inode
FeaturedA Go CLI that stores notes, commands, and secrets as vector embeddings and answers natural-language questions over them with retrieval-augmented generation.
Embed, search by distance, answer from the matches.
AES-256-GCM for secrets. SQLite and sqlite-vec for storage.
$ go install github.com/
Overview
Every developer accumulates a pile of scattered knowledge: the staging database password, the exact flags for a deploy, a snippet you wrote once and will need again. It ends up in notes apps, shell history, password managers, and stray text files. The problem is rarely storing it. The problem is finding it again, weeks later, when you no longer remember the exact words you used.
inode treats that as a retrieval problem. Every note is embedded into a vector space, a question is embedded into the same space, and the notes closest to it by L2 distance become the context a language model answers from. So “the staging database password” finds the entry you saved as “RDS creds for stage”: the two share no words, but their vectors sit close together.
It is built to run entirely on your machine. By default there are no API keys, no accounts, and no network calls: embeddings and language-model inference run locally through Ollama, and everything is stored in a single SQLite file you own. When you want higher-quality results, you can point it at cloud backends without changing a single command you type.
At a glance
- Language
- Go
- Retrieval
- k-NN by L2 distance, cutoff 1.0
- Storage
- SQLite + sqlite-vec · PostgreSQL + pgvector
- Embeddings
- nomic-embed-text (Ollama) · voyage-3
- Language models
- Ollama · Claude · OpenAI
- Encryption
- AES-256-GCM, Argon2id-derived key
- Integrations
- MCP over stdio, read-only
- Categories
- 9 (credentials, commands, runbooks, …)
- Install
- go install · Linux release binary
How it works
Classify
On add, a language model assigns one of nine fixed categories (credentials, commands, snippets, decisions, runbooks, learnings, references, contacts, notes), proposes tags, and flags sensitive content. Anything outside the set falls back to notes, and an explicit --category always wins.
Embed
The note is embedded with nomic-embed-text through Ollama, or voyage-3 through Voyage AI. Both return L2-normalised vectors, so distances fall between 0 and 2 and a fixed relevance threshold means the same thing for every note.
Store
Content goes into a notes table and the vector into a sqlite-vec vec0 virtual table in the same SQLite file, or into a vector(N) column when the backend is PostgreSQL with pgvector. Sensitive content is sealed with AES-256-GCM before it is written.
Retrieve, filter, answer
The question is embedded the same way and the five nearest notes come back by L2 distance. Any candidate further than 1.0 (cosine similarity below 0.5) is dropped, sensitive notes are decrypted in memory, and the rest become the model's only context. The model reports which notes it used, and only those are listed as sources.
Capabilities
01Retrieval that survives different wording
Matching happens between embeddings, not strings, so “prod logging config” finds a runbook titled “observability setup”. The distance ceiling keeps weak matches out of the context window rather than letting the model improvise from them, and when nothing clears it inode says so instead of answering.
02Runs on your machine, cloud is opt-in
Storage, embeddings, and the language model each sit behind an adapter interface: SQLite or PostgreSQL, Ollama or Voyage AI, and Ollama, Claude, or OpenAI. The default is SQLite, nomic-embed-text, and llama3.2, with no API keys and nothing leaving your laptop. Switching a backend is a config change; the commands stay the same.
03Secrets handled like secrets
Sensitive notes are sealed with AES-256-GCM under a fresh random nonce, with the note ID bound as additional authenticated data, so a ciphertext copied onto another row fails to decrypt. The key is derived with Argon2id from a 32-byte master secret held in the OS keyring. Values stay masked in output until you pass --reveal.
04An MCP server your editor can read
inode mcp serves the Model Context Protocol over stdio with three read-only tools: search_notes, list_notes, and get_note. Search skips the local model and returns the raw candidates, because the calling agent is a language model already. Sensitive notes are excluded from search and masked in get_note unless you opt in.
Usage
$ inode add "My Stripe test key is sk_test_xxxxx"The model classifies it as credentials, adds tags, and flags it sensitive, so it is encrypted before it is stored.
$ inode get "stripe test key"Embeds the query, runs k-nearest-neighbour search, drops weak matches, and answers from what is left. Aliases: ask, find, search.
$ inode get "stripe test key" --revealSensitive values are masked by default. --reveal prompts for confirmation, then prints the plaintext.
$ inode list --category credentialsLists notes by category or tag straight from the table, without touching the vector index.
$ inode mcpRun the read-only MCP server over stdio so Claude Code or Cursor can read your knowledge base.
Want the code?
inode is open source and built in public.