Sessions and runs API
Sessions are the durable execution containers. Runs are individual execution attempts queued or executed inside those sessions. Channels are separate top-level public conversation resources. When a channel decides that one session should speak publicly, the daemon creates a normal run of kindChannelDelivery inside that session. Read Channels API for the public conversation surface.
Projects are also separate top-level daemon resources. Starting a project task still creates a normal run inside the assigned session rather than a separate project-local executor. Read Projects API for that coordination layer.
Endpoint inventory
Sessions:POST /v1/sessionsGET /v1/sessionsGET /v1/sessions/{session_id}GET /v1/sessions/{session_id}/memory-contextGET /v1/sessions/{session_id}/memory-searchGET /v1/sessions/{session_id}/skillsPOST /v1/sessions/{session_id}/personaPUT /v1/sessions/{session_id}/personaDELETE /v1/sessions/{session_id}/personaPOST /v1/sessions/{session_id}/capability-scopePUT /v1/sessions/{session_id}/capability-scopeDELETE /v1/sessions/{session_id}/capability-scopePOST /v1/sessions/{session_id}/credential-scopePUT /v1/sessions/{session_id}/credential-scopeDELETE /v1/sessions/{session_id}/credential-scopeGET /v1/sessions/{session_id}/reply-targetsPOST /v1/sessions/{session_id}/reply-targetsPUT /v1/sessions/{session_id}/reply-targetsDELETE /v1/sessions/{session_id}/reply-targetsPOST /v1/sessions/{session_id}/route-policyPUT /v1/sessions/{session_id}/route-policyDELETE /v1/sessions/{session_id}/route-policyGET /v1/sessions/{session_id}/eventsGET /v1/sessions/{session_id}/streamPOST /v1/sessions/{session_id}/inputPOST /v1/sessions/{session_id}/runsPOST /v1/sessions/{session_id}/interruptPOST /v1/sessions/{session_id}/end
GET /v1/runsGET /v1/runs/{run_id}GET /v1/runs/{run_id}/external-actionsGET /v1/runs/{run_id}/eventsGET /v1/runs/{run_id}/streamPOST /v1/runs/{run_id}/cancelGET /v1/runs/{run_id}/debugGET /v1/runs/{run_id}/debug/artifacts/{artifact_id}
Create or reuse a session
POST /v1/sessions accepts:
session_id: optional caller-selected identifierthread_id: optional provider-side thread idpersona_id: optional persona bound at creation timecapability_scope: optional session capability override persisted on the sessioncredential_scope: optional session credential override persisted on the session
- The handler currently returns
201 Created. - If the requested
session_idalready exists, Kheish reuses that session. - A reuse request is rejected if the supplied
persona_idconflicts with the already bound persona. - A reuse request is also rejected if the supplied
capability_scopeconflicts with the already persisted session scope. - A reuse request is also rejected if the supplied
credential_scopeconflicts with the already persisted session scope.
GET /v1/sessions supports one query parameter:
persona_id: filter by currently bound persona snapshot
Session-scoped defaults
The daemon lets you persist session-local defaults that future runs inherit unless they are overridden per request.Route policy
POST and PUT on /v1/sessions/{session_id}/route-policy both persist the same SessionRoutePolicy shape:
provider: preferred daemon route idgeneration.modelgeneration.fallback_modelgeneration.tool_choicegeneration.allow_parallel_tool_callsgeneration.max_output_tokensgeneration.temperaturegeneration.response_format
- explicit run override on
SubmitInputRequest - persisted session
route_policy - daemon
default_route
- On a named-route daemon, the request
providerfield carries the route id, not necessarily the underlying provider family.
- request
providerselects a configured route id - backend responses and secret records may still use
providerto name the underlying provider family
Session capability scope
POST and PUT on /capability-scope both accept:
skill_allowskill_denymcp_server_allowmcp_server_denymcp_tool_allowmcp_tool_deny
- persona capability baseline, when the session has a bound persona
- restricted by the persisted session capability scope
Session credential scope
POST and PUT on /credential-scope both accept:
route_allowroute_denyconnector_allowconnector_denyconnector_credential_allowconnector_credential_denymcp_server_allowmcp_server_deny
CapabilityScope.
CapabilityScopedecides what the session can see or callCredentialScopedecides which auth-backed routes, connector credentials, and credentialed MCP surfaces can actually resolve
- entries are trimmed, sorted, and deduplicated before persistence
*collapses an allow-list or deny-list to that wildcard alone- if you scope connectors with
connector_alloworconnector_denyand leaveconnector_credential_allowempty, concrete connector credential env keys default to denied
- persona, capability-scope, and credential-scope changes are only allowed while the session is idle for topology mutation
- non-idle credential-scope mutation is returned as
409 Conflict
Inspect effective memory and visible skills
Kheish exposes derived session-inspection endpoints that show what the daemon currently considers eligible for the next run before final prompt packing.Session memory context
GET /v1/sessions/{session_id}/memory-context returns a SessionMemoryContextView.
Important fields:
session_ideffective_capability_scopelearning_scopeslearned_contextrecovered_memoryvisible_skills
- which semantic learnings are currently prompt-eligible
- which recovered run memories are currently eligible for recovery
- which skills are currently visible to the session
learned_context or recovered_memory later when it packs the final prompt for one specific input and model budget.
Current projection rules worth remembering:
procedureandrun_summarylearnings stay out oflearned_context- learnings with
publish_tier=provisionalstay out oflearned_context - learnings with
verification_status=failedstay out oflearned_context - automatically published learnings stay out of
learned_contextuntilverification_status=verified - learnings with
policy_decision=escalatedstay out oflearned_context - promoted procedural skills only appear in
visible_skillsafter their promoted-skill rollout state becomesactive
Session memory search
GET /v1/sessions/{session_id}/memory-search returns a bounded SessionMemorySearchView.
Supported query parameters:
querylimit
- when
queryis omitted, the daemon returns a recent browse view - when
queryis present, the daemon lexically ranks visible learnings, recovered runs, and visible skills - returned result kinds are
learning,recovered_run, andskill - skills only appear in the search results when a query is present
- omitted
limitdefaults to12 - the daemon clamps
limitto a maximum of50
memory-contextshows the current eligible automatic projectionmemory-searchshows the broader daemon-owned memory browse/search surface visible to that session
source_idtitleexcerptscoretimestamp_msscopeprompt_eligiblematched_fields
Session-visible skills
GET /v1/sessions/{session_id}/skills returns the skills currently visible to that session.
Supported query parameter:
query
- effective session capability scope
- promoted-skill source-scope visibility
Session reply targets
Structured session reply-target requests are accepted on:POST /v1/sessions/{session_id}/reply-targetsPUT /v1/sessions/{session_id}/reply-targets
rawtelegramslackhttp
GET /v1/sessions/{session_id}/reply-targets returns a SessionReplyTargetsView envelope:
reply_targets array is normalized ReplyHandle data, not the original structured request shape.
Persona binding
Session persona mutation accepts:POST /v1/sessions/{session_id}/personaPUT /v1/sessions/{session_id}/personaDELETE /v1/sessions/{session_id}/persona
Submit work
Kheish intentionally exposes two session submission modes:POST /v1/sessions/{session_id}/input- executes inline and returns an updated
SessionView
- executes inline and returns an updated
POST /v1/sessions/{session_id}/runs- queues detached work and returns
202 Acceptedwith aRunView
- queues detached work and returns
/input when the client wants the session view after execution. Use /runs when the client wants an explicit run handle for later polling or streaming.
SubmitInputRequest
Request fields:
provider: optional run-scoped route overridesource_pluginsource_kindactor_idcontentinput_itemsattachmentsgenerationcompletion_requirementsmetadatabinding_keysreply_targetsreply_pluginreply_address
input_itemscannot be combined with compatibilitycontentorattachments- when you submit only
input_items, send"content": ""so the request still matches the currentSubmitInputRequestshape content,attachments, orinput_itemsmust provide actual inputbinding_keysare durable session-affinity keys remembered by the daemon- one binding key cannot later be rebound to a different session
reply_pluginandreply_addressare compatibility fields; prefer structuredreply_targets
Content plus attachments example
Ordered multimodal input example
Completion requirements
Current daemon-enforced completion requirements are explicit and opt-in. Supported shape today:Inspect session state
GET /v1/sessions/{session_id} returns a SessionView containing:
session_idagent_idsnapshotroute_policycapability_scopeeffective_capability_scopecredential_scopeeffective_credential_scopepersonareply_targetsoutputs
GET /v1/sessions/{session_id}/events returns SessionEventLogView:
sessiondaemon_outputs
GET /v1/sessions/{session_id}/stream exposes the session SSE stream:
Session interrupt and end
POST /v1/sessions/{session_id}/interrupt returns:
interruptedsnapshot
POST /v1/sessions/{session_id}/end accepts:
Run inspection
GET /v1/runs supports one query parameter:
session_id
RunView includes:
run_idsession_idagent_idkindstatussubmitted_at_msupdated_at_msstarted_at_msfinished_at_msqueued_positionrequestpending_approval_idspending_question_idspending_questionsoutputserror
GET /v1/runs/{run_id} as the source of truth for the route and model actually used by one execution.
Run external actions
GET /v1/runs/{run_id}/external-actions returns the signed external-action audit records attached to that run.
Important fields include:
action_idtimestamp_mssession_idagent_idrun_idtool_call_idprincipal_idparent_principal_idgrant_idphasekindtargetrequest_digestresponse_digestoutcomeprev_hashrecord_hashsignature_algkey_idsignature
Run debug surfaces
GET /v1/runs/{run_id}/debug returns one RunDebugView:
run_idlevelartifacts
GET /v1/runs/{run_id}/debug/artifacts/{artifact_id} returns raw UTF-8 text, not a JSON envelope.
Useful artifact ids usually include request, provider event stream, and normalized response records such as:
turn-0001-attempt-0001-model-requestturn-0001-attempt-0001-provider-requestturn-0001-attempt-0001-provider-eventsturn-0001-attempt-0001-model-response
Run events and cancellation
GET /v1/runs/{run_id}/events returns the persisted RunEventEntry[] list, not the SSE envelope format.
GET /v1/runs/{run_id}/stream exposes the run SSE stream:
POST /v1/runs/{run_id}/cancel returns the updated RunView.