matapan

Cấp quyền truy cập API có phạm vi cho Chatgpt hoặc Claude vào repo của bạn thông qua một container docker. Cách ly theo mặc định, các thay đổi không ảnh hưởng đến repo của bạn trừ khi bạn cho phép.

GitHubDùng thử MCP nàyĐược tài trợ

Tài liệu

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 <id>            # diff, digests, evidence, lineage
matapan proposal apply <id> --expected-base <commit>
# {"ProposalID": "019f…", "AppliedHead": "7f84…", "Strategy": "auto",
#  "Rollback": "git -C ~/src/my-app reset --hard <commit>"}

# Housekeeping
matapan workspace destroy <id>        # 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_<NAME> 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-<client_id> 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_ADDRHTTP bind address127.0.0.1:18777
MATAPAN_DB_PATHSQLite control db~/.matapan/matapan.db
MATAPAN_WORKSPACE_ROOTworkspace root dir~/.matapan/workspaces
MATAPAN_DOCKER_IMAGEdigest-pinned run imagealpine:3.23 pinned
MATAPAN_OBOL_KEY_PATHobol HMAC key (0600)~/.matapan/obol.key
MATAPAN_SECRET_KEY_PATHsecrets AES key (0600)~/.matapan/secret.key
MATAPAN_ALLOW_LANtrue/false non-loopback bindfalse
MATAPAN_TOOL_PROFILEminimal/fullminimal
MATAPAN_AUTH_MODElocal/charonlocal
MATAPAN_CHARON_URLCharon validate endpoint—
MATAPAN_GC_IDLE_HOURSidle workspace expiry (int)72
MATAPAN_LEDGER_RETENTION_DAYSaudit retention (int)90
MATAPAN_LEDGER_MAX_ENTRIESaudit cap (int)1000000
MATAPAN_RUNTIME_ISOLATIONdocker/gvisordocker
MATAPAN_OAUTH_CLIENT_IDOAuth 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: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-<workspace>-<seq> 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_<id>_<secret_hex>), 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, acceptance

License

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