Korely

CLI

The Korely memory API from a shell, a fraction of the tokens. The CLI is what you reach for when you already know what to pull: cron jobs, CI prep, editor commands, shell pipelines, and any workflow where you drive the query yourself instead of waiting for an agent to.

Each subcommand maps to one REST endpoint and the matching SDK method, so anything you learn on one surface transfers to the other: memories (add, search, list, get, update, history, delete), facts (read, write, correct, forget), context and profiles, end users and agents, batch import, the audit log, and the account itself. Output is human-readable by default and JSON with --json when you want to script. The same three scoping keys (--user-id, --agent-id, --run-id) mean the same thing here as in the SDK.

Install and authenticate

The CLI ships inside the Python package. One install gives you both the korely_memory import and the korely command. Get a key with one command: korely init --agent mints a free Hobby key and saves it to ~/.korely/config.json, so every command just works. Key precedence is --api-key > KORELY_API_KEY > ~/.korely/config.json, and the API address follows the same order: --base-url > KORELY_BASE_URL > the config file.

korely cli zsh
# Install: gives you both the Python package and the korely command
$ pip install korely-memory

$ korely --version
korely 0.1.18

# Sign up: mint a free Hobby key, saved to ~/.korely/config.json
$ korely init --agent
You're set: a free hobby key was minted and saved to /Users/you/.korely/config.json (chmod 600).
  key     kor_live_…a1b2
  tier    hobby    region eu-hel1
  quotas  250 writes / 25000 queries per month · 2 agents

Next:
  korely add "I am using Korely"
  korely search "am I using Korely"

# Already have a key? Set it in the environment instead
$ export KORELY_API_KEY=kor_live_...
$ korely auth
Authenticated  key kor_live_…a1b2  base https://api.korely.ai
tier hobby  region eu-hel1  scopes memories:read, memories:write

# Or pass the key inline for one-off commands
$ korely search "any topic" --api-key kor_live_... --limit 3

Command map

Every subcommand maps to a REST endpoint and the matching SDK method. Scoping options use --dashes; positional arguments (query text, memory ID) are plain words.

CommandSDK equivalentWhat it does
korely init --agent Korely.init_agent() Mint a free Hobby key and save it locally. The one command that needs no key. korely init --api-key kor_live_... saves a key you already have instead; --force replaces a key already saved.
korely auth korely.ping() Check that the key works: prints the masked key, the API address, the tier, the region and the scopes. korely ping prints the same without the key and address.
korely add "..." korely.add() Write a memory. Graph + temporal extraction included.
korely context "..." korely.get_context() Assembled, prompt-ready context block. The recall path that uses the typed facts, reach for this first.
korely facts korely.get_facts() Bi-temporal typed facts as a flat list. Two-stage contradiction resolution included.
korely search "..." korely.search() Semantic vector search over the raw memories.
korely profile korely.get_profile() Assembled profile of one end user.
korely get <id> korely.get() Full content of one memory by ID.
korely users korely.users() End users you have stored data for.
korely delete <id> korely.delete() Forget one memory (audited).
korely delete-all --user-id ... --yes korely.delete_all() GDPR forget: every memory + fact for one end user.
korely list korely.get_all() The memories of a scope, newest first (--limit up to 200, --offset).
korely update <id> "..." korely.update() Replace a memory's text and re-run extraction. --expected-updated-at refuses the edit (stale_write) if the memory changed since you read it.
korely history <id> korely.history() A memory's timeline, and every fact it produced.
korely events korely.events() Which writes are still being extracted (--status processing|ready|error).
korely agents korely.list_agents() This project's agent namespaces, and the agent cap.
korely delete-agent --agent-id ... --yes korely.delete_agent() Purge one agent namespace of this project, freeing its slot.
korely add-fact S P O korely.add_fact_triple() Write a typed fact directly, no extraction; the contradiction check still runs.
korely correct-fact <id> korely.correct_fact() Supersede a current fact with a corrected one (--subject, --predicate, --object).
korely forget-fact <id> korely.forget_fact() Close a fact (--at the date it stopped being true); it stays in history.
korely batch <file> korely.batch() Bulk import up to 500 memories from a JSON array, {"memories": [...]} or JSON Lines (- reads stdin).
korely batch-status <job_id> korely.batch_status() Poll an import job.
korely audit korely.audit() The audit trail of this key's project, newest first (--action, --since, --until; --all to export every page).
korely delete-account --yes korely.delete_account() Delete the account of this key for good (Cloud, accounts made by init --agent), and remove the key from the config file.

Write a memory and search it

Scope every call with --user-id (your end user, unlimited on every tier) and --agent-id (your application's namespace). Filters are additive: a search scoped to a --user-id never sees another user's memories.

korely cli zsh
# Write: graph + temporal extraction included in the call
$ korely add "Prefers invoices as PDF, replies fastest before 10am CET" \
    --user-id customer-4812 --agent-id billing-bot
stored  mem_8f3a21c...

# Facts are extracted asynchronously: typed triples land a few seconds later
# Read it back, scoped to the same end user
$ korely search "invoice preferences" --user-id customer-4812
[0.930] Prefers invoices as PDF, replies fastest before 10am CET
        mem_8f3a21c...
[0.810] Asked for a consolidated monthly invoice, finance@ in CC
        mem_3b1d90a...

Reads are retrieval, not generation. Most read subcommands are deterministic SQL lookups over your typed facts, zero AI calls. search embeds the query (a fraction of a hundredth of a cent) and retrieves by semantic vector similarity. No generative model composes output on the read path; the model in your pipeline does the reasoning. That is why read quotas are an order of magnitude more generous than write quotas. Full detail in Architecture.

Query facts

korely facts returns typed (subject, predicate, object) triples with bi-temporal validity as a flat list. A facts read is deterministic and makes no model call. Works on every tier, including the free Hobby plan. For the same facts grouped by predicate family, use korely profile.

korely cli zsh
# Current state only: invalidated facts are excluded by default
$ korely facts --user-id customer-4812
  customer-4812 · replies_fastest_before · 10am CET [from 2026-06-11]
  customer-4812 · prefers_format · PDF [from 2026-06-11]

# JSON for scripts: pipe straight into jq (facts are under .facts)
$ korely facts --user-id customer-4812 --json \
    | jq -r '.facts[] | "\(.predicate): \(.object)"'
replies_fastest_before: 10am CET
prefers_format: PDF

Add --include-invalidated to see the full history, with superseded facts included. How invalidation works, and why the stale fact never reaches your agent by default, is covered in Temporal facts.

Search, retrieve, pipe

The pattern for "answer a question from memory" from a shell: assemble a compact, prompt-ready block with context, the recall path that stitches together your end user's active typed facts, then hand it to whatever model you already run, local or hosted. Reach for raw search when you want the underlying memories instead of the assembled view. Either way you pull exactly what you need instead of letting an agent explore, and the same answer costs a fraction of the tokens.

korely cli zsh
$ korely search "EU pricing decision" --user-id alice --limit 3
[0.920] Approved the move to the 50 euro per month plan, effective July.
        mem_9f2c1a...
[0.870] Plan change approval signed by finance.
        mem_3b1d9...
[0.810] Q2 budget retro: EU contracts renewed.
        mem_7a4c2...

$ korely get mem_9f2c1a
mem_9f2c1a  (2026-06-11T09:12:44)
Approved the move to the 50 euro per month plan, effective July.
Marco signs off on the renewal quote; finance updates the forecast...

# Hand a compact context block to a local model
$ korely context "EU pricing decision" --user-id alice | ollama run llama3.1 "summarize the decision"
The team approved moving to the 50 euro per month plan, effective
July, with Marco signing off on the renewal quote.

Scoping and output flags

FlagApplies toMeaning
--user-id add, search, context, facts, profile, delete-all Your end user's identifier. Free-form, unlimited on every tier.
--agent-id add, search, context, facts, profile, users Your application's namespace. One app, one --agent-id.
--run-id add, search, list, add-fact One session. Useful for episodic recall inside a single run.
--timestamp DATE add ISO date the events happened, for a backfill: the facts take it as valid_from.
--limit N search, facts, users, list, events, agents, audit Result count: for search the server's default, 15 (max 50); 50 for facts, users, list, events and agents; 100 for audit (1000 with --all). Keep it small; you are paying for your own model's context.
--token-budget N context Size of the assembled block, default 800, from 50 to 8000. At 400 and above the block opens with a short note for the reader model.
--api-key all commands Override KORELY_API_KEY for this call.
--base-url all commands Override the API base URL (default https://api.korely.ai).
--json all commands JSON on stdout instead of human-readable text. Built for jq, scripts, and CI.
--entity facts Filter facts where this string appears as subject OR object.
--subject facts Filter facts by subject only (more precise than --entity).
--predicate facts Filter facts by one exact predicate, for example subscribes_to.
--family facts Predicate family to filter by. Each new relation gets one of the families once per project; prefer --entity or --subject when you are not sure which one.
--as-of DATE facts, profile Point-in-time query. Returns only facts valid on that ISO date.
--include-invalidated facts Include superseded facts in output. Off by default.
--yes delete-all Confirm the irreversible erasure. Without it nothing is deleted.

A worked example for scripts: a cron job that dumps open action items every Monday, ready for any pipeline.

Terminal window
# crontab: every Monday at 07:00
0 7 * * 1 korely search "open action items" --user-id team --json > /var/data/weekly.json

End-to-end: onboard, enrich, and query a customer

This example walks the full lifecycle of one end user from a shell: write memories during onboarding, extract and inspect the typed facts, search by topic, assemble a prompt-ready context block, and erase everything on request. Each step is a single command.

end-to-end zsh
# ── 1. Authenticate ───────────────────────────────────────────────
$ export KORELY_API_KEY=kor_live_...
$ korely auth
Authenticated  key kor_live_…a1b2  base https://api.korely.ai
tier hobby  region eu-hel1  scopes memories:read, memories:write

# ── 2. Store onboarding context ───────────────────────────────────
$ korely add "Works at Northwind Hosting as head of infrastructure." \
    --user-id customer-4812 --agent-id support-bot
stored  mem_065290ddd6184f3c849d2661b904ab42

$ korely add "Northwind Hosting costs 50 euro per month." \
    --user-id customer-4812 --agent-id support-bot
stored  mem_5ed6d938b8d5440a8926a073ce101273

# ── 3. Write a contradicting fact ─────────────────────────────────
#    Facts extract asynchronously, a few seconds after each write;
#    the old price is superseded once the new one lands.
$ korely add "Northwind Hosting now costs 75 euro per month after the upgrade." \
    --user-id customer-4812 --agent-id support-bot
stored  mem_7101bf8975bd43e9ba537d65e847eead

# ── 4. Inspect current typed facts ────────────────────────────────
$ korely facts --user-id customer-4812 --subject customer-4812
  customer-4812 · role · head of infrastructure [from 2026-06-11]
  customer-4812 · works_at · Northwind Hosting [from 2026-06-11]

$ korely facts --user-id customer-4812 --entity "Northwind Hosting"
  Northwind Hosting · costs · 75 euro per month [from 2026-06-11]
  customer-4812 · works_at · Northwind Hosting [from 2026-06-11]

# ── 5. History: the old price is closed, not deleted ──────────────
$ korely facts --user-id customer-4812 \
    --entity "Northwind Hosting" --include-invalidated
  Northwind Hosting · costs · 75 euro per month [from 2026-06-11]
  Northwind Hosting · costs · 50 euro per month [from 2026-06-11] (superseded 2026-06-11)
  customer-4812 · works_at · Northwind Hosting [from 2026-06-11]

# ── 6. Semantic vector search ─────────────────────────────────────
$ korely search "plan pricing" --user-id customer-4812 --limit 3
[0.654] Northwind Hosting costs 50 euro per month.
        mem_5ed6d938b8d5440a8926a073ce101273
[0.638] Northwind Hosting now costs 75 euro per month after the upgrade.
        mem_7101bf8975bd43e9ba537d65e847eead
[0.540] Works at Northwind Hosting as head of infrastructure.
        mem_065290ddd6184f3c849d2661b904ab42

# ── 7. One-call context block, ready to paste into a system prompt
#    (the note for the reader model that opens it is shortened here)
$ korely context "billing question" --user-id customer-4812
_The facts below are a compact profile of the user; the memories are the verbatim source of truth. Ground your answer in this context. [...] do not abstain when it is present._

## Known facts
- Northwind Hosting costs 75 euro per month (since 2026-06-11)
- The user works_at Northwind Hosting (since 2026-06-11)
- The user has_job_title head of infrastructure (since 2026-06-11)

## Relevant memories
_A time in square brackets [...] is the day it was said._
- [2026-06-11] Northwind Hosting now costs 75 euro per month after the upgrade.
- [2026-06-11] Northwind Hosting costs 50 euro per month.
- [2026-06-11] Works at Northwind Hosting as head of infrastructure.

(279 tokens, 6 source(s))

# ── 8. GDPR: erase one end user in full ──────────────────────────
$ korely delete-all --user-id customer-4812 --yes
forgot user customer-4812  (3 memory(ies), 4 fact(s) erased, audit aud_44c8beba9c234f3cb577e10fdd740f00)

A fact starts at the moment of the write, unless the text says when it became true and writes the year: "costs 50 euro per month since March 2026" dates the fact from March 2026, while "upgraded on June 15" (no year) or "last week" does not. None of the memories above carries a date, so every fact reads the day of the write, and step 5 shows the history with --include-invalidated rather than an --as-of date between the two prices. To date facts yourself, for example when importing history, pass the timestamp field of Add a memory (or of a batch item) through the API or the SDK, or --timestamp on korely add.

Error reference

The CLI exits non-zero and prints a one-line error on stderr. Pass --json to get a machine-readable object with a code field for scripts.

Exit / codeWhen it happensHow to fix it
401 invalid_key Key is missing, malformed, or revoked. Check KORELY_API_KEY. Rotate if needed in the dashboard.
403 agent_cap_exceeded The --agent-id is a new namespace and you are at your plan's agent limit (2 on Hobby, 10 on Developer, 100 on Team, 500 on Scale). Delete an unused agent with korely delete-agent --agent-id ... --yes (DELETE /v1/agents/{agent_id}), or upgrade your plan.
403 forbidden The key lacks the scope the command needs (memories:read or memories:write). Use a key with both scopes, or mint one in the dashboard.
404 not_found korely get or korely delete was called with an id that does not exist or was already forgotten. Verify the id with korely search first.
409 stale_write korely update --expected-updated-at was rejected: the memory changed since you read it, or the value is not the exact updated_at the API returned. Re-fetch with korely get --json and pass its updated_at (or created_at before the first edit) as it is.
409 fact_not_current korely correct-fact on a fact that is history (superseded, forgotten or ended). Correct the current fact the message names, or write the value that holds now with korely add-fact. Nothing was counted.
422 invalid_request Malformed request: a required field is missing or a value is the wrong type. Message reads <field>: Field required. Check flag spelling and required positional arguments.
429 quota_exceeded Your monthly write or query quota is exhausted. The response carries no Retry-After. Wait until the month rolls over, or upgrade your plan. Reads are an order of magnitude more generous, most scripts hit the write limit first.
429 rate_limit_exceeded Too many requests in the current minute, hour or day. Wait the seconds in the Retry-After header, then run the command again.
503 search_unavailable (the vector search did not answer), model_unavailable (a model a write needs gave no usable answer) or writes_paused (the service's daily model budget is spent; reads keep working). Nothing was written. Retry shortly; for writes_paused, after 00:00 UTC.

No overage charges, ever. At 80% of quota a quota.warning webhook fires. Past 100% there is a +10% grace window so a busy day does not break your script. Past that, commands fail with 429 until the month rolls over or you upgrade. Your bill is always exactly the tier price: Hobby free, Developer €19, Team €79, Scale €249.

Related

  • Surfaces overview: when to reach for the CLI versus the SDK versus the REST API directly.
  • SDK: the same operations from Python or Node, with typed return values and structured exceptions.
  • API reference: the REST contract the CLI calls under the hood, with full request and response shapes.
  • Temporal facts: the bi-temporal model behind korely facts and --as-of.
  • Cookbook: chatbot that remembers: a working loop using context and add.
  • Architecture: why read quotas are an order of magnitude more generous than write quotas.