The decision intelligence layer in one tool. get_why answers
"why is this code shaped this way?", pulling from the architectural
decision records, recorded episodes, the wiki, and (when nothing's
recorded) the git history and rationale comments themselves.
The thing to understand before reading a response: acceptance is the
only authority. A record binds you because somebody accepted it in a
recorded event, not because a column says active. Path mode sorts
every record that names your file into one of three lanes on exactly
that test.
When to call
- Before architectural changes: check whether an accepted decision governs what you're about to touch.
- During design reviews: pull the health dashboard to find records whose code has moved, and hotspots nobody has decided anything about.
- On code with no recorded decisions: the git-archaeology fallback reconstructs the origin story from significant commits.
- Following up on an id: an evidence ref another response emitted resolves directly, with no relevance search in between.
Parameters
| Parameter | Type | Description |
|---|---|---|
query | string | Natural-language question, a file/module path, or omit entirely for the health dashboard. |
targets | string[] | File paths to anchor the search. With no query, the targets are the question. |
repo | string | Repository alias. Pass "all" to search decisions across the whole workspace. Not supported with id or with the dashboard. |
id | string | A decision id or an ev_... evidence id previously emitted by get_why. Resolves it directly, skipping relevance search. |
reference | object | An emitted evidence reference object. Pass it back unchanged and both its id and its repository scope are honoured. |
The three lanes
Path mode returns the records that name a file split by who agreed to them. The lane, not the status, is what tells you whether a record binds you.
| Lane | What it holds | How to read it |
|---|---|---|
decisions | Accepted records that still govern | Constraints. Follow them |
candidates | Records something inferred and nobody has agreed to | Hints. A candidates_note says so too, and names the repowise decision confirm command that would promote one |
history | Accepted once, superseded or dismissed since | History. Useful for "this was decided and then replaced", never a rule |
Nothing produces an acceptance except an explicit
repowise decision confirm or a committed ADR that says it is
accepted. A candidate that has recurred across fifty sessions is still
a candidate.
Each accepted record carries a currency, which is what replaced
status as the truth:
currency | Meaning |
|---|---|
active | Accepted, and still describes the code |
needs_review | Accepted, and the files it names have moved. It still binds |
uncheckable | Accepted, but it names nothing the repository can be asked about |
superseded | Replaced by a later decision through an explicit lineage edge |
dismissed | Authority withdrawn, kept for history |
active and needs_review are the two that govern. A candidate
carries review_state: "open" and no currency at all. Every row also
carries an authority: accepted, candidate, or withdrawn.
Do not read the lane off status. That column is a projection kept in
step for readers that predate the split, and a record can carry
status: "active" with no acceptance behind it.
Returns
answer_basis names the strongest lane the whole response rests on:
decision, episode, rationale, archaeology, documentation, or
candidate. Only decision is a ruling. candidate is the weakest,
and means nothing cleared the bar. It is absent on the dashboard, which
is orientation rather than an answer.
Mode 1: Search (query is a question)
mode: "search",querydecisions: up to 8 merged hits (keyword + semantic, deduped)related_documentation: top 3 wiki pages mentioning the querytarget_context: (iftargetsprovided) per-target governing decisions, candidate decisions, origin story, and git archaeologycode_rationale: (iftargetsprovided and no decisions matched) rationale comments mined live from the targets' sourceepisodes: dated facts recorded about the query (or the targets, when given), when any are bound
Mode 2: Path (query is a file path)
mode: "path",pathdecisions: the accepted, governing lane, ranked before the cap of 8 so the 8 that survive are the 8 that govern.decisions_totalanddecisions_omittedappear when more matched. The top-ranked record also carries astill_truesentence when git can speak to whether it holds, and only the top one: the check costs a subprocesscandidatesandcandidates_note,historyandhistory_note: the other two lanes, each capped at three rowsorigin_story: when and why the file was created, by whom, recent change patterns. Built from every lane, since a commit matching a candidate's title still explains the filealignment: coverage counts, scored over every matching record rather than the capped 8git_archaeology: present whenever no accepted decision governs the path, beside whatever candidates or history were foundcode_rationale: rationale comments mined live from the source when decisions and git history are both silentepisodes: dated facts recorded about this file, when any are bound. Additive, not a fallback
Reading alignment
Four counts sum to governing_count, which is every record naming the
file:
active_count: what actually governs itdeprecated_count: accepted and withdrawn sinceuncheckable_count: accepted but naming nothingcandidate_count: merely awaiting review
score is derived from active_count alone, so a file with
active_count: 0 is ungoverned however many candidates name it.
stale_count is the subset of governing records sitting at
needs_review, and sibling_coverage is the share of comparable files
in the same directory that an accepted decision covers.
Mode 3: Health dashboard (no query, no targets)
mode: "health"summary: a one-line count stringcounts: structured counts by lanestale_decisions: ranked by staleness, worst firstproposed_awaiting_review: records nobody has accepted, ranked by confidenceungoverned_hotspots: high-churn files no accepted decision namesconflicts: decisions that disagree over the same files
The counts are computed off the acceptance, not off the status column,
so active here means "somebody accepted this" and proposed means
"nobody has".
Mode 4: Reference lookup (id or reference)
mode: "reference": the exact evidence and its supporting decision, in one call and with no relevance search
Mode 5: Workspace search (repo="all")
mode: "search",workspace: truedecisions: keyword results merged across repos, capped at 15
Example
get_why() # health dashboard
get_why("why is auth using JWT?") # search
get_why("src/auth/service.py") # path mode
get_why(targets=["src/cache/service.py"]) # the targets are the question
get_why(id="ev_8f21c4") # resolve an emitted ref
get_why("redis integration", repo="all") # workspace searchThings worth knowing
- Path detection: natural language wins first. A query ending in
?, starting with a question word ("why", "how", ...), or reading as a sentence (4+ words including a question word) always routes to search. Otherwise a query containing a path separator or ending in a recognized code extension routes to path mode. - Named targets with no query are the question. The call answers about those files rather than falling through to the dashboard.
- A missing lane can mean a tight budget.
candidatesandhistoryshed first under response-budget pressure, so their absence is not proof they were empty.answer_basisis re-derived after shedding, so it never names a lane the budget emptied. - Candidates reach no other tool.
get_overview,get_riskdirectives andget_answerserve accepted records only. A candidate never arrives anywhere as an instruction. - Evidence ids are shared, not corroborating. Evidence-bearing rows
carry a
provenanceand self-containedevidence_refs. Two rows with matching ids rest on the same evidence, which is not two independent confirmations. - Git-archaeology fallback runs when no accepted decision governs a
file: significant commits from the file itself, cross-file references
in other files' commits, then live
git log --followandgit log --grepunder a 10-second timeout. - Workspace mode (
repo="all") uses keyword search across all repos' decisions, capped at 15 merged results, and is unsupported for the dashboard and foridlookups.
Decisions are linked to graph nodes, so when the agent edits a file
get_why will surface the records that govern it without you having to
ask. This is what keeps the why in the codebase when the original
author leaves.