Skip to content

Releases: Kashkovsky/threadnote

v0.6.2: cross-agent recall surfaces seeded project resources

22 May 12:11

Choose a tag to compare

Why

Seeded project resources (README, AGENTS.md, CLAUDE.md, SKILL.md, docs/**) were indexed and searchable but agents weren't using them. Two mechanics conspired: the base `ov search` is biased toward memory-shaped vocabulary ("handoff", "durable", "feature memory") so memories ranked 0.54–0.57 vs seeded resources at 0.45–0.47; with small `nodeLimit`s the resources fell off the top of the result set. And `exactMemoryScopes` excluded `viking://resources/` entirely, so exact-term grep never scanned seeded files.

The fix sits at the MCP/CLI recall layer so it works across every agent — Claude, Codex, Cursor, Copilot — not just Claude via its SessionStart hook.

What changed

  • Parallel resource recall. When a `recall_context` query mentions a project name from `~/.openviking/seed-manifest.yaml`, the tool runs a second `ov search` scoped to `viking://resources/repos/` and merges those results into the response alongside the base semantic hits. Seeded guidance is guaranteed to surface regardless of memory-vocab ranking. Honors a caller-pinned `--uri`/`uri` (skips the augmentation) and `--no-infer-scope` on the CLI side.

  • Exact-term grep covers seeded content. `viking://resources/repos` is added to `exactMemoryScopes` in both the CLI's `runRecall` and the MCP server's `exactMemoryMatchesText`, so verbatim matches in seeded READMEs/AGENTS.md/SKILL.md surface alongside personal memory hits.

  • `recall_context` MCP tool description updated to spell out it returns both personal memories and seeded project resources, with the convention "include the repo or project name in the query to make the project-guidance pass fire". The server-level instructions block gains a short pointer at the same convention.

  • Soft instruction files updated (`docs/agent-instructions.md`) so every agent's installed `/.codex/AGENTS.md` / `/.claude/CLAUDE.md` / Cursor / Copilot file learns about seeded resources as a first-class recall target. `threadnote update` calls `repair` which re-applies these — no manual step needed.

Refactor

  • `runRecallTool` (MCP) refactored to take a typed `RecallToolParams` object instead of raw argv, so the skip-when-pinned check operates on validated input rather than `args.includes('--uri')`.
  • `inferProjectFromQuery` moved from `src/memory.ts` to `src/manifest.ts` so both the CLI and the MCP server share the helper without duplicating manifest parsing.
  • `inferRecallUri` no longer scopes the base search to a project's resources subtree when the query mentions a project name (it used to, which inadvertently excluded personal memories). The "skills" intent scoping is preserved.

Upgrade

```bash
threadnote update
```

No data migration. Runtime-only behavior change plus refreshed soft instructions via the `repair` step that `update` already runs.

v0.6.1: SessionStart hook nags about new threadnote versions

20 May 10:44

Choose a tag to compare

SessionStart update banner

Users miss releases because manual `threadnote update` is opt-in and nobody remembers to run it. The agent-side hooks shipped in v0.5.0 already run once per Claude session — extend the SessionStart hook to surface release availability where the agent is paying attention.

The hook now runs a daily-cached check against the npm registry. When the installed version is behind, it prepends a one-line banner above the existing recall header:

```
[threadnote] v0.7.0 available (current v0.6.1). Run: threadnote update
```

  • Cache: `~/.openviking/.update-state.json`, 24h TTL. Within-day session starts are instant; only the first of the day pays the network round-trip (bounded to 3s via `AbortSignal.timeout`).
  • All network and cache I/O is swallowed silently. A flaky registry, no network, or a malformed response never breaks session start — worst case is a missed banner that day.
  • Banner only shows on `SessionStart`, not `PreCompact`. Compaction fires under context pressure; it's not the time for a network call.

Opt-in auto-update

Set `THREADNOTE_AUTO_UPDATE=1` and the same hook spawns `threadnote update --yes` as a detached background process instead of nagging. The hook returns immediately and the new version takes effect on the next session.

```bash

in your shell rc, or per-session

export THREADNOTE_AUTO_UPDATE=1
```

Off by default — a breaking upgrade landing mid-session would surprise users who didn't ask for it.

Fix: `share sync` ALREADY_EXISTS on added files

`share sync` failed with `[ALREADY_EXISTS] File already exists: ...` when a git-`added` file's URI already existed in OpenViking. The most common cause: the publisher's local `share publish` wrote the URI before the corresponding upstream commit landed in this clone (or an earlier `share init` / `sync` already ingested it). The old code only flipped to `--mode replace` for git-`modified` entries; for `added` it always tried `create`, and OV refused.

Write mode is now decided by `vikingResourceExists`, not by git's per-commit-range view of added vs modified. The warning for the "added but already in OV" case is distinct, so the log makes the underlying race visible.

Upgrade

```bash
threadnote update
```

v0.6.0: fix supersedes-self leak; add share publish --preview and --redact

20 May 09:52

Choose a tag to compare

What was broken

threadnote remember --replace <uri> and the MCP remember_context({replaceUri: ...}) baked a supersedes: <uri> line into the body even when the replace URI matched the URI we were about to write to — an in-place update on a stable project + topic URI. The resulting body carried a self-referential supersedes: line. share publish then copied the body verbatim into the shared subtree, putting the bogus pointer into team git history.

Fix

storeMemory (and the MCP writeDurableMemory mirror) now do a two-pass formatting: compute the destination URI first, then drop the supersedes: line when it would point at the URI we're writing. Cross-URI replaces still emit supersedes: for genuine provenance.

share publish and MCP share_publish also strip every supersedes: and archived_from: line from the memory's header block before writing to the shared subtree. These pointers only resolve on the publisher's machine — teammates pull via git and have no way to dereference them — so they were always noise at the publish boundary, and stripping them is defence-in-depth against this class of regression.

New surface on share publish

  • --preview — read the source, apply the header strip + scrubber + redaction in dry mode, print the exact bytes that would land in git, and exit. No writes, no commits, no pushes. Run this before any publish to catch leaks by inspection.
  • --redact — opt-in mode that replaces soft-leak matches with placeholders and continues instead of blocking. New patterns (macOS / linux home paths) are redactable; credentials always block regardless of --redact.

The MCP share_publish tool gained matching preview and redact boolean arguments.

Upgrade

```bash
threadnote update
```

share publish defaults are unchanged; new flags are opt-in.

v0.5.0 — Agent-side hooks for deterministic context handling

19 May 09:37

Choose a tag to compare

The instruction files Threadnote installs (~/.codex/AGENTS.md, ~/.claude/CLAUDE.md, etc.) are the cross-agent guidance floor — they ask agents to recall context and store handoffs, and they work across every supported agent. But they rely on the agent to comply.

This release adds an agent-side hook surface for the deterministic moments where the agent shouldn't have to remember.

What's new

  • threadnote install-hooks <agent> [--apply | --dry-run | --remove] — mirrors mcp-install. Currently rich for Claude Code; Codex / Cursor / Copilot print an explicit "no hook surface available today, sticking with instruction files" message.
  • threadnote install --with-hooks — opts every supported agent in at install time.
  • Two managed Claude hooks:
    • PreCompactthreadnote pre-compact-hook auto-stores a handoff snapshot for the current repo right before Claude compacts the conversation. Stable topic (auto-precompact) so repeated firings replace one file instead of accumulating. Failures are swallowed — a broken hook never blocks compaction.
    • SessionStartthreadnote session-start-hook prints the latest handoff / durable feature memory for the current repo to stdout, so Claude reads it as injected context on the first turn.
  • Marker-fenced settings.json edits — managed entries are tagged \"_threadnote\": \"managed\" so threadnote repair rewrites them non-destructively and threadnote uninstall removes them without touching any hook entries you added yourself.
  • repair re-asserts hooks if the user previously opted in (detected by the presence of managed entries). It never adds them unsolicited.

Why hooks and instructions

The two surfaces solve different problems and are intentionally complementary:

  • Soft instructions are the cross-agent floor. They cover semantic decisions: "is this fact durable enough to remember?", "is this memory teammate-worthy?", "is this recall relevant to the user's prompt?" Hooks can't make those calls.
  • Hooks are the deterministic safety net. They cover moments where the agent shouldn't be trusted to remember — like flushing a handoff right before compaction wipes the conversation arc.

Replacing one with the other gives up the strengths of whichever you drop.

Try it

threadnote update
threadnote install-hooks claude --dry-run    # preview
threadnote install-hooks claude --apply      # install managed entries

# Or opt every supported agent in at install time:
threadnote install --with-hooks

See the new "Agent hooks" section in the README for the full breakdown.

v0.4.1 — Offer to install uv on a fresh PEP 668 setup

18 May 16:02

Choose a tag to compare

Smooths the first-run experience for developers on macOS/modern Linux where the default python3 is externally managed (Homebrew, system Python, etc.) and pip install --user is refused under PEP 668.

When you run threadnote install and neither uv nor pipx is on PATH, threadnote now offers to install uv for you (the recommended, isolated Python tool installer):

  • Prefers brew install uv when Homebrew is available.
  • Falls back to the official install script: curl -LsSf https://astral.sh/uv/install.sh | sh.
  • Re-detects after install and uses uv to install OpenViking. If the new binary didn't land on the current shell's PATH, prints a clear "open a new shell and re-run" hint.

The prompt only fires when:

  • you didn't pass --package-manager explicitly, and
  • stdin/stdout are a TTY (so CI and scripted installs keep working — they continue to surface the same warning + fall through to pip instead of hanging).

Pass -n at the prompt to skip the install and proceed with pip (you may then hit the PEP 668 error).

v0.4.0 — Share durable memories across the team

18 May 13:25

Choose a tag to compare

A new threadnote share workflow lets engineers publish curated durable memories to a team git repo so teammates' agents can recall them. Personal handoffs, preferences, and unpublished durables stay local by construction — only memories you explicitly publish leave your machine.

What's new

  • threadnote share CLI: init, status, sync, publish, unpublish, list, remove.
  • share_publish MCP tool for agents (Codex / Claude / Cursor / Copilot) — same destructive-publish flow over stdio MCP.
  • Recall covers the shared subtree: recall_context and the exact-grep pass both surface viking://user/<you>/memories/shared/<team>/... alongside personal scopes.
  • Built-in scrubber refuses publishes that match PEM private keys, sk-…, classic GitHub tokens, GitHub fine-grained PATs (github_pat_…), GitLab PATs (glpat-…), HTTP Bearer …, bare JWTs (eyJ…), AWS access keys (AKIA…), and Slack tokens (xox[abcdeprs]).
  • Transactional publish: if removing the personal copy after the shared write fails (transient OV error), the shared write is rolled back so the system never stays half-published.
  • Concurrent-publish safe: writeOvFileWithRetry snapshots the URI's existence before the first write so a teammate's parallel publish to the same URI cannot be silently overwritten on retry.
  • Self-healing .gitignore for OV-generated **/.abstract.md and **/.overview.md so sync's auto-commit never picks them up.
  • Pull-conflict messaging that works under non-English locales and the --separate-git-dir layout (filesystem checks against the team's real gitdir).

Layout per machine

  • Working tree at ~/.openviking/data/viking/<account>/user/<you>/memories/shared/<team>/.
  • Gitdir at ~/.openviking/share/teams/<team>.gitdir/ (separated via git clone --separate-git-dir, so OpenViking never sees git internals).
  • Team registry at ~/.openviking/share/teams.json (mode 0600).

Get started

# Create the shared repo on GitHub/GitLab/etc. and copy its SSH URL.
threadnote share init git@github.com:org/team-memories.git
threadnote share publish viking://user/<you>/memories/durable/projects/<project>/<topic>.md
threadnote share sync           # pull teammates' updates and reindex into local OV

See docs/share.md in the repo for the full workflow, conflict resolution, and the publish-time scrubber rules.

Docs

  • docs/share.md (new) — full workflow and conventions.
  • docs/agent-instructions.md — when agents should publish vs keep local; how to call share_publish over MCP.
  • README.md — pointer to the new commands.

v0.3.8

15 May 08:33

Choose a tag to compare

Highlights

  • Clarified the branch feature-memory workflow in installed agent guidance.
  • Agents now explicitly recall durable feature memories after branch handoffs before coding.
  • Agents now maintain durable feature knowledge separately from handoff state as valuable implementation details, decisions, interfaces, and gotchas emerge.
  • README and migration docs now describe the two-record model: durable feature memory for lasting knowledge, active handoff for current status and next steps.

Upgrade Notes

  • Run threadnote update to refresh the package.
  • Run threadnote install or threadnote repair after updating so user-level agent instructions are refreshed.

v0.3.7

13 May 11:12

Choose a tag to compare

Highlights

  • Added lifecycle-aware memory storage that separates current durable knowledge from historical handoff trails.
  • Added archive and migrate-lifecycle commands for moving old handoffs into archived lifecycle paths.
  • Added packaged post-update migrations so threadnote update can explain and optionally run memory cleanup after upgrading.
  • Made migration handling idempotent: reruns reuse existing archived copies and clean up remaining legacy sources.
  • Updated user-level agent instructions and README guidance for durable memories, handoffs, replacement, archival, and update migrations.

Upgrade Notes

  • threadnote update now runs repair --no-post-update followed by the new package's post-update migration prompt.
  • Older updaters that only run repair will still surface applicable post-update migration instructions.
  • Use threadnote update --yes for unattended local migrations, or threadnote update --no-post-update to skip them.

threadnote v0.3.6

11 May 16:09

Choose a tag to compare

What's Changed

  • Added --replace <uri> to threadnote remember and threadnote handoff so active issue state can be updated without accumulating duplicate progress memories.
  • Added replaceUri support to the MCP remember_context tool; the old memory is forgotten only after the replacement memory is stored successfully.
  • Added supersedes: metadata to replacement memories and handoffs for auditability.
  • Updated the README and installed agent instructions to recommend one current-state memory per active issue, and documented the role split between Threadnote and CLAUDE.md/AGENTS.md.

threadnote v0.3.5

11 May 11:50

Choose a tag to compare

What's Changed

  • Fresh installs now start and health-check OpenViking by default, so setup fails early with a log pointer instead of leaving users to hit MCP ECONNREFUSED 127.0.0.1:1933 later.
  • Added threadnote install --no-start for CI/manual setup flows that should not start the local server.
  • Changed the default Python installer preference to uv, then pipx, then pip, so fresh installs use uv --native-tls and pip-system-certs when available.
  • Kept MCP registration explicit while updating README, migration, troubleshooting, and installer next-step docs for the new install flow.