Infoguana
A cross-project memory for LLM coding agents — typed-graph notes, hybrid retrieval, and MCP integration.
View on GitHubOverview
Iguanas are ectotherms — they rely on external heat to function. Infoguana (info + iguana) gives LLM agents the same kind of external lifeline: a shared memory that lives outside any single session or repository. It is a typed graph of short notes with hybrid retrieval, designed to feed a coding agent only the slice of memory relevant to the current turn — and to carry hard-won lessons from one project into the next.
Static Rule Files
CLAUDE.md and editor rules load every byte every turn and cap out before they can hold much. They are per-repo, so nothing crosses a project boundary.
Chat-History RAG
Mainstream agent-memory tools are tuned for conversation recall, not curated domain knowledge. Flat top-k lookups, with no locality, typing, or lifecycle.
The Rediscovery Tax
Without shared memory, every new session re-learns gotchas that were already solved months ago — in a different repo, by a different agent.
The thesis: memory should be cross-project by default, typed with a lifecycle, and retrieved by a budgeted graph walk from the current project node — not a flat top-k lookup. Pay the context cost once at session start, then drill into the graph on demand.
The token economics
The cost model is the argument. What separates these approaches is not how much they can store — it is what they charge you per turn to keep it available.
| Approach | Cost | What that means in practice |
|---|---|---|
| Static rule files | O(store × turns) |
Every byte is re-sent on every turn, so the store cannot grow without making each turn more expensive. |
| Top-k RAG | O(k × turns) |
Cheaper, but pays again each turn and retrieves without locality, typing, or lifecycle. |
| Infoguana | O(budget) once + O(search) |
One budgeted pack at session start, then only the explicit lookups an agent chooses to make. |
Breadth, quality, and cost all move the same direction: a larger corpus makes the graph walk better without making the session opener bigger.
The full corpus as a typed graph — each node is a note (shape and color encode its type), large pink diamonds are projects, and edges are explicit typed links plus IDF-weighted tag co-occurrences.
How It Works
Every note carries one of nine types — plus unsorted for anything not yet classified — and the type changes how the note is surfaced. Tags are curated by the agent at write time, and a tag_suggest call ranks existing vocabulary first so tags don't drift into one-off singletons.
Memory
An accumulated, self-contained fact — the actionable substance, captured with the how and why, not just a category label.
Feedback
Sticky guidance the agent should re-read — corrections and confirmed working patterns that shape how it behaves.
Plan / Task
Tracked work with a lifecycle (not started → pending → complete). Pending items pin to the top of every context pack.
Reference
A pointer to substance that lives elsewhere — a dashboard, a design doc, an external resource — loaded on demand.
Rule
Injected, not retrieved. Rules are pinned before the turn begins and are exempt from the note budget, so following a hard constraint never competes with recalling a memory. Two scopes: global rules apply everywhere, project rules only in their own repo.
Skill
A procedure stored as a note rather than a per-tool config file. The session pack carries a one-line manifest — name and trigger condition — and the agent fetches the body only once it decides the skill applies.
Hybrid, Budgeted Retrieval
search fuses BM25 lexical scoring (FTS5) and cosine similarity over embeddings (sqlite-vec) into a single ranking using Reciprocal Rank Fusion — it combines the two result lists by rank rather than by score, because a BM25 score and a cosine similarity are not on a common scale and any attempt to weight one against the other directly is a fudge factor in disguise. Hits come back as previews — haiku-sized one-to-five-line summaries generated at write time — so an agent can triage twenty results for a few hundred tokens and pull full bodies only for the notes worth quoting. Previews are explicitly for triage, not citation.
Session-Start Context Packing
MCP lets an agent reach Infoguana on demand, but it has to remember to ask. To skip that cold start, a SessionStart hook packs the agent's very first turn with a layered, token-budgeted context pack:
The layers arrive in this order, and the order is deliberate — everything the agent must obey is delivered before anything it merely might find useful:
- Available skills — a manifest listing every skill in scope as a single line: its name and the trigger condition its author wrote. Bodies are not sent, because a skill document runs several thousand tokens and three of them would exhaust the whole budget before a memory loaded. The agent reads the menu, decides one applies, and fetches it by id.
- Global-scope rules — cross-project guidance the agent must follow everywhere, pinned with full bodies.
- Project-scope rules — standing constraints tagged to the current repo.
- Pending plans and tasks — outstanding tracked work for this project, rendered in full so the first thing an agent sees is what was already underway.
- Project memories, as previews, filling the remaining budget by IDF-weighted BFS relevance from the project node — tag edges are weighted by inverse document frequency, so a tag sitting on half the corpus pulls far more weakly than a rare one, and past the budget it is dropped.
Termination is a token budget, not a hop count, which is what lets retrieval degrade gracefully as the corpus grows — a bigger corpus makes the walk more selective rather than making the opener longer.
Measured on a live 933-note store spanning 17 projects, a session pack runs a median of 10.8k tokens. Two separate mechanisms get it there, and they are worth keeping apart:
- Selection — the graph walk surfaces a median of 25 notes out of 933. Relevance is decided before anything is spent, so a store ten times this size does not make the opener ten times longer.
- Preview compression — those 25 notes cost 1.1k tokens as previews against 11.7k at full body, roughly 10×. Previews are triage-grade by design: the agent reads summaries, decides what matters, and pays for full bodies only on the notes it actually quotes.
What the pack is not is a compressed copy of the store. Its largest component is the pinned rules at 8.4k tokens — full bodies, deliberately exempt from the budget, because a constraint the agent never sees is worse than a memory it never sees. The skill manifest is exempt for the same reason and costs about 1k, since a capability the agent is never told about is one it does not have. So the honest summary is that the memory half of the pack is heavily selected and summarised, while the instruction half is sent whole and on purpose.
Hybrid Search & Filtering
The same hybrid ranking that backs the MCP search tool is exposed through an HTMX web UI, so notes can be captured from a phone or laptop and explored from any browser. A text query combines with faceted filters for type, tag, and status across the entire cross-project corpus, and each hit expands to the full rendered note — body, tags, and typed edges — inline.
Hybrid search with faceted filtering across every project — each hit expands to the full rendered note, including its tags and typed-edge neighbors.
The Typed Graph
Notes are nodes; the edges between them carry meaning. Six typed-edge relationships — implements, supersedes, references, caused_by, bundled_with, and prerequisite_for — let an agent walk design provenance rather than guess at it.
- Traversal.
traverse(start_id, edge_type)walks the graph for multi-hop questions;search(..., include_edges=True)attaches each hit's neighbors inline, so a plan-or-decision lookup lands in a single call. - Superseding is directional, and retrieval respects that.
supersedesis the one edge whose two directions do not mean the same thing, so it is not weighted the same both ways. Walking replacement → stale is de-rated to0.5, well under the1.2an explicit edge normally carries, so retrieval never routes into superseded material at premium weight; walking stale → replacement keeps the full1.2, because an agent that lands on an outdated note should be pulled straight to whatever replaced it. - Non-destructive updates. Every edit snapshots the prior state and bumps a version;
history(id)returns the diffs, and edges survive parent deletes via tombstones. - Design history as a notebook.
export(start_id)walks the typed-edge graph from a root plan in both directions, pulls in every linked PR, and renders the whole arc — original idea, the plan that implemented it, the decisions it superseded, the bugs it caused, the lessons learned, the PRs that shipped — into one markdown engineering notebook.
Cross-Project Memory
The payoff is what happens across repository boundaries. An agent dropped into any project gets the right few thousand tokens of context on its first turn, can drill into the graph for design intent, and can capture what it learned without inventing new vocabulary — and the next session, possibly in a different repository, sees that knowledge surface again.
Cross-project recall in action: while working in one repo, the agent surfaced a pull request from a different project — the graph walk over shared tags and semantic neighbors pulled it into the current task's context unprompted.
Why it matters: the whole design premise of a shared store (versus per-project memory files) is that knowledge from one project surfaces in others when it is relevant — without anyone having to remember it exists.
Architecture & Stack
Infoguana is deliberately a single-file database and a small service — no external search cluster, no managed vector store. The whole system runs from one Docker Compose stack on a home server.
FastAPI
Serves the REST API, the HTMX capture UI, and an MCP Streamable-HTTP endpoint from one async app.
SQLite + vec + FTS5
sqlite-vec holds the embeddings for semantic search; FTS5 provides BM25 lexical scoring. Hybrid retrieval on a single file.
MCP Server
Any MCP-capable agent calls Infoguana over the Model Context Protocol, secured with a per-instance bearer token. Claude Code and Codex both ship with an installer.
Pluggable Classifier
Note-type classification and write-time preview generation run asynchronously, off the request path. The backend is either the Claude CLI or any OpenAI-compatible endpoint — LM Studio, Ollama, vLLM, OpenAI — so a headless install is not tied to one vendor.
Harness Portability
Agent memory is usually written in whatever format one vendor's tool happens to read — a CLAUDE.md, an editor rules file, a proprietary memory store. Switch tools and the memory does not come with you; run two tools and you maintain the same knowledge twice.
Infoguana keeps the protocol, the rules, and the notes in SQLite behind an MCP endpoint, so none of it is expressed in any harness's prompt format. What each client needs is a thin installer that registers a session hook and points it at the server:
- Same memory, different agents. Claude Code and Codex read the same rules, the same skills, and the same notes from one store. A memory written by one is readable by the other on its next session.
- Portable by construction, not by adapter. The session pack is plain text assembled server-side, so supporting a new client means teaching it to fetch and inject that text — not re-encoding the corpus.
- The classifier is swappable too. Pointing it at an OpenAI-compatible endpoint removes the last dependency on a specific vendor's CLI being installed on the host.
Why it matters: memory that lives in one vendor's file format is a bet on that vendor. Keeping it in a database behind an open protocol means the store outlives whichever agent is currently fashionable.
MCP Toolset
Agents interact with Infoguana entirely through Model Context Protocol tools, grouped by purpose. get_skill resolves a skill the way it is actually invoked — by name, after a context summary has dropped the ids, or when someone types /some-skill — since ids are not portable across installs:
Notes
search·similar·recentget·get_many·contextadd·update·deletehistory·tag_suggest
Skills
get_skill- manifest arrives via
context
Plans
plansplan_complete
Graph
link·unlinktraverseinfer_edgesexport
Integrations
- GitHub issues & PRs (read)
- Gated issue / comment writes
- Allowlisted filesystem read
Infoguana is open source under the MIT license, with a one-command Docker deploy and installers that wire it straight into Claude Code or Codex.
View on GitHub