Commands

chamoji why

why.mdEdit on GitHub

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 AGENTS

The 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

  1. 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.
  2. Reads the commit. Its short hash, subject, author and date, and its intent card: the Why:, Constraint:, Gotcha: and Follow-up: lines in its message.
  3. 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.
  4. 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’t file: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, or kind: "commit" with the whole commit as chamoji reads it: hash, author name and email, date, subject, body, gitmoji, trailers, card when there is one, and workstream as 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.

Was this page helpful?