Korely

One personal AI, every channel

Here's the scene this cookbook is about. Your personal agent runs on OpenClaw. On Monday you message it on WhatsApp: "the dentist moved to Thursday". On Wednesday you ask it on Telegram: "what's my week look like?" It knows about the dentist. Not because the two chats share a transcript (they don't), but because both channels write to and read from the same Korely memory.

That's the whole trick: the channel is ephemeral, the memory is not. One memory store, one entity graph, one set of facts. Every surface your agent lives on sees the same brain.

Everything in this recipe runs over the Korely REST API or SDK. Install korely-memory, set your kor_live_ key once, and every channel your agent runs in writes and reads from the same memory. No per-channel configuration. There is no plugin to install.

Setup: two steps

You need a Korely account and an API key. Get started in the quickstart. Then install the SDK once, wherever your agent runs:

agent setup zsh
$ pip install korely-memory

$ export KORELY_API_KEY=kor_live_...

From that moment, every channel your agent bridges, WhatsApp, Telegram, Discord, Slack, Signal, iMessage and the rest, talks to the agent, and the agent reads and writes the same shared memory. The memory is attached to the agent, not to the chat surface. Add a new channel next month and it inherits everything the agent already knows.

What flows where

The Monday-to-Wednesday scene, as actual tool calls:

Monday · WhatsApp

"Dentist moved to Thursday"

  • One message, one channel
  • Chat history stays on WhatsApp

Korely

add()

  • Memory stored in Korely
  • Fact extracted into the graph

Wednesday · Telegram

"What's my week look like?"

  • Different channel
  • No shared transcript

Korely

get_context()

  • Active typed facts, assembled
  • Contradictions resolved

Answer

It knows about the dentist

  • Context from Monday, surfaced Wednesday

The Wednesday read is a get_context() call: Korely assembles the active typed facts for the entity into one ready-to-prompt block, with contradictions already resolved. Reads are retrieval, not generation. No generative model composes output on the read path; your agent's own model does the reasoning on what comes back. Fact assembly is a deterministic lookup, typically under 50 ms, so the memory lookup never becomes the slow part of a chat reply.

Interactions to try

The recipes are prompt-level: you say things to your agent, the agent decides which SDK or REST calls to make. Three to start with, in any channel:

1. Teach it something

"Remember that Marta prefers morning meetings."

The agent calls add() and gets a confirmation back:

add() python
from korely_memory import Korely

korely = Korely()  # reads KORELY_API_KEY from env
korely.add(
    "Marta prefers morning meetings",
    agent_id="personal-assistant",
    user_id="me",
)

On the Korely side, the write path does the heavy lifting: the memory is embedded, entities are extracted on our own infrastructure, and a typed fact, (Marta, prefers, morning meetings), lands in the graph with bi-temporal validity. It is queryable from every channel until it is contradicted or you forget it.

2. Ask it back, anywhere

"What do you know about Marta?"

The agent calls get_facts() filtered to the entity Marta and gets back a flat list of her active typed facts. For a broader "what's my week look like?" recall, the agent reaches for get_context() instead, the moat read path, which assembles the relevant active facts into a ready-to-prompt block. Here we want the precise per-entity facts:

get_facts() python
facts = korely.get_facts(entity="Marta")

# flat list of typed fact triples, active only by default.
# Attribute access (dataclasses), and the verb is normalized:
# "prefers" is stored as predicate "likes", raw verb kept in predicate_raw.
#   facts[0].subject          -> "Marta"
#   facts[0].predicate        -> "likes"
#   facts[0].predicate_raw    -> "prefers"
#   facts[0].object           -> "morning meetings"
#   facts[0].valid_from       -> "2026-06-08"
#   facts[0].invalid_at       -> None   (None = still active)
# Superseded facts (invalid_at set) are hidden by default.
# For facts grouped by family, use get_profile() instead.

Facts are bi-temporal: if you later say Marta switched to afternoons, the old fact is superseded, not deleted, and the agent only sees the current one. Same answer on Telegram, Discord, or Signal, because it's the same memory. And because the read is a deterministic lookup with no AI call in the path, it costs nothing and returns in milliseconds.

3. Hand work to your future self

"Save this article draft for me to review."

The agent calls add() with the article draft as content. Then you open the Korely app on your laptop and the memory is just there, a note you can read, edit, or delete. The memory store is shared between you and your agent: the agent writes from WhatsApp, you polish in the editor, the agent sees your edits on the next read. Korely is the only memory layer where your agent's memory is also something you can open and work on yourself.

Privacy and the off switch

The agent accesses memory scoped to your account only via a kor_live_ key. There's no shared corpus, no cross-account leakage by construction. Two controls matter day to day:

  • Revoke anytime. Delete or rotate your API key and every channel loses memory access at the same instant, because they all authenticate with the same key.
  • Forget propagates everywhere. The Memory Panel in the app shows every fact Korely holds about you, and lets you edit or forget each one, a built-in forget flow you control. A fact you forget stops reaching every channel instantly, because there is only one memory to forget it from.

Everything is stored EU-hosted, on our own infrastructure (Postgres + pgvector), and your memory is always accessible via the app or the REST API.

Recall is agent-driven, by design

Every memory access is an explicit SDK or REST call. The agent decides when to read or write, and in practice modern models reach for memory reliably on explicit asks ("remember…", "what do you know about…"). Korely never silently captures your messages or injects memory into a reply on its own. Each call is explicit in your agent's code, so you always know what was read and what was written.

Where to go next

  • OpenClaw integration guide: the full setup for routing channel messages through your agent.
  • Temporal facts: how contradiction detection keeps "current" answers current when your life changes.
  • Human in the loop: the Memory Panel and why we think the end user should always be able to see and edit what their agent remembers.
  • SDK reference: all methods, parameters, and response shapes for korely-memory.

Built something on this? We want to see it. Email [email protected]. Cross-channel personal agents are exactly the use case we built Korely for, and real setups shape the product.