Skip to main content
API reference sections

HTTP API reference

Runs and schedules

Work delegated to an agent as runs, their history and MCP endpoint, and repeating schedules.

20 operations. The contract has no example values, so example bodies are generated from each schema: every field is shown with a placeholder of its type.

The runs of a workspace

GET/v1/runs

Every run registered in the workspace, oldest first, as its header - objective, agent, scope, status, executing device, results, economics, rating.

Authorization
Bearer token with runs.read
Operation id
runs_list

Parameters

NameInTypeDescription
workspacerequiredquerystring (uuid)

Responses

StatusDescriptionBody
200See above.ListRunsResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "runs": [
    {
      "run": "00000000-0000-4000-8000-000000000000",
      "created_at_ms": 0,
      "requested_by": {
        "profile": "00000000-0000-4000-8000-000000000000",
        "kind": "person"
      },
      "objective": "string",
      "agent": {
        "kind": "built_in",
        "value": "string"
      },
      "requested_model": "string",
      "scope": {
        "kind": "none"
      },
      "context": [
        {
          "workspace": "00000000-0000-4000-8000-000000000000",
          "document": "00000000-0000-4000-8000-000000000000",
          "version": "00000000-0000-4000-8000-000000000000",
          "kind": "document"
        }
      ],
      "grants": [],
      "status": {
        "state": "created"
      },
      "failure_reason": "capability_not_negotiated",
      "environment": {
        "device": "string",
        "kind": "local_device"
      },
      "artifacts": [],
      "economics": {
        "orchestrator_turns": 0,
        "human_turns": 0,
        "turns_with_usage": 0,
        "input": {
          "known": 0,
          "unavailable_turns": 0
        },
        "output": {
          "known": 0,
          "unavailable_turns": 0
        },
        "cached_input": {
          "known": 0,
          "unavailable_turns": 0
        },
        "tool_calls": 0,
        "interventions": 0,
        "elapsed_ms": null,
        "models": [],
        "complete": false
      },
      "rating": {
        "rating": "good",
        "note": "string",
        "rated_by": {
          "profile": "00000000-0000-4000-8000-000000000000",
          "kind": "person"
        },
        "rated_at_ms": 0
      },
      "origin": {
        "origin": "manual"
      }
    }
  ],
  "sessions": {},
  "documents": {},
  "trashed": [
    {
      "header": {
        "run": "00000000-0000-4000-8000-000000000000",
        "created_at_ms": 0,
        "requested_by": {
          "profile": "00000000-0000-4000-8000-000000000000",
          "kind": "person"
        },
        "objective": "string",
        "agent": {
          "kind": "built_in",
          "value": "string"
        },
        "requested_model": "string",
        "scope": {
          "kind": "none"
        },
        "context": [
          {
            "workspace": "00000000-0000-4000-8000-000000000000",
            "document": "00000000-0000-4000-8000-000000000000",
            "version": "00000000-0000-4000-8000-000000000000",
            "kind": "document"
          }
        ],
        "grants": [],
        "status": {
          "state": "created"
        },
        "failure_reason": "capability_not_negotiated",
        "environment": {
          "device": "string",
          "kind": "local_device"
        },
        "artifacts": [],
        "economics": {
          "orchestrator_turns": 0,
          "human_turns": 0,
          "turns_with_usage": 0,
          "input": {
            "known": 0,
            "unavailable_turns": 0
          },
          "output": {
            "known": 0,
            "unavailable_turns": 0
          },
          "cached_input": {
            "known": 0,
            "unavailable_turns": 0
          },
          "tool_calls": 0,
          "interventions": 0,
          "elapsed_ms": null,
          "models": [],
          "complete": false
        },
        "rating": {
          "rating": "good",
          "note": "string",
          "rated_by": {
            "profile": "00000000-0000-4000-8000-000000000000",
            "kind": "person"
          },
          "rated_at_ms": 0
        },
        "origin": {
          "origin": "manual"
        }
      },
      "document": {},
      "trashed_at_ms": 0,
      "artifacts": "keep"
    }
  ]
}
Example request
curl "http://127.0.0.1:$PORT/v1/runs?workspace=$WORKSPACE" \
  -H "Authorization: Bearer $KORU_TOKEN"

Delegate a piece of work to an agent

POST/v1/runs

202 with the run's id, its Run document and its status. The client mints the run id, so a retried request is the same run. The request is durable - intent, captured context and Run document - before this answers; the start follows on the worker.

Authorization
Bearer token with runs.write
Operation id
runs_create

Request body (required)

application/json CreateRunRequest

FieldTypeDescription
runrequiredRunId
workspacerequiredWorkspaceId

The workspace the Run document is registered in.

requested_byrequiredActorRef
objectiverequiredObjective

What a person asked the agent to do (D9). The one field of a run that is a prompt, and therefore the one field that must never be reported.

agentrequiredSessionProfileKey

Stable identity for a launch profile. Built-ins remain readable across machines; user-created profiles are opaque UUIDs.

requested_modelDelegateModelName or null

Explicit model intent. New clients use the v2 create route when present.

scoperequiredWorkspaceScope

The working folder a run is admitted to (P1.5) and started in.

Identity is a [ProjectId] rather than a path: the project already carries a canonical root the host validates at launch, and an id is what a second device can name without being able to resolve it (D15, D16). The folder inside it is text a person chose, and is redacted like every path.

`None` is unreachable at admission. It exists so a request can be built before a scope is chosen and so the modal has a state to refuse; P1.5 makes it impossible to start a run with it. M4 adds git shapes - a worktree per run - as new variants, which is why this is an enum.

contextarray of RunContextItem

Default []

grantsarray of WorkspaceId

The workspaces the run's tools may reach (D28). Empty denies all workspace access.

Default []

Example request body
{
  "run": "00000000-0000-4000-8000-000000000000",
  "workspace": {},
  "requested_by": {
    "profile": "00000000-0000-4000-8000-000000000000",
    "kind": "person"
  },
  "objective": "string",
  "agent": {
    "kind": "built_in",
    "value": "string"
  },
  "requested_model": "string",
  "scope": {
    "kind": "none"
  },
  "context": [],
  "grants": []
}

Responses

StatusDescriptionBody
202See above.CreateRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 202 response
{
  "run": "00000000-0000-4000-8000-000000000000",
  "document": "00000000-0000-4000-8000-000000000000",
  "status": {
    "state": "created"
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/runs" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "run": "00000000-0000-4000-8000-000000000000",
  "workspace": {},
  "requested_by": {
    "profile": "00000000-0000-4000-8000-000000000000",
    "kind": "person"
  },
  "objective": "string",
  "agent": {
    "kind": "built_in",
    "value": "string"
  },
  "requested_model": "string",
  "scope": {
    "kind": "none"
  },
  "context": [],
  "grants": []
}'

Preserve model selection: Delegate a piece of work to an agent

POST/v2/runs

202 with the run's id, its Run document and its status. The client mints the run id, so a retried request is the same run. The request is durable - intent, captured context and Run document - before this answers; the start follows on the worker.

Authorization
Bearer token with runs.write
Operation id
runs_create_v2

Request body (required)

application/json CreateRunRequest

FieldTypeDescription
runrequiredRunId
workspacerequiredWorkspaceId

The workspace the Run document is registered in.

requested_byrequiredActorRef
objectiverequiredObjective

What a person asked the agent to do (D9). The one field of a run that is a prompt, and therefore the one field that must never be reported.

agentrequiredSessionProfileKey

Stable identity for a launch profile. Built-ins remain readable across machines; user-created profiles are opaque UUIDs.

requested_modelDelegateModelName or null

Explicit model intent. New clients use the v2 create route when present.

scoperequiredWorkspaceScope

The working folder a run is admitted to (P1.5) and started in.

Identity is a [ProjectId] rather than a path: the project already carries a canonical root the host validates at launch, and an id is what a second device can name without being able to resolve it (D15, D16). The folder inside it is text a person chose, and is redacted like every path.

`None` is unreachable at admission. It exists so a request can be built before a scope is chosen and so the modal has a state to refuse; P1.5 makes it impossible to start a run with it. M4 adds git shapes - a worktree per run - as new variants, which is why this is an enum.

contextarray of RunContextItem

Default []

grantsarray of WorkspaceId

The workspaces the run's tools may reach (D28). Empty denies all workspace access.

Default []

Example request body
{
  "run": "00000000-0000-4000-8000-000000000000",
  "workspace": {},
  "requested_by": {
    "profile": "00000000-0000-4000-8000-000000000000",
    "kind": "person"
  },
  "objective": "string",
  "agent": {
    "kind": "built_in",
    "value": "string"
  },
  "requested_model": "string",
  "scope": {
    "kind": "none"
  },
  "context": [],
  "grants": []
}

Responses

StatusDescriptionBody
202See above.CreateRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 202 response
{
  "run": "00000000-0000-4000-8000-000000000000",
  "document": "00000000-0000-4000-8000-000000000000",
  "status": {
    "state": "created"
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v2/runs" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "run": "00000000-0000-4000-8000-000000000000",
  "workspace": {},
  "requested_by": {
    "profile": "00000000-0000-4000-8000-000000000000",
    "kind": "person"
  },
  "objective": "string",
  "agent": {
    "kind": "built_in",
    "value": "string"
  },
  "requested_model": "string",
  "scope": {
    "kind": "none"
  },
  "context": [],
  "grants": []
}'

One run, with a window of its history

GET/v1/runs/{run}

The header, what the answering device holds, the current state of every context pin, and a window of the timeline by index, oldest first (from, len up to 500). workspace names the workspace a run this device did not create is registered in - how a second device reads a run that reached it by sync.

Authorization
Bearer token with runs.read
Operation id
runs_run

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)
fromqueryinteger (uint64)

Default 0

lenqueryinteger (uint32, <= 500)

Default 100

workspacequerystring (uuid)

Responses

StatusDescriptionBody
200See above.RunView
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "document": "00000000-0000-4000-8000-000000000000",
  "header": {
    "run": "00000000-0000-4000-8000-000000000000",
    "created_at_ms": 0,
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "context": [
      {
        "workspace": "00000000-0000-4000-8000-000000000000",
        "document": "00000000-0000-4000-8000-000000000000",
        "version": "00000000-0000-4000-8000-000000000000",
        "kind": "document"
      }
    ],
    "grants": [],
    "status": {
      "state": "created"
    },
    "failure_reason": "capability_not_negotiated",
    "environment": {
      "device": "string",
      "kind": "local_device"
    },
    "artifacts": [],
    "economics": {
      "orchestrator_turns": 0,
      "human_turns": 0,
      "turns_with_usage": 0,
      "input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "output": {
        "known": 0,
        "unavailable_turns": 0
      },
      "cached_input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "tool_calls": 0,
      "interventions": 0,
      "elapsed_ms": null,
      "models": [],
      "complete": false
    },
    "rating": {
      "rating": "good",
      "note": "string",
      "rated_by": {
        "profile": "00000000-0000-4000-8000-000000000000",
        "kind": "person"
      },
      "rated_at_ms": 0
    },
    "origin": {
      "origin": "manual"
    }
  },
  "execution": {
    "device": "string",
    "session": "00000000-0000-4000-8000-000000000000",
    "run_workspace": "string"
  },
  "context": [],
  "timeline": {
    "total": 0,
    "from": 0,
    "items": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "kind": {
          "step": "run_created"
        },
        "refs": [],
        "at_ms": 0
      }
    ]
  }
}
Example request
curl "http://127.0.0.1:$PORT/v1/runs/$RUN" \
  -H "Authorization: Bearer $KORU_TOKEN"

End the run

POST/v1/runs/{run}/cancel

The header after the cancellation was asked for. A run mid-turn stays running until the provider answers the cancellation; the stream carries the end. Never a takeover - that is the session's own handover verb (D36).

Authorization
Bearer token with runs.write
Operation id
runs_cancel

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)

Responses

StatusDescriptionBody
200See above.CancelRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "header": {
    "run": "00000000-0000-4000-8000-000000000000",
    "created_at_ms": 0,
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "context": [
      {
        "workspace": "00000000-0000-4000-8000-000000000000",
        "document": "00000000-0000-4000-8000-000000000000",
        "version": "00000000-0000-4000-8000-000000000000",
        "kind": "document"
      }
    ],
    "grants": [],
    "status": {
      "state": "created"
    },
    "failure_reason": "capability_not_negotiated",
    "environment": {
      "device": "string",
      "kind": "local_device"
    },
    "artifacts": [],
    "economics": {
      "orchestrator_turns": 0,
      "human_turns": 0,
      "turns_with_usage": 0,
      "input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "output": {
        "known": 0,
        "unavailable_turns": 0
      },
      "cached_input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "tool_calls": 0,
      "interventions": 0,
      "elapsed_ms": null,
      "models": [],
      "complete": false
    },
    "rating": {
      "rating": "good",
      "note": "string",
      "rated_by": {
        "profile": "00000000-0000-4000-8000-000000000000",
        "kind": "person"
      },
      "rated_at_ms": 0
    },
    "origin": {
      "origin": "manual"
    }
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/runs/$RUN/cancel" \
  -H "Authorization: Bearer $KORU_TOKEN"

Preserve model selection: Continue an interrupted run as a fresh attempt

POST/v2/runs/{run}/resume

The header after the fresh attempt began. Refused with not_interrupted unless the run is interrupted, with attempt_live when the earlier attempt's session is still running, with source_in_trash or source_unavailable when a source the run was given no longer resolves for anything new (D48), and with prior_attempt_unknown when nothing proved the earlier attempt stopped - that one needs {"confirm": true} from a person. The body is optional and every field defaults.

Authorization
Bearer token with runs.write
Operation id
runs_resume_v2

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)

Request body

application/json ResumeRunRequest

FieldTypeDescription
confirmboolean

Default false

Example request body
{
  "confirm": false
}

Responses

StatusDescriptionBody
200See above.ResumeRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "header": {
    "run": "00000000-0000-4000-8000-000000000000",
    "created_at_ms": 0,
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "context": [
      {
        "workspace": "00000000-0000-4000-8000-000000000000",
        "document": "00000000-0000-4000-8000-000000000000",
        "version": "00000000-0000-4000-8000-000000000000",
        "kind": "document"
      }
    ],
    "grants": [],
    "status": {
      "state": "created"
    },
    "failure_reason": "capability_not_negotiated",
    "environment": {
      "device": "string",
      "kind": "local_device"
    },
    "artifacts": [],
    "economics": {
      "orchestrator_turns": 0,
      "human_turns": 0,
      "turns_with_usage": 0,
      "input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "output": {
        "known": 0,
        "unavailable_turns": 0
      },
      "cached_input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "tool_calls": 0,
      "interventions": 0,
      "elapsed_ms": null,
      "models": [],
      "complete": false
    },
    "rating": {
      "rating": "good",
      "note": "string",
      "rated_by": {
        "profile": "00000000-0000-4000-8000-000000000000",
        "kind": "person"
      },
      "rated_at_ms": 0
    },
    "origin": {
      "origin": "manual"
    }
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v2/runs/$RUN/resume" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "confirm": false
}'

Rate a finished run

POST/v1/runs/{run}/rate

The header carrying the rating. One gesture - good or not good - with an optional note that lives in the run's own content and reaches no event and no metric (D44). Refused with wrong_status while the run is still working.

Authorization
Bearer token with runs.write
Operation id
runs_rate

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)

Request body (required)

application/json RateRunRequest

FieldTypeDescription
ratingrequiredRating

One gesture on a finished run (D44): good or not good. An unrated run is a normal state, which is why the header holds an Option<RunRating> and this enum has no "unrated" arm.

noteRatingNote or null
rated_byrequiredActorRef
Example request body
{
  "rating": "good",
  "note": "string",
  "rated_by": {
    "profile": "00000000-0000-4000-8000-000000000000",
    "kind": "person"
  }
}

Responses

StatusDescriptionBody
200See above.RateRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "header": {
    "run": "00000000-0000-4000-8000-000000000000",
    "created_at_ms": 0,
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "context": [
      {
        "workspace": "00000000-0000-4000-8000-000000000000",
        "document": "00000000-0000-4000-8000-000000000000",
        "version": "00000000-0000-4000-8000-000000000000",
        "kind": "document"
      }
    ],
    "grants": [],
    "status": {
      "state": "created"
    },
    "failure_reason": "capability_not_negotiated",
    "environment": {
      "device": "string",
      "kind": "local_device"
    },
    "artifacts": [],
    "economics": {
      "orchestrator_turns": 0,
      "human_turns": 0,
      "turns_with_usage": 0,
      "input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "output": {
        "known": 0,
        "unavailable_turns": 0
      },
      "cached_input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "tool_calls": 0,
      "interventions": 0,
      "elapsed_ms": null,
      "models": [],
      "complete": false
    },
    "rating": {
      "rating": "good",
      "note": "string",
      "rated_by": {
        "profile": "00000000-0000-4000-8000-000000000000",
        "kind": "person"
      },
      "rated_at_ms": 0
    },
    "origin": {
      "origin": "manual"
    }
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/runs/$RUN/rate" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "rating": "good",
  "note": "string",
  "rated_by": {
    "profile": "00000000-0000-4000-8000-000000000000",
    "kind": "person"
  }
}'

Put a run in the trash

POST/v1/runs/{run}/trash

The header and the Run document. This is half of the gesture: a run is a document of the workspace's manifest and putting it in the trash is that document's move into the workspace's bin, which is the caller's to make -- reversible, synced, and exactly what happens to every other document in Koru. What this does is the half only the worker can: refuse a run that is still working with wrong_status (cancel it first -- trashing something still writing into a folder is the one case where the reversible operation is not), and remember what the person said should happen to the run's results when the trash is emptied. Nothing on disk and nothing in the artifact store changes. The body is optional and its one field defaults to keep.

Authorization
Bearer token with runs.write
Operation id
runs_trash

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)

Request body

application/json TrashRunRequest

FieldTypeDescription
artifactsArtifactDisposition

Default "keep"

Example request body
{
  "artifacts": "keep"
}

Responses

StatusDescriptionBody
200See above.TrashRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "header": {
    "run": "00000000-0000-4000-8000-000000000000",
    "created_at_ms": 0,
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "context": [
      {
        "workspace": "00000000-0000-4000-8000-000000000000",
        "document": "00000000-0000-4000-8000-000000000000",
        "version": "00000000-0000-4000-8000-000000000000",
        "kind": "document"
      }
    ],
    "grants": [],
    "status": {
      "state": "created"
    },
    "failure_reason": "capability_not_negotiated",
    "environment": {
      "device": "string",
      "kind": "local_device"
    },
    "artifacts": [],
    "economics": {
      "orchestrator_turns": 0,
      "human_turns": 0,
      "turns_with_usage": 0,
      "input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "output": {
        "known": 0,
        "unavailable_turns": 0
      },
      "cached_input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "tool_calls": 0,
      "interventions": 0,
      "elapsed_ms": null,
      "models": [],
      "complete": false
    },
    "rating": {
      "rating": "good",
      "note": "string",
      "rated_by": {
        "profile": "00000000-0000-4000-8000-000000000000",
        "kind": "person"
      },
      "rated_at_ms": 0
    },
    "origin": {
      "origin": "manual"
    }
  },
  "document": "00000000-0000-4000-8000-000000000000"
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/runs/$RUN/trash" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "artifacts": "keep"
}'

Take a run back out of the trash

POST/v1/runs/{run}/restore

The header and the Run document, which the caller moves back out of the workspace's bin. Nothing was deleted, so the run comes back whole; what this forgets is the decision about its results.

Authorization
Bearer token with runs.write
Operation id
runs_restore

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)

Responses

StatusDescriptionBody
200See above.RestoreRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "header": {
    "run": "00000000-0000-4000-8000-000000000000",
    "created_at_ms": 0,
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "context": [
      {
        "workspace": "00000000-0000-4000-8000-000000000000",
        "document": "00000000-0000-4000-8000-000000000000",
        "version": "00000000-0000-4000-8000-000000000000",
        "kind": "document"
      }
    ],
    "grants": [],
    "status": {
      "state": "created"
    },
    "failure_reason": "capability_not_negotiated",
    "environment": {
      "device": "string",
      "kind": "local_device"
    },
    "artifacts": [],
    "economics": {
      "orchestrator_turns": 0,
      "human_turns": 0,
      "turns_with_usage": 0,
      "input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "output": {
        "known": 0,
        "unavailable_turns": 0
      },
      "cached_input": {
        "known": 0,
        "unavailable_turns": 0
      },
      "tool_calls": 0,
      "interventions": 0,
      "elapsed_ms": null,
      "models": [],
      "complete": false
    },
    "rating": {
      "rating": "good",
      "note": "string",
      "rated_by": {
        "profile": "00000000-0000-4000-8000-000000000000",
        "kind": "person"
      },
      "rated_at_ms": 0
    },
    "origin": {
      "origin": "manual"
    }
  },
  "document": "00000000-0000-4000-8000-000000000000"
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/runs/$RUN/restore" \
  -H "Authorization: Bearer $KORU_TOKEN"

The trash was emptied: delete the run

POST/v1/runs/{run}/purge

Everything this device holds about the run -- its ledger rows, its authority record, and its working folder when Koru made that folder. A run scoped to a project ran inside the person's own repository, and that directory is left exactly alone: folder says kept, removed or absent, because a trash that quietly did less than it offered teaches somebody that it did more. artifacts_retired is how many result families went, which is none unless the person asked for them to go with the run. Refused with run_folder_not_removed when the filesystem would not remove a folder Koru made -- nothing is changed and the run stays in the trash. The Run document is the caller's to remove once this has answered.

Authorization
Bearer token with runs.write
Operation id
runs_purge

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)

Responses

StatusDescriptionBody
200See above.PurgeRunResponse
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example 200 response
{
  "run": "00000000-0000-4000-8000-000000000000",
  "document": "00000000-0000-4000-8000-000000000000",
  "folder": "removed",
  "artifacts_retired": 0
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/runs/$RUN/purge" \
  -H "Authorization: Bearer $KORU_TOKEN"

Follow a run's history and status

GET/v1/runs/{run}/stream

text/event-stream of run_stream_item events: every history entry after after with its index, then live entries as they are written, every status change, and closed when the run ended. workspace names the workspace a run this device did not create is registered in.

Authorization
Bearer token with runs.read
Operation id
runs_stream

Parameters

NameInTypeDescription
runrequiredpathstring (uuid)
afterqueryinteger (uint64)
workspacequerystring (uuid)

Responses

StatusDescriptionBody
200See above.RunStreamItemtext/event-stream
400

The request body, query or path identity is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the operation's run scope

DelegateFailure
404

No run has that id on this device

DelegateFailure
409

The run is not in a status the operation applies to, its earlier attempt is still live, or its prior attempt is unknown and a person has not confirmed the resume

DelegateFailure
413

The request body exceeds the route limit

DelegateFailure
422

A context item could not be captured, or a source the run was given is now in the trash or unavailable (D48)

DelegateFailure
503

The delegate worker is not answering

DelegateFailure
Example request
curl "http://127.0.0.1:$PORT/v1/runs/$RUN/stream" \
  -N \
  -H "Authorization: Bearer $KORU_TOKEN"

Pause a schedule

POST/v1/schedules/pause

200 with the canonical paused schedule projection. A claimed Run is not cancelled.

Authorization
Bearer token with runs.write
Operation id
schedules_pause

Request body (required)

application/json PauseScheduleRequest

FieldTypeDescription
schedulerequiredScheduleId
workspacerequiredWorkspaceId
expected_revisionrequiredinteger (uint32, >= 0)
Example request body
{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_revision": 0
}

Responses

StatusDescriptionBody
200See above.PauseScheduleResponse
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
404

The schedule is missing or belongs to another workspace

DelegateFailure
409

The observed name is stale, or the schedule is retired or read-only

DelegateFailure
413

The schedule request exceeds the body limit

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example 200 response
{
  "schedule": {
    "workspace": "00000000-0000-4000-8000-000000000000",
    "document": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "header": {
      "schedule": "00000000-0000-4000-8000-000000000000",
      "created_at_ms": 0,
      "initial_owner": "string",
      "definition": {
        "revision": 0,
        "effective_at_ms": 0,
        "template": {
          "requested_by": {
            "profile": "00000000-0000-4000-8000-000000000000",
            "kind": "person"
          },
          "objective": "string",
          "agent": {
            "kind": "built_in",
            "value": "string"
          },
          "requested_model": "string",
          "scope": {
            "kind": "none"
          },
          "grants": [],
          "context": []
        },
        "recurrence": {
          "cron": "string",
          "type": "floating"
        },
        "lifecycle": "active"
      }
    },
    "state": {
      "owner": "string",
      "state": "active"
    },
    "next_firing": {
      "at_ms": 0,
      "kind": "exact"
    },
    "firings": [
      {
        "occurrence_ms": 0,
        "revision": 0,
        "outcome": "fired",
        "run": "00000000-0000-4000-8000-000000000000",
        "busy_holder": "00000000-0000-4000-8000-000000000000",
        "at": 0
      }
    ]
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/schedules/pause" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_revision": 0
}'

Resume a schedule

POST/v1/schedules/resume

200 with the canonical active schedule projection. Elapsed paused occurrences are not caught up.

Authorization
Bearer token with runs.write
Operation id
schedules_resume

Request body (required)

application/json ResumeScheduleRequest

FieldTypeDescription
schedulerequiredScheduleId
workspacerequiredWorkspaceId
expected_revisionrequiredinteger (uint32, >= 0)
Example request body
{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_revision": 0
}

Responses

StatusDescriptionBody
200See above.ResumeScheduleResponse
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
404

The schedule is missing or belongs to another workspace

DelegateFailure
409

The observed name is stale, or the schedule is retired or read-only

DelegateFailure
413

The schedule request exceeds the body limit

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example 200 response
{
  "schedule": {
    "workspace": "00000000-0000-4000-8000-000000000000",
    "document": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "header": {
      "schedule": "00000000-0000-4000-8000-000000000000",
      "created_at_ms": 0,
      "initial_owner": "string",
      "definition": {
        "revision": 0,
        "effective_at_ms": 0,
        "template": {
          "requested_by": {
            "profile": "00000000-0000-4000-8000-000000000000",
            "kind": "person"
          },
          "objective": "string",
          "agent": {
            "kind": "built_in",
            "value": "string"
          },
          "requested_model": "string",
          "scope": {
            "kind": "none"
          },
          "grants": [],
          "context": []
        },
        "recurrence": {
          "cron": "string",
          "type": "floating"
        },
        "lifecycle": "active"
      }
    },
    "state": {
      "owner": "string",
      "state": "active"
    },
    "next_firing": {
      "at_ms": 0,
      "kind": "exact"
    },
    "firings": [
      {
        "occurrence_ms": 0,
        "revision": 0,
        "outcome": "fired",
        "run": "00000000-0000-4000-8000-000000000000",
        "busy_holder": "00000000-0000-4000-8000-000000000000",
        "at": 0
      }
    ]
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/schedules/resume" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_revision": 0
}'

Delete a schedule

POST/v1/schedules/retire

200 with the canonical retired schedule projection. Existing Runs and their provenance remain unchanged.

Authorization
Bearer token with runs.write
Operation id
schedules_retire

Request body (required)

application/json RetireScheduleRequest

FieldTypeDescription
schedulerequiredScheduleId
workspacerequiredWorkspaceId
Example request body
{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000"
}

Responses

StatusDescriptionBody
200See above.RetireScheduleResponse
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
404

The schedule is missing or belongs to another workspace

DelegateFailure
409

The observed name is stale, or the schedule is retired or read-only

DelegateFailure
413

The schedule request exceeds the body limit

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example 200 response
{
  "schedule": {
    "workspace": "00000000-0000-4000-8000-000000000000",
    "document": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "header": {
      "schedule": "00000000-0000-4000-8000-000000000000",
      "created_at_ms": 0,
      "initial_owner": "string",
      "definition": {
        "revision": 0,
        "effective_at_ms": 0,
        "template": {
          "requested_by": {
            "profile": "00000000-0000-4000-8000-000000000000",
            "kind": "person"
          },
          "objective": "string",
          "agent": {
            "kind": "built_in",
            "value": "string"
          },
          "requested_model": "string",
          "scope": {
            "kind": "none"
          },
          "grants": [],
          "context": []
        },
        "recurrence": {
          "cron": "string",
          "type": "floating"
        },
        "lifecycle": "active"
      }
    },
    "state": {
      "owner": "string",
      "state": "active"
    },
    "next_firing": {
      "at_ms": 0,
      "kind": "exact"
    },
    "firings": [
      {
        "occurrence_ms": 0,
        "revision": 0,
        "outcome": "fired",
        "run": "00000000-0000-4000-8000-000000000000",
        "busy_holder": "00000000-0000-4000-8000-000000000000",
        "at": 0
      }
    ]
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/schedules/retire" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000"
}'

Edit a schedule

POST/v1/schedules/edit

200 with the canonical schedule projection after one durable revision-checked replacement of its editable definition and name.

Authorization
Bearer token with runs.write
Operation id
schedules_edit

Request body (required)

application/json EditScheduleRequest

FieldTypeDescription
schedulerequiredScheduleId
workspacerequiredWorkspaceId
expected_revisionrequiredinteger (uint32, >= 0)
expected_namerequiredScheduleName

A person-authored schedule label. It is presentation metadata, never schedule identity, and is redacted anywhere a derived Debug can reach.

namerequiredScheduleName

A person-authored schedule label. It is presentation metadata, never schedule identity, and is redacted anywhere a derived Debug can reach.

templaterequiredDelegationTemplate

The reusable request fields. RunId, executing device, and document version pins exist only for one claimed firing and cannot be stored here.

recurrencerequiredRecurrenceRule

A persisted recurrence rule. The variants preserve Koru's existing floating-versus-zoned distinction without an optional timezone.

Example request body
{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_revision": 0,
  "expected_name": "string",
  "name": "string",
  "template": {
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "grants": [],
    "context": []
  },
  "recurrence": {
    "cron": "string",
    "type": "floating"
  }
}

Responses

StatusDescriptionBody
200See above.EditScheduleResponse
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
404

The schedule is missing or belongs to another workspace

DelegateFailure
409

The observed name is stale, or the schedule is retired or read-only

DelegateFailure
413

The schedule request exceeds the body limit

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example 200 response
{
  "schedule": {
    "workspace": "00000000-0000-4000-8000-000000000000",
    "document": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "header": {
      "schedule": "00000000-0000-4000-8000-000000000000",
      "created_at_ms": 0,
      "initial_owner": "string",
      "definition": {
        "revision": 0,
        "effective_at_ms": 0,
        "template": {
          "requested_by": {
            "profile": "00000000-0000-4000-8000-000000000000",
            "kind": "person"
          },
          "objective": "string",
          "agent": {
            "kind": "built_in",
            "value": "string"
          },
          "requested_model": "string",
          "scope": {
            "kind": "none"
          },
          "grants": [],
          "context": []
        },
        "recurrence": {
          "cron": "string",
          "type": "floating"
        },
        "lifecycle": "active"
      }
    },
    "state": {
      "owner": "string",
      "state": "active"
    },
    "next_firing": {
      "at_ms": 0,
      "kind": "exact"
    },
    "firings": [
      {
        "occurrence_ms": 0,
        "revision": 0,
        "outcome": "fired",
        "run": "00000000-0000-4000-8000-000000000000",
        "busy_holder": "00000000-0000-4000-8000-000000000000",
        "at": 0
      }
    ]
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/schedules/edit" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_revision": 0,
  "expected_name": "string",
  "name": "string",
  "template": {
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "grants": [],
    "context": []
  },
  "recurrence": {
    "cron": "string",
    "type": "floating"
  }
}'

The schedules of a workspace

GET/v1/schedules

Canonical definitions, reduced ownership/lifecycle state, truthful next-firing projections, and firing history. A firing carries a RunId only when it actually fired.

Authorization
Bearer token with runs.read
Operation id
schedules_list

Parameters

NameInTypeDescription
workspacerequiredquerystring (uuid)

Responses

StatusDescriptionBody
200See above.ListSchedulesResponse
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example 200 response
{
  "schedules": [
    {
      "workspace": "00000000-0000-4000-8000-000000000000",
      "document": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "header": {
        "schedule": "00000000-0000-4000-8000-000000000000",
        "created_at_ms": 0,
        "initial_owner": "string",
        "definition": {
          "revision": 0,
          "effective_at_ms": 0,
          "template": {
            "requested_by": {
              "profile": "00000000-0000-4000-8000-000000000000",
              "kind": "person"
            },
            "objective": "string",
            "agent": {
              "kind": "built_in",
              "value": "string"
            },
            "requested_model": "string",
            "scope": {
              "kind": "none"
            },
            "grants": [],
            "context": []
          },
          "recurrence": {
            "cron": "string",
            "type": "floating"
          },
          "lifecycle": "active"
        }
      },
      "state": {
        "owner": "string",
        "state": "active"
      },
      "next_firing": {
        "at_ms": 0,
        "kind": "exact"
      },
      "firings": [
        {
          "occurrence_ms": 0,
          "revision": 0,
          "outcome": "fired",
          "run": "00000000-0000-4000-8000-000000000000",
          "busy_holder": "00000000-0000-4000-8000-000000000000",
          "at": 0
        }
      ]
    }
  ],
  "incomplete": false
}
Example request
curl "http://127.0.0.1:$PORT/v1/schedules?workspace=$WORKSPACE" \
  -H "Authorization: Bearer $KORU_TOKEN"

Create repeating delegated work

POST/v1/schedules

201 with the canonical durable Schedule document projection. The client supplies the ScheduleId, workspace, reusable delegation template and recurrence rule; the worker stamps owner, revision, lifecycle and times.

Authorization
Bearer token with runs.write
Operation id
schedules_create

Request body (required)

application/json CreateScheduleRequest

FieldTypeDescription
schedulerequiredScheduleId
workspacerequiredWorkspaceId
namerequiredScheduleName

A person-authored schedule label. It is presentation metadata, never schedule identity, and is redacted anywhere a derived Debug can reach.

templaterequiredDelegationTemplate

The reusable request fields. RunId, executing device, and document version pins exist only for one claimed firing and cannot be stored here.

recurrencerequiredRecurrenceRule

A persisted recurrence rule. The variants preserve Koru's existing floating-versus-zoned distinction without an optional timezone.

Example request body
{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "template": {
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "grants": [],
    "context": []
  },
  "recurrence": {
    "cron": "string",
    "type": "floating"
  }
}

Responses

StatusDescriptionBody
201See above.CreateScheduleResponse
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
409

The schedule identity cannot be used in this workspace

DelegateFailure
413

The schedule request exceeds the body limit

DelegateFailure
422

The schedule definition is invalid

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example 201 response
{
  "schedule": {
    "workspace": "00000000-0000-4000-8000-000000000000",
    "document": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "header": {
      "schedule": "00000000-0000-4000-8000-000000000000",
      "created_at_ms": 0,
      "initial_owner": "string",
      "definition": {
        "revision": 0,
        "effective_at_ms": 0,
        "template": {
          "requested_by": {
            "profile": "00000000-0000-4000-8000-000000000000",
            "kind": "person"
          },
          "objective": "string",
          "agent": {
            "kind": "built_in",
            "value": "string"
          },
          "requested_model": "string",
          "scope": {
            "kind": "none"
          },
          "grants": [],
          "context": []
        },
        "recurrence": {
          "cron": "string",
          "type": "floating"
        },
        "lifecycle": "active"
      }
    },
    "state": {
      "owner": "string",
      "state": "active"
    },
    "next_firing": {
      "at_ms": 0,
      "kind": "exact"
    },
    "firings": [
      {
        "occurrence_ms": 0,
        "revision": 0,
        "outcome": "fired",
        "run": "00000000-0000-4000-8000-000000000000",
        "busy_holder": "00000000-0000-4000-8000-000000000000",
        "at": 0
      }
    ]
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/schedules" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "template": {
    "requested_by": {
      "profile": "00000000-0000-4000-8000-000000000000",
      "kind": "person"
    },
    "objective": "string",
    "agent": {
      "kind": "built_in",
      "value": "string"
    },
    "requested_model": "string",
    "scope": {
      "kind": "none"
    },
    "grants": [],
    "context": []
  },
  "recurrence": {
    "cron": "string",
    "type": "floating"
  }
}'

Rename a schedule

POST/v1/schedules/rename

200 with the canonical schedule projection after its durable owner-authorized name change.

Authorization
Bearer token with runs.write
Operation id
schedules_rename

Request body (required)

application/json RenameScheduleRequest

FieldTypeDescription
schedulerequiredScheduleId
workspacerequiredWorkspaceId
expected_namerequiredScheduleName

A person-authored schedule label. It is presentation metadata, never schedule identity, and is redacted anywhere a derived Debug can reach.

namerequiredScheduleName

A person-authored schedule label. It is presentation metadata, never schedule identity, and is redacted anywhere a derived Debug can reach.

Example request body
{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_name": "string",
  "name": "string"
}

Responses

StatusDescriptionBody
200See above.RenameScheduleResponse
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
404

The schedule is missing or belongs to another workspace

DelegateFailure
409

The observed name is stale, or the schedule is retired or read-only

DelegateFailure
413

The schedule request exceeds the body limit

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example 200 response
{
  "schedule": {
    "workspace": "00000000-0000-4000-8000-000000000000",
    "document": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "header": {
      "schedule": "00000000-0000-4000-8000-000000000000",
      "created_at_ms": 0,
      "initial_owner": "string",
      "definition": {
        "revision": 0,
        "effective_at_ms": 0,
        "template": {
          "requested_by": {
            "profile": "00000000-0000-4000-8000-000000000000",
            "kind": "person"
          },
          "objective": "string",
          "agent": {
            "kind": "built_in",
            "value": "string"
          },
          "requested_model": "string",
          "scope": {
            "kind": "none"
          },
          "grants": [],
          "context": []
        },
        "recurrence": {
          "cron": "string",
          "type": "floating"
        },
        "lifecycle": "active"
      }
    },
    "state": {
      "owner": "string",
      "state": "active"
    },
    "next_firing": {
      "at_ms": 0,
      "kind": "exact"
    },
    "firings": [
      {
        "occurrence_ms": 0,
        "revision": 0,
        "outcome": "fired",
        "run": "00000000-0000-4000-8000-000000000000",
        "busy_holder": "00000000-0000-4000-8000-000000000000",
        "at": 0
      }
    ]
  }
}
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/schedules/rename" \
  -H "Authorization: Bearer $KORU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "schedule": "00000000-0000-4000-8000-000000000000",
  "workspace": "00000000-0000-4000-8000-000000000000",
  "expected_name": "string",
  "name": "string"
}'

Watch a schedule list for changes

GET/v1/schedules/stream

A bounded text/event-stream of content-free schedule generations. Each item means to read the workspace list again; no objective, context, path, document id or schedule id travels in the event.

Authorization
Bearer token with runs.read
Operation id
schedules_stream

Parameters

NameInTypeDescription
workspacerequiredquerystring (uuid)
after_instancequerystring (uuid)
after_generationqueryinteger (uint64)

Responses

StatusDescriptionBody
200See above.ScheduleChangetext/event-stream
400

The request body or workspace query is invalid

DelegateFailure
401

The gateway bearer is absent or invalid

DelegateFailure
403

The bearer lacks the required delegation scope

DelegateFailure
503

The delegate worker or schedule store is not answering

DelegateFailure
Example request
curl "http://127.0.0.1:$PORT/v1/schedules/stream?workspace=$WORKSPACE" \
  -N \
  -H "Authorization: Bearer $KORU_TOKEN"

A delegated run's MCP endpoint (Streamable HTTP, stateless)

POST/v1/runs/{run}/mcp

The endpoint a delegated provider is handed. Authenticated by the run's own bearer (issued through POST /v1/artifacts/authorities), resolved against the durable authority record on every call - never by a gateway session bearer. One JSON-RPC message per POST, answered as application/json; a notification is 202; GET and DELETE are 405. Exactly six tools: create, create_version, get, read, search, attach_to_run. Their definitions, as tools/list returns them, are in x-mcp-tools.

Authorization
A run's endpoint token, any scope
Operation id
runs_mcp

Request body (required)

application/json object

Type object

Example request body
{}

Responses

StatusDescriptionBody
200

The JSON-RPC response

object
202

A notification was accepted; no body

400

The body was not one JSON-RPC message

object
401

The bearer is absent, unknown (authority_unknown), belongs to an earlier attempt (stale_generation), or the run's authority was revoked (authority_revoked)

object
405

GET and DELETE: the endpoint is stateless and never speaks first

503

artifacts.db did not open

Example 200 response
{}

Behavior

MCP tools
[object Object], [object Object], [object Object], [object Object], [object Object], [object Object]
Example request
curl -X POST "http://127.0.0.1:$PORT/v1/runs/$RUN/mcp" \
  -H "Authorization: Bearer $RUN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
Streaming API reference (AsyncAPI) Some operations here answer with a stream. The streaming reference documents the AsyncAPI channels and their messages.

Generated from contract version 1. Last updated .

Privacy choices

Choose which optional tools Koru may use on this site. Your choice is saved in a cookie in this browser for 12 months. Privacy policy

Privacy choices

Keep you signed in, protect forms and remember your language and this choice.

Always on

PostHog and Google Analytics 4 measure page views and actions such as downloads, using cookies or local storage.

PostHog records how pages are used, with form inputs masked and private pages excluded. Needs Analytics.

Ahrefs Web Analytics measures visits and where they come from, and Google Ads measures whether our ads led to a visit or download.