Korely

Human-in-the-loop memory

Human-in-the-loop memory means the person whose data is being stored can inspect every fact, correct what is wrong, and permanently erase what they no longer want kept — without a support ticket, without waiting for a developer. For an agent builder this matters because your agent's memory is only as trustworthy as the data inside it: a user who can audit and fix their own facts gives you a self-correcting knowledge base, and a user who knows that control exists is far more willing to let an agent remember things in the first place.

Every memory layer stores facts about people. Korely is the only one where the person can see those facts, correct them, and delete them in a real app built for humans. This page explains how that works and what it means for the agents you build on top.

The thesis

Agent memory about a person should be visible and correctable by that person. We hold this for two reasons:

  • Trust. A personal assistant that silently accumulates a dossier about its user is creepy. One that says "here is everything I know about you, fix what's wrong" is a product people keep using. Memory you can inspect is memory you can rely on.
  • Control. At some point your users will ask to correct or erase what is stored about them. With Korely those flows ship in the box: the end user edits and deletes facts directly, in the app, without a support ticket.

Memory that only machines can read works until it is wrong, stale, or about something the user wanted forgotten. Then you have a support ticket, a trust problem, or a data-control problem, and no tooling for any of the three. Korely closes that gap by giving the human a first-class surface over the same store your agents use.

What the end user sees

Korely users run the Korely desktop or web app. That app is where memory becomes visible:

The Memory Panel

A panel titled "Things Korely knows about you". Every cross-session fact, the same (subject, predicate, object) triples your agents read via korely.get_facts(), is listed there, grouped by the 9 predicate families (preferences, people, places, work, ownership, health, financial, events, other). Each fact links back to the source note or conversation it was extracted from, so the user can see why Korely believes it.

The Entity Profile drawer

Click any entity (a person, a company, a product) and a drawer opens with everything known about it: facts where the entity appears on either side of a triple, plus the notes that mention it via the entity graph. It answers "what does my memory say about Marco?" in one click.

Edit a fact

Suppose your agent's memory holds a fact that life has since overtaken. Sofia changed jobs, but the fact store still has a live typed triple — the Memory Panel groups it under Work and shows it as current (its invalid_at is null):

Memory Panel → Work (1 fact)
| Fact | Valid from | Live? |
|----------------------------|------------|-------|
| Sofia — works_at — Acme | 2026-01-12 | yes |

Sofia opens the Memory Panel and edits the fact in place. The corrected version becomes the current fact. The old value is invalidated with a timestamp, not erased, consistent with the bi-temporal model every fact already carries (valid_from + invalid_at). The next read your agent makes returns the corrected row, and the full chain stays queryable:

Memory Panel → Work (showing history)
| Fact | Valid from | Invalid at |
|---------------------------------|------------|------------|
| Sofia — works_at — Beacon Labs | 2026-06-09 | — |
| ~~Sofia — works_at — Acme~~ | 2026-01-12 | 2026-06-09 |

Whether the old fact was superseded by new information (automatic contradiction detection) or corrected by the user in the Memory Panel, the mechanics are the same: old fact invalidated, new fact current, history preserved. The default read returns only the current row.

Forget a fact

The user clicks Forget. The fact is invalidated with an audit stub and excluded from all reads immediately. Say Sofia once mentioned an allergy and decides it is not something her assistant should remember. After the Forget click, the default read is clean:

korely.get_facts(subject="Sofia", predicate_family="health")
No facts found.

Forget is a soft delete: the fact's invalid_at is set and it is excluded from every default read, so a model can never surface it as current truth. It is not a hard row delete — the audit trail of who knew what, and when, has to survive an erasure request to be defensible. Passing include_invalidated=True reveals forgotten and superseded facts alike; both stay in history and render strike-through so a model cannot mistake them for current truth.

What this means for your agents

You don't integrate with any of the UI above. It exists on the user's side, and what you get is its consequences, automatically:

User action in the appWhat your agent observes
Edits a fact The next korely.get_facts() call returns the corrected value. No cache to bust, no webhook to handle.
Forgets a fact The fact disappears from default reads instantly. Your agent cannot leak it back into a conversation.
Disputes a memory The invalidation chain is queryable with include_invalidated=True. Who believed what, and when, is reconstructable, with an audit trail.

Propagation is immediate because reads are deterministic. No generative model sits between the fact store and the tool response: there is no reranking model and no answer synthesis on the read path, your agent's own model does the reasoning. A corrected fact is just a row, and the next read returns it, typically in under 50ms. There is no "eventually consistent memory" window where the agent acts on a fact the user already deleted.

Design your prompts for this. Don't tell your agent to cache user facts in its own scratchpad "for efficiency". A cached fact survives the user's Forget click; a fresh korely.get_facts() call doesn't. Re-read facts at the start of each session. Reads are retrieval, not generation, and read quotas are an order of magnitude more generous than write quotas, so the read is effectively free.

Erasure over REST

The Forget button covers the user acting inside Korely. When the deletion request arrives through your product instead, for example a customer closing their account in your app, erasing every memory for that user is one HTTP request. DELETE /v1/users/:end_user/memories invalidates every memory and every fact scoped to that user_id in a single call, with one audit record:

Terminal window
curl -X DELETE https://api.korely.ai/v1/users/customer-4812/memories \
-H "Authorization: Bearer kor_live_..."
// 200 OK
{
"user_id": "customer-4812",
"memories_forgotten": 218,
"facts_invalidated": 64,
"audit_id": "aud_91xb"
}

A single memory can be forgotten the same way with DELETE /v1/memories/:id. Both endpoints mirror the Forget button: invalidation with an audit stub, not a hard row delete, so the "who knew what, when" trail survives the erasure. Full details in the API reference.

Why this matters, per use case

  • Healthcare and legal assistants. Correction and erasure requests are not optional here. Korely gives you the data-control primitives, deletion, editing, an audit trail, EU hosting; the regulatory review of your application stays yours. The request path is "user opens the app and clicks", not "user emails your support, support files a ticket, an engineer runs a manual delete".
  • Personal AI. Trust is retention. A user who finds a wrong fact and can fix it stays; a user who finds a wrong fact and can't gets uneasy and churns. The Memory Panel turns "what does this thing know about me?" from a fear into a feature.
  • Customer support agents. Wrong account facts ("user is on the Team plan" when they downgraded months ago) cause wrong answers. With Korely the user fixes the fact themselves and every subsequent agent interaction is correct, with no escalation loop.

The shared-memory loop

Human-in-the-loop goes beyond facts. The Korely memory store (notes, folders, projects) is shared between agents and the human, and both sides read and write the same data:

  1. An agent drafts a document and saves it with korely.add().
  2. The human sees it appear in the Korely app within seconds, reads it, edits two paragraphs.
  3. The agent reads the memory back with korely.get(id) and continues from the edited version.
sequenceDiagram
    participant Agent
    participant KorelyStore as Korely Store
    participant HumanApp as Korely App (human)

    Agent->>KorelyStore: add("Sofia works at Acme")
    KorelyStore-->>Agent: mem_8f2c1a
    HumanApp->>KorelyStore: open Memory Panel
    KorelyStore-->>HumanApp: Sofia — works_at — Acme (active)
    HumanApp->>KorelyStore: edit fact: "Beacon Labs" + Forget old
    KorelyStore-->>HumanApp: fact updated, old invalidated
    Agent->>KorelyStore: get_facts(subject="Sofia", predicate="works_at")
    KorelyStore-->>Agent: Sofia — works_at — Beacon Labs (active)
Agent and human share one store. Human edits propagate instantly to the next agent read.

No copy-paste between a chat window and a document, no "export to Notion" step, no divergence between what the agent thinks the state is and what the human actually approved. The human's edit is the agent's input.

This loop is the core Korely design. Korely is both the memory layer and the app the end user opens every day to take notes, record meetings, and review what their agents did. The agent surface and the human surface share one store by construction.

Worked example: agent reacts to a user correction

The pattern below is the full human-in-the-loop cycle in code. The agent writes a fact, the user corrects it in the Memory Panel (no code needed on the user's side), and the agent's next read picks up the corrected value automatically. No cache to invalidate, no webhook to handle.

from korely import Korely
korely = Korely(api_key="kor_live_...")
# 1. Agent stores what it learned during the session.
# Korely extracts the fact triple automatically.
mem = korely.add(
"Sofia told me she works at Acme Corp as a product manager.",
user_id="customer-4812",
)
print(mem.id) # mem_8f2c1a
# 2. (Out of band) Sofia opens the Korely app, sees the fact,
# edits it to "Beacon Labs". No code required here.
# 3. Agent's next turn — reads back what is current.
facts = korely.get_facts(
user_id="customer-4812",
subject="Sofia",
predicate="works_at",
)
print(facts)
# Sofia — works_at — Beacon Labs valid_from 2026-06-09 invalid_at None
#
# The old "Acme Corp" fact is invalidated and absent from the default read.
# Pass include_invalidated=True to see the full correction chain.

If the user forgets a fact rather than editing it, the same principle holds: get_facts() returns nothing for that predicate, and your agent cannot leak the erased information back into the conversation. The deletion path is also available over REST for programmatic erasure when the request arrives through your product (for example, a user closing their account):

Terminal window
# Erase all memory for one user — account closure flow.
curl -X DELETE https://api.korely.ai/v1/users/customer-4812/memories \
-H "Authorization: Bearer kor_live_..."
# { "user_id": "customer-4812", "memories_forgotten": 218, "facts_invalidated": 64 }

Next steps

  • See the full get_facts() parameter surface in the API reference.
  • Not connected yet? The quickstart gets you from zero to a working integration in five minutes.
  • Memory Panel, Entity Profile drawer, the graph, and temporal facts are included on every plan. See pricing. Your data is EU-hosted on our own infrastructure, on every plan.

See also

  • Temporal facts & contradictions — how valid_from + invalid_at timestamps work, and how automatic contradiction detection keeps stale facts out of your agent's reads.
  • The memory model — the three-layer store (memories, session context, typed facts) your agent reads and writes, and how each layer is indexed.
  • Data governance — EU hosting, GDPR Art. 17 erasure, audit trails, and what "no generative model on the read path" means for your compliance posture.