Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 1 addition & 56 deletions .github/workflows/firewall_gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,6 @@ name: Tenant Firewall Gate
# every existing leg. The decision reads the PR's diff, not its body, so a PR with no
# `Brain-ref:` line gets the skip exactly as one with it does.
#
# TEMPORARY third skip (PyAutoMind#482): the 'CLAUDE.md → AGENTS.md pointers'
# leg now requires NO CLAUDE.md beside an AGENTS.md, and the organ mains keep
# the retired pointer until the human-dispatched propagation wave removes it,
# so the leg is dropped from BOTH drift checks (PR and push) with a loud
# banner, and PyAutoMind's own absence of a CLAUDE.md is asserted instead.
# Remove when the CLAUDE.md retirement wave has run (session_hook_propagate
# dispatch) — tracked on PyAutoMind#482.
#
# All three organs are checked out. PyAutoHands was omitted at first — its
# firewall clear waited behind the version-stamp task that claimed the repo
# (PyAutoHands#235) — and joined once that leg landed as PyAutoHands#237,
Expand Down Expand Up @@ -192,44 +184,13 @@ jobs:
python3 PyAutoMind/scripts/repos_sync.py --check --root "$GITHUB_WORKSPACE" \
--only "shared-standards blocks (generated)" --repo PyAutoMind

# TEMPORARY: remove when the CLAUDE.md retirement wave has run
# (session_hook_propagate dispatch) — tracked on PyAutoMind#482.
# The compensating control for the pointer-leg skip in both drift checks
# below: propagation never writes PyAutoMind, so its own absence of a
# CLAUDE.md is the PR's to keep, and the retirement logic is pinned here.
- name: Assert PyAutoMind carries no CLAUDE.md (TEMPORARY, PyAutoMind#482)
run: |
pip install pytest
if [ -e PyAutoMind/CLAUDE.md ]; then
echo "::error::PyAutoMind/CLAUDE.md exists — it hides AGENTS.md from Claude Code (PyAutoMind#482)"
exit 1
fi
python3 -m pytest PyAutoMind/tests/test_repos_sync_structure_lint.py -q \
-k "claude_md or pointer or removal"

- name: Drift check (canonical-hook or where-to-file PR — unmeetable legs skipped)
if: steps.hookpr.outputs.hook_pr == 'true' || steps.hookpr.outputs.filing_pr == 'true'
env:
HOOK_PR: ${{ steps.hookpr.outputs.hook_pr }}
FILING_PR: ${{ steps.hookpr.outputs.filing_pr }}
run: |
skip=()
# TEMPORARY: remove when the CLAUDE.md retirement wave has run
# (session_hook_propagate dispatch) — tracked on PyAutoMind#482.
echo "=============================================================="
echo "SKIPPED LEG (TEMPORARY): 'CLAUDE.md → AGENTS.md pointers'"
echo "WHY: PyAutoMind#482 inverted this leg — a repo with AGENTS.md must"
echo " have NO CLAUDE.md — and the sibling organs are checked out at"
echo " their mains, which still carry the retired pointer until the"
echo " human-dispatched .github/workflows/session_hook_propagate.yml"
echo " wave removes it. The leg's precondition is unmeetable until then,"
echo " on pull requests AND on push to main."
echo "STILL ENFORCED: PyAutoMind itself carries no CLAUDE.md, and the"
echo " retirement logic is pinned by its tests (asserted in the step"
echo " above). Remove this skip when the CLAUDE.md retirement wave has"
echo " run (session_hook_propagate dispatch) — tracked on PyAutoMind#482."
echo "=============================================================="
skip+=(--skip "CLAUDE.md → AGENTS.md pointers")
if [ "$HOOK_PR" = "true" ]; then
echo "=============================================================="
echo "SKIPPED LEG: 'generated hooks (session-start + end-at-deliverable)'"
Expand Down Expand Up @@ -270,20 +231,4 @@ jobs:
- name: Drift check (all legs — absent repos are skipped)
if: steps.hookpr.outputs.hook_pr != 'true' && steps.hookpr.outputs.filing_pr != 'true'
run: |
# TEMPORARY: remove when the CLAUDE.md retirement wave has run
# (session_hook_propagate dispatch) — tracked on PyAutoMind#482.
echo "=============================================================="
echo "SKIPPED LEG (TEMPORARY): 'CLAUDE.md → AGENTS.md pointers'"
echo "WHY: PyAutoMind#482 inverted this leg — a repo with AGENTS.md must"
echo " have NO CLAUDE.md — and the sibling organs are checked out at"
echo " their mains, which still carry the retired pointer until the"
echo " human-dispatched .github/workflows/session_hook_propagate.yml"
echo " wave removes it. The leg's precondition is unmeetable until then,"
echo " on pull requests AND on push to main."
echo "STILL ENFORCED: PyAutoMind itself carries no CLAUDE.md, and the"
echo " retirement logic is pinned by its tests (asserted in the step"
echo " above). Remove this skip when the CLAUDE.md retirement wave has"
echo " run (session_hook_propagate dispatch) — tracked on PyAutoMind#482."
echo "=============================================================="
python3 PyAutoMind/scripts/repos_sync.py --check --root "$GITHUB_WORKSPACE" \
--skip "CLAUDE.md → AGENTS.md pointers"
python3 PyAutoMind/scripts/repos_sync.py --check --root "$GITHUB_WORKSPACE"
29 changes: 19 additions & 10 deletions .github/workflows/session_hook_propagate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,16 @@ name: Propagate the canonical hooks
# carries real guidance. It runs only on `workflow_dispatch`, never on the push
# trigger, so the deletion wave is always a human act: dispatch with
# `dry_run: true` first (the diffs are reported, nothing is pushed), then for
# real. Only a tracked CLAUDE.md that the function removed is staged; nothing
# else about what the job writes changes. Repos outside its reach are cleaned
# by hand: PyAutoMind (never a target, below) and every repo carrying
# `session_hook: false` (not a target either).
# real. The removal covers each repo's root AND every tracked folder below it
# whose CLAUDE.md sits beside an AGENTS.md (PyAutoMind#484 — a session started
# inside such a folder loses every ancestor AGENTS.md). Only a tracked
# CLAUDE.md that the function removed is staged — the job reads them back from
# `git ls-files --deleted`, since nothing else here deletes a file; nothing else
# about what the job writes changes. Repos outside its reach are cleaned by
# hand: PyAutoMind (never a target, below) and any repo carrying
# `session_hook: false` (not a target either). None needs it today: PyAutoMind
# carries no CLAUDE.md, and euclid_assistant — the one `session_hook: false`
# repo — was hand-cleaned (a39e35c).

on:
push:
Expand Down Expand Up @@ -220,12 +226,15 @@ jobs:
for rel in .claude/hooks/session-start.sh .claude/hooks/end-at-deliverable.sh .claude/settings.json .codex/hooks.json AGENTS.md; do
[ -e "$repo/$rel" ] && git -C "$repo" add -- "$rel"
done
# Stage the pointer's deletion only: a tracked CLAUDE.md that is now
# gone was removed by remove_claude_md_pointers (nothing else here
# deletes files). A content-bearing one is still on disk, unstaged.
if [ ! -e "$repo/CLAUDE.md" ] && git -C "$repo" ls-files --error-unmatch -- CLAUDE.md >/dev/null 2>&1; then
git -C "$repo" rm --cached --quiet -- CLAUDE.md
fi
# Stage the pointers' deletions only — at the root and in every
# nested folder: a tracked CLAUDE.md that is now gone was removed by
# remove_claude_md_pointers (nothing else here deletes files). A
# content-bearing one is still on disk, unstaged. On a push run the
# removal never ran, so this stages nothing.
git -C "$repo" ls-files -z --deleted -- CLAUDE.md '*/CLAUDE.md' \
| while IFS= read -r -d '' gone; do
git -C "$repo" rm --cached --quiet -- "$gone"
done

# A repo that .gitignore's .claude/ would have `git add` skip the
# file in silence, and this job would then report it "current" while
Expand Down
1 change: 1 addition & 0 deletions docs/pyautobrain/spawn_spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ not. A new organism adopts delivery deliberately after configuring its manifest.
|---|---------|--------|
| 1 | `bibliography/README.md`, `scripts/`, `tests/`, `Makefile`, `LICENSE`, `AGENTS.md`, `CLAUDE.md`, `.gitignore` | KEEP verbatim (tooling + schema + policy; `CLAUDE.md` is the same tolerant leftover as the Mind table's rule 2 — retired, PyAutoMind#482 — scripts/tests are the citation-validation + knowledge-board tooling the Makefile drives; the former `bibliography/*.py` pattern matched nothing and was retired in #32). **Exception:** `scripts/wikilink_baseline.txt` → DROP (checked before `scripts/`) — it is the instance's wikilink ratchet baseline, naming this organism's own sub-wiki pages; `read_baseline()` treats an absent file as empty, so a fresh repo starts from a zero baseline |
| 1b | `AI_POLICY.md`, `CONTRIBUTING.md` (root — the #32 `.github/` move undone with the Mind's, #253) | KEEP with owner substitution — same org-wide pointer docs as the Mind table's rule 3b |
| 1c | `skills/**` | KEEP verbatim — the Memory's own agent skills (today `skills/catch_up/`, added by PyAutoMemory 047ec2b) are generic organism skills, the same class as the Mind table's rule 8 (`skills/**` KEEP). Generic by contract: the canary scan still grades every kept file, so a skill that names instance content fails the run rather than shipping (PyAutoMind#484) |
| 2 | `bibliography/*.bib` and any bibliography data files | EMPTY → file kept with header comment ("populated by your literature") |
| 3 | `wiki/AGENTS.md` (the canonical shared schema), and `wiki/CLAUDE.md` only while a source still carries one | KEEP verbatim — since the wiki/ restructure (PyAutoMemory#24) the schema is a single domain-neutral file at `wiki/AGENTS.md`, kept canary-clean at the source (its examples carry no instance tokens), so spawn no longer maintains a duplicate schema asset. The thin `wiki/CLAUDE.md` adapter is retired (PyAutoMind#482): Claude Code reads `AGENTS.md` natively, and any `CLAUDE.md` would hide it; the KEEP pattern stays only so a source mid-retirement still spawns cleanly |
| 4 | `wiki/*` (all live sub-wikis, all pages) | DROP; generate instead ONE `wiki/example/` containing a slim scope-only `AGENTS.md` (the schema is inherited from rule 3, not copied; no `CLAUDE.md` adapter is generated — retired, PyAutoMind#482), an `index.md` skeleton listing zero sources, and one `sources/EXAMPLE_stub.md` demonstrating the stub format (hand-written once, stored inside spawn as a heredoc/template asset — not copied from live content) |
Expand Down
Loading
Loading