Get started
Set up a repo
A repo that ships as one package needs no setup. When apps or packages ship on
their own, or you want to share project memory and connect Claude Code, run
chamoji setup. It looks at the repo, shows what it found, and saves with
Enter.
Setup never commits. Review chamoji.config.json, then commit it yourself.
Do you need it?
By default chamoji treats a repo as one package: one version, one v* tag and one CHANGELOG.md. That's also right for a monorepo whose packages ship together.
Run setup when:
- apps or packages ship on their own. Each one then gets its own version, tag, changelog and GitHub release. Setup writes this in the
releasesection ofchamoji.config.json. - you want to share project memory with your team through
origin, aschamoji initdoes. - you use Claude Code, and want it to search project memory and write a
Why:line in its commits. - you want the commit composer to open on a plain
git commit.
Run it
chamoji setup
chamoji setup
Setup works out its answers from git and the files in the repo, with no AI and no network. Two things it does after that can reach the network: the squash-merge check asks GitHub through gh, and the memory step talks to origin, with --yes too.
On a terminal, it opens with a summary of what it found and what it recommends. Under it are the questions the repo can’t answer, such as a unit’s first version when it has no tags yet, each with a recommended answer.
- Enter saves every answer as shown.
- c opens “Change something”, which lists every question with what chamoji found.
- Esc on the summary, or Ctrl-C, cancels and saves nothing.
Beside the questions, a preview shows each unit’s next release under the current answers: its version, its tag and the first lines of its notes. It changes as the answers change. On a narrow terminal it goes under the questions. When a unit has releases of its own, setup also applies the answers to up to five of them, and shows how each would have come out next to what was released.
What it found
Without a terminal and without --yes, setup says what it would do, writes nothing and exits 2. This is a small repo with two apps, apps/web and apps/mobile, and one shared package, packages/ui:
chamoji setup
○ releases aren't set up yet
○ memory sharing is off in this clone
○ Claude Code isn't connected here yet
○ the commit composer hook isn't installed in this clone; chamoji setup hook --yes installs it
Found 2 apps (mobile, web) and 1 internal package. mobile and web get their own versions. Shared changes ride along with each app's own releases.
Setup would write this release section to chamoji.config.json:
{
"schema": 1,
"shape": "apps",
"units": {
"mobile": {
"path": "apps/mobile",
"tag": "mobile/v{version}"
},
"web": {
"path": "apps/web",
"tag": "web/v{version}"
}
},
"exclude": [],
"sharedChanges": "ride-along",
"rootFiles": "none"
}
Setup would also share memory through origin, as chamoji init does.
Setup would also connect Claude Code here, as chamoji init --agents does.
Setup would also offer the commit composer hook for this clone.
chamoji: setup needs a terminal to ask; run chamoji setup --yes to take every recommended answer
With --explain, it says where each value came from:
chamoji setup releases --yes --explain
Found 2 apps (mobile, web) and 1 internal package. mobile and web get their own versions. Shared changes ride along with each app's own releases.
release.schema = 1 (the section's format)
release.shape = "apps" (detected in the repo)
release.units.mobile.path = "apps/mobile" (detected in the repo)
release.units.mobile.tag = "mobile/v{version}" (detected in the repo)
release.units.web.path = "apps/web" (detected in the repo)
release.units.web.tag = "web/v{version}" (detected in the repo)
release.exclude = [] (detected in the repo)
release.sharedChanges = "ride-along" (recommended for apps)
release.rootFiles = "none" (recommended for apps)
Wrote chamoji.config.json. Review it and commit it; git restore chamoji.config.json undoes this.
Each app now releases on its own. Neither has a tag yet, so each releases the version in its package.json, and the fix in packages/ui rides along with both:
chamoji release --dry-run
Would release:
mobile 1.0.0 → 1.0.0 first 2 own, 1 shared
web 1.2.0 → 1.2.0 first 2 own, 1 shared
files: apps/mobile/CHANGELOG.md, apps/mobile/package.json, apps/web/CHANGELOG.md, apps/web/package.json
## mobile/v1.0.0
## 1.0.0 - 2026-11-05
### Added
- ✨ Add the cart screen (a1b5c95)
- 🎉 Begin the shop (826991b)
### Fixed
- 🐛 Fix the button's focus ring (e3740b6) (via `packages/ui`)
## web/v1.2.0
…
What it looks for
- Units. Apps are the packages under
apps/, and private top-level packages that nothing depends on. Test and tool apps (e2e,test,tests,playwright,cypress,storybook,docs,dev-tool) andtooling/*are left out. In a repo with no apps, each published package is a unit. A repo with both apps and published packages is set up asappsfor now, and its published packages aren’t units. Setup says so. - Version files. Other files that carry an app’s version, such as Expo’s
app.config.tsorapp.json, anInfo.plistor anandroid/app/build.gradle, go inversionFiles. A unit with an EAS config getsbuildNumber, left asuntouched. - Tags. A unit keeps the tag format it already uses, and other formats it has used go in
read. Tags that came with a template go intags.ignore: the ones reachable from the template’s remote, and the ones reached only by commits from people who haven’t committed recently. Setup writes general patterns such as^\d+\.\d+\.\d+$. When such a pattern would also match tags of your own, it leaves just those out. Stray tags such aswip/…are ignored too. - The template. If the repo began as a template you started from, a remote named
upstream, or else another remote besidesoriginthat shares history with yours, becomesupstream.remote. The name in sync lines comes from the owner in the remote’s URL, andsinceis your first commit that isn’t the template’s. The template’s authors go inupstream.authorswhen some of their commits are ones the remote no longer reaches. The summary names them. - Squash merges. With the
ghCLI and a GitHuborigin, setup reads the repo’s merge settings. GitHub’s “Pull request title” and “Pull request title and description” drop the commits’Release:andWorkstream:lines and their intent cards, such asWhy:, so setup recommends “Default message” or “Pull request title and commit details”, which keep them.
The four steps
Each step can run on its own, with chamoji setup releases, setup memory, setup agents or setup hook.
- Releases. The
releasesection ofchamoji.config.json.chamoji setup releasesasks the release questions again, even when the section exists. - Memory sharing. What
chamoji initdoes. It’s offered when the repo has anorigin. - Claude Code. What
chamoji init --agentsdoes. It’s offered when the repo has a.claudefolder orclaudeis on your PATH. - Commit composer. What
chamoji hook installdoes. It’s offered, never assumed, and its prompt defaults to No.
After the summary, setup asks yes or no for each step that’s offered and not done yet.
In a fresh clone
The release section and .mcp.json are committed and shared. Memory sharing and the hook are per clone. So in a fresh clone of a repo that’s set up, chamoji setup asks only for those, and your readme can tell new contributors to run it.
--yes runs the memory and Claude Code steps when they’re offered and not done. It never installs the hook; chamoji setup hook --yes does that.
chamoji setup --yes
✓ releases are set up in chamoji.config.json
○ memory sharing is off in this clone
○ Claude Code isn't connected here yet
○ the commit composer hook isn't installed in this clone; chamoji setup hook --yes installs it
chamoji.config.json is already up to date.
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.
No memory on origin yet.
.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.
What it writes
chamoji.config.json: only thereleasesection. The file’s other keys are kept, a re-run with nothing new leaves it untouched, and setup won’t write through a symlink.git restore chamoji.config.jsonundoes the releases step..mcp.jsonand.claude/settings.json: the Claude Code step adds chamoji to them and keeps what’s there. Both are meant to be committed.- git config and
.git/: memory sharing and the hook live in the clone, so nothing there is committed.
Config describes every key of the release section, for reading what setup wrote or for writing it by hand.
chamoji init
chamoji init is the memory step on its own. It makes origin fetch chamoji’s memory, then takes in what origin already has. Run it once in each clone:
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.
No memory on origin yet.
chamoji setup also sets up releases, AI agents and the commit composer.
Without an origin, it says there is nothing to share memory with and changes nothing. chamoji init --agents also connects Claude Code: the MCP server in .mcp.json, and a hook in .claude/settings.json that sends back a git commit with no Why: line. Claude Code won’t run a server from a project’s .mcp.json until you approve it, so approve it when Claude Code asks.
Exit codes
- Name
0- Description
- Setup saved, or nothing would change.
- Name
2- Description
Something would change, but there is no terminal and no
--yes, or there is--jsonand no--yes. Setup writes nothing and says what it would do. Also for areleasesection from a newer chamoji.
- Name
1- Description
- You cancelled, or something else went wrong.