Setting a repository up and taking SpecSheriff out of it
sheriff init sets a repository up for the SpecSheriff tools. It writes the git hooks into .githooks/ (§s-4mej6ccn7xu3d3p); stages with the executable mode, 100755, each hook there that holds what it would write and that git's index does not already hold with that mode, naming each one, or, where it cannot stage a hook, names it and says how to stage it executable; and turns them on.
For the agent --agent names, claude or codex, claude where the option is not given, sheriff init adds the marketplace and the plugin to .claude/settings.json as a project declares them (§s-zh2vcr3xjumppg5), keeping every other key there, or writes the agent's hooks for Codex into .codex/hooks.json (§s-n76wt2bkqdmh78x), keeping every other hook there. It refuses another name, naming the two it takes.
Where they are missing, sheriff init writes a sheriff.config.json and a specs/_guidelines/project.json naming as the specification's owner the email git is configured with. It replaces a hook or a declaration that holds what an earlier release of sheriff init wrote, naming each, and no other file that differs from what it would write, naming each one instead; so run again it changes nothing. A hook or a declaration holds what an earlier release wrote where, line endings aside, it equals one of the texts the earlier releases wrote, which the SpecSheriff tools keep.
sheriff remove takes out of a repository what sheriff init writes outside specs/, for both agents: each git hook, the marketplace and the plugin in .claude/settings.json and the agent's hooks for Codex in .codex/hooks.json, where each holds what sheriff init writes now or wrote in an earlier release; core.hooksPath where it names .githooks; a key left holding nothing, a file left holding no key, and .githooks/, .claude/ or .codex/ where that leaves it empty; and sheriff.config.json, whatever it holds. It leaves each hook and declaration that differs, naming it, and leaves specs/ as it is, naming it. It stages nothing, and run again it changes nothing.
On a system whose files keep an executable bit, git runs a hook only where its file has the bit, and a clone checks a file out with the mode its commit records. Git takes that mode from the file when it stages it where files keep the bit, and records it as not executable where they keep none, as on Windows, where git runs a hook whatever its mode; so a hook set up there would reach the clones unable to run, and nothing on the machine that set it up would show it. A mode reaches the clones only staged and committed, and git stages a mode only with the file's content, so sheriff init stages the hooks it holds and nothing else: what else a commit holds stays its author's choice.
Claude Code reads its plugin from .claude/settings.json and Codex its hooks from .codex/hooks.json, so sheriff init writes for the agent the project is set up with, and a project moving to another agent runs it again for that one. A hook or a declaration written by an earlier release is the tools' own, so it is replaced; one that differs otherwise was changed by hand and is the project's.
sheriff remove takes out what sheriff init writes and no more. sheriff.config.json goes whatever it holds, because a repository holding it is one the plugins act in (§s-zh2vcr3xjumppg5) and its settings serve only the tools; specs/ stays, being the project's own content. What sheriff remove takes out is in git's history, and what a commit holds stays its author's choice, so it stages nothing.
The links it makes
- implements → What is checked, when, and what a failure costs
- implements → Where an agent writes, the checks run at each of its edits
- implements → A procedure that writes the specification is idempotent
- cites → A git hook runs the SpecSheriff tools a plugin keeps on the machine
- cites → The plugin for Claude Code carries everything its work needs
- cites → The agent's hooks for Codex CLI
The links made to it
The decisions taken on it
- Problem
sheriff init made the hooks executable with chmod, which git on Windows does not see, so a project set up there committed them as not executable, and a clone on Linux or macOS ran none of its checks, git skipping each hook with a hint: the worked example's recorded run went through there unrefused.
- Ruling
The owner: sheriff init stages each hook it holds with the executable mode where git's index does not already hold it so, naming each, and nothing else, and where it cannot stage a hook says how to.
The tests bound to it
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init --agent codex writes the agent's hooks for Codex beside every other hook there, and declares nothing to Claude Code
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init declares the marketplace and the plugin beside every other key of the agent's settings
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init refuses an agent it does not know, naming the two it takes
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init replaces a hook an earlier release of it wrote, line endings aside, naming each
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init replaces no file that differs from what it would write, and names it
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init stages again with the executable mode a hook git's index holds without it
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init stages each hook it holds with the executable mode, naming each, where files keep no such bit, and stages nothing else
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init writes the git hooks and turns them on, declares the marketplace and the plugin, and starts the settings and the project's guidelines
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff init, where it cannot stage a hook, names it and says how to stage it executable
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff remove keeps every other key and hook, and each hook and declaration that differs, naming it
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff remove takes out a hook an earlier release of sheriff init wrote
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 sheriff remove takes out what sheriff init writes for both agents, keeps specs/ naming it, stages nothing, and run again changes nothing
- skills/tools/test/e2e/init.test.ts · s-7unxytshhc4md54 this repository holds what sheriff init writes, so that running it here writes nothing