Instance
The unit of work. You create one, watch its events, and read its final state.
Resolve is built on six interlocking primitives. Learn these and every other page in the docs clicks into place.
An instance is the unit of work in Resolve. It represents a single run of a resolver against a specific input. Every instance has:
instance_idresolver — which resolver handles itinput — the resolver-specific parametersstatus — where it is in its lifecycleYou create instances with POST /instances and watch them with
GET /instances/{id}/events. An instance is the thing you create, monitor,
pause, resume, and cancel.
Status lifecycle:
A resolver is a pluggable strategy — the thing that actually does the work
inside an instance. It runs as a separate process (not in-process code)
inside an isolated worker container, communicating with the platform over
JSON-RPC on stdio via the amplifier-resolver-sdk.
Every resolver must provide two things:
| Requirement | Purpose |
|---|---|
manifest.json |
Tells the platform how to launch, register, and configure the resolver |
run() implementation |
The code that executes the task and emits events |
Resolvers are registered via amplifier-resolve resolver add, not discovered
automatically. The platform catalog at ~/.amplifier/resolve/resolvers.json is the
single source of truth. Discover available resolvers at GET /resolvers.
The amplifier-resolver-sdk is the base class library for writing resolvers. It
handles the stdio JSON-RPC transport, event emission, state management, and input
requests — you write run(), the SDK does the rest.
from amplifier_resolver_sdk import Resolver, ResolverResult
class MyResolver(Resolver): async def run(self, instance) -> ResolverResult: await self.emit("resolver:phase", {"name": "working"}) # ... do work ... await self.emit("resolver:artifact", {"kind": "summary", "value": "done"}) return ResolverResult(status="completed", summary="done")
if __name__ == "__main__": MyResolver().serve()Every instance produces a live event stream — an append-only JSONL log of everything that happens. Events are the primary observability surface.
data: {"schema_version":1,"event_type":"resolve.worker.ready","instance_id":"abc123",...}
data: {"schema_version":1,"event_type":"resolver:phase","data":{"name":"planning"},...}
data: {"schema_version":1,"event_type":"resolver:artifact","data":{"kind":"pr","value":"https://..."},...}
data: {"schema_version":1,"event_type":"resolver:completed","data":{"outcome":"success"},...}
data: {"type":"done"}Stream events with curl -N $RESOLVE_URL/api/instances/{id}/events or the SSE
endpoint. Events close with {"type": "done"} when the instance reaches a terminal
status.
Three tiers of events — by contract stability:
| Tier | Prefix | Emitter | Stability |
|---|---|---|---|
| 1 | resolve.* |
Platform host | Stable — guaranteed across releases |
| 2 | resolver.* |
SDK infrastructure | Cross-resolver vocabulary (see Event Vocabulary) |
| 3 | {resolver_name}.* |
Resolver-specific | Per-resolver; may change |
Alongside events.jsonl, each instance maintains a state.json — a point-in-time
snapshot of current status and phase, overwritten atomically on each update. Use
GET /instances/{id}/state for “where is it right now?” without parsing the full
event stream.
A viewport is the custom UI that renders alongside an instance in the React frontend. Each resolver can optionally ship a viewport — an ESM JavaScript bundle that the frontend loads dynamically and mounts into a panel.
Viewports receive a ViewportProps object with:
instanceId — the instance they renderfetchData(path) — fetches files from the resolver’s data directoryonEvent(handler) — subscribes to the instance’s SSE event streamA resolver without a viewport gets the generic platform UI (event log, state, input forms). A resolver with a viewport gets full control over its visual representation.
manifest.json:{ "viewport_bundle": "git+https://github.com/myorg/my-viewport@main", "viewport_path": "dist/viewport.js"}A pipeline is a directed graph of agent work, written in DOT format, that
orchestrates multi-step resolver workflows. The dot-graph resolver reads pipeline
files and executes each node as an Amplifier session, passing outputs between nodes.
digraph my_pipeline { rankdir=LR;
Plan [label="Plan\nthe work" session="@bundle:plan-prompt"]; Implement [label="Implement" session="@bundle:implement-prompt"]; Verify [label="Verify\nresult" session="@bundle:verify-prompt"];
Plan -> Implement -> Verify;}Pipelines are the primary way to express multi-phase autonomous workflows in Resolve. They live in the resolver’s working directory and are selected via the instance input.
A reality check is how Resolve proves that generated software actually works. Given a repository and plain-language acceptance criteria, the platform:
pass, fail, or a failure_mode (infrastructure error)Reality checks are invoked from within a resolver’s run() via the SDK:
handle = await self.start_reality_check( software_path="https://github.com/example/app", acceptance_criteria="GET / returns 200 with body containing 'Hello'",)result = await self.wait_for_reality_check(handle)# result.verdict in {"pass", "fail"} — or None with result.failure_mode setInstance
The unit of work. You create one, watch its events, and read its final state.
Resolver
The strategy. Registered once, runs inside isolated containers, emits events.
Events
The observability layer. Append-only JSONL — the primary interface between the resolver and the outside world.
Viewport
The custom UI. An ESM bundle the resolver optionally ships for a rich frontend experience.
Pipeline
The workflow graph. DOT format, executed by the dot-graph resolver to
orchestrate multi-step agent work.
Reality Check
The verification layer. Clean-room deploy + validator = a real pass/fail verdict.