{
  "markdown": "<h1 align=\"center\">Termada</h1>\n\n<p align=\"center\"><b>Persistent, policy-controlled missions for AI agents operating real environments.</b></p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/Islomzoda/termada/releases\"><img alt=\"Release\" src=\"https://img.shields.io/github/v/release/Islomzoda/termada?color=2ea043&label=release\"></a>\n  <a href=\"https://github.com/Islomzoda/termada/actions/workflows/ci.yml\"><img alt=\"CI\" src=\"https://github.com/Islomzoda/termada/actions/workflows/ci.yml/badge.svg\"></a>\n  <a href=\"https://registry.modelcontextprotocol.io\"><img alt=\"MCP Registry\" src=\"https://img.shields.io/badge/MCP-registry-5b5bd6\"></a>\n  <img alt=\"Go\" src=\"https://img.shields.io/badge/go-1.26.5%2B-00ADD8\">\n  <a href=\"LICENSE\"><img alt=\"License\" src=\"https://img.shields.io/badge/license-Apache--2.0-blue\"></a>\n</p>\n\nTermada is a single-binary, local-first runtime that sits between an AI agent and\nthe terminal, locally or over SSH. The agent talks to it over the\n[Model Context Protocol](https://modelcontextprotocol.io) and gets a sturdy\ntoolset instead of a raw shell: bounded `exec_run` waits, persistent sessions\nthat keep `cwd`/env, async jobs with streamed output, PTY input for interactive\nprompts, and structured results — while you watch and control active jobs from a\nlive dashboard with a job kill-switch and an approval queue. **Mission Control**\nadds a durable goal, GPT/Codex-authored plan, runtime-verified steps, interruption\nrecovery, and an exportable evidence report around that execution.\n\n<p align=\"center\">\n  <img alt=\"Termada — the live dashboard\" src=\"docs/preview.jpg\" width=\"860\">\n</p>\n\n<p align=\"center\"><sub>The live dashboard: every session is a real terminal you can watch and take over — block or pause the agent, type in yourself — beside the agent panel, policy management, a tamper-evident History, and a Stop-All active-job kill-switch.</sub></p>\n\n---\n\n## Why\n\nHanding an AI agent a raw shell is fragile and opaque: a command blocks on a\nprompt and the agent hangs; `cd` and exported env vanish between calls; long\nbuilds flood the context window; and you can't see — let alone stop — what's\nrunning. Termada replaces the raw shell with a runtime that is **reliable** for\nthe agent and **transparent** for you:\n\n- **Reliable for the agent** — blocking `exec_run` calls use bounded wait budgets\n  and return structured output; sessions persist `cwd`/env; long jobs run async\n  and stream incrementally instead of dumping; interactive prompts are answerable.\n- **Transparent for you** — one dashboard shows every agent and every session as\n  a real terminal; controlled actions matched by `confirm` wait for your approval; one\n  button installs a short-lived action admission barrier, requests cancellation\n  of active gateway executions, signals active engine jobs and closes forwards;\n  remote/provider effects still require terminal verification or reconciliation.\n- **Accountable as a mission** — an agent's plan, real commands, approval\n  decisions, verification jobs, outcome, and audit anchors stay together. A plan\n  step cannot pass without a real mission job that Termada observed exiting with\n  code zero.\n\n## Mission Control\n\nFor a concrete operational outcome, Codex or another MCP agent starts with\n`mission_create(goal, plan)`. Termada allocates a dedicated persistent session;\nnormal `exec_*` calls keep using the same policy, approval, PTY/SSH and audit\npaths. The agent attaches each successful `job_id` with `mission_update`, then\nexports `mission_report`.\n\n<p align=\"center\">\n  <img alt=\"Termada Mission Control waiting for a human approval\" src=\"docs/build-week/screenshots/approval-desktop.jpg\" width=\"860\">\n</p>\n\nThe report separates runtime-observed evidence from agent notes, includes exact\naudit sequence/hash anchors, and returns a SHA-256 recorded in the audit. If the\ndaemon restarts, a non-terminal mission becomes `interrupted`; `mission_resume`\ncreates a fresh session attempt instead of pretending PTY state survived.\n\nRun the isolated real-execution demo:\n\n```bash\n./demo/mission-control/run.sh\n```\n\nIt starts a broken loopback HTTP service and a separate demo daemon. The\nprotected repair genuinely changes service state and waits for a human approval;\nthe final probe must observe HTTP 200. See\n[`demo/mission-control`](demo/mission-control/README.md) and the\n[`2:40 demo script`](docs/build-week/DEMO_SCRIPT.md).\n\n## Features\n\n**Execution engine**\n- Persistent-shell sessions over a PTY that keep `cwd`, env, and venv between commands.\n- Async jobs: `exec_start` → `job_id`; poll incrementally by a stable cursor, with sequential bounded pages, a full status state machine and structured errors.\n- Answer interactive prompts (`exec_write`, with secret redaction). Local PTY\n  jobs support process-group signals/kill; remote SSH interrupt/kill requests\n  are best-effort Ctrl-C, not a guaranteed force-kill.\n- Clean output: stateful ANSI/VT stripping, CR-collapse, bounded retention, best-effort secret redaction.\n\n**Live control & observability**\n- A long-lived daemon with a control plane over a Unix socket; `serve --stdio` is a thin shim that proxies MCP to it — so **multiple agents share one daemon and one dashboard**.\n- Web dashboard where **each session renders as a real terminal** (xterm.js, streamed over SSE) with **operator take-over**: type into a job's PTY, hold the agent's input, or pause its output.\n- Workspace labels, bounded state bootstrap, cursor-resumable live updates,\n  English controls and responsive desktop/mobile navigation.\n- Approval queue, activity feed, policy/server management, and a **Stop-All**\n  cancellation barrier for admitted actions, active engine jobs and forwards.\n- A TUI (`termada top`) and a full inspection CLI.\n- Synchronously recorded, hash-chained, best-effort-redacted audit log. `termada audit verify` verifies the continuous chain across rotated segments.\n\n**Mission Control**\n- Durable, owner-scoped missions with a goal, up to 24 plan steps, dedicated\n  session, multiple resume attempts, bounded evidence timeline and terminal\n  outcome.\n- Runtime enforcement for passed steps (`job_id` from a mission session,\n  `status=exited`, `exit_code=0`) and refusal to succeed while jobs remain active.\n- Mission-first desktop/mobile dashboard with pinned approval, stale/offline\n  states, compact plan/evidence views and Markdown report download.\n\n**Security**\n- Policy engine: every argv word is shell-quoted; allow / deny / confirm matching sees leading assignments, absolute paths, Darwin case variants, known wrappers and explicit shell payloads. Shell scripts/stdin/interactive shells and ambiguous compound commands fail closed when deny/confirm rules exist. The structured policy additionally matches authenticated principal, tenant, typed action/resource/context, risk and reversibility. Every controlled action that resolves to `confirm` parks in the durable operator queue, times out to deny, and can execute only when the caller retries the exact approved action id.\n- One canonical gateway covers every public side-effect route: current-policy\n  recheck, one-use approval consume, atomic budget authorization, durable intent,\n  provider outcome and explicit `outcome_unknown` reconciliation state.\n- Policy-owned budgets cover operations, runtime, monetary amount, tool/model\n  cost, production changes and post-outcome failures at exact global, tenant,\n  principal or recipient scopes.\n- age-encrypted vault (no CGO); vault APIs never return secret values to agents.\n  Values are injected daemon-side and registered for best-effort output\n  redaction.\n- Per-agent quotas and owner isolation for jobs, sessions, session-scoped remote\n  file operations and forwards. Sessions and pending confirmations are capped\n  at 32 per owner and 128 total; live forwards at 16 per owner and 64 total.\n  Local host paths remain a shared OS/filesystem boundary. Set\n  `security.identity_mode: strict` in production: every configured agent must\n  have an existing assigned policy and authenticate with either a unique strong\n  static token or an explicitly enabled, offline-verified short-lived\n  `agent_identity` JWT. Tokenless, unknown and policyless callers fail closed.\n  A strict policy without structured rules also denies every command that lacks\n  an explicit legacy `allow` match; deny/confirm gates take precedence.\n  `development` retains self-asserted ids for trusted local clients and is the\n  compatibility default for older configs that omit the field.\n- Optional `security.run_as` drops local shell processes to a dedicated uid and\n  disables daemon-privileged local file tools and daemon-environment inheritance;\n  use commands inside that dropped session for local file access. Remote SFTP\n  remains available.\n- Every TCP `/api/*` request and `/metrics` requires either the dashboard token\n  or an enabled, pinned-JWKS-verified human JWT. Operator-only Unix-socket routes\n  similarly require either a verified human JWT or the separate `cli.token` used\n  by the local CLI.\n- Optional pinned-JWKS operator identity binds subject, tenant, roles,\n  delegation and verified MFA to approvals; policy can require role quorum,\n  distinct approvers and requester exclusion. Optional Ed25519 audit anchoring\n  exports signed fsynced chain heads through a durable HTTPS outbox.\n\n**Remote & fleet**\n- Persistent **remote SSH sessions** with reconnect — a dropped link is\n  re-dialled as a fresh shell so the session can serve new commands. The\n  authorized name, host, port, user, tags and keyed vault-reference binding stay\n  pinned, so inventory edits cannot retarget an approved or live session. Prior\n  cwd/env are lost; an in-flight job becomes `orphaned`, and its uncontrolled\n  remote process may still continue. Verify remote state before retrying it.\n- `fleet_run` across servers by name or tag with best-effort-redacted,\n  structured per-server results. Commands must be non-empty argv arrays and run\n  under a shared daemon-wide ceiling of five concurrent fleet targets; a call\n  may request less. One call matches at most 256 targets and returns at most\n  2 MiB of aggregate result text. SSH uses vault creds, ssh-agent, or on-disk keys, with\n  serialized, fsynced TOFU host-key pinning that fails closed on a malformed\n  `known_hosts` file.\n- Owner-scoped local-to-remote port forwards. Opening one is policy-gated and\n  rolled back unless its start audit record is durable; listeners are\n  loopback-only and bounded to 64 simultaneous connections per forward.\n\n**Operations**\n- Crash recovery (jobs persist; running jobs come back as `orphaned`), bounded local-FS snapshots/undo, desktop notifications and outbound-only Telegram notifications.\n- A typed adapter SDK provides durable\n  `prepare → execute → verify → compensate/reconcile` phases, provider\n  idempotency keys, secret-free receipts and restart recovery. Generic shell and\n  plugin effects remain opaque unless a concrete provider adapter defines and\n  proves its semantic invariants.\n- Out-of-process plugins exposed to agents as `<plugin>.<tool>`. Plugins are\n  trusted executables, not a security sandbox; calls are policy-gated and do not\n  start unless their start audit record is durable.\n- `termada update` — bounded self-update from GitHub releases on Unix (mandatory SHA-256 verification, optional Ed25519-signed checksums, exact-member extraction, atomic replace). Windows reports an explicit manual-install path because a running `.exe` cannot be replaced atomically.\n\n> **Not yet:** a native Windows ConPTY runtime (cross-compiles today, but PTY and\n> signals are stubs) and code-signing / notarization.\n\n## Install\n\n**One line, no Go needed** — downloads a prebuilt macOS or Linux `amd64`/`arm64`\nbinary (SHA-256 verified) to `~/.local/bin`:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/Islomzoda/termada/main/install.sh | sh\n```\n\nPin a version with `TERMADA_VERSION=vX.Y.Z`, or change the location with\n`TERMADA_BIN_DIR=~/bin`. If `~/.local/bin` isn't on your `PATH`, the installer\nprints the one line to add.\n\n<details><summary>Other ways — Docker, Homebrew, packages, source</summary>\n\n```bash\n# Docker (current published image: linux/amd64). Keep the published port on\n# host loopback; the image binds 0.0.0.0 only inside its network namespace:\ndocker run --rm --platform linux/amd64 -p 127.0.0.1:7717:7717 ghcr.io/islomzoda/termada\n\n# Persistent container state runs as uid/gid 10001. A fresh named volume is\n# initialized with the image's ownership:\ndocker run --rm --platform linux/amd64 -p 127.0.0.1:7717:7717 \\\n  --mount type=volume,src=termada-data,dst=/home/termada/.config/termada \\\n  ghcr.io/islomzoda/termada\n\n# Homebrew:\nbrew install Islomzoda/tap/termada\n\n# From source (needs Go 1.26.5+):\nTERMADA_FROM_SOURCE=1 ./install.sh\n# or:  go build -o ~/.local/bin/termada ./cmd/termada\n```\n\nThe Docker command starts the daemon directly; open the tokenized URL printed in\nits logs. The native CLI commands below apply when the binary is installed on the\nhost.\n\nReleases also ship `.deb`, `.rpm`, and manual Windows archives on the\n[releases page](https://github.com/Islomzoda/termada/releases). The Windows\nbinary cross-compiles, but native PTY execution still awaits a ConPTY backend.\n\n</details>\n\n## Quick start\n\n```bash\ntermada serve                    # start the daemon; prints a tokenized dashboard URL\ntermada dashboard --open         # print and open a fresh tokenized URL\n```\n\nThe dashboard bootstrap stores the token in browser session storage and removes\nit from the address bar. Static assets are public on loopback, but every TCP\n`/api/*` request and `/metrics` requires the token. The legacy\n`dashboard.local_trust` setting is deprecated and does not bypass API auth.\n\nConnect it to your agent — this is a **one-time, user-wide** step. You do it once\nper user account and every project gets Termada automatically; there's nothing\nto copy into each repo.\n\nFor Claude Code, one command does it:\n\n```bash\nclaude mcp add --scope user termada -- termada serve --stdio\n```\n\nUsing a different agent (or prefer a file)? Add this once to your **global** MCP\nconfig — see [`.mcp.json.example`](.mcp.json.example):\n\n```json\n{ \"mcpServers\": { \"termada\": { \"command\": \"termada\", \"args\": [\"serve\", \"--stdio\"] } } }\n```\n\nThat's it. From now on, just ask the agent to do terminal work — it flows through\nTermada while you watch and control it live. The one shared daemon serves every\nproject and every agent session, all on the same dashboard.\n\nConfiguration is strict: unknown/unsupported fields fail startup. Values written\nas `${NAME}` are expanded from the environment, and an unset referenced variable\nis an error rather than an empty credential. Leave optional credential fields out\nuntil their variables are available.\n\n### Reach remote servers through Termada\n\nFor the agent to operate a remote box **through Termada** (observable, reconnecting,\npolicy-gated) instead of shelling out to raw `ssh`, register the server once — then\nit's reachable **by name**, no IP and no raw ssh client.\n\nAdd it to `config.yaml` (see [`config.example.yaml`](config.example.yaml)) and\nrestart the daemon:\n\n```yaml\nservers:\n  - name: prod\n    host: prod.example.com        # hostname or IP of your server\n    user: deploy\n    # auth is OPTIONAL: a vault entry name for a Termada-stored credential.\n    # Omit it to try SSH_AUTH_SOCK plus unencrypted ~/.ssh/id_ed25519,\n    # id_ecdsa, or id_rsa. Termada does not interpret arbitrary ssh config.\n    # auth: prod-ssh-key\n    tags: [web]\n```\n\n…or add it live from the dashboard (**Servers → Add**). Confirm it's registered:\n\n```bash\ntermada servers          # lists registered servers by name\n```\n\nNow the agent reaches it by name:\n\n- **a remote shell session** — `session_create(target=\"prod\")`, then run `exec_run` / `exec_start` in that session (state persists while connected; after a link drop Termada reconnects a fresh shell, but an orphaned remote process may still be running);\n- **one command across servers** — `fleet_run(command=[...], servers=[\"prod\"])` (or by tag).\n- **a loopback TCP tunnel** — `port_forward(server=\"prod\", remote_host=\"127.0.0.1\", remote_port=5432)`, then close its returned id with `port_forward_close` when done.\n\n### Make the agent actually use Termada\n\nAgents like Claude Code and Cursor ship with a built-in shell and will reach for it\n(and for raw `ssh`) by default. Two things steer them to Termada:\n\n1. **Install the usage skill** — the plugin below, or [`skills/termada`](skills/termada/SKILL.md). It teaches the agent how to drive the tools (and to route remote work through registered servers instead of `ssh`).\n2. **Add a project rule** so the agent *prefers* Termada. Put this in `CLAUDE.md`\n   (Claude Code), `.cursor/rules` (Cursor), or your agent's system prompt:\n\n   > Use the Termada MCP tools for **all** shell and remote work — `exec_run` /\n   > `exec_start` for commands, `session_create(target=\"<server>\")` and `fleet_run`\n   > for remote servers. Do **not** use the built-in shell or a raw `ssh` client:\n   > everything must go through Termada so it is observable, reconnecting, and\n   > policy-gated. If a server isn't in `server_list()`, ask me to register it\n   > rather than falling back to `ssh`. For a concrete operational outcome,\n   > start with `mission_create`, use its session for every command, attach real\n   > successful job ids to plan steps, and finish with `mission_report`.\n\n<details><summary>Install as a Claude Code plugin</summary>\n\nThis repo is also a Claude Code plugin marketplace — it bundles the MCP server\nconfig and the usage skill (you still need the `termada` binary on `PATH`):\n\n```text\n/plugin marketplace add Islomzoda/termada\n/plugin install termada@termada\n```\n\n</details>\n\n<!-- mcp-name: io.github.Islomzoda/termada -->\n\n## MCP tools\n\nCommands are passed as an **argv array** (`[\"echo\", \"hi\"]`), never a shell string,\nso metacharacters are literal unless you explicitly invoke a shell such as\n`[\"bash\", \"-lc\", \"...\"]`. Explicit shell payloads still pass through policy;\nambiguous compound payloads fail closed when deny/confirm rules are present.\n\n| Group | Tools |\n| --- | --- |\n| Missions | `mission_create` · `mission_list` · `mission_get` · `mission_update` · `mission_resume` · `mission_report` |\n| Run | `exec_run` · `exec_start` · `exec_poll` · `exec_write` · `exec_signal` · `exec_kill` · `exec_list` |\n| Sessions | `session_create` · `session_list` · `session_close` |\n| Files & logs | `file_read` · `file_write` · `logs_tail` |\n| Recipes | `recipe_list` · `recipe_run` |\n| Remote | `server_list` · `fleet_run` · `port_forward` · `port_forward_list` · `port_forward_close` |\n| Plugins | `<plugin>.<tool>` names discovered at daemon startup |\n| Meta | `capabilities` |\n\n## CLI\n\n```text\ntermada serve [--stdio]              daemon, or the MCP shim\ntermada dashboard [--open]           print / optionally open the dashboard URL\ntermada top | status                 live TUI / overview\ntermada jobs [-f] | sessions         list jobs / sessions\ntermada logs <job> [-f]              stream a job's output\ntermada kill <job> | stop            kill one job / signal all admitted work\ntermada pending                      list human-in-the-loop approvals\ntermada approve|deny [--reason text] [--ticket id] <action_id>\ntermada audit [verify]               audit feed / verify active + rotated chain\ntermada servers | unlock             remote inventory / unlock the vault\ntermada vault init|set|list|rm|reset manage credentials\ntermada snapshot create|list|restore local-FS safety net (undo)\ntermada setup                        install user-scoped Claude MCP config\ntermada doctor                       health check\ntermada service install|uninstall|status  run the daemon at login\ntermada update                       Unix self-update; Windows prints manual path\n```\n\n## Documentation\n\n- [docs/SECURITY.md](docs/SECURITY.md) — threat model: what's protected and what isn't.\n- [docs/ACTION_CONTROL_PLANE.md](docs/ACTION_CONTROL_PLANE.md) — closed action catalog and production invariants.\n- [docs/PLUGINS.md](docs/PLUGINS.md) — writing out-of-process tool plugins.\n- [docs/PUBLISHING.md](docs/PUBLISHING.md) — release & MCP-registry process.\n- [docs/build-week/SUBMISSION.md](docs/build-week/SUBMISSION.md) — OpenAI Build Week submission package.\n- [docs/build-week/ARCHITECTURE.md](docs/build-week/ARCHITECTURE.md) — Mission Control architecture and trust boundaries.\n\n## Architecture\n\nA single daemon owns runtime state; agents connect through a stdio shim, and\nruntime inspection and controlled actions in the dashboard, TUI, and CLI use the\nsame daemon control plane. Host-owner maintenance commands such as vault-file\ncreation/reset, installation, service registration, self-update, audit-file\nverification, and configuration editing run outside that API and remain part of\nthe trusted OS/deployment boundary.\n\n```text\ncmd/termada            CLI: daemon, shim, inspection/control, vault\ninternal/engine        sessions, jobs, PTY, status machine, signals, files, recipes\ninternal/action        immutable Principal + Action + Resource + Context contract\ninternal/control       authorization, approval, budget, intent and outcome gateway\ninternal/ledger        durable one-use grants, budgets and export outbox\ninternal/budget        typed policy-owned budget resolution\ninternal/adapter       typed prepare/execute/verify/compensate/reconcile SDK\ninternal/identity      pinned-JWKS human and machine JWT verification\ninternal/anchor        signed external audit receipts and durable delivery\ninternal/output        cursor buffers, VT cleaner, redaction\ninternal/policy        argv allow/deny/confirm classification\ninternal/vault         age-encrypted credential store\ninternal/audit         hash-chained tamper-evident log\ninternal/bus           event bus (observability + durable audit)\ninternal/daemon        long-lived process: listeners, auth, lifecycle\ninternal/controlplane  HTTP/JSON control-plane server + client\ninternal/dashboard     embedded web UI\ninternal/tui           termada top\ninternal/fleet         server selection + concurrent aggregation\ninternal/sshx          SSH runner (vault / agent / key auth, TOFU host keys)\ninternal/mcp           MCP JSON-RPC stdio server + tools\ninternal/mission       durable missions, evidence validation, recovery, reports\n```\n\n## Development\n\n```bash\nmake vet test    # vet + tests\nmake race        # tests under the race detector\n./demo/mission-control/verify_demo.sh  # real MCP + approval + HTTP 503→200 flow\n```\n\nEngine tests exercise a real PTY and `bash`; fleet logic is unit-tested with a\nmock runner; the daemon stack and SSH are integration-tested end-to-end.\n\n## License\n\n[Apache-2.0](LICENSE).\n",
  "bytes": 22734,
  "sha": "fe1a4b6f3d63a16c681ec75b668297daee1f77c88eab09ca6b621530588cb5af",
  "repo_slug": "islomzoda/termada",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_islomzoda_termada_2ed03873/readme"
}