Documentation/Guides/Runs & Boundaries

STEP 8 OF 10

Runs & Boundaries

Every time an agent does something, real or dry-run, it becomes an AgentExecution row you can open and read step by step. This guide covers /runs, the per-execution timeline, and the Boundaries tab that shows what an agent is actually allowed to do.

Starting a run

An execution is dispatched to the tenant's data-plane runtime, not run in-process. There is no in-process fallback: if the runtime is unreachable, the execution comes back status: failed with the real error, never a silently degraded answer.

curl -X POST "https://your-control-plane-host/api/v1/executions?tenant_id=$TENANT_ID" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"agent_id": "<agent_id>", "purpose": "manual", "input": {"content": "Summarize open matters."}}'

The response is 202 with the execution row (steps included, though usually empty at the moment you get the response back — the runtime is still working). Poll it, or subscribe to the stream:

curl "https://your-control-plane-host/api/v1/executions/{execution_id}" -H "Authorization: Bearer $TOKEN"
curl "https://your-control-plane-host/api/v1/executions/{execution_id}/stream" -H "Authorization: Bearer $TOKEN"

A run can be refused before it ever reaches the runtime — 429/409/412 with a machine-readable code: budget_exceeded (the tenant's monthly cap), rate_limit_exceeded, or cost_cap_exceeded (a per-agent guardrail, see below). runtime_not_configured means the tenant has no data-plane runtime registered yet.

The step timeline

Every execution's steps array is ordered and typed. The kinds you'll actually see:

  • memory_read — the runtime pulled context from one or more of the 5 memory layers before planning
  • llm_turn — one call to the model, this is where tokens and cost accrue
  • tool_call — the agent invoked a tool (a connector action, a KG search, a gateway action request, ...)
  • policy_decision — the agent's policy graph allowed or denied a tool call; allow: false means the model asked for something outside its boundaries and was refused, not that the run failed
  • approval — a gateway action the agent requested is sitting in the human approval queue
  • memory_write — the runtime wrote a new episodic trace or updated a semantic entity
  • output — the final answer
  • error — something genuinely broke

GET /executions/{id} returns the full list. Each AgentExecution also carries tokens_in, tokens_out, cost_usd, and pricing_status (priced or unpriced — an unpriced run is never shown as $0, the model just wasn't in the pricing table) and trace_chain_verified: the runtime emits a hash-chained trace, and the control plane verifies it wasn't tampered with in transit before it's ever displayed.

Workflow runs nest agent runs

A /workflows/{id}/execute run that includes an agent node doesn't call the model itself — it dispatches a real child AgentExecution for that node, waits for it to finish, and folds its cost and tokens into the workflow total. GET /executions?kind=workflow lists workflow runs with their child executions attached; opening a workflow run in the dashboard shows every node's real sub-timeline, not a summary.

curl "https://your-control-plane-host/api/v1/executions?kind=workflow&tenant_id=$TENANT_ID" \
  -H "Authorization: Bearer $TOKEN"

curl "https://your-control-plane-host/api/v1/executions/cost?tenant_id=$TENANT_ID" \
  -H "Authorization: Bearer $TOKEN"

/executions/cost is what the Cost tab and /runs list read: spend by day, by model, by agent, and the tenant's unpriced_count so a stale pricing table never hides real spend.

The dashboard

/runs lists every execution (agent and workflow, kind filterable) with cost, tokens, duration, and status. /runs/{id} is the timeline view — a resizable, collapsible three-pane layout (file tree of steps on the left, detail pane in the middle, a right rail for metadata) with a fullscreen toggle for reading a long multi-step run without the rest of the dashboard chrome. Layout state (pane widths, which panels are collapsed) persists per browser.

Boundaries

/agents/{id}Boundaries answers "what can this agent actually do" as a three-column table — Can do, Needs approval, Cannot do — built from the agent's real policy graph, not from documentation someone has to keep in sync by hand.

curl "https://your-control-plane-host/api/v1/workforce/agents/{agent_id}/boundaries" \
  -H "Authorization: Bearer $TOKEN"

Every row carries an enforced_at value telling you where the rule is actually checked:

  • runtime_policy — the agent's own policy graph inside the data-plane runtime (tool allowlists, PII redaction)
  • gateway — the Action Gateway, before a real-world action executes (Authority Matrix rules, connector-scoped actions)
  • control_plane — checked by the control plane before dispatch (cost caps, rate limits)
  • advisory — recorded, not enforced (a guardrail field that's set but has nothing wired to block on it yet)

Rows that have fired recently link to the exact run step where they last did — click through from Boundaries straight into a policy_decision or approval step on /runs/{id}.

Boundaries are set per agent via AgentGuardrails:

curl -X PUT "https://your-control-plane-host/api/v1/workforce/agents/{agent_id}/guardrails" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "tool_allowlist": ["search_knowledge_graph", "ask_company_brain"],
    "approval_required_tools": ["request_gateway_action"],
    "max_cost_per_run_usd": 0.50,
    "max_runs_per_hour": 20,
    "pii_redaction": true,
    "output_schema": null
  }'

tool_allowlist: null means no explicit narrowing (the agent gets everything its definition grants); an explicit list is the only thing that can produce a real policy_decision: allow=false — narrow it below what the agent actually tries to use and its next run will show a real denial, not a simulated one.

What's next

Step 9 — Governance: The Rule Book: boundaries like the Authority Matrix rules you saw above don't have to be typed in by hand — they can come from an actual policy document you upload.