@djolex999/vir-cli 0.14.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +281 -264
- package/dist/cli/embedSetup.js +62 -0
- package/dist/cli/embedSetup.js.map +1 -0
- package/dist/cli/queries.js +44 -0
- package/dist/cli/queries.js.map +1 -0
- package/dist/cli.js +143 -20
- package/dist/cli.js.map +1 -1
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -1
- package/dist/diagnostics/doctor.js +79 -0
- package/dist/diagnostics/doctor.js.map +1 -1
- package/dist/mcp/server.js +19 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/pipeline/embeddingSweep.js +17 -11
- package/dist/pipeline/embeddingSweep.js.map +1 -1
- package/dist/pipeline/run.js +19 -7
- package/dist/pipeline/run.js.map +1 -1
- package/dist/pipeline/writer.js +43 -23
- package/dist/pipeline/writer.js.map +1 -1
- package/dist/search/embedder.js +75 -15
- package/dist/search/embedder.js.map +1 -1
- package/dist/search/localProvider.js +99 -0
- package/dist/search/localProvider.js.map +1 -0
- package/dist/search/provider.js +72 -0
- package/dist/search/provider.js.map +1 -0
- package/dist/search/queryLog.js +123 -0
- package/dist/search/queryLog.js.map +1 -0
- package/dist/search/retriever.js +61 -17
- package/dist/search/retriever.js.map +1 -1
- package/dist/search/thresholds.js +18 -0
- package/dist/search/thresholds.js.map +1 -0
- package/dist/state/db.js +65 -17
- package/dist/state/db.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/vir_whirlpool_logo.svg" width="
|
|
2
|
+
<img src="assets/vir_whirlpool_logo.svg" width="140" height="140" alt="vir logo">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">vir</h1>
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
An LLM Wiki for Claude Code, in your Obsidian vault.
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img src="docs/graph.png" width="900" alt="Obsidian graph view of a vault distilled by vir: session notes, articles, PDFs, and topic pages, cross-linked">
|
|
13
|
+
</p>
|
|
14
|
+
|
|
11
15
|
<!--
|
|
12
16
|
GitHub topics (add manually: repo → About → ⚙ → Topics):
|
|
13
17
|
claude, claude-code, ai-memory, obsidian, knowledge-base, llm,
|
|
@@ -18,134 +22,62 @@ developer-tools, mcp, local-first, cross-platform, llm-wiki
|
|
|
18
22
|
<a href="https://www.npmjs.com/package/@djolex999/vir-cli"><img src="https://img.shields.io/npm/v/@djolex999/vir-cli?color=7c6af7&label=npm" alt="npm version"></a>
|
|
19
23
|
<a href="https://www.npmjs.com/package/@djolex999/vir-cli"><img src="https://img.shields.io/npm/dw/@djolex999/vir-cli?color=4fd1a0" alt="npm downloads"></a>
|
|
20
24
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-22d3ee" alt="license"></a>
|
|
21
|
-
<a href="#project-status"><img src="https://img.shields.io/badge/tests-
|
|
25
|
+
<a href="#project-status"><img src="https://img.shields.io/badge/tests-441%20passing-22c55e" alt="tests"></a>
|
|
22
26
|
<a href="#project-status"><img src="https://img.shields.io/badge/platforms-macOS%20%7C%20Linux-lightgrey" alt="platforms"></a>
|
|
23
27
|
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-server-c084fc" alt="mcp"></a>
|
|
24
28
|
<a href="#"><img src="https://img.shields.io/badge/local--first-yes-f59e0b" alt="local-first"></a>
|
|
25
29
|
<a href="https://github.com/djolex999/vir"><img src="https://img.shields.io/github/stars/djolex999/vir?style=social" alt="stars"></a>
|
|
26
30
|
</p>
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
artifact, instead of resetting at the end of every session. He published the idea
|
|
33
|
-
file at [karpathy/llm-wiki.md](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)
|
|
34
|
-
and ended his
|
|
35
|
-
post saying: _"I think there is room here for an incredible new product instead of
|
|
36
|
-
a hacky collection of scripts."_
|
|
37
|
-
|
|
38
|
-
Several open source implementations of this pattern now exist
|
|
39
|
-
([lucasastorian/llmwiki](https://github.com/lucasastorian/llmwiki),
|
|
40
|
-
[Pratiyush/llm-wiki](https://github.com/Pratiyush/llm-wiki),
|
|
41
|
-
[nashsu/llm_wiki](https://github.com/nashsu/llm_wiki) among them). Each takes a
|
|
42
|
-
different shape.
|
|
43
|
-
|
|
44
|
-
Vir is the Obsidian-native one. It treats Obsidian as the primary frontend — not
|
|
45
|
-
just a storage location — and integrates deeply (sidebar plugin coming,
|
|
46
|
-
dataview-compatible frontmatter, canvas integration planned). It reads AI coding
|
|
47
|
-
session transcripts retroactively, so months of existing history become a
|
|
48
|
-
queryable knowledge base in one run.
|
|
32
|
+
That graph is my vault. Every node is a plain markdown file that vir wrote by
|
|
33
|
+
reading my Claude Code transcripts. It lives in Obsidian next to my own notes.
|
|
34
|
+
There is no server, no account, no export step. Uninstall vir tomorrow and the
|
|
35
|
+
vault stays yours.
|
|
49
36
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
## Why this exists
|
|
37
|
+
## Two numbers
|
|
53
38
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
**354 sessions.** Claude Code prunes transcripts after about 30 days. 354 of my
|
|
40
|
+
sessions now exist nowhere except this vault. The decisions and gotchas inside
|
|
41
|
+
them would otherwise be gone.
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
43
|
+
**243 transcripts, about 20 mine.** Of the 243 transcripts on my machine, about
|
|
44
|
+
20 were sessions I actually drove. The rest were subagent runs, workflow
|
|
45
|
+
phases, and headless SDK agents. Vir detects all three kinds and skips them by
|
|
46
|
+
default. The vault holds your work, not your tooling's.
|
|
62
47
|
|
|
63
|
-
|
|
64
|
-
<img src="assets/demo.gif" width="800" alt="vir distilling Claude Code sessions into notes in an Obsidian vault">
|
|
65
|
-
</p>
|
|
48
|
+
## Quick start
|
|
66
49
|
|
|
67
|
-
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g @djolex999/vir-cli
|
|
52
|
+
vir init
|
|
53
|
+
vir run
|
|
54
|
+
```
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
`vir init` is a wizard: provider, models, vault path. `vir run` does one pass
|
|
57
|
+
over your sessions and writes notes. When you like the output,
|
|
58
|
+
`vir schedule install` registers a daemon that keeps the vault current.
|
|
70
59
|
|
|
71
|
-
|
|
72
|
-
submitted to the community plugin marketplace
|
|
73
|
-
- **Multi-agent support** — Codex CLI, Cursor, Aider, Cline (one per release)
|
|
74
|
-
- **PDF/paper ingestion** — broaden beyond developer workflows
|
|
60
|
+
## What it does
|
|
75
61
|
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
Vir reads transcripts from `~/.claude/projects`, filters out the noise,
|
|
63
|
+
classifies what survives with Haiku, and distills durable knowledge with
|
|
64
|
+
Sonnet. Notes are typed: patterns, gotchas, decisions, tools. Three input
|
|
65
|
+
sources feed one vault:
|
|
78
66
|
|
|
79
|
-
|
|
67
|
+
- **Claude Code sessions.** Retroactive: months of existing history become
|
|
68
|
+
notes in one run.
|
|
69
|
+
- **Web articles** clipped to a folder, e.g. via Obsidian Web Clipper.
|
|
70
|
+
- **PDFs and papers.**
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
Everything embeds into one vector space (Ollama, optional, TF-IDF fallback).
|
|
73
|
+
`vir query "<question>"` searches it and synthesizes an answer. An MCP server
|
|
74
|
+
exposes the vault to Claude Code mid-session, so the agent consults past
|
|
75
|
+
decisions instead of rediscovering them. `vir sync-claude` feeds the best
|
|
76
|
+
notes back into your CLAUDE.md files, with a diff and your confirmation.
|
|
84
77
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
or below `0.6` is dropped _before_ the more expensive distill step. Only
|
|
89
|
-
high-confidence notes reach the vault.
|
|
90
|
-
- **Opt-in `CLAUDE.md` sync.** Nothing vir generates touches your prompt context
|
|
91
|
-
automatically. `vir sync-claude` shows a diff and waits for your confirmation —
|
|
92
|
-
you decide what reaches Claude.
|
|
93
|
-
- **Plain markdown output.** Every note is a file in your Obsidian vault. Read
|
|
94
|
-
it, edit it, delete it. Nothing is hidden in a compressed database you can't
|
|
95
|
-
inspect.
|
|
96
|
-
- **Lint and dedupe.** `vir lint` flags contradictions and stale notes;
|
|
97
|
-
`vir dedupe` merges similar notes that have drifted apart.
|
|
98
|
-
- **Active learning** via `vir review`. Walk through new distillations and
|
|
99
|
-
approve, edit, or reject each one. Verified notes get retrieval priority over
|
|
100
|
-
unverified ones (in `vir query` and the MCP server). Rejected notes are moved
|
|
101
|
-
to `.rejected/` — recoverable, not deleted.
|
|
102
|
-
- **MMR-diverse retrieval**. Queries return notes covering different aspects of
|
|
103
|
-
the topic, not 5 similar duplicates. The retrieval algorithm balances
|
|
104
|
-
relevance against diversity automatically.
|
|
105
|
-
- **Topic synthesis** via `vir compose "<topic>"`. Embedding-searches the vault
|
|
106
|
-
for related session notes and articles, then synthesizes them into a single
|
|
107
|
-
topic page under `topics/`, with each source wikilinked so it backlinks in
|
|
108
|
-
Obsidian's graph. `--dry-run` previews the sources and cost for free.
|
|
109
|
-
- **Cost transparency.** `vir run --dry-run` estimates per-session cost _before_
|
|
110
|
-
you spend a cent; `vir cost` reports the actuals (total, median, p90, top
|
|
111
|
-
sessions) from a local `~/.vir/cost.log`; and `--force-model haiku|sonnet`
|
|
112
|
-
lets you calibrate quality against price. Pricing is provider-aware (Anthropic
|
|
113
|
-
list rates + Kie's discount), so the numbers reflect _your_ bill — not a
|
|
114
|
-
blended guess. Kie rates are approximate; override them in `config.pricing` if
|
|
115
|
-
a report looks off.
|
|
116
|
-
- **Reliable failures (v0.8.0).** Every command now exits non-zero on failure —
|
|
117
|
-
no more silent successes hiding broken distills. `vir reconcile --dry-run`
|
|
118
|
-
reports any pre-0.8.0 sessions that landed with empty content (e.g. via the
|
|
119
|
-
v0.7.1 Kie-200-with-body-error bug); `vir reconcile` retries them, bypassing
|
|
120
|
-
the SHA-256 processed-cache for just those rows. Retries that fail again
|
|
121
|
-
leave the row untouched so a second pass can catch them once the underlying
|
|
122
|
-
cause is fixed. Kie 404s carrying an `api_error` body envelope (transient
|
|
123
|
-
service hiccups) are now retried alongside 429/5xx.
|
|
124
|
-
|
|
125
|
-
The bet: with these controls, signal-to-noise stays high enough that the vault
|
|
126
|
-
is a net positive. If your discipline is strong enough to maintain `CLAUDE.md`
|
|
127
|
-
and `lessons.md` by hand, you may not need this. If — like most of us — you let
|
|
128
|
-
those files drift after the first week, Vir catches what slips through.
|
|
129
|
-
|
|
130
|
-
## How it works
|
|
131
|
-
|
|
132
|
-
Vir reads your transcripts from `~/.claude/projects/**/*.jsonl`, runs each
|
|
133
|
-
session through a cheap heuristic filter, classifies the survivors with Haiku,
|
|
134
|
-
and distills durable knowledge with Sonnet. Before distillation it **filters tool
|
|
135
|
-
calls** — preserving intent (file paths, commands, search patterns, errors, short
|
|
136
|
-
results) while truncating large embedded content (file writes, long bash logs,
|
|
137
|
-
big grep dumps) to keep token cost bounded (tunable via `filterToolCalls`).
|
|
138
|
-
Results are written as typed notes — patterns, gotchas, decisions, tools —
|
|
139
|
-
cross-linked with wikilinks and indexed. State lives in local SQLite; content
|
|
140
|
-
hashes make reruns idempotent. Optional Ollama embeddings power semantic search,
|
|
141
|
-
and an MCP server exposes the whole vault to Claude Code mid-session.
|
|
142
|
-
|
|
143
|
-
Web articles saved to a `raw/` directory (e.g. via Obsidian Web Clipper) flow
|
|
144
|
-
through a **parallel pipeline** with its own taxonomy — `concept`, `technique`,
|
|
145
|
-
`reference`, `opinion` — filed under `articles/` in the same vault, embedded and
|
|
146
|
-
indexed alongside session notes, and queryable through the same MCP tools.
|
|
147
|
-
Articles always keep their source URL in frontmatter for backlinks; distillation
|
|
148
|
-
paraphrases and never reproduces more than a short quote.
|
|
78
|
+
<p align="center">
|
|
79
|
+
<img src="assets/demo.gif" width="800" alt="vir distilling Claude Code sessions into notes in an Obsidian vault">
|
|
80
|
+
</p>
|
|
149
81
|
|
|
150
82
|
```
|
|
151
83
|
Claude Code sessions
|
|
@@ -161,7 +93,82 @@ better sessions
|
|
|
161
93
|
...
|
|
162
94
|
```
|
|
163
95
|
|
|
164
|
-
##
|
|
96
|
+
## The pattern
|
|
97
|
+
|
|
98
|
+
In April 2026, Andrej Karpathy described a pattern he calls the **LLM Wiki**:
|
|
99
|
+
AI work that feeds back into itself through a persistent, curated, structured
|
|
100
|
+
artifact, instead of resetting at the end of every session. He published the
|
|
101
|
+
idea file at
|
|
102
|
+
[karpathy/llm-wiki.md](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)
|
|
103
|
+
and ended his post saying: _"I think there is room here for an incredible new
|
|
104
|
+
product instead of a hacky collection of scripts."_
|
|
105
|
+
|
|
106
|
+
Several open source implementations of this pattern now exist
|
|
107
|
+
([lucasastorian/llmwiki](https://github.com/lucasastorian/llmwiki),
|
|
108
|
+
[Pratiyush/llm-wiki](https://github.com/Pratiyush/llm-wiki),
|
|
109
|
+
[nashsu/llm_wiki](https://github.com/nashsu/llm_wiki) among them). Each takes
|
|
110
|
+
a different shape.
|
|
111
|
+
|
|
112
|
+
Vir is the Obsidian-native one. It treats Obsidian as the primary frontend,
|
|
113
|
+
not just a storage location: a sidebar plugin
|
|
114
|
+
([vir-obsidian](https://github.com/djolex999/vir-obsidian)),
|
|
115
|
+
dataview-compatible frontmatter, wikilinked notes that show up in the graph.
|
|
116
|
+
It reads AI coding session transcripts retroactively, so months of existing
|
|
117
|
+
history become a queryable knowledge base in one run.
|
|
118
|
+
|
|
119
|
+
[Karpathy's post →](https://x.com/karpathy/status/2039805659525644595)
|
|
120
|
+
|
|
121
|
+
## Quality controls
|
|
122
|
+
|
|
123
|
+
Auto-distilled notes can be wrong. The most common concern from early users:
|
|
124
|
+
_"if your distillations are wrong, Claude treats them as truth and you get
|
|
125
|
+
worse results, not better."_ Fair. Vir addresses it in layers:
|
|
126
|
+
|
|
127
|
+
- **Transcript filtering.** Workflow transcripts, subagent sidechains, and
|
|
128
|
+
headless SDK agent runs are detected structurally and excluded before any
|
|
129
|
+
API call. Every skip is recorded with a reason, and every skip is
|
|
130
|
+
reversible: flip the knob and the transcripts re-enter on the next run.
|
|
131
|
+
- **Project triage.** `vir projects` shows every project with session counts
|
|
132
|
+
and estimated pending cost. Include or exclude each one. Undecided projects
|
|
133
|
+
are a visible state, never a silent default.
|
|
134
|
+
- **Confidence scores on every note**, written into the frontmatter
|
|
135
|
+
(`confidence: 0.xx`). A cheap heuristic pre-filter drops low-signal sessions
|
|
136
|
+
before any LLM call; classification then scores what survives, and anything
|
|
137
|
+
at or below `0.6` is dropped before the more expensive distill step.
|
|
138
|
+
- **Opt-in `CLAUDE.md` sync.** Nothing vir generates touches your prompt
|
|
139
|
+
context automatically. `vir sync-claude` shows a diff and waits for your
|
|
140
|
+
confirmation. You decide what reaches Claude.
|
|
141
|
+
- **Plain markdown output.** Every note is a file in your Obsidian vault. Read
|
|
142
|
+
it, edit it, delete it. Nothing is hidden in a database you can't inspect.
|
|
143
|
+
- **Lint and dedupe.** `vir lint` flags contradictions and stale notes;
|
|
144
|
+
`vir dedupe` merges near-duplicate notes that have drifted apart.
|
|
145
|
+
- **Active learning** via `vir review`. Walk through new distillations and
|
|
146
|
+
approve, edit, or reject each one. Verified notes rank first in retrieval
|
|
147
|
+
(in `vir query` and the MCP server). Rejected notes move to `.rejected/`,
|
|
148
|
+
recoverable, not deleted.
|
|
149
|
+
- **MMR-diverse retrieval.** Queries return notes covering different aspects
|
|
150
|
+
of the topic, not 5 similar duplicates.
|
|
151
|
+
- **Topic synthesis** via `vir compose "<topic>"`. Embedding-searches the
|
|
152
|
+
vault for related notes and synthesizes them into a single topic page under
|
|
153
|
+
`topics/`, with each source wikilinked so it backlinks in Obsidian's graph.
|
|
154
|
+
`--dry-run` previews the sources and cost for free.
|
|
155
|
+
- **Cost transparency.** `vir run --dry-run` estimates per-session cost before
|
|
156
|
+
you spend a cent; `vir cost` reports the actuals (total, median, p90, top
|
|
157
|
+
sessions) from a local `~/.vir/cost.log`. Pricing is provider-aware
|
|
158
|
+
(Anthropic list rates and Kie's discount), so the numbers reflect your
|
|
159
|
+
bill, not a blended guess.
|
|
160
|
+
- **Reliable failures.** Every command exits non-zero on failure. A provider
|
|
161
|
+
outage is one clear failure, not a retry storm: a cheap preflight probe
|
|
162
|
+
runs before the distill loop. Sessions that fail 3 times in a row are
|
|
163
|
+
parked until you retry them with `vir reconcile --force`.
|
|
164
|
+
|
|
165
|
+
The bet: with these controls, signal-to-noise stays high enough that the
|
|
166
|
+
vault is a net positive. If your discipline is strong enough to maintain
|
|
167
|
+
`CLAUDE.md` and `lessons.md` by hand, you may not need this. If, like most of
|
|
168
|
+
us, you let those files drift after the first week, vir catches what slips
|
|
169
|
+
through.
|
|
170
|
+
|
|
171
|
+
## How vir compares
|
|
165
172
|
|
|
166
173
|
The LLM Wiki space has grown fast. Honest comparison:
|
|
167
174
|
|
|
@@ -171,8 +178,8 @@ The LLM Wiki space has grown fast. Honest comparison:
|
|
|
171
178
|
| --------------------------------- | ---------------------------- | ----------------------------- | ---------------------------------------- | ------------------------- |
|
|
172
179
|
| Language | TypeScript / Node | Python | Python | Cross-platform desktop |
|
|
173
180
|
| Distribution | `npm install -g` | Local app + hosted SaaS | `git clone` + python | Desktop app installer |
|
|
174
|
-
| Obsidian integration | Native (plugin
|
|
175
|
-
| Input sources | Claude Code,
|
|
181
|
+
| Obsidian integration | Native (sidebar plugin) | Markdown output | Outputs to vault | Own UI, no Obsidian |
|
|
182
|
+
| Input sources | Claude Code, web clips, PDFs | PDFs, docs upload | Claude Code, Cursor, Cline, Codex, Gemini | Documents, mixed sources |
|
|
176
183
|
| Retroactive on existing sessions | ✓ | n/a | from install forward | n/a |
|
|
177
184
|
| MCP server | ✓ | ✓ | ✓ | ✓ |
|
|
178
185
|
| License | MIT | open source + hosted commercial | MIT | open source |
|
|
@@ -186,22 +193,22 @@ The LLM Wiki space has grown fast. Honest comparison:
|
|
|
186
193
|
| Setup | `npm install -g` | Bun + uv + Python | pnpm + LM Studio | API/cloud setup |
|
|
187
194
|
| License | MIT | Apache 2.0 | MIT | open core + cloud |
|
|
188
195
|
|
|
189
|
-
|
|
196
|
+
Different tools for different needs:
|
|
190
197
|
|
|
191
198
|
- **If you want a polished cross-platform desktop app** for general document
|
|
192
199
|
knowledge bases, use lucasastorian/llmwiki or nashsu/llm_wiki.
|
|
193
|
-
- **If you want multi-agent support** with rich entity/concept page taxonomy
|
|
194
|
-
don't care about Obsidian integration depth, use Pratiyush/llm-wiki.
|
|
195
|
-
- **If you want a heavyweight Claude Code memory plugin** with real-time
|
|
196
|
-
and vector storage, use claude-mem.
|
|
197
|
-
- **If you're building AI applications that need to remember users**
|
|
198
|
-
use mem0 (different layer entirely).
|
|
199
|
-
- **If you want an Obsidian-native LLM Wiki** that reads your existing Claude
|
|
200
|
-
sessions
|
|
200
|
+
- **If you want multi-agent support** with a rich entity/concept page taxonomy
|
|
201
|
+
and don't care about Obsidian integration depth, use Pratiyush/llm-wiki.
|
|
202
|
+
- **If you want a heavyweight Claude Code memory plugin** with real-time
|
|
203
|
+
capture and vector storage, use claude-mem.
|
|
204
|
+
- **If you're building AI applications that need to remember users**
|
|
205
|
+
long-term, use mem0 (different layer entirely).
|
|
206
|
+
- **If you want an Obsidian-native LLM Wiki** that reads your existing Claude
|
|
207
|
+
Code sessions, use vir.
|
|
201
208
|
|
|
202
|
-
##
|
|
209
|
+
## Numbers from a real run
|
|
203
210
|
|
|
204
|
-
|
|
211
|
+
Output from my first run across 226 Claude Code sessions:
|
|
205
212
|
|
|
206
213
|
| Metric | Value |
|
|
207
214
|
| ------------------- | ------------------------------------------------- |
|
|
@@ -212,10 +219,9 @@ Real output from the author's first run across 226 Claude Code sessions.
|
|
|
212
219
|
| Projects covered | 8 projects |
|
|
213
220
|
| Knowledge breakdown | 54 patterns · 47 decisions · 23 gotchas · 2 tools |
|
|
214
221
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
retroactive + multi-agent positioning match how you actually work?
|
|
222
|
+
Other LLM Wiki implementations would produce similar results with the same
|
|
223
|
+
input. The distinguishing question for vir is workflow fit: does
|
|
224
|
+
Obsidian-native plus retroactive match how you actually work?
|
|
219
225
|
|
|
220
226
|
Example query against the distilled vault:
|
|
221
227
|
|
|
@@ -225,21 +231,19 @@ $ vir query "what gotchas should I know about my auth implementation"
|
|
|
225
231
|
|
|
226
232
|
Based on the notes, here are the key auth gotchas:
|
|
227
233
|
|
|
228
|
-
JWT dual-token setup needs silent refresh on mount
|
|
229
|
-
expire in 15 min
|
|
234
|
+
JWT dual-token setup needs silent refresh on mount. Access tokens
|
|
235
|
+
expire in 15 min; without a mount-time refresh check, users hit
|
|
230
236
|
401s on first load after a break.
|
|
231
|
-
Middleware runs before the session is hydrated
|
|
232
|
-
session data in middleware to gate routes
|
|
237
|
+
Middleware runs before the session is hydrated. Do not read
|
|
238
|
+
session data in middleware to gate routes; check the JWT directly
|
|
233
239
|
from the cookie instead.
|
|
234
|
-
Password reset tokens must be single-use and hashed at rest
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
OAuth callback URLs must be registered exactly — trailing slashes,
|
|
240
|
+
Password reset tokens must be single-use and hashed at rest.
|
|
241
|
+
Storing raw tokens in the DB leaks them if the DB is compromised.
|
|
242
|
+
OAuth callback URLs must be registered exactly. Trailing slashes,
|
|
238
243
|
http vs https, and localhost port mismatches all cause silent
|
|
239
244
|
redirect failures with no useful error message.
|
|
240
245
|
Logout must clear both the access token cookie and the refresh
|
|
241
|
-
token
|
|
242
|
-
causes confusing re-auth loops.
|
|
246
|
+
token. Clearing only one leaves the session partially alive.
|
|
243
247
|
|
|
244
248
|
sources 4 · via embedding · searched 126
|
|
245
249
|
|
|
@@ -252,70 +256,54 @@ sources 4 · via embedding · searched 126
|
|
|
252
256
|
- Anthropic API key **or** Kie.ai API key (~72% cheaper, same models)
|
|
253
257
|
- Optional: Ollama + `nomic-embed-text` for semantic search
|
|
254
258
|
|
|
255
|
-
## Install
|
|
256
|
-
|
|
257
|
-
```bash
|
|
258
|
-
npm install -g @djolex999/vir-cli
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
## Quick start
|
|
262
|
-
|
|
263
|
-
```bash
|
|
264
|
-
vir init # guided wizard: provider, models, vault, cadence,
|
|
265
|
-
# and an optional web-articles (raw/) folder
|
|
266
|
-
vir run # one pass over your sessions → notes in your vault
|
|
267
|
-
vir schedule install # register the daemon (runs every 3h by default)
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
`vir init` asks whether you save web articles to a folder (e.g. Obsidian Web
|
|
271
|
-
Clipper). Point it at that `raw/` directory and Vir distills those articles into
|
|
272
|
-
the same vault. Leave it blank to keep Vir session-only.
|
|
273
|
-
|
|
274
|
-
`vir schedule install` works on Linux too: systemd is preferred, with cron used
|
|
275
|
-
as a fallback when `systemctl` isn't available.
|
|
276
|
-
|
|
277
259
|
## Cost
|
|
278
260
|
|
|
279
|
-
Vir runs two API calls per session: a Haiku classify (cheap) and a
|
|
261
|
+
Vir runs two API calls per session: a Haiku classify (cheap) and a distill
|
|
262
|
+
(the main cost). Cost depends on session size and your provider.
|
|
280
263
|
|
|
281
|
-
### Real cost shape (
|
|
264
|
+
### Real cost shape (measured on 226 historical sessions via Kie)
|
|
282
265
|
|
|
283
|
-
| Metric | Sonnet
|
|
266
|
+
| Metric | Sonnet | Haiku |
|
|
284
267
|
|---|---|---|
|
|
285
268
|
| Median session | $0.07 | $0.025 |
|
|
286
269
|
| p90 session | $0.20 | $0.07 |
|
|
287
270
|
| Long-tail outliers (5-hour epics) | $0.25-$0.30 | $0.08-$0.10 |
|
|
288
271
|
| 226-session backfill | ~$21 | ~$7 |
|
|
289
272
|
|
|
290
|
-
Costs assume Kie.ai pricing (~28% of Anthropic direct). Multiply by ~3.
|
|
273
|
+
Costs assume Kie.ai pricing (~28% of Anthropic direct). Multiply by ~3.5x for
|
|
274
|
+
Anthropic direct rates.
|
|
291
275
|
|
|
292
276
|
### What drives cost
|
|
293
277
|
|
|
294
|
-
Distill output dominates. A multi-hour
|
|
278
|
+
Distill output dominates. A multi-hour session with hundreds of tool calls
|
|
279
|
+
distills to ~4500 output tokens, plus 25-30k input tokens after tool-call
|
|
280
|
+
filtering. Vir strips large tool outputs and oversized skill loads before
|
|
281
|
+
distillation; on one real 517-tool-call session that took the distill input
|
|
282
|
+
from ~217k to ~95k tokens without dropping signal.
|
|
295
283
|
|
|
296
|
-
### Cost controls
|
|
284
|
+
### Cost controls
|
|
297
285
|
|
|
298
|
-
- `vir run`
|
|
299
|
-
- `vir
|
|
300
|
-
- `vir cost --
|
|
301
|
-
-
|
|
302
|
-
- `vir run --
|
|
286
|
+
- `vir run --dry-run` previews per-session cost before any API call.
|
|
287
|
+
- `vir run` asks for confirmation when more than 20 new sessions are queued.
|
|
288
|
+
- `vir cost --since 7d` aggregates real (not estimated) token usage from
|
|
289
|
+
`~/.vir/cost.log`; `--by-session` and `--top 5` surface outliers.
|
|
290
|
+
- `vir run --force-model haiku|sonnet` overrides the distill model per run.
|
|
303
291
|
|
|
304
292
|
### Hybrid routing
|
|
305
293
|
|
|
306
|
-
Haiku is ~
|
|
307
|
-
|
|
308
|
-
|
|
294
|
+
Haiku is ~3x cheaper than Sonnet and captures equal-or-more concrete detail
|
|
295
|
+
on routine and tool-heavy sessions. Calibration showed it only misses
|
|
296
|
+
higher-order architectural lessons on decision-heavy and very large sessions.
|
|
297
|
+
Hybrid routing exploits that. When `models.distillFast` is set, each session
|
|
298
|
+
routes after classification:
|
|
309
299
|
|
|
310
300
|
- `category === "decision"` → `models.distill` (Sonnet)
|
|
311
301
|
- `inputTokens > models.distillThreshold` (default `100000`) → `models.distill`
|
|
312
302
|
- otherwise → `models.distillFast` (Haiku)
|
|
313
303
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
To go all-cheap instead, set `models.distill` itself to the Haiku model (quality degrades on decision-heavy and very large sessions).
|
|
304
|
+
New installs (`vir init`) enable hybrid by default. Existing installs are
|
|
305
|
+
unaffected on upgrade: with `distillFast` unset, `models.distill` is used for
|
|
306
|
+
every session exactly as before.
|
|
319
307
|
|
|
320
308
|
## Platform support
|
|
321
309
|
|
|
@@ -324,11 +312,11 @@ To go all-cheap instead, set `models.distill` itself to the Haiku model (quality
|
|
|
324
312
|
| macOS | launchd | osascript | Stable |
|
|
325
313
|
| Linux (systemd) | systemd user timer | notify-send | Experimental |
|
|
326
314
|
| Linux (cron) | crontab | notify-send | Experimental |
|
|
327
|
-
| Windows | Not supported |
|
|
315
|
+
| Windows | Not supported | none | Planned |
|
|
328
316
|
|
|
329
|
-
Linux support is **experimental and untested
|
|
330
|
-
a systemd user timer and falls back to a crontab entry when systemd
|
|
331
|
-
Please report issues at
|
|
317
|
+
Linux support is **experimental and untested**. `vir schedule install`
|
|
318
|
+
prefers a systemd user timer and falls back to a crontab entry when systemd
|
|
319
|
+
is absent. Please report issues at
|
|
332
320
|
[github.com/djolex999/vir/issues](https://github.com/djolex999/vir/issues)
|
|
333
321
|
with your distro, init system, and Node version.
|
|
334
322
|
|
|
@@ -340,74 +328,69 @@ with your distro, init system, and Node version.
|
|
|
340
328
|
| `vir run` | cheap | Process new sessions |
|
|
341
329
|
| `vir run --full` | $$ | Reprocess all sessions |
|
|
342
330
|
| `vir run --rewrite-only` | free | Reformat notes, no API calls |
|
|
343
|
-
| `vir run --articles-only` | cheap | Distill only web articles
|
|
344
|
-
| `vir run --
|
|
331
|
+
| `vir run --articles-only` | cheap | Distill only web articles |
|
|
332
|
+
| `vir run --pdfs-only` | $$ | Distill only PDFs |
|
|
345
333
|
| `vir run --dry-run` | free | Estimate per-session cost, exit before LLM |
|
|
346
334
|
| `vir run --force-model <m>` | cheap | Override distill model: `haiku` \| `sonnet` |
|
|
335
|
+
| `vir projects` | free | Per-project triage: counts + pending cost |
|
|
336
|
+
| `vir projects include <p>` | free | Track a project |
|
|
337
|
+
| `vir projects exclude <p>` | free | Stop tracking (existing notes untouched) |
|
|
347
338
|
| `vir cost` | free | API cost report (total/median/p90/top) |
|
|
348
|
-
| `vir cost --since <dur>` | free | Cost within a window, e.g. `7d` `24h` `2w` |
|
|
349
|
-
| `vir cost --by-session` | free | Full per-session cost distribution |
|
|
350
339
|
| `vir query "<question>"` | cheap | Semantic search your vault |
|
|
351
|
-
| `vir
|
|
340
|
+
| `vir queries` | free | Retrieval report: method split, degraded rate, dead-weight notes |
|
|
352
341
|
| `vir compose "<topic>"` | $$ | Synthesize a topic page from related notes |
|
|
353
|
-
| `vir compose … --dry-run` | free | Preview sources + cost, exit before LLM |
|
|
354
342
|
| `vir summarize <project>` | cheap | Cross-session project synthesis |
|
|
355
|
-
| `vir summarize --
|
|
343
|
+
| `vir summarize --week` | cheap | Period summary of the week's notes |
|
|
356
344
|
| `vir lint` | cheap | Find orphans, stale notes, contradictions |
|
|
357
|
-
| `vir
|
|
358
|
-
| `vir lint --stale` | free | Staleness check only |
|
|
359
|
-
| `vir lint --contradictions` | cheap | Contradiction check (Haiku) |
|
|
360
|
-
| `vir dedupe` | cheap | Interactive duplicate detection |
|
|
345
|
+
| `vir dedupe` | cheap | Interactive duplicate detection + merge |
|
|
361
346
|
| `vir review` | free | Walk new notes: approve/edit/reject |
|
|
362
|
-
| `vir review --project <s>` | free | Review one project's notes |
|
|
363
|
-
| `vir review --all` | free | Re-review, including verified notes |
|
|
364
347
|
| `vir sync-claude` | free | Inject top knowledge into CLAUDE.md |
|
|
365
|
-
| `vir sync-claude --dry-run` | free | Preview changes, no writes |
|
|
366
|
-
| `vir sync-claude --force` | free | Apply without confirmation |
|
|
367
348
|
| `vir embed` | free | Generate embeddings for semantic search |
|
|
368
|
-
| `vir embed --
|
|
349
|
+
| `vir embed --setup` | free | Install the local embedding provider (no Ollama needed) |
|
|
369
350
|
| `vir schedule install` | free | Register the background daemon |
|
|
370
|
-
| `vir
|
|
371
|
-
| `vir
|
|
372
|
-
| `vir
|
|
373
|
-
| `vir
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
emits a JSON array of results to stdout (`[]` when none) and, on failure, a
|
|
380
|
-
single-line error object to stderr with empty stdout. `doctor --json` emits one
|
|
381
|
-
JSON object and always exits 0 (health lives in its `daemon` field).
|
|
351
|
+
| `vir status` | free | Knowledge base breakdown + daemon status |
|
|
352
|
+
| `vir doctor` | cheap | 13 install/config checks |
|
|
353
|
+
| `vir reconcile` | $$ | Retry sessions that failed, cache-bypassed |
|
|
354
|
+
| `vir mcp install` | free | Register the MCP server with Claude Code |
|
|
355
|
+
|
|
356
|
+
Most commands take `--dry-run`, `--yes`, or `--json` where they make sense;
|
|
357
|
+
run `vir <command> --help` for the full flag list. `vir query --json` and
|
|
358
|
+
`vir doctor --json` are the machine contracts the
|
|
359
|
+
[vir-obsidian](https://github.com/djolex999/vir-obsidian) plugin consumes.
|
|
382
360
|
|
|
383
361
|
## MCP server (Claude Code integration)
|
|
384
362
|
|
|
385
363
|
Vir runs as an MCP server, letting Claude Code consult your vault mid-session
|
|
386
364
|
instead of relying on static CLAUDE.md content.
|
|
387
365
|
|
|
388
|
-
Register Vir with Claude Code:
|
|
389
|
-
|
|
390
366
|
```bash
|
|
391
367
|
vir mcp install
|
|
392
368
|
```
|
|
393
369
|
|
|
394
|
-
Restart Claude Code. The vault is now queryable mid-session via
|
|
370
|
+
Restart Claude Code. The vault is now queryable mid-session via six tools:
|
|
395
371
|
`vir_query`, `vir_status`, `vir_recent_notes`, `vir_recent_articles`,
|
|
396
|
-
`vir_project_summary`. `vir_query` takes a `type` filter
|
|
397
|
-
(`session` | `article` | `
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
372
|
+
`vir_project_summary`, `vir_compose`. `vir_query` takes a `type` filter
|
|
373
|
+
(`session` | `article` | `topic` | `pdf` | `all`). Human-verified notes
|
|
374
|
+
(approved via `vir review`) rank first; pass `verified_only: true` to see
|
|
375
|
+
only those. The server is read-only: it never spends tokens and never writes
|
|
376
|
+
files.
|
|
377
|
+
|
|
378
|
+
To unregister: `vir mcp uninstall`.
|
|
379
|
+
|
|
380
|
+
## Semantic search (optional)
|
|
381
|
+
|
|
382
|
+
Vir works out of the box with keyword search (TF-IDF). No embedding setup is
|
|
383
|
+
required, ever. For semantic search, pick one of two providers; vir detects
|
|
384
|
+
whichever is present:
|
|
401
385
|
|
|
402
|
-
|
|
386
|
+
**One command, no Ollama:**
|
|
403
387
|
|
|
404
388
|
```bash
|
|
405
|
-
vir
|
|
389
|
+
vir embed --setup # installs fastembed + bge-small-en-v1.5 into ~/.vir
|
|
390
|
+
# (~233 MB + ~128 MB model; states cost, asks first)
|
|
406
391
|
```
|
|
407
392
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
Vir uses TF-IDF by default. For semantic search via embeddings:
|
|
393
|
+
**Or Ollama** (768d, slightly larger model):
|
|
411
394
|
|
|
412
395
|
```bash
|
|
413
396
|
brew install ollama
|
|
@@ -415,20 +398,19 @@ ollama pull nomic-embed-text
|
|
|
415
398
|
ollama serve
|
|
416
399
|
```
|
|
417
400
|
|
|
418
|
-
Then
|
|
401
|
+
Then:
|
|
419
402
|
|
|
420
403
|
```bash
|
|
421
404
|
vir embed
|
|
422
405
|
vir query "how do I handle rate limiting in Next.js"
|
|
423
406
|
```
|
|
424
407
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
`retrievalDiversity`
|
|
431
|
-
diverse).
|
|
408
|
+
Every stored vector records the model that produced it. Vectors from
|
|
409
|
+
different models are never compared; if you switch providers,
|
|
410
|
+
`vir embed --force` re-embeds the index after telling you what it costs.
|
|
411
|
+
Falls back to keyword search automatically when no provider is available,
|
|
412
|
+
and says so: `via tfidf (no provider)`. MMR reranking balances relevance
|
|
413
|
+
against diversity, tunable via `retrievalDiversity` (default 0.3).
|
|
432
414
|
|
|
433
415
|
## Config reference
|
|
434
416
|
|
|
@@ -436,75 +418,109 @@ Located at `~/.vir/config.json`.
|
|
|
436
418
|
|
|
437
419
|
| Field | Default | Description |
|
|
438
420
|
| ------------------- | --------------------------- | ---------------------------------------------------------- |
|
|
439
|
-
| `vaultPath` |
|
|
421
|
+
| `vaultPath` | (required) | Absolute path to Obsidian vault |
|
|
440
422
|
| `outputDir` | `vir` | Subdir inside vault |
|
|
441
423
|
| `claudeProjectsDir` | `~/.claude/projects` | Claude Code sessions |
|
|
442
424
|
| `cadenceHours` | `3` | Daemon run frequency (hours) |
|
|
443
425
|
| `provider` | `anthropic` | `anthropic` or `kie` |
|
|
444
|
-
| `anthropicApiKey` |
|
|
445
|
-
| `kieApiKey` |
|
|
426
|
+
| `anthropicApiKey` | (unset) | Required if `provider=anthropic` |
|
|
427
|
+
| `kieApiKey` | (unset) | Required if `provider=kie` |
|
|
446
428
|
| `filterThreshold` | `0.4` | Heuristic pre-filter (0..1) |
|
|
447
|
-
| `articlesDir` |
|
|
448
|
-
| `
|
|
429
|
+
| `articlesDir` | (unset) | Folder of clipped articles. Unset → article ingestion off |
|
|
430
|
+
| `pdfsDir` | (unset) | Folder of PDFs. Unset → PDF ingestion off |
|
|
431
|
+
| `workflowTranscripts` | `exclude` | Workflow/sidechain transcripts: `exclude` \| `include` |
|
|
432
|
+
| `agentTranscripts` | `exclude` | Headless SDK agent transcripts: `exclude` \| `include` |
|
|
433
|
+
| `projects` | (unset) | Per-project `include`/`exclude` map; absent = undecided |
|
|
449
434
|
| `filterToolCalls` | `moderate` | Tool-output filtering: `aggressive` \| `moderate` \| `off` |
|
|
450
|
-
| `retrievalDiversity`| `0.3` | MMR diversity (0..1)
|
|
435
|
+
| `retrievalDiversity`| `0.3` | MMR diversity (0..1) |
|
|
436
|
+
| `logQueries` | `true` | Log retrievals to `~/.vir/queries.jsonl`; `false` = off |
|
|
437
|
+
| `embeddingProvider` | (unset) | `ollama` \| `local` \| `none`; unset = auto-detect |
|
|
451
438
|
| `models.classify` | `claude-haiku-4-5-20251001` | Classify model |
|
|
452
|
-
| `models.distill` | `claude-sonnet-
|
|
453
|
-
| `models.distillFast`|
|
|
454
|
-
| `models.distillThreshold
|
|
455
|
-
| `pricing` |
|
|
439
|
+
| `models.distill` | `claude-sonnet-5` | Distill model for decision-heavy and large sessions |
|
|
440
|
+
| `models.distillFast`| (unset) | Cheap model for routine sessions; set → hybrid routing on |
|
|
441
|
+
| `models.distillThreshold` | `100000` | Input-token ceiling above which `distill` is forced |
|
|
442
|
+
| `pricing` | (built-in) | Optional per-provider `$/1M` overrides |
|
|
456
443
|
|
|
457
444
|
## Vault structure
|
|
458
445
|
|
|
459
446
|
```
|
|
460
447
|
vault/vir/
|
|
461
|
-
index.md # full catalog of every note
|
|
448
|
+
index.md # full catalog of every note vir has written
|
|
462
449
|
log.md # chronological append log of each run
|
|
463
450
|
patterns/ # reusable approaches worth repeating
|
|
464
451
|
gotchas/ # bugs, footguns, and edge cases
|
|
465
452
|
decisions/ # architecture decisions with their rationale
|
|
466
453
|
tools/ # per-tool knowledge and usage notes
|
|
467
|
-
articles/ # web articles distilled from your
|
|
454
|
+
articles/ # web articles distilled from your clips folder
|
|
455
|
+
pdfs/ # distilled PDFs and papers
|
|
456
|
+
topics/ # synthesized topic pages (vir compose)
|
|
468
457
|
projects/ # cross-session project summaries
|
|
458
|
+
summaries/ # weekly/monthly period summaries (derived, never indexed)
|
|
469
459
|
archived/ # deduplicated notes (kept, never deleted)
|
|
470
460
|
```
|
|
471
461
|
|
|
472
462
|
## State & logs
|
|
473
463
|
|
|
474
464
|
```
|
|
475
|
-
~/.vir/config.json
|
|
476
|
-
~/.vir/vir.db
|
|
477
|
-
~/.vir/
|
|
465
|
+
~/.vir/config.json # configuration
|
|
466
|
+
~/.vir/vir.db # SQLite (hashes, embeddings, content)
|
|
467
|
+
~/.vir/cost.log # per-call cost records (JSONL)
|
|
468
|
+
~/.vir/daemon.log # daemon run log
|
|
469
|
+
~/.vir/queries.jsonl # retrieval log (JSONL, rotates at 5 MB, one .1 kept)
|
|
478
470
|
```
|
|
479
471
|
|
|
472
|
+
### Query logging
|
|
473
|
+
|
|
474
|
+
Every `vir query` and MCP `vir_query` retrieval appends one record to
|
|
475
|
+
`~/.vir/queries.jsonl`: the query text, which notes surfaced at what rank and
|
|
476
|
+
score, the search method (embedding vs TF-IDF fallback), and latency. It never
|
|
477
|
+
records the synthesized answer.
|
|
478
|
+
|
|
479
|
+
This log stays on your machine — it is **never transmitted anywhere**. It
|
|
480
|
+
exists so `vir queries` can tell you which notes actually earn their place in
|
|
481
|
+
retrieval (and which never surface), and it is the baseline for future ranking
|
|
482
|
+
improvements. Delete it any time; disable it with `"logQueries": false` in
|
|
483
|
+
`~/.vir/config.json`.
|
|
484
|
+
|
|
480
485
|
## Project status
|
|
481
486
|
|
|
482
487
|
| | |
|
|
483
488
|
| -------------- | ----------------------------------------- |
|
|
484
|
-
|
|
|
489
|
+
| Version | 0.14.1 |
|
|
490
|
+
| Tests | 441 passing |
|
|
485
491
|
| Platforms | macOS (launchd), Linux (systemd/cron) |
|
|
486
492
|
| Node | 20+ |
|
|
487
|
-
| First-run cost | $1
|
|
493
|
+
| First-run cost | $1 to $5 (Kie.ai optional, ~72% cheaper) |
|
|
488
494
|
| Ongoing cost | ~$0.05 per run |
|
|
489
495
|
|
|
490
496
|
## Roadmap
|
|
491
497
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
- [x]
|
|
495
|
-
- [
|
|
498
|
+
Shipped:
|
|
499
|
+
|
|
500
|
+
- [x] Linux support (systemd timer + cron fallback), experimental
|
|
501
|
+
- [x] Active learning: `vir review`, verified notes ranked first in retrieval
|
|
502
|
+
- [x] Web article ingestion (Obsidian Web Clipper folder → same vault)
|
|
503
|
+
- [x] PDF and paper ingestion
|
|
504
|
+
- [x] Obsidian plugin: [vir-obsidian](https://github.com/djolex999/vir-obsidian), sidebar queries against the vault
|
|
505
|
+
- [x] Topic synthesis: `vir compose` builds topic pages from related notes
|
|
506
|
+
- [x] Transcript filtering: workflow, sidechain, and SDK-agent transcripts detected and skipped by default
|
|
507
|
+
- [x] Project triage: `vir projects`, per-project include/exclude with pending-cost estimates
|
|
508
|
+
- [x] Duplicate detection and merge: `vir dedupe`
|
|
509
|
+
|
|
510
|
+
Not built:
|
|
511
|
+
|
|
496
512
|
- [ ] Windows support
|
|
497
513
|
- [ ] GUI installer for non-developers
|
|
498
|
-
- [ ]
|
|
514
|
+
- [ ] More input sources: code repos, images
|
|
499
515
|
- [ ] Export to anchor-plugin skill format
|
|
500
|
-
- [ ]
|
|
516
|
+
- [ ] Other coding agents. Cursor and Codex CLI write transcripts too, and
|
|
517
|
+
the parser is the only Claude-specific stage. Possible, not scheduled.
|
|
501
518
|
|
|
502
519
|
## Contributing
|
|
503
520
|
|
|
504
521
|
PRs welcome. Open an issue first for large changes. Built with TypeScript
|
|
505
|
-
strict
|
|
506
|
-
[CONTRIBUTING.md](CONTRIBUTING.md) for development setup
|
|
507
|
-
the demo GIF.
|
|
522
|
+
strict; run `npm run build` and `npm test` before submitting. See
|
|
523
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for development setup.
|
|
508
524
|
|
|
509
525
|
```bash
|
|
510
526
|
git clone https://github.com/djolex999/vir
|
|
@@ -522,11 +538,12 @@ MIT
|
|
|
522
538
|
|
|
523
539
|
Built by Djordje Marković / GrowthQ Lab DOO.
|
|
524
540
|
|
|
525
|
-
Vir (вир) is the Serbian word for _whirlpool_
|
|
526
|
-
everything in and concentrates it. Sessions flow in,
|
|
527
|
-
and deposits it somewhere permanent.
|
|
541
|
+
Vir (вир) is the Serbian word for _whirlpool_: the place where a river pulls
|
|
542
|
+
everything in and concentrates it. Sessions flow in, vir pulls out what
|
|
543
|
+
matters, and deposits it somewhere permanent.
|
|
528
544
|
|
|
529
|
-
Inspired by Andrej Karpathy's LLM Wiki pattern and Uros Pesic's KB Brain
|
|
545
|
+
Inspired by Andrej Karpathy's LLM Wiki pattern and Uros Pesic's KB Brain
|
|
546
|
+
concept.
|
|
530
547
|
|
|
531
548
|
[GitHub](https://github.com/djolex999) ·
|
|
532
549
|
[LinkedIn](https://www.linkedin.com/in/djmarkovic/) ·
|