Security kernel + sandboxed runner for AI agents
Run any agent safely.
Start Here · 5-Minute Quickstart · Use Cases · 1-Minute Demo · Architecture · Validation · Operations · Security
Guardplane is a security runtime for AI agents.
If you already use Codex, Claude Code, Ollama-based local models, or CI bots, Guardplane lets you keep your existing agent and add three things:
- deny-by-default policy
- approval for risky actions
- replayable audit logs
It sits between the agent and the operating system, adding workspace sandboxing, MCP tool routing, and audited execution without requiring you to adopt a new agent framework.
Think: Docker for AI coding agents, but focused on policy enforcement, approvals, and auditability rather than packaging alone.
Validated with real-agent runs for Codex, Claude, and Llama/Ollama, and designed to support other agents through the same Guardplane action contract.
If you want to try Guardplane immediately:
pipx install guardplane
git clone https://github.com/lhy0718/Guardplane.git
cd Guardplane/docs/tutorials/pipx-quickstart
cat README.mdThat lab gives you a reproducible pipx-installed quickstart with:
- one local daemon
- one policy file
- one guarded job
- one approval
- one replay
- Keep your existing agent or wrapper instead of migrating to a new orchestration stack
- Start with one local agent and one policy file, then add approvals, MCP control, and audit as needed
- Move from demos to production with the same action contract, replay model, and policy surface
- Platform teams that need guardrails around coding agents and internal automation
- Security teams that need approvals, replay, and auditability for agent actions
- Developers who want to wrap an existing agent CLI without rewriting it
- CI and tooling owners who want the same policy model for human and automated runs
Pick the path that matches your use case:
- Try the shortest end-to-end tutorial: use
docs/tutorials/pipx-quickstart/if you want to validate install, daemon, policy, approval, and replay with the published CLI. - Run one local agent safely from source: start with
examples/policy.yaml,examples/job.yaml, andexamples/mock_mcp_server.py, then follow the quickstart below. - Wrap Codex or Claude Code: use
examples/codex_bridge_agent.py,examples/claude_code_adapter.py, and the starter policies inexamples/policies/. - Wrap a local Llama model through Ollama: use
examples/llama_adapter.py,examples/llama_ollama_wrapper.py, andscripts/verify_llama_e2e.sh. - Wrap another agent: emit the Guardplane JSONL action contract from your own planner wrapper or use the Python/TypeScript SDKs described below.
- Run CI or automation with guardrails: use
examples/ci_adapter.py,examples/ci_manifest.yaml, andexamples/policies/ci-bot-safe.yaml. - Need advanced operations: skip ahead later in this README to MCP, policy tooling, audit evidence, remote workers, and tenancy.
- Local guarded job execution: run a deterministic job that writes a report, calls an MCP browser tool, and spawns a local process with policy checks around each step.
- Existing coding agent with guardrails: keep Codex, Claude Code, Ollama-hosted local models, or another planner as the planner, convert its action plan into Guardplane JSONL, and enforce filesystem, network, and tool policy on execution.
- CI with the same policy model: run automation under a narrower policy so safe report generation is allowed by default while risky package installs, network access, or repo writes need approval.
pipx install guardplaneIf you want the latest unreleased source instead:
pipx install "git+https://github.com/lhy0718/Guardplane.git@main"You can also install from a local checkout:
pipx install .pipx install guardplane installs the CLI and daemon only. The repository's examples/, scripts/, and validation assets are not bundled into the wheel, so the demo and validation commands below assume either a source checkout of this repository or your own policy/job/MCP assets.
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]Bootstrap token -> managed token. If you want the shortest path, use docs/tutorials/pipx-quickstart/. The manual flow below uses ./examples/policy.yaml, ./examples/job.yaml, and examples/mock_mcp_server.py, so run it from a repository checkout.
Fastest reproducible path:
pipx install guardplane
git clone https://github.com/lhy0718/Guardplane.git
cd Guardplane/docs/tutorials/pipx-quickstart
cat README.mdManual flow:
- Set auth token
export GUARDPLANE_AUTH_TOKEN="$(python3 -c 'import secrets; print(secrets.token_hex(24))')"- Start daemon
guardplane daemon start- Initialize state
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" init- Mint a managed admin token and switch over
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" auth create --role admin --label ops-admin
# save the returned `token` value, then:
export GUARDPLANE_AUTH_TOKEN="<managed-token>"- Create workspace and agent
mkdir -p workspace/reports workspace/data
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" agent create researcher --workspace ./workspace --policy ./examples/policy.yaml- Register mock MCP server
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" mcp add browser --cmd "python3.11 examples/mock_mcp_server.py"- Run deterministic job
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" run researcher --job ./examples/job.yamlguardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" run researcher --job ./examples/job.yaml
# status=WAITING_APPROVAL request_id=<id>
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" approve <request_id> --reason "reviewed"
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" ps
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" replay <run_id>bridge runs the wrapper command on the host and only guards the emitted JSONL actions. Use it for interoperability with existing agent CLIs.
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" run researcher --sandbox-cmd "python3.11 examples/sandbox_demo_agent.py" --sandbox-cmd-mode bridgecontained runs the wrapper command itself inside Docker with a read-only workspace mount and --network none.
Build the sandbox image once:
docker build -f Dockerfile.sandbox -t guardplane-sandbox:local .Then run a contained wrapper that emits one guarded write action:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" run researcher --sandbox-cmd 'python3 -c "import json; print(json.dumps({\"syscall\":\"fs.write\",\"args\":{\"path\":\"reports/contained-demo.txt\",\"content\":\"contained demo\"}}))"' --sandbox-cmd-mode containedUse contained when the wrapper command and its inputs are available inside the sandbox image or workspace.
- A runtime kernel for agent syscalls
- A sandboxed runner for agent wrappers and deterministic jobs
- A control plane for approvals, replay, audit, policy, MCP, and worker routing
- Not an LLM orchestration framework
- Not a replacement for your existing coding agent
- Not a hard kernel-isolation claim
- Not a generic MCP proxy without policy and audit semantics
| Surface | What it covers | Status |
|---|---|---|
| Policy engine | Capability allow/deny, approval-required rules, policy simulation, rollout governance | Available |
| Workspace sandbox | Path traversal block, absolute path block, symlink escape block | Available |
| Approval gate | Pause/resume runs, approval queue, operator UI, approval SLA metrics | Available |
| Audit and replay | JSONL event log, event integrity chain, replay, archive, evidence packs | Available |
| MCP control plane | MCP registry, tool routing, persistent sessions, tool metadata | Available |
| Wrapper execution | bridge, contained, local, Docker, and bwrap backends |
Available |
| SDKs and adapters | Python SDK, TypeScript SDK, Codex/Claude/CI examples | Available |
| Scale-out | Remote workers, worker pools, tenancy, quota, admission control | Available |
| Operator plane | Trace UI, executive dashboard, saved queries, scheduled reports, alerts | Available |
- Capability policy (
default: deny) - Workspace filesystem sandbox (traversal/symlink/absolute-path escape blocked)
- Approval gate for risky actions
- JSONL event audit log + retention/compression policy
- Replay (
guardplane replay <run_id>) - Agent Sandbox mode (
--sandbox-cmd) withbridgeandcontainedwrapper modes - Python/TypeScript adapter SDKs with versioned action contract
- Managed auth tokens with RBAC (
admin,approver,auditor,run_submitter) - Enterprise identity federation (OIDC JWT), directory sync, delegated admin, and break-glass tokens
- Daemon auth (
Bearer token) + UDS transport option + optional TLS/mTLS - Health/Readiness/Metrics endpoints
- Run cancel + idempotent approval resume
- Local/Docker sandbox backend switch
- Tamper-evident audit log (
sequence,prev_hash,event_hash) + integrity verify - External audit sinks (object-style mirror + SIEM HTTP sink)
- Persistent MCP sessions, tool metadata, and webhook notifications
- Multi-tenant org/business-unit/project/workspace control plane
- Remote workers and per-run executor selection
- Worker-pool scheduling by class/labels with queue-aware dispatch
- Run provenance and project quota/budget controls
- API admission control and rate limiting
- Trace UI (
/ui,/ui/approvals,/ui/executive,/ui/runs/<run_id>)
guardplane [--daemon-url URL] [--daemon-socket /tmp/guardplaned.sock] [--auth-token TOKEN] init
guardplane auth whoami
guardplane auth list [--active-only]
guardplane auth create --role <role> --label <label> [--principal-type service_account|human] [--owner-subject <subject>] [--expires-at <iso8601>]
guardplane auth rotate <token_id> [--label <label>] [--owner-subject <subject>] [--expires-at <iso8601>]
guardplane auth revoke <token_id>
guardplane auth break-glass --label <label> --reason "..." [--owner-subject <subject>] [--expires-at <iso8601>]
guardplane auth directory-sync --file ./directory.yaml
guardplane auth directory-users
guardplane auth directory-groups
guardplane agent create <agent_id> --workspace <path> --policy <file> [--org ORG] [--project PROJECT] [--workspace-id WS] [--worker NAME]
guardplane run <agent_id> --job <job.yaml> [--worker NAME] [--worker-class CLASS] [--worker-label key=value] [--adapter-name NAME] [--agent-version VER] [--image-version VER]
guardplane run <agent_id> --sandbox-cmd "<command string>" [--sandbox-cmd-mode bridge|contained] [--worker NAME] [--worker-class CLASS] [--worker-label key=value]
guardplane cancel <run_id>
guardplane ps
guardplane logs <run_id>
guardplane replay <run_id>
guardplane approvals list [--status PENDING] [--agent-id <id>] [--run-id <run_id>]
guardplane approvals show <request_id>
guardplane approve <request_id> [--by <actor>] [--reason "..."]
guardplane audit events [--run-id <run_id>] [--agent-id <id>] [--event-type EVENT] [--capability CAP] [--status STATUS]
guardplane audit verify <run_id>
guardplane audit export-run <run_id> [--output bundle.json] [--object-dir out/] [--siem-url https://siem.example/ingest]
guardplane audit archive-run <run_id> [--archive-dir ./audit-archives] [--tier hot|warm|cold]
guardplane audit verify-archive ./audit-archives/hot/2026-03-07/<run_id>
guardplane audit restore-archive ./audit-archives/hot/2026-03-07/<run_id> --output-dir ./restored-audit
guardplane audit apply-retention [--archive-dir ./audit-archives] [--hot-days 7] [--warm-days 30] [--cold-days 180]
guardplane audit evidence-pack [--case-id INC-1] [--run-id <id>] [--org-id <id>] [--project-id <id>] [--redact-external] [--create-hold] [--output evidence.json]
guardplane audit verify-evidence --input evidence.json
guardplane audit deliver-evidence --input evidence.json --connector splunk|opensearch|datadog|ticket --url https://...
guardplane audit hold create --case-id INC-1 --run-id <id> [--reason "..."] [--expires-at <iso8601>]
guardplane audit hold list [--case-id INC-1] [--status ACTIVE]
guardplane audit hold release <hold_id> [--reason "..."]
guardplane report dashboard [--scope-type global|org|business_unit|project] [--scope-id <id>] [--horizon-hours 24] [--top-n 5]
guardplane report query create <name> [--scope-type project] [--scope-id <id>] [--event-type POLICY_DECISION] [--capability net.fetch] [--text denied]
guardplane report query list [--scope-type project] [--scope-id <id>]
guardplane report query show <query_id>
guardplane report query run <query_id> [--limit 100]
guardplane report schedule create <name> [--scope-type project] [--scope-id <id>] [--saved-query-id <query_id>] [--interval-minutes 60] [--webhook <url>]
guardplane report schedule list [--scope-type project] [--scope-id <id>]
guardplane report schedule run <report_id>
guardplane report alert create <name> --rule-type pending_approval_overdue|worker_down|denied_capability_spike|failed_runs_spike [--scope-type project] [--scope-id <id>] [--threshold 1] [--webhook <url>]
guardplane report alert list [--scope-type project] [--scope-id <id>]
guardplane report alert evaluate <alert_id>
guardplane policy validate <policy.yaml>
guardplane policy test <policy.yaml> --cases <policy_cases.yaml>
guardplane policy dry-run --policy <policy.yaml> --capability fs.write --resource workspace/reports/out.txt
guardplane policy effective --agent <agent_id>
guardplane policy explain --agent <agent_id> --capability fs.write --resource workspace/reports/out.txt
guardplane policy diff <old-policy.yaml> <new-policy.yaml>
guardplane policy revision create --scope-type project --scope-id <project_id> --file <policy.yaml> [--summary "..."] [--based-on <revision_id>]
guardplane policy revision list [--scope-type project] [--scope-id <id>] [--limit 100]
guardplane policy revision show <revision_id>
guardplane policy rollout create --revision <revision_id> --mode enforce|dry_run [--target-org <id>] [--target-project <id>] [--target-agent <id>]
guardplane policy rollout list [--scope-type project] [--scope-id <id>] [--status ACTIVE]
guardplane policy rollout show <rollout_id>
guardplane policy rollout review <rollout_id> --decision approve|reject [--reason "..."]
guardplane policy rollout activate <rollout_id>
guardplane policy rollout rollback <rollout_id> [--reason "..."]
guardplane policy simulate-run --run <run_id> (--revision <revision_id> | --rollout <rollout_id>)
guardplane policy simulate-bundle --bundle <bundle.json> (--revision <revision_id> | --rollout <rollout_id>)
guardplane tenant org create <org_id> [--policy baseline.yaml] [--region kr-seoul] [--key-ref kms://org/root]
guardplane tenant business-unit create <business_unit_id> --org <org_id> [--region kr-seoul] [--key-ref kms://org/bu]
guardplane tenant project create <project_id> --org <org_id> [--business-unit <id>] [--policy overlay.yaml] [--region kr-seoul] [--failover-region jp-tokyo] [--key-ref kms://org/project] [--max-active-runs 10] [--max-runs-per-day 100] [--max-syscalls-per-run 50] [--max-write-bytes-per-run 1048576] [--max-net-fetches-per-run 5] [--max-proc-spawns-per-run 10] [--max-proc-spawn-seconds-per-run 120] [--approval-sla-seconds 900]
guardplane tenant workspace add <workspace_id> --project <project_id> --root <path>
guardplane tenant membership grant <subject> --subject-type user|group|service_account --scope-type global|org|business_unit|project --scope-id <id> --role <role>
guardplane tenant key-rotate --scope-type org|business_unit|project --scope-id <id> --key-ref kms://ring/new-key
guardplane worker add <name> --endpoint <url> --auth-token-env <ENV> [--backend docker] [--worker-class default] [--region kr-seoul] [--tenant-scope-type org|business_unit|project] [--tenant-scope-id <id>] [--max-concurrency 1] [--tls-ca-file ca.pem] [--tls-client-cert-file client.crt] [--tls-client-key-file client.key] [--tls-pin-sha256 <sha256>] [--max-retries 1] [--backoff-seconds 0.25] [--request-timeout-seconds 20]
guardplane worker list
guardplane worker pools
guardplane worker show <name>
guardplane worker probe <name>
guardplane worker drain <name> [--reason "..."] [--until <iso8601>]
guardplane worker resume <name>
guardplane worker pin-refresh <name>
guardplane mcp add <name> --cmd "<command>" [--session-mode persistent|oneshot] [--auth-env KEY] [--tool-metadata file.yaml]
guardplane mcp list
guardplane tools
guardplane storage inspect [--db state/state.db|postgresql://...]
guardplane storage schema-version [--db state/state.db|postgresql://...]
guardplane storage upgrade [--db state/state.db|postgresql://...] [--dry-run]
guardplane storage backup --output export.json [--db state/state.db|postgresql://...]
guardplane storage restore --input export.json [--db state/state.db|postgresql://...]
guardplane storage export --output export.json [--db state/state.db|postgresql://...]
guardplane storage import --input export.json [--db state/state.db|postgresql://...]
guardplane storage migrate --source state/state.db --target postgresql://guardplane:${DB_PASSWORD}@db/guardplane [--backup-output backup.json] [--dry-run]
guardplane doctor
guardplane daemon start [--host 127.0.0.1 --port 8787 | --socket /tmp/guardplaned.sock] [--tls-certfile cert.pem --tls-keyfile key.pem]
guardplane daemon leases [--lease-type run|approval|schema|maintenance] [--active-only]
guardplane daemon maintenance-run
guardplane daemon admission-stats [--horizon-seconds 3600] [--top-n 10]GET /healthz(no auth)GET /readyz(no auth)GET /metrics(auth required)GET /v1/coordination/leasesGET /v1/admission/statsPOST /v1/maintenance/runGET /v1/auth/whoamiGET /v1/auth/tokensPOST /v1/auth/tokensPOST /v1/auth/tokens/{token_id}/rotatePOST /v1/auth/tokens/{token_id}/revokePOST /v1/auth/break-glassPOST /v1/auth/directory/syncGET /v1/auth/directory/usersGET /v1/auth/directory/groupsPOST /v1/initPOST /v1/orgsGET /v1/orgsPOST /v1/projectsGET /v1/projectsPOST /v1/workspacesGET /v1/workspacesPOST /v1/membershipsGET /v1/membershipsPOST /v1/agentsPOST /v1/runsPOST /v1/runs/{run_id}/cancelGET /v1/runsGET /v1/runs/{run_id}GET /v1/runs/{run_id}/eventsGET /v1/runs/{run_id}/integrityGET /v1/runs/{run_id}/bundlePOST /v1/syscallGET /v1/approvalsGET /v1/approvals/{request_id}POST /v1/approvals/{request_id}/grantGET /v1/audit/eventsGET /v1/executive/dashboardGET /v1/executive/saved-queriesPOST /v1/executive/saved-queriesGET /v1/executive/saved-queries/{query_id}POST /v1/executive/saved-queries/{query_id}/executeGET /v1/executive/scheduled-reportsPOST /v1/executive/scheduled-reportsPOST /v1/executive/scheduled-reports/{report_id}/runGET /v1/executive/alert-policiesPOST /v1/executive/alert-policiesPOST /v1/executive/alert-policies/{alert_id}/evaluatePOST /v1/compliance/evidencePOST /v1/compliance/evidence/verifyGET /v1/compliance/holdsPOST /v1/compliance/holdsPOST /v1/compliance/holds/{hold_id}/releasePOST /v1/policy/evaluatePOST /v1/policy/explain/agents/{agent_id}GET /v1/policy/effective/agents/{agent_id}POST /v1/policy/revisionsGET /v1/policy/revisionsGET /v1/policy/revisions/{revision_id}POST /v1/policy/rolloutsGET /v1/policy/rolloutsGET /v1/policy/rollouts/{rollout_id}POST /v1/policy/rollouts/{rollout_id}/reviewPOST /v1/policy/rollouts/{rollout_id}/activatePOST /v1/policy/rollouts/{rollout_id}/rollbackPOST /v1/policy/simulatePOST /v1/mcp/serversGET /v1/mcp/serversGET /v1/mcp/toolsPOST /v1/workersGET /v1/workersGET /v1/workers/poolsPOST /v1/worker/executeGET /uiGET /ui/approvalsGET /ui/runs/{run_id}
SQLite remains the default. Batch 10 starts the migration path toward a multi-user operational store.
Use PostgreSQL by setting GUARDPLANE_DB_URL:
export DB_PASSWORD="<set-me>"
export GUARDPLANE_DB_URL=postgresql://guardplane:${DB_PASSWORD}@db.internal:5432/guardplane
pip install 'guardplane[postgres]'
guardplanedLocal migration tooling:
guardplane storage schema-version
guardplane storage upgrade --dry-run
guardplane storage inspect
guardplane storage backup --output state-backup.json
guardplane storage migrate \
--source ./state/state.db \
--target postgresql://guardplane:${DB_PASSWORD}@db.internal:5432/guardplane \
--backup-output ./state-backup.json \
--dry-run
guardplane storage migrate \
--source ./state/state.db \
--target postgresql://guardplane:${DB_PASSWORD}@db.internal:5432/guardplane \
--backup-output ./state-backup.json
guardplane storage inspect --db postgresql://guardplane:${DB_PASSWORD}@db.internal:5432/guardplaneLive PostgreSQL integration test is opt-in:
pip install 'guardplane[postgres]'
GUARDPLANE_RUN_POSTGRES_INTEGRATION=1 python3.11 -m pytest tests/test_storage_postgres_integration.pyRegister a persistent MCP server with metadata:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" mcp add browser \
--cmd "python3.11 examples/mock_mcp_server.py" \
--session-mode persistent \
--tool-metadata examples/mcp_browser_metadata.yamlInspect server health:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" mcp list
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" toolsIf the MCP server needs secrets, pass only variable names:
export BROWSER_API_TOKEN="..."
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" mcp add browser \
--cmd "python3.11 examples/mock_mcp_server.py" \
--auth-env BROWSER_API_TOKENReference: docs/MCP_OPERATIONS.md
Validate a policy before rollout:
guardplane policy validate examples/policy.yamlRun fixture-based policy tests:
guardplane policy test examples/policy.yaml --cases examples/policy_cases.yamlPreview one decision without starting a run:
guardplane policy dry-run \
--policy examples/policy.yaml \
--capability proc.spawn \
--resource python3.11 \
--extra-json '{"command":"python3.11"}'Review a policy change before deployment:
guardplane policy diff old-policy.yaml new-policy.yamlInspect the merged runtime policy that actually applies to one agent:
guardplane policy effective --agent researcherExplain one runtime decision with rollout context and matched rule:
guardplane policy explain \
--agent researcher \
--capability fs.write \
--resource workspace/reports/out.txtPropose and stage a rollout instead of replacing policy files in place:
guardplane policy revision create \
--scope-type project \
--scope-id proj-a \
--file examples/policy.yaml \
--summary "tighten report writes"
guardplane policy rollout create \
--revision <revision_id> \
--mode dry_run \
--target-agent researcher
guardplane policy rollout review <rollout_id> --decision approve
guardplane policy rollout activate <rollout_id>Simulate a candidate revision against a historical run before activation:
guardplane policy simulate-run --run <run_id> --revision <revision_id>
guardplane policy simulate-bundle --bundle bundle.json --rollout <rollout_id>Generate a signed compliance evidence pack and optionally place the covered runs on legal hold:
guardplane audit evidence-pack \
--case-id INC-1042 \
--project-id proj-a \
--time-from 2026-03-01T00:00:00Z \
--time-to 2026-03-07T23:59:59Z \
--redact-external \
--create-hold \
--hold-reason "pending regulator review" \
--output evidence.json
guardplane audit verify-evidence --input evidence.json
guardplane audit deliver-evidence --input evidence.json --connector splunk --url https://splunk.example/hecInspect your current principal:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" auth whoamiCreate a scoped approval token:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" auth create \
--role approver \
--label security-approverVerify a run's sealed event chain:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" audit verify <run_id>Mirror one run bundle to object-style storage and ship NDJSON to a SIEM endpoint:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" audit export-run <run_id> \
--object-dir ./audit-archive \
--siem-url https://siem.example/guardplaneCreate a signed archive bundle and verify it before long-term storage:
export GUARDPLANE_AUDIT_SIGNING_KEY="$(python3 -c 'import secrets; print(secrets.token_hex(32))')"
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" audit archive-run <run_id> \
--archive-dir ./audit-archives \
--tier hot
guardplane audit verify-archive ./audit-archives/hot/2026-03-07/<run_id>
guardplane audit restore-archive ./audit-archives/hot/2026-03-07/<run_id> \
--output-dir ./restored-auditGuardplane ships a versioned adapter contract, a Python SDK, and a package-ready TypeScript SDK.
- Contract version:
ag.action/v1 - Python SDK: guardplane/adapters
- TypeScript SDK package: sdk/typescript/package.json
- TypeScript runtime: sdk/typescript/dist/guardplane.js
- Integration guide: docs/ADAPTERS.md
Local package install:
# from the Guardplane repository root
npm install ./sdk/typescriptFirst-party examples:
- Codex adapter: examples/codex_adapter.py
- Claude Code adapter: examples/claude_code_adapter.py
- Llama/Ollama adapter: examples/llama_adapter.py
- CI adapter: examples/ci_adapter.py
Starter policy packs:
- examples/policies/codex-safe.yaml
- examples/policies/claude-code-safe.yaml
- examples/policies/ci-bot-safe.yaml
flowchart LR
A["Agent or Wrapper"] --> B["guardplane CLI"]
B --> C["guardplaned"]
C --> D["Auth Middleware"]
D --> D1["RBAC + Token Store"]
D1 --> E["Policy Engine"]
E --> F["Approval Gate"]
F --> G["Sandbox Executor"]
G --> G1["Local Backend"]
G --> G2["Docker Backend"]
G --> G3["Bwrap Backend"]
C --> H["SQLite state"]
C --> I["JSONL events"]
I --> I1["Hash Chain + Integrity Verify"]
I --> I2["Audit Sinks"]
C --> J["Metrics"]
Details: docs/ARCHITECTURE.md
Projects remain the primary run boundary, but topology can now be modeled as org -> business_unit -> project -> workspace.
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" tenant org create acme \
--policy examples/policy.yaml \
--region kr-seoul \
--key-ref kms://acme/root
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" tenant business-unit create research --org acme \
--region kr-seoul \
--key-ref kms://acme/research
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" tenant project create core --org acme --business-unit research \
--policy examples/policy.yaml \
--region kr-seoul \
--failover-region jp-tokyo \
--key-ref kms://acme/core \
--max-active-runs 10 \
--max-runs-per-day 200 \
--max-syscalls-per-run 50 \
--max-net-fetches-per-run 5 \
--max-proc-spawns-per-run 10 \
--max-proc-spawn-seconds-per-run 120 \
--approval-sla-seconds 900
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" tenant membership grant ci-submitter \
--scope-type project --scope-id core --role run_submitterRun list, approval queue, audit queries, and approval grant are filtered by project scope for non-admin callers.
Org baseline policy + project overlay + agent policy are merged in that order. Use guardplane policy effective --agent <agent_id> to inspect the final document and the project quota applied to that agent.
Region pinning and segmented worker fleets are covered in docs/TENANT_TOPOLOGY.md.
Register a remote worker:
export GUARDPLANE_WORKER_TOKEN="<worker-admin-token>"
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" worker add worker-a \
--endpoint https://worker-a.internal:8787 \
--auth-token-env GUARDPLANE_WORKER_TOKEN \
--backend docker \
--worker-class default \
--region kr-seoul \
--tenant-scope-type project \
--tenant-scope-id core \
--tls-ca-file certs/ca.pem \
--tls-client-cert-file certs/control-plane.crt \
--tls-client-key-file certs/control-plane.key \
--label region=labPin the worker certificate after enrollment:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" worker pin-refresh worker-aDrain a worker for maintenance:
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" worker drain worker-a --reason "certificate rotation"
guardplane --auth-token "$GUARDPLANE_AUTH_TOKEN" worker resume worker-aOpen the trace UI:
open http://127.0.0.1:8787/uiThe UI shell is public, but it still uses a bearer token for /v1/* API calls inside the page.
UI workflows now available:
- Pending approval queue with inline
Approve And Resume - Dedicated queue page at
/ui/approvals - Executive operator page at
/ui/executive - Cross-run search scoped by
global|org|business_unit|project - Saved queries, scheduled reports, and alert policies from the UI
- Run detail provenance cards
- Replay filters by
event_type,capability,status, and free-text payload search
- Deny-by-default capability checks
- Workspace boundary enforcement before file/proc cwd access
- Approval required rules block execution until explicitly granted
- Daemon API bearer token auth by default, with managed tokens and RBAC
- Optional TLS/mTLS and stricter UDS trust mode
net.fetchlimited tohttp|httpsURLs with explicit domain allowlists- Event-sourced audit trail for every syscall decision/result
- Tamper-evident event sealing with integrity verification
- Guardplane is still policy+container guardrail centered, not full kernel-hard isolation.
bridgemode is not process isolation; it only guards emitted actions.- For production, rotate bootstrap credentials into managed tokens, export sealed audit events off-host, and use Docker or
bwrapbackend where possible.
Prometheus format:
guardplane_runs_total{status=...}guardplane_syscall_latency_seconds_*guardplane_approval_wait_seconds_*guardplane_approval_pending_totalguardplane_approval_overdue_totalguardplane_approval_oldest_pending_secondsguardplane_mcp_latency_seconds_*guardplane_mcp_requests_totalguardplane_mcp_server_up
export GUARDPLANE_AUTH_TOKEN="$(python3 -c 'import secrets; print(secrets.token_hex(24))')"
export GUARDPLANE_DOCKER_EGRESS_MODE=proxy-required
export GUARDPLANE_HTTP_PROXY=http://host.docker.internal:3128
export GUARDPLANE_WEBHOOK_URLS="https://hooks.example/guardplane"
docker build -t guardplaned:local .
docker run --rm -p 8787:8787 \
-e GUARDPLANE_AUTH_TOKEN="$GUARDPLANE_AUTH_TOKEN" \
-e GUARDPLANE_SANDBOX_BACKEND=docker \
-e GUARDPLANE_DOCKER_IMAGE=guardplane-sandbox:local \
-e GUARDPLANE_DOCKER_EGRESS_MODE="$GUARDPLANE_DOCKER_EGRESS_MODE" \
-e GUARDPLANE_HTTP_PROXY="$GUARDPLANE_HTTP_PROXY" \
-e GUARDPLANE_WEBHOOK_URLS="$GUARDPLANE_WEBHOOK_URLS" \
-v "$PWD/state:/app/state" \
-v /var/run/docker.sock:/var/run/docker.sock \
guardplaned:localBuild sandbox image:
docker build -f Dockerfile.sandbox -t guardplane-sandbox:local .Contained wrapper guidance:
- Prefer
containedoverbridgefor real wrapper execution. - Put wrapper scripts and prompt/config inputs inside the sandbox image or under the workspace mount.
- Keep wrapper commands non-interactive and deterministic; JSONL action output should go to stdout only.
- Use
GUARDPLANE_DOCKER_MEMORY,GUARDPLANE_DOCKER_CPUS,GUARDPLANE_DOCKER_PIDS_LIMIT, andGUARDPLANE_SANDBOX_CMD_TIMEOUT_SECONDSto bound wrapper execution.
These validation scripts are repository assets, not installed package assets. Run them from a source checkout:
git clone https://github.com/lhy0718/Guardplane.git
cd Guardplanescripts/verify_codex_e2e.shStrict mode:
scripts/verify_codex_e2e.sh --require-real-agentClaude Code path:
scripts/verify_claude_e2e.sh \
--planner-cmd "python3.11 examples/claude_cli_wrapper.py --claude-bin /absolute/path/to/claude --prompt-file {prompt_file} --output-json {output_json}"Strict Claude Code mode:
scripts/verify_claude_e2e.sh \
--require-real-agent \
--planner-cmd "python3.11 examples/claude_cli_wrapper.py --claude-bin /absolute/path/to/claude --prompt-file {prompt_file} --output-json {output_json}"Llama / Ollama path:
scripts/verify_llama_e2e.sh \
--model llama3.2 \
--api-base http://127.0.0.1:11434Strict Llama / Ollama mode:
scripts/verify_llama_e2e.sh \
--require-real-agent \
--model llama3.2 \
--api-base http://127.0.0.1:11434No-mock mode:
export MY_REAL_AGENT_TOKEN="real-secret-for-validation"
scripts/verify_codex_e2e.sh \
--require-real-agent \
--no-mock \
--mcp-cmd "<real mcp server cmd>" \
--mcp-server-name browser \
--mcp-tool-name open \
--mcp-tool-args-file ./examples/mcp_open_args.json \
--secret-scope real_agent/token \
--secret-env-name MY_REAL_AGENT_TOKEN \
--require-real-secrets--no-mock disables the built-in mock MCP server. In that mode, Scenario E uses the exact server/tool/args contract you pass in, and Scenario F validates secrets.read with the --secret-scope / --secret-env-name pair you provide.
If --secret-env-name is omitted, the script derives one from --secret-scope by uppercasing it and replacing non-alphanumeric characters with _.
Release gate script:
scripts/verify_release_gate.shmake install-dev
make daemon
make init
make test
make validate-codex
make validate-codex-strict
make validate-claude
make validate-claude-strict
make validate-llama
make validate-llama-strict
make verify-release-gate
make release-check
make dist
make docker-build
make docker-build-sandbox
make smoke
make smoke-sandbox
make clean-state- Start here by role: docs/README.md
- Tutorials: docs/tutorials/README.md
- Changelog: CHANGELOG.md
Developer path:
- Tutorials: docs/tutorials/README.md
- Guardplane Adapter Guide: docs/ADAPTERS.md
- Real Agent Validation Guide: docs/REAL_AGENT_VALIDATION.md
- MCP Operations Guide: docs/MCP_OPERATIONS.md
Security path:
- Security Hardening Guide: docs/SECURITY_HARDENING.md
- Approval and Audit Guide: docs/APPROVALS_AND_AUDIT.md
- Policy Governance Guide: docs/POLICY_GOVERNANCE.md
- Threat Model: docs/THREAT_MODEL.md
- Compliance Evidence Guide: docs/COMPLIANCE_EVIDENCE.md
- Audit Archival Guide: docs/AUDIT_ARCHIVAL.md
Platform path:
- Operations Guide: docs/OPERATIONS.md
- Admission Control Guide: docs/ADMISSION_CONTROL.md
- Multi-Node Deployment Guide: docs/MULTI_NODE.md
- Worker Pools and Scheduling Guide: docs/WORKER_POOLS.md
- Tenant Topology and Residency Guide: docs/TENANT_TOPOLOGY.md
- Enterprise Identity Guide: docs/ENTERPRISE_IDENTITY.md
Leadership path:
- Executive Control Plane Guide: docs/EXECUTIVE_CONTROL_PLANE.md
- Contribution guide: CONTRIBUTING.md
- Security policy: SECURITY.md
- Code of conduct: CODE_OF_CONDUCT.md
- License: LICENSE