Built on HydraDB · Hack Hydra 2026

You asked for three files.
It changed twenty.

Ichor watches your coding agent while it works and challenges it the moment it goes past the job you gave it — with the path it can point at.

How it works →
claude code — vendor-app
you ›Duplicate email in vendor onboarding returns 500. Handle it properly, show a toast, and don't wipe the form.
claude ›editing src/lib/vendors/create.ts  ✓ in scope
claude ›editing src/app/api/vendors/route.ts  ✓ in scope
claude ›editing src/lib/vendors/submit.ts  ✓ in scope
claude ›creating src/app/api/vendors/check-email/route.ts
⚠ ichor: this looks like scope expansion.
A new POST endpoint that reaches Vendor — but the task's existing path already reaches it:
POST /api/vendors → createVendor → Vendor.email (unique)
Why is a separate endpoint required?
claude ›It isn't. I'll handle the duplicate in the existing submit flow.
result ›3 files changed. 0 new endpoints. Task done.

Runs inside the agent you already use. No account, nothing uploaded.

Claude Code Codex CLI MCP TypeScript Docker
The judgement

Connected is not the same as necessary.

Your agent adds an endpoint during a duplicate-email fix. Ask any search tool whether it relates to the task and everything says yes — same table, same folder, same service. All true, so relatedness gives you no reason to object.

the question Ichor asks next
  the task's existing path
  POST /api/vendors ──────► createVendor ──────► Vendor.email (unique)
                                                        
  the new endpoint                                      
  POST /api/vendors/check-email ────────────────────────┘
                                reaches the same rule by a second road

The database already refuses duplicate emails, and the submit path already reaches that rule. The endpoint is connected, relevant, and unnecessary.


How it works

It knows what your code actually connects to.

Not keyword matching. The TypeScript compiler resolves every call, import, route and model into a graph — then Ichor judges edits against it.

01

It reads your repo, once

Every call, import, route and Prisma model, into a graph in a local HydraDB. 19 seconds for 1,362 files, then seconds to keep up.

02

Your prompt draws the boundary

It finds where the task lives and walks outward through real call edges. No task to type — it reads the conversation, and moves when you move on.

03

Edits outside it get questioned

Before the write lands for an edit tool, the instant the command finishes for a shell write. Always with the existing path that already does the job.


In the session

It follows the job, not the folder.

Two things a boundary has to survive: you moving on, and your agent reaching for the shell.

Move on, and it moves with you

Nobody runs a command between tasks. A boundary drawn at 9am would still be policing vendor code at 2pm while you are deep in billing.

.ichor/hook.log — the same session, two hours later
you ›now fix the invoice totals in lib/billing/invoice.ts
prompt ›NEW — names lib/billing/invoice.ts outright, which the boundary does not cover
prompt ›boundary set — 14 functions in 0.1s
claude ›editing lib/billing/invoice.ts  ✓ EXPECTED
claude ›editing src/lib/vendors/create.ts  ⚠ SUSPICIOUS
note ›vendor code was in scope this morning. It is not the job now.

Your agent gets to use the graph too

The same graph that judges edits will answer questions, as MCP tools and as plain shell commands.

ask the graph
$ichor impact getChunkedCookie
declared in  packages/better-auth/src/cookies/session-store.ts
called by 43:
   getSession      api/routes/session.ts
   setCookieCache  cookies/index.ts
→ direct call, ⇢ through a chain.

Proof

Measured on somebody else's code.

The number that decides whether a tool like this survives is how often it interrupts work you were right to do. Passing your own tests on your own demo proves nothing about that.

False alarms 12.8%

Share of edits a developer genuinely had to make that Ichor would have interrupted — about one in eight. Replayed through the real classifier, not estimated.

Evidence 86

Files across 30 real commits from a real product. Each commit message is the task; the files it changed are the truth. Every file type, not just the ones Ichor reads.

Speed 6s

To catch up after you edit a file in a 1,362-file codebase. The largest repo tested — 7,735 files — is read at Node's default heap.

Every number here is reproducible from the repository, and the harness that produces it ships with the source.


Install

Three commands, and no task to type.

Needs Docker for the local graph database, and a TypeScript or JavaScript repo. Your code never leaves your machine.

your-repo
$npm i -g ichor-cli
$ichor init   # hooks for Claude Code and Codex
$ichor up     # local HydraDB, binds to 127.0.0.1
$ichor watch  # reads your repo, then follows the conversation
Watching. Run your agent as usual — Ichor picks the task up from your prompts.
No account

Your code stays on your machine

HydraDB and MinIO run locally through Docker, every port binds to 127.0.0.1, and there is no telemetry.

Optional

A key lets it weigh an argument

Every boundary, verdict and tool works with no key. Add an OpenRouter key and, when your agent argues an expansion is necessary, that argument gets weighed against the evidence instead of the question coming to you.


Honest limits

What it cannot do.

A tool that claims to know where a task belongs should be precise about where it is blind.

TypeScript and JavaScript only. Python is next. Nothing else is claimed.

It still questions about one edit in eight that you were right to make. Measured, not estimated — naming the file in your prompt is what makes the boundary precise.

It understands one stack deeply. Next.js App Router routes and Prisma models are what it reads. Pages Router routes and other ORMs are not in the graph yet, so on those codebases it sees the calls but not the endpoints or the data.

A shell write is challenged after it lands, not before. An agent editing with sed or a heredoc fires no pre-write hook, so Ichor reads what changed on disk once the command finishes and asks then — before anything is built on top of it.

Ichor can be wrong. The boundary is an expectation, not a fact. When it cannot verify a justification it asks you rather than deciding — and it never blocks a prompt.

The longer list — memory ceilings, one database per repo, static-analysis blind spots — is in the docs.