open-managed-agents
v0.1.2
Published
Self-hostable implementation of Anthropic's Managed Agents API surface.
Readme
Open Managed Agents
Claude Managed Agents, self-hosted.
Swap the base_url in your Anthropic SDK and your agents run here instead:
same API, same event stream, same sandboxed execution — but the sessions,
files, and sandboxes live on your machines, under your policies.
Where OMA stands today: wire-compatible on the synchronous single-agent core — agents, sessions, sandboxes, tools, skills, MCP, vaults, SSE — with sandbox security and egress controls that go beyond CMA's documented self-hosted baseline. The orchestration/persistence layer (multi-agent runtime, memory stores, scheduled deployments, webhooks, outcomes) is deliberately deferred. See PARITY.md for the full domain-by-domain scorecard and the active parity worklist, and ALPHA.md for the first-user alpha readiness plan.
Quickstart
Public onboarding preview: the one-command path is shipped, but its three-minute warm-path target has not yet completed the real-user timing study. Docker image downloads are explicitly outside that warm-path target.
Prerequisites: Node.js 22.19 or newer and a running Docker-compatible daemon. Then run:
npx --yes open-managed-agents@latestThe guided terminal checks local prerequisites, asks which model provider to
use, reads the API key through a masked prompt, starts an authenticated
loopback appliance, creates or reuses a starter agent/environment/session, and
opens that session in the console. The appliance stays attached to the command;
press Ctrl-C to stop it. State and provider credentials persist under ~/.oma.
If the pinned sandbox image is not cached, OMA names the image and asks before pulling it. Rerunning the same command while its onboarding-owned appliance is alive reopens the existing starter session rather than creating duplicates.
For the full source-checkout diagnostics and deterministic smoke tests, use the Getting Started guide:
git clone https://github.com/oneryalcin/open-managed-agents.git
cd open-managed-agents
npm ci
npm link
oma doctor
oma smoke --local-compatible
oma smoke --egress
export ANTHROPIC_API_KEY="..."
oma upoma smoke --local-compatible is the no-paid-API proof: it starts a temporary
OMA server, loopback OpenAI-compatible model fixture, and Docker-local sandbox,
then verifies model discovery, agent/session creation, a real bash tool call,
events, and cleanup.
oma smoke --egress extends that deterministic proof through the real
Docker-local egress boundary: npm, uv/PyPI, and GitHub must work under the
reviewed preset while an unrelated HTTPS destination remains denied.
In the advanced source-checkout flow, oma up starts the durable local appliance
in the foreground, stores data
under ~/.oma, and prints the console URL plus the first workspace API key
once. Docker deployments have the pinned approved-HTTPS sidecar capability,
but every environment remains offline unless its immutable allowlist selects a
reviewed preset or custom hosts. Use that workspace key in the bundled console
to create an agent, environment, session, and prompt. If the key was not saved,
mint another while the server is running:
oma keys mintWhen using the public package without a global install, the equivalent is:
npx --yes open-managed-agents@latest keys mintInteractive, air-gap-safe OpenAPI documentation is served at /docs/, with
the same schema available to tools at /openapi.json. The documentation lists
only routes OMA currently ships; workspace and admin credentials entered in the
UI stay in page memory and are not persisted.
Then point the ordinary Anthropic SDK at it — no OMA-specific client:
import anthropic
client = anthropic.Anthropic(
base_url="http://127.0.0.1:4180",
api_key="oma_...", # returned by `oma keys mint`
default_headers={"anthropic-beta": "managed-agents-2026-04-01"},
)
agent = client.beta.agents.create(name="helper", model="claude-sonnet-5")
env = client.beta.environments.create(
name="dev",
config={"networking": {"type": "limited", "allowed_hosts": []}}, # default-deny
)
session = client.beta.sessions.create(agent=agent.id, environment_id=env.id)
with client.beta.sessions.events.stream(session.id) as stream:
client.beta.sessions.events.send(session.id, events=[
{"type": "user.message", "content": [{"type": "text", "text": "hello"}]},
])
for event in stream:
print(event.type)A complete working example (file mounts, custom tools, tool confirmations, Streamlit UI) lives in examples/ship-your-first-managed-agent. Config overrides, model providers, and key provisioning: Development and deployment setup.
Why This Exists
Managed Agents give agents a durable place to work: sessions, event history, streaming updates, custom tools, and sandboxed filesystem/shell execution. The hosted version is convenient, but some teams need the same API shape with their own runtime, data boundary, sandbox policy, or deployment environment. OMA is that control plane.
How It Is Built
Three habits shape every slice of this codebase, and they are the reason to trust it over a feature checklist:
- Wire parity is measured, not assumed. Behavior is cloned by probing the
hosted API and recording the evidence — error envelopes, middleware
ordering, event sequences — before implementation
(
scratch/, docs/references/). When hosted says 405 before auth, so do we. - Everything fails closed. Unknown config values refuse to start; auth without durable storage refuses to start; sandbox providers must be explicitly enabled; builtin tools without a provider refuse to run. The default is always the safe posture, never the convenient one.
- Narrow surface, high rigor. Every slice ships with adversarial review, mutation-checked tests, and a plan document recording what was decided and why (docs/plans/). We would rather do fewer things whose failure modes are known than more things whose failure modes are a surprise.
Current Status
A working single-node appliance: durable, authenticated, multi-tenant on one node, with real sandboxed execution. Not yet full parity with the hosted Managed Agents beta surface.
What works today, at outcome level:
One command boots it — durable SQLite storage, fail-closed auth, and a first-boot API key (plan 0115).
The full agent loop runs: agents, environments, sessions, file mounts, streaming events with reconnect/replay, custom-tool round trips, permission gating, interrupts — on the Pi runtime with crash-safe recovery of pending work.
Multi-tenant on one node: hashed
x-api-keyworkspaces, per-workspace admission limits, request idempotency on the retry-sensitive endpoints (plan 0113).Real isolation for builtin tools: Docker-local and microsandbox-local providers behind a fail-closed selection boundary.
Credentialed sandbox egress + secrets at rest: default-deny network policy per environment, an envelope-encrypted secrets store, and boundary credential injection — sandboxed agents reach allowlisted hosts with secrets they can never read (ADR 0016).
MCP servers with vault-backed auth: sessions connect to MCP servers behind
OMA_ENABLE_MCP— SSRF-guarded,always_askby default. Credentials live in/v1/vaults(static_bearerandmcp_oauth); OAuth tokens refresh themselves (lazy on use, a proactive in-process ticker, and a 401-driven retry) and rotate warm connections without reconnecting. Access tokens, refresh tokens, and client secrets are injected control-plane-side and leak-swept out of tool results and events — the same "usable but never readable" boundary the sandbox egress applies, now on the auth leg (plan 0122).An admin API and a bundled operator console, served by the appliance at
/console: browse agents, sessions, events, spans, files, and vaults with a workspace key, and validate anmcp_oauthcredential in place; create workspaces, mint/revoke API keys, and inspect per-credential refresh health with the admin key (plan 0119, plan 0120, plan 0125). Fully self-contained — no CDN at first paint; browser keys live in page memory only.Custom skills execution: upload/version private skill bundles, attach them to agents, snapshot concrete content at session creation, advertise the skill through Pi, and read or execute its root-owned files inside the Docker sandbox under
/workspace/skills. Session snapshots remain reproducible after source deletion; the live exit smoke covers model discovery,read,bash, leak checks, tamper resistance, and cleanup (plan 0126).Observability.
GET /health(liveness + readiness, compose healthcheck), fail-closed Prometheus/metrics, and structured JSON logs with programmatically enforced secret redaction (plan 0121).
What's still missing — the appliance product roadmap is the authoritative sequencing:
- session usage metering (
usageisnull); - broader event-topology parity, file-upload idempotency, remote sandbox providers, and RBAC within a workspace.
Architecture
OMA keeps the harness separate from compute.
The harness is the trusted control plane: API requests, session state, event history, model/runtime orchestration, custom-tool correlation, approvals, and recovery state.
Compute is the sandbox execution plane: shell commands, filesystem changes, packages, and generated artifacts.
That split lets applications keep secrets, auth, billing, audit logs, and human review outside the untrusted coding sandbox.
Compatibility
The north star is Claude Managed Agents wire compatibility: same endpoint family, Anthropic-shaped error envelopes, persisted session event stream, SSE replay and reconnect behavior, public custom-tool use/result events. Details and intentional deviations: ADR 0004.
Stack
| Layer | Current choice | | --- | --- | | Control plane | TypeScript + Hono | | Runtime engine | Pi Agent SDK | | Persistence | SQLite (single-node appliance); Postgres is the scale-out target behind existing store interfaces | | Sandbox providers | Docker-local and microsandbox-local, fail-closed selection |
The default sandbox guest is an OMA-owned, multi-architecture image pinned by immutable digest. The alpha coding image includes Node/npm, Python/uv, Git, curl, jq, Bash, ripgrep, archive tools, and a basic native-build toolchain. It is about 256 MiB compressed per platform and remains non-root with a read-only root filesystem. Installed tools do not imply network access: environments are still default-deny and package-registry access must be explicitly allowlisted.
Development
npm ci
npm run typecheck
npm testCommon tasks are also available through thin Make targets (make check,
make ui, make server, make parallel-docker-smoke); see
Development and deployment setup.
Deeper docs:
- Docs index — every plan, ADR, and reference note
- Appliance product roadmap
- First Docker-local run
- Examples
- Architecture · Scope · ADRs
License
Elastic License 2.0: free to use, copy, modify, and distribute — personally or inside your company — with one main limitation: you may not offer OMA itself to third parties as a hosted or managed service.
