Documentation menu
Development and testing
Source checkouts need Node.js 22.13+ for node:sqlite, pnpm, and Git. Run
pnpm install at the root. The source entry is
node packages/; release binaries compile the same CLI with Bun.
| Location | Purpose |
|---|---|
| src/cli | CLI commands and formatting. |
| src/daemon | Orchestration, RPC, integration and agent prompts. |
| src/drivers | Claude, Codex, ACP, PTY and mock drivers. |
| src/dashboard | Local listener and bundled browser UI. |
| src/mcp | Agent coordination tools. |
| test | Unit, end-to-end, browser and optional live tests. |
| scripts | Binary builds, signing and release publication. |
| spikes | Early integration probes. |
See building and releasing for compile targets, signing credentials and local publishing; Daemon API for integration contracts.
Development and tests#
pnpm install
pnpm --filter nid typecheck
pnpm --filter nid test # node:test: unit tests plus e2e suites with mock agents
pnpm --filter nid test:bun # real PTY tests under Bun; PTY tests skip under Node
The end-to-end suites start a real daemon, real nid-mcp servers and real git worktrees in a
temporary NID_HOME, driven by the scripted mock agent (see src/).
Set NID_BIN to a compiled binary to run them against it instead of the sources (CI does this
on Linux, macOS and Windows). Check that it is unset when you mean to test the sources: an
installed nid may have put it in your environment, and the suites then silently test that
binary.
The Node, Bun and browser suites run each file under a process supervisor (test/). It supplies
temporary NID_HOME, TERMINID_HOME and PAWMUX_HOME, journals child launches (including detached
daemon autostarts and MCP grandchildren), and fails with the file name, PID and command
when teardown leaves a process alive. It cleans up those owned processes on failure,
timeout or interruption. Each file has a four-minute deadline (override with
NID; the opt-in migration build uses twenty minutes).
To supervise one file, run node test/ from packages/nid.
Fixtures must still register teardown before starting agents and wait for shutdown;
the supervisor is a final check, not a substitute for teardown. It never kills a process
based only on its name or a scan of the user's home.
Use setupE2E() for a shared daemon, or stopTestDaemon(home) from
test/ in a custom fixture's teardown. Register teardown before
waiting for readiness, so failed startup is covered too. Scratch homes outside the
system temp directory must call registerTestHome(home) before their first launch
so the supervisor can recover a compiled daemon after a test timeout.
For the compiled launch smoke test, run these commands from the repository root
in PowerShell (use the matching dist binary on other platforms):
pnpm build:bin --target native
$env:NID_BIN = (Resolve-Path dist/nid-windows-x64.exe).Path
$env:NID_COMPILED_SMOKE = "1"
node packages/nid/test/run-tests.mjs packages/nid/test/compiled-smoke.test.ts
Remove-Item Env:NID_COMPILED_SMOKE, Env:NID_BIN
This checks init --yes, starts its generated config with a mock agent, forces
compaction through rotate, runs doctor and read-only autostart/uninstall
commands, and checks the embedded dashboard includes setup and context controls.
It isolates the repository, daemon data and user directories, excludes vendor
CLIs from PATH, and answers the release check locally. It does not change the
real installation, login items or user PATH. Without NID,
the test skips.
For the interactive attach --tty smoke test, build a native binary, set NID
to its absolute path, and run pnpm --filter nid test:bun. It starts a disposable daemon and
scripted PTY agent, checks input, Ctrl-C, resize, queued delivery, and Ctrl-] detach. Without that
variable the compiled CLI smoke test skips.
The upgrades to nid have their own end-to-end test with real binaries:
pnpm test:migration builds the last pawmux alpha and the last terminid alpha (v0)
from git history (or copies released ones with --old-pawmux <path> / --old-terminid <path>) and
the native nid target (or uses --dist <dir>), and runs two upgrades in scratch homes against a
local fake release server. First the whole history: a pawmux daemon with mock agents, worktrees
(one held open during the first update), an API key and a pawmux.yaml runs its own
pawmux update to terminid alpha.12, then that terminid's own terminid update to nid. Then a
pawmux-only user runs pawmux update straight to nid. Both check that nid took over: install
moved, PATH updated, old daemon stopped, state and every worktree group migrated (including the one
the pawmux -> terminid move had left behind), the running sessions resumed and working (the stopped
one still stopped), the key readable, the terminid and pawmux shims and an untouched old
terminid binary all reaching the nid daemon, nid doctor green, and nid migrate renaming the
config. It takes a minute or two and never touches your real install, homes, PATH or login items;
--keep leaves the scratch tree for inspection. In pnpm test it skips.
The optional browser smoke suite uses Playwright Chromium and a disposable daemon; the normal test command does not require a browser download:
pnpm --filter nid exec playwright install chromium
pnpm --filter nid test:browser
It skips with installation instructions when Chromium is absent. Set
NID to use an existing compatible Chromium executable, or set
NID to fail instead of skip (the Ubuntu browser CI job does this).
The suite checks browser login, the authenticated API, rejection of foreign-origin
requests, and that the page makes no requests to external hosts. It follows a real mock
agent from overview to transcript, approves its request in the inbox, and sends a chat
message. Additional browser suites cover task/config/group actions, live board updates,
questions, session stop/resume, and 375px layouts.
NID (in packages/nid) runs
a short smoke test against the real codex CLI: a sandboxed write, a denied escalation, the
nid tools, stop + resume, and token counts. It spends a few model tokens; set
NID to pick the model.
More opt-in live suites against real CLIs (each spends a few tokens and uses its own daemon and
NID_HOME; NID dumps events where supported):
Command (in packages/nid) | Checks |
|---|---|
NID | opencode over ACP: system prompt, nid tools, claiming, mid-turn messages, an assigned task end to end, cancel |
NID | the PTY driver against the node REPL and the claude, codex and opencode TUIs (Bun) |
NID | attach --native takeover and hand-back for claude, codex and opencode (NID picks agents) |