Playbooks and flows API
Playbooks and Flows are control-plane resources. They coordinate normal Kheish runs rather than replacing them.Endpoint inventory
Playbooks:GET /v1/playbooksPOST /v1/playbooksPOST /v1/playbooks/validateGET /v1/playbooks/{playbook_id}POST /v1/playbooks/{playbook_id}/publishPOST /v1/playbooks/{playbook_id}/revoke
GET /v1/flowsPOST /v1/flowsGET /v1/flows/{flow_id}POST /v1/flows/{flow_id}/cancelPOST /v1/flows/{flow_id}/evidencePOST /v1/flows/{flow_id}/verify/product-viewGET /v1/flows/{flow_id}/stream
Playbook manifest
POST /v1/playbooks/validate and POST /v1/playbooks both accept:
playbook_id + version + digest is idempotent. Creating the same playbook_id + version with a different digest is rejected.
Manifest fields such as tools, runtime_defaults, scopes, and required_evidence are stored and digest-covered. Flow start still executes a normal SubmitInputRequest; enforcement is expressed through start-time scope checks and Flow contract projection rather than a separate workflow runtime.
When tools.enforce is true, Flow views evaluate scoped session journals against the manifest allow/deny lists. A completed run that used a blocked or non-allowed tool is projected as fail-closed instead of succeeded.
scopes.required_capability_scope and scopes.required_credential_scope use the daemon CapabilityScope and CredentialScope shapes. Flow start rejects sessions whose current scope is wider than these requirements. This keeps scope enforcement on the existing session capability/credential machinery rather than introducing a second runtime.
required_evidence can be declared at the manifest top level and per phase. Missing required evidence prevents a completed Flow from reporting success. Known primitive refs such as run, task, agent, approval, question, schedule, output, and flow must resolve inside the Flow projection; other evidence kinds are treated as operator attestations and can be appended later.
Publish and revoke
POST /v1/playbooks/{playbook_id}/publish accepts:
verified, canary, and active. Publishing to one of those statuses requires evidence_refs.
POST /v1/playbooks/{playbook_id}/revoke accepts:
Start a Flow
POST /v1/flows accepts:
request field is the normal SubmitInputRequest shape used by session run creation. The daemon validates and normalizes that request through the existing session-run path.
Flow start writes daemon-owned kheish_flow metadata into the underlying run. Callers must not provide that metadata key themselves. The metadata includes the Flow id, Playbook id, version, digest, and a daemon-generated nonce used for recovery matching.
Retries are idempotent only when the submitted flow_id, idempotency_key, Playbook reference, session id, input request, Flow metadata, and evidence refs match the existing Flow.
Flow status
Flow status is derived from scoped daemon primitives, not from a persistedflow.status field. The scope starts with the root run and includes sidechain agents spawned from that run, runs in those child sessions, scoped session tasks, and approval/question ids from current run state and historical run events.
FlowView.status uses Flow statuses such as succeeded; the embedded run, when present, is a normal RunView with normal run statuses such as completed. Any interrupted scoped run projects the Flow to interrupted.
- no run reference yet ->
pending - cancelled before run scheduling ->
cancelled - failed scoped run or failed scoped task ->
failed - cancelled scoped run or cancelled scoped task ->
cancelled - waiting scoped run or blocked scoped task ->
waiting - queued/running scoped run or pending/in-progress scoped task ->
running - completed scoped work with no failed/cancelled/running/waiting work ->
succeeded - interrupted scoped run ->
interrupted - missing referenced run ->
unknown
phase_states: one derived entry per manifest phase withpending,satisfied, orblocked.contract: generic validation checks for required evidence and enforced tool policy.completed_at_ms: the first terminal projection boundary. Later reused child-session activity is ignored so an old Flow cannot regress after it has settled.
Append Flow evidence
POST /v1/flows/{flow_id}/evidence accepts:
kind + id. Known daemon primitive kinds must resolve inside the Flow projection. The response is the updated FlowView, so operators can immediately see whether required evidence gates now pass.
GET /v1/flows/{flow_id}/stream is a thin proxy over the referenced run stream. It does not create a second Flow event bus.
Evidence Used
- DTOs and status mapping:
crates/kheish-daemon/src/playbooks.rs - API routes:
crates/kheish-daemon/src/api/handlers.rs - Run scheduling path:
crates/kheish-daemon/src/state/playbook_workflow.rs
Evidence Note
- Code verified:
crates/kheish-daemon/src/playbooks.rs,crates/kheish-daemon/src/state/playbook_workflow.rs,crates/kheish-daemon/src/api/handlers.rs,crates/kheish-daemon/src/cli/commands/playbooks.rs. - CLI/API verified: endpoint inventory and command names checked against implemented routes and CLI commands.
- Daemon live tested for this note: yes; an isolated daemon with OpenAI
gpt-5.4started a Flow, completed a real provider run, failed closed while required manual evidence was missing, then recovered tosucceededafterflows evidence. - Provider-specific tested for this note: OpenAI
gpt-5.4smoke for Flow start, run completion, evidence gate, and evidence append.
