HTTP API

The playground exposes a small FastAPI surface. The base URL is http://localhost:8000 by default. Interactive docs are available at /docs (Swagger) and /redoc when the server is running.

Route summary

MethodPathStatusPurpose
GET/200Service metadata + endpoint list
GET/healthz200Liveness
GET/readyz200Readiness — pings both registries
GET/scenarios200List the scenario catalog
GET/scenarios/{id}200 / 404One scenario's metadata
POST/runs202Start a scenario run
GET/runs/{id}200 / 404Poll run status + result
GET/runs/{id}/events200SSE stream of run events
GET/contexts/{ctx_id}200 / 404Retrieve a context from the right registry
POST/webhooks/acdp204Registry → playground webhook ingestion

Health

GET /healthz

{ "ok": true, "service": "acdp-playground" }

GET /readyz

Best-effort pings both registries; one registry being down does not fail the response.

{ "ok": true, "registry_a": true, "registry_b": true }

Scenarios

GET /scenarios

{
  "scenarios": [
    {
      "id": "s4_chain",
      "name": "Linear Chain A→B→C",
      "description": "...",
      "registry_mode": "single",
      "agent_count": 3,
      "framework": "langchain",
      "default_inputs": { "topic": "GPU supply chains" }
    }
  ]
}

GET /scenarios/{scenario_id}

Returns the single serialized ScenarioDef, or 404 if unknown.

Runs

POST /runs

Request body (RunRequest):

{
  "scenario_id": "s4_chain",
  "inputs": { "topic": "GPU supply chains" },
  "registry_mode": "single"
}
  • scenario_id (required) — must exist (404 otherwise)
  • inputs (optional) — merged over the scenario's default_inputs
  • registry_mode (optional) — overrides the scenario default

Response (202 Accepted):

{
  "run_id": "9f1c...",
  "scenario_id": "s4_chain",
  "status": "running",
  "stream_url": "/runs/9f1c.../events",
  "started_at": "2026-06-10T12:00:00Z"
}

The run executes as a background task. Subscribe to stream_url for live events.

GET /runs/{run_id}

{
  "run_id": "9f1c...",
  "status": "running",      // running | complete | failed
  "result": null             // RunResult once complete
}

Checks both the in-flight queue and persisted results; 404 if the run is unknown and not in flight.

GET /runs/{run_id}/events (SSE)

Media type text/event-stream. Each message is:

data: {"type":"acdp.publish","run_id":"9f1c...","ts":"...","agent_id":"did:web:...","ctx_id":"acdp://...","title":"..."}

Behavior:

  • Run in flight — drains the run's queue as it fills. Sends a keepalive comment every 15s on idle. Terminates on run.complete or run.error.
  • Run already finished — replays the final result and an end marker.
  • The queue is cleaned up on client disconnect.

StepEvent schema

FieldNotes
typeOne of the event types below
run_idCorrelates to the run
tsUTC ISO-8601 timestamp
agent_idEmitting agent's DID (when applicable)
frameworklangchain / crewai / langgraph
ctx_id, title, derived_fromContext details on publish/retrieve
previewShort LLM-output preview
contexts_produced, lineage_graphOn run.complete
errorOn run.error
registry_authority, tenant_id, event_idRouting / dedup metadata

Event types: agent.started, llm.thinking, acdp.publish, acdp.retrieve, acdp.search, acdp.verify, auth.token, auth.revoke, policy.check, scenario.note, webhook.received, run.started, run.complete, run.error.

Contexts

GET /contexts/{ctx_id}

ctx_id is the full ACDP URI (e.g. acdp://registry-a.playground.local/<uuid>); it is matched as a path parameter. The playground extracts the authority, routes to the matching registry, and proxies the retrieval. 404 if no registry is configured for that authority. Registry errors are forwarded as HTTP exceptions.

Webhooks

POST /webhooks/acdp

The endpoint registries call when a context is published/retrieved/searched. Returns 204. The webhook payload and signing scheme are the registry's — see the registry's WEBHOOKS.md; the playground is the receiver.

Signature — header X-ACDP-Signature: sha256=<hex>, a GitHub-style HMAC-SHA256 of the raw body keyed by WEBHOOK_SECRET. A missing or invalid signature yields 401.

Processing:

  1. Validate the body is JSON (400 otherwise).
  2. Parse a WebhookEvent (a schema mismatch logs a warning but does not fail).
  3. Lift request headers onto the event when not already present (RFC-ACDP-0008 §6.4): X-Tenant-Idtenant_id, X-ACDP-Event-Idevent_id (dedup key), X-Run-Idrun_id.
  4. If run_id maps to an in-flight run, convert via StepEvent.from_webhook and enqueue onto that run's SSE bus (silent drop otherwise).
  5. Fire-and-forget forward to the control plane (re-signed with the CP secret), preserving the original body, headers, and tenant id.

In the default demo stack the registry webhook is disabled (its SSRF policy refuses the loopback http://playground:8000 target). Webhook-driven events are exercised in the unit suite and in deployments where the registry can reach the playground over a permitted target.