Commit Check - xsyetopz/claudetto GitHub Wiki
This page describes how claudetto makes sure that a commit or a pull request of Claude has the attribution lines.
It is for a user who wants to know what /claudetto:setup writes, and how to turn the check off.
The harness only makes sure that Claude follows the guidelines of the settings.
The user can turn each part off.
Claude Code adds the attribution lines when it follows a reminder in the context.
The attribution slice sends the same reminder, and it adds three checks for the git commands that Claude runs.
A command that the user types in a terminal has no check.
| Part | When | Result |
|---|---|---|
| Reminder | Before a prompt, and in the task of a subagent | Claude knows the commit line and the pull request line. |
commit-msg hook |
On each git commit of Claude |
Git rejects a message that does not end with the commit line. |
| Bypass deny | Before a git commit that skips the hook |
The call is denied with the reason. |
| Pull request check | After gh pr create or gh pr edit, and before a GitHub MCP write |
Claude gets a note, or the call is denied, when the body lacks the pull request line. |
/claudetto:setup writes the env keys GIT_CONFIG_COUNT, GIT_CONFIG_KEY_<n>, and GIT_CONFIG_VALUE_<n> to the settings.
They define a config-based hook of git: hook.claudetto-attribution.event is commit-msg, and hook.claudetto-attribution.command is the script.
Two more pairs set hook.claudetto-attribution.enabled and hook.commit-msg.enabled to true.
The env keys are in the command scope of git, which wins over the config of a repository.
So a repository that sets one of the enabled keys to false, or sets another command or event, does not remove the check.
A setup from an earlier version has two pairs, and a new run adds the two enabled pairs after them.
The setup adds the keys after the GIT_CONFIG_* keys of the user, keeps those keys, and changes nothing on a second run.
The hook runs next to the hooks of the repository, so it does not replace them.
The attribution hooks write the commit line of each model of the session to a file in ~/.claudetto/attribution/<session id>/.
The script reads the files of the session in CLAUDE_CODE_SESSION_ID.
The script accepts a message when the last line, after git removes the comments, is a recorded line.
It also accepts a message where a recorded line is a whole line of the trailers, such as before a Signed-off-by line.
A rejected commit prints a note with the lines, and Claude adds the line and commits again.
A commit with no session id, or with no recorded line, passes.
The pre-push hook of the AI policy checks only a push from a Bash call of Claude, which CLAUDETTO_AGENT_CALL marks.
The commit hook does not read that name.
Set attribution.commit to an empty string in the settings.
The next prompt empties the record files, so the hook passes.
Set attribution.pr to an empty string to turn off the pull request check.
Remove the four pairs of GIT_CONFIG_KEY_<n> and GIT_CONFIG_VALUE_<n> of claudetto from env, and lower GIT_CONFIG_COUNT, to remove the hook itself.
The config-based hooks need git 2.54 or later.
An older git ignores the keys, so the check passes with no output.
/claudetto:setup runs git --version and says so when git is older than 2.54 or is missing.
The note names the commit-msg and pre-push checks, which do not run.
The reminder and the bypass deny work with each version of git.
When the commit line is on, the slice denies these forms of a git commit of Claude:
-
--no-verify,-n, and a cluster such as-nm. -
-c core.hooksPath=...,-c hook.<name>..., or--config-envof such a key on the commit. - An assignment of
GIT_CONFIG_COUNT,GIT_CONFIG_KEY_<n>,GIT_CONFIG_VALUE_<n>,GIT_CONFIG_PARAMETERS,GIT_CONFIG_GLOBAL,GIT_CONFIG_SYSTEM, orGIT_CONFIG_NOSYSTEMin a command with a commit. - An
export,declare,typeset,readonly,local, orunsetof one of those names in a command with a commit. -
env -u <name>,env -i, orenv --ignore-environmentbeforegitin a command with a commit. -
git commit-tree, which writes a commit and runs no hook.
The Bash tool of Claude Code does not keep the env of one call for the next call, so a change of the env is a bypass only in the call that commits.
The check reads the command with the shell reader of the kernel, so a message that holds -n is not a bypass.
After a gh pr create or gh pr edit call, the slice runs gh pr view --json body.
When the body does not end with the pull request line, Claude gets a note to fix it with gh pr edit --body-file.
The GitHub MCP tools create_pull_request and update_pull_request are denied before the call when the body lacks the line.
The check after the call fails open: a missing gh, no network, or an unreadable body adds no note.
- Guards: the other checks of git commands.
- Settings Snippet: the keys that setup merges.
- Architecture: the slices and the kernel.