aboutsummaryrefslogtreecommitdiff
path: root/claude-templates
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-30 14:18:44 -0500
committerCraig Jennings <c@cjennings.net>2026-05-30 14:18:44 -0500
commit968a39bb3978e6ad499447ce173e2265dee772a2 (patch)
tree65632f3b0e6baaf5b4d65ee3aea67b1c8b2125f5 /claude-templates
parent9c9af9002d2d3b4f21c9a55480b9e5f1aa0f0acd (diff)
downloadrulesets-968a39bb3978e6ad499447ce173e2265dee772a2.tar.gz
rulesets-968a39bb3978e6ad499447ce173e2265dee772a2.zip
fix(startup): exclude Python cache from script sync and restore script exec bits
From health's handoff: the startup =.ai/scripts/= sync was dragging pytest build artifacts into every consuming project. =rsync -a= copies by disk presence, not git status, so the =__pycache__/= and =.pytest_cache/= that rulesets' own pytest leaves in =claude-templates/.ai/scripts/tests/= rode along to each project's tree even though the root =.gitignore= already keeps them out of rulesets' commits. Phase A's scripts rsync now excludes =__pycache__=, =.pytest_cache=, and =*.pyc=. A project that already received the cache has to remove it once by hand, since =--delete= leaves excluded paths in place. I noted that in the startup doc. Health also flagged that =inbox-send.py= kept needing a manual chmod. The cause wasn't rsync dropping the bit. Four shebang scripts (=inbox-send.py=, =cj-scan.py=, =cj-remove-block.py=, =eml-view-and-extract-attachments.py=) were committed mode 100644, so rsync faithfully copied the wrong mode. I set the exec bit on all four so the synced copies are runnable.
Diffstat (limited to 'claude-templates')
-rwxr-xr-x[-rw-r--r--]claude-templates/.ai/scripts/cj-remove-block.py0
-rwxr-xr-x[-rw-r--r--]claude-templates/.ai/scripts/cj-scan.py0
-rwxr-xr-x[-rw-r--r--]claude-templates/.ai/scripts/eml-view-and-extract-attachments.py0
-rwxr-xr-x[-rw-r--r--]claude-templates/.ai/scripts/inbox-send.py0
-rw-r--r--claude-templates/.ai/workflows/startup.org3
5 files changed, 2 insertions, 1 deletions
diff --git a/claude-templates/.ai/scripts/cj-remove-block.py b/claude-templates/.ai/scripts/cj-remove-block.py
index 71c7b3d..71c7b3d 100644..100755
--- a/claude-templates/.ai/scripts/cj-remove-block.py
+++ b/claude-templates/.ai/scripts/cj-remove-block.py
diff --git a/claude-templates/.ai/scripts/cj-scan.py b/claude-templates/.ai/scripts/cj-scan.py
index 275f5ca..275f5ca 100644..100755
--- a/claude-templates/.ai/scripts/cj-scan.py
+++ b/claude-templates/.ai/scripts/cj-scan.py
diff --git a/claude-templates/.ai/scripts/eml-view-and-extract-attachments.py b/claude-templates/.ai/scripts/eml-view-and-extract-attachments.py
index dad6457..dad6457 100644..100755
--- a/claude-templates/.ai/scripts/eml-view-and-extract-attachments.py
+++ b/claude-templates/.ai/scripts/eml-view-and-extract-attachments.py
diff --git a/claude-templates/.ai/scripts/inbox-send.py b/claude-templates/.ai/scripts/inbox-send.py
index 5373bd4..5373bd4 100644..100755
--- a/claude-templates/.ai/scripts/inbox-send.py
+++ b/claude-templates/.ai/scripts/inbox-send.py
diff --git a/claude-templates/.ai/workflows/startup.org b/claude-templates/.ai/workflows/startup.org
index b552b96..0cd7b88 100644
--- a/claude-templates/.ai/workflows/startup.org
+++ b/claude-templates/.ai/workflows/startup.org
@@ -97,7 +97,7 @@ These calls have no dependencies on each other. Issue them all together in one m
2. Check whether =.ai/session-context.org= exists (e.g. =[ -e .ai/session-context.org ] && echo present || echo absent=).
3. =rsync -a ~/code/rulesets/claude-templates/.ai/protocols.org .ai/protocols.org=.
4. =rsync -a --delete ~/code/rulesets/claude-templates/.ai/workflows/ .ai/workflows/=.
-5. =rsync -a --delete ~/code/rulesets/claude-templates/.ai/scripts/ .ai/scripts/=.
+5. =rsync -a --delete --exclude='__pycache__' --exclude='.pytest_cache' --exclude='*.pyc' ~/code/rulesets/claude-templates/.ai/scripts/ .ai/scripts/=.
6. =\ls -t .ai/sessions/ 2>/dev/null | head -5= — list 5 most recent session files. The backslash bypasses any =ls= alias in the user's profile. Without it, bare =ls -t= silently returns no output under =exa= (a common =ls= replacement) — which makes a sessions directory full of files look empty, and the agent then skips Phase B step 2.
7. =\ls -la inbox/ 2>/dev/null= — inventory the inbox. Same reason for the backslash escape, applied uniformly across the Phase A =ls= calls.
8. =cross-agent-status 2>/dev/null || true= — snapshot of pending cross-agent messages across local projects. This is layer A of the cold-start design from =cross-agent-comms.org=: pending messages from other agents (delivered while no session was active here) get surfaced on session start. The =|| true= keeps Phase A from failing if =cross-agent-status= isn't installed yet — older projects without the script still boot cleanly. If HALT is active, =cross-agent-status= prints a banner; surface that prominently in Phase C.
@@ -110,6 +110,7 @@ Notes on the rsync commands:
- Trailing slashes on both source and destination matter — they tell rsync to sync /contents/ rather than nest a directory inside.
- =--delete= on the directory syncs lets retired template files actually disappear from each project on next startup.
- protocols.org is a single file, no =--delete= needed.
+- The =scripts/= sync excludes Python build artifacts (=__pycache__/=, =.pytest_cache/=, =*.pyc=). Running rulesets' own pytest leaves these in =claude-templates/.ai/scripts/tests/=, and =rsync -a= copies by disk presence regardless of =.gitignore=, so without the excludes every consuming project's tree gets polluted with machine-specific cache files. The excludes also protect existing dest copies from =--delete= cleanup, so a project that already received the cache must remove it once by hand.
- The sync touches only =protocols.org=, =workflows/=, and =scripts/=. The project-owned dirs =project-workflows/= and =project-scripts/= are deliberately *outside* the synced set, so a project's own workflows and scripts survive startup. This is why a project script that a workflow imports must live in =.ai/project-scripts/=, never =.ai/scripts/= — the latter is wiped to match the template by =--delete= on every startup. Naming: a script imported as a Python module needs an importable name (underscores, e.g. =zlibrary_api.py=); a CLI-invoked script can stay kebab-case like the template tooling (=cmail-action.py=).
Rationale: Every call in Phase A is read-only or writes to a distinct path. Running them sequentially wastes round-trips; running them in parallel gives Claude the complete starting picture in one round-trip.