columbus

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 10, 2026 License: MIT

README ΒΆ


The navigator your coding agent has been missing.

CI Release Go Reference

πŸ“– Documentation & Guides Β· Quick Start Β· Using with your agent

Your coding agent is brilliant at reasoning and bad at locating and remembering. So it greps in the dark, reads whole files to use ten lines, and leans on stale .md context that quietly lies.

Columbus is a local-only, semantic code-context server your agent calls as a tool. Ask it β€” in plain language β€” where something is and get ranked, LLM-ready context with exact line ranges, reconstructed live from your working tree so it's never stale. It also owns your project's durable memory, so the agent stops re-discovering the codebase every session.

Local embeddings, no cloud, no LLM calls β€” natural-language search that stays on your machine.

[!IMPORTANT] It cannot go stale, because it never stores your code. The database holds metadata, git anchors and embedding vectors only β€” every snippet and exact line range is rebuilt live at query time by re-parsing the working tree. The vectors are a derived index, not your source; the answer always matches the code as it is right now.

Columbus does exactly three things:

  1. Index β€” chart the codebase with embedded tree-sitter and embed each symbol/file on-device (metadata + git anchors + vectors, never your code).
  2. Search β€” natural-language semantic search: vector retrieval re-ranked by deterministic heuristics, returning ranked context with exact line ranges.
  3. Memory β€” own the project's durable record: ADRs, plans and documentation with tags, links, evidence anchors, and drift checks.

Embeddings run on-device with bundled Model2Vec assets (minishlab/potion-code-16M); there are no LLM calls and nothing leaves your machine. Ranking, "why relevant" text, and risk hints are deterministic.

Why Columbus

The agent is great at the thinking. It's the finding and remembering that bleed tokens and go wrong. Columbus takes that off its plate.

Without Columbus With Columbus
Greps for the exact word and misses the concept Natural-language semantic search finds it by meaning
Reads whole files to find ten relevant lines One call returns ranked context with exact line ranges
Context drifts; stale .md files confidently lie Snippets rebuilt live from the working tree β€” never stale
Re-discovers the codebase every session Durable memory β€” ADRs, plans & documentation persist
Repo cluttered with .cursorrules / scattered context files Memory is queryable and git-excluded, not committed noise
Embeddings shipped to a cloud, per-query cost On-device embeddings, zero LLM calls, nothing leaves your machine

[!NOTE] Proof, measured. A with/without study (tokens to first correct location, total session tokens, tool calls, run-to-run variance) is in progress β€” real numbers will land here. Placeholder; not yet published.

Install

Requires Go 1.26+ and a C compiler for the embedded tree-sitter grammars. Columbus is built with -tags fts5. The SQLite, vector, and embedding stack is pure Go, so no ONNX, tokenizer, or SQLite native libraries are required.

Release archives

Download the archive for your platform from Releases. Each archive ships a single columbus binary with the model assets embedded, so local natural-language (vector) search works out of the box with no network at runtime.

Build from source

brew install ripgrep ast-grep
make setup        # fetch Model2Vec assets into internal/embed/assets
make install      # built with -tags fts5 and CGO_ENABLED=1 by default

git is the only hard runtime dependency. ripgrep is the recommended search fast-path (a pure-Go fallback covers the rest); ast-grep is optional. The SQLite metadata store and vec0 vector search use the pure-Go modernc driver; the embedding engine uses a pure-Go Model2Vec runtime and embedded safetensors weights.

Quick start

columbus install                 # onboard: write .columbus.json, create db, first index + embed
columbus search "parse config"   # ranked, LLM-ready context with exact line ranges
columbus reindex                 # re-chunk + re-embed only what changed
columbus view                    # full-screen dashboard (index stats + memory table)
columbus doctor                  # verify git, vec0, model runtime + index health

Then point your agent at Columbus as a tool (see Use it with your agent). The agent stops grepping and starts asking; columbus view gives you the live view of what it's doing.

Documentation

Full guides and reference live in the Columbus Wiki:

How it works

The chart (the index) tells Columbus where things are. The working tree tells it what they currently say. Because Columbus never caches the "what," it can never lie about it.

your working tree ──(tree-sitter)──▢ index: metadata + git anchors   (the chart)
        β”‚                                          β”‚
        β”‚   agent: columbus search "parse config"  β”‚
        β–Ό                                          β–Ό
   re-parse live ◀───────────────────────  rank deterministically
        β”‚
        β–Ό
   ranked results + EXACT line ranges + "why relevant"  ──▢  LLM-ready

Indexing is incremental and cheap, but even a stale index can't produce a stale answer: the snippet and line range you get back are reconstructed from the file as it exists at query time.

Use it with your agent

Columbus is a tool, not an autopilot. Your agent learns when and how to call it through skills β€” small instruction files that teach the agent the CLI (when to search before editing, how to record a decision, how to read the graph). The skills live in the agent/plugin layer, never in this binary, which keeps Columbus a small, deterministic context server with no opinion on your workflow.

The contract the agent consumes:

  • --json β€” a versioned, machine-readable contract with a canonical error envelope. Stable to parse, safe to depend on.
  • --llm β€” markdown shaped for a context window: ranked results, exact line ranges, and a short "why relevant" per hit.

Both are pure projections of the same typed result as the human text output β€” they can never silently diverge.

Search is locate-first: by default it returns ranked locations, signatures, scores and graph edges β€” the cheap "where to look" map β€” and omits code bodies. Add --snippets to attach bodies inline (capped with --snippet-lines N), or pull a specific body on demand with columbus show symbol. Exact line ranges are always present, so an agent can read first and drill down only where it matters.

columbus search "where do we parse config" --llm             # ranked locations, no bodies (cheap)
columbus search "where do we parse config" --llm --snippets  # same, with code bodies inline
columbus graphs --in internal/server --json                  # dependency graph as {nodes, edges}, machine-readable

[!NOTE] Columbus skills (for Claude Code and other agents) are published separately as plugin assets. Link coming soon.

Commands

Lifecycle

columbus install                    # onboard: write config, create db, first index + embed
columbus reindex                    # re-chunk + re-embed changes (also --full/--changed/--clean/--status)
columbus doctor                     # environment + project health (git, vec0, runtime, model, index)
columbus uninstall                  # remove config + delete the db (confirm; --yes when non-TTY)
columbus purge                      # clear all records + reset config to defaults (confirm; --yes)

Search & navigate

columbus search "where do we parse config"    # natural-language, ranked, LLM-ready results
columbus search "auth token check" --kind all # code hits + full-body memory section in one call
columbus show symbol Engine --in internal/search
columbus show file internal/store/store.go
columbus graphs --json                        # whole dependency graph as {nodes, edges}
columbus graphs --role impl --in internal/store   # narrow + induce subgraph

Search is semantic: the query is embedded on-device and matched by vector similarity, then re-ranked by deterministic heuristics. With no runtime library present it degrades to keyword (FTS) ranking β€” columbus doctor shows which.

One search is the master query: alongside the ranked code hits it returns a MEMORIES section with the full bodies (plus tags, links, and evidence) of the most relevant memories, and 1-hop graph edges (imports / imported-by / tests) per code hit β€” so an agent gets complete context in a single call, no follow-up show memory needed.

Memory (durable knowledge)

Three kinds β€” adr (architecture decision), plan (durable implementation plan), and documentation (everything else worth remembering). All of it is embedded and surfaces in semantic search with full bodies.

columbus memory add adr --title "Use WAL" --body "readers never block writers" \
  --evidence internal/store/store.go:30-40 --link symbol:Open --tag db
columbus memory add plan --title "Ship master search" --body "one query = full context"
columbus memory add documentation --title "Release process" --body "goreleaser + zig"
columbus memory update mem_001 --title "Use WAL mode" --add-tag sqlite
columbus memory list --kind adr --tag db
columbus memory remove mem_001                  # destructive; id retired

Memories are a passive, durable record. Links and evidence anchors are drift-checked against the indexed file/symbol targets; show file|symbol lists in reverse the memories that reference that entity.

columbus show memory mem_001          # full body, tags, links, evidence
columbus search "WAL" --kind memory   # memory-only search (full bodies)
columbus memory validate              # evidence drift + link resolution report

Import / export

columbus export --out memories.json    # portable memory doc (schema v4)
columbus import memories.json          # vectors are not exported β€” reindex rebuilds them

Dashboard

columbus view opens a full-screen, read-mostly terminal dashboard over the indexed project: index freshness, file/symbol/embedding counts, memory counts, and a full-width memory table. It auto-refreshes, so external columbus reindex/agent edits appear on their own.

Keys: ↑/↓ (or j/k) navigate Β· enter detail (full body, tags, links) Β· / semantic search across code and memory (ranked results, snippets in detail) Β· esc back Β· r refresh Β· R reindex (in-process) Β· ? help Β· q quit confirmation. It is a projection of the same data the JSON/LLM commands expose; only R writes (it runs the indexer) β€” memory is read-only.

Output modes

text (default, human; color only on a TTY), --json (machine contract), and --llm (markdown) are pure projections of the same typed result β€” they can never silently diverge. Color follows --no-color, then NO_COLOR, FORCE_COLOR, TERM=dumb, and CI, in that order, before falling back to TTY detection.

Exit codes

code meaning
0 success (incl. "usable with warnings")
1 runtime error
2 usage error
3 not initialized / index missing
4 transient / retryable (e.g. index writer locked)

Design invariants

  • Data always reflects current project state. The database stores metadata + git anchors only β€” never code lines or file bodies. Snippets and exact line ranges are reconstructed live at query time by re-parsing the working tree with tree-sitter.
  • The DB is a metadata + graph cache, not a content store.
  • git is the only hard runtime dependency. ripgrep is the recommended search fast-path; a pure-Go fallback covers the rest. ast-grep is optional.
  • --json is a versioned API contract with a canonical error envelope.

Languages (V1)

TypeScript + TSX, JavaScript + JSX, Python, Go, Markdown. Adding a language is a grammar + .scm queries + an extension mapping β€” no core changes.

Development

make test       # go test -tags fts5 ./...
make vet
golangci-lint run ./...
make cover

See CHANGELOG.md for release history.

Contributing

Contributions are welcome β€” see CONTRIBUTING.md and the Code of Conduct. For security reports, see SECURITY.md.

License

MIT β€” see LICENSE.

Directories ΒΆ

Path Synopsis
cmd
columbus command
Command columbus is a local-only, deterministic code-context server invoked as a tool by a code agent.
Command columbus is a local-only, deterministic code-context server invoked as a tool by a code agent.
internal
cli
clock
Package clock provides an injectable time source so domain code never reads the wall clock directly (required for deterministic tests).
Package clock provides an injectable time source so domain code never reads the wall clock directly (required for deterministic tests).
config
Package config loads, validates and writes the local-only .columbus.json file and resolves the OS data directory.
Package config loads, validates and writes the local-only .columbus.json file and resolves the OS data directory.
contract
Package contract defines the stable machine-facing surface of Columbus: the JSON schema version, the canonical error codes, and their mapping to process exit codes.
Package contract defines the stable machine-facing surface of Columbus: the JSON schema version, the canonical error codes, and their mapping to process exit codes.
doctor
Package doctor runs environment and project health checks.
Package doctor runs environment and project health checks.
embed
Package embed turns text into dense vectors entirely on-device, with no network access.
Package embed turns text into dense vectors entirely on-device, with no network access.
extract
Package extract turns source files into a shared intermediate representation (symbols, imports, exports, todos) via embedded tree-sitter grammars driven by per-language .scm queries.
Package extract turns source files into a shared intermediate representation (symbols, imports, exports, todos) via embedded tree-sitter grammars driven by per-language .scm queries.
gitrepo
Package gitrepo wraps the git CLI.
Package gitrepo wraps the git CLI.
grep
Package grep provides live content search over the working tree: a ripgrep fast-path when rg is on PATH, and a pure-Go fallback otherwise (so Columbus works with git as the only hard dependency).
Package grep provides live content search over the working tree: a ripgrep fast-path when rg is on PATH, and a pure-Go fallback otherwise (so Columbus works with git as the only hard dependency).
ids
Package ids provides an injectable source of non-deterministic identifiers (the project_id minted at init).
Package ids provides an injectable source of non-deterministic identifiers (the project_id minted at init).
index
Package index builds and maintains the metadata index: file-set selection, content-hash change detection, parallel parse with a single serialized writer, and the atomic transaction that makes an index run all-or-nothing.
Package index builds and maintains the metadata index: file-set selection, content-hash change detection, parallel parse with a single serialized writer, and the atomic transaction that makes an index run all-or-nothing.
live
Package live resolves exact line ranges and snippets by re-parsing the working tree with tree-sitter at query time.
Package live resolves exact line ranges and snippets by re-parsing the working tree with tree-sitter at query time.
logging
Package logging provides a per-project JSONL logger (slog + size-capped rotation) distinct from per-invocation stderr diagnostics.
Package logging provides a per-project JSONL logger (slog + size-capped rotation) distinct from per-invocation stderr diagnostics.
memory
Package memory owns the durable project memory: records, evidence, links, tags, validation and drift detection.
Package memory owns the durable project memory: records, evidence, links, tags, validation and drift detection.
project
Package project owns project identity and lifecycle operations: init, git anchoring, and (later) file-set selection.
Package project owns project identity and lifecycle operations: init, git anchoring, and (later) file-set selection.
render
Package render projects a typed command result into one of three output formats: text (human), json (machine contract) and llm (markdown).
Package render projects a typed command result into one of three output formats: text (human), json (machine contract) and llm (markdown).
search
Package search runs the deterministic two-source search pipeline: FTS5 over metadata (in-DB) and live content matches over the working tree (ripgrep fast-path or pure-Go fallback).
Package search runs the deterministic two-source search pipeline: FTS5 over metadata (in-DB) and live content matches over the working tree (ripgrep fast-path or pure-Go fallback).
show
Package show renders detailed views of a single entity: a symbol (all matching definitions), a file (outline + graph), or a memory by id.
Package show renders detailed views of a single entity: a symbol (all matching definitions), a file (outline + graph), or a memory by id.
store
Package store owns the SQLite database: connection setup, PRAGMAs, embedded migrations, and typed repositories.
Package store owns the SQLite database: connection setup, PRAGMAs, embedded migrations, and typed repositories.
tui
Package tui implements `columbus view`: a local, full-screen dashboard over the project's indexed state, embeddings and durable memory.
Package tui implements `columbus view`: a local, full-screen dashboard over the project's indexed state, embeddings and durable memory.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL