trackmcp
Back to directory

Local-first transactional control plane for agent-produced code: disposable container-isolated workspaces in, sealed evidence-bearing proposals out, compare-and-swap apply.

0 stars GoOthers Updated Jul 23, 2026

Documentation

Matapan

Matapan is a **local-first transactional control plane for agent-produced

code**. Coding agents (ChatGPT, Claude, Codex) get disposable,

container-isolated workspaces and return work only as immutable,

evidence-bearing proposals, applied via compare-and-swap. **Your active

checkout is never in the agent's write path.**

The loop:

> import trusted source → disposable isolated workspace → scoped

> tools/runtime → capture edits + verification → seal immutable proposal

> against an expected base → review → compare-and-swap apply → revoke and

> destroy → redacted audit trail remains.

Matapan is a workspace transaction manager — not an IDE, not an agent, not a

generic sandbox, not a Git GUI.

Status

0.1.0-beta.1 — all eight planned sprints are landed: security core,

workspace lifecycle (leases + GC), hardened runtime (gVisor experimental),

MCP tool surface, MVP proposal engine, policy profiles, secrets broker,

egress proxy, audit retention, Charon adapter boundary, packaging, and

adversarial hardening (fuzz + edge matrix). See `CHANGELOG.md`,

`docs/MVP-acceptance.md`, and `docs/docker-limitations.md`.

Quickstart

From zero, on macOS or Linux (requires git, Go 1.25.12+ to build from source,

and a local Docker daemon for `workspace_run`):

sh
# Install (builds and installs to /usr/local/bin, or --user for ~/.local/bin)
scripts/install.sh

# Verify the environment
matapan doctor
# git                    ok   git version 2.50.1
# config                 ok   ~/.matapan/config.json
# database               ok   ~/.matapan/matapan.db (schema v7)
# obol key               ok   ~/.matapan/obol.key (perms 600)
# docker                 ok   daemon reachable
# runtime image          ok   present, digest matches
# runtime spawn          ok   hardened container ran, exit 0

# Pre-pull the digest-pinned runtime image
matapan runtime pull

# Create a workspace from a git repo (worktree at an exact commit)
matapan workspace create --repo ~/src/my-app --base main
# {"ID": "019f…", "State": "ready", "Branch": "matapan/019f…", …}

# Start the daemon, then connect an agent (see docs/quickstart-claude.md)
matapand &

The agent then drives `workspace_file_edit` / `workspace_run` /

`workspace_commit` against that workspace ID. When the work is done:

sh
# Seal the workspace into an immutable proposal (via the agent or MCP),
# then review and apply with compare-and-swap:
matapan proposal list
matapan proposal show             # diff, digests, evidence, lineage
matapan proposal apply  --expected-base 
# {"ProposalID": "019f…", "AppliedHead": "7f84…", "Strategy": "auto",
#  "Rollback": "git -C ~/src/my-app reset --hard "}

# Housekeeping
matapan workspace destroy         # verified teardown
matapan gc --dry-run                  # what idle/expired GC would collect

Other source types: `--source snapshot --path /dir` (defended copy of a

non-Git directory), `--source fresh [--git-init]` (empty scaffold). Useful

flags: `--profile restricted` (policy profile), `--lease 24h` (GC

expiry), `--egress proxy.example.com` (human egress grant).

Connecting agents

  • Claude Code / local agents (stdio): `matapand --stdio` with

`MATAPAN_OBOL` set — see docs/quickstart-claude.md.

  • ChatGPT (HTTPS tunnel): authenticated StreamableHTTP at `/mcp` via a

user-managed tunnel — see docs/quickstart-chatgpt.md.

Tool surface

  • Profiles (`mcp.tool_profile` in config.json, default `minimal`):

minimal is the core 12 tools; `full` adds typed `workspace_file_glob` and

`workspace_file_grep` for hosts that prefer typed search over shell

`rg`/`find` (DevSpace parity).

  • Capability discovery: `matapan_capabilities` returns the server

version, profile, tools + annotations, hard clamps, and feature flags so

any agent can self-configure.

  • Typed errors: tool failures return a structured

`{"error": {"code", "message"}}` field with stable codes (`unauthorized`,

`not_found`, `path_escape`, `workspace_locked`, `stale_base`,

`spec_refused`, `state_conflict`, `invalid_argument`, `egress_denied`,

`unsupported`, `unavailable`, `internal`).

  • Instructions: root `AGENTS.md`/`CLAUDE.md` are discovered and returned

on `workspace_status`, and their digests are recorded in every proposal

seal. Instruction content is data for the agent, never control input

it cannot change policy, scopes, or limits.

  • Egress grants: network stays `none` unless the workspace has a grant

from a human (`matapan workspace create --egress DOMAIN` or the

`workspace_grant_egress` tool, scope `workspace.grant` — agent principals

don't get it). Granted runs go through the matapan egress proxy

(allowlisting CONNECT/HTTP proxy): HTTP(S) to granted domains works,

everything else is denied and ledgered. Enforcement honesty: on

native Linux Docker the container attaches to an internal network with no

direct route out (full enforcement); on Docker Desktop the container runs

on the default bridge with the proxy as its only configured path —

HTTP(S) is filtered, but raw-IP egress is a documented gap until the

sidecar proxy lands.

Policy profiles, secrets, and identity

  • Policy profiles (`default`, `restricted`, `open`; `matapan policy

list/show`): image allowlists, egress policy, argv[0] command denylists,

resource ceilings. Assigned per workspace at create (`--profile`); the

profile digest is sealed into every proposal as `policy_digest`.

  • Secrets: `matapan secret set` stores values AES-256-GCM-encrypted

(key at 0600, never plaintext at rest; value read from stdin or `--env`,

never argv). Humans grant secrets to workspaces

(`workspace_grant_secret` / `matapan secret grant`); runs inject only

granted secrets as `MATAPAN_SECRET_` env vars; grants are revoked

automatically at proposal seal and workspace destroy. Values are

registered with the ledger redactor at injection time.

  • Charon mode: `auth.mode: charon` + `auth.charon_url` switches token

validation to the Charon validate endpoint (5s, fail-closed, audience

`matapan` enforced either way). `review.prevent_self_approval` (default

true in charon mode) blocks a proposal's creator from applying or

rejecting it — independent review.

  • OAuth mode: `auth.mode: oauth` makes the instance a full OAuth 2.0

authorization server for connectors that require OAuth (ChatGPT,

Claude). HS256 JWT access tokens (24h, same HMAC key file as obols),

public PKCE client `chatgpt-mcp`, metadata discovery under

`/.well-known/`, and an owner approval gate: the authorize endpoint

renders a form demanding the owner password (`MATAPAN_OAUTH_OWNER_PASSWORD`

at daemon start — hashed in memory, never stored; startup refuses oauth

mode without it). No open enrollment: only the configured client and

allowlisted redirect URIs are accepted. Tokens map to a

connector-specific `agent-` principal (AgentScopes: no

`workspace.grant`, no `proposal.apply`) — the connector cannot grant

egress or secrets and cannot apply proposals; apply stays human. The

approval page renders the exact effective scopes. Obols keep working

alongside JWTs. `matapan config oauth-setup` prints the exact

connector instructions.

  • Audit retention: `ledger.retention_days` (90) and

`ledger.max_entries` (1e6); the startup/daily sweeper compacts with an

anchor entry so `Verify` still validates the retained tail.

Runtime configuration

The `runtime` section of `config.json` sets per-run defaults

(`timeout_sec`, `memory_mb`, `pids_limit`, `nano_cpus`,

`max_output_bytes`). Per-call values may lower these but never raise them

past the hard clamps, which are constants in `internal/runtime` (not

config): timeout ≤ 10 min, memory ≤ 4 GiB, captured/streamed output ≤ 4

MiB. Images are digest-pinned (`docker_image`) and verified after every

pull; provenance lives in the `runtime_images` table

(`matapan runtime images`).

Configuration precedence and env overrides

Precedence, always: env > file > defaults. Every `MATAPAN_*` variable

is applied after the config file loads, before validation; invalid values

fail closed with an error naming the variable.

VariableMeaningDefault
`MATAPAN_LISTEN_ADDR`HTTP bind address`127.0.0.1:18777`
`MATAPAN_DB_PATH`SQLite control db`~/.matapan/matapan.db`
`MATAPAN_WORKSPACE_ROOT`workspace root dir`~/.matapan/workspaces`
`MATAPAN_DOCKER_IMAGE`digest-pinned run imagealpine:3.23 pinned
`MATAPAN_OBOL_KEY_PATH`obol HMAC key (0600)`~/.matapan/obol.key`
`MATAPAN_SECRET_KEY_PATH`secrets AES key (0600)`~/.matapan/secret.key`
`MATAPAN_ALLOW_LAN``true`/`false` non-loopback bind`false`
`MATAPAN_TOOL_PROFILE``minimal`/`full``minimal`
`MATAPAN_AUTH_MODE``local`/`charon``local`
`MATAPAN_CHARON_URL`Charon validate endpoint
`MATAPAN_GC_IDLE_HOURS`idle workspace expiry (int)`72`
`MATAPAN_LEDGER_RETENTION_DAYS`audit retention (int)`90`
`MATAPAN_LEDGER_MAX_ENTRIES`audit cap (int)`1000000`
`MATAPAN_RUNTIME_ISOLATION``docker`/`gvisor``docker`
`MATAPAN_OAUTH_CLIENT_ID`OAuth public client_id (oauth mode)`chatgpt-mcp`

Container

sh
scripts/docker-build.sh matapan:local   # builds + version-stamps the image

docker run -d --name matapand \
  -p 127.0.0.1:18777:18777 \
  -v /etc/matapan/config.json:/etc/matapan/config.json:ro \
  -v ~/.matapan:/data \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$HOME/src:$HOME/src" \
  matapan:local

Path parity is required: the workspace root and any source repos must

be mounted at the *same absolute path* inside and outside the container —

matapand bind-mounts workspace dirs into run containers and runs git

worktree ops against host paths. See `docs/operations.md` for the full

container deployment guide (including the per-model compose layout) and

the docker.sock trust note. The image runs as root (documented in the

Dockerfile): the Docker socket's group varies by host; agent workloads

still run under the full hardened profile.

Security summary

  • No shell anywhere. All subprocesses are `os/exec` argv arrays; there is

no `sh -c` path in the codebase.

  • Workspace path defense. Every file tool call re-canonicalizes with

`filepath.EvalSymlinks` and rejects `..` escapes and symlink escapes from

the workspace root, with a TOCTOU re-check on open.

  • Hardened container runtime. Non-root user, `CapDrop: ALL`,

no-new-privileges, default seccomp, memory/CPU/PID limits, read-only

rootfs, `NetworkMode: none` by default (explicit egress grant required),

digest-pinned images with post-pull digest verification, explicit env

allowlist (no ambient host env), and a hard refusal of privileged mode,

host PID/IPC, and any `/var/run/docker.sock` mount. Containers are named

`matapan--` and labeled so destroy and reconciliation can

find them; cleanup is verified, not trusted. Command evidence includes

exit code, OOM-kill flag, verified image digest, termination reason, and

bounded (truncation-marked) output.

  • Immutable proposals + CAS apply. A proposal seals the diff, base/head

commits, and a content digest. Apply verifies the target branch head equals

both the proposal base and your `expected_base`, merges in a temporary

worktree first, and is idempotent on replay. Stale base returns a typed

error carrying the current head.

  • Audit ledger. Append-only, hash-chained, redacted before persistence —

secret values are never stored (`ledger.Redact`).

  • Obol auth. HMAC-SHA256 bearer tokens (`obol__`),

revocable, audience hardcoded to `matapan`.

  • Snapshot import defense. Non-Git sources are copied, never referenced:

source root canonicalized, escaping symlinks skipped and recorded,

FIFOs/devices rejected, byte/file caps, TOCTOU-defended source opens.

  • Lifecycle safety. Per-workspace locking (in-process mutex + flock,

crash-safe), destroy allowed from any state with post-delete verification,

startup reconciliation for stuck/orphaned workspaces, and Matapan-labeled

containers killed on destroy.

Honest isolation language: this is *hardened container isolation*, not "safe

execution". gVisor/Kata/microVM profiles are the higher-assurance path

(gVisor is experimental as of Sprint 8). Full honest detail:

`docs/docker-limitations.md`.

Layout

code
cmd/matapand        daemon (MCP over stdio or authenticated HTTP)
cmd/matapan         CLI (workspace/proposal/policy/secret/gc/runtime/doctor/config)
internal/config     daemon config + obol signing key load/generate
internal/obol       HMAC-SHA256 token service (audience "matapan")
internal/auth       identity adapter (local obols / Charon validate endpoint)
internal/policy     principals, scopes, workspace grants, named policy profiles
internal/ledger     hash-chained append-only audit + retention sweeps
internal/idempotency key-based dedup
internal/store      SQLite schema, migrations, typed store
internal/workspace  lifecycle, worktrees, snapshots, locking, leases + GC,
                    canonical path defense
internal/reconcile  startup crash recovery + orphan reconciliation
internal/runtime    hardened Docker exec, verified images, egress proxy wiring
internal/egressproxy allowlisting CONNECT/HTTP egress proxy
internal/secrets    AES-256-GCM secret registry + grant lifecycle
internal/proposal   seal, CAS apply strategies, conflict handling, revise
internal/testparse  JUnit/TAP evidence parsing (matapan-observed)
internal/mcpserver  workspace-scoped MCP tools (mcp-go v0.56.0)
internal/httpserver daemon HTTP (/api/health, /mcp)
scripts/            install.sh + release.sh packaging
docs/               threat model, ADRs, quickstarts, operations, acceptance

License

MIT — Copyright (c) 2026 OpenLethe. See `LICENSE`.

Frequently asked questions

What is matapan?

matapan is Local-first transactional control plane for agent-produced code: disposable container-isolated workspaces in, sealed evidence-bearing proposals out, compare-and-swap apply.

How do I install matapan?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is matapan open source?

Yes — it is hosted on GitHub at https://github.com/openlethe/matapan.

Related MCP tools

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP