api_version, capabilities, channel, started_at
API reference sections
HTTP API reference
Store and system
The Store's status, its own contracts, backup, import, settings, shutdown, and the sync WebSocket.
13 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.
GET/v1/status
- Authorization
- Bearer token, any scope
Responses
| Status | Description | Body |
|---|---|---|
| 200 | See above. | GatewayStatus |
| 401 | no bearer token, or one that is not recognised | Failure |
| 403 | the credential does not hold the required scope | Failure |
{
"api_version": 0,
"capabilities": [
"string"
],
"channel": "string",
"started_at": 0,
"gateway": "starting",
"store": "starting",
"ai": "starting"
}curl "http://127.0.0.1:$PORT/v1/status" \
-H "Authorization: Bearer $KORU_TOKEN"GET/v1/openapi.json
an OpenAPI 3.1 document
- Authorization
- None: a public discovery page.
Responses
curl "http://127.0.0.1:$PORT/v1/openapi.json"POST/v1/shutdown
stopping: whether it is going down
- Authorization
- Bearer token with
manage_workspaces
Responses
{
"stopping": false
}curl -X POST "http://127.0.0.1:$PORT/v1/shutdown" \
-H "Authorization: Bearer $KORU_TOKEN"POST/v1/backup
the destination after the backup is complete
- Authorization
- Bearer token with
manage_workspaces
Request body (required)
application/json StoreBackup
| Field | Type | Description |
|---|---|---|
| destinationrequired | string |
{
"destination": "string"
}Responses
| Status | Description | Body |
|---|---|---|
| 200 | See above. | StoreBackupResult |
| 401 | no bearer token, or one that is not recognised | Failure |
| 403 | the credential does not hold the required scope | Failure |
{
"destination": "string"
}curl -X POST "http://127.0.0.1:$PORT/v1/backup" \
-H "Authorization: Bearer $KORU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"destination": "string"
}'GET/v1/sync
a WebSocket; the token travels on the upgrade, never in the protocol
- Authorization
- Bearer token with
read_documents
Responses
curl "http://127.0.0.1:$PORT/v1/sync" \
-H "Authorization: Bearer $KORU_TOKEN"POST/v1/import
the workspace. The complete bundle is buffered in memory, with no HTTP size ceiling beyond the bundle format itself. There is no default mode, deliberately: restore keeps the ids so the result can converge with its origin, duplicate mints new ones so it never will, and guessing wrong is quiet either way
- Authorization
- Bearer token with
manage_workspaces
Responses
{
"id": "00000000-0000-4000-8000-000000000000",
"owner": {},
"name": "string",
"created_at": 0,
"last_opened_at": 0,
"icon": "string",
"color": "string",
"pinned": false,
"archived": false,
"deleted_at": 0,
"position": 0
}curl -X POST "http://127.0.0.1:$PORT/v1/import" \
-H "Authorization: Bearer $KORU_TOKEN"GET/v1/store/status
api_version, capabilities, channel, started_at
- Authorization
- Bearer token, any scope
- Operation id
- store_status
Responses
{
"api_version": 0,
"capabilities": [
"string"
],
"channel": "string",
"started_at": 0
}curl "http://127.0.0.1:$PORT/v1/store/status" \
-H "Authorization: Bearer $KORU_TOKEN"POST/v1/store/search
a page of hits, and optionally the workspace list and recent queries. A POST because the query travels in the body: a URL is written to the access log, and a search is not something to leave in a file that rotates for a week. updating_workspaces names any workspace the answer may be behind on rather than waiting for it
- Authorization
- Bearer token with
read_documents - Operation id
- store_search
Request body (required)
application/json SearchRequest
| Field | Type | Description |
|---|---|---|
| textrequired | string | |
| entity_picker | boolean | Restrict results to document/file titles and live task nodes for an @ picker. This is a query shape over the existing projection, not a stored index. Default |
| workspaces | array of WorkspaceId | Empty means every workspace the index knows. The caller resolves a profile to this; the index has never heard of one. Default |
| excluded_workspaces | array of WorkspaceId | Default |
| kinds | array of string |
Default |
| tags | array of string | Tag names, not A surface may fill this directly; a person fills it by typing Default |
| attributes | array of AttrFilter | Typed attribute filters. A hit's node must satisfy every one. One general filter rather than a field per attribute, because a workspace defines its own attributes and declares their types: a wire naming Default |
| sort | SearchSort | Default |
| lifecycle | LifecycleFilter2 | Default |
| page_size | integer (uint, >= 0) | Clamped by the store; see [ Default |
| offset | integer (uint, >= 0) | Default |
| request_seq | integer (uint64, >= 0) | Copied to the response, so a surface typing quickly can drop an answer to a keystroke it has already moved past. Default |
| include_facets | boolean | Also return the workspaces the index knows, for a scope picker. Default |
| recent_queries | integer (uint, >= 0) or null | Also return this many recent queries. Absent means none. Default |
{
"text": "string",
"entity_picker": false,
"workspaces": [],
"excluded_workspaces": [],
"kinds": [],
"tags": [],
"attributes": [],
"sort": "relevance",
"lifecycle": "live",
"page_size": 50,
"offset": 0,
"request_seq": 0,
"include_facets": false,
"recent_queries": 0
}Responses
| Status | Description | Body |
|---|---|---|
| 200 | See above. | SearchResponse |
| 401 | no bearer token, or one that is not recognised | Failure |
| 403 | the credential does not hold the required scope | Failure |
{
"page": {
"hits": [
{
"workspace": "string",
"workspace_name": "string",
"document": "string",
"node": "string",
"document_kind": "",
"mime": "string",
"kind": "string",
"field": "string",
"title": "string",
"breadcrumb": "string",
"breadcrumb_spans": [
{
"start": 0,
"end": 0
}
],
"snippet": "string",
"spans": [
{
"start": 0,
"end": 0
}
],
"lifecycle": "live",
"trashed_at": 0,
"trashed_by": "string",
"score": 0,
"observed_modified_at_ms": 0,
"workspace_last_used_at_ms": 0
}
],
"next_offset": 0,
"updating_workspaces": [
"string"
],
"request_seq": 0,
"corrected_query": "string"
},
"facets": {
"workspaces": [
{
"workspace": "string",
"workspace_name": "string"
}
]
},
"recent_queries": [
{
"text": "string",
"used_at_ms": 0
}
]
}curl -X POST "http://127.0.0.1:$PORT/v1/store/search" \
-H "Authorization: Bearer $KORU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text": "string",
"entity_picker": false,
"workspaces": [],
"excluded_workspaces": [],
"kinds": [],
"tags": [],
"attributes": [],
"sort": "relevance",
"lifecycle": "live",
"page_size": 50,
"offset": 0,
"request_seq": 0,
"include_facets": false,
"recent_queries": 0
}'GET/v1/settings/{section}
The typed section: global, ai, or terminal. Secrets are never returned.
- Authorization
- Bearer token with
settings.read - Operation id
- settings_read_section
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| sectionrequired | path | "global" | "ai" | "terminal" |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | See above. | GlobalSettings or AiSettings or TerminalSettings |
| 400 | The patch names a field that is not a setting, or a value the registry refuses | |
| 401 | The gateway bearer is absent or invalid | |
| 403 | The session does not hold the scope this operation needs | |
| 404 | There is no such settings section | |
| 409 | A required system side effect refused, so nothing was written | |
| 500 | The write did not land; the body carries the authoritative section | |
| 503 | The settings authority or the AI worker is unavailable |
{
"theme": "system",
"icon_pack": "phosphor",
"caret_color": "default",
"caret_width": "thin",
"caret_height": "short",
"ui_font": "follow_default",
"body_font": "follow_default",
"headings_font": "follow_default",
"code_font": "follow_default",
"chat_font": "follow_default",
"document_text_size": "follow_default",
"base_color_light": "string",
"base_color_dark": "string",
"accent_color_light": "string",
"accent_color_dark": "string",
"density": "normal",
"scroll_speed": "2x",
"zoom": 0,
"default_view_mode": "page",
"default_canvas_background": "auto",
"pinned_show_title": false,
"tabs_per_workspace": false,
"popout_close": "ask",
"emoji_skin_tone": "string",
"dictation_gesture": "push_to_talk",
"dictation_language": "automatic",
"dictation_tier": "compact",
"dictation_input": "system_default",
"spellcheck_enabled": false,
"spellcheck_language": "automatic",
"favorite_models": [],
"close_behavior": "ask",
"global_shortcut": "string",
"global_dictation_enabled": false,
"global_dictation_shortcut": {},
"start_on_login": false,
"reminder_start_on_login_explained": false,
"automatic_update_checks": false,
"delegate_temporary_root": "string",
"recording": {
"preset": "",
"custom_width": 0,
"custom_height": 0,
"frame_rate": 0,
"cursor": false,
"folder": "string"
},
"disabled_agents": [],
"default_permission": "manual",
"default_permission_other": "manual",
"default_agent": "string",
"agent_order": []
}curl "http://127.0.0.1:$PORT/v1/settings/$SECTION" \
-H "Authorization: Bearer $KORU_TOKEN"PATCH/v1/settings/{section}
The section as it stands after the change, read back from the authority.
- Authorization
- Bearer token with
settings.write - Operation id
- settings_patch_section
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| sectionrequired | path | "global" | "ai" | "terminal" |
Request body (required)
application/json GlobalPatch or AiPatch or TerminalPatch
One of 3 shapes:
GlobalPatch
One patch of [
GlobalSettings]. Absent fields are left alone.Field Type Description theme ThemeChoice or null icon_pack IconPackChoice or null caret_color CaretColorChoice or null caret_width CaretWidthChoice or null caret_height CaretHeightChoice or null ui_font FontSetting or null body_font FontSetting or null headings_font FontSetting or null code_font FontSetting or null chat_font FontSetting or null follow_defaultputs the chat back on the app font.document_text_size DocTextSizeSetting or null base_color_light Nullable_RgbColor #rrggbbsets the light theme's base color;nullputs the theme's own back. Settings offers that as its first swatch, so unlike the text size this choice can be taken back - which is why this is a [Field] and not anOption.base_color_dark Nullable_RgbColor The same for the dark theme.
accent_color_light Nullable_RgbColor #rrggbbsets the light theme's accent;nullputs the theme's own back, which Settings offers as the row's first swatch.accent_color_dark Nullable_RgbColor The same for the dark theme.
density DensityChoice or null scroll_speed ScrollSpeedChoice or null zoom number (float) or null default_view_mode ViewModeChoice or null default_canvas_background CanvasBackground or null pinned_show_title boolean or null tabs_per_workspace boolean or null popout_close PopoutCloseChoice or null emoji_skin_tone string or null dictation_gesture DictationGesture or null dictation_language LanguageChoice or null dictation_tier DictationTier or null dictation_input DictationInput or null spellcheck_enabled boolean or null spellcheck_language LanguageChoice or null favorite_models array of FavoriteModel or null The whole favorites list, written whole on every star: an empty list clears them. Absent leaves the stored list alone.
close_behavior CloseBehaviorChoice or null global_shortcut GlobalShortcut or null global_dictation_enabled boolean or null global_dictation_shortcut DictationShortcut or null start_on_login boolean or null reminder_start_on_login_explained boolean or null automatic_update_checks boolean or null delegate_temporary_root Nullable_string nullputs it back to the platform's temporary directory, which is why this is a [Field] and not anOption: absent, null and a path are three different instructions and only two of them fit in anOption.recording RecordingPrefs or null The recorder's prefill, written whole on every Record. Absent leaves the stored set alone.
disabled_agents array of string or null The whole off list, written whole on every switch: an empty list is Restore defaults. Absent leaves the stored list alone.
default_permission AgentPermission or null The permission a new chat with a supported agent starts in.
default_permission_other AgentPermission or null The permission a new chat with any other agent starts in: Manual or Yolo - an agent with no auto mode has no Auto to start in.
default_agent Nullable_string The agent a new chat starts with;
nullis Auto.agent_order array of string or null The whole order, written whole on every move: an empty list is the built-in order. Absent leaves the stored order alone.
AiPatch
One patch of [
AiSettings].The nullable fields use [
Field] so that clearing a model is expressible:"openai_model": nullclears it, and omitting the key leaves it alone.Field Type Description selected_provider Nullable_AiProvider openai_model Nullable_string openai_reasoning ReasoningChoice or null ollama_endpoint string or null ollama_model Nullable_string ollama_reasoning ReasoningChoice or null TerminalPatch
One patch of [
TerminalSettings].Field Type Description theme ThemeChoice or null font FontSetting or null zoom number (float) or null cursor_color CaretColorChoice or null cursor_width TerminalCursorWidth or null cursor_height TerminalCursorHeight or null cursor_blink TerminalCursorBlink or null composer_default boolean or null
{
"theme": "system",
"icon_pack": "phosphor",
"caret_color": "default",
"caret_width": "thin",
"caret_height": "short",
"ui_font": "follow_default",
"body_font": "follow_default",
"headings_font": "follow_default",
"code_font": "follow_default",
"chat_font": "follow_default",
"document_text_size": "follow_default",
"base_color_light": {},
"base_color_dark": {},
"accent_color_light": {},
"accent_color_dark": {},
"density": "normal",
"scroll_speed": "1x",
"zoom": 0,
"default_view_mode": "page",
"default_canvas_background": "auto",
"pinned_show_title": false,
"tabs_per_workspace": false,
"popout_close": "ask",
"emoji_skin_tone": "string",
"dictation_gesture": "push_to_talk",
"dictation_language": "automatic",
"dictation_tier": "compact",
"dictation_input": "system_default",
"spellcheck_enabled": false,
"spellcheck_language": "automatic",
"favorite_models": [
{
"agent": "string",
"model": "string"
}
],
"close_behavior": "ask",
"global_shortcut": "string",
"global_dictation_enabled": false,
"global_dictation_shortcut": "string",
"start_on_login": false,
"reminder_start_on_login_explained": false,
"automatic_update_checks": false,
"delegate_temporary_root": {},
"recording": {
"preset": "",
"custom_width": 0,
"custom_height": 0,
"frame_rate": 0,
"cursor": false,
"folder": "string"
},
"disabled_agents": [
"string"
],
"default_permission": "manual",
"default_permission_other": "manual",
"default_agent": {},
"agent_order": [
"string"
]
}Responses
| Status | Description | Body |
|---|---|---|
| 200 | See above. | GlobalSettings or AiSettings or TerminalSettings |
| 400 | The patch names a field that is not a setting, or a value the registry refuses | |
| 401 | The gateway bearer is absent or invalid | |
| 403 | The session does not hold the scope this operation needs | |
| 404 | There is no such settings section | |
| 409 | A required system side effect refused, so nothing was written | |
| 500 | The write did not land; the body carries the authoritative section | |
| 503 | The settings authority or the AI worker is unavailable |
{
"theme": "system",
"icon_pack": "phosphor",
"caret_color": "default",
"caret_width": "thin",
"caret_height": "short",
"ui_font": "follow_default",
"body_font": "follow_default",
"headings_font": "follow_default",
"code_font": "follow_default",
"chat_font": "follow_default",
"document_text_size": "follow_default",
"base_color_light": "string",
"base_color_dark": "string",
"accent_color_light": "string",
"accent_color_dark": "string",
"density": "normal",
"scroll_speed": "2x",
"zoom": 0,
"default_view_mode": "page",
"default_canvas_background": "auto",
"pinned_show_title": false,
"tabs_per_workspace": false,
"popout_close": "ask",
"emoji_skin_tone": "string",
"dictation_gesture": "push_to_talk",
"dictation_language": "automatic",
"dictation_tier": "compact",
"dictation_input": "system_default",
"spellcheck_enabled": false,
"spellcheck_language": "automatic",
"favorite_models": [],
"close_behavior": "ask",
"global_shortcut": "string",
"global_dictation_enabled": false,
"global_dictation_shortcut": {},
"start_on_login": false,
"reminder_start_on_login_explained": false,
"automatic_update_checks": false,
"delegate_temporary_root": "string",
"recording": {
"preset": "",
"custom_width": 0,
"custom_height": 0,
"frame_rate": 0,
"cursor": false,
"folder": "string"
},
"disabled_agents": [],
"default_permission": "manual",
"default_permission_other": "manual",
"default_agent": "string",
"agent_order": []
}curl -X PATCH "http://127.0.0.1:$PORT/v1/settings/$SECTION" \
-H "Authorization: Bearer $KORU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"theme": "system",
"icon_pack": "phosphor",
"caret_color": "default",
"caret_width": "thin",
"caret_height": "short",
"ui_font": "follow_default",
"body_font": "follow_default",
"headings_font": "follow_default",
"code_font": "follow_default",
"chat_font": "follow_default",
"document_text_size": "follow_default",
"base_color_light": {},
"base_color_dark": {},
"accent_color_light": {},
"accent_color_dark": {},
"density": "normal",
"scroll_speed": "1x",
"zoom": 0,
"default_view_mode": "page",
"default_canvas_background": "auto",
"pinned_show_title": false,
"tabs_per_workspace": false,
"popout_close": "ask",
"emoji_skin_tone": "string",
"dictation_gesture": "push_to_talk",
"dictation_language": "automatic",
"dictation_tier": "compact",
"dictation_input": "system_default",
"spellcheck_enabled": false,
"spellcheck_language": "automatic",
"favorite_models": [
{
"agent": "string",
"model": "string"
}
],
"close_behavior": "ask",
"global_shortcut": "string",
"global_dictation_enabled": false,
"global_dictation_shortcut": "string",
"start_on_login": false,
"reminder_start_on_login_explained": false,
"automatic_update_checks": false,
"delegate_temporary_root": {},
"recording": {
"preset": "",
"custom_width": 0,
"custom_height": 0,
"frame_rate": 0,
"cursor": false,
"folder": "string"
},
"disabled_agents": [
"string"
],
"default_permission": "manual",
"default_permission_other": "manual",
"default_agent": {},
"agent_order": [
"string"
]
}'GET/docs
- Authorization
- None: a public discovery page.
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Offline HTTP API documentation |
curl "http://127.0.0.1:$PORT/docs"GET/docs/asyncapi
- Authorization
- None: a public discovery page.
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Offline streaming API documentation |
curl "http://127.0.0.1:$PORT/docs/asyncapi"GET/v1/asyncapi.json
- Authorization
- None: a public discovery page.
Responses
| Status | Description | Body |
|---|---|---|
| 200 | The generated public AsyncAPI contract |
curl "http://127.0.0.1:$PORT/v1/asyncapi.json"Generated from contract version 1. Last updated .
