Minolith Runbooks API
The Runbooks service stores multi-step procedures that agents execute with persistent progress tracking. An agent loads a runbook, works through each step, records outcomes, and picks up exactly where it left off if interrupted. The agent can't forget where it was.
A runbook is a reusable template. It defines a procedure — ordered steps with optional branching, variables, and checkpoints. Each time the procedure is followed, a run is created — a specific execution with its own state, variable values, and step-by-step progress.
Base URL: https://api.minolith.io/v1/runbooks
Authentication: All endpoints require an API key via the Authorization header:
Authorization: Bearer mlth_your_api_key_here
Pricing: Creating a runbook template costs 5 credits ($0.05). Starting a run is free. All other operations — reading, updating, step management, progression, filtering — are free.
Core Concepts
Runbook (Template)
A reusable procedure definition containing:
- Steps — ordered instructions with optional branching
- Variables — placeholders filled in when a run starts (
{version},{environment}) - Metadata — name, description, category, tags
A runbook can be run many times. Each execution creates a Run.
Run (Execution)
A specific execution of a runbook containing:
- Variable values — the actual values for this execution
- Step states — which steps are pending, active, completed, skipped, or failed
- Step outcomes — what happened at each step (notes, outputs, timestamps)
- Overall status —
running,paused,completed,failed,cancelled
Step Types
| Type | Purpose |
|---|---|
action |
Do something. The default step type. |
check |
Verify something. Use outcome values (pass/fail) to branch. |
gate |
Wait for human input. The dashboard provides approve/reject buttons. The agent reads the outcome via get_current_step and then calls advance_step. |
branch |
Conditional routing based on outcome. Routes to different steps depending on the result. |
Branching
Steps can route to different next steps based on the outcome. Each step has:
next_default— the step to go to if no outcome-based routing matches (or for linear flow)next_on_outcome— a map of outcome value → step ID for conditional routing
Step 2: "Run test suite" (type: check)
→ outcome "pass" → Step 4: "Deploy"
→ outcome "fail" → Step 3: "Fix failures"
Step 3: "Fix failures"
→ outcome "done" → Step 2: "Run test suite" (retry)
Important: When using next_on_outcome, you must provide explicit step targets for all outcomes. A null value in next_on_outcome means "end of runbook" — it does NOT mean "continue to next step." If you want an outcome to continue the default flow, specify the target step ID explicitly or use a step:ref reference.
Variables
Variables are placeholders in step instructions. They are defined on the runbook template and filled in when a run starts.
{
"variables": [
{"name": "version", "description": "Release version", "required": true},
{"name": "environment", "required": false, "default": "production"}
]
}
In step instructions, use {variable_name}:
"Deploy {version} to {environment}"
When a run starts with {"version": "2.5.0"}, the instruction resolves to:
"Deploy 2.5.0 to production"
Step References
When creating a runbook with all steps in a single request, steps don't have IDs yet. Use ref labels to reference steps in next_on_outcome:
{
"steps": [
{"label": "Run tests", "type": "check", "next_on_outcome": {"pass": "step:deploy", "fail": "step:fix"}},
{"label": "Fix failures", "ref": "fix", "next_on_outcome": {"done": "step:tests"}},
{"label": "Deploy", "ref": "deploy"}
]
}
The API resolves step:ref_label to actual step IDs on creation. Once created, all routing uses step IDs.
Endpoints
Create Runbook
POST /v1/runbooks/
Creates a new runbook template with steps. Costs 1 credit.
Request body:
{
"name": "Deploy to Production",
"description": "Standard production deployment procedure.",
"category": "deployment",
"tags": ["production", "release"],
"variables": [
{"name": "version", "description": "Release version", "required": true},
{"name": "branch", "description": "Git branch", "required": true, "default": "main"}
],
"steps": [
{"label": "Pull latest code", "instruction": "Pull the latest code from {branch}.", "type": "action"},
{"label": "Run test suite", "instruction": "Run the full test suite.", "type": "check", "next_on_outcome": {"pass": "step:deploy", "fail": "step:fix"}},
{"label": "Fix test failures", "instruction": "Review and fix failures.", "ref": "fix", "next_on_outcome": {"done": "step:tests"}},
{"label": "Deploy application", "instruction": "Deploy {version} to production.", "ref": "deploy"},
{"label": "Smoke test", "instruction": "Verify critical endpoints.", "type": "check"},
{"label": "Confirm", "instruction": "Confirm deployment of {version}.", "type": "gate"}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Max 255 characters |
description |
string | no | Max 5,000 characters |
category |
string | no | Max 100 characters, lowercase alphanumeric + hyphens |
tags |
array | no | Up to 20 tags, each max 100 chars, lowercase alphanumeric + hyphens |
variables |
array | no | Up to 20 variable definitions (see Variables) |
steps |
array | yes | 1–100 steps (see Step Fields) |
Step fields:
| Field | Type | Required | Description |
|---|---|---|---|
label |
string | yes | Short name, max 255 characters |
instruction |
string | yes | Full instruction, max 5,000 characters. May contain {variable} placeholders. |
type |
string | no | action (default), check, gate, branch |
required |
boolean | no | Whether the step can be skipped. Default true. |
ref |
string | no | Reference label for targeting from other steps' next_on_outcome |
next_on_outcome |
object | no | Map of outcome value → step ref or step ID |
metadata |
object | no | Step-specific configuration |
Response (201 Created):
{
"data": {
"id": "rnb_a1b2c3d4e5f6",
"name": "Deploy to Production",
"description": "Standard production deployment procedure.",
"category": "deployment",
"tags": ["production", "release"],
"variables": [...],
"steps": [
{"id": "rbs_001", "position": 1, "label": "Pull latest code", "type": "action", "required": true, "next_default": "rbs_002", "next_on_outcome": null},
{"id": "rbs_002", "position": 2, "label": "Run test suite", "type": "check", "required": true, "next_default": "rbs_003", "next_on_outcome": {"pass": "rbs_004", "fail": "rbs_003"}}
],
"is_archived": false,
"created_at": "2026-03-17 10:00:00",
"updated_at": "2026-03-17 10:00:00"
}
}
Default step wiring: Steps without explicit next_default are automatically wired to the next step by position. The last step has next_default: null (end of procedure).
Error responses:
402— Spending cap exceeded.422— Validation error.
List Runbooks
GET /v1/runbooks/
Returns runbook templates. Excludes archived runbooks by default.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
category |
string | Filter by category |
tags |
string | Filter by tags (comma-separated, matches ANY) |
is_archived |
boolean | Include archived runbooks (true to show only archived) |
limit |
integer | 1–100, default 20 |
cursor |
string | Cursor for pagination |
Response (200 OK):
{
"data": [
{
"id": "rnb_a1b2c3d4e5f6",
"name": "Deploy to Production",
"description": "...",
"category": "deployment",
"tags": ["production"],
"step_count": 6,
"is_archived": false,
"created_at": "2026-03-17 10:00:00",
"updated_at": "2026-03-17 10:00:00"
}
],
"pagination": {"has_more": false, "next_cursor": null, "limit": 20}
}
Get Runbook
GET /v1/runbooks/:id
Returns a runbook with all its steps.
Response (200 OK): Same format as the create response.
Error responses:
404— Runbook not found.
Update Runbook
PUT /v1/runbooks/:id
Updates runbook metadata. Name, description, category, tags, and variables are always editable. Only include fields you want to change.
Steps cannot be added, removed, or reordered if any runs exist. Step labels and instructions can always be edited via the step endpoints.
Request body (partial update):
{
"name": "Updated name",
"category": "new-category",
"tags": ["updated", "tags"]
}
Response (200 OK): Returns the full updated runbook.
Delete Runbook
DELETE /v1/runbooks/:id
Permanently deletes a runbook, its steps, and all runs. Cannot delete a runbook with active runs (status running or paused) — archive it instead.
Response (204 No Content).
Error responses:
404— Runbook not found.409— Runbook has active runs.
{
"error": {
"code": "conflict",
"message": "Runbook 'rnb_xxx' cannot be deleted — it has 2 active run(s). Archive it instead.",
"docs": "https://docs.minolith.io/api/runbooks#delete-runbook"
}
}
Archive Runbook
POST /v1/runbooks/:id/archive
Archives a runbook. Archived runbooks are excluded from list results by default and cannot have new runs started.
Response (200 OK):
{"data": {"message": "Runbook archived."}}
Add Step
POST /v1/runbooks/:id/steps
Adds a step to a runbook. Blocked if any runs exist.
Request body:
{
"label": "New step",
"instruction": "Do this thing.",
"type": "action",
"required": true
}
Response (201 Created): Returns the created step.
Update Step
PUT /v1/runbooks/:id/steps/:step_id
Updates a step. Label and instruction are always editable. Structural fields (type, required, ref, next_default, next_on_outcome, metadata) are only editable if no runs exist.
Response (200 OK): Returns the updated step.
Delete Step
DELETE /v1/runbooks/:id/steps/:step_id
Removes a step. Blocked if any runs exist.
Response (204 No Content).
Reorder Steps
PUT /v1/runbooks/:id/steps/reorder
Reorders steps. Blocked if any runs exist.
Request body:
{
"step_ids": ["rbs_003", "rbs_001", "rbs_002"]
}
Response (200 OK): Returns the reordered steps.
Start Run
POST /v1/runbooks/:id/runs
Starts a new execution of a runbook. Costs 1 credit. Provide variable values for this run. Returns the first step to execute.
Request body:
{
"variables": {
"version": "2.5.0",
"branch": "release/2.5.0"
}
}
Response (201 Created):
{
"data": {
"id": "run_x1y2z3w4",
"runbook_id": "rnb_a1b2c3d4e5f6",
"runbook_name": "Deploy to Production",
"status": "running",
"variables": {"version": "2.5.0", "branch": "release/2.5.0"},
"current_step": {
"id": "rbs_001",
"label": "Pull latest code",
"instruction": "Pull the latest code from release/2.5.0.",
"type": "action",
"required": true,
"status": "active"
},
"progress": {
"total_steps": 6,
"completed": 0,
"skipped": 0,
"failed": 0,
"remaining": 6
},
"started_at": "2026-03-17 14:00:00"
}
}
Error responses:
402— Spending cap exceeded.404— Runbook not found.409— Runbook is archived or has no steps.422— Missing required variable.
List Runs
GET /v1/runbooks/runs
Lists runs across all runbooks.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status (comma-separated): running, paused, completed, failed, cancelled |
runbook_id |
string | Filter by runbook template |
started_after |
string | ISO date/datetime |
limit |
integer | 1–100, default 20 |
cursor |
string | Cursor for pagination |
Response (200 OK):
{
"data": [
{
"id": "run_x1y2z3w4",
"runbook_id": "rnb_a1b2c3d4e5f6",
"runbook_name": "Deploy to Production",
"status": "running",
"progress": {"total_steps": 6, "completed": 3, "skipped": 0, "failed": 0, "remaining": 3},
"started_at": "2026-03-17 14:00:00",
"completed_at": null
}
],
"pagination": {"has_more": false, "next_cursor": null, "limit": 20}
}
Get Run
GET /v1/runbooks/runs/:run_id
Returns a run with all step states, instructions (with resolved variables), outcomes, notes, and outputs.
Response (200 OK):
{
"data": {
"id": "run_x1y2z3w4",
"runbook_id": "rnb_a1b2c3d4e5f6",
"runbook_name": "Deploy to Production",
"status": "running",
"variables": {"version": "2.5.0"},
"steps": [
{
"step_id": "rbs_001",
"label": "Pull latest code",
"instruction": "Pull the latest code from release/2.5.0.",
"type": "action",
"required": true,
"position": 1,
"status": "completed",
"outcome": "done",
"notes": "Pulled commit abc123.",
"output": null,
"started_at": "2026-03-17 14:00:00",
"completed_at": "2026-03-17 14:02:00"
}
],
"progress": {"total_steps": 6, "completed": 3, "skipped": 0, "failed": 0, "remaining": 3},
"started_at": "2026-03-17 14:00:00",
"completed_at": null
}
}
Get Current Step
GET /v1/runbooks/runs/:run_id/current
This is the primary resume endpoint. Call this at the start of any session to know exactly where you are in a procedure and what to do next. Returns the current step instruction, progress summary, completed steps, and run variables.
Response (200 OK):
{
"data": {
"run_id": "run_x1y2z3w4",
"run_status": "running",
"current_step": {
"id": "rbs_004",
"label": "Deploy application",
"instruction": "Deploy 2.5.0 to production.",
"type": "action",
"required": true,
"status": "active",
"outcome": null
},
"progress": {"total_steps": 6, "completed": 3, "skipped": 0, "failed": 0, "remaining": 3},
"completed_steps": [
{"id": "rbs_001", "label": "Pull latest code", "status": "completed", "outcome": "done", "completed_at": "2026-03-17 14:02:00"},
{"id": "rbs_002", "label": "Run test suite", "status": "completed", "outcome": "pass", "completed_at": "2026-03-17 14:05:00"}
],
"variables": {"version": "2.5.0", "branch": "release/2.5.0"}
}
}
When the run is completed, current_step is null.
Advance Step
POST /v1/runbooks/runs/:run_id/advance
Marks the current step as completed and advances to the next step. The outcome value determines which step comes next when branching is configured.
Request body:
{
"outcome": "pass",
"notes": "All 247 tests passed. No warnings.",
"output": {
"test_count": 247,
"failures": 0,
"duration_seconds": 34
}
}
| Field | Type | Required | Description |
|---|---|---|---|
outcome |
string | no | Step outcome, used for branching. Default "done". Max 100 characters. |
notes |
string | no | What happened during this step. Max 10,000 characters. |
output |
object | no | Structured output data (command results, file paths, etc.). Max 50KB serialised. |
Response (200 OK): Same format as Get Current Step, showing the next step.
Advance logic:
- Mark current step as
completedwith the provided outcome, notes, and output - Check
next_on_outcome— if the outcome matches a key, go to that step - If no match (or no
next_on_outcome), go tonext_default - If next step is
null, the run is complete - Return the updated run state
Error responses:
404— Run not found.409— Run is not active (paused, completed, failed, or cancelled).
Skip Step
POST /v1/runbooks/runs/:run_id/skip
Skips the current step. Only works if the step is not required. Advances to the next step via the default route.
Request body:
{
"notes": "Skipping database backup — no schema changes in this release."
}
Response (200 OK): Same format as Get Current Step.
Error responses:
409— Run is not active.422— Step is required and cannot be skipped.
Fail Step
POST /v1/runbooks/runs/:run_id/fail
Marks the current step as failed. This also sets the run status to failed. The failure is recorded in the step's notes and output. The run can be resumed later.
Request body:
{
"notes": "Migration failed: column already exists.",
"output": {"error": "SQLSTATE[42S21]", "migration": "2026_03_17_add_column"}
}
Response (200 OK): Same format as Get Current Step.
Update Run
PUT /v1/runbooks/runs/:run_id
Updates run status. Use to pause, resume, or cancel a run.
Request body:
{"status": "paused"}
Valid status transitions:
| From | Allowed To |
|---|---|
running |
paused, cancelled |
paused |
running, cancelled |
failed |
running (resumes — reactivates the failed step for retry) |
completed |
(none) |
cancelled |
(none) |
Response (200 OK):
{"data": {"id": "run_x1y2z3w4", "status": "paused"}}
Error responses:
409— Invalid status transition.
Validation Rules
| Field | Constraints |
|---|---|
name |
Required, max 255 characters |
description |
Max 5,000 characters |
category |
Max 100 characters, lowercase alphanumeric + hyphens |
steps |
1–100 steps per runbook |
step.label |
Required, max 255 characters |
step.instruction |
Required, max 5,000 characters |
step.type |
action, check, gate, branch (default: action) |
variables |
Max 20 per runbook |
variable.name |
Required, max 50 characters, alphanumeric + underscore |
tags |
Max 20, each max 100 characters, lowercase alphanumeric + hyphens |
outcome |
Max 100 characters |
notes |
Max 10,000 characters |
output |
Max 50KB serialised |
Editing Runbooks With Existing Runs
Once a runbook has any runs (regardless of status), structural changes are restricted to protect run integrity:
Always editable: name, description, category, tags, variables, step labels, step instructions.
Blocked if runs exist: adding steps, removing steps, reordering steps, changing step type/required/ref/next_default/next_on_outcome.
To make structural changes, delete all runs first, or create a new runbook.
Gate Steps
Gate steps are the human-in-the-loop mechanism. When a run reaches a gate step:
- The step becomes
active— the agent sees it viaget_current_step - A human approves or rejects via the dashboard (sets the step's outcome to
approvedorrejected) - The agent calls
get_current_stepand sees the outcome on the active step - The agent calls
advance_stepwith that outcome to continue
The dashboard does NOT advance the run — the agent does. The dashboard just records the human's decision. This keeps the agent autonomous and in control of the execution flow.
Error Responses
All errors follow the standard Minolith error format. Runbooks-specific error codes:
| Code | HTTP | Message |
|---|---|---|
not_found |
404 | Runbook or run not found in this project. |
conflict |
409 | Run is not active, runbook has active runs, or runbook is archived. |
validation_error |
422 | Step is required (can't skip), missing variable, invalid step type, too many steps. |
spending_cap_exceeded |
402 | Creating runbook or starting run would exceed spending cap. |
ID Formats
| Entity | Prefix | Example |
|---|---|---|
| Runbook | rnb_ |
rnb_a1b2c3d4e5f6 |
| Step | rbs_ |
rbs_a1b2c3d4e5f6 |
| Run | run_ |
run_a1b2c3d4e5f6 |
| Run Step | rrs_ |
rrs_a1b2c3d4e5f6 |
Credit Costs
| Action | Credits | Cost |
|---|---|---|
| Create runbook template | 5 | $0.05 |
| Start run | 0 | Free |
| All other operations | 0 | Free |
Rate Limiting
All API endpoints are rate-limited to 100 requests per minute per API key. See Platform API — Rate Limiting.
MCP Tools
The Runbooks service is available via MCP for direct integration with AI coding tools.
create_runbook
Create a new runbook template. Define the procedure name, steps, and optional variables. Steps are wired linearly by default — only specify next_on_outcome for branching steps.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Runbook name |
description |
string | no | What this procedure does |
category |
string | no | Category for grouping |
tags |
array | no | Tags for filtering |
variables |
array | no | Variable definitions |
steps |
array | yes | Step definitions |
list_runbooks
List available runbook templates. Use to find an existing procedure before creating a new one.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
category |
string | no | Filter by category |
tags |
array | no | Filter by tags |
limit |
integer | no | Max results (default 20, max 100) |
start_run
Start a new execution of a runbook. Provide variable values. Returns the first step to execute.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
runbook_id |
string | yes | Runbook template ID |
variables |
object | no | Variable values for this run |
get_current_step
The primary resume endpoint. Call this at session start to know where you are and what to do next. Returns current step, progress, completed steps, and variables.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run ID |
advance_step
Complete the current step and advance. Provide outcome (for branching), notes, and optional output.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run ID |
outcome |
string | no | Step outcome for branching. Default "done". |
notes |
string | no | What happened during this step. |
output |
object | no | Structured output data. |
skip_step
Skip the current step. Only works for non-required steps.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run ID |
notes |
string | no | Why this step is being skipped. |
fail_step
Mark the current step as failed. Also marks the run as failed. The run can be resumed later.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run ID |
notes |
string | no | What went wrong. |
output |
object | no | Error details or diagnostics. |
pause_run
Pause a running run. Use when ending a session mid-procedure or when waiting for an external dependency. The run can be resumed later by calling get_current_step and continuing to advance.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run ID |
reason |
string | no | Why the run is being paused (e.g. "session ending", "waiting for approval"). |
list_runs
List runs. Filter by status to find active, paused, or failed runs. Use at session start to check for in-progress procedures.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
string | no | Filter by status (comma-separated) |
runbook_id |
string | no | Filter by runbook template |
limit |
integer | no | Max results (default 20, max 100) |
Example Workflows
Agent executes a deployment
1. Agent calls list_runbooks with category: "deployment"
2. Finds "Deploy to Production" (rnb_xxx)
3. Agent calls start_run with variables: {version: "2.5.0"}
4. API returns first step: "Pull latest code"
5. Agent executes the step
6. Agent calls advance_step with outcome: "done"
7. API returns next step: "Run test suite"
8. Agent runs tests, they pass
9. Agent calls advance_step with outcome: "pass"
10. API routes to "Deploy" (skipping the failure branch)
11. Agent deploys, advances through remaining steps
12. At the gate step, agent checks get_current_step — sees outcome from dashboard
13. Agent calls advance_step, run completes
Agent resumes an interrupted run
1. New session starts
2. Agent calls list_runs with status: "running,paused"
3. Finds an active run at step 5
4. Agent calls get_current_step — gets full context: what's done, what's next, variables
5. Agent picks up exactly where it left off
Agent creates a runbook from experience
1. Developer walks through a process with the agent
2. At the end: "create a runbook from what we just did"
3. Agent constructs steps from the conversation
4. Agent calls create_runbook with the structured procedure
5. Next time: agent loads and follows the runbook consistently