Skip to content

Your agent can’t tell a decision from a quirk

Clark mines the decisions buried in git history, checks stated reasons against the commit, and serves the records over MCP so your agent can check before editing.

View on GitHub
npm install -g @imgeekk/clark

Indexing needs Node 22+, git, and a Gemini API key.

Open sourceMITEarly release
illustrative example
clark

$ clark why src/net/retry.ts

keep randomized backoff

evidence
stated
confidence
0.9
reason
“add jitter to retries, thundering herd after outage”
commit
8f3c1a2

Illustrative output. The commit, file, hash, and confidence are invented for the example.

The why is not in the code

An agent sees sleep(400 + random(200)) as noise and cleans it up. It cannot see the outage that put the jitter there. The cleanup ships, and the failure comes back.

illustrative example

past commit

“add jitter to retries, thundering herd after outage”

8f3c1a2 · src/net/retry.ts

agent without the record

“Simplify this retry logic.”

The delay looks arbitrary, so the edit replaces it with a tidy 500ms wait.

proposed change

- sleep(400 + random(200))

+ sleep(500)

clark, before the edit

Keep randomized backoff

evidence
stated
confidence
0.9
why
thundering herd after an outage
from
8f3c1a2 · src/net/retry.ts

The agent can check before the edit. Inferred records are labeled guesses and capped at 0.7.

Illustrative example. The hash, message, file, and confidence are invented.

The code shows what changed the history shows why

How Clark gets a reason to the agent

Clark does not guess at intent in the moment. It mines what was already decided, checks the model's answer against the commit, and serves it over MCP.

  1. 01

    Index the history

    Clark reads commits that are not merges, skips lockfiles, build output, docs, CI and tests, then sends each remaining message and diff to Gemini with three questions: does it change runtime behavior, public API, data format, security or a hot path; would a future agent choose differently; and would undoing it need the reason?

    git log → Gemini
  2. 02

    Verify the answer

    A stated reason must quote the commit message verbatim and contain a causal marker. Otherwise it is downgraded to inferred, confidence is capped per evidence type, and file paths the commit did not touch are dropped. Decisions go into SQLite and embeddings.

    stated / inferred
  3. 03

    Serve before the edit

    The server exposes three MCP tools over stdio: search_decisions, why, and check_change. The check_change tool ranks prior decisions by file overlap then recency, and stays silent below 0.5 confidence.

    search · why · check

What changes for the agent

The difference is not a better prompt. It is a reason that is already indexed when the agent checks before the edit.

An answer with a receipt

Every decision carries its evidence level, confidence, a verbatim reason quote when the commit states one, and the commit SHA that supports it.

A check before the edit

The check_change tool returns prior decisions with direct file overlap, ranked by overlap then recency, when the agent asks before changing the file.

Honest about guesses

A stated reason is checked against the commit. An inferred reason is labeled a hypothesis and capped at 0.7 confidence.

Local index, explicit egress

The database stays in .repo-memory inside the repository. Indexing sends commit messages and diffs to Gemini; the why and check_change tools work offline.

What Clark cannot do

The honest version, before you run it on a real repository.

  • A quote is not the truth

    A stated record proves the commit said it, not that the reason was right. An inferred record is a hypothesis, capped at 0.7. If commit messages only say what changed, most records will be inferred. There is no human review step.

  • Merge commits are skipped

    If the rationale only lives in a pull request description, Clark cannot see it.

  • Large diffs are truncated

    Diffs stop at 12,000 characters per commit, so a reason buried deep in a large change can be missed.

  • The default index is partial

    The default limit is 100 commits. The status command counts what is stored, not how much history exists. One server process serves one repository.

  • Search grows in memory

    Semantic search loads every stored embedding per query. That is fine for a few thousand decisions, not tens of thousands.

  • Reverts are not marked stale

    If a later commit undoes a decision, Clark does not mark the original record stale yet.

  • Some records are search only

    A decision with no verifiable file paths is stored, but it will not appear in why or check_change. Use search_decisions to find it.

  • History leaves your machine

    Indexing sends commit messages and diffs to Gemini, and decision text and search queries are sent for embeddings. Do not index a repository whose history cannot go to a third party.

Questions, answered plainly

What does Clark produce?

A local SQLite index of engineering decisions. Each record carries a rationale, an evidence level, a confidence score, the commit message quote when the reason is stated, and the commit SHA. The MCP server serves the records on demand.

Can the extracted reasoning be wrong?

Yes. A stated record quotes the commit, but the quote check proves what was written, not that the decision was correct. Inferred records are hypotheses, capped at 0.7 confidence and phrased as guesses. There is no human review step, so treat an inferred record as a lead.

Does Clark change my source code?

No. It writes its database under .repo-memory in the repository and leaves source files alone. The init command with --agents-md can also append an instruction block to AGENTS.md; for Claude Code, add the same block to CLAUDE.md.

How are stated reasons checked?

A stated rationale must quote the commit message verbatim and contain a causal marker. If it does not, the record is downgraded to inferred. Confidence is capped per evidence type, and file paths the commit did not touch are dropped.

Which coding agents work with Clark?

The init command prints registration commands for Claude Code, Codex, and OpenCode. Clients that only read a config file can use the --json flag. The server is tested with the official MCP SDK client over stdio, not per client.

What leaves my machine?

Indexing sends commit messages and diffs to Gemini. Decision text and search queries are sent to compute embeddings. The database stays in .repo-memory. The why and check_change tools only read SQLite and work offline.

Why not just write docs?

Docs describe the current state. Clark mines the history behind that state, keeps the commit and quote, and serves the reason when an agent checks before editing.

Is it ready to use?

It is an early release. The CLI and MCP surface work, the package is published on npm, and 73 tests pass without network access. Expect changes.

early release

Run it on a repo

Install the CLI, index a repository, then register the MCP server with your client. Node 22+, git, and a Gemini API key.

  • Node 22+
  • git
  • GEMINI_API_KEY
View on GitHub

quickstart · from the repo root

$ npm install -g @imgeekk/clark

# add GEMINI_API_KEY to .env

$ clark index .

$ clark status .

$ clark init .

# run the printed client command, then restart the client

$ clark init . --agents-md

Registering the server only makes the tools available. The --agents-md block adds an instruction to AGENTS.md; Claude Code reads CLAUDE.md, so add the same block there. The block calls clark by name, so it needs the global install.

local by default

The index lives in .repo-memory inside the repository. The why and check_change tools only read SQLite and work offline.

what leaves

Indexing sends commit messages and diffs to Gemini. Every kept commit is sent once. Decision text and search queries are sent for embeddings. Keep GEMINI_API_KEY in .env, and add .env to .gitignore.

verified

73 tests, no network. The server is exercised with the official MCP SDK client over stdio, not per client.

@imgeekk/clark on npm