Repository navigation
v1.21.2 — the guard asks the repository that owns the write - #24
Merged
Merged
Conversation
The PreToolUse guard decided whether coordination was on from the SESSION's
project (${CLAUDE_PROJECT_DIR:-$PWD}/.claude/agent-sync.json, hooks/_lib.sh
agent_sync_configured, called at the top of guard.sh) and then ran the check
somewhere else:
- a `git -C <repo> commit` / `cd <repo> && git commit` into a repository with
no config ran `agent_sync.py guard` there, which exits 2 for "no config";
the guard read that as "no lease" and blocked the commit
- an Edit in another repository ran the guard from the session's cwd, so the
path was resolved against the wrong root and the wrong guardedFiles applied
- a session whose own project has no config guarded nothing at all
Now agent_sync_owner (hooks/_lib.sh) resolves `git -C <dir> rev-parse
--show-toplevel` — the file's nearest existing directory, or the commit's
-C/cd target — and the check runs from that toplevel only when it carries its
own config; otherwise, and for a path in no repository, the guard allows.
Fail-closed on a missing python3 (and now git) is kept for configured
sessions; a payload without `commit` skips the commit tokeniser.
- check_guard_asks_the_repository_that_owns_the_file: 15 cases through the
real hook, 7 failed on 1.21.1, all pass
- self-test plants: the session lookup and the early exit put back; both caught
- lifecycle hooks (SessionStart/renew/SessionEnd) unchanged: they act on the
session's run in the session's project; cross-repo lease renewal stays AS-07
- docs: hooks.md, README, SKILL.md, SECURITY.md, hooks.json description,
CHANGELOG, verification ledger, backlog
Gate: npm test EXIT=0 — validate PASS v1.21.2 (also on Python 3.9.6),
SELF-TEST PASS (66 fixtures), claim cell 27, session hooks 13, installer 11;
audit regressions pass; evals OK; pinned house audit 0 GAP / 18 PASS;
claude plugin validate --strict passed for . and plugins/agent-sync.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
PreToolUseguard decided whether coordination was on from the session's project and then ran the check in a different repository. Three effects, each reproduced against 1.21.1:git -C <repo> commit(orcd <repo> && git commit) into a repository with no.claude/agent-sync.jsonwas blocked:agent_sync.py guardthere exits 2 for "no config", and the guard read that as "no lease";../other/docs/ROADMAP.md) and the session'sguardedFilesapplied instead of the other repository's;Root cause.
plugins/agent-sync/hooks/guard.sh:32(1.21.1)agent_sync_configured || exit 0, wherehooks/_lib.sh:36checks${CLAUDE_PROJECT_DIR:-$PWD}/.claude/agent-sync.json; thenguard.sh:126ran(cd "$repo" && python3 "$S" guard "$staged")for a commit, andguard.sh:135ranpython3 "$S" guard "$path"from the session's cwd for an edit.Fix.
agent_sync_owner(hooks/_lib.sh) resolvesgit -C <dir> rev-parse --show-toplevel(the file's nearest existing directory for Edit/Write, the-C/cdtarget for a commit) and returns it only when that toplevel carries its own config. No config, or no repository, means allowed; otherwiseagent_sync.py guardruns from that toplevel. A missing python3 or git still fails closed in a configured session. A Bash payload withoutcommitnow exits before the commit tokeniser starts, because the guard runs in every session now. The lifecycle hooks (SessionStart, renew, SessionEnd) are unchanged: they act on the session's run in the session's project. Renewing leases taken in a second repository is still open as AS-07.Tests. I wrote
check_guard_asks_the_repository_that_owns_the_filefirst. It runs 15 cases through the real hook, and 7 of them failed on 1.21.1. All 15 pass now. Two self-test plants were added and both are caught: one puts the session lookup back inagent_sync_owner, the other restores the early exit on the session's config.Gate (local).
npm testEXIT=0: validate PASS v1.21.2 (also on Python 3.9.6), SELF-TEST PASS (66 fixtures), claim cell 27, session hooks 13, installer 11. Audit regressions pass, evals OK, pinned house audit 0 GAP / 18 PASS (body 4744/4750 tokens).claude plugin validate --strictpassed for.andplugins/agent-sync.🤖 Generated with Claude Code