Repository navigation
Releases: yybd/repo-guards
Release list
RepoGuards 0.3.1
A patch, from a simulated-stranger re-test of 0.3.0. No blockers were found; these are the places where the guards and the README still disagreed.
The push refusal shows what it would have published
A refused foreign push now lists the commits it would have published — up to eight, then a count. When the branch is level with its upstream it says nothing is ahead; with no upstream it says git cannot tell.
- Before: the refusal pointed at
git log @{u}..HEADand left the looking to the agent — the one step a session about to push is least likely to take. - Four new pipeline checks cover the three cases.
README
- Ground Rule 4 quotes the Stop guard's real heading, "Work left open outside this session's own
git status", instead of a sentence it never printed. - Registering by hand: the entry goes inside the existing
projectsobject, beside the_example_*entries, which are ignored. - What deploy writes outside the repo: one
envvariable per place in~/.claude/settings.json, and nothing else. TheenabledPluginsandextraKnownMarketplacesentries there are Claude Code's own. - One
$BASEfor every command, including the try-it block. - Why
claude plugin listshows a commit hash rather than a version:plugin.jsondeclares none on purpose; releases are git tags. - "Upgrading from Grove" moved below "Known limits".
Also
- The shared rules say what
$SITEand$KEYS_ROOTare, and when each is absent. deploy.pylists the registered places by name.- Comments no longer name one machine's paths.
RepoGuards 0.3.0
This release fixes what a stranger-install test found when it followed the README to the letter.
The guard now protects every repo
Any git repository other than the one the session is standing in now counts as foreign, whether or not it is registered.
- Before: only repos in the registry counted. A
push,commit -aoradd .into a fresh, unregistered repo went through without a word, even though the README said the guards run everywhere. - Now: git decides. The target is foreign when its working tree (
git rev-parse --show-toplevel) differs from the session's. The registry only gives the repo a name. - Eight new pipeline checks cover unregistered repos.
Also
- Guard messages: they no longer quote the author's own incidents.
deploy.py:- when it fixes something, it now marks the fix "✓ done" instead of leaving a line that reads like a fault;
- it lists the hooks the next session will load;
- it counts anchor variables separately from repos;
- it writes
$GROVEonly on a machine that already had it, and$KEYS_ROOTonly once that folder exists.
close.py: prints its own full path.register-project: no longer tells you to commit the registry, which is gitignored machine data.- README:
- a prerequisites line;
- a "Try it in 60 seconds" section that runs the real hook with no session;
- how to register a repo by hand, as a three-line registry entry;
- what registration actually writes;
- a link to the
owns.jsonformat.
- Shared rules: the author's dated incidents are gone.
Upgrading
git -C <clone> pull
python3 <clone>/tools/deploy.pyThen open a new session.
RepoGuards 0.2.0 — formerly Grove
Grove is now RepoGuards. The product is RepoGuards. Every identifier is repo-guards:
- the repository,
yybd/repo-guards - the marketplace and the plugin,
repo-guards@repo-guards - the commands,
/repo-guards:deployand/repo-guards:register-project
The old GitHub address redirects.
Upgrading from 0.1.0
The marketplace and the plugin have new names, so an installed grove@grove is replaced rather than updated in place:
git -C <your clone> pull
claude plugin marketplace remove grove
claude plugin marketplace add "<your clone, absolute path>"
python3 <your clone>/tools/deploy.pyThen open a new session.
Renamed
| Before | Now |
|---|---|
$GROVE |
$REPO_GUARDS |
GROVE_* |
REPO_GUARDS_* |
grove_repo |
guards_repo |
~/.claude/.grove/ |
~/.claude/.repo-guards/ |
For one release, the old names keep working:
- deploy still writes
$GROVE - every
GROVE_*variable is still read as a fallback grove_repore-exportsguards_repo
App Factory 0.4.0 relies on these, and App Factory 0.4.1 no longer needs them.
Also
- The install instructions use an absolute path for
marketplace add. A relative path is read as a GitHubowner/repo, and the install fails. A clean-HOME install test hit this. - A personal
~/.claude/CLAUDE.mdcan import the shared rules with an@pathline instead of being a symlink to them. The staleness check accepts both forms.
grove 0.1.0
The first tagged release of grove: cross-repo guards for Claude Code.
What is in it
- Seven guards. Two of them block.
honor_ownershiprefuses a write to a path that another repo declared in its.claude/owns.json. It checks the writing tools and shell lines alike: redirections,sed -i,cp,mv,teeandrm.scope_foreign_commitsrefusescommit -a,add .andpushinto a repo the session is not standing in.- The other five report and do not block. For example: when a write into a foreign repo is allowed, it hands back that repo's
git status, and at the end of a turn it says what was left open elsewhere.
tools/close.pyreports every place the session touched. With--commitit commits in each of them only the paths this session wrote.tools/deploy.pyis the whole install. It writes the registry from the template, installs the plugin, and checks that everything is in place.
Install
git clone https://github.com/yybd/cross-repo-guards.git <base>/cross-repo-guards
claude plugin marketplace add <base>/cross-repo-guards
python3 <base>/cross-repo-guards/tools/deploy.pyThen open a new session.
Known limits
These are stated in the README, and the tests check that each one is still true:
- Writes a script makes from the inside are out of reach.
- A target the shell computes at run time is allowed.
- Every guard fails open.
Built for Claude Code, and tested only there. CI runs on macOS and Linux, with Python 3.9, 3.12 and 3.13.