Honest state of the project. Nothing here is marked done until it works and has tests.
M0 — Scaffold — implemented#
Bun workspace monorepo, TypeScript project references, biome, CI on macOS, Linux
and Windows, Bun.build bundling, earshot --version.
M1 — Provider layer — implemented#
- Unified message, request and stream-event types
- One bridge to the AI SDK's
LanguageModelV4spec, shared by every adapter - 7 wire adapters, 19 providers, 896 models
- models.dev catalog, pruned at build time; live refresh
- Auth store (
0600, atomic) and the CLI → env → file → ambient resolution order - Cost accounting including prompt caching
earshot models,earshot -p- Conformance suite covering every adapter through the shared bridge
Historical M1 deferrals (resolved below): the ChatGPT sign-in (openai-codex-responses) provider, and
Ollama's native adapter — At that milestone Ollama used the OpenAI-compatible endpoint,
which drops tool calls when streaming.
Verification: the shared conformance suite uses scripted output, and an OpenRouter free-route request has completed against the live API.
M2 — Coding agent — implemented#
The milestone that makes earshot usable.
- Agent loop: assemble → stream → tool calls → permission gate → execute → repeat.
runTurn()is an async generator, interruptible viaAbortSignal; read-only calls run concurrently, mutating ones serialised in emission order - Steering: a message typed mid-turn is injected at the next model call rather than cancelling the turn
- Tools:
read,write,edit,multi_edit,ls,glob,grep,bash,bash_output,web_fetch,ask_user,todo - Permissions: modes
plan | ask | accept-edits | auto | yolo;Tool(pattern)rules at global, project and local scope; deny-first and never overridable by allow; writes outside cwd always ask; command rules match every segment of a chained command, not just its prefix - Sessions: tree-structured JSONL under the data dir,
--resume,--continue AGENTS.mdloading (andCLAUDE.md), nearest-wins by ordering- Ink TUI: inline scrollback via
Static, permission and question prompts, diff view, collapsible tool blocks, status line - Undo: per-tool-batch snapshots in a shadow git object store, outside the user's repository
Decision taken: Windows requires Git Bash. bash resolves Git for Windows
and fails with an install pointer when it is absent, rather than falling back to
PowerShell. Two shell dialects would mean quoting, pipelines and permission-rule
matching all differ by machine for the tool the agent uses most.
Historical M2 deferrals (resolved below): context shapers and auto-compaction, /fork, /rewind and
/undo — all landed in M3.
Verification: the complete agent loop has run against OpenRouter's live API in headless mode as well as against scripted providers in the suite.
M3 — Listening + context — implemented#
The milestone the project is named after.
- Context shapers, run before every model call, cheapest first: individual tool
results capped head-and-tail, older results reduced to one-line stubs, and
auto-compaction at 80% of the window — a model-written summary plus the recent
messages verbatim, open todos and files touched. Nothing rewrites history:
the request is shaped, and compaction appends a
summaryentry naming the entries it stands in for - Scope contract:
declare_scopebefore the first change, and a guard that stops and asks on a file nobody listed, a dependency, a rename or delete, a formatting sweep, a removed test, or a turn several times its own estimate - Preference memory with provenance: files with frontmatter recording the user's
own words and the date, an index in every prompt, two-keystroke capture from a
correction typed at the prompt,
/memoryto review and forget - Honest completion and verification: a turn that changed files runs the project's detected test command and puts its output in front of the model verbatim, alongside a self-check comparing the request with what changed
- Status line: context percentage and what compaction has dropped, beside spend
- Session tree:
/tree,/rewind,/fork,/undo
Historical M3 deferrals (resolved below): /plan (behaviour 3) and the intent line (behaviour 6),
which move to M4 with the rest of the command surface. Curiosity levels and
--max-cost also landed later, after M6.
Verification: the TUI has completed a live-model turn in a real macOS PTY; its detailed interaction suite also runs against a controlled terminal stream.
M4 — Extensibility — implemented#
The milestone where earshot stops being a closed program. Everything in it is a contract with code somebody else wrote, so each boundary is documented by what it is not allowed to do. See Extending earshot.
- MCP client — stdio and streamable HTTP, tools namespaced
server__tooland put through the same gate as built-ins. An MCP tool is never read-only whatever the server claims about itself, and a stdio server a project checked in does not start untilearshot mcp trustsays so - Skills and slash commands — discovered from the project and the config
directory. A skill contributes instructions and nothing else;
allowed-toolsintersects with the session's tools and can only narrow them - Hooks — Claude Code's JSON contract, with one deliberate incompatibility: a hook may deny or downgrade an allow to a prompt, never approve. A hook that fails, times out or prints garbage blocks nothing
- Subagents — a nested agent with its own context window, inheriting the permission rules, the declared scope, the approved plan and the cost total, and returning an answer rather than a transcript
- Headless JSON —
earshot.v1on every record, additive within the version, a new major requested by name. See Headless output /plan— a plan file you edit in$EDITORand approve; what is pinned is what the file says, not what the model wrote- Intent line — a one-line "why" before every tool batch, as an event, so a batch that arrived without one is visible rather than merely undesirable
- OpenRouter PKCE sign-in, and Ollama's native
/api/chatadapter, which keeps tool calls that the OpenAI-compatible endpoint drops
Historical M4 decision: ChatGPT sign-in for Codex models, which moved from "planned"
to "deliberately not supported" — see
Providers. Curiosity levels and
--max-cost landed after M6.
Verification: the suite spawns a real stdio MCP process and covers its environment isolation, tool listing, calls, diagnostics, and shutdown.
M5 — Ship — acceptance remaining#
Documentation, npm i -g @raegent/earshot, compiled binaries (macOS arm64/x64, Linux
x64/arm64, Windows x64), earshot doctor, Windows QA in Windows Terminal, changelog,
contributor guide.
This website owns the latest-only MDX documentation. The historical VitePress deployment is retired only after a coordinated launch update. Tagged
releases validate a clean global npm install, publish the package, and ship
five native executables. earshot doctor validates the local runtime without exposing
credentials. Windows has native CI plus a release-blocking Windows Terminal
acceptance checklist; the checklist result is recorded per release rather than
claimed by code.
Release acceptance remaining: record the hands-on Windows Terminal checklist and verify release assets and public destinations. Publication and acceptance are external release actions, not claims established by local builds.
Target: adding an OpenAI-compatible vendor takes ≤30 lines. Currently 1.
M6 — v1.x — acceptance remaining#
ACP server (Zed, JetBrains, Neovim), in-process TypeScript extensions, image input, tool search for large MCP sets.
ACP implemented: stable v1 initialization, session creation and loading, prompt streaming, cancellation, permissions, elicitation and tool events are implemented with protocol-level tests. Zed, JetBrains and Neovim still require the recorded physical QA checklist in Editor integration with ACP; client-provided MCP definitions and draft ACP v2 are not part of this slice.
Image input implemented: unified user prompts now carry text and images into
compatible provider adapters from --image and ACP. Unsupported model
capabilities and file formats fail before the provider request.
Tool search implemented: past 25 MCP tools, their schemas leave the request
and tool_search finds them on demand. A surfaced tool is listed for the rest of
the session and goes through the same permission gate it always would; the
search itself grants nothing.
In-process extensions implemented: a module in .earshot/extensions/ or the
config directory contributes tools directly, namespaced and gated like any
other. A project extension is inert until earshot extensions trust names it,
because being in-process means it is not sandboxed and cannot be.
Dropped from M6: Anthropic server-side compaction. earshot's own shapers and compaction are provider-agnostic and already do the job; a second, vendor-only context path would mean the loop behaves differently depending on who is serving the model, which is the thing the provider boundary exists to prevent.
Acceptance remaining: the recorded editor QA checklist in Zed, JetBrains and Neovim. Everything else in M6 is implemented and covered by tests.
Since M6: --max-cost and curiosity, the last two behaviours
Listening described but the code did not have.
M7 — Trust at Scale — future#
Production hardening and a sustainable ecosystem after M6 has seen real use:
- Stable v1 compatibility guarantees for configuration, transcripts, headless
output, ACP, and extension APIs. Two of those surfaces already carry a version
marker and an additive-within-the-version rule —
earshot.v1on headless records and ACP v1 — so for them M7 is writing the promise down and testing it, not inventing it. Configuration, the transcript format and the extension API have no such marker yet - A discoverable plugin and extension marketplace with sandboxed third-party
code. This is the one item M6 argues with: in-process TypeScript extensions
are deliberately not sandboxed and cannot be, which is why a project
extension stays inert until
earshot extensions trustnames it. A marketplace therefore needs an execution boundary that does not exist today — an out-of-process extension host, or distribution restricted to MCP servers — and choosing it is the first design question of this item, not a detail of it - Signed standalone binaries, macOS notarization, and Windows code signing
- Signed automatic updates with stable, beta, and nightly release channels
- Crash recovery and repair tooling for interrupted or damaged sessions. Sessions are append-only JSONL and history is never rewritten, so a damaged session is a truncated or partial-line tail rather than a corrupt structure; repair means detecting that tail and recovering the tree around it
- Performance benchmarks and regression budgets for startup, rendering, context
shaping, and long-running sessions. The harness and the recorded baselines are
in —
bun run bench, documented in Performance baselines, with CI recording a run per platform on every push tomain. The budgets are deliberately not: the first baselines put startup at a 9% spread and several in-process cases above 200%, so what a threshold may claim has to come from the accumulated history rather than from the first run that produced it - A maintained live-provider compatibility matrix. This is the standing gap the suite cannot close: every adapter is covered through the shared bridge with scripted output, and only OpenRouter has answered live
- Package-manager distribution through Homebrew, WinGet, Scoop, and AUR
- Independent security audit and a refreshed threat model before v1 stability
Entry condition: M6 has shipped and real editor/extension usage has exposed which interfaces deserve a long-term compatibility promise. Until then, this is direction rather than a frozen contract.
Current acceptance boundary. The 0.3.2 npm package and update implementation exist. Windows Terminal and physical editor acceptance must be recorded per release; this documentation does not infer those results from a passing test suite. Performance baselines and compatibility contracts already exist; signing, distribution channels, and broader live-provider coverage remain future work.
Explicitly out of scope#
- Subscription workarounds. No Claude Pro/Max OAuth, no Gemini Code Assist OAuth, nothing that circumvents a provider's terms. See Providers.
- A web UI. earshot is a terminal tool. The ACP server covers editors.
- Model hosting or fine-tuning. Not this project.
- Telemetry. Zero, with an optional local usage log.
Where help is most useful#
- Live provider testing. The single biggest gap. If you have a key for anything, run a turn and report what breaks.
- Adding providers — usually one line.
- Windows testing. CI covers it; real terminals are another matter.
- Driving the TUI for real. An interactive macOS PTY smoke test has completed; broader real-terminal coverage is still useful.