@djolex999/vir-cli 0.1.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.
Files changed (69) hide show
  1. package/CLAUDE.md +149 -0
  2. package/LICENSE +21 -0
  3. package/README.md +155 -0
  4. package/dist/claude/updater.js +230 -0
  5. package/dist/claude/updater.js.map +1 -0
  6. package/dist/cli.js +779 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config.js +82 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/daemon/launchd.js +93 -0
  11. package/dist/daemon/launchd.js.map +1 -0
  12. package/dist/dedupe/detector.js +159 -0
  13. package/dist/dedupe/detector.js.map +1 -0
  14. package/dist/dedupe/merger.js +116 -0
  15. package/dist/dedupe/merger.js.map +1 -0
  16. package/dist/lint/linter.js +224 -0
  17. package/dist/lint/linter.js.map +1 -0
  18. package/dist/pipeline/distiller.js +208 -0
  19. package/dist/pipeline/distiller.js.map +1 -0
  20. package/dist/pipeline/filter.js +28 -0
  21. package/dist/pipeline/filter.js.map +1 -0
  22. package/dist/pipeline/parser.js +109 -0
  23. package/dist/pipeline/parser.js.map +1 -0
  24. package/dist/pipeline/run.js +312 -0
  25. package/dist/pipeline/run.js.map +1 -0
  26. package/dist/pipeline/scanner.js +47 -0
  27. package/dist/pipeline/scanner.js.map +1 -0
  28. package/dist/pipeline/scrubber.js +51 -0
  29. package/dist/pipeline/scrubber.js.map +1 -0
  30. package/dist/pipeline/summarizer.js +162 -0
  31. package/dist/pipeline/summarizer.js.map +1 -0
  32. package/dist/pipeline/types.js +2 -0
  33. package/dist/pipeline/types.js.map +1 -0
  34. package/dist/pipeline/writer.js +195 -0
  35. package/dist/pipeline/writer.js.map +1 -0
  36. package/dist/search/embedder.js +93 -0
  37. package/dist/search/embedder.js.map +1 -0
  38. package/dist/search/retriever.js +212 -0
  39. package/dist/search/retriever.js.map +1 -0
  40. package/dist/search/synthesizer.js +26 -0
  41. package/dist/search/synthesizer.js.map +1 -0
  42. package/dist/state/db.js +309 -0
  43. package/dist/state/db.js.map +1 -0
  44. package/dist/ui/display.js +148 -0
  45. package/dist/ui/display.js.map +1 -0
  46. package/package.json +50 -0
  47. package/src/claude/updater.ts +273 -0
  48. package/src/cli.ts +953 -0
  49. package/src/config.ts +89 -0
  50. package/src/daemon/launchd.ts +115 -0
  51. package/src/dedupe/detector.ts +197 -0
  52. package/src/dedupe/merger.ts +172 -0
  53. package/src/lint/linter.ts +286 -0
  54. package/src/pipeline/distiller.ts +280 -0
  55. package/src/pipeline/filter.ts +43 -0
  56. package/src/pipeline/parser.ts +118 -0
  57. package/src/pipeline/run.ts +378 -0
  58. package/src/pipeline/scanner.ts +51 -0
  59. package/src/pipeline/scrubber.ts +55 -0
  60. package/src/pipeline/summarizer.ts +204 -0
  61. package/src/pipeline/types.ts +41 -0
  62. package/src/pipeline/writer.ts +242 -0
  63. package/src/search/embedder.ts +88 -0
  64. package/src/search/retriever.ts +255 -0
  65. package/src/search/synthesizer.ts +45 -0
  66. package/src/state/db.ts +451 -0
  67. package/src/ui/display.ts +184 -0
  68. package/tsconfig.json +23 -0
  69. package/vir-flow.html +708 -0
package/vir-flow.html ADDED
@@ -0,0 +1,708 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Vir โ€” Flow & Usage</title>
7
+ <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Syne:wght@400;600;700;800&display=swap');
9
+
10
+ :root {
11
+ --bg: #0a0a0f;
12
+ --surface: #111118;
13
+ --surface2: #16161f;
14
+ --border: #1e1e2e;
15
+ --accent: #7c6af7;
16
+ --accent2: #4fd1a0;
17
+ --accent3: #f7a26a;
18
+ --danger: #f76a7c;
19
+ --text: #e8e8f0;
20
+ --muted: #6b6b8a;
21
+ --dim: #3a3a5c;
22
+ }
23
+
24
+ * { margin: 0; padding: 0; box-sizing: border-box; }
25
+
26
+ body {
27
+ background: var(--bg);
28
+ color: var(--text);
29
+ font-family: 'Syne', sans-serif;
30
+ min-height: 100vh;
31
+ overflow-x: hidden;
32
+ }
33
+
34
+ /* Background grain */
35
+ body::before {
36
+ content: '';
37
+ position: fixed;
38
+ inset: 0;
39
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E");
40
+ pointer-events: none;
41
+ z-index: 0;
42
+ }
43
+
44
+ .container {
45
+ max-width: 1100px;
46
+ margin: 0 auto;
47
+ padding: 60px 40px;
48
+ position: relative;
49
+ z-index: 1;
50
+ }
51
+
52
+ /* Header */
53
+ .header {
54
+ display: flex;
55
+ align-items: flex-end;
56
+ gap: 24px;
57
+ margin-bottom: 72px;
58
+ }
59
+
60
+ .logo {
61
+ font-size: 96px;
62
+ font-weight: 800;
63
+ line-height: 1;
64
+ background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
65
+ -webkit-background-clip: text;
66
+ -webkit-text-fill-color: transparent;
67
+ background-clip: text;
68
+ letter-spacing: -4px;
69
+ }
70
+
71
+ .header-sub {
72
+ padding-bottom: 12px;
73
+ }
74
+
75
+ .tagline {
76
+ font-size: 13px;
77
+ font-family: 'JetBrains Mono', monospace;
78
+ color: var(--muted);
79
+ text-transform: uppercase;
80
+ letter-spacing: 3px;
81
+ margin-bottom: 6px;
82
+ }
83
+
84
+ .desc {
85
+ font-size: 18px;
86
+ font-weight: 600;
87
+ color: var(--text);
88
+ max-width: 380px;
89
+ line-height: 1.4;
90
+ }
91
+
92
+ /* Section titles */
93
+ .section-title {
94
+ font-size: 11px;
95
+ font-family: 'JetBrains Mono', monospace;
96
+ text-transform: uppercase;
97
+ letter-spacing: 4px;
98
+ color: var(--accent);
99
+ margin-bottom: 24px;
100
+ display: flex;
101
+ align-items: center;
102
+ gap: 12px;
103
+ }
104
+
105
+ .section-title::after {
106
+ content: '';
107
+ flex: 1;
108
+ height: 1px;
109
+ background: var(--border);
110
+ }
111
+
112
+ /* Pipeline flow */
113
+ .pipeline {
114
+ margin-bottom: 72px;
115
+ }
116
+
117
+ .pipeline-steps {
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: 0;
121
+ }
122
+
123
+ .step {
124
+ display: grid;
125
+ grid-template-columns: 48px 1fr;
126
+ gap: 0 24px;
127
+ position: relative;
128
+ }
129
+
130
+ .step-line {
131
+ display: flex;
132
+ flex-direction: column;
133
+ align-items: center;
134
+ }
135
+
136
+ .step-dot {
137
+ width: 48px;
138
+ height: 48px;
139
+ border-radius: 50%;
140
+ display: flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ font-family: 'JetBrains Mono', monospace;
144
+ font-size: 13px;
145
+ font-weight: 700;
146
+ flex-shrink: 0;
147
+ position: relative;
148
+ z-index: 1;
149
+ border: 2px solid;
150
+ }
151
+
152
+ .step-dot.free { background: #0d1f18; border-color: var(--accent2); color: var(--accent2); }
153
+ .step-dot.haiku { background: #13101f; border-color: var(--accent); color: var(--accent); }
154
+ .step-dot.sonnet { background: #1a1008; border-color: var(--accent3); color: var(--accent3); }
155
+ .step-dot.write { background: #0d1f18; border-color: var(--accent2); color: var(--accent2); }
156
+
157
+ .step-connector {
158
+ width: 2px;
159
+ flex: 1;
160
+ min-height: 24px;
161
+ background: linear-gradient(to bottom, var(--dim), transparent);
162
+ margin: 4px 0;
163
+ }
164
+
165
+ .step-body {
166
+ padding: 12px 0 32px;
167
+ }
168
+
169
+ .step-name {
170
+ font-size: 20px;
171
+ font-weight: 700;
172
+ margin-bottom: 6px;
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 12px;
176
+ }
177
+
178
+ .badge {
179
+ font-size: 10px;
180
+ font-family: 'JetBrains Mono', monospace;
181
+ padding: 3px 8px;
182
+ border-radius: 4px;
183
+ font-weight: 500;
184
+ text-transform: uppercase;
185
+ letter-spacing: 1px;
186
+ }
187
+
188
+ .badge-free { background: #0d2a1c; color: var(--accent2); border: 1px solid #1a4a30; }
189
+ .badge-haiku { background: #1a1030; color: var(--accent); border: 1px solid #2a1a50; }
190
+ .badge-sonnet { background: #2a1a08; color: var(--accent3); border: 1px solid #4a2a0a; }
191
+
192
+ .step-detail {
193
+ font-size: 14px;
194
+ color: var(--muted);
195
+ line-height: 1.7;
196
+ max-width: 600px;
197
+ }
198
+
199
+ .step-detail code {
200
+ font-family: 'JetBrains Mono', monospace;
201
+ font-size: 12px;
202
+ background: var(--surface2);
203
+ padding: 2px 6px;
204
+ border-radius: 3px;
205
+ color: var(--accent2);
206
+ }
207
+
208
+ /* Commands grid */
209
+ .commands {
210
+ margin-bottom: 72px;
211
+ }
212
+
213
+ .commands-grid {
214
+ display: grid;
215
+ grid-template-columns: repeat(2, 1fr);
216
+ gap: 12px;
217
+ }
218
+
219
+ .cmd-card {
220
+ background: var(--surface);
221
+ border: 1px solid var(--border);
222
+ border-radius: 12px;
223
+ padding: 20px 24px;
224
+ transition: border-color 0.2s, transform 0.2s;
225
+ cursor: default;
226
+ }
227
+
228
+ .cmd-card:hover {
229
+ border-color: var(--accent);
230
+ transform: translateY(-2px);
231
+ }
232
+
233
+ .cmd-card.wide {
234
+ grid-column: span 2;
235
+ }
236
+
237
+ .cmd-name {
238
+ font-family: 'JetBrains Mono', monospace;
239
+ font-size: 13px;
240
+ color: var(--accent2);
241
+ margin-bottom: 8px;
242
+ font-weight: 500;
243
+ }
244
+
245
+ .cmd-name span {
246
+ color: var(--muted);
247
+ }
248
+
249
+ .cmd-desc {
250
+ font-size: 13px;
251
+ color: var(--muted);
252
+ line-height: 1.5;
253
+ }
254
+
255
+ .cmd-cost {
256
+ display: inline-block;
257
+ margin-top: 10px;
258
+ font-size: 10px;
259
+ font-family: 'JetBrains Mono', monospace;
260
+ padding: 2px 8px;
261
+ border-radius: 4px;
262
+ text-transform: uppercase;
263
+ letter-spacing: 1px;
264
+ }
265
+
266
+ .cost-free { background: #0d2a1c; color: var(--accent2); }
267
+ .cost-cheap { background: #13101f; color: var(--accent); }
268
+ .cost-medium { background: #2a1a08; color: var(--accent3); }
269
+
270
+ /* Loop diagram */
271
+ .loop {
272
+ margin-bottom: 72px;
273
+ }
274
+
275
+ .loop-diagram {
276
+ background: var(--surface);
277
+ border: 1px solid var(--border);
278
+ border-radius: 16px;
279
+ padding: 40px;
280
+ display: flex;
281
+ align-items: center;
282
+ justify-content: space-between;
283
+ gap: 16px;
284
+ position: relative;
285
+ overflow: hidden;
286
+ }
287
+
288
+ .loop-diagram::before {
289
+ content: '';
290
+ position: absolute;
291
+ top: -60px;
292
+ left: 50%;
293
+ transform: translateX(-50%);
294
+ width: 300px;
295
+ height: 300px;
296
+ background: radial-gradient(circle, rgba(124,106,247,0.06) 0%, transparent 70%);
297
+ pointer-events: none;
298
+ }
299
+
300
+ .loop-node {
301
+ flex: 1;
302
+ text-align: center;
303
+ position: relative;
304
+ z-index: 1;
305
+ }
306
+
307
+ .loop-icon {
308
+ width: 56px;
309
+ height: 56px;
310
+ border-radius: 14px;
311
+ display: flex;
312
+ align-items: center;
313
+ justify-content: center;
314
+ font-size: 24px;
315
+ margin: 0 auto 12px;
316
+ }
317
+
318
+ .loop-icon.purple { background: #13101f; border: 1px solid #2a1a50; }
319
+ .loop-icon.green { background: #0d1f18; border: 1px solid #1a4a30; }
320
+ .loop-icon.orange { background: #2a1a08; border: 1px solid #4a2a0a; }
321
+ .loop-icon.blue { background: #0a1525; border: 1px solid #1a3050; }
322
+
323
+ .loop-label {
324
+ font-size: 13px;
325
+ font-weight: 700;
326
+ margin-bottom: 4px;
327
+ }
328
+
329
+ .loop-sub {
330
+ font-size: 11px;
331
+ color: var(--muted);
332
+ font-family: 'JetBrains Mono', monospace;
333
+ }
334
+
335
+ .loop-arrow {
336
+ color: var(--dim);
337
+ font-size: 20px;
338
+ flex-shrink: 0;
339
+ display: flex;
340
+ flex-direction: column;
341
+ align-items: center;
342
+ gap: 4px;
343
+ }
344
+
345
+ .loop-arrow span {
346
+ font-size: 9px;
347
+ font-family: 'JetBrains Mono', monospace;
348
+ color: var(--muted);
349
+ white-space: nowrap;
350
+ }
351
+
352
+ /* Cost table */
353
+ .costs {
354
+ margin-bottom: 72px;
355
+ }
356
+
357
+ .cost-table {
358
+ width: 100%;
359
+ border-collapse: collapse;
360
+ font-size: 13px;
361
+ }
362
+
363
+ .cost-table th {
364
+ font-family: 'JetBrains Mono', monospace;
365
+ font-size: 10px;
366
+ text-transform: uppercase;
367
+ letter-spacing: 2px;
368
+ color: var(--muted);
369
+ padding: 12px 16px;
370
+ text-align: left;
371
+ border-bottom: 1px solid var(--border);
372
+ }
373
+
374
+ .cost-table td {
375
+ padding: 14px 16px;
376
+ border-bottom: 1px solid var(--border);
377
+ color: var(--text);
378
+ }
379
+
380
+ .cost-table tr:last-child td { border-bottom: none; }
381
+ .cost-table tr:hover td { background: var(--surface2); }
382
+
383
+ .cost-table td:first-child {
384
+ font-family: 'JetBrains Mono', monospace;
385
+ color: var(--accent2);
386
+ font-size: 12px;
387
+ }
388
+
389
+ .cost-table td:last-child {
390
+ color: var(--accent3);
391
+ font-family: 'JetBrains Mono', monospace;
392
+ }
393
+
394
+ /* Footer */
395
+ .footer {
396
+ padding-top: 40px;
397
+ border-top: 1px solid var(--border);
398
+ display: flex;
399
+ justify-content: space-between;
400
+ align-items: center;
401
+ }
402
+
403
+ .footer-left {
404
+ font-family: 'JetBrains Mono', monospace;
405
+ font-size: 11px;
406
+ color: var(--muted);
407
+ }
408
+
409
+ .footer-right {
410
+ font-size: 20px;
411
+ font-weight: 800;
412
+ background: linear-gradient(135deg, var(--accent), var(--accent2));
413
+ -webkit-background-clip: text;
414
+ -webkit-text-fill-color: transparent;
415
+ background-clip: text;
416
+ }
417
+
418
+ /* Animations */
419
+ @keyframes fadeUp {
420
+ from { opacity: 0; transform: translateY(20px); }
421
+ to { opacity: 1; transform: translateY(0); }
422
+ }
423
+
424
+ .pipeline, .commands, .loop, .costs {
425
+ animation: fadeUp 0.6s ease both;
426
+ }
427
+
428
+ .commands { animation-delay: 0.1s; }
429
+ .loop { animation-delay: 0.2s; }
430
+ .costs { animation-delay: 0.3s; }
431
+ </style>
432
+ </head>
433
+ <body>
434
+ <div class="container">
435
+
436
+ <!-- Header -->
437
+ <div class="header">
438
+ <div class="logo">vir</div>
439
+ <div class="header-sub">
440
+ <div class="tagline">Claude Code Memory System</div>
441
+ <div class="desc">Distills sessions into compounding knowledge. Every run makes future sessions sharper.</div>
442
+ </div>
443
+ </div>
444
+
445
+ <!-- Pipeline -->
446
+ <div class="pipeline">
447
+ <div class="section-title">Pipeline โ€” every vir run</div>
448
+ <div class="pipeline-steps">
449
+
450
+ <div class="step">
451
+ <div class="step-line">
452
+ <div class="step-dot free">01</div>
453
+ <div class="step-connector"></div>
454
+ </div>
455
+ <div class="step-body">
456
+ <div class="step-name">Scanner <span class="badge badge-free">free</span></div>
457
+ <div class="step-detail">Walks <code>~/.claude/projects/**/*.jsonl</code>. Computes SHA-256 of each file. Skips anything already in SQLite with the same hash โ€” fully idempotent.</div>
458
+ </div>
459
+ </div>
460
+
461
+ <div class="step">
462
+ <div class="step-line">
463
+ <div class="step-dot free">02</div>
464
+ <div class="step-connector"></div>
465
+ </div>
466
+ <div class="step-body">
467
+ <div class="step-name">Filter <span class="badge badge-free">free</span></div>
468
+ <div class="step-detail">Heuristic scorer โ€” no LLM tokens spent. Score based on session length, tool call count, unique files touched, signal words (error, fixed, learned). Sessions below threshold 0.4 are skipped.</div>
469
+ </div>
470
+ </div>
471
+
472
+ <div class="step">
473
+ <div class="step-line">
474
+ <div class="step-dot free">03</div>
475
+ <div class="step-connector"></div>
476
+ </div>
477
+ <div class="step-body">
478
+ <div class="step-name">Scrubber <span class="badge badge-free">free</span></div>
479
+ <div class="step-detail">Strips API keys, Bearer tokens, AWS credentials, emails, absolute paths with usernames before anything touches the LLM.</div>
480
+ </div>
481
+ </div>
482
+
483
+ <div class="step">
484
+ <div class="step-line">
485
+ <div class="step-dot haiku">04</div>
486
+ <div class="step-connector"></div>
487
+ </div>
488
+ <div class="step-body">
489
+ <div class="step-name">Classify <span class="badge badge-haiku">Haiku</span></div>
490
+ <div class="step-detail">Haiku classifies the session: <code>category</code> (pattern / gotcha / decision / tool), <code>topic</code> (2โ€“4 words), <code>project</code>, <code>confidence</code> (0โ€“1). Sessions with confidence &lt; 0.6 are skipped โ€” no Sonnet call.</div>
491
+ </div>
492
+ </div>
493
+
494
+ <div class="step">
495
+ <div class="step-line">
496
+ <div class="step-dot sonnet">05</div>
497
+ <div class="step-connector"></div>
498
+ </div>
499
+ <div class="step-body">
500
+ <div class="step-name">Distill <span class="badge badge-sonnet">Sonnet</span></div>
501
+ <div class="step-detail">Sonnet extracts durable knowledge: Summary, What Was Learned, Context, Related. Stored in SQLite content column. Rate-limited with 60/120/240s backoff on 429.</div>
502
+ </div>
503
+ </div>
504
+
505
+ <div class="step">
506
+ <div class="step-line">
507
+ <div class="step-dot write">06</div>
508
+ </div>
509
+ <div class="step-body">
510
+ <div class="step-name">Write <span class="badge badge-free">free</span></div>
511
+ <div class="step-detail">Writes typed markdown note to Obsidian vault: <code>patterns/</code>, <code>gotchas/</code>, <code>decisions/</code>, <code>tools/</code>. Updates <code>index.md</code> catalog and <code>log.md</code>. Wikilinks injected for Obsidian graph view clustering.</div>
512
+ </div>
513
+ </div>
514
+
515
+ </div>
516
+ </div>
517
+
518
+ <!-- Commands -->
519
+ <div class="commands">
520
+ <div class="section-title">Commands</div>
521
+ <div class="commands-grid">
522
+
523
+ <div class="cmd-card">
524
+ <div class="cmd-name">vir run</div>
525
+ <div class="cmd-desc">Run pipeline once. Processes only new/changed sessions. Used by the launchd daemon every 4 hours.</div>
526
+ <div class="cmd-cost cost-cheap">Haiku + Sonnet</div>
527
+ </div>
528
+
529
+ <div class="cmd-card">
530
+ <div class="cmd-name">vir run <span>--full</span></div>
531
+ <div class="cmd-desc">Force reprocess all sessions. Required after schema migrations or first setup. Expensive one-time cost.</div>
532
+ <div class="cmd-cost cost-medium">$$</div>
533
+ </div>
534
+
535
+ <div class="cmd-card">
536
+ <div class="cmd-name">vir run <span>--rewrite-only</span></div>
537
+ <div class="cmd-desc">Rewrite all vault notes from SQLite โ€” no LLM calls. Use after changing writer format (e.g. adding wikilinks).</div>
538
+ <div class="cmd-cost cost-free">free</div>
539
+ </div>
540
+
541
+ <div class="cmd-card">
542
+ <div class="cmd-name">vir query <span>"question"</span></div>
543
+ <div class="cmd-desc">TF-IDF retrieves top 8 notes, Sonnet synthesizes a direct answer. Citations included.</div>
544
+ <div class="cmd-cost cost-cheap">~$0.01</div>
545
+ </div>
546
+
547
+ <div class="cmd-card">
548
+ <div class="cmd-name">vir summarize <span>&lt;project&gt;</span></div>
549
+ <div class="cmd-desc">Generate cross-session synthesis for a project: key patterns, gotchas, decisions, knowledge gaps.</div>
550
+ <div class="cmd-cost cost-cheap">~$0.02</div>
551
+ </div>
552
+
553
+ <div class="cmd-card">
554
+ <div class="cmd-name">vir lint</div>
555
+ <div class="cmd-desc">Three checks: orphan notes, stale notes (&gt;90d with newer activity), contradiction detection between similar notes.</div>
556
+ <div class="cmd-cost cost-free">free + Haiku</div>
557
+ </div>
558
+
559
+ <div class="cmd-card">
560
+ <div class="cmd-name">vir dedupe</div>
561
+ <div class="cmd-desc">Interactive duplicate detection. Haiku finds candidates, you confirm each merge. Duplicates archived, not deleted.</div>
562
+ <div class="cmd-cost cost-cheap">Haiku</div>
563
+ </div>
564
+
565
+ <div class="cmd-card">
566
+ <div class="cmd-name">vir sync-claude <span>--dry-run</span></div>
567
+ <div class="cmd-desc">Preview what would be injected into ~/.claude/CLAUDE.md and per-project CLAUDE.md files. Shows diff: added, upgraded, removed.</div>
568
+ <div class="cmd-cost cost-free">free</div>
569
+ </div>
570
+
571
+ <div class="cmd-card">
572
+ <div class="cmd-name">vir status</div>
573
+ <div class="cmd-desc">Knowledge heatmap: notes by project and category, confidence distribution, gaps, daemon status.</div>
574
+ <div class="cmd-cost cost-free">free</div>
575
+ </div>
576
+
577
+ <div class="cmd-card">
578
+ <div class="cmd-name">vir schedule <span>install</span></div>
579
+ <div class="cmd-desc">Register launchd plist at ~/Library/LaunchAgents/. Runs vir run every 4 hours automatically.</div>
580
+ <div class="cmd-cost cost-free">free</div>
581
+ </div>
582
+
583
+ </div>
584
+ </div>
585
+
586
+ <!-- The Loop -->
587
+ <div class="loop">
588
+ <div class="section-title">The compounding loop</div>
589
+ <div class="loop-diagram">
590
+
591
+ <div class="loop-node">
592
+ <div class="loop-icon purple">โšก</div>
593
+ <div class="loop-label">Claude Code</div>
594
+ <div class="loop-sub">session runs</div>
595
+ </div>
596
+
597
+ <div class="loop-arrow">
598
+ โ†’<br><span>JSONL transcripts</span>
599
+ </div>
600
+
601
+ <div class="loop-node">
602
+ <div class="loop-icon green">๐ŸŒ€</div>
603
+ <div class="loop-label">Vir</div>
604
+ <div class="loop-sub">distills knowledge</div>
605
+ </div>
606
+
607
+ <div class="loop-arrow">
608
+ โ†’<br><span>markdown notes</span>
609
+ </div>
610
+
611
+ <div class="loop-node">
612
+ <div class="loop-icon orange">๐Ÿ““</div>
613
+ <div class="loop-label">Obsidian vault</div>
614
+ <div class="loop-sub">knowledge base</div>
615
+ </div>
616
+
617
+ <div class="loop-arrow">
618
+ โ†’<br><span>vir sync-claude</span>
619
+ </div>
620
+
621
+ <div class="loop-node">
622
+ <div class="loop-icon blue">๐Ÿง </div>
623
+ <div class="loop-label">CLAUDE.md</div>
624
+ <div class="loop-sub">feeds future sessions</div>
625
+ </div>
626
+
627
+ </div>
628
+ </div>
629
+
630
+ <!-- Cost reference -->
631
+ <div class="costs">
632
+ <div class="section-title">Cost reference (Kie.ai)</div>
633
+ <table class="cost-table">
634
+ <thead>
635
+ <tr>
636
+ <th>Operation</th>
637
+ <th>Model</th>
638
+ <th>When</th>
639
+ <th>Cost</th>
640
+ </tr>
641
+ </thead>
642
+ <tbody>
643
+ <tr>
644
+ <td>Scanner / Filter / Scrubber</td>
645
+ <td>โ€”</td>
646
+ <td>every session</td>
647
+ <td>free</td>
648
+ </tr>
649
+ <tr>
650
+ <td>Classify</td>
651
+ <td>Haiku 4.5</td>
652
+ <td>sessions passing filter</td>
653
+ <td>~$0.001/session</td>
654
+ </tr>
655
+ <tr>
656
+ <td>Distill</td>
657
+ <td>Sonnet 4.6</td>
658
+ <td>confidence โ‰ฅ 0.6</td>
659
+ <td>~$0.02/session</td>
660
+ </tr>
661
+ <tr>
662
+ <td>First full run (226 sessions)</td>
663
+ <td>Haiku + Sonnet</td>
664
+ <td>one-time</td>
665
+ <td>~$1.50</td>
666
+ </tr>
667
+ <tr>
668
+ <td>Ongoing (4h daemon, ~8 sessions)</td>
669
+ <td>Haiku + Sonnet</td>
670
+ <td>per run</td>
671
+ <td>~$0.05/run</td>
672
+ </tr>
673
+ <tr>
674
+ <td>vir query</td>
675
+ <td>Sonnet 4.6</td>
676
+ <td>per query</td>
677
+ <td>~$0.01</td>
678
+ </tr>
679
+ <tr>
680
+ <td>vir summarize</td>
681
+ <td>Sonnet 4.6</td>
682
+ <td>per project</td>
683
+ <td>~$0.02</td>
684
+ </tr>
685
+ <tr>
686
+ <td>vir dedupe / lint --contradictions</td>
687
+ <td>Haiku 4.5</td>
688
+ <td>per pair checked</td>
689
+ <td>~$0.001/pair</td>
690
+ </tr>
691
+ </tbody>
692
+ </table>
693
+ </div>
694
+
695
+ <!-- Footer -->
696
+ <div class="footer">
697
+ <div class="footer-left">
698
+ config: ~/.vir/config.json &nbsp;ยท&nbsp;
699
+ state: ~/.vir/vir.db &nbsp;ยท&nbsp;
700
+ logs: ~/.vir/daemon.log &nbsp;ยท&nbsp;
701
+ vault: ~/Documents/Vir/vir/
702
+ </div>
703
+ <div class="footer-right">vir</div>
704
+ </div>
705
+
706
+ </div>
707
+ </body>
708
+ </html>