Learnings API
Kheish exposes the daemon-owned learning plane through three related HTTP surfaces:- learning candidates
- published learnings
- promoted procedural skills
kheish-daemon learnings ....
Resource model
The normal flow is:- create or capture a learning candidate
- review it manually or through daemon automation
- publish it into a durable learning record, or reject it
- later revoke or supersede the learning
- optionally promote one reviewed
procedurelearning into a daemon-owned skill
Scope rules
Every candidate and learning belongs to one scope:sessionpersonaprojectworkspace
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_idwithoutscope_kindis rejectedscope_kindwithoutscope_idis rejected forsession,persona, andproject- only
workspacemay omitscope_id
Learning candidates
Endpoints
GET /v1/learning-candidatesPOST /v1/learning-candidatesGET /v1/learning-candidates/{candidate_id}POST /v1/learning-candidates/{candidate_id}/publishPOST /v1/learning-candidates/{candidate_id}/reject
List filters
GET /v1/learning-candidates supports:
queryscope_kindscope_idkindstate
Create payload
POST /v1/learning-candidates accepts:
scopekindsensitivitycontentconfidencesourceevidence_refsexpires_at_ms
contentis requiredcontentis capped at1600charactersconfidencemust stay in0..=100sensitivitydefaults toscopedconfidencedefaults to80sourcedefaults to an empty source object- public attempts to create
run_summarycandidates are rejected becauserun_summarycapture is daemon-owned
Candidate origins
Returned candidates retain one ingress origin:apidaemon
- daemon automation only treats
sourceandevidence_refsas 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:originstateautomation_reviewpublished_learning_id
pendingescalatedpublishedrejected
automation_review is the daemon-owned audit record written by the automation worker. It includes:
modeactionreviewed_at_msmatched_rule_namejudgereason
automation_review.judge includes:
actionjudged_at_msreason
Publish payload
POST /v1/learning-candidates/{candidate_id}/publish accepts optional overrides:
scopekindsensitivitycontentconfidenceexpires_at_mspublish_tierevidence_refssupersedes
- the daemon normalizes
policy_decisiontomanual - the daemon normalizes
policy_actortooperator publish_tierdefaults toactivewhen omittedpublish_tier=provisionalproduces a durable learning withstatus=provisionalpublish_tier=activeproduces a durable learning withstatus=activesupersedesis only accepted when the published record usespublish_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-policyPOST /v1/runtime/learning-policykheish-daemon runtime learning-policy getkheish-daemon runtime learning-policy set
modecapturepublicationjudge
manual_onlyshadowenabled
shadow.
Important update rule:
POST /v1/runtime/learning-policyreplaces the full policy- send
modeexplicitly when mutating policy - send
expected_revisionwhen multiple operators or automations may update runtime config - the policy is persisted in
runtime-config.json;learning-policy.jsonis legacy migration input only
expected_revision is rejected instead of resetting the policy implicitly.
Capture settings
capture currently contains:
run_summary_candidatessemantic_candidates
capture.run_summary_candidates defaults to true.
capture.semantic_candidates currently contains:
enabledmodeltimeout_msmax_candidates_per_run
enabled=falsemodel=nulltimeout_ms=nullmax_candidates_per_run=2
timeout_msmust be greater than zero when providedmax_candidates_per_runmust be between1and8- daemon semantic capture drops
fact,preference, anddecisioncandidates that contain secret-like material, runtime redaction markers, or redactable provider/API tokens
Publication settings
publication currently contains:
default_actionallow_api_origin_active_publicationquarantined_rule_namesrules
manual_reviewrejectpublish_provisionalpublish_active
default_actioncannot bepublish_active- a
publish_activerule must declare an explicitkind publish_activeis not supported forprocedurelearnings- quarantined rule names must be non-empty and unique
- semantic
fact,preference, anddecisioncandidates/learnings that look like secrets are rejected before persistence, including common key/value assignment shapes such asapi-key:,x-api-key:,clientSecret:,secret_token=, andpersonal access token= - equivalent same-subject/value forms such as
Project codename is Atlasandproject codename: atlasuse the same deterministic semantic key for deduplication - automatic
publish_activeis downgraded tomanual_reviewwhen the candidate conflicts with an active same-scope, same-kind learning with the same obvious subject and a different normalized value - explicit candidate publication also rejects an active same-scope, same-kind conflict unless the request names the replaced learning in
supersedes - publishing an equivalent same-scope, same-kind prompt-visible learning reuses the existing learning id instead of creating a duplicate record
Judge settings
judge currently contains:
enabledmodeltimeout_ms
enabled mode, judge failures fail closed to manual_review.
Current validation rule:
judge.timeout_msmust 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 topublication.default_action.
Each rule can match on:
namescope_kindscope_idkindsensitivitymin_confidencerequire_evidencerequire_source_runrequire_source_sessionactionexpires_after_ms
require_evidencerequire_source_runrequire_source_session
Automatic publication outcomes
The automation worker can currently decide:manual_reviewrejectpublish_provisionalpublish_active
procedurecan never auto-publish with the active tier- API-origin candidates are downgraded from automatic
publish_activetopublish_provisionalunlessallow_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, anddecisioncandidates, the daemon can verify the content against the persisted run-memory record of the source run using exact containment or a conservative normalized-term match - otherwise the daemon checks source-run debug artifacts referenced by
evidence_refs - if verification fails, the daemon downgrades the result to
publish_provisional
publish_active, but the stored learning lands as provisional when daemon-owned verification does not support active publication.
Published learnings
Endpoints
GET /v1/learningsGET /v1/learnings/{learning_id}POST /v1/learnings/{learning_id}/revokePOST /v1/learnings/{learning_id}/supersedePOST /v1/learnings/revoke-matchingPOST /v1/learnings/{learning_id}/promote-skill
List filters
GET /v1/learnings supports:
queryscope_kindscope_idkindstatuspolicy_decisionpolicy_actormatched_rule_name
statuspublish_tierverification_statuspolicy_decisionpolicy_actorevidence_refssupersedessuperseded_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
queryscope_kindscope_idkindstatuspolicy_decisionpolicy_actormatched_rule_name
Supersede payload
POST /v1/learnings/{learning_id}/supersede accepts:
scopekindsensitivitycontentconfidenceexpires_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 - the replacement
scopemust match the source learning scope; cross-scope migration must be modeled as an explicit new learning plus revocation instead of a normal supersession
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
- active
procedurelearnings remain excluded fromlearned_context - active
run_summarylearnings remain excluded fromlearned_context - learnings marked
sensitivity=sensitiveremain excluded fromlearned_contextand session memory-search - learnings with
publish_tier=provisionalremain excluded - learnings with
verification_status=failedremain excluded - automatically published learnings are prompt-visible only after
verification_status=verified - learnings with
policy_decision=escalatedremain excluded - promoted procedure skills appear through
visible_skillsinstead
learned_context and recovered_memory later when it packs the final prompt for a specific input and model budget. For real session input, prompt-eligible learnings are ordered with query-aware lexical ranking against the pending input before that packing step, so relevant wider-scope learnings can beat newer or narrower-scope unrelated learnings. Prompt injection scores learning content only; kind and scope terms remain useful for memory-search, but they do not make a learning eligible for prompt injection by themselves. If at least one learning scores against the pending input, zero-score learnings are omitted from that prompt projection. If nothing scores, unrelated inputs receive no learned_context; explicit memory requests keep the existing recency/scope fallback.
GET /v1/sessions/{session_id}/memory-context?query=... uses the same lexical ranking to preview that ordering without submitting a run.
Session memory search
To inspect the broader session-visible memory browse/search surface, use:GET /v1/sessions/{session_id}/memory-search
- visible learnings
- recovered runs visible through the session’s learning scopes
- visible skills
query is present, visible learnings use the same deterministic Unicode-aware lexical scoring as prompt retrieval. Returned learning results expose score and matched_fields so operators can see whether content, kind, or scope matched the query.
Promoted procedural skills
Promotion turns one reviewedprocedure 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
workspacescope - promoted procedure skills must use
fork - promoted procedure skills must resolve to the
verificationagent profile
Endpoints
POST /v1/learnings/{learning_id}/promote-skillGET /v1/learning-skillsGET /v1/learning-skills/{skill_name}POST /v1/learning-skills/{skill_name}/rollout-resultPOST /v1/learning-skills/{skill_name}/revokePOST /v1/learning-skills/{skill_name}/rollback
Promotion payload
POST /v1/learnings/{learning_id}/promote-skill accepts:
skill_namedescriptionwhen_to_useversioninstructionsallowed_toolsblocked_toolscontextagent_profileprovidermodelfallback_modelstatus
contextmust resolve toforkagent_profilemust resolve toverificationskill_namemust be single-line ASCII and may contain only letters, digits,:,_, and-- empty or whitespace-only
descriptionfalls back to the generic non-sensitive default description - empty or whitespace-only
agent_profile,provider,model, andfallback_modelare normalized away - omitted
agent_profiledefaults toverification - omitted
statusdefaults todraft - new promoted skills cannot start directly in
active verifiedrequires daemon-validated verification evidenceactiverequires verification evidence, at least one successful canary rollout, and zero canary failures- changing the active definition requires a new draft rollout
skill_name,description,when_to_use,version, andinstructionsare rejected when they look like secret material- skill revocation and rollback reasons are also rejected when they look like secret material, so operator audit text cannot persist key/value secrets such as
api-key:orclientSecret: - rollback refuses to remount a promoted skill if its source procedure learning is no longer active with the active publish tier
Learning-skill list filters
GET /v1/learning-skills supports:
source_learning_idstatus
statusverification_statusevidence_refssuccessful_run_countdistinct_session_countverifier_run_idsreal_daemon_verifiedlast_verified_workspace_digestcanary_success_countcanary_failure_countdefinition_fingerprintlifecycle_events
SKILL.md differs, and runtime use_skill rejects active promoted skills whose loaded catalog definition no longer matches the active record.
Rollout-result payload
POST /v1/learning-skills/{skill_name}/rollout-result records daemon-validated rollout evidence from an existing run:
kind:verificationorcanaryrun_idexpected_output_containsdefinition_fingerprintoptional guard; when supplied, it must match the current promoted-skilldefinition_fingerprint
expected_output_contains.
Successful evidence notes retain the current definition fingerprint for audit.
Verification evidence can be recorded while the skill is still draft. Canary evidence requires status=canary. A failed canary increments canary_failure_count and blocks activation until the operator starts a new draft rollout.
Revoke payload
POST /v1/learning-skills/{skill_name}/revoke accepts:
reason
Rollback payload
POST /v1/learning-skills/{skill_name}/rollback restores the latest historical active snapshot for the promoted skill and accepts:
reason
Relationship to the normal skills catalog
Promoted skills are only added to the normal skill catalog when their promoted-skill record isactive.
Current rollout behavior:
draftstays durable but hiddenverifiedstays durable but hidden and requires verified daemon evidencecanarystays durable but hidden; canary rollout results are recorded against the current definition fingerprintactivebecomes visible through/v1/skillsand session-visible skill projectionrevokedis removed from the visible catalog but retained durably for audit- rollback restores the latest retained active snapshot and remounts it in the visible catalog
use_skill.
CLI surface
The CLI mirrors the learning plane:kheish-daemon learnings candidates ...kheish-daemon learnings listkheish-daemon learnings getkheish-daemon learnings revokekheish-daemon learnings revoke-matchingkheish-daemon learnings supersedekheish-daemon learnings skills listkheish-daemon learnings skills getkheish-daemon learnings skills promotekheish-daemon learnings skills rollout-resultkheish-daemon learnings skills revokekheish-daemon learnings skills rollback
- the CLI candidate-create surface does not currently expose
evidence_refs - use the HTTP API when you need explicit evidence-backed automatic
publish_activetesting
Error model
The learning surfaces return normal400, 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
1600characters - confidence outside
0..=100 - promoting a non-
procedurelearning - promoting a non-
activelearning - promoting a non-
workspacelearning - using a promoted-procedure context other than
fork - activating a promoted skill before verification and canary evidence exists
- recording canary evidence before the skill is in
canary - 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
