Agent Runs from Claude Code: Workflow Runs, Facts and Usage
The agent-farm MCP server: a run-centric tool set over core's agent_runs for developers and project managers, with the workflow engine as the run origin, scoped to the caller's own runs and projects, with the workflow inbox and per-person usage.
On this page
The agent-farm MCP server gives developers and project managers the run
lifecycle from inside Claude Code or Cowork: start a workflow run, follow the
headless agent steps it queues, read their event streams and recorded facts,
cancel them, answer the decisions the workflow is waiting on, and read usage for
themselves or one of their projects. It sits beside the admin systemprompt
server on port 5011 and is scoped to the user OAuth scope. The workflow
engine itself is described in Workflow Orchestration;
this server is the developer-facing way in.
Who reaches it
Entitlement is declared in services/access-control/rules.yaml like every
other entity. The astound-engineering workspace, its plugin, the
agent_farm_runs skill and the mcp_server/agent-farm entity are closed by
default and allowed to the developer, project_manager, admin,
platform_admin and super_admin roles. This server is not the admin plane:
project_manager is named here because the server scopes every run tool itself.
The role band only decides who sees the server. Inside it, every run tool applies one rule:
- a person reaches a run they launched, or that ran as them, including a step that ran as a workflow's service account on a run they started;
- a person reaches every run of a project they belong to;
- an administrator reaches every run.
Anything else is refused with a Forbidden: error that names the run. The
scope word is the same on every listing tool: mine, project, or all,
and all is refused without an administrator role.
Tools
| Tool | Read-only | What it does |
|---|---|---|
run_start |
no | Start a workflow definition's manual trigger as yourself; returns the workflow run id at once |
run_status |
yes | One agent run's lifecycle state, timings, tokens, cost, error class |
run_events |
yes | A page of the run's event stream, by seq |
run_cancel |
no | Cancel the workflow run a step belongs to, then the step |
run_list |
yes | Runs the caller may see, newest first, with recorded facts; workflow_run and definition narrow it |
run_facts |
yes | Everything recorded about one run, plus the workflow run's decisions, effects and history |
run_stats |
yes | Rollups over 24h, 7d or 30d, by status, error class and origin kind |
workflow_inbox |
yes | The open decisions addressed to a role you hold |
workflow_decide |
no | Answer one: approve, request_changes, reject or cancel |
analytics_costs |
yes | Spend over a window for the caller or a project |
analytics_requests |
yes | Gateway requests, failures, denials, latency, by model |
analytics_skills |
yes | Skill adoption and the conversations it reached |
analytics_tools |
yes | MCP tool executions by server and tool |
catalog_list |
yes | What the caller's access grants |
Every input is flat: strings and numbers with defaults, so a client never has
to guess a flag. Nothing here is model-judged: run_facts reports what the
tables recorded and nothing else.
A run from start to facts
run_start {"origin": "workflow", "definition": "core-dev", "context_json": "{\"jira_key\":\"ENG-12\"}"}
run_list {"scope": "mine", "workflow_run": "<origin_run_id>"}
run_status {"run_id": "<id>"} until terminal
run_events {"run_id": "<id>", "after_seq": 0}
run_facts {"run_id": "<id>"}
workflow_inbox {}
workflow_decide {"decision_id": "<id>", "outcome": "approve"}
run_start goes through the workflow engine's own trigger service, so the
definition's trigger roles, required context keys, variant and project rules
are resolved exactly as the console's Start button resolves them. The engine
then queues the run's agent steps; the tool never waits for them.
run_facts is the record the tables hold: outcome, tokens, reported and
metered cost, tool use counts by name, hook and governance decisions,
structured output and whether it matched the schema the request asked for,
and the workspace diff summary. A step's project and launcher come from its
workflow run (workflow_runs.project_id and initiated_by), which is how a
step that ran as a service account still belongs to the person who started the
workflow.
Connecting from Claude Code
MCP servers are reached through the gateway, never on their own port: the
server URL is https://<your instance>/api/v1/mcp/agent-farm/mcp. A personal
access token (PAT) is not accepted there directly; exchange it for a bridge
token first and present that as the bearer:
curl -s -X POST https://<your instance>/v1/auth/bridge/pat \
-H "Authorization: Bearer <pat>" -H "Content-Type: application/json" -d '{}'
claude mcp add --transport http agent-farm https://<your instance>/api/v1/mcp/agent-farm/mcp \
--header "Authorization: Bearer <bridge token>"
The bridge does all of this for you: a signed-in Claude Code or Cowork
session that holds the astound-engineering workspace receives the server
from its manifest with the token already attached. A call made straight to the
server's port fails with Invalid request context headers by design.
Operating it
The server is an internal MCP binary, systemprompt-mcp-agent-farm, declared
in services/mcp/agent-farm.yaml and built with the workspace. On this
instance it is compiled with the workflows feature on, which links the
workflows crate; the farm feature of the shared source is off because this
instance has no agent-farm domain. Access audit rows land in user_activity
like every other server's; tool usage lands in the same ledger the admin
console reads.