B2 · quick start
GitHub ↗
Set up · index · search · discover connections

Get started with B2

Point B2 at a folder of Markdown and it becomes a second brain that reads everything, lets you search it, and surfaces the notes most similar in meaning for you to connect.

This guide takes you from an empty checkout to a working vault you can search and grow — about ten minutes, most of it a one-time model download. Your .md files stay plain and yours the whole way; B2 only ever adds a hidden index folder and (with your say-so) a typed link in a note's frontmatter.

Before you start

You'll need a Rust toolchain (rustup.rs) to build the b2 binary — B2 ships as source today, as one static binary. macOS and Linux are the tested platforms.

One thing is optional, and it's local — B2 makes no network calls and needs no account or API key at any point:

Set up

1

Build the b2 CLI

Clone the repo and build the release binary, then alias it so b2 is on your path for this shell:

$ git clone https://github.com/AlteredCraft/B2 && cd B2
$ cargo build --release -p b2-cli
$ alias b2=./target/release/b2
$ b2 --help
B2 — explore a Markdown vault's typed graph and search from the terminal
Tip Every command takes a global -C <path> (or --vault) to point at your vault — or set B2_VAULT_PATH once so every command finds it without the flag — and --json to emit machine-readable output for agents and scripts. The examples below run from inside the vault folder, so read-only commands default to .; commands that write (reindex, add, mv, link) need an explicit vault (a path, -C, or B2_VAULT_PATH), so they can't silently touch the wrong directory.
2

Install the embedding model (one-time)

Semantic search and connection discovery run on a local embedding model — no account, no API key, no network at query time. b2 init downloads and verifies the model into a shared cache once — it is not re-downloaded per vault, and there is never a surprise download mid-command later.

$ b2 init
Installed 'bge-base-en-v1.5' (768 dims). Run `b2 reindex` to embed your vault.
No model? You can do everything in this guide offline by prefixing commands with B2_EMBEDDER=fake. Search still works on keywords (BM25), but the semantic half is switched off — the CLI tells you so, and never pretends a result is semantic when it isn't.

Create a vault

A vault is nothing more than a folder of Markdown files. Point B2 at notes you already have, or start fresh — there's no import step and no proprietary format to convert into.

3

Create some notes

Just write Markdown files. Here are two — a concept and a note that connects to it. The frontmatter is minimal; the body is plain prose:

# ~/vault/concepts/memory.md
---
type: concept
title: "Human memory"
created: 2026-07-03
---
The brain encodes, stores, and retrieves information.
# ~/vault/notes/spaced-repetition.md
---
type: note
title: "Spaced repetition"
created: 2026-07-03
---
Spaced repetition exploits the retrieval curve.

## Relations
- elaborates [[concepts/memory|Human memory]] — applies the forgetting curve

That last line is a typed connection: the verb elaborates, a wikilink [[concepts/memory|Human memory]] to the target, and a "why". A bare [[path|title]] anywhere in prose is an untyped references link. The verbs come from a small closed vocabulary — references, relates, elaborates, supports, refutes, contradicts, example-of, part-of, supersedes, derived-from — the same palette you'll pick from with b2 link.

Or scaffold one Prefer a command? b2 add notes/spaced-repetition --title "Spaced repetition" --content "…" writes a valid note and indexes it in one step (so you can skip the reindex in step 5 for notes you create this way). The .md extension is optional; parent folders are created for you.
4

Know what B2 will and won't touch

Nothing is hidden — the files stay ordinary Markdown that work in Obsidian, or anything else, with no B2 running. After indexing (next step), that first note gains exactly one line B2 manages:

---
b2id: 01KWMCW242E0WSKVYDYNQBT7SN   # set by B2 on first index — a stable id, never changes
type: note
title: "Spaced repetition"
created: 2026-07-03
---
Spaced repetition exploits the retrieval curve.

## Relations
- elaborates [[concepts/memory|Human memory]] — applies the forgetting curve
The one rule B2 writes to your notes in exactly two places, and never touches your prose: it stamps the b2id the first time it indexes a note, and — only when you run b2 link (step 8) — it appends a typed link to a frontmatter relations: block. Connections you write yourself live in the body and are labelled inline; ones you commit with b2 link live in frontmatter and are labelled frontmatter. That's the whole of B2's write surface.
5

Index the vault

b2 reindex reads every note, stamps any missing b2id, and builds the searchable index. It's how B2 catches up to files you've created or edited by hand:

$ cd ~/vault
$ b2 reindex .
Indexing /Users/you/vault
  embedding 2/2 · notes/spaced-repetition.md (2 chunks)
Indexed 2 notes (2 embedded, 2 stamped)

Run it again after editing notes — it's incremental: unchanged notes keep their vectors, so only what actually changed is re-embedded. Two flags help:

  • b2 reindex --dry-run — preview what would happen (writes nothing, not even a b2id).
  • b2 reindex --force — re-embed everything from scratch.
Where it lives The index goes in a single .b2/ folder inside your vault. It's disposable — delete it and the next reindex rebuilds it identical from your Markdown. Nothing durable lives outside your notes. Add .b2/ to your .gitignore if the vault is a git repo.

Work with it

6

Search

One command, hybrid ranking — it fuses keyword (BM25) and semantic (vector) matches, so you find notes by wording and by meaning:

$ b2 search "how does forgetting work"
0.0328  Spaced repetition (notes/spaced-repetition.md)
    Spaced repetition exploits the retrieval curve.
0.0161  Human memory (concepts/memory.md)
    The brain encodes, stores, and retrieves information.

Use --limit N to widen or narrow the result set.

7

Explore the graph

Follow the connections around any note. neighbors is a quick list of what a note links to and from; explain adds each connection's why and its provenance:

$ b2 neighbors notes/spaced-repetition
→ elaborates  Human memory (concepts/memory.md) — applies the forgetting curve

$ b2 explain concepts/memory
Human memory (concepts/memory.md)  [b2id 01KWMCW242E0WSKVYDYNQBT7SN]
Connections:
  ← elaborated-by  Spaced repetition (notes/spaced-repetition.md)  [inline]
      why: applies the forgetting curve

You can pass a note as either its vault-relative path or its b2id. When nothing points at a note, explain flags it as an orphan — surfaced for you to notice, never auto-changed.

8

Discover connections

This is the point of B2. b2 similar <note> surfaces the notes most semantically similar to a given one that you haven't linked yet — a pure, instant read over the vectors reindex already stored. No model call, no network, no cost: the ranking and the "∖ already-connected" exclusion happen locally over your whole vault.

$ b2 similar notes/spaced-repetition
0.71  Cramming works       (notes/cramming.md)
    Massed practice yields only short-term recall.
0.63  The forgetting curve  (concepts/forgetting-curve.md)
    Retention decays exponentially without review.

Each row is a similarity score, the note's title and path, and the passage that made it similar. The note itself and anything already linked to it never appear. It lists about ten by default; --limit N widens or narrows that.

You're the precision gate B2 finds the candidates; you supply the judgment and the type. There's no review queue and nothing "inert until accepted" — a connection exists only once you author it. The intelligence is in the whole-vault semantic surfacing, which is free and local; the decision stays yours.

Pick the connections worth keeping and commit them. Either write a [[link]] in your note's body yourself, or run b2 link:

$ b2 link notes/spaced-repetition notes/cramming --type contradicts --explanation "massed vs. spaced practice"
Linked spaced-repetition → cramming (contradicts). Wrote the typed relation into the source note's frontmatter.

b2 link <src> <dst> appends the typed relation to the source note's frontmatter relations: — Markdown-first, never the body. --type picks the verb from the closed vocabulary (defaults to references); --explanation records the "why". Re-run b2 similar afterward and a note you just linked drops off the list — it's connected now, so the exclusion filters it out.

Day to day

Edit notes in whatever you like — B2 is a layer over your files, not a place you have to live in. When you rename or reorganize, let B2 keep the graph intact:

$ b2 mv concepts/memory concepts/human-memory
Moved concepts/memory.md → concepts/human-memory.md
Rewrote 1 inbound link(s) across 1 file(s).

Because connections key on the immutable b2id, a move never breaks a backlink — B2 also repairs the human-readable link text in every note that pointed at it. Refactor fearlessly: move, split, merge, rename. After a batch of hand-edits, a quick b2 reindex catches everything up.

index = projection of ( Markdown )

The mental model in one line: your Markdown is the only source of truth. The index is a disposable cache you can drop and rebuild identically from your notes — nothing durable exists that your Markdown can't reconstruct. Nothing locks you in.

Command reference

CommandWhat it doesModel?
b2 initDownload + verify the embedding model (one-time, per machine).downloads it
b2 add <path>Create a note (--title, --content) and index it.embeds
b2 reindexRe-project the vault; incremental. --dry-run, --force.embeds
b2 search <query>Hybrid keyword + semantic search. --limit N.embeds query
b2 neighbors <note>List a note's typed links, in and out.no
b2 explain <note>Every connection with its "why" + provenance; flags orphans.no
b2 mv <from> <to>Move/rename a note and repair every inbound link.re-embeds touched
b2 similar <note>Surface the semantically nearest notes you haven't linked yet. --limit N.reads vectors
b2 link <src> <dst>Commit a typed relation into the source note's frontmatter. --type, --explanation.re-embeds note

Config & environment

Zero-config is the happy path — everything above works with no config file. When you want to tune, a single optional TOML at ~/.config/b2/config.toml configures the embedder:

# ~/.config/b2/config.toml  (all optional)
[embedder]
model = "bge-base-en-v1.5"
Environment variableEffect
B2_VAULT_PATHVault root, so commands find it without -C. An explicit -C/--vault overrides it. Read-only commands fall back to the current dir; commands that write (reindex/add/mv/link) require it explicitly.
B2_EMBEDDER=fakeOffline mode: deterministic non-semantic embedder. Search runs keyword-only.
B2_DEBUGPrint internal error detail after the generic user-facing message.
Honest about limits Search snippets and scores come from the index, so reindex first. similar reads the vectors a prior reindex stored, so index before you discover. And under B2_EMBEDDER=fake the semantic half of search and similarity is off — great for offline exploring, not for real recall.
Docs home 📐 System architecture 🗂️ Indexing pipeline 🔗 Connection discovery Source on GitHub