Something's coming — join the waitlist →

deadeye.

He doesn't waste shots.

A plugin for your coding agent that fits the model, effort level, and context to each task — before the tokens are spent, not after. Built for Claude Code; a plugin for Codex too, and lighter tiers for Gemini CLI, Cursor & Windsurf.

$ /plugin marketplace add deepaksinghcs14/deadeye-cc
$ /plugin install deadeye@deadeye
Claude Code. Run both inside Claude Code. Hooks register themselves; the binary bootstraps on first use, sha256-verified. The full engine, including model and effort routing. Details
$ codex plugin marketplace add deepaksinghcs14/deadeye-cc
$ codex plugin add deadeye@deadeye
Codex CLI. Run both in your terminal, then start Codex, run /hooks and trust deadeye's hooks. Most of the engine; no model or effort routing yet. Details
$ deadeye init gemini
$ gemini extensions install --path ~/.deadeye/gemini-extension
Gemini CLI. Needs the deadeye binary on your PATH first. Coder persona and session guidance. Details
$ deadeye init cursor
Cursor. Needs the deadeye binary on your PATH first; run it in your project. Adds the persona as a rules file, plus hooks for output trimming and the exfiltration guard. Experimental. Details
$ deadeye init windsurf
Windsurf. Needs the deadeye binary on your PATH first; run it in your project. The coder persona, as a rules file. Details
go test -v — raw485 bytes
14 lines — 4 PASS lines, 1 FAIL with its
context, carried into the conversation whole.
go test -v — deadeye99 bytes
$ go test ./... -v 2>&1 | grep -A 5 -E '(FAIL|ERROR|error:|panic:)' | head -120 --- FAIL: TestReconciliationAppliesTaxBeforeDiscount (0.00s) FAIL FAIL canondemo/orders 0.539s FAIL
The rewrite happens before the command runs.
79.6%–99.5% smaller, measured on real runs, not averaged. This run: 485 bytes shrank to 99. This repo's own full test suite (202 lines, 10,301 bytes, all passing): shrank to 55 bytes. A real npm install express mocha: 553 bytes of progress spam shrank to 55, errors still passed through. Three separate real measurements, not one number blended across different situations — run /deadeye-stats savings to see your own numbers.

Why deadeye

What sets it apart

Most tools optimize after the fact, guess at the savings, or ship your code to a server. deadeye does none of that.

79.6–99.5%smaller command output

Verbose test/build/install output is trimmed before it enters context — measured on real runs, not averaged: 485 bytes → 99, a 202-line passing suite → 55.

88.4%lighter subagents

The coder persona a subagent inherits dropped from 9,499 to 1,099 bytes per spawn — measured, on every spawn.

100%measured, never estimated

Every figure is a real row in decisions.jsonl — and 95% of events (the quiet no-ops) aren't logged at all. No invented savings for code never written.

0code sent anywhere

No telemetry, no API keys, no third-party service. All state lives in one file under ~/.deadeye/. The AI routing judge (on by default) sends an ambiguous task's description — never your code — through your own Claude login to classify it; off switch included, same as the background reads.

6 signalsdecided before the spend

Model, effort, and context are fit ahead of the call from six cheap signals, reasoning always visible. Genuinely ambiguous cases get one real classification instead of a blind default.

Fail-opennever blocks, never overrides

If anything inside it errors, your call passes through untouched. It advises on your main session — it never seizes your settings or your model.

We didn't just claim it — we measured it. See the proof · 6× measured →

How it decides

Reads the task, not keywords

A lot of routing tools just match words in your prompt — see "architecture," assume it's a big job. deadeye instead looks at a few real signals about the task, then works out the cheapest model and effort level that should still get it done properly. The reasoning behind every decision is always visible, never a black box.

  • LookWhich files are touched, recent git activity, whether tests exist nearby, how the wording reads, whether the task itself names something real — a file deadeye can verify actually exists, not just a plausible-looking string — and whether it's a read-only subagent. Six cheap signals — no LLM call, no network request.
  • DecideModel and effort level matter together — a mid-tier model on high effort can match a top-tier model on low effort. deadeye works out the cheapest combination that should still clear the bar for this task, not a fixed tier picked by rule of thumb.
  • ApplyPicks the model and effort level when a subagent starts — but only where you didn't already pick one yourself. Trims noisy output before it enters context. Asks before a multi-file edit that skipped a plan.
  • LearnPick a bigger model than it recommended, and it gets more cautious for that kind of task next time.
/deadeye-route "fix the null check in handler.go" Evidence: promptshape complexity=0.00 confidence=0.85 filescope complexity=0.15 confidence=0.85 gitchurn complexity=0.30 confidence=0.82 testpresence complexity=0.10 confidence=0.80 taskspecificity complexity=0.00 confidence=0.85 Decision: model: claude-haiku-5-5 effort: medium confidence: 0.80 reason: all evidence supports downshift: low complexity, confidence >= threshold

Real output, from this repo, this session. Nothing actually changes unless you turn a setting to enforce — by default, deadeye only advises.

When it's unsure — a capable middle, not the priciest

Missing information never buys the cheapest model. When deadeye can't tell how big a change is, it defaults to a capable middle (sonnet-tier), reserving the top tier for genuinely hard work — picking cheaper always needs real evidence above a confidence bar. When the signals truly can't place a task, a routing judge classifies it: one small claude -p call on your own login, about half a cent, on by default, one setting to turn off.

  • Wrong-but-expensive is recoverableWorst case, it costs you some money. Wrong-but-cheap costs you a bad diff, plus the time spent finding it.
  • Never touches your settingsdeadeye keeps its own state in one file. Your settings.json stays yours, untouched.
  • Never blocks your workIf anything inside deadeye errors, that call just passes through untouched. A tool like this should never be the reason your work stops.

Range card

What it manages

Each one works on its own, has its own on/off setting, and can be switched off without touching the others.

What / effect / default settingoff · advise · enforce
WhatWhat it doesDefault
ContextTrims verbose command output before it enters context — test suites across nine language ecosystems, builds, linters, package installs, pod logs, log tails. Also flags wasteful patterns: re-reading unchanged files, whole-reads of huge files, a command re-run (identical, or the same target with only flag changes), a URL re-fetched, an oversized MCP response, a paste-sized prompt, a long exploration streak better handed to a subagent, and a good moment to /compact before auto-compact lands mid-task. The biggest, safest win.on
CoderA lean-first coding persona injected every session (it survives compaction) and into subagents: question whether the code needs to exist, stdlib before custom code, one line before fifty — plus a live security check on what's written and its dependencies. Three levels — spotter, marksman, sniper.marksman
SecurityThe exfiltration guard — a Read of a credential file, or a Bash command shipping one out, escalates to a permission prompt the model can't answer for itself. Adding a known-vulnerable dependency asks too; existing ones get flagged at session start. Independent of coder mode.ask
Codebase mapA persistent per-project map — directory/package skeleton, most-touched files accumulated across every session, recent exploration notes — injected once per session so a fresh session doesn't re-explore the repo from scratch.on
EffortSuggests lower effort for mechanical steps, or sets it on subagent calls that didn't choose one. Has no effect if CLAUDE_CODE_EFFORT_LEVEL is pinned for the session — /deadeye-status tells you plainly if that's the case.advise
ModelPicks the model when a subagent starts. Prices come from a table built into the binary and refreshed from a hosted copy, so a new model or price reaches you without a release. Each host has its own table.advise
Routing judgeClassifies a subtask the cheap signals can't place, with one small claude -p call on your own login: about half a cent, about 2.5 seconds, cached per task.on
Plan gateAsks once before a multi-file edit that skipped writing a plan first, then stays quiet for the rest of that task.soft
WorkflowSuggests the ultracode keyword when a task looks like genuine parallel/fan-out work. Only ever suggests it — never starts one for you.on

Fits alongside the built-ins

Covers what Claude Code doesn't

Claude Code ships its own reviews, plan mode, and size-based output truncation. deadeye doesn't compete — it layers under and around them. Coder mode, security and the codebase map open up below the table.

Built-inwhat deadeye adds
/code-review, /simplifyNative review is open-ended and conversational. /deadeye-review runs four fixed lenses — over-engineering, correctness, performance, security — and drops any finding that can't show its proof. Confirmed findings feed next session's coder mode.layers
/security-review/deadeye-guard is the quick pass on the current diff, OWASP-mapped, with dependency audits. Escalate to /security-review for the full audit.layers
PR review/deadeye-pr puts a whole PR through the same four lenses, ranked by severity. Prints locally; --post adds inline comments with one-click suggestions.four lenses
Plan modeNative plan mode exists, but nothing triggers it. deadeye's gate notices a risky multi-file edit coming and nudges into it.triggers
Output truncationNative truncation cuts by size, at 30K characters. deadeye rewrites the command before it runs, so only the failure context enters at all.stacks
Subagent modelsNative subagents inherit the parent's model. deadeye recommends the cheapest tier the evidence supports, or sets it for you, and /deadeye-stats shows what each subagent actually ran on.routes
No native equivalent/deadeye-vapt: a whole-service pen-test pass with full OWASP coverage, ranked worst-first, every finding linked to its source standard.unique
No native equivalent/deadeye-sweep: applies the serious findings from the reviews above, verifies the build, and re-scans until clean. Never pushes or comments without asking.unique
No native equivalentCoder mode: a lean-first coding discipline injected every session. Expands below.unique
No native equivalentIt checks its own claims: /deadeye-stats accuracy, disagreement and adherence report where the reviewer, the router and the persona fell short.unique
A marksman's coding discipline

Beyond routing and trimming, deadeye can inject a coding persona: a lazy-senior-dev discipline that pushes every change toward the leanest solution that actually works. Injected at every session start — it survives compaction — and travels into subagents too.

Level / discipline/deadeye-coder
SpotterCalls the shot, doesn't take it: builds what's asked, names the leaner alternative in one line. You pick.light
MarksmanThe lean-first ladder enforced: YAGNI, stdlib before custom code, native before dependencies, shortest working diff.default
SniperOne shot only. Ships the one-liner and challenges the rest of the requirement in the same breath.max

Deliberate shortcuts get a deadeye: comment naming the ceiling and upgrade trigger — /deadeye-debt collects them into a ledger. Safety isn't just preserved, it's checked for: input validation, error handling that prevents data loss, security, and accessibility stay at every level, and a live pass flags injection, secrets, weak crypto, and vulnerable dependencies as you write. Every handled failure leaves one log line, at error or warn, without being asked; routine success stays silent.

/deadeye-coder sniper DEADEYE CODER CHANGED — level: sniper every session start: DEADEYE CODER ACTIVE — level: sniper the ladder, abridged: 1. Does this need to exist at all? 2. Already in this codebase? 3. Stdlib does it? 4. Native platform feature covers it? 5. Already-installed dependency solves it? 6. Can it be one line? 7. Only then: the minimum code that works.

Off any time: say normal mode, or DEADEYE_CODER=off. An optional statusline badge shows each session's live level — deadeye offers the setup once and never edits your settings itself.

How it worksone ruleset, filtered
InjectThe ruleset ships embedded in the binary. At every session start the daemon prints it into the model's context, filtered to the active level — a marksman session never pays tokens for the other levels' rows.start
SurviveWhen Claude Code compacts a long conversation, the hook fires again and re-injects at whatever level you'd switched to. No drift back to over-building.compact
TravelSubagents inherit a condensed card — just the behavior-bearing rules. Measured: 9,499 bytes per spawn before, 1,099 after, an 88.4% cut on every spawn. Scope it with coder.subagent_matcher.−88.4%
ResolveKill switch beats your session switch, beats coder.default_level in config, beats the built-in default. Switches last until the session ends.precedence
GuardEvery Edit/Write is checked against the ADDED text only — injection shapes, secrets, provider tokens, weak crypto, TLS-off, and near-zero-FP pen-test shapes (unverified JWTs, insecure deserialization, permissive CORS, SSTI, XXE, open redirects and more) — plus the dependency itself on a manifest edit. Independent of the persona level now, so stop coder doesn't silence it. Deep pass on demand: /deadeye-guard, or a full whole-service pass: /deadeye-vapt.check-your-backstop
the same request, per level -- "add a cache for these API responses": spotter Done, cache added. FYI: lru_cache covers this in one line if you'd rather not own a cache class. marksman @lru_cache(maxsize=1000) on the fetch function. Skipped custom cache class, add when lru_cache measurably falls short. sniper No cache until a profiler says so. When it does: @lru_cache. A hand-rolled TTL cache is a bug farm with a hit rate.

Every answer keeps one shape: code first, then at most three short lines — what was skipped, and when to add it. Bug fixes go to the root cause every caller routes through, not the one path the ticket named. Comments follow their own rule: the why, never the what — and corner-cuts use a pinned grammar (deadeye: … ceiling: … upgrade: …) that /deadeye-debt parses reliably.

the same request, per level -- "look a user up by name": spotter Done. FYI: name is interpolated into the query -- bind it instead. marksman Parameterized query, name bound not interpolated. Skipped a sanitizer layer; the driver escapes. sniper Bound parameter, and it returns id+name only -- fewer columns out, less to leak.

The safe form is usually the SHORT form — a parameterized query beats hand-rolled escaping, exec.Command(bin, args...) beats building a shell string. Lean and safe are the same move.

Editing a manifest checks the dependency too: a bundled table flags packages the platform has since absorbed (request → fetch, moment → Temporal/date-fns), and an optional OSV.dev lookup catches known vulnerabilities — name and version only, nothing else about the code, and never on the hook's response path: a cache miss refreshes in the background and informs the next edit, never blocks this one. Turn just that lookup off with coder.security_osv: false; the bundled table keeps working fully offline. /deadeye-guard is the on-demand deep pass — diff-scoped, verifies a missing sanitizer or authz check against the surrounding code before reporting it, and runs govulncheck/npm audit/pip-audit/cargo audit when installed.

A prompt injection can't answer a permission prompt

The real attack on a coding agent isn't bad code you write — it's malicious content in a repo or a web page telling the agent to read your credentials and ship them out. deadeye already sits at the exact choke points, so it watches them: the moment that matters escalates to a prompt you answer, not one the model can talk itself past.

Read ~/.ssh/id_ed25519 → permission: ask deadeye exfiltration guard: Read of a sensitive credential path (ssh-private-key). Approve only if you asked for this; a prompt-injected instruction cannot answer this prompt for you. # stays silent, because these are routine: Read ~/.ssh/config Read .env.example ssh -i ~/.ssh/id_rsa deploy@host

Covers ssh private keys, ~/.aws/credentials, .env, ~/.claude/.credentials.json, ~/.netrc, kube/docker/gcloud/gh tokens, and your own security.sensitive_paths — on Read and on a Bash command shaped to ship one out (a credential piped to curl/nc/scp, an env dump to the network). Default ask; soften to advise or off.

The rest of the security surfacesecurity.*
Its own axisThe exfil guard is security.exfil, not part of coder mode — turning the persona off never turns it off. Only DEADEYE=off or security.exfil: "off" does.ask
Not a moodThe live Edit/Write check (injection shapes, secrets, provider tokens, weak crypto, TLS-off, across five languages) no longer dies when you say stop coder. Security is part of coding, not the persona's voice.advise
Vulnerable depsAdding a package with a confirmed OSV advisory asks by name (coder.security: "ask"). And once per session deadeye flags what's already in your tree with a known advisory.ask
Provider tokensA bare ghp_…, xoxb-…, sk-ant-…, Stripe live key, or signed JWT pasted as a literal is caught even with no key = around it — length-bound so prose never trips it.secret

Honest ceiling: the exfil guard matches regex-visible shapes, not shell obfuscation or a novel egress binary. It shrinks the blast radius of the common automated attack — it isn't a sandbox. /deadeye-guard is the deep, diff-scoped pass with native auditors.

A fresh session shouldn't start from zero

A fresh session normally burns 15–40 tool calls rediscovering the project — directory layout, what each package does, which files matter. deadeye persists that per project under ~/.deadeye/map/ and injects it once, at the first prompt.

What persists~/.deadeye/map/
SkeletonDirectory rows with file counts and, for Go repos, each package's one-line doc-comment purpose. Built from git ls-files, regenerated only when the tracked-file list changes.map.md
Touch counterA path → sessions counter merged at every session end, ranked by relevance rather than recency — a file touched in 14 of 20 sessions stays on top.touched.json
Exploration notesThe explore skill caches its summary via deadeye notes-append so the next session inherits findings instead of re-deriving them. Newest 5 kept.notes.md

First-ever session in a project gets nothing — the map is written at session end, so value starts at session #2. Resumed or compacted sessions are skipped; their context already carries the exploration.

injected once, at session start: # Codebase map: deadeye-cc scope: 145 git-tracked files cmd/deadeye/ 37 files .go internal/codemap/ 6 files .go the structural half of the map internal/coder/ 4 files .go the lean-first persona Frequently touched files: README.md 4 sessions internal/codemap/codemap.go 3 sessions

Lives under mode.codemap (off/on, default on) — the same DEADEYE=off kill switch turns it off along with everything else.

Measured, not estimated

Every number here comes from a logged decision

Every time deadeye trims something, it logs which rule fired. Every decision is logged with what went into it. Nothing here is a made-up formula that turns "we ran N tool calls" into a savings number — if it isn't a real row in decisions.jsonl, it doesn't get printed.

/deadeye-stats savings real session, this repo -- add Mark() + test, subagent delegated 17 decisions logged by surface PostToolUse 7 PreToolUse/Edit 3 PreToolUse/Agent 1 SessionEnd 1 PreToolUse/Bash 2 Stop 2 SubagentStart 1 by action advise 1 noop 13 rewrite 2 savings-shown 1 preprocessing rewrites (estimated bytes -- see each rule's EstBeforeBytes/EstAfterBytes, not a measurement of this run) build-filter 1x ~15,000 → ~9,600 bytes test-filter 1x ~30,000 → ~9,600 bytes total ~45,000 → ~19,200 bytes (~25,800 saved) Cross-check these figures against /usage's plugin attribution.

Unedited output from a real feature task run through the installed plugin — a cheaper model suggested before a subagent started, both commands trimmed, an end-of-turn savings summary. The 25,800 figure is each rule’s own labelled estimate; the 485 → 99 and 10,301 → 55 numbers up top are the measured ones. Captured before quiet no-op rows stopped being logged (0.7.0), so yours will show no noop line, and adds a Subagents section.

After installing

Check it, switch it off, ask it questions

The install commands for each host are at the top of the page: pick your host there.

Is it working?

deadeye doctor

One read-only pass over the plumbing: the binary, whether ~/.deadeye is private, whether config.json parses, the daemon, whether the routing judge can reach claude, and whether the hooks cover every tool deadeye handles. Each failure prints the command that fixes it.

Turn it off

DEADEYE=off everything DEADEYE_PREPROCESS=off context hygiene DEADEYE_GATE=off plan gate DEADEYE_CODER=off coder persona

Every control also has its own switch on the settings page.

Does it phone home?

No telemetry, no API keys, no deadeye-run service. Everything it remembers lives in one local folder, ~/.deadeye/. Two kinds of traffic leave your machine, each with its own off switch:

  • The routing judge (on by default) sends an ambiguous task's description, never your code, to claude -p on your own login. It is the one thing that blocks a hook: about 2.5 seconds on a first-seen unsure task, 10 at most, then it fails open.
  • Three background checks send nothing of yours and never block: a release check, an OSV.dev lookup for flagged dependencies, and a refresh of the model catalog.

Off by default: tier sampling (mode.tier_sample) asks the judge for a second opinion on some confident decisions, to measure over-routing. Same payload, and it runs after the decision.

Can I check whether any of this actually works?

/deadeye-stats has three views that hold deadeye to its own claims:

  • accuracy: reviewed diffs where a later fix landed on lines the review passed, beside the findings you disputed.
  • disagreement: where the judge would have routed cheaper than the heuristics did. A second opinion, not a replay.
  • adherence: the coder ladder's checkable rungs on shipped diffs: new dependencies, files per change.

They measure going forward, so an empty report means "not measured yet", never "nothing wrong".

Will it make Claude dumber?

That's the failure it's built to avoid. When it isn't confident about a task, it defaults to the more capable option; cheaper always needs real evidence first. If it under-powers a task, that's a bug: report it with the /deadeye-route output.

It rewrote a command and I needed the full output.

Every rewrite rule is conservative and can be turned off on its own in config. A rule that loses information the agent needed is a bug in that rule: report it with the command.

Can it change the model my main session is using?

No. Nothing can do that reliably partway through a session. deadeye sets the model for subagents, where most of the tokens go, and only advises on the main session.

Does coder mode cut corners on safety?

No. At every level the persona keeps input validation at trust boundaries, error handling that prevents data loss, security measures and accessibility basics. Every deliberate shortcut gets a deadeye: marker with an upgrade trigger, so /deadeye-debt can hold it to account later.

Why "deadeye"?

Because efficiency isn't spending less — it's not missing.