Procedural Learning API
The authenticated /api/v1/learning API registers immutable experimental
contracts, proposes candidates, records observed outcomes and selects qualified
procedures. The same durable learning ledger owns qualification and monitoring
decisions. Clients submit requests and receive results; these endpoints do not
run models, tools or arbitrary code.
Use http://localhost:7474 from the browser or a client on the Docker host.
Import OpenAPI for complete request and response schemas.
All JSON requests require contract_version: 1, use the existing 64 KiB transport
limit, and reject unrecognized fields. Responses carry contract_version: 1
and Cache-Control: no-store.
Authentication and scope#
Use Authorization: Bearer <credential>. Tenant and actor derive from the live
credential. Scoped operations use the same exact scope as versioned memory:
{"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"}
Shared access requires an exact grant within the tenant. Private access includes the authenticated subject, so another subject's private namespace is distinct. A separate evaluator subject needs a shared scope to evaluate another subject's proposal. Credential capability names grant no implicit additional permissions.
| Method and endpoint | Capability | Result envelope |
|---|---|---|
POST /api/v1/learning/policies |
policy_admin |
entry: immutable policy registration |
GET /api/v1/learning/policies/{id} |
policy_admin |
entry: registered policy |
POST /api/v1/learning/contexts |
policy_admin |
entry: immutable context registration |
GET /api/v1/learning/contexts/{id} |
policy_admin |
entry: registered context |
POST /api/v1/learning/proposals |
procedure_propose plus scope grant |
receipt: original candidate registration |
POST /api/v1/learning/procedures/read |
memory_read plus scope grant |
procedure: original receipt and current record |
POST /api/v1/learning/evaluations |
procedure_evaluate plus scope grant and policy evaluator subject |
receipt: durable admission outcome |
POST /api/v1/learning/evaluations/read |
memory_read plus scope grant |
receipt: original admission |
POST /api/v1/learning/select |
memory_read plus scope grant |
selection: qualified procedure or exact baseline |
Successful operations return 200, including identical retries and durable admission of rejected/incomplete evidence. HTTP success alone does not mean an evaluation was accepted or a procedure was promoted.
Register the administrative contracts#
A policy administrator posts this to /api/v1/learning/policies:
{
"contract_version": 1,
"id": "policy-v1",
"definition": {
"algorithm": "fixed_budget_hoeffding_v1",
"parameters": {
"qualification_trials": 32,
"confidence_delta": 0.01,
"min_improvement": 0.05,
"min_candidate_utility": 0.7,
"max_cost_units": 10000,
"max_latency_ms": 60000,
"max_failure_streak": 3,
"evaluator_id": "evaluator",
"evaluation_contract": "rubric-v1"
}
}
}
The evaluator ID is an authenticated subject, not a client-supplied actor field. The algorithm uses a fixed qualification count without early acceptance; its statistical assumptions and per-proposal error budget are documented in the learning contract. This example is suitable for a synthetic integration test, not a claim of measured agent improvement.
Register the exact context at /api/v1/learning/contexts:
{
"contract_version": 1,
"id": "context-v1",
"context": {
"task": "task-v1",
"baseline_revision": "baseline-v1",
"model_provider": "provider",
"model_revision": "model-v1",
"tools": {"search": "search-artifact-v1"},
"environment_revision": "environment-v1",
"evaluation_contract": "rubric-v1",
"dataset_revision": "held-out-v1",
"harness_revision": "harness-v1",
"permissions_revision": "permissions-v1"
}
}
Policy/context IDs are immutable within a tenant. The response entry preserves
schema_version, tenant, id, payload, payload_digest, registered_by and
recorded_at_millis. The actor string is <credential UUID>:<subject ID>.
An identical retry returns the original entry; changed content returns 409.
A new revision needs a new ID. Registry identities support 1–512 UTF-8 bytes,
and a context supports up to 128 tool identities.
Definitions are tenant-wide administrative registrations. Authorized proposers may reference registered definitions; this version does not implement automatic retirement or a mutable per-scope active-policy assignment. Administrators must register only definitions they intend to make available in that tenant.
Propose an immutable candidate#
Post to /api/v1/learning/proposals using a proposing credential:
{
"contract_version": 1,
"scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
"proposal": {
"id": "candidate-v1",
"policy_id": "policy-v1",
"context_id": "context-v1",
"instructions": "Check source evidence before answering.",
"source_refs": ["training-trace-v1"]
}
}
Task, baseline and policy parameters are resolved from the registered contracts. The caller cannot insert policy thresholds into this request. Source references number 1–128, each 1–2048 bytes; instructions support up to 65536 bytes in the library, subject to the smaller effective space available in the whole HTTP body. References declare provenance; the platform does not fetch or authenticate arbitrary external evidence merely because its ID appears here.
The ProposalReceipt preserves tenant, authorized namespace, original request,
policy/context digests, authenticated actor and original Candidate record.
Candidate and receipt commit in one synchronous WAL batch. The procedure ID is
unique within tenant/namespace; changed retries conflict. Identical retries always
return this original receipt, even after later promotion or suspension.
To read current state, post to /api/v1/learning/procedures/read:
{"contract_version":1,"scope":{"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},"procedure_id":"candidate-v1"}
The procedure envelope has receipt (original registration) and record
(current ProcedureRecord). The latter includes immutable proposal/scope,
state, qualification and monitoring counts, mean improvement/utility, budget
violations, lower improvement bound, failure streak, creation time and decision
history. Each decision records its prior/next state, reason, triggering case and
transaction timestamp. States are Candidate, Active, Rejected, Suspended.
Submit outcomes with an evaluator credential#
Post to /api/v1/learning/evaluations:
{
"contract_version": 1,
"scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
"procedure_id": "candidate-v1",
"submission": {
"case_id": "held-out-case-001",
"phase": "Qualification",
"policy_id": "policy-v1",
"context_id": "context-v1",
"baseline_revision": "baseline-v1",
"evidence_ref": "evaluation-trace-001",
"status": "complete",
"baseline_utility": 0.0,
"candidate_utility": 1.0,
"candidate_cost_units": 100,
"candidate_latency_ms": 250,
"detail": null
}
}
Baseline and candidate must describe the same held-out case. Valid utilities lie
in [0,1]. Cost uses the unit defined by the evaluation contract; latency uses
milliseconds. Measurements can be null/omitted to express unknown values.
Status is complete, rejected, incomplete, cancelled or
pending_or_unknown. Phase is Qualification or Monitoring.
The AdmissionReceipt retains schema, tenant/namespace/procedure, authenticated
actor (subject_id, credential_id), exact submission, outcome, stable
reason, state_after, optional accepted evaluation and transaction time.
Only outcome: accepted updates the efficacy ledger. Other outcomes are
rejected, incomplete, cancelled, pending_or_unknown,
unknown_consumption; see admission semantics.
An accepted observation may be negative and cause statistical rejection or
suspension. Missing accounting never becomes zero.
Case IDs are immutable across phases and outcomes. Identical retries by the same
evaluator subject preserve the original receipt; changed submissions return 409.
Corrected experiments require new case IDs and cannot reuse already accepted
evidence as independent evidence. To read a receipt, post the procedure-read
request plus case_id to /api/v1/learning/evaluations/read.
Select or fall back to the exact baseline#
Post to /api/v1/learning/select:
{"contract_version":1,"scope":{"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},"policy_id":"policy-v1","context_id":"context-v1","max_instruction_bytes":4096}
The instruction budget is 0–65536 UTF-8 bytes, not model tokens. Selection requires an active procedure qualified under those exact registered IDs/digests. It scans that learning scope under the mutation lock, checks the selected record against its immutable binding, and ranks by lower improvement bound with a stable procedure-ID tie break. No indexed-scale latency claim is implied.
A qualified response has selection.type: procedure and a procedure containing
its original receipt and current record. Otherwise the complete response is:
{"contract_version":1,"policy_id":"policy-v1","context_id":"context-v1","selection":{"type":"baseline","baseline_revision":"baseline-v1","reason":"no_qualified_compatible_procedure"}}
Changing model, tools, environment, permissions or another context field requires a new context and fresh qualification. The old procedure is not silently reused. Monitoring regressions can suspend an active procedure and restore baseline selection. This is the platform's single current selection result, not an execution permit or a guarantee that a selected procedure cannot regress later.
Failure and recovery contracts#
| Status | Contract |
|---|---|
| 400 | Invalid shape/version, invalid registration or incompatible policy/context proposal |
| 401 | Missing, expired, rotated or revoked credential |
| 403 | Missing capability/grant or wrong authenticated evaluator subject |
| 404 | No referenced contract, procedure or receipt in the authorized namespace |
| 409 | Immutable ID/case reused with changed content |
| 413 | Request exceeds the transport body limit |
| 500 | Storage failure or inconsistent/unsupported persisted record |
A well-formed evaluation with mismatched contract or unusable evidence returns a 200 rejected admission receipt, rather than silently counting evidence. Authentication failures and malformed requests do not create admission records. Synchronous WAL preserves acknowledged ledger mutations across process crashes; accepted admission and decision changes are atomic. An authorized in-flight request may finish during concurrent credential revocation. Unsupported schema or inconsistent binding/evaluation data fails explicitly. Deletion of procedural history, policy retirement, external trace verification and remote execution are separate capabilities outside this contract.