Karpathy's LLM Wiki, built automatically from your Claude Code and Codex sessions.
Plain markdown you own: best in Obsidian, fine without it.
That graph is my vault. Every node is a plain markdown file that vir wrote by reading my Claude Code transcripts. It lives in Obsidian next to my own notes. There is no server, no account, no export step. Uninstall vir tomorrow and the vault stays yours.
396 sessions. Claude Code prunes transcripts after about 30 days. 396 of my distilled sessions now exist nowhere except this vault. The decisions and gotchas inside them would otherwise be gone.
1,386 transcripts, 410 notes. Of the 1,386 transcripts vir has read on my machine, 562 were subagent runs, workflow phases, or sidechains — skipped by default — and 361 had nothing durable in them. 410 became notes. The vault holds your work, not your tooling's.
Numbers from my machine, September 2026. Yours will differ. Website: virwiki.dev.
npm install -g @djolex999/vir-cli
vir init
vir runvir init is a wizard: which coding agents you use, provider, models, notes
folder. vir run does one pass
over your sessions and writes notes. When you like the output,
vir schedule install registers a daemon that keeps the vault current.
| Agent | Sessions | Status |
|---|---|---|
| Claude Code | ~/.claude/projects/ |
✅ |
| Codex (CLI, IDE extension, desktop app) | ~/.codex/sessions/ |
✅ new in 0.26 |
| Cursor | — | planned |
vir init asks which agents you use and pre-checks the ones it finds. To add
Codex to an existing install, re-run vir init, or set codexSessionsDir in
~/.vir/config.json:
{ "codexSessionsDir": "~/.codex/sessions" }A project you work on from both agents is one project: vir names it by the
folder you started
10BC8
in, the same way for each. Codex desktop chats started
outside a repo (~/Documents/Codex/…) are grouped as one codex-scratch
project. Codex subagent and review threads are skipped, like Claude Code's
sidechains.
Things to know about Codex:
- New Codex projects start undecided. Codex sessions run larger than
Claude Code's, so nothing is distilled until you include a project. Run
vir run --dry-runfirst to see the estimate, thenvir projects. - Archived Codex threads are not distilled. vir reads
~/.codex/sessions/only; archiving a thread moves it out of reach. - No API key needed with a ChatGPT plan:
provider: "codex-cli"distills throughcodex exec(experimental, see Cost). Any other provider works too.
Vir reads transcripts from ~/.claude/projects, filters out the noise,
classifies what survives with Haiku, and distills durable knowledge with
Sonnet. Notes are typed: patterns, gotchas, decisions, tools. Three input
sources feed one vault:
- Claude Code sessions. Retroactive: months of existing history become notes in one run.
- Web articles clipped to a folder, e.g. via Obsidian Web Clipper.
- PDFs and papers.
Everything embeds into one vector space (Ollama, optional, TF-IDF fallback).
vir query "<question>" searches it and synthesizes an answer. An MCP server
exposes the vault to Claude Code or Codex mid-session, so the agent consults
past decisions instead of rediscovering them. vir sync-claude feeds the best
notes back into your CLAUDE.md files, and into AGENTS.md files that already
exist (~/.codex/AGENTS.md, project roots), with a diff and your confirmation.
New in 0.25: vir connect finds a lesson you keep re-learning across sessions
and proposes it as a rule, quoting each note it came from. You review it, and
vir sync-claude adds it to CLAUDE.md only with a yes for that rule.
Claude Code sessions
↓
vir
↓
markdown notes (Obsidian vault optional)
↓
CLAUDE.md
↓
better sessions
↓
...
In April 2026, Andrej Karpathy described a pattern he calls the LLM Wiki: AI work that feeds back into itself through a persistent, curated, structured artifact, instead of resetting at the end of every session. He published the idea file at karpathy/llm-wiki.md and ended his post saying: "I think there is room here for an incredible new product instead of a hacky collection of scripts."
Several open source implementations of this pattern now exist (lucasastorian/llmwiki, Pratiyush/llm-wiki, nashsu/llm_wiki among them). Each takes a different shape.
Vir is the one built from your own coding sessions, and it is Obsidian-native
when you want it. In Obsidian it is a frontend, not just a storage location: a
sidebar plugin
(vir-obsidian),
dataview-compatible frontmatter, wikilinked notes that show up in the graph.
It reads AI coding session transcripts retroactively, so months of existing
history become a queryable knowledge base in one run. Without Obsidian it is a
folder of markdown, and vir query and the MCP server work with no editor at
all.
Auto-distilled notes can be wrong. The most common concern from early users: "if your distillations are wrong, Claude treats them as truth and you get worse results, not better." Fair. Vir addresses it in layers:
- Transcript filtering. Workflow transcripts, subagent sidechains, and headless SDK agent runs are detected structurally and excluded before any API call. Every skip is recorded with a reason, and every skip is reversible: flip the knob and the transcripts re-enter on the next run.
- Project triage.
vir projectsshows every project with session counts and estimated pending cost. Include or exclude each one. Undecided projects are a visible state, never a silent default. - Confidence scores on every note, written into the frontmatter
(
confidence: 0.xx). A cheap heuristic pre-filter drops low-signal sessions before any LLM call; classification then scores what survives, and anything at or below0.6is dropped before the more expensive distill step. - Opt-in
CLAUDE.mdsync. Nothing vir generates touches your prompt context automatically.vir sync-claudeshows a diff and waits for your confirmation. You decide what reaches Claude. Notes thatvir auditorvir audit --transcriptflagged stay out until you approve them invir review --audited. - Plain markdown output. Every note is a file in your notes folder. Read it, edit it, delete it. Nothing is hidden in a database you can't inspect.
- Lint and dedupe.
vir lintflags contradictions and stale notes;vir dedupemerges near-duplicate notes that have drifted apart. - Active learning via
vir review. Walk through new distillations and approve, edit, or reject each one. Verified notes get a ranking boost in retrieval (invir queryand the MCP server). Rejected notes move to.rejected/, recoverable, not deleted. - Measured retrieval. Ranking defaults are set by a retrieval eval over
judged queries, not by feel: pure relevance by default, with MMR diversity
(
retrievalDiversity) available when you want it. - Recurring lessons become rules, only with your yes.
vir connectlooks for a lesson you've written down in at least 3 sessions over at least a week (by embedding each "What Was Learned" item), and has the model state it as one rule, with a verbatim quote from every note it cites; quotes that aren't in the note are thrown out. Proposed rules live ininsights/rules/, stay out of search until you accept them invir review --insights, and reach CLAUDE.md only throughvir sync-claude, which asks about each rule separately and never adds one under--force. Rejected rules stay rejected even after the source notes are rewritten. Needs an embedding provider. - Topic synthesis via
vir compose "<topic>". Embedding-searches the vault for related notes and synthesizes them into a single topic page undertopics/, with each source wikilinked so it backlinks in Obsidian's graph.--dry-runpreviews the sources and cost for free. - Cost transparency.
vir run --dry-runestimates per-session cost before you spend a cent;vir costreports the actuals (total, median, p90, top sessions) from a local~/.vir/cost.log. Pricing is provider-aware (Anthropic list rates and Kie's discount), so the numbers reflect your bill, not a blended guess. - Reliable failures. Every command exits non-zero on failure. A provider
outage is one clear failure, not a retry storm: a cheap preflight probe
runs before the distill loop. Sessions that fail 3 times in a row are
parked until you retry them with
vir reconcile --force.
The bet: with these controls, signal-to-noise stays high enough that the
vault is a net positive. If your discipline is strong enough to maintain
CLAUDE.md and lessons.md by hand, you may not need this. If, like most of
us, you let those files drift after the first week, vir catches what slips
through.
The LLM Wiki space has grown fast. Honest comparison:
| Vir | lucasastorian/llmwiki | Pratiyush/llm-wiki | nashsu/llm_wiki | |
|---|---|---|---|---|
| Language | TypeScript / Node | Python | Python | Cross-platform desktop |
| Distribution | npm install -g |
Local app + hosted SaaS | git clone + python |
Desktop app installer |
| Obsidian integration | Native (sidebar plugin) | Markdown output | Outputs to vault | Own UI, no Obsidian |
| Input sources | Claude Code, Codex, web clips, PDFs | PDFs, docs upload | Claude Code, Cursor, Cline, Codex, Gemini | Documents, mixed sources |
| Retroactive on existing sessions | ✓ | n/a | from install forward | n/a |
| MCP server | ✓ | ✓ | ✓ | ✓ |
| License | MIT | open source + hosted commercial | MIT | open source |
| Vir | claude-mem | claude-memory | mem0 | |
|---|---|---|---|---|
| Reads existing Claude Code sessions | ✓ | from install forward | from install forward | n/a |
| Markdown output | ✓ | ChromaDB | LanceDB | various backends |
| Setup | npm install -g |
Bun + uv + Python | pnpm + LM Studio | API/cloud setup |
| License | MIT | Apache 2.0 | MIT | open core + cloud |
Different tools for different needs:
- If you want a polished cross-platform desktop app for general document knowledge bases, use lucasastorian/llmwiki or nashsu/llm_wiki.
- If you want multi-agent support with a rich entity/concept page taxonomy and don't care about Obsidian integration depth, use Pratiyush/llm-wiki.
- If you want a heavyweight Claude Code memory plugin with real-time capture and vector storage, use claude-mem.
- If you're building AI applications that need to remember users long-term, use mem0 (different layer entirely).
- If you want an LLM Wiki that reads your existing Claude Code sessions, Obsidian-native or just a folder of markdown, use vir.
Output from my first run across 226 Claude Code sessions:
| Metric | Value |
|---|---|
| Sessions scanned | 226 |
| Notes distilled | 126 |
| Avg confidence | 0.91 |
| High signal (≥0.8) | 121 of 126 |
| Projects covered | 8 projects |
| Knowledge breakdown | 54 patterns · 47 decisions · 23 gotchas · 2 tools |
Other LLM Wiki implementations would produce similar results with the same input. The distinguishing question for vir is workflow fit: does retroactive distillation of your own sessions, Obsidian-native when you want it, match how you actually work?
Example query against the distilled vault:
$ vir query "what gotchas should I know about my auth implementation"Based on the notes, here are the key auth gotchas:
JWT dual-token setup needs silent refresh on mount. Access tokens expire in 15 min; without a mount-time refresh check, users hit 401s on first load after a break. Middleware runs before the session is hydrated. Do not read session data in middleware to gate routes; check the JWT directly from the cookie instead. Password reset tokens must be single-use and hashed at rest. Storing raw tokens in the DB leaks them if the DB is compromised. OAuth callback URLs must be registered exactly. Trailing slashes, http vs https, and localhost port mismatches all cause silent redirect failures with no useful error message. Logout must clear both the access token cookie and the refresh token. Clearing only one leaves the session partially alive.
sources 4 · via embedding · searched 126
- macOS or Linux (systemd or cron)
- Node.js 20+
- Claude Code (sessions at
~/.claude/projects/) and/or Codex (sessions at~/.codex/sessions/) - A folder for notes. An Obsidian vault works great but is optional; see Without Obsidian.
- A distill provider — any one of:
- Anthropic API key (predictable per-session cost, no effect on your Claude Code limits)
- Your Claude Code subscription (
provider: "claude-cli"— free and keyless; distills consume your Claude Code usage limits) - Kie.ai API key (~72% cheaper, third-party proxy — used for testing and calibration runs, not recommended for your real vault)
- Your ChatGPT plan through the Codex CLI (
provider: "codex-cli"— experimental, keyless; distills consume your Codex usage limits)
- Optional: Ollama +
nomic-embed-textfor semantic search
vir writes plain markdown with YAML frontmatter. Obsidian is the nicest way to browse it, but nothing depends on it:
- Any editor works. Notes are ordinary
.mdfiles under<notes folder>/vir/.[[wikilinks]]read fine as text, and VS Code with Foam or Markdown Memo resolves them as links. - No editor needed for retrieval.
vir query "<question>"and the MCP server (vir mcp install) search the folder directly. - Point
vir initat any folder. If no Obsidian vault exists, it suggests~/notesand creates it.
Vir runs two API calls per session: a Haiku classify (cheap) and a distill (the main cost). Cost depends on session size and your provider.
With provider: "claude-cli" vir shells out to your installed claude
binary instead of calling an API — no key, no per-session dollars. The
trade: every distill consumes your Claude Code subscription quota (the same
limits your interactive sessions use), and that quota has no meter. vir
therefore caps claude-cli runs at 25 sessions per run (the rest are picked
up next cycle), halts immediately if your subscription limit is hit (with
the reset time; nothing is retried against the wall), and records these
calls in cost.log with cost marked not-applicable — never a fake $0.00.
The API path remains the default.
With provider: "codex-cli" vir distills through codex exec on your
ChatGPT login: no key, no per-session dollars, and the same quota rules as
claude-cli (25-session cap per run, halt on a usage limit, cost logged as
not-applicable). Codex picks the model (models.classify / models.distill
set to "default"); set a model id there to pin one.
Every call runs read-only, ephemeral (no new rollout in ~/.codex/sessions,
so vir never distills its own calls) and with Codex's tools switched off:
no shell, web search, apps, plugins or subagents, because the prompt carries
transcript text vir doesn't control. Your global ~/.codex/AGENTS.md still
loads, as ~/.claude/CLAUDE.md does for claude-cli. Each call carries about
16k tokens of Codex's own preamble. Verified on codex-cli 0.160.1; a Codex
version that doesn't know one of the switched-off features makes the call
fail with an "update Codex" message rather than run with tools vir hasn't
checked.
| Metric | Sonnet | Haiku |
|---|---|---|
| Median session | $0.07 | $0.025 |
| p90 session | $0.20 | $0.07 |
| Long-tail outliers (5-hour epics) | $0.25-$0.30 | $0.08-$0.10 |
| 226-session backfill | ~$21 | ~$7 |
Costs assume Kie.ai pricing (~28% of Anthropic direct). Multiply by ~3.5x for Anthropic direct rates.
Distill output dominates. A multi-hour session with hundreds of tool calls distills to ~4500 output tokens, plus 25-30k input tokens after tool-call filtering. Vir strips large tool outputs and oversized skill loads before distillation; on one real 517-tool-call session that took the distill input from ~217k to ~95k tokens without dropping signal.
vir run --dry-runpreviews per-session cost before any API call.vir runasks for confirmation when more than 20 new sessions are queued.vir cost --since 7daggregates real (not estimated) token usage from~/.vir/cost.log;--by-sessionand--top 5surface outliers.vir run --force-model haiku|sonnetoverrides the distill model per run.
Haiku is ~3x cheaper than Sonnet and captures equal-or-more concrete detail
on routine and tool-heavy sessions. Calibration showed it only misses
higher-order architectural lessons on decision-heavy and very large sessions.
Hybrid routing exploits that. When models.distillFast is set, each session
routes after classification:
category === "decision"→models.distill(Sonnet)inputTokens > models.distillThreshold(default100000) →models.distill- otherwise →
models.distillFast(Haiku)
New installs (vir init) enable hybrid by default. Existing installs are
unaffected on upgrade: with distillFast unset, models.distill is used for
every session exactly as before.
| Platform | Daemon | Notifications | Status |
|---|---|---|---|
| macOS | launchd | Vir.app (osascript fallback) | Stable |
| Linux (systemd) | systemd user timer | notify-send | Experimental |
| Linux (cron) | crontab | notify-send | Experimental |
| Windows | Not supported | none | Planned |
On macOS, notifications come from a small bundled helper, so they show as
vir with the vir icon rather than "Script Editor". macOS asks once
whether to allow them. vir init triggers that prompt, and so does
vir notifications at any time. Until you allow them, vir falls back to
osascript.
Linux support is experimental and untested. vir schedule install
prefers a systemd user timer and falls back to a crontab entry when systemd
is absent. Please report issues at
github.com/djolex999/vir/issues
with your distro, init system, and Node version.
| Command | Cost | Description |
|---|---|---|
vir init |
free | Interactive setup |
vir run |
cheap | Process new sessions |
vir run --full |
$$ | Reprocess all sessions |
vir run --rewrite-only |
free | Reformat notes, no API calls |
vir run --articles-only |
cheap | Distill only web articles |
vir run --pdfs-only |
$$ | Distill only PDFs |
vir run --dry-run |
free | Estimate per-session cost, exit before LLM |
vir run --force-model <m> |
cheap | Override distill model: haiku | sonnet |
vir projects |
free | Per-project triage: counts + pending cost |
vir projects include <p> |
free | Track a project |
vir projects exclude <p> |
free | Stop tracking (existing notes untouched) |
vir cost |
free | API cost report (total/median/p90/top) |
vir query "<question>" |
cheap | Semantic search your vault |
vir queries |
free | Retrieval report: method split, degraded rate, dead-weight notes |
vir compose "<topic>" |
$$ | Synthesize a topic page from related notes |
vir connect --dry-run |
free | Find lessons you keep re-learning; show candidates + cost |
vir connect |
$ | Propose those lessons as cited rules (≤10 LLM calls) |
vir summarize <project> |
cheap | Cross-session project synthesis |
vir summarize --week |
cheap | Period summary of the week's notes |
vir journal [date] |
free | Daily work journal from transcripts, no LLM calls (default: today) |
vir journal --since <date> |
free | Write every day with activity from that date on |
vir lint |
cheap | Find orphans, stale notes, contradictions |
vir lint --stale |
free | Old notes with newer work in the same project, each with how often agents still retrieve it |
vir dedupe |
cheap | Interactive duplicate detection + merge |
vir review |
free | Walk new notes: approve/edit/reject |
vir review --restore <note> |
free | Put one rejected note back |
vir audit |
cheap | Model judges each note; verdicts feed vir review --audited |
vir audit --dry-run |
free | Notes, batches and est. cost, no model call |
vir review --audited |
free | Walk notes vir audit flagged, worst first |
vir review --insights |
free | Accept, edit or reject rules proposed by vir connect |
vir audit --apply-rejects |
free | Move fresh reject verdicts to .rejected/ (reversible) |
vir audit --transcript |
$$ | Check each note against its own transcript; contradicted notes join vir review --audited |
vir lint --strays |
free | Note files with no live DB row (retitle debris) |
vir lint --strays --fix |
free | Move retitle debris to archived/ (only when a live copy exists) |
vir lint --legacy-related |
free | Pre-0.12.0 notes whose stored Related holds content a rewrite drops |
vir lint --legacy-related --fix |
free | Move that content into ## Details, re-render the notes |
vir prune |
free | Dry run: agent-derived notes to demote |
vir prune --apply |
free | Demote them to .rejected/ (never deletes) |
vir prune --restore |
free | Put every pruned note back, exactly |
vir sync-claude |
free | Inject top knowledge into CLAUDE.md (and existing AGENTS.md; --no-agents, --agents-only; --backfill-lessons is a cheap paid step for older gotchas) |
vir embed |
free | Generate embeddings for semantic search |
vir embed --setup |
free | Install the local embedding provider (no Ollama needed) |
vir schedule install |
free | Register the background daemon |
vir status |
free | Knowledge base breakdown + daemon status |
vir doctor |
cheap | 15 install/config checks |
vir notifications |
free | Allow vir's macOS notifications + send a test |
vir reconcile |
$$ | Retry sessions that failed, cache-bypassed |
vir mcp install |
free | Register the MCP server with Claude Code |
Most commands take --dry-run, --yes, or --json where they make sense;
run vir <command> --help for the full flag list. vir query --json and
vir doctor --json are the machine contracts the
vir-obsidian plugin consumes.
vir journal writes one file per day, vault/vir/journal/YYYY-MM-DD.md, with
what happened in each project: what got done, what's in progress, blocked or
still open, links to that day's decision notes, and work left unfinished on an
earlier day that nothing has touched since. It reads your transcripts
directly and makes no LLM calls, so it's free and gives the same file every
time for the same input.
## my-app
2 sessions
**Done**
- fix: retry webhook on 502 (commit a1b2c3d)
- Add idempotency key to checkout (task 1f2e3d4c#todo-0a1b2c3d)
**In progress**
- Migrate sessions table (task 1f2e3d4c#todo-4e5f6a7b)
**Decisions**
- [[use-sqlite-for-job-state-1f2e3d4c]]
**Carried over**
- Rotate webhook secret (task 9c8b7a6d#todo-1c2d3e4f), in progress, open 3 daysEvery line has to point at evidence: a commit sha git printed, or a task whose tool result confirmed it. A rejected commit, a refused call or a plan step nobody finished doesn't count. Tasks come from TaskCreate/TaskUpdate, TodoWrite and the Claude desktop app's task list.
vir journal # today
vir journal 2026-11-04 # one day
vir journal --since 2026-10-28 # every day with activity since then
vir journal --all # rewrite every day
vir journal --stdout # print instead of writing
vir journal --tz Europe/Belgrade
Days are local calendar days in your machine's time zone (or --tz). The
facts are copied into vir's SQLite state first, so the journal survives Claude
Code deleting transcripts after about 30 days; delete the folder and re-run to
get the same files back. Edits to journal files are overwritten. Search
(vir query, MCP) and vir lint skip the folder: it records work done, it
isn't knowledge to retrieve.
An unfinished task carries over day to day until it's completed, deleted, picked up again under the same name in a later session, or left untouched for more than 7 days.
Limits: Claude Code sessions only (not Codex yet). Commits made with
git commit -q, merges, rebases and commits outside an agent session aren't
seen. Work finished outside a session keeps carrying until the 7-day limit.
vir ships an Agent Skills skill that teaches Claude
Code, Codex, Cursor and other skill-aware agents to check your notes before
they work: search with vir query --json (free, no LLM call), cite the notes
they use, and verify them against the current code.
npx skills add djolex999/virThe skill is read-only. It never writes your notes, never runs paid commands
like vir run unless you ask, and if vir isn't installed it tells you how to
set it up instead of installing it. It prefers the MCP server when that's
registered, and falls back to reading the notes folder directly. Source:
skills/vir/SKILL.md.
Vir runs as an MCP server, letting your coding agent consult your vault mid-session instead of relying on static CLAUDE.md / AGENTS.md content.
vir mcp install # Claude Code: registers via `claude mcp add`
vir mcp install --target codex # Codex: prints the config to addFor Codex, vir never edits ~/.codex/config.toml itself; it prints the block
(or run codex mcp add vir -- vir mcp):
[mcp_servers.vir]
command = "vir"
args = ["mcp"]Restart the agent. The vault is now queryable mid-session via six tools:
vir_query, vir_status, vir_recent_notes, vir_recent_articles,
vir_project_summary, vir_compose. vir_query takes a type filter
(session | article | topic | pdf | all). Human-verified notes
(approved via vir review) get a +0.2 score boost; pass verified_only: true
to see only those. The server never writes the vault. vir_query is the one tool
that spends tokens: it synthesizes an answer with your provider, and
synthesize: false returns just the matching notes.
To unregister: vir mcp uninstall.
Vir works out of the box with keyword search (TF-IDF). No embedding setup is required, ever. For semantic search, pick one of two providers; vir detects whichever is present:
One command, no Ollama:
vir embed --setup # installs fastembed + bge-small-en-v1.5 into ~/.vir
# (~233 MB + ~128 MB model; states cost, asks first)Or Ollama (768d, slightly larger model):
brew install ollama
ollama pull nomic-embed-text
ollama serveThen:
vir embed
vir query "how do I handle rate limiting in Next.js"Every stored vector records the model that produced it. Vectors from
different models are never compared; if you switch providers,
vir embed --force re-embeds the index after telling you what it costs.
Falls back to keyword search automatically when no provider is available,
and says so: via tfidf (no provider). Results rank by pure relevance by
default; retrievalDiversity (0..1) turns on MMR reranking, which trades
relevance for diversity. A verified note gets a small boost only when it
already ranks near the top, so it wins near-ties without displacing more
relevant notes.
Located at ~/.vir/config.json.
| Field | Default | Description |
|---|---|---|
vaultPath |
(required) | Absolute path to your notes folder (Obsidian vault optional) |
outputDir |
vir |
Subdir inside vault |
claudeProjectsDir |
~/.claude/projects |
Claude Code sessions |
cadenceHours |
3 |
Daemon run frequency (hours) |
provider |
anthropic |
anthropic | claude-cli (subscription, keyless) | kie |
anthropicApiKey |
(unset) | Required if provider=anthropic |
kieApiKey |
(unset) | Required if provider=kie |
filterThreshold |
0.4 |
Heuristic pre-filter (0..1) |
articlesDir |
(unset) | Folder of clipped articles. Unset → article ingestion off |
pdfsDir |
(unset) | Folder of PDFs. Unset → PDF ingestion off |
workflowTranscripts |
exclude |
Workflow/sidechain transcripts: exclude | include |
agentTranscripts |
exclude |
Headless SDK agent transcripts: exclude | include |
projects |
(unset) | Per-project include/exclude map; absent = undecided |
filterToolCalls |
moderate |
Tool-output filtering: aggressive | moderate | off |
retrievalDiversity |
0 |
MMR diversity (0..1); 0 = pure relevance |
logQueries |
true |
Log retrievals to ~/.vir/queries.jsonl; false = off |
checkTranscripts |
false |
After each daemon pass, run vir audit --transcript on the oldest unchecked notes |
checkTranscriptsPerRun |
20 |
Notes checked per daemon pass when checkTranscripts is on |
embeddingProvider |
(unset) | ollama | local | none; unset = auto-detect |
models.classify |
claude-haiku-5-5 |
Classify model (Kie keeps Haiku 4.5) |
models.distill |
claude-sonnet-5 |
Distill model for decision-heavy and large sessions |
models.distillFast |
(unset) | Cheap model for routine sessions; set → hybrid routing on |
models.distillThreshold |
100000 |
Input-token ceiling above which distill is forced |
pricing |
(built-in) | Optional per-provider $/1M overrides |
vault/vir/
index.md # full catalog of every note vir has written
log.md # chronological append log of each run
patterns/ # reusable approaches worth repeating
gotchas/ # bugs, footguns, and edge cases
decisions/ # architecture decisions with their rationale
tools/ # per-tool knowledge and usage notes
articles/ # web articles distilled from your clips folder
pdfs/ # distilled PDFs and papers
topics/ # synthesized topic pages (vir compose)
projects/ # cross-session project summaries
summaries/ # weekly/monthly period summaries (derived, never indexed)
journal/ # daily work journal, YYYY-MM-DD.md (vir journal; never indexed)
archived/ # deduplicated notes (kept, never deleted)
~/.vir/config.json # configuration
~/.vir/vir.db # SQLite (hashes, embeddings, content)
~/.vir/cost.log # per-call cost records (JSONL)
~/.vir/daemon.log # daemon run log
~/.vir/queries.jsonl # retrieval log (JSONL, rotates at 5 MB, one .1 kept)
Every vir query and MCP vir_query retrieval appends one record to
~/.vir/queries.jsonl: the query text, which notes surfaced at what rank and
score, the search method (embedding vs TF-IDF fallback), and latency. It never
records the synthesized answer.
This log stays on your
8
machine
8F1C
— it is never transmitted anywhere. It
exists so vir queries can tell you which notes actually earn their place in
retrieval (and which never surface), and it is the baseline for future ranking
improvements. Delete it any time; disable it with "logQueries": false in
~/.vir/config.json.
| Version | 0.24.2 |
| Tests | 1073 passing |
| Platforms | macOS (launchd), Linux (systemd/cron) |
| Node | 20+ |
| First-run cost | $1 to $5 (Kie.ai optional, ~72% cheaper) |
| Ongoing cost | ~$0.05 per run |
Shipped:
- Linux support (systemd timer + cron fallback), experimental
- Active learning:
vir review, verified notes boosted in retrieval - Web article ingestion (a clipped-markdown folder → same vault)
- PDF and paper ingestion
- Obsidian plugin: vir-obsidian, sidebar queries against the vault
- Topic synthesis:
vir composebuilds topic pages from related notes - Transcript filtering: workflow, sidechain, and SDK-agent transcripts detected and skipped by default
- Project triage:
vir projects, per-project include/exclude with pending-cost estimates - Duplicate detection and merge:
vir dedupe - Obsidian optional: any folder of markdown works (0.24.3)
- Any agent can read your notes:
npx skills add djolex999/vir(0.25.0) - Recurring lessons become reviewed rules:
vir connect(0.25.0) - Codex sessions, and a keyless
codex-cliprovider (0.26.0) - Daily work journal from transcripts, no LLM calls:
vir journal(0.30.0)
Not built:
- Windows support
- GUI installer for non-developers
- More input sources: code repos, images
- Export to anchor-plugin skill format
- Cursor sessions (Codex shipped in 0.26.0)
- Connect pass v2: flag decisions that contradict each other or went stale
PRs welcome. Open an issue first for large changes. Built with TypeScript
strict; run npm run build and npm test before submitting. See
CONTRIBUTING.md for development setup.
git clone https://github.com/djolex999/vir
cd vir
npm install
npm run build
npm testMIT
Built by Djordje Marković / GrowthQ Lab DOO.
Vir (вир) is the Serbian word for whirlpool: the place where a river pulls everything in and concentrates it. Sessions flow in, vir pulls out what matters, and deposits it somewhere permanent.
Inspired by Andrej Karpathy's LLM Wiki pattern and Uros Pesic's KB Brain concept.
If vir saves you time, a coffee on Ko-fi keeps it maintained and in step with Claude Code and Codex releases.
GitHub · LinkedIn · npm · GrowthQ Lab