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.
Subcommands mirror the REST endpoints and SDK methods, so anything you
learn on one surface transfers to the other. 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.
# Install: gives you both the Python package and the korely command
$ pip install korely-memory
$ korely --version
korely 0.1.2
# 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 ~/.korely/config.json (chmod 600).
tier hobby region eu-hel1
# Already have a key? Set it in the environment instead
$ export KORELY_API_KEY=kor_live_...
$ korely auth
✓ Authenticated key kor_live_… base https://api.korely.ai
0 end user(s) stored.
# 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.
| Command | SDK equivalent | What it does |
|---|---|---|
korely init --agent | — | Mint a free Hobby key and save it locally. The one command that needs no key. |
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. |
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.
# 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 shortly after
# 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 typically returns in under 50 ms. Works on every tier,
including the free Hobby plan. For the same facts grouped by predicate
family, use korely profile.
# Current state only: invalidated facts are excluded by default
# Predicates are normalized — "prefers" is stored as "likes" (raw verb in predicate_raw)
$ korely facts --user-id customer-4812
customer-4812 · likes · PDF invoices [from 2026-06-11]
customer-4812 · likes · replies before 10am CET [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)"'
likes: PDF invoices
likes: replies before 10am CET
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 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
| Flag | Applies to | Meaning |
|---|---|---|
--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, users | Your application's namespace. One app, one --agent-id. |
--run-id | add | One session. Useful for episodic recall inside a single run. |
--limit N | search, facts, users | Result count. Keep it small; you are paying for your own model's context. |
--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). |
--family | facts | Predicate family to filter by. The taxonomy is limited; many verbs map to other, so prefer --entity or --subject when in doubt. |
--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. |
A worked example for scripts: a cron job that dumps open action items every Monday, ready for any pipeline.
# crontab: every Monday at 07:000 7 * * 1 korely search "open action items" --user-id team --json > /var/data/weekly.jsonEnd-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.
# ── 1. Authenticate ───────────────────────────────────────────────
$ export KORELY_API_KEY=kor_live_...
$ korely auth
✓ Authenticated key kor_live_… base https://api.korely.ai
0 end user(s) stored.
# ── 2. Store onboarding context ───────────────────────────────────
$ korely add "Works at Northwind Hosting as head of infrastructure." \
--user-id customer-4812 --agent-id support-bot
stored mem_8f2c1a
$ korely add "Current plan costs 50 euro per month. Renewed on June 1." \
--user-id customer-4812 --agent-id support-bot
stored mem_b91e3d
# ── 3. Write a contradicting fact — facts extract asynchronously, ─
# and the old price is superseded once they land ───────────────
$ korely add "Upgraded to the 75 euro per month plan on June 15." \
--user-id customer-4812 --agent-id support-bot
stored mem_f4a890
# ── 4. Inspect current typed facts ────────────────────────────────
$ korely facts --user-id customer-4812 --subject customer-4812
customer-4812 · works_at · Northwind Hosting [from 2026-06-11]
customer-4812 · role · head of infrastructure [from 2026-06-11]
$ korely facts --user-id customer-4812 --entity Northwind Hosting
Northwind Hosting · costs · 75 euro per month [from 2026-06-15]
(1 superseded — run --include-invalidated to see)
# ── 5. Point-in-time: what did we know before the upgrade? ────────
$ korely facts --user-id customer-4812 \
--entity Northwind Hosting --as-of 2026-06-12
Northwind Hosting · costs · 50 euro per month [from 2026-06-01, invalid 2026-06-15]
# ── 6. Semantic vector search ─────────────────────────────────────
$ korely search "plan pricing" --user-id customer-4812 --limit 3
[0.950] "Upgraded to the 75 euro per month plan on June 15."
mem_f4a890
[0.880] "Current plan costs 50 euro per month. Renewed on June 1."
mem_b91e3d
[0.760] "Works at Northwind Hosting as head of infrastructure."
mem_8f2c1a
# ── 7. One-call context block, ready to paste into a system prompt
$ korely context "billing question" --user-id customer-4812
--- korely context (642 tokens, 3 sources) ---
[fct_b91e] Northwind Hosting · costs · 75 euro per month (from 2026-06-15)
[fct_3d0f] customer-4812 · works_at · Northwind Hosting (from 2026-06-11)
[mem_f4a890] Upgraded to the 75 euro per month plan on June 15.
[mem_b91e3d] Current plan costs 50 euro per month. Renewed on June 1.
----------------------------------------------
# ── 8. GDPR: erase one end user in full ──────────────────────────
$ korely delete-all --user-id customer-4812 --yes
forgotten 3 memories, 4 facts audit aud_3d0f 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 / code | When it happens | How 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 or upgrade your plan. |
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 | An update was rejected because another writer changed the record since you last read it. | Re-fetch with korely get and retry. Only relevant to programmatic update calls, not shell pipelines. |
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 write-quota response carries no Retry-After; the per-second rate-limit response does (a Retry-After header, in integer seconds). | 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. |
No overage charges, ever. At 80% of quota you receive an
email warning. 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 factsand--as-of. - Cookbook: chatbot
that remembers: a working loop using
contextandadd. - Architecture: why read quotas are an order of magnitude more generous than write quotas.