KodaMemory
A shared knowledge graph for your agents. As sessions work, they record durable project knowledge — decisions, gotchas, where-things-live pointers — as linked nodes. When a new session starts, Koda recalls the memory relevant to its task, not just the last few notes, so what your agents learn compounds instead of getting relearned.
koda_memory_note, koda_memory_query) and graph-based recall are part of the 7-day free trial and stay on with Pro.Overview
CLI agents are turn-based and forgetful: each new session starts cold, and anything a previous agent figured out — a subtle build flag, why a decision was made, which file really owns a behavior — is gone unless someone wrote it down. The legacy fix was a flat list of the last handful of "learnings," surfaced by recency. That doesn't scale: the note you need is rarely one of the last five.
KodaMemory replaces recency with relevance. Knowledge is stored as a graph of typed nodes connected by typed relationships, and recall ranks that graph against the task in front of the agent. The result is that a session picks up the decisions and gotchas that actually bear on its work — with the links between them attached — the moment it starts.
.koda/coord/ folder, two different jobs.The graph model
Everything in KodaMemory is either a node (a thing worth remembering) or an edge (a relationship between two things). Both use a small, fixed vocabulary so the graph stays consistent and dedupable.
Node types
| Type | What it captures |
|---|---|
component | A subsystem or module — a coherent part of the codebase. |
file | A where-things-live pointer — the file that really owns a behavior. |
decision | Why something was done a particular way. |
gotcha | A pitfall, sharp edge, or hard-won fix. |
entity | An external service, API, or concept the project touches. |
task | A unit of work, linked back to the board card it came from. |
Edge relations
Edges connect nodes by name using a closed set of relationships, so the graph reads like a set of plain-English facts:
| Relation | Meaning |
|---|---|
depends_on | A needs B to work. |
relates_to | A and B are connected (the general-purpose link). |
caused_by | A gotcha or failure was caused by B. |
supersedes | A replaces B — B is now obsolete (see compaction). |
implements | A implements B (e.g. a file implements a decision). |
blocks | A blocks B from proceeding. |
learned_from | A was learned from B (a card, an investigation). |
Writing memory
There are two ways knowledge enters the graph.
Structured notes
An agent calls koda_memory_note to assert a node — its type, a stable name, a one- or two-sentence summary, optional tags, and optional edges to other nodes. This is the right tool when the knowledge has a clear subject and/or relates to other things.
{
"kind": "node",
"type": "gotcha",
"name": "stripe portal needs a live config id",
"summary": "The billing portal 500s until a live billing_portal config is created in the dashboard.",
"tags": ["stripe", "billing", "portal"],
"cardId": "cmr1o9bdm-4-985160",
"by": "4",
"ts": 1782886553745
}
Quick learnings
koda_record_learning is the lightweight path: a one-line text learning with no subject or edges. It's ideal for a fast "note to future sessions." Under the hood Koda still turns it into a gotcha node, so quick learnings flow into the same graph as everything else.
Recall & ranking
Memory is only useful if the right piece shows up at the right time. KodaMemory surfaces knowledge two ways.
At session start
On the first prompt of a session, Koda ranks the whole graph against the task (the prompt plus the card title) and injects the top matches — with their one-hop relationships — straight into the agent's context. It's the same hook that auto-announces the card, so it's automatic and needs no tool call.
Relevant project memory (KodaMemory knowledge graph):
- stripe portal needs a live config id [gotcha]
caused_by → missing billing_portal config
- surface the real Stripe error, not the wrapper [decision]
- supabase/functions/portal/index.ts [file]
implements → surface the real Stripe error
Ranking is deterministic and dependency-free — a keyword score over each node's name, tags and summary, boosted by how often the node has been mentioned and how recently it was seen. Nodes that have been superseded are penalized, and if nothing matches the query, Koda still surfaces the most important recent nodes so a session is never handed an empty slate.
Mid-task queries
When an agent wants to look something up while working — before it investigates a subsystem or changes a behavior — it calls koda_memory_query with a natural-language query and an optional type filter. It returns the matching nodes with their summaries, tags and one-hop edges, ranked the same way.
{
"ok": true, "count": 1, "matched": true,
"nodes": [
{
"id": "n_a1b2", "type": "gotcha",
"name": "stripe portal needs a live config id",
"summary": "The billing portal 500s until a live config is created.",
"tags": ["stripe", "billing"], "mentions": 3,
"status": "active",
"edges": [{ "rel": "caused_by", "to": "missing billing_portal config" }]
}
]
}
Memory tools reference
KodaMemory adds three tools to the coordination server. Agents call them by their fully-qualified MCP names (e.g. mcp__koda-coord__koda_memory_note); they're documented here by their short names.
Adds a node to the graph, plus any edges from it. The dedup key is (type + normalized name), so re-asserting the same node merges tags, unions its card provenance, and bumps its mention count rather than duplicating it.
component, file, decision, gotcha, entity, or task.{ to, rel } relationships to other nodes.Searches the materialized graph and returns matching nodes with their summaries, tags, mention counts, status and one-hop edges — ranked by relevance plus importance and recency. Read-only.
Records a one-line learning for future sessions. Kept in an auditable learnings.jsonl log and also emitted as a gotcha node so it flows into the graph. Not gated — it keeps working even when your entitlement can't be verified.
Architecture & storage
KodaMemory is built the same way as the rest of coordination: a zero-dependency server that only appends, and a single writer in Koda that materializes. That split is what keeps many agent panes writing concurrently without locks or corruption.
| File | Written by | Holds |
|---|---|---|
memory-events.jsonl | each pane's MCP server (append-only) | The source of truth — one node/edge event per line. |
graph.json | Koda main (single writer) | The materialized snapshot: merged nodes and edges with rankings. |
graph-cursor.json | Koda main | Byte offsets of what's already been materialized, for fast polling. |
Agents never write graph.json directly — they only append events, which is race-safe across processes. Koda's main process tails the event log on each presence poll and rebuilds the graph: it merges duplicate assertions, upserts edges, recomputes mention and recency rankings, and marks superseded nodes. Every node carries its provenance — the pane that authored it and the board cards it traces back to — so the memory is auditable, not a black box.
.koda/coord/. There's no database to run and no service to reach.Dedup & compaction
Left alone, an append-only log grows forever. KodaMemory keeps the graph tight in three ways:
- Dedup on write. Nodes are keyed by
hash(type + normalized name)and edges by(from · rel · to). Re-asserting merges instead of duplicating — trivial spelling and whitespace differences collapse to one node. - Supersede, don't delete. Marking a node obsolete (a new node with a
supersedesedge) flips its status to superseded. It stays in the graph for history and audit, but its recall score is heavily discounted, so the living graph never contradicts itself. - Log compaction. When the event log passes a size threshold, Koda rewrites it as one snapshot event per surviving node and edge, folding in the aggregated mentions and timestamps. The file's size is then bounded by the number of distinct things you know, not by how long you've been recording them. The rewrite is guarded so it never races a concurrent append.
Privacy & tiers
KodaMemory inherits coordination's stance: local files, no backend, no proxy.
- The entire graph lives in the gitignored
.koda/coord/folder in your workspace. Nothing is uploaded, synced, or telemetered — there is no Koda backend to send it to. - It rides the local MCP tool server the CLIs already call; it never touches a provider credential or OAuth token.
Access gating is enforced at every layer and fails closed — if your trial or subscription can't be verified, the graph features pause and only the ungated basics keep working:
| Capability | Unverified access | Trial & Pro |
|---|---|---|
koda_record_learning | ✓ | ✓ |
| Last-few learnings at session start | ✓ | ✓ |
koda_memory_note / koda_memory_query | — | ✓ |
| Graph materialization & relevance recall | — | ✓ |
| Memory graph view in the Tasks panel | — | ✓ |
KodaMemory is active throughout your trial and on Pro. Everything it records lives locally in .koda/coord/, so nothing is lost between sessions — or between the trial and a subscription.
Limitations
KodaMemory is deliberately simple in v1. A few honest edges to know about:
Keyword ranking, not embeddings
Recall scores on keywords, tags and mentions — not semantic similarity. It's fast and dependency-free, but a query has to share words with a node to match it. Semantic search is on the roadmap.
Grows by distinct nodes
Log size is bounded by compaction, but the count of distinct nodes has no hard cap yet. In practice this stays small; heavy pruning of stale links is a future refinement.
Recall can lag a beat
The graph is rebuilt on Koda's presence poll, so a note written this turn may take one poll cycle to appear in a query. Session-start recall always reads the freshest snapshot.
Troubleshooting
Memory tools return "pro-required"
koda_memory_note and koda_memory_query need an active trial or Pro subscription. Sign in and make sure it's active; the gate fails closed, so a login that can't be verified is treated as unentitled.
A note isn't showing up in queries
The graph materializes on a poll cycle — give it a moment. Confirm coordination is On for the workspace, since memory rides the same bus.
Two notes I meant as one are separate
The dedup key is the node name. Name the same thing the same way and future assertions merge; small differences in wording create distinct nodes.
Old, wrong knowledge keeps surfacing
Don't delete it — supersede it. Write the corrected node with a supersedes edge to the old one, and the old node drops down the rankings while staying in the audit trail.
