diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-15 18:21:12 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-15 18:21:12 -0500 |
| commit | 23a77929b4a67fd80c99de1a925b94f1b8b7ac74 (patch) | |
| tree | 5261cb499ac5ed51c7b45c6d64e81ba7839ea7f8 /todo.org | |
| parent | b7d5ba97f08e668f49c45642035820d70099d785 (diff) | |
| download | rulesets-23a77929b4a67fd80c99de1a925b94f1b8b7ac74.tar.gz rulesets-23a77929b4a67fd80c99de1a925b94f1b8b7ac74.zip | |
chore(ai): wrap fold-claude-templates + audit/install-ai + ratio migration
Diffstat (limited to 'todo.org')
| -rw-r--r-- | todo.org | 348 |
1 files changed, 173 insertions, 175 deletions
@@ -1771,181 +1771,6 @@ The four canonical rules (=commits=, =testing=, =verification=, =subagents=) are The Elisp pair is the most suspicious — three repos using essentially the same rules. Audit: diff these across the projects, check for drift, then decide whether to canonicalize them under =~/code/rulesets/claude-rules/languages/<lang>/= and symlink, or leave them as project-local. -** DONE [#B] Encode follow-up filing rules into =/start-work= -CLOSED: [2026-05-15 Fri] - -Phase 4 step 5 of =/start-work= ("refactor audit") says any candidate that isn't fix-now must land in one of three buckets: fold-into-related-commit, separate =refactor:= commit, or "file a ticket or todo.org entry." The third disposition doesn't say *where* — which leaves the orchestrator picking a location ad-hoc. Result: follow-ups buried under children of an epic parent get orphaned when the parent closes, or follow-ups for standalone tasks scatter across the file with no convention. - -Proposed placement rule (already memorized for this project as =feedback_followups_as_siblings.md=, generalizing): - -- *Epic-style parent task* (level-2 with multiple level-3 children) → follow-ups file as level-2 *siblings* of the parent. Stays visible after parent closure. -- *Standalone task* (level-2 with no children, or a level-3 inside another structure) → follow-up files as a new level-2 top-level entry in the same =* Open Work= section. Don't nest under the originating task. - -Both cases: include a "Triggered by: <date> <task or commit>" line so a future reader sees what surfaced it. - -Update =.claude/commands/start-work.md= Phase 4 step 5's "Disposition for each candidate" section to spell this out. Update any cross-references in =commits.md= or other files that touch the discipline. - -Triggered by: 2026-05-15 fold-epic session — Craig flagged the gap mid-flight after I'd surfaced a follow-up but hadn't filed it. - -** DONE [#A] Consolidate =.ai/= template infrastructure (fold + audit + install-ai + ratio) :feature: -CLOSED: [2026-05-15 Fri] - -End-state: one repo (=rulesets=) is the single source of truth for =.ai/= template content. =make audit= verifies and applies drift across every =.ai/=-using project on the machine. =make install-ai= bootstraps new projects. Same setup propagated to ratio so both machines run the same way. - -Today (2026-05-15) the canonical-source rule got violated again: rulesets commit =372fb76= added a wrap-up subsection to =rulesets= without going through =claude-templates= first, and the next session's startup rsync was about to silently undo it. Two-repo coordination is the root cause; fold solves it. - -Build order: fold first (others depend on the new canonical path), then audit + install-ai in parallel, then test, then propagate to ratio. - -*** DONE [#A] Fold =claude-templates= into rulesets -CLOSED: [2026-05-15 Fri] - -Two repos, one source of truth. =~/projects/claude-templates/= is the canonical =.ai/= template that gets rsync'd into every project at session start. Keeping it standalone means a second =git pull= in startup Phase A.0, a second remote to push to at wrap-up, and a split history any time a change touches both. Folding it into =rulesets/claude-templates/= gives one repo to clone on a fresh machine and one place to edit templates. - -**** Open design choices - -- *History.* =git subtree add --prefix=claude-templates ~/projects/claude-templates main= preserves the 84-commit history under the new prefix. Plain content copy (=cp -a= + =git add=) is simpler but loses history. Either is fine since the standalone repo stays archived on =cjennings.net=. -- *Layout.* =rulesets/claude-templates/= mirrors the old repo name and sits next to =claude-rules/= cleanly. Alternative: absorb =.ai/= directly under a different name (=rulesets/.ai-template/= or similar). First option is clearer. -- *bin/ai.* The standalone Makefile symlinks =$HOME/.local/bin/ai → bin/ai=. After the move, fold that into rulesets' Makefile as another install target. - -**** Mechanical steps - -1. Subtree-merge or copy =~/projects/claude-templates/= into =rulesets/claude-templates/=. -2. Update 3 references in rulesets: - - =.ai/protocols.org= line 163 — pointer in the "Let's run/do the X workflow" section. - - =.ai/workflows/cross-agent-comms.org= line 8 — promotion-target path. - - =.ai/workflows/startup.org= lines 22, 96-98 — Phase A.0 pull + Phase A rsync sources. -3. Update Phase A.0 of =startup.org= to pull rulesets instead of claude-templates. Inside rulesets sessions, the existing project-repo pull already covers it. Outside rulesets (every other project's session), Phase A.0 needs an explicit =git pull= on =~/code/rulesets/= before the rsync — otherwise the templates will be stale. -4. Replace =~/projects/claude-templates/= with a symlink to =~/code/rulesets/claude-templates/= for transition continuity. -5. After every active project has had one session start (and rsync'd the new =startup.org=), drop the symlink and archive =cjennings.net:git/claude-templates.git=. - -**** Bootstrap gap - -Every project on the machine has a =.ai/workflows/startup.org= that rsyncs from =~/projects/claude-templates/=. Until each project's startup.org gets refreshed (which happens via the rsync itself), the old path needs to keep resolving. The symlink at step 4 is the bridge: old paths resolve into the new location, the rsync delivers the updated startup.org, next session uses the new path directly. - -*** DONE [#A] Add =make audit= — drift detector across all =.ai/=-using projects -CLOSED: [2026-05-15 Fri] - -Companion to =make doctor= (single-machine scope, checks =~/.claude/=). =audit= is cross-project scope: walks every directory on the machine that has a =.ai/=, diffs the synced template files against the canonical source, and reports drift. =--apply= flag rsyncs the drift into the project's working tree (no auto-commit). Catches stale projects without forcing a session start in each one. - -**** Open design choices - -- *Scope.* Template-sync drift is the useful flavor: for each project, diff =.ai/protocols.org=, =.ai/workflows/=, =.ai/scripts/= against the canonical source. -- *Source path.* Post-fold: =~/code/rulesets/claude-templates/.ai/=. Build =audit= against the new path from day one. -- *Project discovery.* Walk =~/code/=, =~/projects/=, =~/.emacs.d/= up to depth 3 for any directory containing =.ai/=. Skip the canonical source itself. -- *Default mode is report-only.* =--apply= triggers rsync; =--force= overrides the dirty-skip safety. - -**** Per-project flow (designed 2026-05-15) - -For each discovered project, in order: - -1. Verify =.ai/= exists (path probe). If missing → =FAIL=, skip, continue loop. -2. Detect git tracking via =git check-ignore .ai/= → =tracked= or =gitignored=. -3. Verify no uncommitted =.ai/= changes (=git status --porcelain .ai/=). Dirty → =WARN=, skip rsync unless =--force=. -4. Verify content matches canonical via three =rsync -a --dry-run --itemize-changes= calls (=protocols.org=, =workflows/=, =scripts/=). Zero items = clean. -5. Action (=--apply= only, drift detected): three =rsync -a [--delete]= calls. -6. Verify rsync converged (re-run the dry-runs; zero now). -7. Verify working-tree state after rsync (tracked projects). Report deltas. Do not auto-commit. -8. Verify no unpushed =.ai/= commits (=git log @{u}..HEAD -- .ai/=). Informational only. - -**** Output format (mirrors =doctor=) - -#+begin_example -Claude-templates source: - ok rulesets/claude-templates is current (origin/main) - -Per-project .ai/ drift: - ok ~/projects/work - applied ~/projects/homelab 3 files changed - skipped ~/code/winvm uncommitted .ai/ (use --force) - ok ~/projects/clipper - -Summary: 18 ok, 3 applied, 1 skipped, 0 failed -#+end_example - -Exit code: =0= if all clean, no skips, no failures. =1= otherwise. - -**** Why not extend =make doctor= instead - -=doctor= has a clean meaning today: "is this machine's =~/.claude/= consistent with rulesets?" Mixing in cross-project =.ai/= drift muddies the exit code. Keep them separate. =audit= can optionally invoke =doctor= as its last check since both ask "did the symlinks keep up with the source?". A future =make all-checks= can wrap both. - -*** DONE [#A] Add =make install-ai PROJECT=<path>= — bootstrap =.ai/= in a fresh project -CLOSED: [2026-05-15 Fri] - -Separate target from =audit= because operating on projects that lack =.ai/= is a distinct action. The absence might be intentional, so =audit= skips them. Bootstrap is explicit opt-in. - -**** Flow - -1. Refuse if =.ai/= already exists in =PROJECT=. Message: "already installed; use =make audit --apply= to update." -2. Verify =PROJECT= is a git checkout (warn if not — works without git, loses some lifecycle benefits). -3. Create =PROJECT/.ai/= directory. -4. Rsync canonical content: =protocols.org=, =workflows/=, =scripts/= (same three rsyncs as =audit=). -5. Seed =PROJECT/.ai/notes.org= from a canonical template with project-name placeholder. -6. Create empty =PROJECT/.ai/sessions/= (with =.gitkeep= for tracked projects). -7. Track or gitignore =.ai/=? Default: ask. Flag: =--track= / =--gitignore=. -8. Print next-steps banner: =make install-lang LANG=<lang> PROJECT=<path>=; open Claude Code in the project. - -**** Symmetry with existing install targets - -#+begin_example -make install-lang LANG=python PROJECT=/path # language bundle (existing) -make install-ai PROJECT=/path # .ai/ template (new) -make install-lang # no args → fzf-pick -make install-ai # no args → fzf-pick from - # ~/projects/* + ~/code/* dirs - # without an existing .ai/ -#+end_example - -*** DONE [#A] Test plan for audit + install-ai before propagating to ratio -CLOSED: [2026-05-15 Fri] - -Test against the current state of this machine before pushing changes to ratio. - -**** =make audit= tests - -1. Dry-run report only (no =--apply=). Should show: claude-templates current; per-project drift; correct =ok=/=drift= classifications; summary line and exit code match. -2. After the fold lands, every project should be reported as drift (their =startup.org= still points at the old path). Run =--apply= → rsync converges. Re-run audit → all =ok=. -3. Manually edit one =.ai/workflows/foo.org= in a tracked project. Re-run audit → should report =skipped: uncommitted .ai/=. Run =--apply --force= → rsync clobbers the edit. Verify the edit is gone. -4. Manually delete one =.ai/= dir. Re-run audit → =FAIL: .ai/ missing=. Loop continues. -5. Idempotency: =--apply= twice in a row converges to all =ok= on the second pass. - -**** =make install-ai= tests - -1. Create =/tmp/test-fresh-project= as a git repo. Run =make install-ai PROJECT=/tmp/test-fresh-project=. Verify =.ai/= structure matches canonical, =notes.org= has placeholder, =sessions/= exists. -2. Run =make install-ai PROJECT=/tmp/test-fresh-project= again → should refuse (=.ai/= already exists). -3. Open Claude Code in the new project. Startup workflow runs cleanly (Phase A.0 + Phase A rsync should be a no-op since the install just ran). -4. fzf form: =make install-ai= with no args. Lists candidate dirs (=~/projects/*=, =~/code/*= without =.ai/=). - -**** Pass criteria - -- =audit= behavior matches the per-project flow spec for every classification path. -- =install-ai= produces a project indistinguishable from one that's been running sessions for a while. -- =make doctor= still passes 36/0/0 after all the work. -- =make test= (pytest + ERT) passes. - -*** DONE [#A] Migrate projects on ratio (second machine) -CLOSED: [2026-05-15 Fri] - -After local fold + audit + install-ai are working, propagate to ratio. - -**** Steps - -1. On ratio: =git -C ~/code/rulesets pull= — picks up the folded =claude-templates/= subdir and updated =Makefile= targets. -2. On ratio: archive or =mv= the standalone =~/projects/claude-templates/= aside, replace with symlink to =~/code/rulesets/claude-templates/= (same bridge mechanic as local). -3. On ratio: =make audit= → see drift across ratio's projects. -4. On ratio: =make audit --apply= → rsync into each tracked/gitignored project. Surface projects with uncommitted =.ai/= drift for manual handling. -5. On ratio: =make doctor= → catch any =~/.claude/= install drift (likely some, since ratio hasn't seen recent rulesets updates). -6. Verify by opening Claude Code in a few ratio projects. Startup should be a no-op or near-zero rsync. - -**** Known unknowns - -- Ratio may have its own project list overlapping with this machine's but not identical. =audit= discovers projects via the walk, so this is automatic. -- Ratio might have uncommitted =.ai/= work in some projects that this machine doesn't. =audit= surfaces them; handle case-by-case. -- If anything goes wrong, ratio's archived =~/projects/claude-templates/= is the safety net — restore the symlink target and re-run audit. - -**** Adjacent: cross-machine memory sync - -The =[#A] DOING= memory-sync investigation (todo.org:10) is adjacent. Both involve "make my Claude setup portable across machines." Coordinate so the memory-sync stow approach (if approved) doesn't conflict with this fold's symlink mechanics. - ** TODO [#C] Test harness for =make audit= + =make install-ai= edge cases :test: Three edge cases from the fold-epic test plan were not exercised because they're destructive on real projects: @@ -2134,3 +1959,176 @@ Origin: came up while scrubbing a project's todo.org on 2026-05-11 — moving a Built and shipped 2026-05-11: =--archive-done= added to =.ai/scripts/todo-cleanup.el= test-first; 13-test ERT suite (=tests/test-todo-cleanup.el=) + realistic synthetic fixture (=tests/fixtures/todo-sample.org=), wired into =make test= / =make test-scripts= alongside pytest. The CLI dispatch moved into =tc-main= behind a guard so the suite can =require= the file without firing it. Section matching is case-insensitive and tolerates the =<Project> Open Work= / =<Project> Resolved= naming variants. Opt-in only — not wired into the wrap-up flow. Source of truth is =~/projects/claude-templates/=; rsync'd into this repo. +** DONE [#B] Encode follow-up filing rules into =/start-work= +CLOSED: [2026-05-15 Fri] + +Phase 4 step 5 of =/start-work= ("refactor audit") says any candidate that isn't fix-now must land in one of three buckets: fold-into-related-commit, separate =refactor:= commit, or "file a ticket or todo.org entry." The third disposition doesn't say *where* — which leaves the orchestrator picking a location ad-hoc. Result: follow-ups buried under children of an epic parent get orphaned when the parent closes, or follow-ups for standalone tasks scatter across the file with no convention. + +Proposed placement rule (already memorized for this project as =feedback_followups_as_siblings.md=, generalizing): + +- *Epic-style parent task* (level-2 with multiple level-3 children) → follow-ups file as level-2 *siblings* of the parent. Stays visible after parent closure. +- *Standalone task* (level-2 with no children, or a level-3 inside another structure) → follow-up files as a new level-2 top-level entry in the same =* Open Work= section. Don't nest under the originating task. + +Both cases: include a "Triggered by: <date> <task or commit>" line so a future reader sees what surfaced it. + +Update =.claude/commands/start-work.md= Phase 4 step 5's "Disposition for each candidate" section to spell this out. Update any cross-references in =commits.md= or other files that touch the discipline. + +Triggered by: 2026-05-15 fold-epic session — Craig flagged the gap mid-flight after I'd surfaced a follow-up but hadn't filed it. +** DONE [#A] Consolidate =.ai/= template infrastructure (fold + audit + install-ai + ratio) :feature: +CLOSED: [2026-05-15 Fri] + +End-state: one repo (=rulesets=) is the single source of truth for =.ai/= template content. =make audit= verifies and applies drift across every =.ai/=-using project on the machine. =make install-ai= bootstraps new projects. Same setup propagated to ratio so both machines run the same way. + +Today (2026-05-15) the canonical-source rule got violated again: rulesets commit =372fb76= added a wrap-up subsection to =rulesets= without going through =claude-templates= first, and the next session's startup rsync was about to silently undo it. Two-repo coordination is the root cause; fold solves it. + +Build order: fold first (others depend on the new canonical path), then audit + install-ai in parallel, then test, then propagate to ratio. + +*** DONE [#A] Fold =claude-templates= into rulesets +CLOSED: [2026-05-15 Fri] + +Two repos, one source of truth. =~/projects/claude-templates/= is the canonical =.ai/= template that gets rsync'd into every project at session start. Keeping it standalone means a second =git pull= in startup Phase A.0, a second remote to push to at wrap-up, and a split history any time a change touches both. Folding it into =rulesets/claude-templates/= gives one repo to clone on a fresh machine and one place to edit templates. + +**** Open design choices + +- *History.* =git subtree add --prefix=claude-templates ~/projects/claude-templates main= preserves the 84-commit history under the new prefix. Plain content copy (=cp -a= + =git add=) is simpler but loses history. Either is fine since the standalone repo stays archived on =cjennings.net=. +- *Layout.* =rulesets/claude-templates/= mirrors the old repo name and sits next to =claude-rules/= cleanly. Alternative: absorb =.ai/= directly under a different name (=rulesets/.ai-template/= or similar). First option is clearer. +- *bin/ai.* The standalone Makefile symlinks =$HOME/.local/bin/ai → bin/ai=. After the move, fold that into rulesets' Makefile as another install target. + +**** Mechanical steps + +1. Subtree-merge or copy =~/projects/claude-templates/= into =rulesets/claude-templates/=. +2. Update 3 references in rulesets: + - =.ai/protocols.org= line 163 — pointer in the "Let's run/do the X workflow" section. + - =.ai/workflows/cross-agent-comms.org= line 8 — promotion-target path. + - =.ai/workflows/startup.org= lines 22, 96-98 — Phase A.0 pull + Phase A rsync sources. +3. Update Phase A.0 of =startup.org= to pull rulesets instead of claude-templates. Inside rulesets sessions, the existing project-repo pull already covers it. Outside rulesets (every other project's session), Phase A.0 needs an explicit =git pull= on =~/code/rulesets/= before the rsync — otherwise the templates will be stale. +4. Replace =~/projects/claude-templates/= with a symlink to =~/code/rulesets/claude-templates/= for transition continuity. +5. After every active project has had one session start (and rsync'd the new =startup.org=), drop the symlink and archive =cjennings.net:git/claude-templates.git=. + +**** Bootstrap gap + +Every project on the machine has a =.ai/workflows/startup.org= that rsyncs from =~/projects/claude-templates/=. Until each project's startup.org gets refreshed (which happens via the rsync itself), the old path needs to keep resolving. The symlink at step 4 is the bridge: old paths resolve into the new location, the rsync delivers the updated startup.org, next session uses the new path directly. + +*** DONE [#A] Add =make audit= — drift detector across all =.ai/=-using projects +CLOSED: [2026-05-15 Fri] + +Companion to =make doctor= (single-machine scope, checks =~/.claude/=). =audit= is cross-project scope: walks every directory on the machine that has a =.ai/=, diffs the synced template files against the canonical source, and reports drift. =--apply= flag rsyncs the drift into the project's working tree (no auto-commit). Catches stale projects without forcing a session start in each one. + +**** Open design choices + +- *Scope.* Template-sync drift is the useful flavor: for each project, diff =.ai/protocols.org=, =.ai/workflows/=, =.ai/scripts/= against the canonical source. +- *Source path.* Post-fold: =~/code/rulesets/claude-templates/.ai/=. Build =audit= against the new path from day one. +- *Project discovery.* Walk =~/code/=, =~/projects/=, =~/.emacs.d/= up to depth 3 for any directory containing =.ai/=. Skip the canonical source itself. +- *Default mode is report-only.* =--apply= triggers rsync; =--force= overrides the dirty-skip safety. + +**** Per-project flow (designed 2026-05-15) + +For each discovered project, in order: + +1. Verify =.ai/= exists (path probe). If missing → =FAIL=, skip, continue loop. +2. Detect git tracking via =git check-ignore .ai/= → =tracked= or =gitignored=. +3. Verify no uncommitted =.ai/= changes (=git status --porcelain .ai/=). Dirty → =WARN=, skip rsync unless =--force=. +4. Verify content matches canonical via three =rsync -a --dry-run --itemize-changes= calls (=protocols.org=, =workflows/=, =scripts/=). Zero items = clean. +5. Action (=--apply= only, drift detected): three =rsync -a [--delete]= calls. +6. Verify rsync converged (re-run the dry-runs; zero now). +7. Verify working-tree state after rsync (tracked projects). Report deltas. Do not auto-commit. +8. Verify no unpushed =.ai/= commits (=git log @{u}..HEAD -- .ai/=). Informational only. + +**** Output format (mirrors =doctor=) + +#+begin_example +Claude-templates source: + ok rulesets/claude-templates is current (origin/main) + +Per-project .ai/ drift: + ok ~/projects/work + applied ~/projects/homelab 3 files changed + skipped ~/code/winvm uncommitted .ai/ (use --force) + ok ~/projects/clipper + +Summary: 18 ok, 3 applied, 1 skipped, 0 failed +#+end_example + +Exit code: =0= if all clean, no skips, no failures. =1= otherwise. + +**** Why not extend =make doctor= instead + +=doctor= has a clean meaning today: "is this machine's =~/.claude/= consistent with rulesets?" Mixing in cross-project =.ai/= drift muddies the exit code. Keep them separate. =audit= can optionally invoke =doctor= as its last check since both ask "did the symlinks keep up with the source?". A future =make all-checks= can wrap both. + +*** DONE [#A] Add =make install-ai PROJECT=<path>= — bootstrap =.ai/= in a fresh project +CLOSED: [2026-05-15 Fri] + +Separate target from =audit= because operating on projects that lack =.ai/= is a distinct action. The absence might be intentional, so =audit= skips them. Bootstrap is explicit opt-in. + +**** Flow + +1. Refuse if =.ai/= already exists in =PROJECT=. Message: "already installed; use =make audit --apply= to update." +2. Verify =PROJECT= is a git checkout (warn if not — works without git, loses some lifecycle benefits). +3. Create =PROJECT/.ai/= directory. +4. Rsync canonical content: =protocols.org=, =workflows/=, =scripts/= (same three rsyncs as =audit=). +5. Seed =PROJECT/.ai/notes.org= from a canonical template with project-name placeholder. +6. Create empty =PROJECT/.ai/sessions/= (with =.gitkeep= for tracked projects). +7. Track or gitignore =.ai/=? Default: ask. Flag: =--track= / =--gitignore=. +8. Print next-steps banner: =make install-lang LANG=<lang> PROJECT=<path>=; open Claude Code in the project. + +**** Symmetry with existing install targets + +#+begin_example +make install-lang LANG=python PROJECT=/path # language bundle (existing) +make install-ai PROJECT=/path # .ai/ template (new) +make install-lang # no args → fzf-pick +make install-ai # no args → fzf-pick from + # ~/projects/* + ~/code/* dirs + # without an existing .ai/ +#+end_example + +*** DONE [#A] Test plan for audit + install-ai before propagating to ratio +CLOSED: [2026-05-15 Fri] + +Test against the current state of this machine before pushing changes to ratio. + +**** =make audit= tests + +1. Dry-run report only (no =--apply=). Should show: claude-templates current; per-project drift; correct =ok=/=drift= classifications; summary line and exit code match. +2. After the fold lands, every project should be reported as drift (their =startup.org= still points at the old path). Run =--apply= → rsync converges. Re-run audit → all =ok=. +3. Manually edit one =.ai/workflows/foo.org= in a tracked project. Re-run audit → should report =skipped: uncommitted .ai/=. Run =--apply --force= → rsync clobbers the edit. Verify the edit is gone. +4. Manually delete one =.ai/= dir. Re-run audit → =FAIL: .ai/ missing=. Loop continues. +5. Idempotency: =--apply= twice in a row converges to all =ok= on the second pass. + +**** =make install-ai= tests + +1. Create =/tmp/test-fresh-project= as a git repo. Run =make install-ai PROJECT=/tmp/test-fresh-project=. Verify =.ai/= structure matches canonical, =notes.org= has placeholder, =sessions/= exists. +2. Run =make install-ai PROJECT=/tmp/test-fresh-project= again → should refuse (=.ai/= already exists). +3. Open Claude Code in the new project. Startup workflow runs cleanly (Phase A.0 + Phase A rsync should be a no-op since the install just ran). +4. fzf form: =make install-ai= with no args. Lists candidate dirs (=~/projects/*=, =~/code/*= without =.ai/=). + +**** Pass criteria + +- =audit= behavior matches the per-project flow spec for every classification path. +- =install-ai= produces a project indistinguishable from one that's been running sessions for a while. +- =make doctor= still passes 36/0/0 after all the work. +- =make test= (pytest + ERT) passes. + +*** DONE [#A] Migrate projects on ratio (second machine) +CLOSED: [2026-05-15 Fri] + +After local fold + audit + install-ai are working, propagate to ratio. + +**** Steps + +1. On ratio: =git -C ~/code/rulesets pull= — picks up the folded =claude-templates/= subdir and updated =Makefile= targets. +2. On ratio: archive or =mv= the standalone =~/projects/claude-templates/= aside, replace with symlink to =~/code/rulesets/claude-templates/= (same bridge mechanic as local). +3. On ratio: =make audit= → see drift across ratio's projects. +4. On ratio: =make audit --apply= → rsync into each tracked/gitignored project. Surface projects with uncommitted =.ai/= drift for manual handling. +5. On ratio: =make doctor= → catch any =~/.claude/= install drift (likely some, since ratio hasn't seen recent rulesets updates). +6. Verify by opening Claude Code in a few ratio projects. Startup should be a no-op or near-zero rsync. + +**** Known unknowns + +- Ratio may have its own project list overlapping with this machine's but not identical. =audit= discovers projects via the walk, so this is automatic. +- Ratio might have uncommitted =.ai/= work in some projects that this machine doesn't. =audit= surfaces them; handle case-by-case. +- If anything goes wrong, ratio's archived =~/projects/claude-templates/= is the safety net — restore the symlink target and re-run audit. + +**** Adjacent: cross-machine memory sync + +The =[#A] DOING= memory-sync investigation (todo.org:10) is adjacent. Both involve "make my Claude setup portable across machines." Coordinate so the memory-sync stow approach (if approved) doesn't conflict with this fold's symlink mechanics. |
