aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ai/sessions/2026-06-02-20-04-signal-paging-go-bundle-and-catalog-spec.org121
-rw-r--r--todo.org57
2 files changed, 149 insertions, 29 deletions
diff --git a/.ai/sessions/2026-06-02-20-04-signal-paging-go-bundle-and-catalog-spec.org b/.ai/sessions/2026-06-02-20-04-signal-paging-go-bundle-and-catalog-spec.org
new file mode 100644
index 0000000..072a283
--- /dev/null
+++ b/.ai/sessions/2026-06-02-20-04-signal-paging-go-bundle-and-catalog-spec.org
@@ -0,0 +1,121 @@
+#+TITLE: Session Context
+#+DATE: 2026-06-02
+
+* Summary
+
+** Active Goal
+
+Started from a clean startup, committed four finished-but-uncommitted doc edits, then worked Craig's three-item queue in order: Signal paging (full install), the Go language bundle (full tier), and the cross-project pattern catalog (one-page spec). Eight commits, all pushed to origin/main.
+
+** Decisions
+
+- *Signal pager = a dedicated Google Voice account, not the primary.* signal-cli registered to +15045173983 ("Claude Pager"); pages go from it to Craig's Signal account, which notifies normally. The old primary-to-itself path was the non-notifying bug.
+- *Craig's Signal identity is a UUID, not a number.* Phone-number privacy hides his number; the page destination is account UUID b1b5601e-6126-47f8-afaa-0a59f5188fde. His primary +15103169357 reads "unregistered" in Signal's directory — never page it.
+- *page-signal default flipped* from --note-to-self to send-from-PAGE_SIGNAL_ACCOUNT-to-PAGE_SIGNAL_TO (both env-overridable, baked defaults), -a pins the sender, --to accepts a UUID.
+- *Go bundle = full tier (Craig's pick), matching elisp.* The two rule files (go.md, go-testing.md) are the sync fingerprint — their absence was why the bundle's coverage slice wasn't sync-maintainable. The validate hook runs gofmt + go vet (not auto-tests; packages can be slow/integration).
+- *Two inbox handoffs filed, not acted inline* (lint-followups reconcile from .emacs.d; start-work Justify-gate item from work) — both [#C] :feature:, both senders replied.
+- *Pattern-catalog: spec-first per Pearl's recommendation.* Drafted a one-page spec making a recommended call on all five open questions (one-file-per-pattern + frontmatter; home = rulesets patterns/; agent-driven surfacing via a thin pointer rule; anti-patterns as a field; capture-on-landing/promote-on-review). Filed a VERIFY for Craig's review.
+
+** Data Collected / Findings
+
+- signal-cli 0.14.4.1 built from AUR (Java 26 satisfies the JRE dep). Registration needs a captcha (signalcaptchas.org, ~1-2 min token TTL) + an SMS code to the GV number. The prior session's clone + registration were gone — this was a from-scratch install.
+- signal-mcp (rymurr) cloned to ~/.local/share/signal-mcp, uv .venv (py 3.13.13, mcp 1.6.0); claude mcp list shows it ✓ Connected.
+- Go 1.26.3 present; full `make test` green (exit 0) after adding the bundle + re-baselining install-lang.bats test 7.
+- Pre-existing, unrelated: scripts/remove.sh missing exec bit makes `make lint` exit non-zero (one-line chmod fix, left for Craig).
+
+** Files Modified
+
+- claude-rules/emacs.md, review-code/SKILL.md, voice/SKILL.md + voice-profile.org — the four startup doc edits (commits 066faed, 9bc7e67, a0c98c4).
+- mcp/servers.json, mcp/README.org, claude-templates/bin/page-signal, page-signal.org (canonical+mirror) — Signal paging (cfaff12, d2aaf86).
+- languages/go/ — full bundle: go.md, go-testing.md, validate-go.sh, settings.json, githooks/pre-commit, CLAUDE.md; scripts/tests/validate-go.bats + install-lang.bats test 7 (3a06aff).
+- todo.org — 4 tasks filed/closed (task-review-at-end-of-audit, lint-followups, start-work, Signal MCP DONE) + pattern-catalog VERIFY; docs/design/2026-06-02-pattern-catalog-spec.org (671fbe9, 0b07c15, 91b067d).
+- Memory: project_signal_pager_account.md + MEMORY.md pointer.
+
+** Next Steps
+
+- Pattern-catalog: Craig reviews the spec (VERIFY under the catalog task), then implement patterns/ + the six seed patterns. Pearl available for spec-review iterations.
+- Filed [#C] tasks await Craig's pace: lint-followups reconcile-on-write, start-work Justify "reasons not to" item, task-review-at-end-of-audit.
+- Optional one-liner: chmod +x scripts/remove.sh to make `make lint` clean.
+- Next session: signal-mcp's send/receive tools load fresh — worth a live tool-call smoke test.
+
+* Session Log
+
+** 2026-06-02 ~13:50 CDT — Committed four uncommitted doc edits, filed task-audit task
+
+Startup found four uncommitted doc/rule edits in the tree (no crash-recovery file — last session wrapped clean, so these were finished-but-uncommitted work). Reviewed via /review-code --staged (Approve, no issues), drafted three atomic commit messages through /voice personal, committed:
+- 066faed docs(emacs): auth-source two-hour credential cache gotcha
+- 9bc7e67 docs(review-code): plain-text terminal output in Phase 5
+- a0c98c4 docs(voice): generalize §38 to omit-needless-words walk
+
+Then filed a new [#C] task (671fbe9) per Craig's request: have task-audit chain a task-review pass as its final phase. Filed under Rulesets Open Work, tags :chore:solo:.
+
+Four commits sit unpushed on main. Push pending Craig's confirmation.
+
+Next: Craig queued three carryover items in order — Signal MCP install, Go bundle buildout, cross-project pattern catalog. Signal is the long-standing blocker (GPG pinentry needs the desktop). Setting up the queue.
+
+** 2026-06-02 ~13:55 CDT — Signal prerequisites are gone; task is from-scratch, not "finish at desktop"
+
+Probed the Signal state before diving in. This session IS graphical (WAYLAND_DISPLAY=wayland-1, DISPLAY=:0), so pinentry is no longer the blocker. But the prerequisites the 5/29 notes assumed are absent on this machine:
+- signal-cli NOT installed / not on PATH (5/29 said registered to +15103169357).
+- signal-mcp clone GONE from ~/.local/share/signal-mcp.
+- signal-mcp NOT registered in `claude mcp list`.
+
+So Task #1 is effectively from-scratch: install signal-cli (system pkg), register a number, re-clone rymurr/signal-mcp + venv, then make install-mcp. The unresolved design decision from 5/29 still stands — primary-to-itself doesn't notify on Signal mobile, so real paging needs a separate Google Voice number. Stopping to surface this + get push confirmation for the 4 commits before proceeding.
+
+** 2026-06-02 ~13:58 CDT — Signal install in progress (option 2, GV number +15045173983)
+
+Craig chose option 2: register signal-cli with the Google Voice number (504) 517-3983 so paging notifies from the start. Progress:
+- signal-cli 0.14.4.1 building from AUR (yay, background job bxkurg667) — libsignal-client Rust + gradle, ETA ~10-15 min. Java 26 satisfies the runtime dep.
+- Re-cloned rymurr/signal-mcp to ~/.local/share/signal-mcp; built its venv via `uv sync` (Python 3.13.13, mcp 1.6.0). The .venv/bin/python + signal_mcp/main.py paths servers.json expects now exist.
+- Updated mcp/servers.json signal-mcp --user-id to +15045173983 (was the primary +15103169357). UNCOMMITTED.
+
+Still to do once signal-cli finishes building:
+1. Register: signal-cli -a +15045173983 register [--captcha TOKEN] — Signal now requires a captcha (browser, Craig solves) + then SMS code delivered to the GV number (Craig reads from Google Voice). Human-in-the-loop.
+2. Verify: signal-cli -a +15045173983 verify CODE.
+3. make install-mcp to register signal-mcp in claude.
+4. DECISION to raise: page-signal defaults to --note-to-self. With the GV account as sender, paging Craig's primary Signal needs --to +15103169357 (outbound from GV → primary notifies normally). Change the page-signal default sender accordingly.
+5. Commit servers.json + page-signal change; update page-signal.org known-limitation note; memory entry for the GV sender number.
+
+Push of the 4 doc/task commits still pending Craig's yes/no.
+
+** 2026-06-02 ~14:10 CDT — GV account registered and live; primary number is the snag
+
+Registered +15045173983 with signal-cli: captcha (2nd token — first 403'd on expiry), SMS code 968081 from Google Voice, verify OK. Set profile given/family name to "Claude Pager". signal-cli listAccounts shows +15045173983.
+
+Test page GV -> primary +15103169357 FAILED: "Unregistered user +15103169357". Signal's directory has no account on the primary right now (listAccounts was empty before today, so the 5/29 signal-cli-as-primary registration is gone). So the page DESTINATION is unknown — need the number Craig's phone Signal is actually registered under. Sender side (GV account) fully works; blocked on target. Asked Craig.
+
+** 2026-06-02 ~18:05 CDT — Signal DONE. Destination is Craig's account UUID (phone-number privacy); committed cfaff12
+
+Craig sent a message from his phone to the GV account; signal-cli receive revealed his Signal identity is a stable account UUID b1b5601e-6126-47f8-afaa-0a59f5188fde (phone-number privacy hides his number; primary +15103169357 reads unregistered in Signal's directory). Paged the UUID -> landed on his phone with notification, he replied "Cowabunga!". Two-way confirmed.
+
+Finished the install:
+- page-signal (claude-templates/bin/) default changed from --note-to-self to: send FROM PAGE_SIGNAL_ACCOUNT (+15045173983) TO PAGE_SIGNAL_TO (the UUID), both env-overridable; -a pins the sender; --to now also accepts a UUID. usage() sed range 3->23. Symlinked into ~/.local/bin.
+- mcp/servers.json --user-id -> +15045173983. make install-mcp registered signal-mcp; claude mcp list shows it ✓ Connected; server smoke-tested OK.
+- page-signal.org (canonical + mirror) "Known limitation" note rewritten to "resolved 2026-06-02"; sync-check --fix kept the mirror honest.
+- Memory: project_signal_pager_account.md (+ MEMORY.md pointer).
+- review-code (Approve) + /voice personal; committed cfaff12.
+Task #1 complete.
+
+** 2026-06-02 ~18:08 CDT — Processed two inbox handoffs, filed as TODOs, replied to senders
+
+- .emacs.d (lint-followups drift): filed [#C] :feature: — lint-org reconcile-on-write (dedupe + drop resolved, content-keyed) + task-audit Phase C dead-link reaping (scoped to dead-link only). Replied via direct write to ~/.emacs.d/inbox/ (inbox-send doesn't scan ~/.emacs.d).
+- work (start-work Justify gate): filed [#C] :feature: — add "top reasons not to do this" item with one-line fallback. Replied via inbox-send to work.
+- Both committed in 0b07c15; LAST_INBOX_PROCESS bumped to 2026-06-02. Inbox clean.
+
+Six commits unpushed: 066faed 9bc7e67 a0c98c4 671fbe9 cfaff12 0b07c15. Still awaiting Craig's push yes/no. Next queue item: Task #2 Go bundle.
+
+** 2026-06-02 ~18:20 CDT — Built the full Go language bundle (Task #2), full tier
+
+Craig chose full tier (option 1). The Go bundle was coverage-slice-only; the missing fingerprint (no rule files) meant sync-language-bundle.sh couldn't detect it, so its coverage slice wasn't sync-maintainable — that was the original motivation. Added six files:
+- claude/rules/go.md + go-testing.md — style + testing rules (table-driven, -race, errors.Is, the coverage slice). The two rule files are the sync fingerprint that now makes the bundle detectable.
+- claude/hooks/validate-go.sh — PostToolUse hook: gofmt + go vet on each edited .go (vet type-checks, so it catches compile/syntax). Tests deliberately not auto-run (slow/integration packages). TDD'd via scripts/tests/validate-go.bats (6 tests, red→green).
+- claude/settings.json — Go permissions + hook wiring.
+- githooks/pre-commit — secret scan + gofmt check on staged .go (functionally smoke-tested).
+- CLAUDE.md — seed.
+Updated scripts/tests/install-lang.bats test 7 (was "coverage-only, no CLAUDE.md" — now asserts the full bundle). End-to-end install into a temp project verified all files land + wire correctly. `make test` fully green (exit 0). `make lint` clean for the new files (one pre-existing unrelated warning: scripts/remove.sh not executable).
+
+Reviewed (Approve) + /voice personal; committed 3a06aff and pushed (origin synced 0/0). Task #2 complete.
+
+Pre-existing follow-up noticed (NOT mine, not committed): scripts/remove.sh missing exec bit makes `make lint` exit non-zero — one-line `chmod +x scripts/remove.sh` fix if Craig wants make lint clean.
+
+Queue: Task #3 cross-project pattern catalog ([#B] :spec:thinking:) remains. It's a spec/thinking task — surfacing to Craig for scope direction rather than diving in blind.
diff --git a/todo.org b/todo.org
index f29cea2..865937e 100644
--- a/todo.org
+++ b/todo.org
@@ -70,35 +70,6 @@ Three more pearl handoffs landed and were filed during this audit. Filed: [[file
*** VERIFY Review the pattern-catalog spec (5 decisions + 3 open questions)
One-page spec drafted 2026-06-02: [[file:docs/design/2026-06-02-pattern-catalog-spec.org][2026-06-02-pattern-catalog-spec.org]]. It makes a recommended call on each of the five open design questions — format (one file per pattern with frontmatter), home (a =patterns/= dir in rulesets), surfacing (a thin =claude-rules/patterns.md= pointer, agent-driven), anti-patterns (a field within each pattern), intake (capture-on-landing, promote-on-review) — plus three smaller open questions (directory name, generalize-now-vs-lazily, whether a =/pattern= skill is worth it). Implementation is gated on your review. Pearl is available for spec-review iterations.
-** DONE [#B] Add Signal MCP server (rymurr/signal-mcp) :feature:
-CLOSED: [2026-06-02 Tue]
-:PROPERTIES:
-:CREATED: [2026-05-29 Fri]
-:LAST_REVIEWED: 2026-05-29
-:END:
-Done 2026-06-02. Registered signal-cli to the Google Voice pager account, added the signal-mcp entry to servers.json, installed via make install-mcp (claude mcp list shows it connected), and documented the signal-cli + GV dependency in mcp/README.org. The GV-registration dependency this task flagged is resolved. Shipped in cfaff12 (page-signal routing) and this commit (README).
-
-Install [[https://github.com/rymurr/signal-mcp][rymurr/signal-mcp]] so Claude can call =send_message_to_user=, =send_message_to_group=, and =receive_message= natively rather than shelling out to the =page-signal= wrapper. Python, MCP framework, depends on =signal-cli= being configured locally.
-
-Two-way capability is the differentiator over the CLI: =receive_message= lets the agent listen for replies on the phone, enabling page-as-confirm flows, "should I proceed?" loops over Signal, and structured Q&A across devices.
-
-*** Dependency
-
-This depends on the Google Voice account being registered with =signal-cli= first. Sending from Craig's primary number to itself doesn't notify (Signal treats it as one account on linked devices). The MCP server takes =--user-id= at startup, one account per instance, so it has to point at the GV account, with the primary as the per-send recipient.
-
-If GV registration is still pending when this task runs, block here and surface that.
-
-*** Implementation
-
-- =mcp/servers.json= — add =signal-mcp= entry under stdio transport (=command=, =args=, optional =env= for the user-id pointer).
-- =mcp/README.org= — document the signal-cli + GV-registration dependency and the user-id pattern.
-- =mcp/secrets.env.gpg= — only if the MCP server's user-id needs to be encrypted (probably not; the GV number isn't a secret beyond being personal).
-- Verify: =make install-mcp= followed by =make check-mcp= shows =signal-mcp ok=; smoke-test via a Claude tool call sending a message + waiting on =receive_message=.
-
-*** Why this matters
-
-=page-signal= is the fast path (a hook, a script, a make recipe can call it without an MCP round-trip). The MCP server is the smart path. When Claude wants to send and then *react to the reply*, the CLI can't do that — only the MCP server can. The two complement each other; this task adds the second half.
-
** TODO [#C] Check that memories are sync'd across machines via git :spec:
:PROPERTIES:
:LAST_REVIEWED: 2026-05-28
@@ -2483,3 +2454,31 @@ Decision (Craig, 2026-05-31): *approved the four-lane structure (Summary/Executi
Teach startup/routing to read =Summary= only at routing time, then =Execution= only for the selected workflow. Other sections become opt-in.
After the pilot, evaluate: did the savings show up in real session token use? Did the structure constrain the workflow expressiveness too much? If yes to savings and no to constraint, expand to the next-largest workflows. If not, document why and stop. Don't templatize universally — shorter workflows don't need tiering.
+** DONE [#B] Add Signal MCP server (rymurr/signal-mcp) :feature:
+CLOSED: [2026-06-02 Tue]
+:PROPERTIES:
+:CREATED: [2026-05-29 Fri]
+:LAST_REVIEWED: 2026-05-29
+:END:
+Done 2026-06-02. Registered signal-cli to the Google Voice pager account, added the signal-mcp entry to servers.json, installed via make install-mcp (claude mcp list shows it connected), and documented the signal-cli + GV dependency in mcp/README.org. The GV-registration dependency this task flagged is resolved. Shipped in cfaff12 (page-signal routing) and this commit (README).
+
+Install [[https://github.com/rymurr/signal-mcp][rymurr/signal-mcp]] so Claude can call =send_message_to_user=, =send_message_to_group=, and =receive_message= natively rather than shelling out to the =page-signal= wrapper. Python, MCP framework, depends on =signal-cli= being configured locally.
+
+Two-way capability is the differentiator over the CLI: =receive_message= lets the agent listen for replies on the phone, enabling page-as-confirm flows, "should I proceed?" loops over Signal, and structured Q&A across devices.
+
+*** Dependency
+
+This depends on the Google Voice account being registered with =signal-cli= first. Sending from Craig's primary number to itself doesn't notify (Signal treats it as one account on linked devices). The MCP server takes =--user-id= at startup, one account per instance, so it has to point at the GV account, with the primary as the per-send recipient.
+
+If GV registration is still pending when this task runs, block here and surface that.
+
+*** Implementation
+
+- =mcp/servers.json= — add =signal-mcp= entry under stdio transport (=command=, =args=, optional =env= for the user-id pointer).
+- =mcp/README.org= — document the signal-cli + GV-registration dependency and the user-id pattern.
+- =mcp/secrets.env.gpg= — only if the MCP server's user-id needs to be encrypted (probably not; the GV number isn't a secret beyond being personal).
+- Verify: =make install-mcp= followed by =make check-mcp= shows =signal-mcp ok=; smoke-test via a Claude tool call sending a message + waiting on =receive_message=.
+
+*** Why this matters
+
+=page-signal= is the fast path (a hook, a script, a make recipe can call it without an MCP round-trip). The MCP server is the smart path. When Claude wants to send and then *react to the reply*, the CLI can't do that — only the MCP server can. The two complement each other; this task adds the second half.