The platform

Outcomes and learning

How an agent on Yohanun gets better without anyone retraining a model: outcomes reported against the memory that informed them, a track record that moves ranking, mandates that let an agent act up to a line and escalate above it, and reconciliation that proposes changes to what is held and waits to be ratified.

Report an outcome

POST /api/learning/outcome
{
  "outcome": "success" | "failure" | "correction",
  "principal_id": "agent:ops",
  "situation": "customer asked for a refund over the limit",
  "action": "escalated to the owner with the order details",
  "lesson": "refunds above 50 always need the owner; do not promise a timeline",
  "memory_ids": ["1f3c…", "9a21…"],      // the memory that informed the action
  "contexts": ["support"],
  "compartment": "matter:acme", "acl_classification": 1,   // the lesson's own labels
  "score": 0.0
}
GET /api/learning/outcomes?limit=100

Two things happen. The lesson becomes a retrievable memory under the labels you gave it, so the next similar situation finds it. And every memory named in memory_ids has its track record moved: outcome_helpful or outcome_harmful is incremented, and the ranking nudges that memory up or down by a bounded amount (about fifteen per cent) on later searches. Both counters ride on every search hit, so your application can show why something ranked where it did.

Implicit outcomes

When chat is grounded on memory and the next turn says, in effect, "yes, exactly" or "no, that's wrong", the platform records that as an outcome against the memory that grounded the answer. No call is needed; the conversation is the evaluation signal. Explicit outcomes override implicit ones.

Mandates: act up to a line

POST /api/access/mandates/grant        {"principal_id": "agent:ops", "action": "refund", "limit": 50, "unit": "EUR"}
POST /api/access/authorize-action      {"principal_id": "agent:ops", "action": "refund", "amount": 35, "unit": "EUR"}
→ {"decision": "allow", "limit": 50, "reason": "within mandate"}
→ {"decision": "escalate", "escalation_id": 1842, "limit": 50, "reason": "..."}

GET  /api/access/escalations?status=pending
POST /api/access/escalations/{id}/decide   {"approve": true, "reason": "...", "decider": "user:owner"}

Below the limit the action is allowed and recorded. Above it, with no mandate, or on a unit mismatch, it escalates to a human queue with an id your application can show. The check fails closed: if the mandate service itself cannot answer, the action escalates rather than proceeds. Deciding enforces the two-person rule on the platform side: never the principal who raised it, and only someone whose own mandate covers that action at that amount; a refused decision is a 403 and a decision_refused audit row, and the request stays pending. The agent runtime (POST /api/agent/run) exposes authorize_action and record_outcome as built-in tools, so an agent loop gets both without wiring.

Reconciliation: propose, then ratify

When a belief-grain memory is stored (a memory your application creates, a fact distilled from a session or a document; not raw conversation turns or document chunks), the platform compares it with its neighbours inside the same wall. Content-identical stores are closed automatically. Where a judge finds the new memory refines or contradicts an existing one, nothing changes: a proposal lands in a queue.

GET  /api/memory/reconciliation/proposals            pending, as cluster heads with cluster_size
POST /api/memory/reconciliation/proposals/{id}/decide {"decision": "ratify" | "reject" | "keep"}
GET  /api/memory/reconciliation/stats                 per-verdict ratify/reject record

ratify executes the supersession or close through the lifecycle primitives, with the history kept. keep keeps both live and records a typed relation (contradicts, refines) that reads expose. The judge applies one rule worth knowing: a belief (how something is) can be superseded, a record (that something happened on an occasion) never can, because the earlier occasion still happened. The stats endpoint is the judge's own track record; autonomy is earned against it, never assumed.

Grades move too

A memory's weight is a value axis separate from access. Regrade one in place (POST /api/memory/memories/{id}/grade) or every passage of a document (POST /api/documents/{id}/grade); each leaves a ledger row with the old and new grade. A librarian's regrade is how a team's know-how is promoted without copying it.

Why this matters. An agent that acts within limits and learns from outcomes is the difference between a demo and a deployment: Memory for AI agents that keeps its history.

Get a key

Yohanun is in invited beta. Tell us what you are building and we send a key with a developer account; a memory-profile key for your own model, or a chat-profile key if you want the platform to run the model and meter it. There is no card and no self-serve sign-up.

Request an invite