Drive terminal coding agents by voice, with receipts that never claim more than they proved.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
π‘ Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Drive terminal coding agents by voice, and never let the answer claim more than it proved.
You are away from your desk. You speak; an agent in a terminal does the work; you get a spoken reply. That reply is the only thing you have β you cannot see the screen. So the worst failure is not a crash, it is the voice saying "done" while your text sits unread in a prompt box.
Yapitalism is a local MCP server that lets a voice client reach your coding agents, plus a receipt layer that decides what the voice is allowed to say.
Public pre-alpha. Local-only. No production deployment, no external messaging, and no automation of closed-source clients.
The voice client never reaches your machine directly: it drives a local agent session, and that
session talks to this server over 127.0.0.1. Nothing is exposed to the network.
pane_send returns a verdict, not a shrug.
| meaning | |
|---|---|
| GREEN | the agent echoed a one-time marker. It demonstrably processed the text. |
| YELLOW | the write landed; processing was not proven. Never round this up. |
| RED | the backend refused the write. Nothing reached the terminal. |
YELLOW is the whole point. Text left unsubmitted in an agent's input box looks identical to work
in progress from outside β same spinner, same scrolling output, same HTTP 200. A voice that rounds
that up to "done" costs you hours before you notice.
Explicitly not acceptance: an HTTP 2xx, a PTY write returning, terminal output changing, a revision advancing, or the prompt echoing your own words back.
A fixed deadline reports on the clock, not on the agent. An agent that thinks for a minute and then answers correctly was verified all along, and calling that YELLOW teaches an operator to ignore YELLOW. So the wait is an idle timeout: it restarts whenever the pane changes, bounded by a hard ceiling.
Pane movement decides only whether to keep waiting. It is never evidence of acceptance β that stays the canary alone. A YELLOW therefore says which kind it is:
canary_timeout_pane_moving β the pane's text was still changing. Named after what was
measured: a spinner, a clock, a log tail or a second agent sharing the pane all produce this
without the intended agent doing anything. It is a hint that looking again may be worth it,
never a claim that the agent is working.canary_timeout_pane_still β nothing moved at all.What remains irreducible: if an agent silently ignores the text and prints nothing, no mechanism here can distinguish that from an agent that never received it. Verification needs the agent to emit something.
A receipt carries who enforced each guarantee, which is finer than whether:
| meaning | |
|---|---|
host | the host refuses the write itself β the check and the write are one operation |
client | this process checks, then writes; real against what it covers, not atomic |
none | nothing checks |
yapitalism setup prints the table for your machine. On a Superset host carrying the guarded
terminal.send, all three are host. On a stock Superset build β which routes terminal.writeInput
and none of the guarded send β they move to client, and the send still happens. tmux enforces two
of three itself and cannot do the third at all.
These levels are asked of the host, not assumed. They were constants describing one machine's build until that was caught: every stock user would have received a GREEN asserting three guards their host had never heard of.
Both reach GREEN. They are not the same GREEN, and saying so is the difference between a receipt and a decoration.
Needs Python 3.11+ and tmux. Everything runs on your machine; nothing is exposed to the network.
setup interviews the machine rather than printing "installed successfully": which backends are
usable, which agent CLIs are on PATH, whether a Superset host is live and which build it is, and
the guarantee table above filled in for you. It writes nothing except, if you say yes, the Superset
manifest β and it names what is still missing with the exact command for each.
Then talk to the voice app: "list my panes", then "send this to the Codex pane".
YAPITALISM_MCP_PORT moves the port if 8792 is taken. YAPITALISM_TMUX_SOCKET targets a
non-default tmux server.
Codex takes a URL. Claude Desktop, Cursor and most other MCP clients instead spawn the process
and speak over stdin/stdout, so point them at --stdio and do not run a separate server:
Use the absolute path from command -v yapitalism-mcp if the client does not inherit your
PATH β GUI apps on macOS usually do not. YAPITALISM_MCP_TRANSPORT=stdio does the same as the
flag, for clients that only let you set the environment.
In stdio mode nothing but protocol may reach stdout, so the server suppresses its own startup banner. If you wrap it in a shell script, keep that script silent too.
The voice route dies when the server does, so run it under your init system rather than a terminal. Both units run as your user, never root: the server can read every terminal you can see.
.agents/launchd/. The plist is a template; its README has a sed line that
fills in the real binary path, because launchd searches neither PATH nor ~..agents/systemd/, a --user unit. systemctl --user enable --now yapitalism-mcp.Kill any shell instance first either way, or the two race for port 8792 and which one wins is down to timing.
The tmux backend needs nothing. Superset needs a 0600 manifest holding the host endpoint and
token β and you do not write it by hand, because Superset already writes what it needs:
That reads the app's own ~/.superset/host/<organizationId>/manifest.json, proves the token against
the live host, picks a default terminal and writes
~/.cache/superset-watch-voice/yapitalism-manifest.json (or $YAPITALISM_SUPERSET_MANIFEST). It
refuses rather than guesses: a source file looser than 0600, a manifest naming a dead process, or
two live organizations with no way to choose all stop it. The token is never printed.
Without a manifest, panes_list still returns your tmux panes and reports Superset in errors β a
backend that could not be reached is never silently reported as "no terminals".
.agents/skills/superset-operator/ holds the policy that stops a model rounding YELLOW up to
"done", plus a drift check against the copy your agent actually loads.
The five-leg model is usable without the MCP server:
capture β the intent was captureddispatch β a concrete target received a write attemptaccept β the target proved acceptance by canary or explicit acknowledgementwork β material agent progress was observeddeliver β a final update reached the userEvidence carries provenance β api, terminal_diff, ui_observation, user_report, inferred β
and inferred may never mark a leg succeeded. Events append to a 0600 JSONL ledger with a
per-row hash chain, contiguous sequence, and single-use confirmation claims for anything that
mutates a terminal.
That fixture is the incident this project came from: the audio session stayed alive, spoken progress
stopped, two 180-second watchers saw the terminal frozen at revision 920118, and the canary never
arrived. The product is not "fix the voice client". It is never fake GREEN.
CLI surface: doctor, receipt show, ledger verify|manifest|migrate, and superset status|send.
A confirmed superset send requires reusing the exact client-token a dry run emitted, snapshots
immediately before dispatch, rejects a changed revision, and never retries an ambiguous POST.
Stated plainly, because a receipt system that overclaims is worse than none:
docs/adr/0004.pane_send takes no
expected revision. Reading the pane twice and refusing if it moved would be a different guarantee
wearing that name, so it is reported none rather than approximated.pane_clear
is the way through. Validated against real panes, not a large sample.The receipt-integrity core was written by @liri-ha, whose commits are carried here unrewritten. See CONTRIBUTORS.md.
Raw transcripts, terminal text, and credentials do not belong in this repository. Ledgers store
bounded metadata, hashes, and classifications. A manifest holding a bearer token lives outside the
repo at mode 0600 and is read only when its path is passed explicitly; it is never printed. See
SECURITY.md.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/yapitalism)<a href="https://allmcps.com/mcp/yapitalism"><img src="https://allmcps.com/api/badge/yapitalism?style=directory" alt="Yapitalism on AllMCPs" /></a>