Adapter isolation contracts¶
This is the operator‑facing reference for the runtime isolation
contract of each agent execution adapter. Pick adapters by risk
profile, not by name. For multi‑tenant or internet‑exposed
deployments, the sandboxed adapters (claude_sandbox, codex_sandbox)
and the hardened docker adapter are the recommended choices; the
unsandboxed local adapters are for trusted single‑tenant hosts only.
See adapters.md for the configuration knobs and local-adapter-deprecation.md for the deprecation path of the unsandboxed local adapters.
Quick reference¶
| Adapter | Runs as | Host filesystem | Host env vars | Network | Container hardening | Recommended for |
|---|---|---|---|---|---|---|
claude_local |
child process on the Trimus host | full (constrained by agent CWD) | inherited from host | host network | — | trusted single‑tenant dev |
codex_local |
child process on the Trimus host | full (constrained by agent CWD) | inherited from host | host network | — | trusted single‑tenant dev |
claude_sandbox |
claude CLI inside a hardened container |
only --tmpfs /tmp |
curated set only | trimus-egress-allowlist |
full sandbox hardening | preferred for production |
codex_sandbox |
codex CLI inside a hardened container |
only --tmpfs /tmp |
curated set only | trimus-egress-allowlist |
full sandbox hardening | preferred for production |
docker |
container (your image) | only the image + --tmpfs |
only what's forwarded | per Network config |
full hardening flags | production agents per‑company |
lambda |
HTTP call to a configured endpoint | — (off‑host) | — (off‑host) | outbound HTTPS to endpoint | upstream is operator's job | managed inference service |
remote |
A2A / worker on another host | — (peer‑owned) | — (peer‑owned) | outbound HTTPS to peer | peer's responsibility | cross‑host / cross‑instance |
claude_local — host‑process Claude CLI¶
What runs: a child claude CLI process via exec.CommandContext
on the Trimus host (internal/engine/adapters/claude_local.go).
Filesystem: cmd.Dir is the agent's home under TRIMUS_HOME, but
the process otherwise inherits the full host root filesystem — no
chroot, namespace, or bind‑mount restriction. Any file the Trimus
service account can read is reachable.
Environment: cmd.Env = BuildClaudeEnv(os.Environ(), …) — every var
on the Trimus service is inherited, including DATABASE_URL and
TRIMUS_ENCRYPTION_KEY unless the operator strips them in the unit.
Network: whatever the host has. No --network=none analog.
Hardening: none — there is no container.
Recommended: trusted single‑tenant development. The dev machine is the sandbox. Not for production multi‑tenant.
Risks: a prompt‑injection or CLI bug escalates directly to
host‑level access (read secrets, disclose TRIMUS_ENCRYPTION_KEY, reach
the network). Cross‑company isolation rests only on the application
layer (RLS); a process escape bypasses it.
Server‑side guardrails (even on the unsandboxed path):
TRIMUS_FORBID_DANGEROUS_CLAUDE_PERMISSIONStruthy ⇒ the--dangerously-skip-permissionsflag is silently dropped and the drop is logged (SEC‑015), even if a per‑agent config asks for it.TRIMUS_CLAUDE_BINARY_ALLOWLISTpins whichclaudebinary may run (basename or absolute‑path entries).
Migration: switch the agent to claude_sandbox — same behaviour,
hardened container around the same CLI.
codex_local — host‑process Codex CLI¶
Same shape as claude_local (internal/engine/adapters/codex_local.go):
CWD set to the agent home, rest of filesystem inherited, env inherited
via BuildCodexEnv(os.Environ(), …), host network, no container.
Recommended / risks: identical to claude_local — the runtime is
OpenAI's codex rather than Anthropic's claude, but the host‑process
escape surface is the same. Switch to codex_sandbox for production.
claude_sandbox / codex_sandbox — sandboxed local CLIs¶
What runs: the same claude / codex CLIs the *_local adapters
invoke, but inside a Docker container with full sandbox hardening
(internal/engine/adapters/sandbox_wrap.go, parallel to the plugin
sandbox in internal/plugins/sandbox.go).
Differences from the local adapters:
- Container root with
--read-only+ a writable/tmptmpfs. - No host env inheritance — only the curated provider/context vars
the CLI needs.
DATABASE_URLandTRIMUS_ENCRYPTION_KEYdo not enter the container. - The container joins the
trimus-egress-allowlistDocker network. With the egress DNS resolver enabled, it can reach only allow‑listed hostnames; other lookups return NXDOMAIN and write anegress_anomaly_eventsrow for operator review. --pids-limitviaTRIMUS_SANDBOX_PIDS_LIMIT(default 100), plus the shared hardening flags:--cap-drop ALL,--security-opt no-new-privileges,--memory-swappinned to--memory, and anyTRIMUS_DOCKER_SECURITY_OPTSprofiles.
Recommended: production and multi‑tenant deployments. These are the preferred default whenever you'd otherwise reach for a local CLI.
docker — generic Docker container¶
What runs: an operator‑specified image, started via docker run
with argv from internal/engine/adapters/docker.go.
Filesystem: the image's root, no host bind‑mounts by default;
--read-only + --tmpfs /tmp:rw,nosuid,size=64m (root read‑only, only
/tmp writable, 64 MiB cap). Opt out per agent with "writable": true.
Environment: only the explicit cfg.Env map plus Trimus‑injected
context (TRIMUS_AGENT_ID, TRIMUS_RUN_ID, TRIMUS_ISSUE_*). Host env
is not inherited.
Network: default none (the DockerConfig default). Point
Network at trimus-egress-allowlist for production SSRF safety.
Hardening:
--security-opt no-new-privileges(always)--cap-drop ALL(always)--pids-limit 100(default; override viapids_limitinadapter_configorTRIMUS_DOCKER_PIDS_LIMIT)--memory-swap=--memory(swap disabled so the memory limit is honest — SEC‑020 parity with the plugin sandbox)--memory+--cpus(operator‑supplied)--security-opt <opt>perTRIMUS_DOCKER_SECURITY_OPTSentry (seccomp/AppArmor hook, SEC‑029)
Recommended: production agents that ship their own runtime image.
Risks: the image is operator‑trusted — embedded secrets or a vulnerable runtime become the blast radius. Network policy is per‑container; you must opt into the egress network for SSRF protection.
lambda — generic HTTP endpoint¶
What runs: nothing on the Trimus host — the adapter is an HTTP
client (internal/engine/adapters/lambda.go). EndpointURL is the
target (despite the name, any HTTP service that speaks the payload
contract: AWS Lambda Function URLs, Cloud Run, self‑hosted inference).
Method, headers, auth header, and timeout are operator‑configured.
Filesystem / env / hardening: none on the Trimus host (no process).
Network: outbound HTTPS to the configured endpoint. Egress allowlisting does NOT apply — the call originates from the Trimus server, not a sandboxed container.
Recommended: delegate execution to a managed service you already run.
Risks: the upstream service is the entire trust boundary; ensure
EndpointURL is not attacker‑controllable.
remote — worker / A2A on another host¶
What runs: nothing on the Trimus host. The adapter queues a task
that a registered trimus-worker (or A2A peer) claims and runs with
its own locally‑configured adapter, posting the result back.
Filesystem / env / network / hardening: all owned by the worker / peer host.
Recommended: run execution on a different host — e.g. the server in
a container but local‑CLI agents on a host with ~/.claude / ~/.codex.
See remote-workers.md.
Risks: worker / peer credentials are the trust boundary. A compromised worker can exfiltrate whatever the dispatching company shares with it.
The egress allowlist + DNS enforcement¶
At boot, adapters.EnsureEgressNetwork creates the
trimus-egress-allowlist Docker network; sandboxed adapters land in it.
When TRIMUS_EGRESS_DNS_ADDR is set, Trimus starts a deny‑by‑default
DNS resolver (miekg/dns): containers resolve only allow‑listed
hostnames, and any unregistered lookup returns NXDOMAIN (so the host
isn't leaked) while writing an egress_anomaly_events row.
Manage the per‑company allowlist and review recent denials at
/companies/{id}/egress (admin). TRIMUS_EGRESS_DNS_DEFAULT overrides
the resolver address published into containers (default: the bridge
gateway).
Picking an adapter (decision tree)¶
- Single‑tenant dev box you trust?
claude_local/codex_local— cheapest, no Docker. - Multi‑tenant production running the local CLIs?
claude_sandbox/codex_sandboxon the egress‑allowlist network. - Production with your own runtime image?
dockerwith the hardening flags +Network=trimus-egress-allowlist. - Runtime lives in a managed service?
lambdaagainst your Function URL / Cloud Run service (egress allowlist does not apply). - Work delegated to another host / Trimus instance?
remotewith a tagged worker or A2A peer.
Cross‑references¶
- adapters.md — per‑adapter configuration.
- security.md — production hardening checklist.
- local-adapter-deprecation.md — the
TRIMUS_LOCAL_ADAPTERSgate roadmap. ARCHITECTURE.md— the application‑layer RLS isolation that complements the runtime isolation here.