matapan
Local-first transactional control plane for agent-produced code: disposable container-isolated workspaces in, sealed evidence-bearing proposals out, compare-and-swap apply.
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`):
# 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:
# 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 collectOther 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.
| Variable | Meaning | Default |
|---|---|---|
| `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 image | alpine: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
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:localPath 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
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, acceptanceLicense
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
eBPF-powered network observability for Kubernetes. Indexes L4/L7 traffic with full K8s context, decrypts TLS without keys. Queryable by AI agents via MCP and humans via dashboard.
GOWA - WhatsApp REST API with support for UI, Multi Account, Webhooks, and MCP, and Chatwoot. Built with Golang for efficient memory use.
The missing open-source Kubernetes UI with a built-in MCP server for AI agents. See what's broken, why, and what changed. Issues, Topology, event timeline, Helm, GitOps, live service traffic, and cluster audits - all in one Go binary.
mcp-language-server gives MCP enabled clients access semantic tools like get definition, references, rename, and diagnostics.
The Terraform MCP Server provides seamless integration with Terraform ecosystem, enabling advanced automation and interaction capabilities for Infrastructure as Code (IaC) development.
Run MATLAB® using AI applications with the official MATLAB MCP Server from MathWorks®. This MCP server for MATLAB supports a wide range of coding agents like Claude Code® and Visual Studio® Code.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP