Container & Data Model
Every instance runs in an isolated worker container managed by the platform orchestrator. The container’s filesystem is the coordination medium — the host writes to it, the resolver reads and writes to it, and the monitor polls it.
Container topology
Section titled “Container topology”Host machine│├── Incus container: resolve-{id} ← main worker│ ││ ├── /project/│ │ ├── .resolve/ ← coordination directory (platform-managed)│ │ │ ├── config.json ← InstanceConfig written by host at startup│ │ │ ├── events.jsonl ← resolver writes; host mirrors via monitor│ │ │ ├── state.json ← resolver writes (atomic); host polls│ │ │ ├── status.json ← resolver-reported status checkpoints│ │ │ ├── input-requests/│ │ │ │ ├── {rid}.json ← A2UI schema, written by SDK via resolver│ │ │ │ └── {rid}.response.json ← response payload, written by host│ │ │ ├── messages/│ │ │ │ ├── 001.json ← consumer messages, written by host│ │ │ │ └── 002.json│ │ │ └── data/ ← resolver artifacts, fetched on demand│ │ │ ├── graph.dot│ │ │ └── progress.json│ │ └── workspace/│ │ └── {repo}/ ← repos cloned by host before run()│ ││ └── Resolver process (python -m my_resolver)│ └── amplifier-resolver-sdk (stdio JSON-RPC)│├── Incus container: resolve-{id}-gitea ← Gitea sidecar (optional)│ └── Local git server for workspace repos│└── Incus container: resolve-{id}-env-{uuid} ← ephemeral sub-container (optional) └── Sandboxed step executionWho owns what
Section titled “Who owns what”| Path | Written by | Read by | Notes |
|---|---|---|---|
.resolve/config.json |
Host (at startup) | Resolver | InstanceConfig: instance_id, params, credentials |
.resolve/events.jsonl |
Resolver (via SDK) | Host monitor | Append-only; flushed immediately |
.resolve/state.json |
Resolver (via SDK) | Host monitor | Overwritten atomically via os.replace() |
.resolve/status.json |
Resolver | Host monitor | Optional resolver-reported checkpoints |
.resolve/input-requests/{rid}.json |
SDK (resolver calls request_input) | Host monitor | A2UI schema + prompt |
.resolve/input-requests/{rid}.response.json |
Host | Resolver (SDK returns future) | Consumer’s response payload |
.resolve/messages/{N}.json |
Host | Resolver | Sequentially numbered consumer messages |
.resolve/data/{path} |
Resolver | Consumers via API | On-demand artifacts, any format |
/project/workspace/{repo} |
Host (before run()) | Resolver | Git repos cloned by orchestrator |
/usr/local/bin/create-pr |
Host (injected at startup) | Resolver | Provider-agnostic PR creation script |
Coordination flows
Section titled “Coordination flows”Input request flow
Section titled “Input request flow”Message flow
Section titled “Message flow”Data file flow
Section titled “Data file flow”Event streaming: files are the API
Section titled “Event streaming: files are the API”The events.jsonl file on disk IS the source of truth. The SSE endpoint is a
convenience layer over this file. You can always tail -f the file directly on the
host machine.
# Direct file access on hosttail -f ~/.amplifier/resolve/instances/{instance_id}/events/events.jsonl
# Or via APIcurl -N "$RESOLVE_URL/api/instances/{id}/events?token=$TOKEN"Container safety: three-layer defense
Section titled “Container safety: three-layer defense”After a production incident where 4,269 runaway pytest processes consumed 103 GiB
of RAM and triggered OOM kills, the platform implements a three-layer defense:
Layer 1 is the kernel-enforced backstop — it fires after the application layers fail. Layer 2 prevents most runaway scenarios before they escalate. Layer 3 catches slow-burn resource exhaustion between tool calls.
The three layers are deliberately redundant. No single layer is trusted.
InstanceConfig — what the resolver receives
Section titled “InstanceConfig — what the resolver receives”The host writes /project/.resolve/config.json before calling run(). This is the
source of truth for everything the resolver needs:
{ "instance_id": "a1b2c3d4e5f6", "resolver_name": "understudy", "params": { "spec": "Add GET /api/ping endpoint...", "repo": "myorg/myrepo" }, "workspace_path": "/project/workspace", "git_provider": { "type": "gitea", "base_url": "http://localhost:3000", "token": "..." }, "credentials": { "anthropic_api_key": "sk-...", "gh_token": "ghp_..." }, "sub_container_token": "...", "capabilities": ["gitea"]}The resolver reads this via the SDK’s config parameter to run(). Never read it
directly — the SDK provides typed accessors.
Gitea sidecar
Section titled “Gitea sidecar”When capabilities_required: ["gitea"] is set in manifest.json, the host spawns a
Gitea container (resolve-{id}-gitea) before calling run(). This provides a local
git server with:
- A working repository mirroring each cloned workspace repo
- A
create-prscript in the worker container that pushes to Gitea and creates PRs - Full Gitea REST API accessible from the worker at a known URL
Resolvers use Gitea to manage their working branch and create PRs without needing network access to GitHub during implementation. The platform handles the GitHub → Gitea mirror and Gitea → GitHub PR promotion.