Skip to main content

Runtime API

These endpoints expose or mutate daemon-wide runtime state. They are operational controls, not per-run settings.

Endpoint inventory

Inspection:
  • GET /v1/capabilities
  • GET /v1/runtime
  • GET /v1/runtime/learning-policy
  • GET /v1/runtime/secrets
  • GET /v1/runtime/secrets/{secret_ref}
  • GET /v1/runtime/auth/accounts
  • GET /v1/runtime/auth/accounts/{slot_id}
  • GET /v1/runtime/auth/subjects/{subject_id}
  • GET /v1/runtime/auth/leases/{lease_id}
  • GET /v1/runtime/connectors
  • GET /v1/runtime/connectors/{kind}/{name}
  • GET /v1/runtime/hooks
  • GET /v1/skills
  • GET /v1/skills/{skill_name}
Mutation:
  • POST /v1/runtime/model
  • POST /v1/runtime/learning-policy
  • POST /v1/runtime/secrets
  • POST /v1/runtime/auth/accounts
  • POST /v1/runtime/auth/accounts/mcp-oauth
  • POST /v1/runtime/auth/accounts/{slot_id}/refresh
  • POST /v1/runtime/auth/accounts/{slot_id}/revoke
  • POST /v1/runtime/auth/subjects/{subject_id}/revoke
  • POST /v1/runtime/auth/leases/{lease_id}/revoke
  • DELETE /v1/runtime/auth/accounts/{slot_id}
  • DELETE /v1/runtime/secrets/{secret_ref}
  • POST /v1/runtime/permission-mode
  • POST /v1/runtime/system-prompt
  • POST /v1/runtime/hooks
  • POST /v1/runtime/debug-level
  • PUT /v1/runtime/connectors/{kind}/{name}
  • DELETE /v1/runtime/connectors/{kind}/{name}
Streaming:
  • GET /v1/events/stream

GET /v1/capabilities

This is the coarse daemon feature advertisement. Current fields include:
  • control_plane_version
  • approvals
  • sidechains
  • mailboxes
  • session_events
  • restart_restore
  • live_events
Example:
{
  "control_plane_version": "0.1.0",
  "approvals": true,
  "sidechains": true,
  "mailboxes": true,
  "session_events": true,
  "restart_restore": true,
  "live_events": true
}

GET /v1/runtime

This is the main operator snapshot for a live daemon. Important fields:
  • default_route: the daemon-wide fallback route when no session or run override applies
  • route_id: the active default route identifier
  • provider and model: compatibility fields derived from the active default route
  • routes: the full daemon route inventory
  • learning_policy
  • permission_mode
  • system_prompt
  • hooks
  • debug_level
  • mcp
  • skills
Each route entry exposes its resolved route_id, auth_ref, and coarse capability flags such as multimodal input, native web search, image generation, and image editing. These route flags are intentionally coarse. Audio generation is currently surfaced through control-tool availability rather than one dedicated route capability field.

MCP snapshot

When MCP is enabled, mcp includes:
  • config_path: Codex-compatible MCP config path when one was loaded.
  • selected_profiles: built-in MCP catalog profiles selected through --mcp-profile or KHEISH_MCP_PROFILES.
  • servers: per-server snapshots.
  • tool_names: daemon-global MCP helper and qualified MCP tool names before session/persona filtering.
Each server snapshot can include:
  • server
  • source: codex_config or built_in_catalog
  • profiles: built-in profile names that selected the server when it came from the catalog
  • catalog_entry_id: built-in catalog entry id when applicable
  • transport
  • uses_credentials
  • credential_secret_refs: daemon auth-store refs used by the server, without secret values
  • connected
  • tools
  • error
  • instructions
The runtime snapshot reports daemon inventory. A session or persona can still narrow MCP visibility with capability scope, and child agents can further narrow credential inheritance.

Learning automation policy

GET /v1/runtime/learning-policy returns the daemon-owned LearningAutomationPolicyConfig. POST /v1/runtime/learning-policy replaces the full learning automation policy. Current top-level fields:
  • mode
  • capture
  • publication
  • judge
Current mode values:
  • manual_only
  • shadow
  • enabled
Current defaults:
  • mode defaults to shadow
  • capture.run_summary_candidates defaults to true
  • capture.semantic_candidates.enabled defaults to false
  • capture.semantic_candidates.max_candidates_per_run defaults to 2
  • publication.default_action defaults to manual_review
  • publication.allow_api_origin_active_publication defaults to false
  • judge.enabled defaults to false

Evidence note

  • Code verified: crates/kheish-mcp/src/manager.rs, crates/kheish-daemon/src/state.rs, crates/kheish-daemon/src/api/types.rs, crates/kheish-daemon/src/api/handlers.rs, crates/kheish-auth/src/types.rs, crates/kheish-auth/src/backends/mcp_oauth.rs.
  • CLI verified: runtime get, runtime auth accounts list/get/refresh/revoke, and mcp oauth status/login/refresh/logout.
  • Daemon live tested: yes, using a fresh daemon with --mcp-profile docs and the generic MCP OAuth true-binary protocol harness.
  • Provider-specific tested: no provider-specific model behavior is required for this control-plane snapshot.
Important update rule:
  • POST /v1/runtime/learning-policy replaces the full policy
  • send mode explicitly when mutating policy, because omitting that field is not the same thing as applying the effective runtime default
Current capture fields:
  • run_summary_candidates
  • semantic_candidates
semantic_candidates currently contains:
  • enabled
  • model
  • timeout_ms
  • max_candidates_per_run
Current semantic-capture validation:
  • timeout_ms must be greater than zero when provided
  • max_candidates_per_run must be between 1 and 8
Current publication fields:
  • default_action
  • allow_api_origin_active_publication
  • quarantined_rule_names
  • rules
Current publication rule fields:
  • name
  • scope_kind
  • scope_id
  • kind
  • sensitivity
  • min_confidence
  • require_evidence
  • require_source_run
  • require_source_session
  • action
  • expires_after_ms
Current action values:
  • manual_review
  • reject
  • publish_provisional
  • publish_active
Important validation rules:
  • publication.default_action cannot be publish_active
  • a publish_active rule must declare an explicit kind
  • publish_active is not supported for procedure learnings
  • quarantined_rule_names must be non-empty and unique
Important runtime rule:
  • require_evidence, require_source_run, and require_source_session only count as trusted rule inputs for daemon-owned candidates
  • this trusted-input rule only affects rule matching; API-created candidates can still auto-publish when another rule matches, but automatic active publication is still subject to allow_api_origin_active_publication and daemon-owned verification
Important automatic-active rule:
  • API-origin candidates are downgraded from automatic publish_active to publish_provisional unless allow_api_origin_active_publication=true
  • publish_active still requires daemon-owned verification before prompt visibility
Current judge fields:
  • enabled
  • model
  • timeout_ms
The judge is model-backed and daemon-owned. It runs after deterministic policy evaluation, can only choose actions inside the policy envelope, and fails closed to manual_review in enabled mode when execution fails. Example:
{
  "mode": "enabled",
  "capture": {
    "run_summary_candidates": false,
    "semantic_candidates": {
      "enabled": true,
      "model": {
        "provider": "openai",
        "generation": {
          "model": "gpt-5.4-mini"
        }
      },
      "timeout_ms": 15000,
      "max_candidates_per_run": 2
    }
  },
  "publication": {
    "default_action": "manual_review",
    "allow_api_origin_active_publication": false,
    "quarantined_rule_names": [],
    "rules": [
      {
        "name": "session-fact-autopublish",
        "scope_kind": "session",
        "kind": "fact",
        "sensitivity": "scoped",
        "min_confidence": 95,
        "require_evidence": false,
        "require_source_run": false,
        "require_source_session": false,
        "action": "publish_provisional"
      }
    ]
  },
  "judge": {
    "enabled": true,
    "model": {
      "provider": "anthropic",
      "generation": {
        "model": "claude-sonnet-4-5"
      }
    },
    "timeout_ms": 15000
  }
}

Change the default route

POST /v1/runtime/model changes the daemon default route. It does not rewrite session route policies, queued runs, active runs, or already suspended runs. Request body:
  • provider: optional route identifier such as openai, anthropic, or openrouter
  • model: required backend model string
Example:
{
  "provider": "openrouter",
  "model": "openai/gpt-5.4-mini"
}
Named-route note:
  • On a named-route daemon, provider is the daemon route id.
  • The concrete model stays in model.
Terminology note:
  • request provider selects a configured route id
  • secret-slot provider names the underlying auth/backend family

Secret slots

The runtime secret surface stores daemon-managed auth material. Read endpoints return AuthSlotStatus, not raw secret values. AuthSlotStatus fields:
  • slot_id
  • provider
  • mode
  • summary
  • updated_at_ms
  • details: backend-specific redacted metadata, such as expiry, source, issuer, resource, scopes, or last refresh outcome

POST /v1/runtime/secrets

This endpoint accepts a full AuthSlotRecord:
  • slot_id
  • provider
  • mode
  • state
  • updated_at_ms

Generic opaque secret example

Useful for connector secret references and MCP token slots such as mcp.linear.LINEAR_API_KEY.
{
  "slot_id": "connectors.http.inbox.bearer_token",
  "provider": "generic",
  "mode": "opaque_secret",
  "state": {
    "value": "super-secret-token"
  },
  "updated_at_ms": 1760000000000
}
Runtime secret writes persist only when the daemon was started with KHEISH_AUTH_STORE_MASTER_KEY or KHEISH_AUTH_STORE_MASTER_KEY_FILE. MCP and connector token slots should use provider: "generic" with mode: "opaque_secret" unless you are writing a provider route key such as OpenAI or Anthropic. For MCP, a stored secret is useful only when a loaded built-in catalog entry or explicit MCP config references that mcp.* slot. Built-in catalog slots can be inspected with mcp auth slots <entry-id>, and explicit MCP config can reference slots through bearer_token_secret_ref, http_header_secret_refs, or env_secret_refs. MCP inventory is loaded at daemon startup. After writing or rotating a secret used by an MCP server, restart the daemon so that server reconnects with the new value.

OpenAI API key example

{
  "slot_id": "openai.primary",
  "provider": "open_ai",
  "mode": "api_key",
  "state": {
    "kind": "api_key",
    "api_key": "sk-...",
    "organization": "org_123",
    "project": "proj_123"
  },
  "updated_at_ms": 1760000000000
}
Other provider API-key states are also explicit in the auth backends:
  • Anthropic: {"kind":"api_key","api_key":"..."}
  • Google: {"kind":"api_key","api_key":"..."}
  • OpenRouter: {"kind":"api_key","api_key":"..."}
  • xAI: {"kind":"api_key","api_key":"..."}
For account-backed OAuth records, prefer the CLI import or account flows when possible because the stored state is backend-specific and more verbose than simple API-key records.

OAuth account endpoints

These endpoints expose redacted account status and write-only MCP OAuth import. They never return tokens.
  • GET /v1/runtime/auth/accounts: lists only slots where mode is oauth_account.
  • GET /v1/runtime/auth/accounts/{slot_id}: returns one OAuth account status and rejects non-OAuth slots.
  • POST /v1/runtime/auth/accounts/{slot_id}/refresh: forces one backend refresh and returns redacted status. The endpoint rejects non-OAuth slots.
  • POST /v1/runtime/auth/accounts/{slot_id}/revoke and DELETE /v1/runtime/auth/accounts/{slot_id}: delete the local OAuth account after normal dependency checks.
  • POST /v1/runtime/auth/accounts/mcp-oauth: stores one completed MCP OAuth authorization-code login. This is the endpoint used by kheish-daemon mcp oauth login.
  • POST /v1/runtime/auth/accounts: compatibility alias for the same MCP OAuth import body. Prefer /v1/runtime/auth/accounts/mcp-oauth in new clients.
MCP OAuth import body:
{
  "slot_id": "mcp.oauth.acme",
  "server_name": "acme",
  "resource": "https://mcp.acme.example/mcp",
  "issuer": "https://auth.acme.example",
  "authorization_endpoint": "https://auth.acme.example/oauth/authorize",
  "token_endpoint": "https://auth.acme.example/oauth/token",
  "client_id": "client_123",
  "client_secret": null,
  "access_token": "write-only",
  "refresh_token": "write-only",
  "expires_at_ms": 1760000000000,
  "scopes": ["read", "search"]
}
The API validates MCP OAuth account records before storage:
  • slot ids must use the mcp. namespace
  • resource, issuer, authorization endpoint, and token endpoint must use https, except loopback http test URLs
  • empty core fields are rejected
  • refresh responses cannot add scopes that were not already approved
Deletion:
  • DELETE /v1/runtime/secrets/{secret_ref} returns {"accepted": true} when the slot was removed.
  • Deletion returns 409 Conflict when a runtime connector or loaded MCP server still references that slot.

Brokered runtime auth

Kheish exposes operator-facing inspection for the broker that resolves auth-backed route and connector access at execution time.

Subject endpoints

  • GET /v1/runtime/auth/subjects/{subject_id}
  • POST /v1/runtime/auth/subjects/{subject_id}/revoke
AuthSubjectStatus fields:
  • subject_id
  • current_epoch
  • revoked
  • active_connector_lease_ids
  • active_route_lease_ids
  • active_mcp_lease_ids
Common subject ids are derived from the execution principal, typically:
  • session:{session_id}
  • agent:{agent_id}
  • connector:{connector_name}
  • daemon
Revoking a subject immediately prevents future auth resolution for that subject and revokes its still-active leases.

Lease endpoints

  • GET /v1/runtime/auth/leases/{lease_id}
  • POST /v1/runtime/auth/leases/{lease_id}/revoke
CredentialLeaseStatus fields:
  • lease
  • revoked
  • active
The nested lease payload includes:
  • id
  • grant_id
  • subject_id
  • subject_epoch
  • audience
  • issued_at_ms
  • expires_at_ms
Current lease audiences are:
  • {"type":"route","route_id":"openai","slot_id":"openai.prod"}
  • {"type":"connector","connector":"slack-prod","env_keys":["BOT_TOKEN"]}
  • {"type":"mcp_server","server":"acme","slot_id":"mcp.oauth.acme","scopes_hash":"..."}
These endpoints are useful when you need to confirm whether one run or sidecar is still operating on a live delegated lease before rotating credentials or revoking delegated access. Matching CLI commands:
./target/debug/kheish-daemon runtime auth subject session:demo
./target/debug/kheish-daemon runtime auth revoke-subject session:demo
./target/debug/kheish-daemon runtime auth lease route-lease-abc123
./target/debug/kheish-daemon runtime auth revoke-lease route-lease-abc123

Permission mode

POST /v1/runtime/permission-mode replaces the daemon-wide permission mode. Request body:
{
  "mode": "acceptEdits"
}
Supported values:
  • default
  • acceptEdits
  • bypassPermissions
  • plan
  • dontAsk

System prompt settings

POST /v1/runtime/system-prompt replaces the current SystemPromptSettings. Fields:
  • override_prompt
  • custom_prompt
  • append_prompt
  • language
  • output_style
Example:
{
  "settings": {
    "append_prompt": "When a tool can perform the next step directly, use it instead of narrating intent.",
    "language": "English",
    "output_style": "Concise, operator-facing responses."
  }
}

Hooks

GET /v1/runtime/hooks returns the current HookSettings. POST /v1/runtime/hooks replaces the full hook map. Minimal example:
{
  "hooks": {
    "session_start": [
      {
        "name": "announce-start",
        "executor": {
          "type": "command",
          "command": "echo session-started",
          "timeout_ms": 1000
        }
      }
    ]
  }
}
For the full hook schema, event names, and executor variants, read Hook reference.

Debug capture

POST /v1/runtime/debug-level replaces the daemon-wide debug capture level. Example:
{
  "level": "redacted"
}
Supported values:
  • off
  • on
  • redacted
  • full
full is daemon-global and should only be enabled on isolated instances.

Runtime connectors

Detailed connector payloads and ingress behavior are documented in Connectors API. The important runtime behavior is:
  • GET /v1/runtime/connectors returns the full connector inventory
  • GET /v1/runtime/connectors/{kind}/{name} returns one projected connector view
  • PUT /v1/runtime/connectors/{kind}/{name} creates or updates one daemon-managed connector
  • DELETE /v1/runtime/connectors/{kind}/{name} removes one daemon-managed connector after dependency checks
Supported kinds:
  • telegram
  • slack
  • http
Important upsert rule:
  • The connector PUT surface behaves like a field-aware upsert.
  • Fields present in the JSON payload are applied.
  • Fields omitted from the payload keep their current stored value.
This matters because PUT here is not a blind full-record replacement.

Daemon-wide event stream

GET /v1/events/stream exposes the daemon-wide SSE stream used by control-plane observers.
curl -N http://127.0.0.1:4000/v1/events/stream
The current SSE event names emitted by the daemon bus include:
  • trace
  • session_state_changed
  • session_snapshot
  • output
  • run_updated
  • interrupted
  • runtime_updated
Read Connectors API, Skills API, and Hook reference for the linked subsystems surfaced by GET /v1/runtime.