How isanna runs.
One architecture under the hosted products, and the retrieval design behind the memory substrate.
The shared path
client
│
▼
Cloudflare DNS · CDN / proxy
│
▼
Fly.io per-product application containers
│
▼
Postgres schema-isolated per productOne path to learn rather than one per product: a service grows without being rebuilt, and a new product inherits the route instead of inventing it. Builder is the exception — it is a command-line workflow with nothing hosted at all.
Data and isolation
Each product owns its own schema and connects with its own login role that cannot bypass row-level security. Where a table belongs to a user, the ownership check is a policy in the database rather than a condition someone has to remember to write.
Not every table is owned by a user, and those are scoped by the application instead — a choice each migration records in writing, so which mechanism protects which table is answerable rather than assumed.
Retrieval
Memory for coding agents is a retrieval problem before it is a storage problem. Vector search alone, over a store that keeps growing, returns what is similar rather than what is relevant — and cannot tell a current decision from the one that superseded it. The design follows from that, and it is built in stages.
- Running
- Hybrid search — lexical and vector together — with mxbai-embed-large producing the embeddings, then a reranker over the merged candidates. First-stage retrieval is allowed to be generous, and the reranker decides what actually surfaces.
- Running
- The embedding model and its dimension are decoupled from the storage schema, so the model can be replaced without a migration.
- Next
- Query rewriting, and contextual retrieval — embedding a chunk together with the context that makes it readable on its own.
- Later
- Hierarchical summary trees, graph retrieval and late-interaction models such as ColBERT. These are strong where a corpus has heavy structure or needs reasoning across documents; this one is neither yet, so they sit behind the work above rather than in front of it.
The sequence is the decision worth explaining: each stage has to earn the index it adds and the latency it spends, so the cheap wins land before the elaborate ones.