threadnote 0.7.10 → 0.7.12

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 CHANGED
@@ -4,11 +4,14 @@
4
4
 
5
5
  # Threadnote
6
6
 
7
+ [![npm version](https://img.shields.io/npm/v/threadnote.svg)](https://www.npmjs.com/package/threadnote) [![CI](https://img.shields.io/github/actions/workflow/status/Kashkovsky/threadnote/ci.yml?branch=main&label=CI)](https://github.com/Kashkovsky/threadnote/actions/workflows/ci.yml) [![npm downloads](https://img.shields.io/npm/dm/threadnote.svg)](https://www.npmjs.com/package/threadnote) [![license](https://img.shields.io/npm/l/threadnote.svg)](./LICENSE) ![node version](https://img.shields.io/node/v/threadnote.svg)
8
+
7
9
  `threadnote` is a safe local workflow for using [OpenViking](https://openviking.ai/) as shared, agent-neutral context for development work.
8
10
  It is intentionally scoped to curated docs, memories, skills, and handoffs. It is not a source-navigation replacement,
9
11
  and it does not index whole repositories by default.
10
12
 
11
- > **Walkthrough deck:** https://kashkovsky.github.io/threadnote/
13
+ **Walkthrough:** https://kashkovsky.github.io/threadnote/
14
+ **Wiki:** https://github.com/Kashkovsky/threadnote/wiki
12
15
 
13
16
  ## Real-World Uses
14
17
 
@@ -45,424 +48,3 @@ which memory to keep/update, which old handoffs to archive, and which exact dupl
45
48
  Use `threadnote remember --replace <uri>` or `threadnote handoff --replace <uri>` to keep one current-state memory fresh
46
49
  instead of accumulating near-duplicate progress notes. Replacing a shared `durable/` URI updates that shared memory in
47
50
  place and pushes the shared repo, so you do not need a separate `share publish` step.
48
-
49
- ## Memory Lifecycle
50
-
51
- Threadnote separates current durable knowledge from the historical handoff trail.
52
-
53
- New `remember` records default to `kind: durable` and `status: active`. New `handoff` records use `kind: handoff` and
54
- `status: active`. Add `--project` and `--topic` when the memory represents an ongoing issue or stable fact:
55
-
56
- ```bash
57
- threadnote remember --project threadnote --topic install-health --text "Install/repair waits for OpenViking health."
58
- threadnote handoff --project threadnote --topic lifecycle-storage --task "Implement lifecycle-aware memories"
59
- ```
60
-
61
- Active memories with the same project/topic write to a stable lifecycle path, so later updates replace the current
62
- version instead of creating another timestamped note. Untagged memories still use timestamped files when you want a
63
- historical trail.
64
-
65
- For feature branches, keep a durable feature memory and an active handoff side by side with the same project/topic:
66
-
67
- ```bash
68
- threadnote remember --kind durable --project my-repo --topic feature-x --text "Feature knowledge: ..."
69
- threadnote handoff --project my-repo --topic feature-x --task "Current status for feature X"
70
- ```
71
-
72
- Agents should update the durable feature memory when valuable implementation knowledge changes, and update the handoff
73
- when current status, tests, blockers, or next steps change.
74
-
75
- Bare `threadnote handoff` defaults to the current repo and current git branch as its stable project/topic, so routine
76
- handoffs update one active branch record. Use `threadnote handoff --timestamped` only when you intentionally want a
77
- historical note.
78
-
79
- Use `compact` when active memories for a project/topic start to overlap:
80
-
81
- ```bash
82
- threadnote compact --project my-repo --topic feature-x --dry-run
83
- threadnote compact --project my-repo --topic feature-x --apply
84
- ```
85
-
86
- The dry-run plan is the default. Applying archives stale handoffs, forgets only exact duplicates, and preserves source
87
- `viking://` URIs in the kept memory. Ambiguous durable or incident memories are left for manual review.
88
-
89
- Use `archive` when an old handoff is useful for provenance but should stop being treated as current working context:
90
-
91
- ```bash
92
- threadnote archive viking://user/example/memories/handoffs/active/threadnote/lifecycle-storage.md
93
- threadnote recall --query "threadnote lifecycle storage"
94
- threadnote recall --query "threadnote lifecycle storage" --include-archived
95
- ```
96
-
97
- If OpenViking is still processing the original file, `archive` keeps the archived copy and tells you to retry
98
- `threadnote forget <uri>` later.
99
-
100
- ## Why Not Just CLAUDE.md Or AGENTS.md?
101
-
102
- Use them. Threadnote is not a replacement for checked-in instructions.
103
-
104
- `CLAUDE.md`, `AGENTS.md`, Cursor rules, and repo docs are the right place for stable, canonical guidance: coding
105
- standards, test commands, review rules, architecture notes, and anything the whole team should version and discuss.
106
-
107
- They are less ideal for living context: what happened in the last agent session, which branch was halfway through a
108
- refactor, what an on-call investigation concluded, which workaround was verified on one machine, or which duplicate
109
- memories should be compacted. Putting that history into instruction files makes them noisy, stale, and expensive to load
110
- into every context window.
111
-
112
- Threadnote keeps that moving layer local, searchable, and shared across agents. Agents recall only the relevant durable
113
- feature memories, handoffs, and skill/resource pointers when they need them, while the source files stay authoritative
114
- for project rules.
115
-
116
- The split is simple: put durable repo policy in `CLAUDE.md`/`AGENTS.md`; put feature knowledge, task history, handoffs,
117
- personal workflow facts, and local cross-agent memory in Threadnote.
118
-
119
- ## Safety Model
120
-
121
- - Machine writes stay **locally** under `THREADNOTE_HOME`, which defaults to `~/.openviking`.
122
- - Curated manifests only: seed commands import only paths listed in `config/seed-manifest.example.yaml` or an explicit
123
- per-developer manifest.
124
- - Ignore rules: `.threadnoteignore` excludes build output, binary artifacts, local auth files, env files, and logs.
125
- - Redaction: known config files such as `.mcp.json`, `config.toml`, and settings JSON are copied through a redactor
126
- before import.
127
- - Secret scanning: candidate files are skipped if common token or private-key patterns remain after redaction.
128
- - User instructions: `install` upserts managed Threadnote guidance in `~/.codex/AGENTS.md`, `~/.claude/CLAUDE.md`,
129
- `~/.cursor/rules/threadnote.md`, and `~/.copilot/instructions/threadnote.instructions.md` without replacing existing
130
- personal instructions.
131
- - Agent config changes are explicit: `mcp-install` prints commands and snippets by default; use `--apply` to run them.
132
-
133
- ## Install
134
-
135
- Install with one command:
136
-
137
- ```bash
138
- curl -fsSL https://raw.githubusercontent.com/Kashkovsky/threadnote/main/scripts/install.sh | sh
139
- ```
140
-
141
- This installs the published package from npmjs and runs `threadnote install`. The install command sets up local config,
142
- repairs the OpenViking Python environment, and starts the local server so health problems surface immediately. It does
143
- not use npm `postinstall`, because setup writes local machine config and should be an explicit action.
144
-
145
- Confirm it is healthy:
146
-
147
- ```bash
148
- threadnote doctor --dry-run
149
- ```
150
-
151
- If install or health checks fail, see [Troubleshooting](docs/troubleshooting.md).
152
-
153
- To force a runtime:
154
-
155
- ```bash
156
- curl -fsSL https://raw.githubusercontent.com/Kashkovsky/threadnote/main/scripts/install.sh | THREADNOTE_RUNTIME=bun sh
157
- curl -fsSL https://raw.githubusercontent.com/Kashkovsky/threadnote/main/scripts/install.sh | THREADNOTE_RUNTIME=deno sh
158
- ```
159
-
160
- Or install manually:
161
-
162
- ```bash
163
- npm install --global threadnote
164
- threadnote install
165
- threadnote doctor --dry-run
166
- ```
167
-
168
- ### Update
169
-
170
- Threadnote occasionally checks npm for a newer published version when you run human-facing commands such as `doctor`,
171
- `start`, `install`, or `repair`. The check is cached under `THREADNOTE_HOME` and never runs in CI or when
172
- `THREADNOTE_NO_UPDATE_CHECK` or `NO_UPDATE_NOTIFIER` is set.
173
-
174
- Update the package and refresh local shims, user instructions, and MCP config with one command:
175
-
176
- ```bash
177
- threadnote update
178
- ```
179
-
180
- Check without changing anything:
181
-
182
- ```bash
183
- threadnote version
184
- threadnote update --check
185
- threadnote update --dry-run
186
- ```
187
-
188
- `threadnote version` prints the installed version, latest npm version, and GitHub release notes. When no update is
189
- available, it shows the current release notes; when an update is available, it shows every newer version. `threadnote
190
- update` prints the same full "What's new" diff when an update is available.
191
-
192
- After updating, restart Cursor, Copilot, Codex, Claude, or open a fresh agent session so MCP tools reload.
193
-
194
- Some releases include post-update memory migrations. `threadnote update` runs the new package's migration prompt after
195
- repair, explains what will change, and asks before applying it. Use `threadnote update --yes` for unattended local
196
- migrations or `threadnote update --no-post-update` to skip them.
197
-
198
- Applied migrations are tracked by id under `THREADNOTE_HOME`, and migration commands are written to be safe to rerun.
199
-
200
- If you update from an older Threadnote version that only knew how to run `repair`, the new repair step will still detect
201
- applicable migrations and print the manual command to run next.
202
-
203
- ### MCP
204
-
205
- Make the agents you use aware of Threadnote. Use only the MCP install lines for agents you actually use. Open a fresh
206
- agent session after installing MCP so the new server registration is loaded.
207
-
208
- Dry-run examples:
209
-
210
- ```bash
211
- threadnote mcp-install codex
212
- threadnote mcp-install claude
213
- threadnote mcp-install cursor
214
- threadnote mcp-install copilot
215
- ```
216
-
217
- Apply after review:
218
-
219
- ```bash
220
- threadnote mcp-install codex --apply
221
- threadnote mcp-install claude --apply
222
- threadnote mcp-install cursor --apply
223
- threadnote mcp-install copilot --apply
224
- ```
225
-
226
- Claude installs at `user` scope by default so the same OpenViking MCP server is available from any repo or worktree.
227
- Use `--scope local` or `--scope project` only when you intentionally want repo-scoped Claude MCP config.
228
- Cursor installs by updating the global `~/.cursor/mcp.json` file.
229
- Copilot installs by updating the VS Code user-profile `mcp.json` file. Set `THREADNOTE_COPILOT_MCP_CONFIG` if you use a
230
- custom VS Code profile or want to test against a temporary file.
231
-
232
- If the package or checkout that originally installed `threadnote` has moved, run repair:
233
-
234
- ```bash
235
- threadnote repair
236
- ```
237
-
238
- This rewrites the `threadnote` shim and reinstalls the stdio MCP adapter for available agents so launcher paths point
239
- at the current checkout.
240
-
241
- The default install uses the bundled stdio MCP adapter, because OpenViking `0.3.12` does not expose the native `/mcp`
242
- HTTP route:
243
-
244
- ```bash
245
- codex mcp add threadnote -- threadnote-mcp-server
246
- claude mcp add threadnote -- threadnote-mcp-server
247
- ```
248
-
249
- Cursor uses the equivalent entry in `~/.cursor/mcp.json`.
250
- Copilot uses the VS Code MCP `servers` entry in the user-profile `mcp.json`.
251
-
252
- ### Agent hooks (optional, opt-in)
253
-
254
- The instruction files (`~/.codex/AGENTS.md`, `~/.claude/CLAUDE.md`, etc.) are the **cross-agent guidance floor** — they
255
- ask agents to recall context, store handoffs, and so on, and they work for every supported agent. They rely on the
256
- agent to comply.
257
-
258
- For deterministic moments where the agent shouldn't have to remember, Threadnote can also install agent-side
259
- **hooks** — currently for Claude Code (the only supported agent that exposes a hook surface today):
260
-
261
- - **`PreCompact`** auto-stores a handoff snapshot for the current repo right before Claude compacts the conversation,
262
- so the next turn can recall it even if the agent forgot to write a handoff manually.
263
- - **`SessionStart`** preloads the latest threadnote handoff/feature memory for the current repo into the new session
264
- context, so the first turn already knows where you left off. The same hook also runs a daily-cached check against
265
- the npm registry and prints a one-line `[threadnote] vX.Y.Z available; run threadnote update` banner when the
266
- installed version is behind, so you stop missing releases. Set `THREADNOTE_AUTO_UPDATE=1` to skip the nag and have
267
- the hook spawn `threadnote update --yes` in the background instead — the new version takes effect on the next
268
- session.
269
-
270
- Install them per agent (Codex / Cursor / Copilot are no-ops today — Threadnote prints a clear explanation):
271
-
272
- ```bash
273
- threadnote install-hooks claude --dry-run # preview the change
274
- threadnote install-hooks claude --apply # add managed entries to ~/.claude/settings.json
275
- threadnote install-hooks claude --remove --apply # take them out again
276
- ```
277
-
278
- Or opt in at install time and let Threadnote drive every supported agent in one shot:
279
-
280
- ```bash
281
- threadnote install --with-hooks
282
- ```
283
-
284
- Managed entries are tagged with `"_threadnote": "managed"` so `threadnote repair` and `threadnote uninstall` can find
285
- and rewrite/remove only those entries without touching any of your own hooks. Hooks complement, not replace, the
286
- instruction files: the soft guidance covers semantic decisions ("is this memory durable?", "is this work meaningful
287
- enough to publish?"); hooks cover deterministic moments the agent shouldn't be trusted to remember.
288
-
289
- If a future OpenViking build exposes a healthy native endpoint, install it explicitly:
290
-
291
- ```bash
292
- threadnote mcp-install claude --native-http --apply
293
- ```
294
-
295
- ### Seed Local Repos
296
-
297
- Memories and handoffs work before seeding. Seed local repos when you want agents to recall repo guidance, docs, and
298
- skills without reopening the same files by hand.
299
-
300
- Create or update the local manifest with the repos you care about:
301
-
302
- ```bash
303
- threadnote init-manifest --repo ~/src/my-service --repo ~/work/mobile-app
304
- ```
305
-
306
- Review what will be imported, then seed curated repo guidance:
307
-
308
- ```bash
309
- threadnote seed --dry-run
310
- threadnote seed
311
- ```
312
-
313
- For Git worktrees, seed the stable checkout by default:
314
-
315
- ```bash
316
- threadnote init-manifest --repo ~/src/coda
317
- ```
318
-
319
- You usually do not need to add every temporary worktree such as `~/src/worktrees/coda/my-branch`. Threadnote treats each
320
- worktree path as its own manifest project today, so adding every worktree can duplicate seeded repo resources and make
321
- recall noisier. Add a worktree only when it is long-lived or has branch-specific docs, instructions, or repo-local skills
322
- that should be recalled separately.
323
-
324
- Optionally seed shared and repo-local skills. This imports existing `SKILL.md` files as a searchable resource catalog so
325
- agents can discover relevant workflow guidance; it does not install or activate skills in the agent runtime.
326
-
327
- ```bash
328
- threadnote seed-skills --dry-run
329
- threadnote seed-skills
330
- ```
331
-
332
- When you add another local repo later, rerun `init-manifest --repo <path>` and seed again.
333
-
334
- This is it! Start working with your agents as usual. The agent will automatically recall relevant memories and store the new ones. If you want to force it to recall/handoff something, just ask explicitly.
335
-
336
- ## Commands
337
-
338
- - `doctor`: checks prerequisites, the generated command shim, manifest shape, templates, and local OpenViking health.
339
- - `install`: installs `openviking[local-embed]==0.3.12` if missing, creates `~/.openviking` config files if absent,
340
- writes the command shim, upserts user-level agent instructions, and starts/checks OpenViking health by default. Use
341
- `--no-start` to skip the health check.
342
- - `version`: prints the installed Threadnote version, latest npm version, and release notes for newer GitHub releases.
343
- - `update`: updates the published Threadnote package, then runs `repair` so shims and MCP config point at the new
344
- version. When an update is available, it prints release notes for the full version diff.
345
- - `manage`: opens the local React web manager for browsing, recalling, reading, editing, archiving, forgetting,
346
- publishing, consolidating, and diagnosing local/shared memories. It binds to `127.0.0.1` with a per-session token; use
347
- `--no-open` to print the URL without opening a browser.
348
- - `repair`: fixes install/config/shim/manifest/server health issues and rewrites Codex/Claude/Cursor/Copilot MCP configs
349
- from the current checkout.
350
- - `start`: starts `openviking-server` on `127.0.0.1:1933`.
351
- - `stop`: stops the detached server pid or macOS LaunchAgent.
352
- - `uninstall`: removes Threadnote shims, MCP config, launchd config, and managed user instructions. Memories are
353
- preserved by default; pass `--erase-memories` to delete `THREADNOTE_HOME`.
354
- - `init-manifest`: creates or updates `~/.openviking/seed-manifest.yaml` from one or more developer repo roots.
355
- - `seed`: imports curated repo guidance and docs from the manifest.
356
- - `seed-skills`: imports global and repo-local `SKILL.md` files as a searchable resource catalog so agents can discover
357
- reusable workflow guidance. Use `seed-skills --native` only after configuring a working VLM provider.
358
- - `mcp-install codex|claude|cursor|copilot`: installs or prints OpenViking MCP configuration for Codex, Claude, Cursor,
359
- or GitHub Copilot in VS Code.
360
- - `remember`: stores a durable memory. Use `--replace <uri>` to store an updated memory and remove a superseded personal
361
- memory after the new memory succeeds; if `<uri>` is shared, Threadnote updates that shared memory in place and pushes
362
- the shared repo. Use `--kind`, `--project`, and `--topic` to store lifecycle-aware current knowledge.
363
- - `migrate-memories`: migrates legacy session-only `MEMORY` and `HANDOFF` records into durable memory files. Run
364
- `migrate-memories --dry-run` first; use `--all-accounts` when importing from older local OpenViking accounts.
365
- - `migrate-lifecycle`: moves clear legacy handoff memories from the old events path into archived lifecycle handoff
366
- paths. It dry-runs by default; use `--apply` after reviewing the output.
367
- - `recall`: searches shared OpenViking context. It infers repo or skill scope from queries like
368
- `skills for api service`; use `--uri` or `--no-infer-scope` to override. Queries that mention `this branch` or
369
- `current branch` are enriched with local git/workspace terms when available. Exact memory/resource matches skip
370
- archived lifecycle paths unless `--include-archived` is passed. Recall also nudges scoped cleanup when many active
371
- handoffs or overlapping returned memories surface.
372
- - `compact`: prints or applies scoped memory hygiene for active personal memories. It dry-runs by default; use `--apply`
373
- after reviewing the plan. It archives stale handoffs, forgets exact duplicates, and leaves ambiguous durable memories
374
- for manual review.
375
- - `read`: reads a `viking://` URI returned by `recall` or `list`.
376
- - `list` / `ls`: lists a `viking://` directory.
377
- - `handoff`: stores current git state and next-step notes as a durable handoff. Bare handoffs use the current repo and
378
- current branch as stable project/topic; use `--timestamped` for historical notes or `--project` / `--topic` to override.
379
- - `archive`: copies a memory into the archived lifecycle tree, then removes the original after the archive write
380
- succeeds.
381
- - `forget`: removes a `viking://` URI.
382
- - `export-pack` / `import-pack`: moves local context through `.ovpack` files.
383
- - `share init|status|sync|publish|unpublish|list|rename|set-url|remove`: opts a curated subset of durable memories into a team git
384
- repo. Threadnote periodically fetches configured share repos and automatically syncs clean incoming changes before
385
- agent recall/read; use `share sync` for dirty worktrees, conflicts, explicit pushes, or immediate manual sync.
386
- Personal handoffs and preferences stay local. See `docs/share.md` for the full workflow and the publish-time scrubber
387
- rules.
388
-
389
- ## Source Checkout
390
-
391
- TypeScript sources live under `src/`; `src/threadnote.ts` is the CLI entrypoint and `src/mcp_server.ts` is the stdio MCP
392
- adapter entrypoint.
393
-
394
- For local development from this repo:
395
-
396
- ```bash
397
- npm install
398
- npm run build
399
- npm run doctor -- --dry-run
400
- npm run threadnote -- install
401
- ```
402
-
403
- `install` writes a small command shim to `~/.local/bin/threadnote` by default and upserts user-level agent guidance in
404
- `~/.codex/AGENTS.md`, `~/.claude/CLAUDE.md`, `~/.cursor/rules/threadnote.md`, and
405
- `~/.copilot/instructions/threadnote.instructions.md`. After that, use the short command from any repo or working
406
- directory:
407
-
408
- ```bash
409
- threadnote doctor --dry-run
410
- threadnote init-manifest --repo ~/src/my-service --repo ~/work/mobile-app
411
- threadnote seed --dry-run
412
- threadnote seed-skills --dry-run
413
- ```
414
-
415
- If `~/.local/bin` is not on your `PATH`, either add it or set `THREADNOTE_BIN_DIR` before running `install`.
416
- After reviewing dry-run output, remove `--dry-run` for the operation you want to perform.
417
-
418
- The bundled `config/seed-manifest.example.yaml` is only an example. Each developer should create a local manifest at
419
- `~/.openviking/seed-manifest.yaml` with `threadnote init-manifest`; repo paths can be anywhere.
420
-
421
- ## Configuration
422
-
423
- Environment variables:
424
-
425
- - `THREADNOTE_HOME`: local state directory, default `~/.openviking`.
426
- - `THREADNOTE_MANIFEST`: seed manifest path. Defaults to `~/.openviking/seed-manifest.yaml` if present, otherwise
427
- the bundled example manifest.
428
- - `THREADNOTE_ACCOUNT`: OpenViking account header/config value, default `local`.
429
- - `THREADNOTE_USER`: OpenViking user value, default local username.
430
- - `THREADNOTE_AGENT_ID`: shared agent identity, default `threadnote`.
431
- - `THREADNOTE_OPENVIKING_VERSION`: package version to install, default `0.3.12`.
432
- - `THREADNOTE_NPM_REGISTRY`: npm registry used by the installer and updater, default `https://registry.npmjs.org/`.
433
- - `THREADNOTE_NO_UPDATE_CHECK`: disables opportunistic update notifications.
434
- - `THREADNOTE_BIN_DIR`: directory for the `threadnote` shim, default `~/.local/bin`.
435
- - `THREADNOTE_COPILOT_MCP_CONFIG`: explicit VS Code/Copilot `mcp.json` path for `mcp-install copilot`.
436
- - `THREADNOTE_HOST`: local bind host, default `127.0.0.1`.
437
- - `THREADNOTE_PORT`: local bind port, default `1933`.
438
-
439
- Local projects using `localhost:80` or `localhost:443` do not conflict with OpenViking on `127.0.0.1:1933`. A conflict
440
- only occurs when another process already owns the same host and port. If that happens, choose a different
441
- `THREADNOTE_PORT`.
442
-
443
- ## Misc
444
-
445
- See `docs/migration.md` for switching an existing repo workflow to `threadnote` without deleting canonical
446
- `AGENTS.md`, `CLAUDE.md`, `.claude/`, or `.agents/` files.
447
-
448
- See `docs/agent-instructions.md` for the user-level agent guidance installed by `threadnote install`.
449
-
450
- ## Recall And Read
451
-
452
- Recall is a search step. It returns candidate `viking://` URIs plus abstracts. Agents should then read or list the
453
- selected URI:
454
-
455
- ```bash
456
- threadnote recall --query "agent context"
457
- threadnote read viking://agent/threadnote/memories/.abstract.md
458
- threadnote list viking://agent/threadnote/memories --all --recursive
459
- ```
460
-
461
- When MCP is installed, the agent should use Threadnote MCP `recall_context`, then `read_context` or `list_context`.
462
- Agents must pass JSON arguments, for example `recall_context({"query":"agent context"})`. For MCP recall queries that
463
- say "current repo" or "this branch", pass the current workspace path as `callerCwd` so Threadnote can resolve branch and
464
- workspace terms without guessing from the MCP server's launch directory. Use `compact_context` for scoped memory hygiene
465
- dry-runs before applying cleanup. Older adapters expose `search`, `read`, and `list` aliases. Before recall/read returns,
466
- Threadnote automatically syncs clean incoming shared memory updates when a
467
- configured share repo is behind; failures are reported as warnings and the local read still continues. The CLI commands
468
- are the fallback path.
@@ -36148,7 +36148,6 @@ function exactMemoryScopes(config2, includeArchived) {
36148
36148
  `${userBase}/durable/projects`,
36149
36149
  `${userBase}/handoffs/active`,
36150
36150
  `${userBase}/incidents/active`,
36151
- `${userBase}/events`,
36152
36151
  `${userBase}/shared`,
36153
36152
  `viking://agent/${uriSegment2(config2.agentId)}/memories`,
36154
36153
  // Seeded project resources live outside the user/memories tree. Include
@@ -36286,8 +36285,8 @@ async function runSharePublishTool(config2, sourceUri, options) {
36286
36285
  `Refusing to publish: ${targetUri} already exists in the shared namespace. Inspect it via threadnote read; if it should be replaced, forget the existing shared copy first.`
36287
36286
  );
36288
36287
  }
36289
- await ensureSharedDirectoryChain(config2, ov, targetUri, false);
36290
- await writeMemoryFile(config2, ov, targetUri, content, "create", false);
36288
+ await ensureSharedDirectoryChain(config2, ov, targetUri, false, { quiet: true });
36289
+ await writeMemoryFile(config2, ov, targetUri, content, "create", false, { quiet: true });
36291
36290
  const messages = [`Published ${sourceUri} -> ${targetUri}`];
36292
36291
  for (const redaction of scrub.redactions) {
36293
36292
  messages.push(`Redacted ${redaction.count}\xD7 ${redaction.name} before publish.`);
@@ -3868,6 +3868,22 @@ async function gitValue(args, cwd = getInvocationCwd()) {
3868
3868
  }
3869
3869
  return result.stdout.trim();
3870
3870
  }
3871
+ async function resolveRepoName(cwd = getInvocationCwd()) {
3872
+ const repoRoot = await gitValue(["rev-parse", "--show-toplevel"], cwd);
3873
+ if (!repoRoot) {
3874
+ return void 0;
3875
+ }
3876
+ const commonDir = await gitValue(["rev-parse", "--git-common-dir"], repoRoot);
3877
+ if (commonDir) {
3878
+ const absoluteCommonDir = (0, import_node_path.isAbsolute)(commonDir) ? commonDir : (0, import_node_path.resolve)(repoRoot, commonDir);
3879
+ const primaryRoot = (0, import_node_path.basename)(absoluteCommonDir) === ".git" ? (0, import_node_path.dirname)(absoluteCommonDir) : absoluteCommonDir;
3880
+ const name = (0, import_node_path.basename)(primaryRoot).replace(/\.git$/, "");
3881
+ if (name && name !== ".") {
3882
+ return name;
3883
+ }
3884
+ }
3885
+ return (0, import_node_path.basename)(repoRoot);
3886
+ }
3871
3887
  async function runInteractive(executable, args) {
3872
3888
  return new Promise((resolvePromise) => {
3873
3889
  const child = (0, import_node_child_process.spawn)(executable, args, { stdio: "inherit" });
@@ -10012,7 +10028,6 @@ function exactMemoryScopes(config, includeArchived) {
10012
10028
  `${userBase}/durable/projects`,
10013
10029
  `${userBase}/handoffs/active`,
10014
10030
  `${userBase}/incidents/active`,
10015
- `${userBase}/events`,
10016
10031
  `${userBase}/shared`,
10017
10032
  `viking://agent/${uriSegment(config.agentId)}/memories`,
10018
10033
  // Seeded project resources (READMEs, AGENTS.md, SKILL.md, docs/**) live
@@ -10315,7 +10330,7 @@ async function buildHandoff(options) {
10315
10330
  const status = await gitValue(["status", "--short"], repoRoot) ?? "";
10316
10331
  const diffStat = await gitValue(["diff", "--stat", "HEAD"], repoRoot) ?? "";
10317
10332
  const touchedFiles = await gitTouchedFiles(repoRoot);
10318
- const repoName = (0, import_node_path6.basename)(repoRoot);
10333
+ const repoName = await resolveRepoName(repoRoot) ?? (0, import_node_path6.basename)(repoRoot);
10319
10334
  const topicBranch = branch && branch !== "unknown" ? branch : "current";
10320
10335
  const metadata = {
10321
10336
  kind: "handoff",
@@ -10644,8 +10659,7 @@ async function hasManagedClaudeHooks() {
10644
10659
  }
10645
10660
  async function runPreCompactHook(config, options = {}) {
10646
10661
  try {
10647
- const repoRoot = await gitValue(["rev-parse", "--show-toplevel"]);
10648
- const project = repoRoot ? (0, import_node_path9.basename)(repoRoot) : "general";
10662
+ const project = await resolveRepoName() ?? "general";
10649
10663
  await runHandoff(config, {
10650
10664
  blockers: "- none recorded",
10651
10665
  dryRun: options.dryRun === true,
@@ -10665,11 +10679,10 @@ async function runPreCompactHook(config, options = {}) {
10665
10679
  }
10666
10680
  async function runSessionStartHook(config, options = {}) {
10667
10681
  try {
10668
- const repoRoot = await gitValue(["rev-parse", "--show-toplevel"]);
10669
- if (!repoRoot) {
10682
+ const project = await resolveRepoName();
10683
+ if (!project) {
10670
10684
  return;
10671
10685
  }
10672
- const project = (0, import_node_path9.basename)(repoRoot);
10673
10686
  await emitUpdateBannerIfOutdated(config);
10674
10687
  process.stdout.write(`## Threadnote \u2014 latest context for ${project}
10675
10688
 
package/docs/index.html CHANGED
@@ -765,6 +765,7 @@
765
765
  <a href="#update" data-label="Update"><span>Update</span></a>
766
766
  <a href="#lifecycle" data-label="Lifecycle"><span>Lifecycle</span></a>
767
767
  <a href="#share" data-label="Share"><span>Share</span></a>
768
+ <a href="#manager" data-label="Web manager"><span>Manager</span></a>
768
769
  <a href="#use-cases" data-label="Use cases"><span>Use cases</span></a>
769
770
  <a href="#close" data-label="Get started"><span>Start</span></a>
770
771
  </nav>
@@ -782,7 +783,7 @@
782
783
  team-shared decisions — recallable from any session, on any agent, in any worktree.
783
784
  </p>
784
785
  <div class="cta-row">
785
- <span class="pill"><span id="version-tag">v0.6.1</span> · local-first · MIT</span>
786
+ <span class="pill"><span id="version-tag">v0.6.1</span> · local-first · GPL-3.0-or-later</span>
786
787
  </div>
787
788
  </div>
788
789
  <div class="scroll-cue">scroll ↓ &nbsp;·&nbsp; <span class="kbd">↓</span> / <span class="kbd">j</span></div>
@@ -1400,10 +1401,72 @@ threadnote remember \
1400
1401
  </div>
1401
1402
  </section>
1402
1403
 
1403
- <!-- 12. USE CASES -->
1404
+ <!-- 12. WEB MANAGER -->
1405
+ <section id="manager" class="slide">
1406
+ <div class="slide-inner">
1407
+ <span class="slide-eyebrow">11 · Web manager</span>
1408
+ <h2>A local web UI for the whole memory store.</h2>
1409
+ <p class="lead">
1410
+ Prefer a UI to the CLI? <code>threadnote manage</code> serves a local React app on
1411
+ <code>127.0.0.1</code> with a per-session token. Browse the tree, edit Markdown, run health checks, and
1412
+ manage shares — everything it does, the CLI and MCP do too.
1413
+ </p>
1414
+
1415
+ <img
1416
+ src="web-manager.png"
1417
+ alt="Threadnote web manager — Health and Doctor view with the memory tree, Memory / Sharing / Health / Tools tabs, and Run Doctor / Start OpenViking / Repair controls"
1418
+ loading="lazy"
1419
+ style="
1420
+ width: 100%;
1421
+ height: auto;
1422
+ display: block;
1423
+ margin-top: 1.5rem;
1424
+ border: 1px solid var(--line);
1425
+ border-radius: var(--radius-lg);
1426
+ "
1427
+ />
1428
+
1429
+ <div class="grid grid-2" style="margin-top: 1.5rem">
1430
+ <div class="card reveal">
1431
+ <span class="card-kicker">Memory</span>
1432
+ <h3>Browse &amp; edit the tree</h3>
1433
+ <p>
1434
+ Resizable, filterable navigation. Markdown preview by default, raw edit on demand, and
1435
+ confirmation-gated bulk archive / publish / forget that never silently targets filtered-out files.
1436
+ </p>
1437
+ </div>
1438
+ <div class="card reveal">
1439
+ <span class="card-kicker">Health</span>
1440
+ <h3>Doctor on open</h3>
1441
+ <p>
1442
+ The default tab runs <code>doctor</code> automatically. Run Doctor, Start OpenViking, and Repair stream
1443
+ into a scrollable output pane — the view in the screenshot above.
1444
+ </p>
1445
+ </div>
1446
+ <div class="card reveal">
1447
+ <span class="card-kicker">Sharing</span>
1448
+ <h3>Team repos, no CLI</h3>
1449
+ <p>
1450
+ Status, publish, sync, rename, set-url, remove, and preserve-local — full parity with
1451
+ <code>threadnote share</code>.
1452
+ </p>
1453
+ </div>
1454
+ <div class="card reveal">
1455
+ <span class="card-kicker">Tools</span>
1456
+ <h3>Recall, compact, consolidate</h3>
1457
+ <p>
1458
+ Recall and read, scoped compaction dry-runs, import/export packs, seeding, and AI-assisted consolidation
1459
+ drafted by a local Codex or Claude CLI then applied on confirm.
1460
+ </p>
1461
+ </div>
1462
+ </div>
1463
+ </div>
1464
+ </section>
1465
+
1466
+ <!-- 13. USE CASES -->
1404
1467
  <section id="use-cases" class="slide">
1405
1468
  <div class="slide-inner">
1406
- <span class="slide-eyebrow">11 · Real-world use cases</span>
1469
+ <span class="slide-eyebrow">12 · Real-world use cases</span>
1407
1470
  <h2>What you say. What the agent does.</h2>
1408
1471
  <p class="lead">
1409
1472
  You don't run threadnote commands yourself. You talk to your agent the way you already do; the agent calls
@@ -1415,7 +1478,7 @@ threadnote remember \
1415
1478
  <div class="v-say">Continue where we left off on this branch.</div>
1416
1479
  <pre class="v-call">recall_context({query: "&lt;branch&gt; latest handoff durable feature memory"})</pre>
1417
1480
  <pre class="v-response">
1418
- → viking://user/you/memories/handoffs/active/&lt;branch&gt;/auto-precompact.md
1481
+ → viking://user/you/memories/handoffs/active/&lt;repo&gt;/auto-precompact.md
1419
1482
  → viking://user/you/memories/durable/projects/&lt;repo&gt;/&lt;feature&gt;.md</pre
1420
1483
  >
1421
1484
  <div class="v-answer">
@@ -1495,10 +1558,10 @@ Stored: viking://user/you/memories/durable/projects/&lt;repo&gt;/release-process
1495
1558
  </div>
1496
1559
  </section>
1497
1560
 
1498
- <!-- 13. CLOSE -->
1561
+ <!-- 14. CLOSE -->
1499
1562
  <section id="close" class="slide">
1500
1563
  <div class="slide-inner">
1501
- <span class="slide-eyebrow">12 · Get started</span>
1564
+ <span class="slide-eyebrow">13 · Get started</span>
1502
1565
  <h2>Try it on your machine in 90 seconds.</h2>
1503
1566
 
1504
1567
  <pre style="margin-top: 1.5rem">
@@ -1522,8 +1585,8 @@ threadnote doctor --dry-run</code></pre>
1522
1585
  </div>
1523
1586
 
1524
1587
  <p class="colophon">
1525
- threadnote · MIT · built on OpenViking 0.3.12 · use <span class="kbd">↑</span> <span class="kbd">↓</span> /
1526
- <span class="kbd">j</span> <span class="kbd">k</span> to navigate
1588
+ threadnote · GPL-3.0-or-later · built on OpenViking 0.3.12 · use <span class="kbd">↑</span>
1589
+ <span class="kbd">↓</span> / <span class="kbd">j</span> <span class="kbd">k</span> to navigate
1527
1590
  </p>
1528
1591
  </div>
1529
1592
  </section>
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threadnote",
3
- "version": "0.7.10",
3
+ "version": "0.7.12",
4
4
  "type": "commonjs",
5
5
  "main": "dist/threadnote.cjs",
6
6
  "description": "Shared local context and handoffs for development agents",