Skip to content

Workflows & Architect API

Workflow definition CRUD, run lifecycle, approvals, and the AI-assisted Architect panel.

This page documents the gateway endpoints that manage workflow definitions and workflow runs, plus the Architect panel that proposes AI-assisted revisions to a workflow. These are the routes the dashboard’s Workflows pages call, and they are what you script when you want to create, run, approve, retry, or monitor workflows without clicking through the UI.

Workflow definitions are declarative YAML pipelines stored in Kumiho graph memory and executed by the operator-mcp backend. If you are writing the YAML itself, start with Your first workflow and the Workflow YAML reference; this page covers the HTTP surface around it. For the dashboard equivalents, see Workflows, editor & runs.

Every route on this page requires the pairing bearer token:

Authorization: Bearer <token>

Obtain the token through the flow in Pairing & authentication. A missing or invalid token returns 401. Most routes share the gateway’s default 64 KiB JSON body cap and request timeout, with two exceptions called out below: POST/PUT on workflow definitions accept a 16 MiB body (real workflows can exceed 64 KiB), and operator-tool-backed routes (run, approve, retry, cancel, Architect) each have a fixed operator timeout.

Workflow definitions and run history live in Kumiho, not config.toml:

ResourceKumiho spaceItem kind
DefinitionsRevka/Workflowsworkflow
Run historyRevka/WorkflowRunsworkflow_run
Run requestsRevka/WorkflowRunRequestsworkflow-run-request

Each definition is a Kumiho item whose latest published revision holds the metadata, with the YAML itself stored as a workflow.yaml revision artifact rather than inline metadata (to stay under Kumiho’s size limit). Every save writes a new revision and tags it published, so history is preserved and each run can be pinned to the exact revision it executed. The gateway creates the project and spaces lazily on first write.

GET /api/workflows
POST /api/workflows (16 MiB body)
PUT /api/workflows/{*kref} (16 MiB body)
DELETE /api/workflows/{*kref}
POST /api/workflows/deprecate
GET /api/workflows/revisions/{*kref}

The {*kref} segment expects the bare path after the scheme — for example Revka/Workflows/my-flow.workflow (no kref:// prefix). PUT and DELETE prepend the scheme themselves and will double it if you include it. The exception is GET /api/workflows/revisions/{*kref}, which does strip a leading kref:// prefix before looking up the item.

GET /api/workflows?include_deprecated=false&include_definition=true&q=report
Authorization: Bearer <token>
Query paramTypeDefaultMeaning
include_deprecatedboolfalseInclude deprecated workflows in the result.
include_definitionbooltrueInclude the full YAML in each entry. Set false for a lighter list.
qstringFull-text search across definitions.

Non-search list responses are served from a short in-process cache (about 30 s) to absorb dashboard polling, and the cache is invalidated on every write.

POST /api/workflows
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "daily-report",
"description": "Summarise yesterday and email the team.",
"definition": "name: daily-report\nversion: \"1.0\"\nsteps:\n - id: summarize\n action: summarize\n agent:\n prompt: \"Summarise ${inputs.topic}.\"\n",
"version": "1.0",
"tags": ["reporting"]
}
FieldRequiredMeaning
nameyesDisplay name; slugified into the item identifier.
descriptionyesHuman-readable purpose.
definitionyesThe full workflow YAML, as a string.
versionnoSemantic version label.
tagsnoClassification list for search and filtering.

Before persisting, the gateway validates the YAML by calling the operator’s validator (see Validation). On success it slugifies name, writes the metadata revision, stores the YAML as the workflow.yaml artifact, tags the revision published, and returns 201 Created with { "workflow": { ... } }. It also syncs cron jobs and broadcasts a workflow.revision.published event.

PUT /api/workflows/Revka/Workflows/daily-report.workflow
Authorization: Bearer <token>
Content-Type: application/json

The body has the same shape as create. An update writes a new revision (it never edits the old one in place), re-tags it published, re-syncs cron jobs, and broadcasts workflow.revision.published. Because old revisions are retained, in-progress and historical runs continue to display the YAML they actually executed.

POST /api/workflows/deprecate
Authorization: Bearer <token>
Content-Type: application/json
{ "kref": "kref://Revka/Workflows/daily-report.workflow", "deprecated": true }

Deprecation is a soft toggle. Deprecated workflows are hidden from the default list (pass include_deprecated=true to see them) and their cron jobs are removed. Set "deprecated": false to restore the workflow and re-register its cron triggers.

DELETE /api/workflows/Revka/Workflows/daily-report.workflow
Authorization: Bearer <token>

Returns 204 No Content. This permanently removes the item and its cron jobs. Prefer deprecation when you only want to disable a workflow.

GET /api/workflows/revisions/kref://Revka/Workflows/daily-report.workflow?r=3
Authorization: Bearer <token>

Returns { "workflow": { ... } } with the YAML pinned to that exact revision kref, independent of whatever is currently tagged published. The dashboard run viewer uses this to render the exact definition a run executed. A revision whose workflow.yaml artifact is missing returns 404.

A run is one execution of a definition. Triggering a run creates a durable workflow-run-request item in Kumiho and immediately invokes the operator’s run_workflow tool for fast startup; if that direct call fails, the request item is still picked up by the operator’s listener. Run state is reported by overlaying local checkpoint data on top of the Kumiho run record, so progress stays current.

GET /api/workflows/runs
GET /api/workflows/runs/{run_id}
POST /api/workflows/run/{name}
POST /api/workflows/runs/{run_id}/approve
POST /api/workflows/runs/{run_id}/retry
POST /api/workflows/runs/{run_id}/cancel
DELETE /api/workflows/runs/{run_id}
StatusMeaning
pendingCreated but not yet picked up by the executor.
runningThe executor is active.
pausedWaiting at a human-approval or human-input gate.
completedAll steps finished successfully.
failedA step failed; the checkpoint is preserved so the run can be retried.
cancelledStopped by a user or the system.
staleNon-terminal status with no checkpoint and no live lock (for example, after a redeploy wiped local state).
GET /api/workflows/runs?limit=20&workflow=daily-report
Authorization: Bearer <token>
Query paramTypeDefaultMeaning
limitint20Maximum number of recent runs to return.
workflowstringFilter to runs of a single workflow by name.

Returns { "runs": [...], "count": N }, newest first.

GET /api/workflows/runs/{run_id}
Authorization: Bearer <token>

Returns { "run": { ... } } with per-step detail. Live runs are read from the executor’s in-memory status; finished runs are resolved from the Kumiho run record. An unknown run_id returns 404.

POST /api/workflows/run/daily-report
Authorization: Bearer <token>
Content-Type: application/json
{
"inputs": { "topic": "AI safety" },
"cwd": "/path/to/project",
"target_step_id": "summarize"
}
FieldRequiredMeaning
inputsnoObject mapping workflow input names to values.
cwdnoWorking directory for shell/agent steps.
target_step_idno”Run to here” — execute only the transitive ancestors of this step, plus the step itself, then stop.

The path segment is the workflow name (not a kref). The workflow is validated before dispatch; an invalid definition or an unknown target_step_id returns 400 with a validation-error body. On success the response is:

{ "run_id": "<uuid>", "workflow": "daily-report", "status": "pending" }

A workflow can pause at a human_approval step (defined in the YAML) until an operator approves or rejects. Resolve the gate with:

POST /api/workflows/runs/{run_id}/approve
Authorization: Bearer <token>
Content-Type: application/json
{ "approved": true, "feedback": "LGTM" }
FieldRequiredMeaning
approvedyestrue to continue the workflow, false to reject.
feedbacknoFree-text note recorded with the decision.

The gateway atomically claims the approval from an internal registry before resuming, so concurrent approvals (for example, a dashboard click and a Discord reply arriving at the same time) cannot double-resolve the gate. It then calls the operator’s resume_workflow tool, audits the decision, and broadcasts a human_approval_resolved SSE event. A successful call returns:

{ "status": "ok", "message": "Workflow approved", "run_id": "<uuid>", "approved": true }
POST /api/workflows/runs/{run_id}/retry
Authorization: Bearer <token>
Content-Type: application/json
{ "cwd": "/path/to/project" }

The body is optional. Retry re-executes from the first failed step — successful step outputs are preserved from the checkpoint, so only the failed step and its downstream steps run again. It broadcasts a workflow_retry SSE event and returns the operator tool’s result payload.

POST /api/workflows/runs/{run_id}/cancel
Authorization: Bearer <token>

No body. Cancel sets the executor’s cancel flag via the cancel_workflow tool; the executor reads it at the next step boundary, kills any in-flight shell or python subprocesses, and transitions the run to cancelled. The HTTP status reflects the outcome:

StatusCondition
200 OKThe run was active and cancellation was requested.
404 Not FoundThe run is not in the active registry (already finished or unknown).
409 ConflictThe run is already in a terminal state.

A successful cancel broadcasts a workflow_cancel SSE event.

DELETE /api/workflows/runs/{run_id}
Authorization: Bearer <token>

Returns 204 No Content. Deletes the run record from Revka/WorkflowRuns and best-effort cleans up local files — the checkpoint at ~/.revka/workflow_checkpoints/{run_id}.json and any per-run artifacts directory.

A single aggregated call powers the Workflows landing page so it does not need to fan out into separate definition and run requests:

GET /api/workflows/dashboard?include_definition=true
Authorization: Bearer <token>

include_definition (default true) controls whether the YAML is included for each definition. The response is wrapped in dashboard:

{
"dashboard": {
"definitions_count": 12,
"definitions": [ ... ],
"active_runs": 2,
"recent_runs": [ ... ],
"total_runs": 47
}
}

active_runs counts runs in running or paused state, and recent_runs holds the most recent runs.

For the dashboard’s Live Execution View, each agent that runs inside a workflow keeps a per-agent JSONL run log. Read it for drill-down into that agent’s tool calls, messages, and results:

GET /api/workflows/agent-activity/{agent_id}?view=summary&limit=100
Authorization: Bearer <token>
Query paramTypeDefaultMeaning
viewstringsummaryOne of summary, tool_calls, messages, errors, full.
limitint100Max entries to return (capped at 500).

The summary view returns header, total event count, tool-call count, error count, the last message (truncated), recent tool calls, and aggregated token-usage stats. The other views return the matching filtered entries, newest first. An agent with no log returns 404. Log files live at ~/.revka/operator_mcp/runlogs/{agent_id}.jsonl.

Architect — AI-assisted workflow revision

Section titled “Architect — AI-assisted workflow revision”

The Architect panel in the workflow editor proposes structured edits to a workflow and lets you preview, validate, and revert revisions. All four routes require auth, and the operator-backed ones use a 30 s operator-tool timeout. The Architect requires the operator-mcp server to be connected.

POST /api/architect/revise
POST /api/architect/validate_yaml
GET /api/architect/revisions?workflow_kref=kref://...
POST /api/architect/republish
POST /api/architect/revise
Authorization: Bearer <token>
Content-Type: application/json
{
"workflow_kref": "kref://Revka/Workflows/daily-report.workflow",
"operations": [ { "op": "add_step", "step": { "id": "review", "action": "review" } } ],
"rationale": "Add a review gate before publishing."
}
FieldRequiredMeaning
workflow_krefyesThe workflow item to revise.
operationsyesNon-empty array of operation objects, forwarded verbatim to the operator’s revise_workflow tool. The tool defines and validates the operation shapes.
rationalenoHuman explanation attached to the revision.

The structured result from revise_workflow is returned unchanged.

POST /api/architect/validate_yaml
Authorization: Bearer <token>
Content-Type: application/json
{
"yaml": "<proposed workflow yaml>",
"base_yaml": "<current yaml, optional>",
"intent_summary": "Add a review gate"
}

This routes the proposed YAML through the same propose_workflow_yaml operator tool the LLM uses, returning { valid, errors, warnings, yaml, summary, added_step_ids, modified_step_ids, removed_step_ids }. It is validation only — nothing is persisted. The editor uses this for the chat-fallback path: when the Architect emits YAML in chat instead of calling the tool, the client posts the extracted YAML here so it still passes schema and workflow-level checks before reaching the canvas.

GET /api/architect/revisions?workflow_kref=kref://Revka/Workflows/daily-report.workflow
Authorization: Bearer <token>

Returns { "revisions": [ { "kref": "...?r=N", "number": N, "created_at": "...", "tags": [...], "metadata": { ... } } ] } — a thin summary of the workflow item’s revision history, used by the editor’s history strip.

POST /api/architect/republish
Authorization: Bearer <token>
Content-Type: application/json
{ "revision_kref": "kref://Revka/Workflows/daily-report.workflow?r=2" }

Re-tags an earlier revision as published. This is the UI-safe revert: it points the workflow back at a previous revision without deleting anything. The published tag is hardcoded — callers cannot use this route to set arbitrary tag values. On success it returns { "ok": true, "revision_kref": "..." }, invalidates the workflow list cache, and broadcasts a workflow.revision.published event so the editor refreshes the canvas and YAML.

Workflow state changes are pushed to dashboard clients over the Server-Sent Events stream (GET /api/events). The relevant event types are:

Event typeEmitted when
workflow.revision.publishedA definition is created, updated, or reverted via republish.
human_approval_resolvedA run’s approval gate is approved or rejected.
workflow_retryA run retry is requested.
workflow_cancelA run cancellation is requested.

human_approval_resolved, workflow_retry, and workflow_cancel carry run_id and a timestamp. workflow.revision.published carries workflow_kref, revision_kref, revision_number, name, published_at, and originating_session. For the full SSE envelope and other event types, see Realtime: WebSocket, SSE & Live Canvas.

Saving or running a workflow validates its YAML through the operator’s validate_workflow tool, which runs a six-pass check (duplicate step IDs, dependency references, cycle detection, per-step config, variable references, and trigger fields). On failure, POST/PUT definitions and POST /api/workflows/run/{name} reject with 400 and a body of this shape:

{
"error": "Workflow validation failed: ...",
"valid": false,
"errors": [ ... ],
"warnings": [ ... ]
}

If validation cannot run because of an infrastructure error (for example, the operator is briefly unreachable), it is skipped rather than blocking the save (fail-open). For the validation rules in depth, see Workflow YAML reference.