Commands
chamoji init
Set this clone up to share project memory through origin, and take in what
origin already has. With --agents, also connect Claude Code in this repo:
the chamoji MCP server in .mcp.json and a commit hook in
.claude/settings.json.
Git doesn’t clone chamoji’s memory ref, or the setting that fetches it, so
every clone runs chamoji init once. It never pushes: chamoji memory sync
shares what you have.
What it does, in order
- With --agents, checks both files.
.mcp.jsonand.claude/settings.jsonat the repo root, wherever you run it. Both are read and checked before either is written. If chamoji can’t safely change one, it changes neither, skips the memory step and exits 1. - With --agents, merges into them. The MCP server and the commit hook, unless they’re there already. Your other entries are kept. Each file is replaced in one step, so a failure never leaves half a file.
- Makes origin fetch memory. Adds
+refs/chamoji/*:refs/chamoji/remotes/origin/*toremote.origin.fetch, once. It leavesremote.origin.pushalone, so a plaingit pushstill pushes your branch. Without anorigin, it says so and changes nothing. - Takes in origin’s memory. Fetches it and merges it into yours, so a fresh clone needs nothing else. If
the fetch fails, it says why on stderr, and the setting stays for the next
memory sync.
After init, a plain git fetch or git pull also downloads origin’s memory, to a side ref that chamoji memory doesn’t read. chamoji memory sync takes it in. chamoji release --push syncs memory too, but only in a clone that ran init. Once per clone, outside CI, init ends with a one-line hint about chamoji setup on stderr.
setup runs the same two steps as setup memory and setup agents, alongside the release settings and the commit composer hook.
What --agents writes
Both files are meant to be committed, so everyone who uses Claude Code in the repo gets the same setup. A changed file is written back as plain JSON with its indent kept, so other layout, such as blank lines, may differ.
chamoji on your PATH
{
"mcpServers": {
"chamoji": {
"command": "chamoji",
"args": [
"mcp"
]
}
}
}
When chamoji isn’t on your PATH, the server starts with npx --yes @chamoji/cli mcp and the hook runs npx --yes @chamoji/cli agent-hook || true. A node_modules/.bin on the PATH doesn’t count, since npx and package scripts add one just for the run.
- Name
.mcp.json- Description
Gets
mcpServers.chamoji, which runschamoji mcp. Achamojiserver that’s already there is yours to keep, whatever it runs.
- Name
.claude/settings.json- Description
Gets an entry in
hooks.PreToolUsethat runschamoji agent-hookbefore Claude Code’s Bash tool runs agit commit. Any entry whose command already runschamoji agent-hookcounts as there. The|| trueis for a chamoji too old to know the hook: it would exit 2, which Claude Code reads as “block this”, and the file is shared.
Claude Code won’t start a server from a project’s .mcp.json until you approve it. Until then, claude mcp list shows it as pending approval.
chamoji leaves a file alone, and changes nothing, when it is a symlink or in a symlinked folder, isn’t valid JSON or a JSON object, has an mcpServers, hooks or hooks.PreToolUse of the wrong type, or holds a number that can’t be written back exactly.
On native Windows, the .mcp.json entry may need a cmd /c wrapper for npx
or a chamoji shim. This hasn’t been tested there yet.
The commit hook
chamoji agent-hook is the hook itself. Claude Code runs it before a Bash command and passes the command on stdin. When the command is a git commit whose message has no card line, it prints a denial, and the agent sees this reason:
Add why this change was made: put a "Why: <reason>" line at the end of the commit message, after a blank line. Constraint:, Gotcha: and Follow-up: lines are welcome too. Only if the user told you to skip this, prefix the command with CHAMOJI_NO_CARD=1.
- What counts: any of
Why:,Constraint:,Gotcha:orFollow-up:, below the subject paragraph, in-m,--traileror a heredoc.-m "Why: because"alone is a subject, not a card. A baregit commithas no message to read, so it’s denied too. - What passes:
CHAMOJI_NO_CARD=1in front of the command, a message from a file or another commit (-F,-C),--no-editwith no new message, and commands that only look, such as--dry-runand--help. Every other command passes too. - What it can’t see: it reads the command text, so a commit inside
sh -c '…',xargsor a shell alias isn’t checked. - It never blocks by failing: whatever goes wrong, it prints nothing and exits 0, and the command goes through.
The hook covers Claude Code only. Other agents can use the MCP server, and write their cards by hand.
Arguments
chamoji init takes no arguments. Extra words are ignored.
Flags
- Name
--agents- Type
- boolean
- Description
Also connect Claude Code in this repo, before the memory step: the MCP server in
.mcp.jsonand the commit hook in.claude/settings.json, at the repo root. Safe to run again: what’s there already is left as it is.
- Name
--no-update-check- Type
- boolean
- Description
Don’t check npm for a newer chamoji. See the update notice.
Common combinations
chamoji init
Once in each clone: share memory through origin, and take in what it has.
chamoji init --agents
The same, and connect Claude Code. Commit the two files it writes.
chamoji memory sync
Afterwards, whenever you want to share what you remembered.
Output
These are from real runs in fresh clones of a small repo called widgets, whose origin had one workstream in memory:
chamoji init
origin now fetches chamoji memory.
A plain git fetch or git pull downloads origin's memory but doesn't change what chamoji memory shows. Run chamoji memory sync to take it in and share yours.
Took in memory from origin: 1 entry.
chamoji setup also sets up releases, AI agents and the commit composer.
chamoji init --agents
.mcp.json: added the chamoji MCP server
.claude/settings.json: added the commit hook
These files are meant to be committed, so everyone who uses Claude Code here gets the same setup. A changed file is written back as plain JSON with its indent kept, so other layout, such as blank lines or how short lists wrap, may differ.
origin now fetches chamoji memory.
A plain git fetch or git pull downloads origin's memory but doesn't change what chamoji memory shows. Run chamoji memory sync to take it in and share yours.
Took in memory from origin: 1 entry.
chamoji setup also sets up releases, AI agents and the commit composer.
Run again, it changes nothing:
chamoji init --agents
.mcp.json: already has the chamoji MCP server
.claude/settings.json: already has the commit hook
origin already fetches chamoji memory.
A plain git fetch or git pull downloads origin's memory but doesn't change what chamoji memory shows. Run chamoji memory sync to take it in and share yours.
Took in memory from origin: 1 entry.
Run through npx, in a clone whose .claude/settings.json already allowed npm test. The file keeps its tabs and its entry:
npx @chamoji/cli init --agents
.mcp.json: added the chamoji MCP server
.claude/settings.json: added the commit hook
These files are meant to be committed, so everyone who uses Claude Code here gets the same setup. A changed file is written back as plain JSON with its indent kept, so other layout, such as blank lines or how short lists wrap, may differ. chamoji is not on your PATH, so they start it with npx.
…
.claude/settings.json
{
"permissions": {
"allow": [
"Bash(npm test)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git commit *)",
"command": "npx --yes @chamoji/cli agent-hook || true"
}
]
}
]
}
}
What the hook prints when Claude Code hands it git commit -m "✨ Add the date picker", which has no card. For a command it lets through, it prints nothing:
chamoji agent-hook
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Add why this change was made: put a \"Why: <reason>\" line at the end of the commit message, after a blank line. Constraint:, Gotcha: and Follow-up: lines are welcome too. Only if the user told you to skip this, prefix the command with CHAMOJI_NO_CARD=1."}}
Problems
$ chamoji init
No remote named origin, so there is nothing to share memory with. Add one and run chamoji init again.
Exit codes
- Name
0- Description
Memory sharing is set up. Also when there is no
originto share with, and when the fetch from origin failed: the message says why.
- Name
1- Description
--agentscan’t safely change.mcp.jsonor.claude/settings.json, or can’t write one. Also outside a git repo, and anything else that fails.
chamoji agent-hook always exits 0. Its answer is what it prints. Exit codes has every command’s codes.