diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-05 00:28:31 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-05 00:28:31 -0500 |
| commit | 3eed2895b2d23d1d8e468aee6f3dfd8122012fe4 (patch) | |
| tree | 51bab603c833cf8732ae30bf5e189e476fa14594 | |
| parent | 4779ce8a64560e68b34311ced309013c50706d39 (diff) | |
| download | rulesets-3eed2895b2d23d1d8e468aee6f3dfd8122012fe4.tar.gz rulesets-3eed2895b2d23d1d8e468aee6f3dfd8122012fe4.zip | |
feat(startup): run make install in Phase A.0 to link new skills
A skill added to rulesets and pushed reached each machine's files on the next pull, but not its ~/.claude symlink. make install only links what isn't already linked, and a git pull doesn't run it. So a new skill stayed silently uninstalled until someone re-ran make install by hand. The flush skill sat in that gap from 2026-06-02 until a manual install today.
I added a make install step right after the Phase A.0 rulesets pull, the step that brings the skill's files in. It's idempotent: skips already-linked targets, links only what's new, and only writes symlinks under ~/.claude and ~/.local/bin. A grep keeps the all-skip case to one quiet line. Link, relink, and WARN lines get surfaced, and a new Phase C bullet handles them: a skill the harness already picked up mid-session is noted as available, one it didn't gets a restart prompt, a non-symlink collision goes to the user.
Now "add a skill, commit, push" is enough to reach every machine on the next session. The step also covers a newly-added rule or script, since make install links those too. The canonical template and the .ai/ mirror both carry the change.
| -rw-r--r-- | .ai/workflows/startup.org | 19 | ||||
| -rw-r--r-- | claude-templates/.ai/workflows/startup.org | 19 |
2 files changed, 38 insertions, 0 deletions
diff --git a/.ai/workflows/startup.org b/.ai/workflows/startup.org index 16e983d..e630460 100644 --- a/.ai/workflows/startup.org +++ b/.ai/workflows/startup.org @@ -44,6 +44,24 @@ Behavior: - *Dirty working tree* → skip the pull. Don't auto-stash and don't auto-merge — those would either lose work or invite conflicts at the worst possible moment (session start). - *Non-fast-forward history* → =--ff-only= aborts with an error. Surface that to the user; the rsync still proceeds against the working tree as-is. +*** Install rulesets symlinks into ~/.claude (idempotent) + +A skill, rule, or bin script added to rulesets and pushed reaches each machine's *files* on the next pull, but not its =~/.claude= *symlink* — =make install= only links what isn't already linked, and =git pull= doesn't run it. So a newly-added skill stays silently uninstalled until someone re-runs =make install= by hand. The flush skill sat in that gap from 2026-06-02 until a manual install on 2026-06-05. Running =make install= here, right after the rulesets pull, closes it: "add a skill, commit, push" becomes enough for it to reach every machine on the next session. + +=make install= is idempotent — it skips every already-linked target, links only what's new, WARNs on a non-symlink collision, and only ever writes symlinks under =~/.claude= and =~/.local/bin=, so it's safe and reversible. It covers skills, rules, claude config, and bin scripts in one pass, so the same step also picks up a newly-added rule or script, not just a skill. + +#+begin_src bash +if [ -d "$HOME/code/rulesets" ]; then + make -C "$HOME/code/rulesets" install 2>&1 \ + | grep -E '^[[:space:]]+(link|relink|WARN)' \ + || echo "make install: nothing new to link" +else + echo "rulesets: not present — skipping make install" +fi +#+end_src + +The =grep= keeps the all-skip case quiet — a clean machine prints only "nothing new to link". Any =link= / =relink= / =WARN= line is surfaced for Phase C to act on. The placement mirrors the rulesets-pull dependency: the pull brings a new skill's files in, so the install that links them belongs immediately after. It runs in every project's session, not just rulesets sessions, which is the point — the link reaches whatever machine the session is on. + *** Refresh project repo (cwd) Pull down whatever's been pushed to the project's remotes since the last session — could be commits Craig made on another machine, teammate pushes, or any branch that advanced upstream. Without this, the session starts from a stale local view and any new branch work happens on top of an out-of-date base. @@ -166,6 +184,7 @@ This phase touches the user and runs sequentially: - Briefly note significant template updates noticed during sync (new workflows, protocol changes). - *Task-review nudge.* If the Phase A staleness count (step 11) is greater than zero, surface one line: "=<N>= top-level tasks unreviewed for >7 days — say 'let's do a task review' to run a cycle." If zero, say nothing. - *Language-bundle sync.* If the Phase A step-12 call (=sync-language-bundle.sh=) printed anything, surface it. =fixed= lines are informational — the drift was already repaired (note that =.claude/= is now dirty if the project commits it). A =drift= line on =settings.json= is surface-only and needs the printed =make install-<lang> PROJECT=.= to reconcile; flag it so the user can decide. If the call was silent, say nothing. + - *Newly-installed symlinks.* If the Phase A.0 =make install= step printed any =link= / =relink= / =WARN= line, surface it. A =link= line means a skill, rule, or script added to rulesets is now linked into =~/.claude= for the first time on this machine. For a newly-linked *skill*, check the agent's available-skills list: if the harness already registered it mid-session, note it's available and move on; if it's absent, stop and tell Craig to restart the agent so it loads (whether a mid-session reload works is harness-version-dependent). A =WARN ... not a symlink= line is a real collision at the target path — surface it; it needs a human. If the step printed only "nothing new to link", say nothing. - *Template-sync churn (safety net).* Check whether Phase A's rsync left uncommitted churn in the synced =.ai/= paths — accumulated from a prior session that crashed before wrap-up, or freshly added this session when rulesets advanced. Without surfacing, it builds up silently until it blocks Phase A.0's auto-ff (git won't ff a dirty tree). Skip in the rulesets repo itself (there =.ai/= is a committed mirror, kept honest by the pre-commit hook). The check is sequential here, after the rsync has finished — not a Phase A step, to keep that batch race-free. #+begin_src bash diff --git a/claude-templates/.ai/workflows/startup.org b/claude-templates/.ai/workflows/startup.org index 16e983d..e630460 100644 --- a/claude-templates/.ai/workflows/startup.org +++ b/claude-templates/.ai/workflows/startup.org @@ -44,6 +44,24 @@ Behavior: - *Dirty working tree* → skip the pull. Don't auto-stash and don't auto-merge — those would either lose work or invite conflicts at the worst possible moment (session start). - *Non-fast-forward history* → =--ff-only= aborts with an error. Surface that to the user; the rsync still proceeds against the working tree as-is. +*** Install rulesets symlinks into ~/.claude (idempotent) + +A skill, rule, or bin script added to rulesets and pushed reaches each machine's *files* on the next pull, but not its =~/.claude= *symlink* — =make install= only links what isn't already linked, and =git pull= doesn't run it. So a newly-added skill stays silently uninstalled until someone re-runs =make install= by hand. The flush skill sat in that gap from 2026-06-02 until a manual install on 2026-06-05. Running =make install= here, right after the rulesets pull, closes it: "add a skill, commit, push" becomes enough for it to reach every machine on the next session. + +=make install= is idempotent — it skips every already-linked target, links only what's new, WARNs on a non-symlink collision, and only ever writes symlinks under =~/.claude= and =~/.local/bin=, so it's safe and reversible. It covers skills, rules, claude config, and bin scripts in one pass, so the same step also picks up a newly-added rule or script, not just a skill. + +#+begin_src bash +if [ -d "$HOME/code/rulesets" ]; then + make -C "$HOME/code/rulesets" install 2>&1 \ + | grep -E '^[[:space:]]+(link|relink|WARN)' \ + || echo "make install: nothing new to link" +else + echo "rulesets: not present — skipping make install" +fi +#+end_src + +The =grep= keeps the all-skip case quiet — a clean machine prints only "nothing new to link". Any =link= / =relink= / =WARN= line is surfaced for Phase C to act on. The placement mirrors the rulesets-pull dependency: the pull brings a new skill's files in, so the install that links them belongs immediately after. It runs in every project's session, not just rulesets sessions, which is the point — the link reaches whatever machine the session is on. + *** Refresh project repo (cwd) Pull down whatever's been pushed to the project's remotes since the last session — could be commits Craig made on another machine, teammate pushes, or any branch that advanced upstream. Without this, the session starts from a stale local view and any new branch work happens on top of an out-of-date base. @@ -166,6 +184,7 @@ This phase touches the user and runs sequentially: - Briefly note significant template updates noticed during sync (new workflows, protocol changes). - *Task-review nudge.* If the Phase A staleness count (step 11) is greater than zero, surface one line: "=<N>= top-level tasks unreviewed for >7 days — say 'let's do a task review' to run a cycle." If zero, say nothing. - *Language-bundle sync.* If the Phase A step-12 call (=sync-language-bundle.sh=) printed anything, surface it. =fixed= lines are informational — the drift was already repaired (note that =.claude/= is now dirty if the project commits it). A =drift= line on =settings.json= is surface-only and needs the printed =make install-<lang> PROJECT=.= to reconcile; flag it so the user can decide. If the call was silent, say nothing. + - *Newly-installed symlinks.* If the Phase A.0 =make install= step printed any =link= / =relink= / =WARN= line, surface it. A =link= line means a skill, rule, or script added to rulesets is now linked into =~/.claude= for the first time on this machine. For a newly-linked *skill*, check the agent's available-skills list: if the harness already registered it mid-session, note it's available and move on; if it's absent, stop and tell Craig to restart the agent so it loads (whether a mid-session reload works is harness-version-dependent). A =WARN ... not a symlink= line is a real collision at the target path — surface it; it needs a human. If the step printed only "nothing new to link", say nothing. - *Template-sync churn (safety net).* Check whether Phase A's rsync left uncommitted churn in the synced =.ai/= paths — accumulated from a prior session that crashed before wrap-up, or freshly added this session when rulesets advanced. Without surfacing, it builds up silently until it blocks Phase A.0's auto-ff (git won't ff a dirty tree). Skip in the rulesets repo itself (there =.ai/= is a committed mirror, kept honest by the pre-commit hook). The check is sequential here, after the rsync has finished — not a Phase A step, to keep that batch race-free. #+begin_src bash |
