Skip to main content

Learnings API

Kheish exposes the daemon-owned learning plane through three related HTTP surfaces:
  • learning candidates
  • published learnings
  • promoted procedural skills
The CLI mirrors this under kheish-daemon learnings ....

Resource model

The normal flow is:
  1. create or capture a learning candidate
  2. review it manually or through daemon automation
  3. publish it into a durable learning record, or reject it
  4. later revoke or supersede the learning
  5. optionally promote one reviewed procedure learning into a daemon-owned skill

Scope rules

Every candidate and learning belongs to one scope:
  • session
  • persona
  • project
  • workspace
For workspace, the stable scope id is always default. If you pass scope_kind=workspace without scope_id, the HTTP API normalizes that to default. For query filters:
  • scope_id without scope_kind is rejected
  • scope_kind without scope_id is rejected for session, persona, and project
  • only workspace may omit scope_id

Learning candidates

Endpoints

  • GET /v1/learning-candidates
  • POST /v1/learning-candidates
  • GET /v1/learning-candidates/{candidate_id}
  • POST /v1/learning-candidates/{candidate_id}/publish
  • POST /v1/learning-candidates/{candidate_id}/reject

List filters

GET /v1/learning-candidates supports:
  • query
  • scope_kind
  • scope_id
  • kind
  • state

Create payload

POST /v1/learning-candidates accepts:
  • scope
  • kind
  • sensitivity
  • content
  • confidence
  • source
  • evidence_refs
  • expires_at_ms
Current validation notes:
  • content is required
  • content is capped at 1600 characters
  • confidence must stay in 0..=100
  • sensitivity defaults to scoped
  • confidence defaults to 80
  • source defaults to an empty source object
  • public attempts to create run_summary candidates are rejected because run_summary capture is daemon-owned
Example:
{
  "scope": {
    "kind": "workspace",
    "id": "default"
  },
  "kind": "procedure",
  "sensitivity": "scoped",
  "content": "Use the verification child profile when checking scheduler regressions.",
  "confidence": 92,
  "source": {
    "session_id": "ops-review"
  }
}

Candidate origins

Returned candidates retain one ingress origin:
  • api
  • daemon
This matters for automation:
  • daemon automation only treats source and evidence_refs as trusted policy inputs for daemon-origin candidates
  • API-origin candidates may still auto-publish through other matching rules, but they do not satisfy the require_* trusted-input gates

Candidate states and automation review

Returned candidates expose:
  • origin
  • state
  • automation_review
  • published_learning_id
Current candidate states are:
  • pending
  • escalated
  • published
  • rejected
automation_review is the daemon-owned audit record written by the automation worker. It includes:
  • mode
  • action
  • reviewed_at_ms
  • matched_rule_name
  • judge
  • reason
When present, automation_review.judge includes:
  • action
  • judged_at_ms
  • reason

Publish payload

POST /v1/learning-candidates/{candidate_id}/publish accepts optional overrides:
  • scope
  • kind
  • sensitivity
  • content
  • confidence
  • expires_at_ms
  • publish_tier
  • evidence_refs
  • supersedes
If omitted, Kheish publishes the candidate as-is. Current operator-path behavior:
  • the daemon normalizes policy_decision to manual
  • the daemon normalizes policy_actor to operator
  • publish_tier defaults to active when omitted
  • publish_tier=provisional produces a durable learning with status=provisional
  • publish_tier=active produces a durable learning with status=active
  • supersedes is only accepted when the published record uses publish_tier=active

Reject behavior

POST /v1/learning-candidates/{candidate_id}/reject marks the candidate as rejected. Rejected candidates are not converted into learnings.

Automatic learning policy

The daemon can review and publish candidates automatically through runtime policy. Operator surfaces:
  • GET /v1/runtime/learning-policy
  • POST /v1/runtime/learning-policy
  • kheish-daemon runtime learning-policy get
  • kheish-daemon runtime learning-policy set
The current policy model contains:
  • mode
  • capture
  • publication
  • judge
Current modes:
  • manual_only
  • shadow
  • enabled
The current default mode is shadow. Important update rule:
  • POST /v1/runtime/learning-policy replaces the full policy
  • send mode explicitly when mutating policy

Capture settings

capture currently contains:
  • run_summary_candidates
  • semantic_candidates
capture.run_summary_candidates defaults to true. capture.semantic_candidates currently contains:
  • enabled
  • model
  • timeout_ms
  • max_candidates_per_run
Current semantic-capture defaults:
  • enabled=false
  • model=null
  • timeout_ms=null
  • max_candidates_per_run=2
Current validation rules:
  • timeout_ms must be greater than zero when provided
  • max_candidates_per_run must be between 1 and 8

Publication settings

publication currently contains:
  • default_action
  • allow_api_origin_active_publication
  • quarantined_rule_names
  • rules
Current action values:
  • manual_review
  • reject
  • publish_provisional
  • publish_active
Current validation rules:
  • 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

Judge settings

judge currently contains:
  • enabled
  • model
  • timeout_ms
The judge is model-backed and daemon-owned. It runs after deterministic policy evaluation and can only choose actions inside the policy envelope. In enabled mode, judge failures fail closed to manual_review. Current validation rule:
  • judge.timeout_ms must be greater than zero when provided

Rule matching semantics

Publication rules are evaluated in order. The first matching rule wins. If no rule matches, the daemon falls back to publication.default_action. Each rule can match on:
  • name
  • scope_kind
  • scope_id
  • kind
  • sensitivity
  • min_confidence
  • require_evidence
  • require_source_run
  • require_source_session
  • action
  • expires_after_ms
Important trusted-input rule:
  • require_evidence
  • require_source_run
  • require_source_session
only match for daemon-origin candidates. That trusted-input rule affects rule matching only. API-origin candidates can still auto-publish when another rule matches and later daemon-owned verification succeeds.

Automatic publication outcomes

The automation worker can currently decide:
  • manual_review
  • reject
  • publish_provisional
  • publish_active
Additional runtime guardrails apply:
  • procedure can never auto-publish with the active tier
  • API-origin candidates are downgraded from automatic publish_active to publish_provisional unless allow_api_origin_active_publication=true
  • named quarantined rules are skipped during evaluation

Automatic active verification

publish_active is still guarded by daemon-owned verification. Current behavior:
  • the candidate must carry a non-empty content
  • the candidate must have source.run_id
  • for daemon-origin semantic fact, preference, and decision candidates, the daemon can verify the content against the persisted run-memory record of the source run
  • otherwise the daemon checks source-run debug artifacts referenced by evidence_refs
  • if verification fails, the daemon downgrades the result to publish_provisional
This means a policy rule and judge may still aim for publish_active, but the stored learning lands as provisional when daemon-owned verification does not support active publication.

Published learnings

Endpoints

  • GET /v1/learnings
  • GET /v1/learnings/{learning_id}
  • POST /v1/learnings/{learning_id}/revoke
  • POST /v1/learnings/{learning_id}/supersede
  • POST /v1/learnings/revoke-matching
  • POST /v1/learnings/{learning_id}/promote-skill

List filters

GET /v1/learnings supports:
  • query
  • scope_kind
  • scope_id
  • kind
  • status
  • policy_decision
  • policy_actor
  • matched_rule_name
Important returned fields on each learning include:
  • status
  • publish_tier
  • verification_status
  • policy_decision
  • policy_actor
  • evidence_refs
  • supersedes
  • superseded_by

Revoke payload

POST /v1/learnings/{learning_id}/revoke accepts:
  • reason

Bulk revoke payload

POST /v1/learnings/revoke-matching accepts the same main filters as learning listing plus:
  • reason
Current filter fields:
  • query
  • scope_kind
  • scope_id
  • kind
  • status
  • policy_decision
  • policy_actor
  • matched_rule_name
This is the main operator surface for bulk rollback of automatically published memory.

Supersede payload

POST /v1/learnings/{learning_id}/supersede accepts:
  • scope
  • kind
  • sensitivity
  • content
  • confidence
  • expires_at_ms
content is required for supersession. The same 1600-character limit applies. This creates a new active learning and marks the older record as superseded. Current supersession rule:
  • the replacement record always uses publish_tier=active

Prompt visibility versus durability

Published learnings are the source of truth, but they are not all prompt-eligible. To inspect the effective eligible projection before final prompt packing, use:
  • GET /v1/sessions/{session_id}/memory-context
Important current prompt rules:
  • active procedure learnings remain excluded from learned_context
  • active run_summary learnings remain excluded from learned_context
  • learnings with publish_tier=provisional remain excluded
  • learnings with verification_status=failed remain excluded
  • automatically published learnings are prompt-visible only after verification_status=verified
  • learnings with policy_decision=escalated remain excluded
  • promoted procedure skills appear through visible_skills instead
The runtime can still truncate or omit learned_context and recovered_memory later when it packs the final prompt for a specific input and model budget. To inspect the broader session-visible memory browse/search surface, use:
  • GET /v1/sessions/{session_id}/memory-search
That derived session view returns a bounded mix of:
  • visible learnings
  • recovered runs visible through the session’s learning scopes
  • visible skills
It is a search surface, not the canonical source of truth. Promotion turns one reviewed procedure learning into a daemon-owned reusable skill.

Promotion constraints

Current production rules:
  • the source learning must have kind procedure
  • the source learning must be active
  • the source learning must use publish_tier=active
  • the source learning must use workspace scope
  • promoted procedure skills must use fork
  • promoted procedure skills must resolve to the verification agent profile

Endpoints

  • POST /v1/learnings/{learning_id}/promote-skill
  • GET /v1/learning-skills
  • GET /v1/learning-skills/{skill_name}
  • POST /v1/learning-skills/{skill_name}/revoke

Promotion payload

POST /v1/learnings/{learning_id}/promote-skill accepts:
  • skill_name
  • description
  • when_to_use
  • version
  • instructions
  • allowed_tools
  • blocked_tools
  • context
  • agent_profile
  • provider
  • model
  • fallback_model
  • status
Current validation notes:
  • context must resolve to fork
  • agent_profile must resolve to verification
  • skill_name must be single-line ASCII and may contain only letters, digits, :, _, and -
  • empty or whitespace-only description falls back to the generic non-sensitive default description
  • empty or whitespace-only agent_profile, provider, model, and fallback_model are normalized away
  • omitted agent_profile defaults to verification
  • omitted status defaults to draft
  • new promoted skills cannot start directly in active
Example:
{
  "skill_name": "learning:scheduler-review",
  "description": "Run the scheduler review procedure in a verification child agent.",
  "when_to_use": "Use when the operator explicitly asks for the learning:scheduler-review skill.",
  "version": "1",
  "instructions": "Reply with exactly `SCHEDULER_REVIEW_OK:${KHEISH_SKILL_ARGS}` and nothing else.",
  "allowed_tools": ["read_file"],
  "blocked_tools": [],
  "context": "fork",
  "agent_profile": "verification"
}

Learning-skill list filters

GET /v1/learning-skills supports:
  • source_learning_id
  • status
Promoted skill records expose rollout and audit fields such as:
  • status
  • verification_status
  • evidence_refs
  • successful_run_count
  • distinct_session_count
  • verifier_run_ids
  • real_daemon_verified
  • last_verified_workspace_digest
  • canary_success_count
  • canary_failure_count

Revoke payload

POST /v1/learning-skills/{skill_name}/revoke accepts:
  • reason

Relationship to the normal skills catalog

Promoted skills are only added to the normal skill catalog when their promoted-skill record is active. Current rollout behavior:
  • draft stays durable but hidden
  • verified stays durable but hidden
  • canary stays durable but hidden
  • active becomes visible through /v1/skills and session-visible skill projection
  • revoked is removed from the visible catalog but retained durably for audit
Those endpoints remain inspection-only. Actual execution still happens inside the runtime through use_skill.

CLI surface

The CLI mirrors the learning plane:
  • kheish-daemon learnings candidates ...
  • kheish-daemon learnings list
  • kheish-daemon learnings get
  • kheish-daemon learnings revoke
  • kheish-daemon learnings revoke-matching
  • kheish-daemon learnings supersede
  • kheish-daemon learnings skills list
  • kheish-daemon learnings skills get
  • kheish-daemon learnings skills promote
  • kheish-daemon learnings skills revoke
Current CLI note:
  • the CLI candidate-create surface does not currently expose evidence_refs
  • use the HTTP API when you need explicit evidence-backed automatic publish_active testing

Error model

The learning surfaces return normal 400, 404, and 409 control-plane errors for validation and conflict cases. Examples of current client-visible validation failures include:
  • invalid learning scope
  • missing or empty content
  • content longer than 1600 characters
  • confidence outside 0..=100
  • promoting a non-procedure learning
  • promoting a non-active learning
  • promoting a non-workspace learning
  • using a promoted-procedure context other than fork
  • invalid skill_name
  • invalid learning-policy publication rules

Operational behavior

The current implementation is durable and restart-aware:
  • published learnings survive restart
  • promoted procedural skills survive restart
  • semantic capture can replay pending runs on boot without duplication
  • revoking or superseding a promoted source learning also revokes the linked promoted skill
  • the daemon repairs missing promoted-skill files on boot
  • the daemon does not silently rebind a promoted-skill record to an unrelated skill root