diff options
| -rw-r--r-- | .ai/sessions/2026-05-19-02-09-process-rules-and-ai-launcher-polish.org | 163 | ||||
| -rw-r--r-- | inbox/lint-followups.org | 14 | ||||
| -rw-r--r-- | todo.org | 25 |
3 files changed, 189 insertions, 13 deletions
diff --git a/.ai/sessions/2026-05-19-02-09-process-rules-and-ai-launcher-polish.org b/.ai/sessions/2026-05-19-02-09-process-rules-and-ai-launcher-polish.org new file mode 100644 index 0000000..5b00c1b --- /dev/null +++ b/.ai/sessions/2026-05-19-02-09-process-rules-and-ai-launcher-polish.org @@ -0,0 +1,163 @@ +#+TITLE: Session Context — process rules and ai launcher polish +#+AUTHOR: Craig Jennings & Claude +#+DATE: 2026-05-18 + +* Summary + +** Active Goal + +Process the inbox (3 files: 2 cross-project handoffs, 1 lint follow-ups). Implement the two process-improvement signals from the absorbed handoffs as rule edits — disk-check before declaring =/review-code= unavailable, and a mechanical primary trigger for =session-context.org= writes. Then customize the =ai= launcher to send a per-project opening line to each Claude window. Then add a new global rules file for cross-project trigger phrases, with "launch project X" as the first entry. Finally, close a moot todo entry on inspection. + +** Decisions + +- *Discovery-check off-ramp in =commits.md= Step 1.* When =/review-code= isn't in the session's available-skills list, check the filesystem before declaring it unavailable and falling through to the trivial-one-liner exception in Step 2. The handoff's narrow ask, narrow fix. +- *Mechanical primary trigger for session-context writes (Option 4 variant)* over Option 1 (wrap-up forcing function — wrong moment, only fires when wrap runs), Option 2 (Stop-hook nudge — infra-heavy and timing-late), or Option 3 (accept retrospective reconstruction — concedes the crash-recovery purpose). The trigger: any state-modifying tool call (Edit, Write, Agent dispatch, MCP write, Bash that mutates) → write to session-context before the closing user-facing message. Pure-read or conversational turns don't trigger. 5-turn safety net unchanged. +- *=ai= opening-line wording: verbatim spec with =.ai/= prefix.* "This is <host> <name> project. Follow all instructions in .ai/protocols.org." Picked over prepositional ("the X project on Y") or tagged ("Session start: Y / X") variants. +- *=uname -n= for hostname* over the =hostname= binary, which isn't installed by default on Arch. POSIX-standard, works everywhere. +- *New file =claude-rules/triggers.md=* for cross-project trigger phrases over adding to =protocols.org= "Important Terminology" (per-project, wrong layer for cross-project triggers) or shoehorning into an existing rule file. First entry: "launch project X" (synonyms: launch X, open project X, switch to project X) → =ai <path>= against the matched basename. +- *Ambiguity handling for "launch project X": list candidates and ask*, don't guess or fall through to fzf. Asking once costs one short turn; wrong project picks cost a session. +- *Close the Phase A inbox-blind-spot todo as moot* rather than implement a fix. =inbox-send.py= discovery scans single-level under =~/code/= and =~/projects/=, so =claude-templates/= (two levels deep) can't be a routable target. The original 2026-05-15 incident was a manual workaround for a missing project-root =inbox/= that was added in =470085f= this session's predecessor work. Subtree inbox doesn't exist on disk anymore. +- *Bundle the stale =Source:= header line fix into the ai opening-line commit* rather than separate it — touched the same file, trivial cleanup. + +** Data Collected / Findings + +- =hostname= binary not installed on this Arch system. =uname -n=, =cat /proc/sys/kernel/hostname=, and =hostnamectl --static= all work; =uname -n= is the most portable. +- =Makefile= already includes =RULES := $(wildcard claude-rules/*.md)= — new =.md= files are auto-picked-up by install / uninstall / doctor. No Makefile change was needed for =triggers.md=. +- =make doctor= went 36/0/0 → 39/0/0 over the session (Craig's =working-files.md= landed via concurrent push, plus this session's =triggers.md=). +- =inbox-send.py='s =discover_projects()= at line 65-83: scans =~/code/*= and =~/projects/*= single-level via =iterdir()=. Projects must have both =.ai/= and =inbox/= at root. The two-levels-deep =claude-templates/= can never qualify as a routable target. +- =claude-templates/inbox/= doesn't exist on disk; removed 2026-05-15 in the fold session. +- Two concurrent pushes from another machine landed during this session: =3e46a6f feat(rules): working-files convention= (after commit 3 of this session, before commit 4) and =89da216 docs(inbox): session-context handoff= (after commit 1, before commit 2). Both fast-forwarded cleanly with no overlap. +- One push of =283ce6a= failed transiently with "Please make sure you have correct access rights" — same-command =fetch= worked. Retry landed clean. No persistent issue. +- The new mid-session-write rule self-tested cleanly: every state-modifying turn this session that followed the rule's introduction (commit 049a9f8 onward) included a session-context update before the closing message. + +** Files Modified + +Six commits pushed to =origin/main=: + +- =986bb4c docs(commits): check disk before declaring /review-code unavailable= — new "Discovery check" paragraph in =claude-rules/commits.md= Step 1. Inbox also cleared (3 deletions: skill-discovery handoff absorbed by this edit, missing-inbox-dir handoff already resolved by =470085f=, stale lint-followups deferred to first task-review cycle). +- =049a9f8 docs(protocols): mechanical primary trigger for session-context writes= — rewrote =claude-templates/.ai/protocols.org= (and =.ai/protocols.org= mirror) § "When to update (Session Log)" to lead with the mechanical primary trigger; demoted the existing bullets to elaboration of high-loss cases; removed the judgment heuristic. Absorbed and deleted the session-context discipline handoff from the work project. +- =9d804cd feat(ai): per-project opening line with host and project name= — added =build_instructions()= helper to =claude-templates/bin/ai=, updated three =tmux send-keys= sites (=create_window=, =single_mode= new-session, =multi_mode= first-window) to use it. Also fixed the stale =Source:= / =Install:= header pointing at the pre-fold path. +- =6856972 fix(ai): explicit end-of-session placement for new windows= — Craig's manual one-line edit to =create_window=: =tmux new-window -t "$SESSION"= → =tmux new-window -a -t "$SESSION:{end}"=. Reviewed inline, voice walk zero patterns. +- =8f992af feat(rules): add triggers.md for cross-project launch phrases= — new =claude-rules/triggers.md= file with the "launch project X" entry and a "Why a separate file" rationale. =make install= symlinked it to =~/.claude/rules/triggers.md=. +- =283ce6a chore(todo): close Phase A inbox-blind-spot task as moot= — DONE flip on =todo.org:1773= with CLOSED line and a resolution note explaining the find. + +** Next Steps + +Open [#A] carryover, all multi-hour: +- Implement task-review daily-habit per spec (six components — staleness script, wrap-up health check, elisp, workflow, startup nudge, smoke test). Filed last session; not started. +- =DOING= memory-sync (VERIFY on stow approach pending). +- Build =create-documentation= skill. +- Build =/update-skills= skill. +- 2026-05-04 audit review pass. + +Open [#B] late-night-friendly: +- =make remove= for interactive ruleset removal via fzf (~45 min when picked up next). +- Document =mcp/= install pipeline in =mcp/README.org=. + +* Session Log + +** Startup (01:17 CDT) + +Clean startup — =session-context.org= absent (last session wrapped cleanly), no cross-agent traffic, no Active Reminders, no Pending Decisions. Phase A.0 rulesets pull was a no-op (already up to date). Project repo had no behind branches. Phase A and Phase B ran as parallel batches. Read the five most recent session Summaries. + +Inbox had three files: +- =2026-05-16-handoff-from-dotemacs-review-code-skill-discovery.org= — process-improvement signal: when =/review-code= isn't in the session's available-skills list, fall through to filesystem check before declaring it unavailable. +- =2026-05-16-handoff-from-dotemacs-rulesets-missing-inbox-dir.org= — already resolved by =470085f= (the =inbox/= directory now exists and is tracked). +- =lint-followups.org= — date-coverage scan output from 05-16 and 05-17, deferred per prior decision to the first task-review cycle once the habit lands. + +** Inbox absorb + +Per Craig's directive: delete the lint file, delete the resolved missing-inbox-dir handoff, implement the review-code skill-discovery handoff. + +Deleted =inbox/lint-followups.org= and =inbox/2026-05-16-handoff-from-dotemacs-rulesets-missing-inbox-dir.org=. Inbox down to two files (the third handoff plus =.gitkeep=). + +** commits.md — discovery-check rule + +The handoff's narrow ask: add a sub-step to =commits.md= Step 1 telling Claude to check =~/.claude/commands/review-code.md= and =./.claude/commands/review-code.md= on disk before declaring =/review-code= unavailable. The trigger from the dotemacs session was that the session's available-skills list only enumerates plugin-installed skills, not user commands at =~/.claude/commands/= — which are still routable as slash-commands. + +Edited =claude-rules/commits.md= Step 1, inserting a new =**Discovery check.**= paragraph between the bulleted invocation list and the "Surface all findings" line. The new paragraph explains the gap in the available-skills enumeration, directs to check both candidate paths on disk, and instructs to surface the discrepancy to the user rather than auto-skipping via the trivial-one-liner off-ramp in Step 2. + +Deleted =inbox/2026-05-16-handoff-from-dotemacs-review-code-skill-discovery.org= — signal fully absorbed by the rule edit. Inbox now empty (just =.gitkeep=). + +** Commit + push + +Step 0 reconcile was clean (0/0). Step 1 ran =/review-code --staged= inline — the new Discovery-check rule itself was the prompt to look on disk for =review-code.md=. Both copies (=~/.claude/commands/= and =./.claude/commands/=) were present, so the rule worked as intended on the first use. Review verdict: Approve (rules-file change, no code, no security/test impact). Step 2 voice-mode check returned =.ai/notes.org= → general-voice mode (no approval gate). Drafted commit message to =/tmp/commit-review-code-discovery-check.md=, ran =/voice= general (31 patterns). Three patterns fired: #11 (elegant variation — unified "missing/absent/unavailable" terminology), #26 (long → short — "enumeration" → "list", "discrepancy" → "mismatch"), #22 (filler trim — subject tightened). + +Committed as =986bb4c docs(commits): check disk before declaring /review-code unavailable=. Pre-push reconcile 0 behind / 1 ahead. Pushed to =origin/main= clean. + +** Second arrival: session-context discipline handoff + +Craig asked to re-check the inbox, then to =git pull=. =git fetch= showed 1 behind. Pulled =89da216= which dropped =inbox/2026-05-18-0227-from-work-recurring-wrap-time-discipline-miss.org= — a process-improvement signal from the work project. Pattern: across at least 4 work-project sessions, the mid-session =session-context.org= narration discipline keeps slipping; reconstruction at wrap time covers the no-crash case but the crash-recovery purpose stays unprotected. Four candidate fixes proposed in the handoff, none prescribed. + +Walked the four options inline: +- *Option 1 (wrap-up forcing function)* rejected — wraps only run in the no-crash path, so the gate checks the wrong moment. +- *Option 2 (hook nudge)* expanded into hook-type tradeoffs (Stop wrong timing; PreCompact + UserPromptSubmit the strongest minimal-hook design); rejected as infra-heavy for what is really a discipline drift, not infra failure. +- *Option 3 (accept reconstruction)* rejected as retreat — the 2026-01-22 incident motivating the rule was a real loss. +- *Option 4 (harder named checkpoints)* picked, with a variant: replace the judgment heuristic (=/If this session crashed right now.../=) with a mechanical binary primary trigger: a turn that called any state-modifying tool writes to session-context before the closing user-facing message. Demote the existing bullet list to elaboration of the high-loss cases. + +** Implementing Option 4 — primary-trigger rewrite + +Editing =claude-templates/.ai/protocols.org= § Session Context File — § When to update (Session Log). New top paragraph introduces the mechanical primary trigger; existing bullets reframed as elaboration; judgment heuristic removed. Rsync to project mirror. Then commit + push. + +** Commit + push (protocols rule) + +Step 0 reconcile clean (0/0). Step 1 ran =/review-code --staged= inline — verdict Approve (rules-file restructure, root cause addressed, no security/test impact). Voice-mode check still general. Drafted to =/tmp/commit-protocols-session-context-trigger.md=, ran =/voice= general (31 patterns). One pattern fired: #3 (-ing analysis) — "wrap-time reconstruction covering the trace afterward" → "a wrap-time reconstruction afterward". + +Committed as =049a9f8 docs(protocols): mechanical primary trigger for session-context writes=. Pre-push reconcile 0 behind / 1 ahead. Pushed to =origin/main= clean. + +The new rule fired its first self-test mid-session: this very Session Log update was written before the closing user-facing message because the turn called state-modifying tools (Edit, Write, Bash with git push). The mechanical primary trigger works as intended on the first invocation after shipping. + +** ai script — opening-line change + +Craig: customize the ai launcher to start each Claude with a project-identifying opening line. Spec: "This is <hostname> <directory> project. Follow all instructions in protocols.org." Path-prefix amendment after discussion: =.ai/protocols.org= (preserves the current instruction's reliable-resolve behavior). + +Variants offered: (A) verbatim, (B) prepositional "the rulesets project on ratio", (C) tagged "Session start: ratio / rulesets". Craig picked A — verbatim with =.ai/= prefix. Also confirmed bundling the stale =Source:= header line fix (the comment still points at the pre-fold path =~/projects/claude-templates/bin/ai=) into the same commit. + +Implementation: +- Replace constant =CLAUDE_INSTRUCTIONS= with =build_instructions()= helper taking the project name, returning the formatted opening line. +- Update three =tmux send-keys= sites in =create_window=, =single_mode=, and =multi_mode= to call the helper. +- Fix the stale =Source:= comment to the in-repo canonical path. + +Discovered =hostname= binary isn't installed by default (Arch ships it via a separate =inetutils= package; this machine doesn't have it). Switched =build_instructions= to =uname -n= — POSIX, present everywhere, returns short hostname on properly-configured systems. Smoke-test verified output across three project basenames: rulesets, .emacs.d, jr-estate. All clean. + +Surprise mid-flight: pulled in =3e46a6f feat(rules): working-files convention for in-progress task artifacts= during pre-commit fetch. Concurrent push from another machine. Fast-forward landed cleanly (no overlap with my bin/ai change). Acknowledged the inbound, then continued. + +Committed =9d804cd feat(ai): per-project opening line with host and project name=. Pre-push reconcile 0/1. Pushed to =origin/main= clean. + +** Craig's manual follow-up: explicit window placement in create_window + +While I was waiting for the next ask, Craig made a one-line edit to =create_window=: changed =tmux new-window -t "$SESSION"= to =tmux new-window -a -t "$SESSION:{end}"=. The new flags ensure new windows always insert after the existing last window, instead of letting tmux pick the lowest free index (which can land between existing windows when the session's indexes have gaps). + +Reviewed inline — clean targeted behavior fix, only touches =create_window= (the two =tmux new-session= sites for fresh sessions don't need it, no existing windows to append after). Verdict: approve. Voice walk: zero patterns fired (concise + concrete throughout). + +Committed =6856972 fix(ai): explicit end-of-session placement for new windows=. Pre-push reconcile 0/1. Pushed to =origin/main= clean. + +** triggers.md — new global rule for cross-project launch phrases + +Craig asked about the trigger phrase "launch project X" → run the ai script with that project. Question: where to remember this globally? + +Proposed: new file =claude-rules/triggers.md=, since the existing files (=commits.md=, =testing.md=, =verification.md=, =subagents.md=, =interaction.md=, =cross-project.md=, =todo-format.md=) don't have a clean fit for cross-project trigger phrases. =protocols.org= "Important Terminology" hosts the existing trigger phrases (=Let's run the [X] workflow=, =Wrap it up=), but it's per-project — wrong layer for a cross-project launch trigger. + +Craig confirmed the file location. Ambiguity handling on the trigger: list candidates and ask user to pick. Sequence: do the window-append commit first (done above), then this one. + +Implementation: write =claude-rules/triggers.md=, add Makefile install/uninstall lines, run =make install= to symlink it into =~/.claude/rules/=. Then commit + push. + +Discovered the Makefile already uses =RULES := $(wildcard claude-rules/*.md)= — new =.md= files are auto-picked-up by install, uninstall, and doctor. No Makefile change needed. Saves one diff hunk and one decision. + +Wrote =claude-rules/triggers.md= with the launch-trigger entry, a "Why a separate file" section explaining the architectural choice, and an "Adding new triggers" footer for future entries. Ran =make install=: new symlink at =~/.claude/rules/triggers.md=. =make doctor= reports 39/0/0 (up from 36 before working-files.md and triggers.md landed today). + +Step 0 reconcile clean (0/0). Step 1 review-code inline — approve. Step 2 voice walk: one pattern fired (#27, passive "was needed" → "needed"). Committed =8f992af feat(rules): add triggers.md for cross-project launch phrases=. Pre-push reconcile 0/1. Pushed to =origin/main= clean. + +** Reading inbox-send.py — Phase A inbox-blind-spot turns out moot + +Craig asked for the second =[#B]= option in detail: Phase A startup blind to =claude-templates/inbox/= post-fold. Read the todo body, then on Craig's request read =inbox-send.py= itself before recommending. + +Key findings on inspection: +- =inbox-send.py='s =discover_projects()= scans =~/code/*= and =~/projects/*= single-level only, so =claude-templates/= (two levels under =~/code/=) can never be a routable target. The script can only file to =rulesets/inbox/=. +- =claude-templates/inbox/= doesn't exist on disk anymore — removed during the 2026-05-15 fold session. +- The 2026-05-15 incident that motivated the todo was a one-time manual workaround: rulesets didn't yet have a project-root =inbox/=, so the dotemacs session manually =mkdir='d =claude-templates/inbox/= and Wrote there. The root =inbox/= was added in =470085f= (this session's predecessor work). + +So the bug is moot in current state. Phase A scanning only =./inbox/= is correct given current state: nothing routes to the subtree inbox, and the subtree inbox doesn't exist on disk. + +Closed the todo per depth-based completion convention: =DONE [#B]= + =CLOSED: [2026-05-19 Tue]= + a resolution note explaining the find. Committed =283ce6a chore(todo): close Phase A inbox-blind-spot task as moot=. First push attempt failed with "Please make sure you have the correct access rights" — unclear cause (auth had worked fine earlier in the session and fetch in the same command worked). Retried push, landed clean. + diff --git a/inbox/lint-followups.org b/inbox/lint-followups.org new file mode 100644 index 0000000..2c80942 --- /dev/null +++ b/inbox/lint-followups.org @@ -0,0 +1,14 @@ + +* 2026-05-19 lint-org follow-ups — todo.org +** TODO line 2143 — misplaced-heading — Possibly misplaced heading line + +* 2026-05-19 Tue — Date coverage: [#A] / [#B] tasks without DEADLINE or SCHEDULED +Review each: add a date, drop the priority, or confirm 'no-date by intent' inline. +- 10: ** TODO [#A] Implement task-review daily-habit per spec +- 28: ** DOING [#A] Check that memories are sync'd across machines via git.m +- 58: ** TODO [#A] Build =create-documentation= skill for high-quality project/product docs +- 692: ** TODO [#A] Review pass: tighten skills and rulesets after 2026-05-04 audit +- 1221: ** TODO [#B] Build =ov-1= skill for DoDAF OV-1 (High-Level Operational Concept Graphic) +- 1295: ** TODO [#A] Build =/update-skills= skill for keeping forks in sync with upstream +- 1621: ** TODO [#B] Add =make remove= for interactive ruleset removal via fzf +- 1686: ** TODO [#B] Document the =mcp/= install pipeline in =mcp/README.org= @@ -1770,19 +1770,6 @@ Options: Triggered by: 2026-05-15 fold session's refactor audit (commit =2d645fc=). -** DONE [#B] Phase A startup blind to =claude-templates/inbox/= post-fold :bug:fold: -CLOSED: [2026-05-19 Tue] - -Resolved on inspection: the bug is moot in current state. =inbox-send.py='s discovery scans =~/code/*= and =~/projects/*= single-level only, so =claude-templates/= (two levels under =~/code/=) is never a routable target; the 2026-05-15 incident was a one-time manual workaround because =rulesets/inbox/= didn't exist yet, and that root inbox was added in =470085f=. =claude-templates/inbox/= was removed 2026-05-15 and is no longer on disk. - -Phase A's inbox check at =startup.org:107= runs =\ls -la inbox/= against the project root. Post-fold, the canonical's inbox sits inside the subtree at =claude-templates/inbox/= and never gets scanned. A 2026-05-15 cross-project handoff from a dotemacs session dropped a record there; the next rulesets session (this one) missed it at startup entirely. Picked up only when the working-tree drift surfaced during the publish flow. - -Fix: extend Phase A's discovery to also scan =claude-templates/inbox/= when the canonical lives in-repo (i.e., when =claude-templates/.ai/= exists alongside =./.ai/=). The Phase B/C inbox-processing flow already handles per-file routing once a file is surfaced; the gap is only in discovery. - -Adjacent question worth answering at the same time: should cross-project handoffs file into =./inbox/= at the project root (matching what Phase A already scans), or stay in =claude-templates/inbox/= and rely on the discovery fix? The =inbox-send= script's target-project logic is the place to settle that. - -Triggered by: 2026-05-15 evening session, surfaced when committing the test-harness work. - ** TODO [#C] Refactor =daily-prep.org= to delegate to =triage-intake.org= for the triage section =daily-prep.org= still does its own inline triage (Gmail × 3 accounts, Slack, Linear, GHE PRs, calendars) as part of the full prep flow. Now that =triage-intake.org= exists as a standalone scan over the same source set, daily-prep could call it and consume its synthesis instead of duplicating the source-scan logic — DRYs up a 57k-line workflow and keeps both flows in sync when sources change. @@ -2195,3 +2182,15 @@ CLOSED: [2026-05-16 Sat] For many of them, git.cjennings.net mirrors to github.com, and github.com isn't the remote. For many others, git.cjennings.net is the remote with no mirror. Remove or replace the reference to github.com +** DONE [#B] Phase A startup blind to =claude-templates/inbox/= post-fold :bug:fold: +CLOSED: [2026-05-19 Tue] + +Resolved on inspection: the bug is moot in current state. =inbox-send.py='s discovery scans =~/code/*= and =~/projects/*= single-level only, so =claude-templates/= (two levels under =~/code/=) is never a routable target; the 2026-05-15 incident was a one-time manual workaround because =rulesets/inbox/= didn't exist yet, and that root inbox was added in =470085f=. =claude-templates/inbox/= was removed 2026-05-15 and is no longer on disk. + +Phase A's inbox check at =startup.org:107= runs =\ls -la inbox/= against the project root. Post-fold, the canonical's inbox sits inside the subtree at =claude-templates/inbox/= and never gets scanned. A 2026-05-15 cross-project handoff from a dotemacs session dropped a record there; the next rulesets session (this one) missed it at startup entirely. Picked up only when the working-tree drift surfaced during the publish flow. + +Fix: extend Phase A's discovery to also scan =claude-templates/inbox/= when the canonical lives in-repo (i.e., when =claude-templates/.ai/= exists alongside =./.ai/=). The Phase B/C inbox-processing flow already handles per-file routing once a file is surfaced; the gap is only in discovery. + +Adjacent question worth answering at the same time: should cross-project handoffs file into =./inbox/= at the project root (matching what Phase A already scans), or stay in =claude-templates/inbox/= and rely on the discovery fix? The =inbox-send= script's target-project logic is the place to settle that. + +Triggered by: 2026-05-15 evening session, surfaced when committing the test-harness work. |
