Documentation menu
Compatibility and upgrades
You should be able to install a newer nid over any older release (or over a terminid or pawmux alpha) and carry on: same groups, tasks, notes, sessions, keys and worktrees. This page states what we keep reading, for how long, and how that is tested.
The promise#
Every nid release reads the on-disk state of every earlier release since pawmux 0.1.0-alpha.1, terminid 0.1.0-alpha.10 to alpha.12 included, through 1.0. After 1.0, a release reads the state of at least the two previous minor versions and of every release from the last 12 months, whichever reaches further back. When support for an old format is dropped, the release notes say so one release ahead, and the last release that still reads it stays downloadable so you can step through it.
Upgrading changes state in place (the database schema, file names, keyring entries), so it is one-way:
- Downgrades are not supported. An older release may refuse or misread a database that a
newer one has migrated. To go back, restore the state you had before the upgrade (for terminid
and pawmux,
~/.terminidand~/.pawmuxare left as they were; see Upgrading from terminid).nid update --versionrefuses releases from before nid (older than 0.1.0-alpha.13) for the same reason. - Skipping releases is fine. Migrations are cumulative and idempotent, so alpha.1 straight to the newest release works, and an interrupted upgrade finishes on the next start.
What is kept#
| State | Where | What we promise |
|---|---|---|
| Database | ~/.nid/nid.db (terminid: terminid.db, pawmux: pawmux.db) | Every group, session, task (status, owner, deps, summary), note, lock, message, approval, question and event is migrated to the current schema on first open. Old groups keep their integration branch (terminid/ or pawmux/); land, diff, sync and rm use the stored name. Spend recorded before billing modes existed keeps counting as billed. |
| Running sessions | restart.json, the database | Sessions come back as stopped after a crash or upgrade; nid resume (or daemon restart, or the update itself) continues the same conversations, and claimed tasks stay with their owners. Approvals and questions that were pending when the old daemon died are closed (denied / timed out) instead of hanging. |
daemon.json | ~/ | Only used to find a running daemon. A stale one (crash, reboot) or one from an older release is ignored and replaced; it is never copied between homes. |
| Project config | nid.yaml (also terminid.yaml and pawmux.yaml, deprecated, read with a one-line notice; nid migrate renames them) | Keys keep their meaning. Removed keys are reported as unknown, never silently reinterpreted. |
| User config | ~/ | Same rule as project config. |
| Project memory | ~/ | Read as written by any release since memory was added (pawmux alpha.9). |
| API keys | ~/.nid/secrets, OS keychain / Secret Service, DPAPI files on Windows | Plain and DPAPI files are read in place; keyring entries stored under terminid's or pawmux's service name are copied to nid's (the old ones stay). A key the keyring will not give up yet is retried at every daemon start. |
| Worktrees | ~/ | Moved with their groups (terminid and pawmux homes) and repaired (Git links, paths in the database). |
| Verify stamps | <git common dir>/ | Stamps a terminid or pawmux checkout wrote are still accepted by the publisher. |
| Running agents | the terminid MCP server entry in an agent's config | Agents started before the upgrade keep calling the terminid server until their next spawn; new spawns get nid. |
| Environment | TERMINID_* and PAWMUX_* variables, the terminid and pawmux commands | Still accepted as aliases, with a deprecation notice, until 1.0 (NID_* wins, then TERMINID_*). The commands are shims that forward to nid. |
A terminid or pawmux home is brought over as described in
Upgrading from terminid: the default ~/.terminid (or, for
anyone still on pawmux, ~/.pawmux, directly) is copied into ~/.nid (worktrees are moved);
a home you chose with NID_HOME, TERMINID_HOME or PAWMUX_HOME is upgraded in place.
How it is tested#
packages/ holds a home for every released version,
written by that release's own code: scripts/ extracts each release tag
with git archive into a temporary directory and runs scripts/ against its store,
memory and secrets modules. Each home has two groups, sessions in every state (one mid-turn, as if
the daemon was killed), tasks in every status the release knew (with dependencies and a claim),
notes, locks, delivered and pending messages, pending and resolved approvals and questions,
events, settings, project memory, a stored API key (a fake one) and a stale daemon.json.
Repository paths are placeholders, so the fixtures carry nothing from the machine that made them.
test/ (part of pnpm test) checks every fixture three ways, each on a temporary
copy:
- Store: the current code opens the database and migrates it to exactly the schema a new database has (tables, columns, indexes); every row reads back the same; new tasks, claims and dependency checks work; opening it again changes nothing.
- Migration: a terminid or pawmux home moves to a separate nid home: database, memory and
API keys arrive, the stale
daemon.jsonis left behind, and the old home stays usable. - Daemon:
daemon runstarts on the home (a terminid or pawmux home is upgraded in place), replaces the staledaemon.json, recovers the crashed sessions asstopped, closes what was pending, and the resumed sessions finish the task they had claimed before the upgrade and claim the next one.
The full binary upgrade path (terminid update from a real terminid alpha.12 binary, or
pawmux update from a pawmux alpha, to this build, with a running daemon) is covered separately by pnpm test:migration (see
Development and tests).
After every release#
Add the new release's fixture so the next one is held to it:
git tag --list 'v*' # the new tag must exist locally
pnpm compat:fixtures v0.2.0 # writes test/fixtures/compat/0.2.0/
pnpm --filter nid test # compat.test.ts picks it up
Commit the new directory with the release. Never regenerate the fixtures of older releases unless the seed script itself changes; they are the record of what those releases wrote.
Name history#
The product has been renamed twice. Each rename keeps the old names working for upgrades; this list is the record of what each one changed.
| Release | Rename | What kept working |
|---|---|---|
| 0.1.0-alpha.10 | pawmux -> terminid | pawmux command (shim), PAWMUX_* variables, pawmux.yaml, pawmux/ branches, pawmux-* release assets, ~/.pawmux migrated to ~/.terminid. See Upgrading from pawmux. |
| first nid release | terminid -> nid | terminid and pawmux commands (shims), TERMINID_* and PAWMUX_* variables, terminid.yaml and pawmux.yaml, terminid/ and pawmux/ branches, the terminid MCP server name for agents running at upgrade time, terminid-* and pawmux-* release assets, ~/.terminid (and ~/.pawmux) migrated to ~/.nid. Domains terminid.dev and terminid.com redirect to nid.dev. See Upgrading from terminid. |