threadnote 0.4.1 → 0.5.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 +35 -0
- package/dist/threadnote.cjs +395 -158
- package/docs/.nojekyll +0 -0
- package/docs/index.html +1532 -0
- package/package.json +1 -1
package/docs/index.html
ADDED
|
@@ -0,0 +1,1532 @@
|
|
|
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, viewport-fit=cover" />
|
|
6
|
+
<meta name="color-scheme" content="dark" />
|
|
7
|
+
<title>Threadnote — shared local context for development agents</title>
|
|
8
|
+
<meta
|
|
9
|
+
name="description"
|
|
10
|
+
content="Threadnote is a safe local workflow for using OpenViking as shared, agent-neutral context for development work — across Codex, Claude, Cursor, and Copilot."
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
14
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
15
|
+
<link
|
|
16
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
|
17
|
+
rel="stylesheet"
|
|
18
|
+
/>
|
|
19
|
+
|
|
20
|
+
<style>
|
|
21
|
+
:root {
|
|
22
|
+
--bg: #0a0a0d;
|
|
23
|
+
--bg-elev: #14141a;
|
|
24
|
+
--bg-elev-2: #1c1c24;
|
|
25
|
+
--line: #2a2a35;
|
|
26
|
+
--text: #ececf1;
|
|
27
|
+
--muted: #8a8a96;
|
|
28
|
+
--dim: #5c5c68;
|
|
29
|
+
--accent: #5ee0c5;
|
|
30
|
+
--accent-soft: rgba(94, 224, 197, 0.12);
|
|
31
|
+
--accent-line: rgba(94, 224, 197, 0.35);
|
|
32
|
+
--warn: #ffb86b;
|
|
33
|
+
--danger: #ff7a7a;
|
|
34
|
+
--code-bg: #101019;
|
|
35
|
+
--radius-lg: 16px;
|
|
36
|
+
--radius-md: 10px;
|
|
37
|
+
--radius-sm: 6px;
|
|
38
|
+
--maxw: 1080px;
|
|
39
|
+
--section-pad: clamp(2rem, 6vh, 5rem) clamp(1.25rem, 6vw, 5rem);
|
|
40
|
+
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', system-ui, sans-serif;
|
|
41
|
+
--font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
* {
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
html,
|
|
49
|
+
body {
|
|
50
|
+
margin: 0;
|
|
51
|
+
padding: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
html {
|
|
55
|
+
background: var(--bg);
|
|
56
|
+
color: var(--text);
|
|
57
|
+
font-family: var(--font-sans);
|
|
58
|
+
font-feature-settings: 'cv02', 'cv11', 'ss01';
|
|
59
|
+
-webkit-font-smoothing: antialiased;
|
|
60
|
+
-moz-osx-font-smoothing: grayscale;
|
|
61
|
+
scroll-snap-type: y mandatory;
|
|
62
|
+
scroll-behavior: smooth;
|
|
63
|
+
scroll-padding-top: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
body {
|
|
67
|
+
line-height: 1.55;
|
|
68
|
+
font-size: clamp(15px, 1.05vw, 17px);
|
|
69
|
+
overflow-x: hidden;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
::selection {
|
|
73
|
+
background: var(--accent-soft);
|
|
74
|
+
color: var(--text);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
a {
|
|
78
|
+
color: var(--accent);
|
|
79
|
+
text-decoration: none;
|
|
80
|
+
border-bottom: 1px solid transparent;
|
|
81
|
+
transition: border-color 0.15s ease;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
a:hover {
|
|
85
|
+
border-bottom-color: var(--accent-line);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
code {
|
|
89
|
+
font-family: var(--font-mono);
|
|
90
|
+
font-size: 0.92em;
|
|
91
|
+
background: var(--code-bg);
|
|
92
|
+
padding: 0.1em 0.4em;
|
|
93
|
+
border-radius: 4px;
|
|
94
|
+
color: #d6d6e0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pre {
|
|
98
|
+
font-family: var(--font-mono);
|
|
99
|
+
font-size: 0.86em;
|
|
100
|
+
background: var(--code-bg);
|
|
101
|
+
color: #d6d6e0;
|
|
102
|
+
border: 1px solid var(--line);
|
|
103
|
+
border-left: 3px solid var(--accent);
|
|
104
|
+
border-radius: var(--radius-md);
|
|
105
|
+
padding: 1em 1.2em;
|
|
106
|
+
overflow-x: auto;
|
|
107
|
+
line-height: 1.55;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
pre code {
|
|
111
|
+
background: transparent;
|
|
112
|
+
padding: 0;
|
|
113
|
+
font-size: 1em;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.deck {
|
|
117
|
+
position: relative;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.slide {
|
|
121
|
+
min-height: 100vh;
|
|
122
|
+
scroll-snap-align: start;
|
|
123
|
+
padding: var(--section-pad);
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
justify-content: center;
|
|
127
|
+
align-items: stretch;
|
|
128
|
+
position: relative;
|
|
129
|
+
border-bottom: 1px solid var(--line);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.slide-inner {
|
|
133
|
+
width: 100%;
|
|
134
|
+
max-width: var(--maxw);
|
|
135
|
+
margin: 0 auto;
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
justify-content: center;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.slide-eyebrow {
|
|
142
|
+
display: inline-flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
gap: 0.6em;
|
|
145
|
+
font-family: var(--font-mono);
|
|
146
|
+
font-size: 0.82rem;
|
|
147
|
+
letter-spacing: 0.08em;
|
|
148
|
+
text-transform: uppercase;
|
|
149
|
+
color: var(--accent);
|
|
150
|
+
margin-bottom: 1rem;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.slide-eyebrow::before {
|
|
154
|
+
content: '';
|
|
155
|
+
width: 1.5em;
|
|
156
|
+
height: 1px;
|
|
157
|
+
background: var(--accent);
|
|
158
|
+
display: inline-block;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
h1,
|
|
162
|
+
h2,
|
|
163
|
+
h3 {
|
|
164
|
+
margin: 0;
|
|
165
|
+
line-height: 1.15;
|
|
166
|
+
letter-spacing: -0.018em;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
h1 {
|
|
170
|
+
font-size: clamp(2.5rem, 6.5vw, 4.5rem);
|
|
171
|
+
font-weight: 800;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
h2 {
|
|
175
|
+
font-size: clamp(1.85rem, 4vw, 2.75rem);
|
|
176
|
+
font-weight: 700;
|
|
177
|
+
margin-bottom: 1.25rem;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
h3 {
|
|
181
|
+
font-size: 1.15rem;
|
|
182
|
+
font-weight: 600;
|
|
183
|
+
color: var(--text);
|
|
184
|
+
margin-bottom: 0.35rem;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.lead {
|
|
188
|
+
font-size: clamp(1.1rem, 1.6vw, 1.35rem);
|
|
189
|
+
color: var(--muted);
|
|
190
|
+
max-width: 56ch;
|
|
191
|
+
margin-top: 1.25rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.muted {
|
|
195
|
+
color: var(--muted);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.dim {
|
|
199
|
+
color: var(--dim);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* hero */
|
|
203
|
+
#hero {
|
|
204
|
+
background: radial-gradient(circle at 25% 30%, rgba(94, 224, 197, 0.08), transparent 55%),
|
|
205
|
+
radial-gradient(circle at 75% 70%, rgba(124, 140, 255, 0.05), transparent 55%), var(--bg);
|
|
206
|
+
place-items: center;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
#hero .slide-inner {
|
|
210
|
+
align-items: flex-start;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.brand {
|
|
214
|
+
display: inline-flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
gap: 0.6rem;
|
|
217
|
+
margin-bottom: 1.5rem;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.brand-mark {
|
|
221
|
+
width: 32px;
|
|
222
|
+
height: 32px;
|
|
223
|
+
border-radius: 8px;
|
|
224
|
+
background: linear-gradient(135deg, var(--accent), #7c8cff);
|
|
225
|
+
display: grid;
|
|
226
|
+
place-items: center;
|
|
227
|
+
color: #0a0a0d;
|
|
228
|
+
font-family: var(--font-mono);
|
|
229
|
+
font-weight: 700;
|
|
230
|
+
font-size: 14px;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.brand-name {
|
|
234
|
+
font-family: var(--font-mono);
|
|
235
|
+
font-size: 0.95rem;
|
|
236
|
+
color: var(--muted);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.hero-title-gradient {
|
|
240
|
+
background: linear-gradient(180deg, #ffffff, #b8b8c8);
|
|
241
|
+
-webkit-background-clip: text;
|
|
242
|
+
background-clip: text;
|
|
243
|
+
-webkit-text-fill-color: transparent;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.hero-accent {
|
|
247
|
+
color: var(--accent);
|
|
248
|
+
font-style: normal;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.scroll-cue {
|
|
252
|
+
position: absolute;
|
|
253
|
+
bottom: 2rem;
|
|
254
|
+
left: 50%;
|
|
255
|
+
transform: translateX(-50%);
|
|
256
|
+
font-family: var(--font-mono);
|
|
257
|
+
font-size: 0.78rem;
|
|
258
|
+
color: var(--dim);
|
|
259
|
+
animation: drift 2.4s ease-in-out infinite;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@keyframes drift {
|
|
263
|
+
0%,
|
|
264
|
+
100% {
|
|
265
|
+
transform: translate(-50%, 0);
|
|
266
|
+
opacity: 0.7;
|
|
267
|
+
}
|
|
268
|
+
50% {
|
|
269
|
+
transform: translate(-50%, 6px);
|
|
270
|
+
opacity: 1;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* grids */
|
|
275
|
+
.grid {
|
|
276
|
+
display: grid;
|
|
277
|
+
gap: 1.25rem;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.grid-2 {
|
|
281
|
+
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.grid-3 {
|
|
285
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.card {
|
|
289
|
+
background: var(--bg-elev);
|
|
290
|
+
border: 1px solid var(--line);
|
|
291
|
+
border-radius: var(--radius-lg);
|
|
292
|
+
padding: 1.5rem 1.5rem 1.4rem;
|
|
293
|
+
transition: border-color 0.2s ease, transform 0.2s ease;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.card:hover {
|
|
297
|
+
border-color: var(--accent-line);
|
|
298
|
+
transform: translateY(-2px);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.card .card-kicker {
|
|
302
|
+
font-family: var(--font-mono);
|
|
303
|
+
font-size: 0.78rem;
|
|
304
|
+
letter-spacing: 0.06em;
|
|
305
|
+
text-transform: uppercase;
|
|
306
|
+
color: var(--accent);
|
|
307
|
+
margin-bottom: 0.6rem;
|
|
308
|
+
display: block;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.card p {
|
|
312
|
+
margin: 0;
|
|
313
|
+
color: var(--muted);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.pill {
|
|
317
|
+
display: inline-block;
|
|
318
|
+
font-family: var(--font-mono);
|
|
319
|
+
font-size: 0.72rem;
|
|
320
|
+
letter-spacing: 0.06em;
|
|
321
|
+
text-transform: uppercase;
|
|
322
|
+
padding: 0.2em 0.6em;
|
|
323
|
+
border-radius: 999px;
|
|
324
|
+
background: var(--accent-soft);
|
|
325
|
+
color: var(--accent);
|
|
326
|
+
border: 1px solid var(--accent-line);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
ul.flat {
|
|
330
|
+
list-style: none;
|
|
331
|
+
padding: 0;
|
|
332
|
+
margin: 0.5rem 0 0;
|
|
333
|
+
display: grid;
|
|
334
|
+
gap: 0.75rem;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
ul.flat > li {
|
|
338
|
+
position: relative;
|
|
339
|
+
padding-left: 1.4rem;
|
|
340
|
+
color: var(--muted);
|
|
341
|
+
line-height: 1.6;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
ul.flat > li::before {
|
|
345
|
+
content: '';
|
|
346
|
+
position: absolute;
|
|
347
|
+
left: 0;
|
|
348
|
+
top: 0.65em;
|
|
349
|
+
width: 6px;
|
|
350
|
+
height: 6px;
|
|
351
|
+
background: var(--accent);
|
|
352
|
+
border-radius: 2px;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
ul.flat > li strong {
|
|
356
|
+
color: var(--text);
|
|
357
|
+
font-weight: 600;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* comparison split */
|
|
361
|
+
.compare {
|
|
362
|
+
display: grid;
|
|
363
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
364
|
+
gap: 1.5rem;
|
|
365
|
+
margin-top: 1.5rem;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.compare-col {
|
|
369
|
+
background: var(--bg-elev);
|
|
370
|
+
border: 1px solid var(--line);
|
|
371
|
+
border-radius: var(--radius-lg);
|
|
372
|
+
padding: 1.5rem;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.compare-col h3 {
|
|
376
|
+
margin-bottom: 0.75rem;
|
|
377
|
+
font-size: 1rem;
|
|
378
|
+
font-family: var(--font-mono);
|
|
379
|
+
letter-spacing: 0.04em;
|
|
380
|
+
text-transform: uppercase;
|
|
381
|
+
color: var(--accent);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.compare-col h3.warm {
|
|
385
|
+
color: var(--warn);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.compare-col ul {
|
|
389
|
+
margin-top: 0.5rem;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* architecture diagram */
|
|
393
|
+
.architecture {
|
|
394
|
+
background: var(--bg-elev);
|
|
395
|
+
border: 1px solid var(--line);
|
|
396
|
+
border-radius: var(--radius-lg);
|
|
397
|
+
padding: 1.75rem;
|
|
398
|
+
margin-top: 1.5rem;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.architecture svg {
|
|
402
|
+
width: 100%;
|
|
403
|
+
height: auto;
|
|
404
|
+
display: block;
|
|
405
|
+
max-height: 56vh;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.architecture-legend {
|
|
409
|
+
margin-top: 1.5rem;
|
|
410
|
+
font-family: var(--font-mono);
|
|
411
|
+
font-size: 0.82rem;
|
|
412
|
+
color: var(--muted);
|
|
413
|
+
display: grid;
|
|
414
|
+
gap: 0.5rem;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.architecture-legend strong {
|
|
418
|
+
color: var(--text);
|
|
419
|
+
font-weight: 600;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/* terminal */
|
|
423
|
+
.terminal {
|
|
424
|
+
background: var(--code-bg);
|
|
425
|
+
border: 1px solid var(--line);
|
|
426
|
+
border-radius: var(--radius-lg);
|
|
427
|
+
overflow: hidden;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.terminal-bar {
|
|
431
|
+
display: flex;
|
|
432
|
+
gap: 0.4em;
|
|
433
|
+
padding: 0.65rem 0.9rem;
|
|
434
|
+
background: var(--bg-elev-2);
|
|
435
|
+
border-bottom: 1px solid var(--line);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.terminal-bar span {
|
|
439
|
+
width: 10px;
|
|
440
|
+
height: 10px;
|
|
441
|
+
border-radius: 50%;
|
|
442
|
+
background: var(--dim);
|
|
443
|
+
opacity: 0.7;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.terminal-bar span:nth-child(1) {
|
|
447
|
+
background: #ff5f56;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.terminal-bar span:nth-child(2) {
|
|
451
|
+
background: #ffbd2e;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.terminal-bar span:nth-child(3) {
|
|
455
|
+
background: #27c93f;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.terminal pre {
|
|
459
|
+
margin: 0;
|
|
460
|
+
border: 0;
|
|
461
|
+
border-radius: 0;
|
|
462
|
+
background: transparent;
|
|
463
|
+
padding: 1.1rem 1.2rem;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.terminal .cmd {
|
|
467
|
+
color: var(--accent);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.terminal .out {
|
|
471
|
+
color: var(--muted);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.terminal .out-strong {
|
|
475
|
+
color: var(--text);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.terminal .err {
|
|
479
|
+
color: var(--danger);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* vignette use-case cards */
|
|
483
|
+
.vignettes {
|
|
484
|
+
display: grid;
|
|
485
|
+
gap: 1.25rem;
|
|
486
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
487
|
+
margin-top: 1.5rem;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.vignette {
|
|
491
|
+
background: var(--bg-elev);
|
|
492
|
+
border: 1px solid var(--line);
|
|
493
|
+
border-radius: var(--radius-lg);
|
|
494
|
+
padding: 1.5rem;
|
|
495
|
+
display: grid;
|
|
496
|
+
gap: 0.6rem;
|
|
497
|
+
transition: border-color 0.2s ease;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.vignette:hover {
|
|
501
|
+
border-color: var(--accent-line);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.vignette .v-prompt {
|
|
505
|
+
font-style: italic;
|
|
506
|
+
color: var(--text);
|
|
507
|
+
font-size: 1rem;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.vignette .v-answer {
|
|
511
|
+
color: var(--muted);
|
|
512
|
+
font-size: 0.95rem;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.vignette .v-cmd {
|
|
516
|
+
font-family: var(--font-mono);
|
|
517
|
+
font-size: 0.82rem;
|
|
518
|
+
color: var(--accent);
|
|
519
|
+
padding: 0.45rem 0.75rem;
|
|
520
|
+
background: var(--code-bg);
|
|
521
|
+
border-radius: 6px;
|
|
522
|
+
border: 1px solid var(--line);
|
|
523
|
+
white-space: nowrap;
|
|
524
|
+
overflow-x: auto;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* side nav dots */
|
|
528
|
+
.deck-nav {
|
|
529
|
+
position: fixed;
|
|
530
|
+
right: max(1rem, 2.5vw);
|
|
531
|
+
top: 50%;
|
|
532
|
+
transform: translateY(-50%);
|
|
533
|
+
display: flex;
|
|
534
|
+
flex-direction: column;
|
|
535
|
+
gap: 0.7rem;
|
|
536
|
+
z-index: 50;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.deck-nav a {
|
|
540
|
+
position: relative;
|
|
541
|
+
width: 8px;
|
|
542
|
+
height: 8px;
|
|
543
|
+
border-radius: 50%;
|
|
544
|
+
background: var(--line);
|
|
545
|
+
border: 0;
|
|
546
|
+
display: block;
|
|
547
|
+
transition: background-color 0.2s ease, transform 0.2s ease;
|
|
548
|
+
}
|
|
549
|
+
.deck-nav a::after {
|
|
550
|
+
content: '';
|
|
551
|
+
position: absolute;
|
|
552
|
+
inset: -8px;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.deck-nav a.active {
|
|
556
|
+
background: var(--accent);
|
|
557
|
+
transform: scale(1.4);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.deck-nav a:hover {
|
|
561
|
+
background: var(--accent-line);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.deck-nav a span {
|
|
565
|
+
position: absolute;
|
|
566
|
+
right: 16px;
|
|
567
|
+
top: 50%;
|
|
568
|
+
transform: translateY(-50%);
|
|
569
|
+
white-space: nowrap;
|
|
570
|
+
font-family: var(--font-mono);
|
|
571
|
+
font-size: 0.7rem;
|
|
572
|
+
color: var(--dim);
|
|
573
|
+
opacity: 0;
|
|
574
|
+
transition: opacity 0.15s ease;
|
|
575
|
+
pointer-events: none;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.deck-nav a:hover span,
|
|
579
|
+
.deck-nav a.active span {
|
|
580
|
+
opacity: 1;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/* progress bar */
|
|
584
|
+
.progress {
|
|
585
|
+
position: fixed;
|
|
586
|
+
top: 0;
|
|
587
|
+
left: 0;
|
|
588
|
+
width: 100%;
|
|
589
|
+
height: 2px;
|
|
590
|
+
background: transparent;
|
|
591
|
+
z-index: 60;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.progress-bar {
|
|
595
|
+
height: 100%;
|
|
596
|
+
background: linear-gradient(90deg, var(--accent), #7c8cff);
|
|
597
|
+
width: 0;
|
|
598
|
+
transition: width 0.1s linear;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/* footer-ish closing */
|
|
602
|
+
#close .slide-inner {
|
|
603
|
+
align-items: flex-start;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.cta-row {
|
|
607
|
+
display: flex;
|
|
608
|
+
flex-wrap: wrap;
|
|
609
|
+
gap: 0.75rem;
|
|
610
|
+
margin-top: 2rem;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.cta {
|
|
614
|
+
display: inline-block;
|
|
615
|
+
padding: 0.8rem 1.4rem;
|
|
616
|
+
background: var(--accent);
|
|
617
|
+
color: #0a0a0d;
|
|
618
|
+
font-family: var(--font-mono);
|
|
619
|
+
font-size: 0.95rem;
|
|
620
|
+
font-weight: 600;
|
|
621
|
+
border-radius: 8px;
|
|
622
|
+
text-decoration: none;
|
|
623
|
+
border: 0;
|
|
624
|
+
transition: transform 0.15s ease;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.cta:hover {
|
|
628
|
+
transform: translateY(-1px);
|
|
629
|
+
border-bottom: 0;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.cta.outline {
|
|
633
|
+
background: transparent;
|
|
634
|
+
color: var(--accent);
|
|
635
|
+
border: 1px solid var(--accent-line);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.colophon {
|
|
639
|
+
font-family: var(--font-mono);
|
|
640
|
+
color: var(--dim);
|
|
641
|
+
font-size: 0.82rem;
|
|
642
|
+
margin-top: 3rem;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.kbd {
|
|
646
|
+
display: inline-block;
|
|
647
|
+
font-family: var(--font-mono);
|
|
648
|
+
font-size: 0.78em;
|
|
649
|
+
padding: 0.1em 0.45em;
|
|
650
|
+
border-radius: 4px;
|
|
651
|
+
border: 1px solid var(--line);
|
|
652
|
+
background: var(--bg-elev);
|
|
653
|
+
color: var(--text);
|
|
654
|
+
line-height: 1.4;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/* reveal animation */
|
|
658
|
+
.reveal {
|
|
659
|
+
opacity: 0;
|
|
660
|
+
transform: translateY(14px);
|
|
661
|
+
transition: opacity 0.6s ease, transform 0.6s ease;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.reveal.visible {
|
|
665
|
+
opacity: 1;
|
|
666
|
+
transform: none;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
@media (max-width: 720px) {
|
|
670
|
+
.deck-nav {
|
|
671
|
+
display: none;
|
|
672
|
+
}
|
|
673
|
+
.slide {
|
|
674
|
+
min-height: auto;
|
|
675
|
+
padding: 3rem 1.25rem;
|
|
676
|
+
}
|
|
677
|
+
html {
|
|
678
|
+
scroll-snap-type: none;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
</style>
|
|
682
|
+
</head>
|
|
683
|
+
|
|
684
|
+
<body>
|
|
685
|
+
<div class="progress"><div class="progress-bar" id="progressBar"></div></div>
|
|
686
|
+
|
|
687
|
+
<nav class="deck-nav" aria-label="Section progress">
|
|
688
|
+
<a href="#hero" data-label="Intro"><span>Intro</span></a>
|
|
689
|
+
<a href="#problem" data-label="Problem"><span>Problem</span></a>
|
|
690
|
+
<a href="#meet" data-label="Meet threadnote"><span>Meet</span></a>
|
|
691
|
+
<a href="#vs-instructions" data-label="vs CLAUDE.md / AGENTS.md"><span>vs instructions</span></a>
|
|
692
|
+
<a href="#how" data-label="How it works"><span>How</span></a>
|
|
693
|
+
<a href="#safety" data-label="Safety model"><span>Safety</span></a>
|
|
694
|
+
<a href="#install" data-label="Install"><span>Install</span></a>
|
|
695
|
+
<a href="#seed" data-label="Seed"><span>Seed</span></a>
|
|
696
|
+
<a href="#update" data-label="Update"><span>Update</span></a>
|
|
697
|
+
<a href="#lifecycle" data-label="Lifecycle"><span>Lifecycle</span></a>
|
|
698
|
+
<a href="#use-cases" data-label="Use cases"><span>Use cases</span></a>
|
|
699
|
+
<a href="#share" data-label="Share"><span>Share</span></a>
|
|
700
|
+
<a href="#close" data-label="Get started"><span>Start</span></a>
|
|
701
|
+
</nav>
|
|
702
|
+
|
|
703
|
+
<main class="deck">
|
|
704
|
+
<!-- 1. HERO -->
|
|
705
|
+
<section id="hero" class="slide">
|
|
706
|
+
<div class="slide-inner">
|
|
707
|
+
<div class="brand">
|
|
708
|
+
<div class="brand-mark">t</div>
|
|
709
|
+
<span class="brand-name">threadnote</span>
|
|
710
|
+
</div>
|
|
711
|
+
<h1 class="hero-title-gradient">
|
|
712
|
+
Shared local context<br />for <em class="hero-accent">development agents</em>.
|
|
713
|
+
</h1>
|
|
714
|
+
<p class="lead">
|
|
715
|
+
One memory layer Codex, Claude, Cursor, and Copilot all see. Durable feature knowledge, recent handoffs, and
|
|
716
|
+
team-shared decisions — recallable from any session, on any agent, in any worktree.
|
|
717
|
+
</p>
|
|
718
|
+
<div class="cta-row">
|
|
719
|
+
<span class="pill">v0.5.0 · local-first · MIT</span>
|
|
720
|
+
</div>
|
|
721
|
+
</div>
|
|
722
|
+
<div class="scroll-cue">scroll ↓ · <span class="kbd">↓</span> / <span class="kbd">j</span></div>
|
|
723
|
+
</section>
|
|
724
|
+
|
|
725
|
+
<!-- 2. PROBLEM -->
|
|
726
|
+
<section id="problem" class="slide">
|
|
727
|
+
<div class="slide-inner">
|
|
728
|
+
<span class="slide-eyebrow">01 · The problem</span>
|
|
729
|
+
<h2>Agent context is ephemeral. <span class="muted">You aren't.</span></h2>
|
|
730
|
+
<p class="lead">
|
|
731
|
+
Every new session your agent starts from zero. You re-explain the same architecture, repaste the same
|
|
732
|
+
handoff, and rediscover the same gotchas. Across four different agents this multiplies.
|
|
733
|
+
</p>
|
|
734
|
+
<ul class="flat reveal" style="margin-top: 2rem">
|
|
735
|
+
<li><strong>Conversation history evaporates.</strong> Compaction summarizes; the nuance is lost.</li>
|
|
736
|
+
<li>
|
|
737
|
+
<strong>Each agent has its own memory.</strong> Switching from Codex to Claude means starting over.
|
|
738
|
+
</li>
|
|
739
|
+
<li>
|
|
740
|
+
<strong>CLAUDE.md/AGENTS.md is per-repo and static.</strong> It can't carry an in-flight feature's design
|
|
741
|
+
decisions across sessions, much less across agents or repos.
|
|
742
|
+
</li>
|
|
743
|
+
<li>
|
|
744
|
+
<strong>Hand-typed handoffs rot.</strong> The next session needs them, but you only remember to write them
|
|
745
|
+
half the time.
|
|
746
|
+
</li>
|
|
747
|
+
<li>
|
|
748
|
+
<strong>Team knowledge stays in DMs.</strong> Decisions made in Slack thread #1842 don't reach your
|
|
749
|
+
teammate's agent.
|
|
750
|
+
</li>
|
|
751
|
+
</ul>
|
|
752
|
+
</div>
|
|
753
|
+
</section>
|
|
754
|
+
|
|
755
|
+
<!-- 3. MEET THREADNOTE -->
|
|
756
|
+
<section id="meet" class="slide">
|
|
757
|
+
<div class="slide-inner">
|
|
758
|
+
<span class="slide-eyebrow">02 · Meet threadnote</span>
|
|
759
|
+
<h2>A safe local memory layer for the agents you already use.</h2>
|
|
760
|
+
<p class="lead">
|
|
761
|
+
Threadnote sits between your agents and a local
|
|
762
|
+
<a href="https://openviking.ai/" target="_blank" rel="noopener">OpenViking</a> store. One stdio MCP adapter,
|
|
763
|
+
one URI scheme, one set of commands. Everything stays on your machine until you explicitly publish it.
|
|
764
|
+
</p>
|
|
765
|
+
|
|
766
|
+
<div class="grid grid-2" style="margin-top: 2rem">
|
|
767
|
+
<div class="card reveal">
|
|
768
|
+
<span class="card-kicker">Cross-agent</span>
|
|
769
|
+
<h3>One memory, four agents</h3>
|
|
770
|
+
<p>
|
|
771
|
+
Codex, Claude Code, Cursor, and Copilot all recall and write into the same OpenViking store via the
|
|
772
|
+
threadnote MCP adapter.
|
|
773
|
+
</p>
|
|
774
|
+
</div>
|
|
775
|
+
<div class="card reveal">
|
|
776
|
+
<span class="card-kicker">Cross-session</span>
|
|
777
|
+
<h3>Survives compaction</h3>
|
|
778
|
+
<p>
|
|
779
|
+
After the context window fills up, the next turn recalls durable feature memories and the latest handoff
|
|
780
|
+
instead of relying on the compressed summary alone.
|
|
781
|
+
</p>
|
|
782
|
+
</div>
|
|
783
|
+
<div class="card reveal">
|
|
784
|
+
<span class="card-kicker">Lifecycle-aware</span>
|
|
785
|
+
<h3>Durable vs handoff</h3>
|
|
786
|
+
<p>
|
|
787
|
+
<code>kind: durable</code> for facts that should outlive a session. <code>kind: handoff</code> for
|
|
788
|
+
current work logs. One stable file per <code>project/topic</code>; updates replace rather than
|
|
789
|
+
accumulate.
|
|
790
|
+
</p>
|
|
791
|
+
</div>
|
|
792
|
+
<div class="card reveal">
|
|
793
|
+
<span class="card-kicker">Local-first</span>
|
|
794
|
+
<h3>Yours, on your machine</h3>
|
|
795
|
+
<p>
|
|
796
|
+
Nothing leaves <code>~/.openviking</code> unless you explicitly <code>share publish</code> a curated
|
|
797
|
+
memory to a team git repo. No telemetry, no SaaS, no network egress.
|
|
798
|
+
</p>
|
|
799
|
+
</div>
|
|
800
|
+
</div>
|
|
801
|
+
</div>
|
|
802
|
+
</section>
|
|
803
|
+
|
|
804
|
+
<!-- 4. vs CLAUDE.md / AGENTS.md -->
|
|
805
|
+
<section id="vs-instructions" class="slide">
|
|
806
|
+
<div class="slide-inner">
|
|
807
|
+
<span class="slide-eyebrow">03 · Why not just CLAUDE.md or AGENTS.md?</span>
|
|
808
|
+
<h2>Use them. Threadnote is not a replacement.</h2>
|
|
809
|
+
<p class="lead">
|
|
810
|
+
They are perfect for stable, canonical, version-controlled rules. They are wrong for living context — what
|
|
811
|
+
happened in the last session, which branch is mid-refactor, which on-call workaround actually shipped.
|
|
812
|
+
</p>
|
|
813
|
+
|
|
814
|
+
<div class="compare">
|
|
815
|
+
<div class="compare-col reveal">
|
|
816
|
+
<h3 class="warm">CLAUDE.md · AGENTS.md · Cursor rules</h3>
|
|
817
|
+
<ul class="flat">
|
|
818
|
+
<li><strong>Where it lives:</strong> in the repo, versioned, shared via PR.</li>
|
|
819
|
+
<li>
|
|
820
|
+
<strong>Best for:</strong> coding standards, test commands, review rules, architecture invariants.
|
|
821
|
+
</li>
|
|
822
|
+
<li><strong>Read pattern:</strong> loaded into every agent context window in this repo.</li>
|
|
823
|
+
<li><strong>Edit cost:</strong> human writes; PR review; high friction (which is the point).</li>
|
|
824
|
+
<li><strong>Lifecycle:</strong> long-lived. Stale entries hurt every session.</li>
|
|
825
|
+
</ul>
|
|
826
|
+
</div>
|
|
827
|
+
|
|
828
|
+
<div class="compare-col reveal">
|
|
829
|
+
<h3>Threadnote</h3>
|
|
830
|
+
<ul class="flat">
|
|
831
|
+
<li>
|
|
832
|
+
<strong>Where it lives:</strong> local OpenViking store, cross-repo, cross-agent. Optionally published
|
|
833
|
+
to a team git repo.
|
|
834
|
+
</li>
|
|
835
|
+
<li>
|
|
836
|
+
<strong>Best for:</strong> feature knowledge, handoffs, branch state, prod-on-call findings, personal
|
|
837
|
+
workflow facts.
|
|
838
|
+
</li>
|
|
839
|
+
<li>
|
|
840
|
+
<strong>Read pattern:</strong> recalled on demand; only the relevant URIs enter the context window.
|
|
841
|
+
</li>
|
|
842
|
+
<li><strong>Edit cost:</strong> agents write; humans guide; low friction by design.</li>
|
|
843
|
+
<li><strong>Lifecycle:</strong> durable / handoff / archived. Compact in place, never accrete.</li>
|
|
844
|
+
</ul>
|
|
845
|
+
</div>
|
|
846
|
+
</div>
|
|
847
|
+
|
|
848
|
+
<p class="muted" style="margin-top: 1.5rem">
|
|
849
|
+
<strong style="color: var(--text)">The split:</strong> put repo policy in the .md files. Put feature
|
|
850
|
+
history, in-flight task state, handoffs, and personal workflow facts in threadnote.
|
|
851
|
+
</p>
|
|
852
|
+
</div>
|
|
853
|
+
</section>
|
|
854
|
+
|
|
855
|
+
<!-- 5. HOW IT WORKS -->
|
|
856
|
+
<section id="how" class="slide">
|
|
857
|
+
<div class="slide-inner">
|
|
858
|
+
<span class="slide-eyebrow">04 · How it works</span>
|
|
859
|
+
<h2>One MCP adapter, one URI scheme, one local store.</h2>
|
|
860
|
+
|
|
861
|
+
<div class="architecture reveal">
|
|
862
|
+
<svg viewBox="0 0 880 380" role="img" aria-label="Threadnote architecture diagram">
|
|
863
|
+
<defs>
|
|
864
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
|
865
|
+
<path d="M0,0 L10,5 L0,10 z" fill="#5ee0c5" />
|
|
866
|
+
</marker>
|
|
867
|
+
<linearGradient id="agentGrad" x1="0" y1="0" x2="1" y2="1">
|
|
868
|
+
<stop offset="0" stop-color="#1c1c24" />
|
|
869
|
+
<stop offset="1" stop-color="#15151a" />
|
|
870
|
+
</linearGradient>
|
|
871
|
+
</defs>
|
|
872
|
+
|
|
873
|
+
<!-- agents row -->
|
|
874
|
+
<g font-family="JetBrains Mono, monospace" font-size="13" fill="#ececf1">
|
|
875
|
+
<rect x="20" y="20" width="170" height="64" rx="10" fill="url(#agentGrad)" stroke="#2a2a35" />
|
|
876
|
+
<text x="105" y="48" text-anchor="middle">Codex CLI</text>
|
|
877
|
+
<text x="105" y="68" text-anchor="middle" fill="#8a8a96" font-size="11">stdio MCP</text>
|
|
878
|
+
|
|
879
|
+
<rect x="210" y="20" width="170" height="64" rx="10" fill="url(#agentGrad)" stroke="#2a2a35" />
|
|
880
|
+
<text x="295" y="48" text-anchor="middle">Claude Code</text>
|
|
881
|
+
<text x="295" y="68" text-anchor="middle" fill="#8a8a96" font-size="11">stdio MCP</text>
|
|
882
|
+
|
|
883
|
+
<rect x="400" y="20" width="170" height="64" rx="10" fill="url(#agentGrad)" stroke="#2a2a35" />
|
|
884
|
+
<text x="485" y="48" text-anchor="middle">Cursor</text>
|
|
885
|
+
<text x="485" y="68" text-anchor="middle" fill="#8a8a96" font-size="11">stdio MCP</text>
|
|
886
|
+
|
|
887
|
+
<rect x="590" y="20" width="170" height="64" rx="10" fill="url(#agentGrad)" stroke="#2a2a35" />
|
|
888
|
+
<text x="675" y="48" text-anchor="middle">Copilot (VS Code)</text>
|
|
889
|
+
<text x="675" y="68" text-anchor="middle" fill="#8a8a96" font-size="11">stdio MCP</text>
|
|
890
|
+
</g>
|
|
891
|
+
|
|
892
|
+
<!-- arrows down -->
|
|
893
|
+
<g stroke="#5ee0c5" stroke-width="1.5" fill="none" marker-end="url(#arrow)" opacity="0.7">
|
|
894
|
+
<line x1="105" y1="84" x2="380" y2="148" />
|
|
895
|
+
<line x1="295" y1="84" x2="400" y2="148" />
|
|
896
|
+
<line x1="485" y1="84" x2="480" y2="148" />
|
|
897
|
+
<line x1="675" y1="84" x2="500" y2="148" />
|
|
898
|
+
</g>
|
|
899
|
+
|
|
900
|
+
<!-- threadnote MCP -->
|
|
901
|
+
<g font-family="JetBrains Mono, monospace" font-size="13" fill="#ececf1">
|
|
902
|
+
<rect x="340" y="150" width="200" height="60" rx="10" fill="#5ee0c5" />
|
|
903
|
+
<text x="440" y="178" text-anchor="middle" fill="#0a0a0d" font-weight="600">threadnote-mcp-server</text>
|
|
904
|
+
<text x="440" y="196" text-anchor="middle" fill="#0a0a0d" opacity="0.7" font-size="11">
|
|
905
|
+
recall · read · list · remember · share
|
|
906
|
+
</text>
|
|
907
|
+
</g>
|
|
908
|
+
|
|
909
|
+
<!-- arrow to OV -->
|
|
910
|
+
<g stroke="#5ee0c5" stroke-width="1.5" fill="none" marker-end="url(#arrow)" opacity="0.7">
|
|
911
|
+
<line x1="440" y1="210" x2="440" y2="244" />
|
|
912
|
+
</g>
|
|
913
|
+
|
|
914
|
+
<!-- OpenViking -->
|
|
915
|
+
<g font-family="JetBrains Mono, monospace" font-size="13" fill="#ececf1">
|
|
916
|
+
<rect x="290" y="246" width="300" height="60" rx="10" fill="url(#agentGrad)" stroke="#2a2a35" />
|
|
917
|
+
<text x="440" y="272" text-anchor="middle">openviking-server</text>
|
|
918
|
+
<text x="440" y="290" text-anchor="middle" fill="#8a8a96" font-size="11">
|
|
919
|
+
127.0.0.1:1933 · python · uv-managed
|
|
920
|
+
</text>
|
|
921
|
+
</g>
|
|
922
|
+
|
|
923
|
+
<!-- arrows to storage -->
|
|
924
|
+
<g stroke="#5ee0c5" stroke-width="1.5" fill="none" marker-end="url(#arrow)" opacity="0.7">
|
|
925
|
+
<line x1="380" y1="306" x2="240" y2="340" />
|
|
926
|
+
<line x1="500" y1="306" x2="640" y2="340" />
|
|
927
|
+
</g>
|
|
928
|
+
|
|
929
|
+
<!-- storage -->
|
|
930
|
+
<g font-family="JetBrains Mono, monospace" font-size="12" fill="#ececf1">
|
|
931
|
+
<rect x="60" y="340" width="360" height="32" rx="6" fill="#101019" stroke="#2a2a35" />
|
|
932
|
+
<text x="240" y="361" text-anchor="middle">~/.openviking/data/viking/<account>/...</text>
|
|
933
|
+
|
|
934
|
+
<rect x="460" y="340" width="360" height="32" rx="6" fill="#101019" stroke="#2a2a35" />
|
|
935
|
+
<text x="640" y="361" text-anchor="middle">vectordb (LevelDB · semantic index)</text>
|
|
936
|
+
</g>
|
|
937
|
+
</svg>
|
|
938
|
+
<div class="architecture-legend">
|
|
939
|
+
<div><strong>One adapter, one URI scheme.</strong> Every agent calls the same MCP tools.</div>
|
|
940
|
+
<div>
|
|
941
|
+
<strong>URIs are stable.</strong> A memory at <code>viking://user/<you>/...</code> is the same
|
|
942
|
+
pointer from every session.
|
|
943
|
+
</div>
|
|
944
|
+
<div>
|
|
945
|
+
<strong>Storage is plain markdown</strong> on your filesystem. The vectordb is regenerable; the source
|
|
946
|
+
of truth is on disk.
|
|
947
|
+
</div>
|
|
948
|
+
</div>
|
|
949
|
+
</div>
|
|
950
|
+
</div>
|
|
951
|
+
</section>
|
|
952
|
+
|
|
953
|
+
<!-- 6. SAFETY -->
|
|
954
|
+
<section id="safety" class="slide">
|
|
955
|
+
<div class="slide-inner">
|
|
956
|
+
<span class="slide-eyebrow">05 · Safety model</span>
|
|
957
|
+
<h2>Local by default. Explicit when it isn't.</h2>
|
|
958
|
+
<p class="lead">
|
|
959
|
+
Threadnote is designed for an environment where agents write to your memory. The defaults assume that's
|
|
960
|
+
untrusted and that mistakes happen.
|
|
961
|
+
</p>
|
|
962
|
+
|
|
963
|
+
<div class="grid grid-2" style="margin-top: 1.5rem">
|
|
964
|
+
<div class="card reveal">
|
|
965
|
+
<span class="card-kicker">Local</span>
|
|
966
|
+
<h3>Writes stay on disk</h3>
|
|
967
|
+
<p>
|
|
968
|
+
Every <code>remember</code> / <code>handoff</code> writes under <code>THREADNOTE_HOME</code> (defaults
|
|
969
|
+
to <code>~/.openviking</code>). Nothing leaves the machine without explicit user action.
|
|
970
|
+
</p>
|
|
971
|
+
</div>
|
|
972
|
+
<div class="card reveal">
|
|
973
|
+
<span class="card-kicker">Curated</span>
|
|
974
|
+
<h3>Manifest-scoped seeding</h3>
|
|
975
|
+
<p>
|
|
976
|
+
<code>threadnote seed</code> imports only paths declared in a seed manifest. It does not index whole
|
|
977
|
+
repos. The default patterns target <code>CLAUDE.md</code>, <code>AGENTS.md</code>,
|
|
978
|
+
<code>SKILL.md</code>, and <code>docs/**</code>.
|
|
979
|
+
</p>
|
|
980
|
+
</div>
|
|
981
|
+
<div class="card reveal">
|
|
982
|
+
<span class="card-kicker">Filtered</span>
|
|
983
|
+
<h3>Built-in ignore + redaction</h3>
|
|
984
|
+
<p>
|
|
985
|
+
<code>.threadnoteignore</code> excludes build output, binaries, env files, and logs. Known config files
|
|
986
|
+
(<code>.mcp.json</code>, <code>config.toml</code>, settings JSON) pass through a redactor before import.
|
|
987
|
+
</p>
|
|
988
|
+
</div>
|
|
989
|
+
<div class="card reveal">
|
|
990
|
+
<span class="card-kicker">Scanned</span>
|
|
991
|
+
<h3>Secret-pattern scrubber</h3>
|
|
992
|
+
<p>
|
|
993
|
+
Candidate files are skipped if common token shapes survive redaction. The
|
|
994
|
+
<code>share publish</code> path refuses to push memories that contain PEM keys,
|
|
995
|
+
<code>sk-…</code> / <code>github_pat_…</code> / <code>glpat-…</code>, JWTs, AWS keys, or Slack tokens.
|
|
996
|
+
</p>
|
|
997
|
+
</div>
|
|
998
|
+
<div class="card reveal">
|
|
999
|
+
<span class="card-kicker">Explicit</span>
|
|
1000
|
+
<h3>Agent configs are opt-in</h3>
|
|
1001
|
+
<p>
|
|
1002
|
+
<code>mcp-install <agent></code> prints the commands by default. Pass <code>--apply</code> to
|
|
1003
|
+
actually modify Codex/Claude/Cursor/Copilot config. User-level instruction blocks are surrounded by
|
|
1004
|
+
markers and only their managed region is rewritten.
|
|
1005
|
+
</p>
|
|
1006
|
+
</div>
|
|
1007
|
+
<div class="card reveal">
|
|
1008
|
+
<span class="card-kicker">Transactional</span>
|
|
1009
|
+
<h3>No half-published state</h3>
|
|
1010
|
+
<p>
|
|
1011
|
+
If <code>share publish</code> can't remove the personal copy after writing the shared copy, it rolls the
|
|
1012
|
+
shared write back. You either publish cleanly or you publish nothing.
|
|
1013
|
+
</p>
|
|
1014
|
+
</div>
|
|
1015
|
+
</div>
|
|
1016
|
+
</div>
|
|
1017
|
+
</section>
|
|
1018
|
+
|
|
1019
|
+
<!-- 7. INSTALL -->
|
|
1020
|
+
<section id="install" class="slide">
|
|
1021
|
+
<div class="slide-inner">
|
|
1022
|
+
<span class="slide-eyebrow">06 · Install</span>
|
|
1023
|
+
<h2>One command. Then point your agents at it.</h2>
|
|
1024
|
+
<p class="lead">
|
|
1025
|
+
The installer wires up the npm package, the OpenViking Python environment, and the local server. After
|
|
1026
|
+
that, <code>mcp-install</code> per agent and you're done.
|
|
1027
|
+
</p>
|
|
1028
|
+
|
|
1029
|
+
<div class="grid grid-2" style="margin-top: 1.5rem">
|
|
1030
|
+
<div class="reveal">
|
|
1031
|
+
<h3 style="margin-bottom: 0.5rem">1. Install threadnote</h3>
|
|
1032
|
+
<div class="terminal">
|
|
1033
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1034
|
+
<pre><span class="cmd">$ curl -fsSL https://raw.githubusercontent.com/Kashkovsky/threadnote/main/scripts/install.sh | sh</span>
|
|
1035
|
+
|
|
1036
|
+
<span class="out">Installed threadnote@0.4.1</span>
|
|
1037
|
+
<span class="out">Already exists: ~/.local/bin/threadnote</span>
|
|
1038
|
+
<span class="out">OpenViking installs into Python; neither uv nor pipx is</span>
|
|
1039
|
+
<span class="out">on PATH so threadnote would fall back to `pip install</span>
|
|
1040
|
+
<span class="out">--user`, which fails on PEP 668 setups.</span>
|
|
1041
|
+
<span class="out">Install uv now? [Y/n] </span><span class="out-strong">Y</span>
|
|
1042
|
+
<span class="out">Installing uv via Homebrew…</span>
|
|
1043
|
+
<span class="out-strong">OK openviking 0.3.12 ready · server healthy</span></pre>
|
|
1044
|
+
</div>
|
|
1045
|
+
<p class="muted" style="margin-top: 0.75rem; font-size: 0.9rem">
|
|
1046
|
+
Or manually: <code>npm install -g threadnote && threadnote install</code>. On a fresh macOS / modern
|
|
1047
|
+
Linux machine the installer offers to <code>brew install uv</code> for you (avoids PEP 668 errors).
|
|
1048
|
+
</p>
|
|
1049
|
+
</div>
|
|
1050
|
+
|
|
1051
|
+
<div class="reveal">
|
|
1052
|
+
<h3 style="margin-bottom: 0.5rem">2. Wire up each agent (pick what you use)</h3>
|
|
1053
|
+
<div class="terminal">
|
|
1054
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1055
|
+
<pre><span class="cmd">$ threadnote mcp-install codex --apply</span>
|
|
1056
|
+
<span class="cmd">$ threadnote mcp-install claude --apply</span>
|
|
1057
|
+
<span class="cmd">$ threadnote mcp-install cursor --apply</span>
|
|
1058
|
+
<span class="cmd">$ threadnote mcp-install copilot --apply</span>
|
|
1059
|
+
<span class="out">Installed MCP server `threadnote` for codex, claude,</span>
|
|
1060
|
+
<span class="out">cursor, copilot. Restart agent sessions to pick up.</span>
|
|
1061
|
+
|
|
1062
|
+
<span class="cmd">$ threadnote doctor --dry-run</span>
|
|
1063
|
+
<span class="out-strong">Summary: 0 failure(s), 0 warning(s)</span></pre>
|
|
1064
|
+
</div>
|
|
1065
|
+
<p class="muted" style="margin-top: 0.75rem; font-size: 0.9rem">
|
|
1066
|
+
Without <code>--apply</code>, each command prints a dry run so you can review before changing your agent
|
|
1067
|
+
configs. Run <code>doctor</code> anytime to verify.
|
|
1068
|
+
</p>
|
|
1069
|
+
</div>
|
|
1070
|
+
</div>
|
|
1071
|
+
|
|
1072
|
+
<p class="muted" style="margin-top: 2rem">
|
|
1073
|
+
Open a fresh agent session after installing MCP — the tool list reloads at session start.
|
|
1074
|
+
</p>
|
|
1075
|
+
</div>
|
|
1076
|
+
</section>
|
|
1077
|
+
|
|
1078
|
+
<!-- 8. SEEDING -->
|
|
1079
|
+
<section id="seed" class="slide">
|
|
1080
|
+
<div class="slide-inner">
|
|
1081
|
+
<span class="slide-eyebrow">07 · Seeding repo context</span>
|
|
1082
|
+
<h2>Pull just the curated docs into recall.</h2>
|
|
1083
|
+
<p class="lead">
|
|
1084
|
+
Threadnote does not index whole repos. Instead, point it at a seed manifest of paths you actually want
|
|
1085
|
+
agents to recall — typically <code>AGENTS.md</code>, <code>CLAUDE.md</code>, repo docs, and
|
|
1086
|
+
<code>SKILL.md</code> guidance.
|
|
1087
|
+
</p>
|
|
1088
|
+
|
|
1089
|
+
<div class="grid grid-2" style="margin-top: 1.5rem">
|
|
1090
|
+
<div class="reveal">
|
|
1091
|
+
<h3>Generate a manifest</h3>
|
|
1092
|
+
<div class="terminal">
|
|
1093
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1094
|
+
<pre><span class="cmd">$ threadnote init-manifest \
|
|
1095
|
+
--repo ~/src/web-app \
|
|
1096
|
+
--repo ~/src/mobile-app</span>
|
|
1097
|
+
<span class="out">Wrote ~/.openviking/seed-manifest.yaml (2 project(s))</span>
|
|
1098
|
+
|
|
1099
|
+
<span class="cmd">$ threadnote seed</span>
|
|
1100
|
+
<span class="out-strong">Imported 47 curated path(s); skipped 6 secret-flagged.</span>
|
|
1101
|
+
|
|
1102
|
+
<span class="cmd">$ threadnote seed-skills</span>
|
|
1103
|
+
<span class="out-strong">Imported SKILL.md catalog from Codex, Claude, repos.</span></pre>
|
|
1104
|
+
</div>
|
|
1105
|
+
</div>
|
|
1106
|
+
|
|
1107
|
+
<div class="reveal">
|
|
1108
|
+
<h3>What the manifest looks like</h3>
|
|
1109
|
+
<pre><code>version: 1
|
|
1110
|
+
projects:
|
|
1111
|
+
- name: web-app
|
|
1112
|
+
path: ~/src/web-app
|
|
1113
|
+
uri: viking://resources/repos/web-app
|
|
1114
|
+
seed:
|
|
1115
|
+
- AGENTS.md
|
|
1116
|
+
- CLAUDE.md
|
|
1117
|
+
- docs/**/*.md
|
|
1118
|
+
- .claude/skills/**/SKILL.md
|
|
1119
|
+
- name: mobile-app
|
|
1120
|
+
path: ~/src/mobile-app
|
|
1121
|
+
uri: viking://resources/repos/mobile-app
|
|
1122
|
+
seed:
|
|
1123
|
+
- AGENTS.md
|
|
1124
|
+
- docs/**/*.md</code></pre>
|
|
1125
|
+
</div>
|
|
1126
|
+
</div>
|
|
1127
|
+
|
|
1128
|
+
<ul class="flat reveal" style="margin-top: 2rem">
|
|
1129
|
+
<li>
|
|
1130
|
+
<strong>Recall is smart enough to scope by query.</strong> Ask "web-app durable feature memories" and
|
|
1131
|
+
recall prefers <code>viking://resources/repos/web-app</code> first.
|
|
1132
|
+
</li>
|
|
1133
|
+
<li>
|
|
1134
|
+
<strong>Seeding is opt-in and re-runnable.</strong> <code>threadnote seed</code> never deletes; it
|
|
1135
|
+
upserts.
|
|
1136
|
+
</li>
|
|
1137
|
+
<li>
|
|
1138
|
+
<strong>Skills are a first-class catalog.</strong> <code>seed-skills</code> makes reusable workflows
|
|
1139
|
+
discoverable: testing, release, on-call, debugging, plugin guidance.
|
|
1140
|
+
</li>
|
|
1141
|
+
</ul>
|
|
1142
|
+
</div>
|
|
1143
|
+
</section>
|
|
1144
|
+
|
|
1145
|
+
<!-- 9. UPDATES -->
|
|
1146
|
+
<section id="update" class="slide">
|
|
1147
|
+
<div class="slide-inner">
|
|
1148
|
+
<span class="slide-eyebrow">08 · Updates & repair</span>
|
|
1149
|
+
<h2>Always one command from a clean state.</h2>
|
|
1150
|
+
|
|
1151
|
+
<div class="grid grid-2" style="margin-top: 1.5rem">
|
|
1152
|
+
<div class="reveal">
|
|
1153
|
+
<h3>Routine update</h3>
|
|
1154
|
+
<div class="terminal">
|
|
1155
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1156
|
+
<pre><span class="cmd">$ threadnote update</span>
|
|
1157
|
+
<span class="out">Latest: threadnote@0.4.1 (installed: 0.4.0)</span>
|
|
1158
|
+
<span class="out">Running: npm install -g threadnote@0.4.1</span>
|
|
1159
|
+
<span class="out">Running: threadnote repair</span>
|
|
1160
|
+
<span class="out-strong">All checks passed. Restart agents to reload MCP.</span></pre>
|
|
1161
|
+
</div>
|
|
1162
|
+
<p class="muted" style="font-size: 0.9rem; margin-top: 0.75rem">
|
|
1163
|
+
<code>update --check</code> reports what's available. <code>update --dry-run</code> shows the plan.
|
|
1164
|
+
Releases may include post-update memory migrations that prompt before applying.
|
|
1165
|
+
</p>
|
|
1166
|
+
</div>
|
|
1167
|
+
|
|
1168
|
+
<div class="reveal">
|
|
1169
|
+
<h3>Repair after a moved checkout</h3>
|
|
1170
|
+
<div class="terminal">
|
|
1171
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1172
|
+
<pre><span class="cmd">$ threadnote repair</span>
|
|
1173
|
+
<span class="out">OK threadnote shim: ~/.local/bin/threadnote</span>
|
|
1174
|
+
<span class="out">OK codex / claude / cursor / copilot user instructions</span>
|
|
1175
|
+
<span class="out">OK manifest, ignore file, templates</span>
|
|
1176
|
+
<span class="out">OK openviking health</span>
|
|
1177
|
+
<span class="out-strong">Summary: 0 failure(s), 0 warning(s)</span></pre>
|
|
1178
|
+
</div>
|
|
1179
|
+
<p class="muted" style="font-size: 0.9rem; margin-top: 0.75rem">
|
|
1180
|
+
Rewrites the threadnote shim and every agent's MCP config to point at the current install. Run after
|
|
1181
|
+
deleting an old npm prefix or moving the package between Node versions.
|
|
1182
|
+
</p>
|
|
1183
|
+
</div>
|
|
1184
|
+
</div>
|
|
1185
|
+
</div>
|
|
1186
|
+
</section>
|
|
1187
|
+
|
|
1188
|
+
<!-- 10. LIFECYCLE -->
|
|
1189
|
+
<section id="lifecycle" class="slide">
|
|
1190
|
+
<div class="slide-inner">
|
|
1191
|
+
<span class="slide-eyebrow">09 · Memory lifecycle</span>
|
|
1192
|
+
<h2>Durable. Handoff. Archived.</h2>
|
|
1193
|
+
<p class="lead">
|
|
1194
|
+
Three lifecycle states, one stable URI per <code>project/topic</code>. Updates replace, never accrete.
|
|
1195
|
+
</p>
|
|
1196
|
+
|
|
1197
|
+
<div class="grid grid-3" style="margin-top: 1.5rem">
|
|
1198
|
+
<div class="card reveal">
|
|
1199
|
+
<span class="card-kicker">kind: durable</span>
|
|
1200
|
+
<h3>Long-lived feature knowledge</h3>
|
|
1201
|
+
<p>
|
|
1202
|
+
Design decisions, API contracts, gotchas, intended behavior. The kind that should outlive a session and
|
|
1203
|
+
travel across agents. Default for <code>threadnote remember</code>.
|
|
1204
|
+
</p>
|
|
1205
|
+
</div>
|
|
1206
|
+
<div class="card reveal">
|
|
1207
|
+
<span class="card-kicker">kind: handoff</span>
|
|
1208
|
+
<h3>Current work logs</h3>
|
|
1209
|
+
<p>
|
|
1210
|
+
Repo, branch, files touched, tests run, blockers, next step. The kind your next agent recalls first.
|
|
1211
|
+
<code>threadnote handoff</code> captures git state automatically.
|
|
1212
|
+
</p>
|
|
1213
|
+
</div>
|
|
1214
|
+
<div class="card reveal">
|
|
1215
|
+
<span class="card-kicker">status: archived</span>
|
|
1216
|
+
<h3>Provenance only</h3>
|
|
1217
|
+
<p>
|
|
1218
|
+
Old handoffs that helped at the time but shouldn't be current working context. <code>archive</code>
|
|
1219
|
+
moves them out of the active recall scope; <code>--include-archived</code> still finds them.
|
|
1220
|
+
</p>
|
|
1221
|
+
</div>
|
|
1222
|
+
</div>
|
|
1223
|
+
|
|
1224
|
+
<div style="margin-top: 2rem" class="reveal">
|
|
1225
|
+
<h3 style="margin-bottom: 0.75rem">One file per project/topic</h3>
|
|
1226
|
+
<pre><code># Capture an in-flight feature memory and its current handoff side by side:
|
|
1227
|
+
threadnote remember \
|
|
1228
|
+
--kind durable --project web-app --topic auth-token-refresh \
|
|
1229
|
+
--text "Architecture: provider-only token client, JWT helpers in jwt.ts..."
|
|
1230
|
+
|
|
1231
|
+
threadnote handoff \
|
|
1232
|
+
--project web-app --topic auth-token-refresh \
|
|
1233
|
+
--task "Address reviewer comments on token refresh PR" \
|
|
1234
|
+
--tests "make lint-lite; mocha auth_client_test 77 passing" \
|
|
1235
|
+
--next-step "Push and request re-review"
|
|
1236
|
+
|
|
1237
|
+
# Later, update the durable memory in place (no timestamped duplicates):
|
|
1238
|
+
threadnote remember \
|
|
1239
|
+
--kind durable --project web-app --topic auth-token-refresh \
|
|
1240
|
+
--replace viking://user/<you>/memories/durable/projects/web-app/auth-token-refresh.md \
|
|
1241
|
+
--text "..."</code></pre>
|
|
1242
|
+
</div>
|
|
1243
|
+
</div>
|
|
1244
|
+
</section>
|
|
1245
|
+
|
|
1246
|
+
<!-- 11. USE CASES -->
|
|
1247
|
+
<section id="use-cases" class="slide">
|
|
1248
|
+
<div class="slide-inner">
|
|
1249
|
+
<span class="slide-eyebrow">10 · Real-world use cases</span>
|
|
1250
|
+
<h2>Where it actually pays off.</h2>
|
|
1251
|
+
|
|
1252
|
+
<div class="vignettes">
|
|
1253
|
+
<div class="vignette reveal">
|
|
1254
|
+
<div class="v-prompt">"Continue the feature from yesterday."</div>
|
|
1255
|
+
<div class="v-answer">
|
|
1256
|
+
Fresh session, fresh agent. Threadnote recalls the active handoff for the branch plus the durable
|
|
1257
|
+
feature memory: design decisions, the open PR, what's left, what just failed in CI. No re-explaining.
|
|
1258
|
+
</div>
|
|
1259
|
+
<div class="v-cmd">threadnote recall --query "<branch> latest handoff"</div>
|
|
1260
|
+
</div>
|
|
1261
|
+
|
|
1262
|
+
<div class="vignette reveal">
|
|
1263
|
+
<div class="v-prompt">"What did we conclude about that prod-on-call thing?"</div>
|
|
1264
|
+
<div class="v-answer">
|
|
1265
|
+
The sanitized handoff from the on-call escalation is still there. Re-open the same Slack thread three
|
|
1266
|
+
weeks later; the durable feature memory points your agent at the right files and the resolution.
|
|
1267
|
+
</div>
|
|
1268
|
+
<div class="v-cmd">threadnote recall --query "export workflow timeout on-call findings"</div>
|
|
1269
|
+
</div>
|
|
1270
|
+
|
|
1271
|
+
<div class="vignette reveal">
|
|
1272
|
+
<div class="v-prompt">"Switch from Codex to Claude mid-task."</div>
|
|
1273
|
+
<div class="v-answer">
|
|
1274
|
+
Codex stores a handoff before pausing. Claude opens the same MCP layer, recalls the handoff plus the
|
|
1275
|
+
durable memory, picks up the test command and the open blocker without you typing them again.
|
|
1276
|
+
</div>
|
|
1277
|
+
<div class="v-cmd">threadnote handoff --task "..." --next-step "..."</div>
|
|
1278
|
+
</div>
|
|
1279
|
+
|
|
1280
|
+
<div class="vignette reveal">
|
|
1281
|
+
<div class="v-prompt">"Onboard a new teammate to a feature."</div>
|
|
1282
|
+
<div class="v-answer">
|
|
1283
|
+
Publish the feature's durable memory to the team repo with <code>share publish</code>. Their agent
|
|
1284
|
+
pulls it on the next <code>share sync</code> and recall surfaces it alongside their own personal
|
|
1285
|
+
memories — no DM forwarding, no PDF dumping.
|
|
1286
|
+
</div>
|
|
1287
|
+
<div class="v-cmd">threadnote share publish viking://user/<you>/memories/durable/...</div>
|
|
1288
|
+
</div>
|
|
1289
|
+
|
|
1290
|
+
<div class="vignette reveal">
|
|
1291
|
+
<div class="v-prompt">"Compaction is about to nuke the context."</div>
|
|
1292
|
+
<div class="v-answer">
|
|
1293
|
+
Before context fills up, the agent stores a handoff. The next turn after compaction recalls it — the
|
|
1294
|
+
summary covers the conversation arc, threadnote covers the durable facts the summary couldn't keep.
|
|
1295
|
+
</div>
|
|
1296
|
+
<div class="v-cmd">threadnote handoff --project <repo> --topic <feature> ...</div>
|
|
1297
|
+
</div>
|
|
1298
|
+
|
|
1299
|
+
<div class="vignette reveal">
|
|
1300
|
+
<div class="v-prompt">"Where does this repo run its release notes?"</div>
|
|
1301
|
+
<div class="v-answer">
|
|
1302
|
+
You discovered it the hard way last time. Tell your agent to <code>remember</code> the fact. Next time
|
|
1303
|
+
anyone asks, the agent finds it in two seconds without grepping the wiki.
|
|
1304
|
+
</div>
|
|
1305
|
+
<div class="v-cmd">threadnote remember --kind durable --topic release-process ...</div>
|
|
1306
|
+
</div>
|
|
1307
|
+
</div>
|
|
1308
|
+
</div>
|
|
1309
|
+
</section>
|
|
1310
|
+
|
|
1311
|
+
<!-- 12. SHARE -->
|
|
1312
|
+
<section id="share" class="slide">
|
|
1313
|
+
<div class="slide-inner">
|
|
1314
|
+
<span class="slide-eyebrow">11 · Sharing across the team</span>
|
|
1315
|
+
<h2>Curated memories. Yours to push. Theirs to pull.</h2>
|
|
1316
|
+
<p class="lead">
|
|
1317
|
+
<code>threadnote share</code> publishes a subset of durable memories into a git repo so other engineers'
|
|
1318
|
+
agents can recall them. Personal handoffs, preferences, and unpublished durables always stay local.
|
|
1319
|
+
</p>
|
|
1320
|
+
|
|
1321
|
+
<div class="grid grid-2" style="margin-top: 1.5rem">
|
|
1322
|
+
<div class="reveal">
|
|
1323
|
+
<h3>One-time setup</h3>
|
|
1324
|
+
<div class="terminal">
|
|
1325
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1326
|
+
<pre><span class="cmd">$ threadnote share init git@github.com:org/team-memories.git</span>
|
|
1327
|
+
<span class="out">Cloned into ~/.openviking/data/.../memories/shared/default/</span>
|
|
1328
|
+
<span class="out">Ingested 12 shared memory file(s) into OpenViking.</span>
|
|
1329
|
+
<span class="out">Added .gitignore exclusions for OV directory summaries.</span></pre>
|
|
1330
|
+
</div>
|
|
1331
|
+
<p class="muted" style="font-size: 0.9rem; margin-top: 0.6rem">
|
|
1332
|
+
Working tree lives inside the OV data tree so recall sees it. The git directory is moved aside via
|
|
1333
|
+
<code>--separate-git-dir</code> so OV never sees git internals.
|
|
1334
|
+
</p>
|
|
1335
|
+
</div>
|
|
1336
|
+
|
|
1337
|
+
<div class="reveal">
|
|
1338
|
+
<h3>Publish a durable memory</h3>
|
|
1339
|
+
<div class="terminal">
|
|
1340
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1341
|
+
<pre><span class="cmd">$ threadnote share publish \
|
|
1342
|
+
viking://user/<you>/memories/durable/projects/<p>/<t>.md</span>
|
|
1343
|
+
<span class="out">Scrubber: no secret patterns detected.</span>
|
|
1344
|
+
<span class="out">git commit -m 'share: publish durable/projects/<p>/<t>.md'</span>
|
|
1345
|
+
<span class="out-strong">Published. Pushed to origin/main.</span></pre>
|
|
1346
|
+
</div>
|
|
1347
|
+
<p class="muted" style="font-size: 0.9rem; margin-top: 0.6rem">
|
|
1348
|
+
Refuses to publish if the memory matches secret patterns (PEM, <code>sk-</code>, <code>gh*_</code>,
|
|
1349
|
+
<code>github_pat_</code>, <code>glpat-</code>, JWTs, AWS keys, Slack tokens). Refuses to silently
|
|
1350
|
+
overwrite an existing shared URI.
|
|
1351
|
+
</p>
|
|
1352
|
+
</div>
|
|
1353
|
+
|
|
1354
|
+
<div class="reveal">
|
|
1355
|
+
<h3>Pull teammates' updates</h3>
|
|
1356
|
+
<div class="terminal">
|
|
1357
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1358
|
+
<pre><span class="cmd">$ threadnote share sync</span>
|
|
1359
|
+
<span class="out">git pull --rebase</span>
|
|
1360
|
+
<span class="out">Reindexed 3 file change(s) into OpenViking.</span>
|
|
1361
|
+
<span class="out-strong">Recall now finds new shared memories alongside personal.</span></pre>
|
|
1362
|
+
</div>
|
|
1363
|
+
<p class="muted" style="font-size: 0.9rem; margin-top: 0.6rem">
|
|
1364
|
+
Recall sees the shared subtree by default. Both semantic search and exact-token grep cover
|
|
1365
|
+
<code>viking://user/<you>/memories/shared/<team>/...</code> alongside your personal memories.
|
|
1366
|
+
</p>
|
|
1367
|
+
</div>
|
|
1368
|
+
|
|
1369
|
+
<div class="reveal">
|
|
1370
|
+
<h3>Take it back</h3>
|
|
1371
|
+
<div class="terminal">
|
|
1372
|
+
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1373
|
+
<pre><span class="cmd">$ threadnote share unpublish <shared-uri></span>
|
|
1374
|
+
<span class="out">Wrote back to personal namespace.</span>
|
|
1375
|
+
<span class="out-strong">git rm + commit + push.</span></pre>
|
|
1376
|
+
</div>
|
|
1377
|
+
<p class="muted" style="font-size: 0.9rem; margin-top: 0.6rem">
|
|
1378
|
+
The publish flow is transactional: if removing the personal copy fails after the shared write, the
|
|
1379
|
+
shared write is rolled back. You never end up half-published.
|
|
1380
|
+
</p>
|
|
1381
|
+
</div>
|
|
1382
|
+
</div>
|
|
1383
|
+
|
|
1384
|
+
<ul class="flat reveal" style="margin-top: 2rem">
|
|
1385
|
+
<li>
|
|
1386
|
+
<strong>Only <code>durable/</code> memories are shareable.</strong> Handoffs, preferences, incidents, and
|
|
1387
|
+
everything else stays local by construction.
|
|
1388
|
+
</li>
|
|
1389
|
+
<li>
|
|
1390
|
+
<strong>Concurrent-publish safe.</strong> If two teammates publish the same <code>project/topic</code> at
|
|
1391
|
+
the same time, the retry path won't silently overwrite the other's write.
|
|
1392
|
+
</li>
|
|
1393
|
+
<li>
|
|
1394
|
+
<strong>MCP-native too.</strong> Agents can call the <code>share_publish</code> tool directly when they
|
|
1395
|
+
decide a memory is teammate-worthy.
|
|
1396
|
+
</li>
|
|
1397
|
+
</ul>
|
|
1398
|
+
</div>
|
|
1399
|
+
</section>
|
|
1400
|
+
|
|
1401
|
+
<!-- 13. CLOSE -->
|
|
1402
|
+
<section id="close" class="slide">
|
|
1403
|
+
<div class="slide-inner">
|
|
1404
|
+
<span class="slide-eyebrow">12 · Get started</span>
|
|
1405
|
+
<h2>Try it on your machine in 90 seconds.</h2>
|
|
1406
|
+
|
|
1407
|
+
<pre style="margin-top: 1.5rem">
|
|
1408
|
+
<code>curl -fsSL https://raw.githubusercontent.com/Kashkovsky/threadnote/main/scripts/install.sh | sh
|
|
1409
|
+
threadnote mcp-install codex --apply # or claude / cursor / copilot
|
|
1410
|
+
threadnote doctor --dry-run</code></pre>
|
|
1411
|
+
|
|
1412
|
+
<div class="cta-row">
|
|
1413
|
+
<a class="cta" href="https://github.com/Kashkovsky/threadnote" target="_blank" rel="noopener">
|
|
1414
|
+
GitHub →
|
|
1415
|
+
</a>
|
|
1416
|
+
<a class="cta outline" href="https://www.npmjs.com/package/threadnote" target="_blank" rel="noopener">
|
|
1417
|
+
npm
|
|
1418
|
+
</a>
|
|
1419
|
+
<a
|
|
1420
|
+
class="cta outline"
|
|
1421
|
+
href="https://github.com/Kashkovsky/threadnote/blob/main/docs/share.md"
|
|
1422
|
+
target="_blank"
|
|
1423
|
+
rel="noopener"
|
|
1424
|
+
>
|
|
1425
|
+
docs/share.md
|
|
1426
|
+
</a>
|
|
1427
|
+
</div>
|
|
1428
|
+
|
|
1429
|
+
<p class="colophon">
|
|
1430
|
+
threadnote · MIT · built on OpenViking 0.3.12 · use <span class="kbd">↑</span> <span class="kbd">↓</span> /
|
|
1431
|
+
<span class="kbd">j</span> <span class="kbd">k</span> to navigate
|
|
1432
|
+
</p>
|
|
1433
|
+
</div>
|
|
1434
|
+
</section>
|
|
1435
|
+
</main>
|
|
1436
|
+
|
|
1437
|
+
<script>
|
|
1438
|
+
// Section progress + scroll spy + keyboard nav.
|
|
1439
|
+
(function () {
|
|
1440
|
+
const slides = Array.from(document.querySelectorAll('.slide'));
|
|
1441
|
+
const dots = Array.from(document.querySelectorAll('.deck-nav a'));
|
|
1442
|
+
const progressBar = document.getElementById('progressBar');
|
|
1443
|
+
|
|
1444
|
+
// Map dot href -> dot element for spy.
|
|
1445
|
+
const dotByHash = new Map(dots.map(d => [d.getAttribute('href'), d]));
|
|
1446
|
+
|
|
1447
|
+
const io = new IntersectionObserver(
|
|
1448
|
+
entries => {
|
|
1449
|
+
entries.forEach(entry => {
|
|
1450
|
+
if (entry.isIntersecting && entry.intersectionRatio > 0.55) {
|
|
1451
|
+
dots.forEach(d => d.classList.remove('active'));
|
|
1452
|
+
const dot = dotByHash.get('#' + entry.target.id);
|
|
1453
|
+
if (dot) dot.classList.add('active');
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
},
|
|
1457
|
+
{threshold: [0.55, 0.75]},
|
|
1458
|
+
);
|
|
1459
|
+
slides.forEach(s => io.observe(s));
|
|
1460
|
+
|
|
1461
|
+
// Reveal-on-enter for any element with .reveal
|
|
1462
|
+
const revealIo = new IntersectionObserver(
|
|
1463
|
+
entries => {
|
|
1464
|
+
entries.forEach(entry => {
|
|
1465
|
+
if (entry.isIntersecting) {
|
|
1466
|
+
entry.target.classList.add('visible');
|
|
1467
|
+
revealIo.unobserve(entry.target);
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
},
|
|
1471
|
+
{threshold: 0.15},
|
|
1472
|
+
);
|
|
1473
|
+
document.querySelectorAll('.reveal').forEach(el => revealIo.observe(el));
|
|
1474
|
+
|
|
1475
|
+
// Progress bar fills as you scroll through the deck.
|
|
1476
|
+
const updateProgress = () => {
|
|
1477
|
+
const scrolled = window.scrollY;
|
|
1478
|
+
const max = document.documentElement.scrollHeight - window.innerHeight;
|
|
1479
|
+
progressBar.style.width = `${Math.min(100, (scrolled / Math.max(1, max)) * 100)}%`;
|
|
1480
|
+
};
|
|
1481
|
+
window.addEventListener('scroll', updateProgress, {passive: true});
|
|
1482
|
+
updateProgress();
|
|
1483
|
+
|
|
1484
|
+
// Keyboard navigation: ↑/↓/j/k/Space/PgUp/PgDn jump between slides.
|
|
1485
|
+
const goTo = idx => {
|
|
1486
|
+
const i = Math.max(0, Math.min(slides.length - 1, idx));
|
|
1487
|
+
slides[i].scrollIntoView({behavior: 'smooth'});
|
|
1488
|
+
};
|
|
1489
|
+
const currentIdx = () => {
|
|
1490
|
+
const y = window.scrollY + window.innerHeight / 2;
|
|
1491
|
+
for (let i = 0; i < slides.length; i += 1) {
|
|
1492
|
+
const r = slides[i].getBoundingClientRect();
|
|
1493
|
+
const top = r.top + window.scrollY;
|
|
1494
|
+
if (y >= top && y < top + r.height) return i;
|
|
1495
|
+
}
|
|
1496
|
+
return 0;
|
|
1497
|
+
};
|
|
1498
|
+
window.addEventListener('keydown', e => {
|
|
1499
|
+
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
|
1500
|
+
const tag = (e.target && e.target.tagName) || '';
|
|
1501
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA') return;
|
|
1502
|
+
const i = currentIdx();
|
|
1503
|
+
switch (e.key) {
|
|
1504
|
+
case 'ArrowDown':
|
|
1505
|
+
case 'j':
|
|
1506
|
+
case ' ':
|
|
1507
|
+
case 'PageDown':
|
|
1508
|
+
e.preventDefault();
|
|
1509
|
+
goTo(i + 1);
|
|
1510
|
+
break;
|
|
1511
|
+
case 'ArrowUp':
|
|
1512
|
+
case 'k':
|
|
1513
|
+
case 'PageUp':
|
|
1514
|
+
e.preventDefault();
|
|
1515
|
+
goTo(i - 1);
|
|
1516
|
+
break;
|
|
1517
|
+
case 'Home':
|
|
1518
|
+
e.preventDefault();
|
|
1519
|
+
goTo(0);
|
|
1520
|
+
break;
|
|
1521
|
+
case 'End':
|
|
1522
|
+
e.preventDefault();
|
|
1523
|
+
goTo(slides.length - 1);
|
|
1524
|
+
break;
|
|
1525
|
+
default:
|
|
1526
|
+
break;
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
})();
|
|
1530
|
+
</script>
|
|
1531
|
+
</body>
|
|
1532
|
+
</html>
|