Commands
chamoji why
Ask why a line of code is there. chamoji blames the line in your working copy and prints the commit that wrote it, with its author, date and intent card. It only reads git: nothing is changed or sent anywhere.
SINCE 0.11.0 --json FOR CI AND AGENTSThe file is relative to the folder you run chamoji in, as with git blame. In
src/, ask for picker.js:2, not src/picker.js:2.
What it does, in order
- Blames the line. In your working copy, so the line numbers are the ones your editor shows. It follows moved lines and renames, and skips changes that only touched whitespace.
- Reads the commit. Its short hash, subject, author and date, and its intent card: the
Why:,Constraint:,Gotcha:andFollow-up:lines in its message. - Adds the workstream. When the commit has no card but names a workstream, it shows that
workstream’s title and status, from project memory or, failing that,
.chamoji/workstreams.yml. - Prints it. A commit without a card says “This commit records no intent.” A line you haven’t committed yet says so and exits 0.
Project memory explains intent cards, and how to write them.
Arguments
- Name
file:line- Type
- string · required
- Description
The file and the line number, from 1, such as
src/auth.ts:42. It splits at the last colon, so a file name may hold colons. Give exactly one: none, or more than one, exits 2. Anything that isn’tfile:line, such as a missing line number or line 0, exits 1.
Flags
- Name
--json- Type
- boolean
- Description
Print the blame result as JSON on stdout. It’s
{"kind": "uncommitted"}for a line you haven’t committed, orkind: "commit"with the whole commit as chamoji reads it: hash, author name and email, date, subject, body, gitmoji, trailers,cardwhen there is one, andworkstreamas a slug. It doesn’t look up the workstream’s title. The exit codes stay the same.
- Name
--no-update-check- Type
- boolean
- Description
Don’t check npm for a newer chamoji. See the update notice.
Common combinations
chamoji why src/auth.ts:42
The commit behind a line, and the reason it gave.
chamoji why src/auth.ts:42 --json
The same, for a script or an agent.
chamoji memory search retry
Search every commit’s card instead, when you don’t know the line.
An agent can ask the same question through chamoji mcp’s why tool. See mcp.
Output
These are from real runs in a small repo called widgets. A commit with a card:
chamoji why src/picker.js:2
39a81ce 🐛 Return null for an empty date
Sam Rivera, 2026-11-05
Why: the form crashed when the field was cleared
Gotcha: callers still compare with undefined in two places
A commit with no card, made while a workstream was active:
chamoji why src/picker.js:7
f8b510b ✨ Move between days with the arrow keys
Sam Rivera, 2026-11-05
This commit records no intent.
Workstream: ⌨️ Keyboard support (shipped)
A line you’ve added but not committed:
chamoji why src/picker.js:11
src/picker.js:11 is not committed yet.
With --json:
chamoji why src/picker.js:2 --json
{
"kind": "commit",
"commit": {
"hash": "39a81ce2e6ccbf81d0a10631819841989b040e3a",
"shortHash": "39a81ce",
"authorName": "Sam Rivera",
"authorEmail": "sam@example.com",
"date": "2026-11-05T02:08:02-07:00",
"subject": "🐛 Return null for an empty date",
"body": "Why: the form crashed when the field was cleared\nGotcha: callers still compare with undefined in two places\n",
"gitmoji": "bug",
"gitmojiSource": "gitmoji",
"type": null,
"scope": null,
"description": "Return null for an empty date",
"breaking": false,
"trailers": [
…
],
"card": {
"why": [
"the form crashed when the field was cleared"
],
"constraint": [],
"gotcha": [
"callers still compare with undefined in two places"
],
"followUp": []
}
}
}
Errors
$ chamoji why
chamoji: why needs one location: chamoji why <file:line>
Exit codes
- Name
0- Description
It found the commit, or the line isn’t committed yet.
- Name
2- Description
- No location, or more than one.
- Name
1- Description
Anything else, such as a location that isn’t
file:line, a file or line that doesn’t exist, a repo with no commits yet, or outside a git repo.
Exit codes has every command’s codes.