The project & task engine for AI agents

A reliable memory for every AI assistant.

nexus-flow is an agent-native, offline-first engine for projects and tasks. It keeps track of what exists, what depends on what, and what to work on next — instant locally, convergent when it syncs.

$ curl -fsSL https://nxf.nxsflow.com/install.sh | sh
macOS · Linux · single static binary · no sudoSource on GitHub

In the terminal

No dashboard required. Your agent asks; the engine answers — deterministically.

nxf — agent session
$ nxf next0001  P1  open  [epic]  Payments revamp0002  P1  open  [feature]  Design new checkout flow    ↳ 0001 · Payments revamp$ nxf blocked0003  P2  open  [chore]  Migrate billing webhooks    ↳ blocked by: 0002 (open)$ nxf next --json[{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Rework the payments stack for v2.","design":null,"due":null,"id":"ab12.0001","parent":null,"priority":"1","priority_label":"P1","status":"open","title":"Payments revamp","type":"epic","type_label":"epic"},{"archived":null,"assignee":null,"belongs_to":"ab12.0001","closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"One-page checkout with saved cards.","design":null,"due":null,"id":"ab12.0002","parent":{"id":"ab12.0001","title":"Payments revamp","type":"epic","type_label":"epic"},"priority":"1","priority_label":"P1","status":"open","title":"Design new checkout flow","type":"feature","type_label":"feature"}]$ 

Real output. ready and next are computed from the dependency graph on every call — never stored, never stale. Every command takes --json.

What it does

One engine, four parts. Everything opinionated lives in plugins on top.

01

A data model built for real work

Projects and tasks with dependencies on both levels, belongs-to and contributes-to relations, due and defer dates, and an append-only history with a closing comment. Strong enough to model how work actually connects — and nothing more.

02

ready, blocked, next — computed, not stored

What's workable is derived deterministically from the converged state on every query, including invariant repair after merges. The answer to “what should I work on next?” can never drift out of date.

03

A CLI agents can rely on

Machine-readable --json on every command, deterministic output, millisecond cold start. Agent ergonomics is the measuring stick — your assistant reads state in one call instead of scraping a web UI.

04

Offline-first sync that converges

Local SQLite is the working copy; changes merge through a purpose-built CRDT, so replicas converge without conflicts by construction. The relay server is open source and self-hostable.

What's new

Version 0.27.0

July 14, 2026

Added

  • More --json reads now carry the same additive fields the primary reads already do, for cross-verb agent consistency: blocked and search gain priority_label/type_label, next's nested parent join gains type_label, and blocked/deferred/closed/archived plus prime now carry the sparse plugin custom field map (identical to list/next/show). Canonical fields are unchanged; all additions are additive and appear only where relevant.

Changed

  • nxs mcp serve with no --workspace/--db now defaults its auto-initialized board to a neutral, nxs-owned location (com.nxsflow.nxs under the platform data dir) instead of a specific consumer app's data home. The OSS server no longer assumes any consumer; a consumer that wants its own board installs its own --workspace-pinned MCP entry (and may import this board's data). If you relied on the previous default location, point the entry at it explicitly with --workspace.

Version 0.26.0

July 13, 2026

Added

  • nxf show, list, and next --json now carry additive priority_label and type_label fields — the active plugin's display labels (e.g. P2, epic) — alongside the canonical priority/type keys, so an agent no longer needs a separate schema lookup to render them. create and update now also accept the canonical ordinal priority key (e.g. 2) in addition to the label (P2), so a value read back from --json round-trips as valid input. The canonical priority/type keys, the human (non---json) output, and the embedding/MCP record are all unchanged.

Changed

  • The "no embedded minisign public key" error from nxs self-update and nxf verify-signature is now actionable: it explains that the binary is unsigned (a locally-built or development build) and points to the official signed-release install (curl -fsSL https://nxf.nxsflow.com/install.sh | sh), instead of referencing an internal spec document that isn't shipped with the binary. The fail-closed refusal itself is unchanged.

Fixed

  • Piping CLI output into a reader that closes early (nxf blocked | head, nxf list | grep -m1 …) no longer panics with "failed printing to stdout: Broken pipe". The process now terminates quietly on SIGPIPE like any other Unix filter, so agent scripts that page or truncate output stay clean.

Version 0.25.1

July 13, 2026

Added

  • Plugins can now declare their own custom item fields on top of the 16 built-in ones. A plugin declares them in a [fields] table (each with a type — text/longtext/date/enum — an optional on type scope, required, and a display label); you then set them with nxf create/nxf update --set <name>=<value> (type-validated; an empty value clears). They surface everywhere reads do: nxf schema --json lists each declared field (marked custom, with its kind/on/required/label, and values for an enum), and nxf show/list/next --json attach a sparse custom map with the item's set values (a field that is unset — or belongs to a different plugin — is simply omitted). The MCP flow_schema/flow_show/flow_list/flow_next tools carry the identical shape. nxf show's human view also prints declared custom fields under their label. This replaces overloading labels/description for domain data (a file's uri, a person's email, a project's stage).

Fixed

  • Plugin custom fields follow-ups (post-v0.25.0 review): nxf create --json - now accepts custom fields via a set array in the JSON payload (mirroring the --set flag), so an item whose type has a required custom field can be created from a JSON payload too — previously that path silently dropped custom fields. The "custom field does not apply to this type" error now also lists the type(s) the field applies to, so an agent can self-correct without a schema round-trip.

Version 0.24.2

July 12, 2026

Fixed

  • Opening a freshly-created workspace database from two connections at once — e.g. nxs init / `nxf init` over an existing workspace (or an E4 sync reset) while a long-lived app is watching it — no longer intermittently fails with "duplicate column name: domain". The schema migration now runs under a write lock, so concurrent openers serialize instead of both applying the same ALTER.
  • The "your first move" suggestion after nxs init / nxf init now names a type the active plugin actually declares (e.g. epic for issue-tracker, project for personal-todo), so the copy-pasted first command works. Previously it hardcoded --type task, which no bundled plugin accepts — the very first suggested command errored on a stock install.
  • The ready lane (next) is dramatically faster on larger boards. Resolving the ready set no longer issues one query per item — each of which re-materialised the parent projection, making the lane O(n·edges) — it now bulk-resolves in a single query. On a ~156-item board this cuts read::next from ~0.7 s to well under 100 ms, speeding every board refresh and session start (nxf next, nxs prime).

Version 0.24.1

July 12, 2026

Added

  • Added a bulk labels read to the embedding API — Engine::labels_bulk(ids) (and read::labels_bulk, Store::labels_of_bulk) — that returns the present labels for many items in a single indexed query instead of one labels(id) call per item. Decorating a whole lane (the app-bridge with_labels seam) now costs one query rather than N. The list/next --json label projection uses it internally, so those lane reads collapse their per-row label lookups to one bulk read while the output stays byte-identical. The existing labels(id) is unchanged; the new method is additive and backward-compatible.
  • nexus-chat now gates its nxc CLI/onboarding surface behind a default-on cli Cargo feature. An embedding consumer that links only nexus_chat::engine::Engine can build with default-features = false and drop the whole CLI/TUI dependency closure — clap, nxs-ui (and its inquire/crossterm), nxs-init, inventory, sha2 — leaving just the engine/facade/store/model/watch surface over the shared substrate. The nxs binary and nxc are unchanged (the feature is on by default).

Fixed

  • The nxc inbox (and the inbox section of nxc prime) now displays unread messages in deterministic causal order. Following the message-ordering fix, the inbox's own display order was still keyed on the raw ULID message_id, so two unread messages posted in the same millisecond could show in an arbitrary, per-database order. It now orders by the CRDT clock (lamport, site, message_id) — the same guarantee the channel, thread and search reads already give — while the unread cursor keeps its own message_id watermark unchanged.
  • Chat messages now read back in a deterministic, causal order. Reads (channel history, thread assembly, search, and the M2 review board) are ordered by the CRDT clock `(lamport, site, message_id) instead of the raw message_id. A message_id is m-`+ULID (a millisecond timestamp plus random bits), so two messages posted in the same millisecond — an ask opener and its first reply, or a rapid send/reply burst — previously sorted by ULID randomness, i.e. in an arbitrary, per-database order. Lamport is the substrate's logical clock (a reply's op is emitted after the request it answers), so the read order now always matches post order and is reproducible across runs and across sites/merges.

Version 0.23.1

July 11, 2026

Added

  • nexus-chat (`nxc`) is now discoverable and set up through the suite. nxc — agent-to-agent messaging — joins the nxs init chooser and, once active, the single SessionStart fan-out: `nxs prime` now catches an agent up on its entire unread inbox (both "act now" and "next session" messages) at the start of each session. nxc init sets chat up in a workspace and wires the one nxs prime hook (joining an existing flow/memory workspace without adding a second hook), and `nxc agent-manifest` exposes chat's session contract as data. The suite cross-sell now runs in every direction — setting up flow or memory points you at chat, and setting up chat points you at flow and memory. Coordinate agents through nxc instead of ad-hoc notes.
  • nexus-chat (`nxc`) messages now travel across your machines. With the M1 messaging substrate complete, an agent-to-agent message posted in one workspace reaches an agent on another machine after nxs sync — messages ride the same offline-first sync as your tasks and durable memory, no extra service. The three engines share one .nxs/ workspace while staying fully independent: your projects (flow) and memory are byte-for-byte unaffected by chat traffic, and every message carries a globally unique id so agents keep the same reference to it on every machine.
  • nexus-chat now embeds in apps. A new in-process app-facade (nexus_chat::engine::Engine) lets a frontend read channels, inbox, messages and threads, send/reply/mark-read, and subscribe to change notifications through one long-lived handle — no nxc subprocess. It derives identically to the nxc CLI and returns the same errors/rejections (proven by an App↔CLI parity test), and channel reads carry per-channel unread counts in two queries regardless of channel count.
  • MCP hosts can now discover the active plugin's item types and their containment roles. A new flow_schema MCP tool reports the valid item types, which of them are containers (and each type's allowed parents, parent cardinality, and the hierarchy depth limit), and the create/update field model — so an agent driving a board over MCP learns what to create without guessing. nxf schema gains the same information as an additive hierarchy block, and both surfaces now render from one shared record (facade::read::schema) so they cannot drift.
  • When every requested reviewer has replied, the thread's opener is now woken: nxc inbox and the nxs prime catch-up surface a "Threads you opened" block with the completed board and its replies (and a note when a board is past its deadline but still waiting). Your own sent messages no longer show up in your own unread.
  • nxc ask opens a review board in one step — post a request, declare who must reply, and set an optional deadline. nxc threads list/show render the reply quorum (who has replied, who is still outstanding, whether the board is complete), and nxc threads expect re-declares the reviewer set to unstick a board waiting on a non-responder.
  • Applications embedding nexus-chat can now read the reply quorum through the in-process engine, not just the CLI: a bulk read returns the per-reviewer state for a whole set of boards at once (for a coordination-UI quorum bar, no N+1), a single board in full, and the opener's completed/overdue wake — all identical to what nxc reports. The subscribe change feed lets the UI re-read the quorum and surface "complete"/"past deadline" transitions live.

Changed

  • Large boards read much faster. next, list, and show now use covering indexes for the per-item labels, notes, and dependency lookups they run once per row, instead of scanning the whole projection table on every call. A 159-item board lane that took ~2.0s to decorate now renders in ~0.6s, and the gain grows with board size. Applied automatically on the next workspace open — no migration step.
  • nexus-chat app-facade refinements. Channel reads are now genuinely a fixed two SQLite queries regardless of channel count (the member-list read was collapsed from a per-channel loop into a single query). Store reads now surface database errors as a structured io error instead of panicking the embedded engine. And send/reply take named-field request structs (SendRequest/ReplyRequest) instead of a long positional argument list, so callers can't transpose same-typed arguments.

Fixed

  • `nxs init` now works for the chat module on a real install. The nxc persona symlink was never created by the production install paths (install.sh and nxs self-update) — only by in-tree dev builds — so a fresh install would fail with "is nxc installed?" when setting up chat. All three personas (nxf, nxm, nxc) are now linked on install and self-update, and a regression test pins the full set so a future persona can't silently repeat the gap.

Version 0.17.0

July 7, 2026

Added

  • nxs prime and nxf guide now teach the defer-vs-wait convention: defer an item only for a real calendar date, and model waiting on an external delivery as an open WAIT: chore your items depend on (closed, with the delivered version, to release the chain). A new guide topic nxf guide deferring-and-waiting walks through it with a worked example.

Fixed

  • The facade Engine embedding handle now exposes user-labels (h89s), which v0.16.0 shipped but wired only for the CLI/MCP/migration paths: label_add, label_remove, labels, a with_label filter, and label-bearing reads show_value / list_value / next_value (labels ride as a sparse labels key, matching the CLI/MCP JSON). The priority write contract is clarified and documented: create/update take the plugin label (P0..P4) — the form schema advertises — not the read-form ordinal reads emit; a consumer that stores the ordinal translates it to the label at its own seam.

Version 0.16.0

July 6, 2026

Added

  • Items can now carry user labels — free-text tags, distinct from the plugin's display type — across every layer. Attach and detach them with nxf label add/remove <id> <label> and read them with nxf label list <id>; labels appear in the --json of show, list, and next, and list/next accept a --label <tag> filter. Labels ride their own observed-remove OR-set, so concurrent edits converge like dependencies do (re-adding the same label leaves one; a remove only detaches what it observed). The same tools are exposed over MCP as flow_label_add, flow_label_remove, and flow_label_list. The bundled beads → nexus-flow migration now carries a ticket's beads labels into this OR-set.
  • Plugins can now declare a per-field merge strategy in their schema — a new optional [merge] table maps a field to lww, crdt-text, or or-set, so how concurrent edits to a field are reconciled is a declarative choice rather than a hardcoded rule. The bundled issue-tracker and personal-todo plugins are unchanged: every field stays last-writer-wins. crdt-text is reserved for the upcoming collaborative note body and folds last-writer-wins until the text-CRDT reducer lands, so declaring it today is safe and lossless.

Changed

  • setup claude is now a first-class umbrella verb: nxs setup claude is the canonical command, and nxf setup claude delegates to it. Host integration belongs to the umbrella because the wired SessionStart hook is nxs prime. Both surfaces behave identically — same --json output, same workspace resolution — and there is now a single implementation, so the two can never drift.
  • The managed nexus-flow block written into AGENTS.md/CLAUDE.md now opens with a Markdown header (## nexus-flow tools for agents), so the pointer reads as its own section instead of a bare stray sentence.
  • The flow plugin set is now assembled from a compile-time registry instead of a hardcoded list, so a consumer can supply its own plugin by linking a crate that registers one — the plugin's definition never has to live in this repository. A duplicate plugin name across registered crates is rejected loudly (never resolved by link-order chance), and a single bad third-party plugin surfaces as an error rather than aborting the whole tool. The two bundled plugins (issue-tracker, personal-todo) are unchanged. Facade API: available() is now fallible (returns a Result), and the PLUGIN_NAMES constant is deprecated in favour of a registry-driven plugin_names() function (kept one release as a migration window).

Fixed

  • nxs init and setup claude now bring back a deleted AGENTS.md. Previously, re-running nxs init in a workspace where every selected tool was already set up did nothing (the file assembly was tied to setting a tool up for the first time), and setup claude only wired the session hook — so a removed AGENTS.md stayed gone. Both now (re)assemble the shared agent files on every run, idempotently, and refresh the managed pointer in an existing CLAUDE.md (a CLAUDE.md is never created).
  • The beads → nexus-flow migration (nxs init --from-beads) no longer silently drops a ticket's defer and due dates. A ticket deferred in beads (defer_until) now migrates into the deferred lane with its date intact — nxf deferred lists it and it stays out of nxf next until then — and a due date (due_at) is carried over as well. Previously both fields were discarded during import, so a deferred ticket landed as plain open work with no date.
  • The beads → nexus-flow migration (nxs init --from-beads) now validates a ticket's defer_until and due dates before carrying them over: a malformed value is skipped and reported under a new warnings list in the migration report, rather than being written verbatim. Because the deferred and ready lanes compare these dates as text, a malformed date would otherwise have silently and permanently misclassified an item's lane. Labels that fail validation are likewise reported under warnings instead of the (edges-only) skipped list.

Version 0.14.1

July 3, 2026

Fixed

  • Fixed the @nexus-flow/mcp npx runner so the documented host-config form npx -y @nexus-flow/mcp -- --workspace <path> works. npx forwards the -- separator into the shim's arguments, which previously reached the server as nxs mcp serve -- --workspace <path> and was rejected ("unexpected argument '--workspace'"). The shim now drops a single leading --, so the workspace and other flags reach the server correctly. The no-flags form (`npx -y @nexus-flow/mcp`, the shared default workspace) was unaffected.

Version 0.14.0

July 3, 2026

Added

  • nxs mcp serve — a Model Context Protocol server (read-only, over stdio) for MCP-native hosts like Claude Desktop. It exposes the flow read tools flow_next, flow_show, and flow_list against the same shared .nxs/ workspace the CLI uses, so a tool result is the same canonical record as nxf <command> --json. On connect it sends static usage guidance (workflow rules + the tool reference + a "call flow_next first" nudge) as the session's instructions; the live ready set comes from the tools. Shipped on by default; build with --no-default-features to omit it.
  • Closing a parent now warns about the children it silently sweeps away (epic 07a). Because a closed parent masks a still-open child into the closed lane without writing to it, the closer could not see what they caused — especially for a child shared across several containers. nxf close (and the flow_close MCP tool) now report it: a human warning line, and under --json a swept_children field listing each swept child with its title and its other parents (id + status), so you can tell whether the child still hangs somewhere open and re-open or follow up if it still has a reason to exist. The children's own status is never changed.
  • The MCP server now exposes the rest of flow's read surface as tools, completing the read seam: flow_blocked (blocked items with the open blockers holding each one up), flow_search (lane-ranked substring search over title/description/design/DoD/notes, with the same status/type and archive filters as the CLI), flow_note_list (an item's worklog notes), and flow_mention_list (the short-ids an item cites). Each is a thin shell over the same read compute the nxf CLI uses, so its structuredContent is byte-identical to nxf blocked, nxf search, nxf note list, and nxf mention list under --json, and each carries machine-readable read-only annotations. An id-addressed list on a missing item is a not_found tool error, matching the CLI. (flow_next already covers the ready set, so it is not part of this slice.) The facade gains additive read::notes / read::mentions helpers (plus their *_to_value renderers) that the CLI and the MCP seam now share.
  • The MCP server now exposes the rest of flow's write surface as tools, completing the write seam: a contributes-to edge via flow_contributes_add / flow_contributes_remove (n:m, never blocks), and the batch archive operations flow_archive / flow_unarchive. Each runs through the same shared write layer as the nxf CLI, so its receipt is byte-identical to nxf contributes …, nxf archive, and nxf unarchive under --json, with now and actor explicit per call. The archive tools are partial batches: a root that fails its precondition (e.g. archiving an item that is not closed) is reported in the receipt's per-root results with a reason code — never an error — exactly like the CLI. Each tool carries machine-readable annotations (read-only false; destructive/idempotent per op) so strict hosts can badge it correctly.
  • The MCP server now exposes flow's write operations as tools, so MCP-native hosts (Claude Desktop, Claude Cowork, …) can change the board, not just read it: flow_create, flow_update, flow_claim, flow_close, flow_dep_add/flow_dep_remove, flow_mention_add/ flow_mention_remove, and flow_note_add. Each tool runs through the same shared write layer as the nxf CLI, so its result is byte-identical to nxf <command> --json, and each advertises accurate machine-readable annotations (readOnlyHint: false plus per-operation destructive/idempotent hints) so a host can badge and guard mutations correctly. A new nxs mcp serve --actor <id> flag (or NXS_ACTOR) sets the default author recorded on writes, and any tool call may override it per write with its own actor — so a long-lived, host-started server attributes each change instead of writing everything under one identity.
  • New command nxs mcp install registers this nxs binary as an MCP server in your installed hosts' config, so MCP-native apps (Claude Desktop, Cursor, Windsurf) can reach it without nxs being on their PATH. It writes an idempotent mcpServers.nxs entry naming the absolute path of the running binary plus mcp serve, preserving every other server and setting already in the file (the write is atomic, so an interrupted run can never truncate your config). With no flags it scans the known hosts and patches each one that is installed; a re-run whose entry already matches changes nothing, and a single corrupt or unreadable host config is reported and skipped instead of aborting the others. Pass --host <id> (repeatable: claude-desktop | cursor | windsurf) to target a specific host even if it isn't auto-detected, and --workspace <path> to pin a project workspace in the entry (omit it and the server serves its per-user default workspace). --json prints the per-host result (written / unchanged / skipped / error).
  • nxs mcp install can now set up the workspace in the same command that registers the server. Pass --setup (or just --plugin <id>, which implies it) and it also materializes the flow board the server will open — so one command both registers nxs in your MCP hosts and creates the board, finishing the one-command onboarding. The plugin defaults to personal-todo (the everyday to-do board); pass --plugin issue-tracker for the coding case. The server stays plugin-agnostic and reads the choice from the workspace's config.toml. The board is created at exactly the directory the server resolves, so setup and the server never point at two different boards: with no --workspace it lands at the per-user default workspace and the host entry stays flag-less; with --workspace <path> it lands there and that path is pinned in the entry. Setup is idempotent and never overwrites an existing board, and an unknown --plugin fails loudly before anything is created. --json reports the seated plugin and the board location under a new setup field.
  • The MCP server now exposes the memory engine as tools, so MCP-native hosts (Claude Desktop, Claude Cowork, …) can read and write durable agent memories alongside the flow board: memory_list, memory_search, memory_show, memory_add, memory_update, and memory_close. The memory tools are fanned out over the active modules — they appear only when the served workspace has the memory module active (after nxm init), so a flow-only workspace never shows them. Each tool runs through the same shared memory facade as the nxm CLI, so its result is byte-identical to `nxm <command> --json, and each advertises accurate machine-readable annotations (read tools readOnlyHint: true`; write tools readOnlyHint: false with per-operation destructive/idempotent hints). When memory is active, the connect-time usage instructions also nudge the host to call memory_list at the start of a session to load durable facts, alongside flow_next.
  • You can now run the nexus-flow MCP server on a machine where nxs is not installed at all. A new npm runner shim, @nexus-flow/mcp, lets a host config launch the server with npx -y @nexus-flow/mcp -- --workspace <path>: it fetches the signed nxs prebuilt for your platform, verifies it (sha256 and minisign — a tampered, unsigned, or wrong-key download aborts before anything runs, with no insecure fallback), caches it, and execs nxs mcp serve. The first launch downloads and verifies (a few seconds); later launches use the cache and start instantly, even offline. To write this portable entry, run nxs mcp install --runner npx (the default, --runner native, still writes the absolute-path entry for an already-installed nxs).
  • New "Connect an MCP host" guide — as a /docs portal page and as nxf guide mcp — covering how to connect Claude Desktop, Cursor, and Windsurf to nexus-flow. It gives copy-paste config snippets for both entry styles: the zero-install npx @nexus-flow/mcp runner (works before nxs is installed) and the direct entry written by nxs mcp install. It also documents both bootstrap paths (the signed install.sh one-liner and the npx runner), how to choose the workspace the server opens (the shared default, a pinned --workspace, or a per-tool override), and the fail-closed signature verification behind every fetch.
  • Every nxs mcp serve tool now accepts an optional workspace argument that overrides the server's launch-pinned workspace for that one call — so a single running server can drive several boards without a registry. Omit it (or pass an empty string) and the tool resolves the launch default (the per-user App-Data-Home workspace, or the --workspace the server was started with), exactly as before. Pass a path and that call reads/writes the .nxs/ board there instead. The store is opened per call, so the override is just a different resolution root. Resolution walks up from the path (as the CLI does), so a path with no .nxs/ in itself or any parent returns a no_workspace error on that tool result (run nxs init there) and leaves the server serving its launch board — it is not a start-up failure.

Changed

  • nxs mcp serve now works out of the box without --workspace: it auto-initializes and serves a stable per-user default workspace (macOS ~/Library/Application Support/it.nexflow.app/.nxs/, Linux XDG, Windows %APPDATA%), so an MCP host like Claude Desktop — which has no useful working directory — always resolves to one consistent board. --db/NXS_DB and --workspace/NXS_WORKSPACE still take precedence; the server no longer guesses a workspace from the current directory.
  • nxf search now groups every matching item by its effective lane, so a child suppressed or masked by its parents no longer vanishes from the results (epic 07a). A child hidden under a blocked ancestor now appears in the blocked group, one under a deferred ancestor in the deferred group, and a still-open child whose parents are all closed in the closed group — each still showing its own stored status, only its grouping shifts. nxf list and nxf next (and the matching flow_list / flow_next MCP tools and the embed Engine) now also carry the parent_closed_reason join — already on nxf show — for such a closed-masked child, so an agent enumerating the board sees *why* an item looks closed (every closed parent and its closing reason) without a follow-up lookup. An in-progress child of a not-yet-started (ready) parent is grouped as ready rather than over-stating progress; its stored status is left unchanged.
  • Claiming an item now marks its parent chain in progress too (epic 07a, "claim-up"). When you claim a child (nxf claim, flow_claim, or the embed Engine::claim), every still-open ancestor up the full parent chain — all parents, transitively — is flipped to in_progress, so a container reflects that work has started inside it. A closed ancestor is left closed (a child's claim never revives a deliberately-closed container) and an already-in-progress one is unchanged. And nxf next/nxf ready (and the embed Engine) now **suppress a child whose parent chain holds a blocked or deferred ancestor**: if any ancestor is waiting (blocked by an open dependency or deferred into the future), its descendants drop out of the ready/next recommendation until that ancestor can proceed — so you are not pointed at work nested under a container that cannot start. A related closed-mask also lands: a still-open child whose parents are all closed drops out of ready/next too (it is effectively closed via its containers), and nxf show on such a child now carries a parent_closed_reason field listing each closed parent and its closing comment — so you can see *why* an open item looks finished and decide whether to re-open it. The child's own stored status is never rewritten. These are the first slices of the parent↔child status-coupling model (docs/specs/07a-parent-child-status-coupling.md), in which parent becomes a gating containment edge while contributes_to stays the non-gating escape hatch.
  • nxf prime (and the MCP session instructions) now teach the deliberate choice between the two containment edges (epic 07a): parent is gating — a child rests when its container rests, so a deferred, blocked, or closed parent propagates down and hides or masks the child — while contributes_to is the non-gating association for "belongs here, contributes there". A single worked one-liner makes the distinction concrete, so agents don't over-constrain a board and silently hide work.
  • nxs prime / nxm prime now states the memory rule far more emphatically. The line is marked CRITICAL, uses a NEVER-style imperative against writing a MEMORY.md (or any other ad-hoc memory file), and spells out the consequence: nxs never reads such a file, so it is never replayed at session start and that knowledge is silently lost. The message makes clear that nxm remember is the one durable channel for project knowledge (conventions, gotchas, decisions) — reuse a stable --key to evolve a fact in place. Earlier wording was too soft and agents kept creating MEMORY.md files whose contents never survived to the next session.
  • The flow and memory store read paths are now fault-tolerant: a real database error (e.g. SQLITE_BUSY past the busy-timeout, or a malformed row) is surfaced as a structured io error instead of panicking. Previously the list-shaped reads .unwrap()-ed the SQLite result, so a db failure unwound the caller — acceptable for a one-shot CLI, but in the long-lived nxs mcp serve stdio server a read tool (memory_list/memory_search, flow_list/flow_show) could unwind its handler. The flow facade reads (list, blocked, closed, archived, search, prime, undeclared_types) and the embedding Engine reads (list/blocked/closed/archived, and memory's memories) now return a Result, and a db error maps to the io kind at the store boundary. Memory's recall/get also no longer swallow a db error into a misleading not_found — only a genuinely absent key is not_found, a db failure is io. This is a backward-incompatible change to the crates/facade public read API (a minor break).

Fixed

  • Workspaces created before the plugin type system could hold legacy item types (project/task) that the active plugin no longer declares — those items displayed their raw type and could not take parent edges, with no supported way to repair them. type is now settable via the retype primitive nxf update <id> --set type=<declared> (validated against the active plugin's types, with the relationship edges re-checked), and nxf prime now shows a non-silent hint at session start when a workspace holds undeclared item types (suggested map: project→epic, task→feature).
  • The legacy-type repair (nxf update <id> --set type=) now migrates a workspace whose *entire* hierarchy predates the plugin type system. Previously the retype re-validated both the item's parent and child edges strictly, so on an all-legacy project/task board neither end could be retyped — the child was blocked by its still-legacy parent and the parent by its still-legacy child (a deadlock, nothing repairable). The retype now skips an edge whose other end is still an undeclared legacy type, so the board migrates item by item, in any order.
  • The MCP server's connect-time instructions no longer name tools that don't exist. Workflow rules that reference write commands with no read-only tool (claim, close, note, mention) are now kept as plain CLI references instead of being rewritten into invented flow_* tool names; only commands backed by a real tool (e.g. flow_next) render as tool names. Every tool the instructions mention is now guaranteed to appear in the server's tool list.
  • nxf schema now spells out the exact create --json payload key and value form for every field, so an agent building a payload no longer has to trial-and-error against deny_unknown_fields. Three create keys deliberately follow the CLI flags and diverge from the read/show --json/update --set spelling — dod/defer/parent for completion_criterion/defer_until/belongs_to — and priority on create is a named label (P0P4), not the read-form ordinal. Each field now reports create_json_key (and priority its create_json_values) under nxf schema --json and in the human view, and a payload keyed with the canonical name gets a targeted pointer (e.g. "use 'dod', not 'completion_criterion' — see nxf schema") instead of the bare "unknown field" list. The accepted payload contract is unchanged (still strict) — it is now discoverable. Consumers embedding the engine: your create payloads are unaffected; if you surface a create form to agents, read the exact keys from nxf schema --json.
  • The long-lived MCP/embed server no longer crashes when the database hiccups during a derivation or a parent-edge write check. Following the store-read hardening, the derivation layer (next, ready, deferred, blocked, search, prime) and the write-time parent-validation walk (the cycle, cardinality, and depth checks on create/update --parent) now surface a transient database error — a busy lock, a corrupted read — as a structured io error instead of panicking the handler, exactly like the dependency-cycle check already did. Reading nxf over a shared workspace, or calling the tools from a host, is now robust to a momentary contended database.
  • The last parent-edge reads on the long-lived MCP/embed server no longer crash when the database hiccups. Completing the store-read hardening, the effective-lane display joins (show/list/next closed-mask reasons, the close receipt's swept-children warning, and search's lane grouping), the claim-up walk (claim propagating in-progress up the parent chain), and the retype revalidation (update --set type=…) now surface a transient database error as a structured io error instead of panicking the handler. A single-item lookup that hits a genuine database fault now also reports it as io rather than a misleading "not found". Working over a shared workspace, or driving the tools from a host, is now robust to a momentarily contended database on every read path.
  • The MCP server's read tools now work with strict hosts such as Claude Desktop and Claude Cowork. flow_list and flow_next previously returned a top-level JSON array as structuredContent, which strict hosts reject as a missing result — they now return a JSON object with the item list under items. All three read tools (flow_next, flow_show, flow_list) additionally advertise machine-readable readOnlyHint: true / openWorldHint: false annotations, so hosts can recognize, badge, and auto-approve them as safe, closed-domain reads.

Removed

  • The retired ready verb is now gone from every public surface. ready folded into next back in C4 — nxf next is the ranked ready set, and nxf next --include-in-progress also surfaces claimed work. The CLI migration stub is removed, so nxf ready is simply an unrecognized subcommand now (the MCP server never exposed it). Embedding apps: Engine::ready(now) and the read::ready helper are removed from the facade API — call Engine::next(now, false) for the same ready set. The internal derivation the recommendation is built from is unchanged; only the redundant ready-named surface is retired.

Version 0.10.0

June 26, 2026

Added

  • nxs init (and nxf/nxm init) now detect a project that still uses beads and offer to migrate it to nexus-flow. On consent it backs up all beads data (bd export --all, kept — never deleted), imports the tickets into flow (title, description, type, priority, status, parent/dependency edges via id-remapping, and closing reasons — with original timestamps preserved) and the bd remember memories into nxm (keys preserved), then rolls back beads' managed config (the BEADS INTEGRATION block in AGENTS.md/CLAUDE.md and the bd prime hooks) and wires up nxs — leaving any hand-written prose untouched. Consent is mandatory: a terminal asks first; --json/non-interactive runs never migrate without the explicit --from-beads flag, and report a dry-run preview instead. nxs doctor now also flags leftover beads config (a half-finished migration) so it can be cleaned up.
  • nxf create -q (alias --id-only) prints just the new item's id on a single line — no JSON, no output framing — so it can be captured straight into the next command (id=$(nxf create "..." -q)) without parsing JSON. Given together with --json, -q takes precedence (the id wins; --json is ignored, not an error). nxf prime points agents at this capture pattern and notes that --jq is a gh idiom that does not exist here.
  • A parent edge that would create a cycle over the parent relation (the target already reaches the source through its parents) is now rejected at write time with a loud cycle error and nothing is persisted — the parent analogue of the existing dependency-cycle guard. Re-pointing an item under one of its own descendants is therefore refused at the source instead of producing an invalid hierarchy.
  • Durable agent memory (nxm) is now embeddable in-process by host applications, mirroring the issue tracker's embedding API. A long-lived Engine handle owns the shared workspace + store for the app's lifetime and exposes the memory verbs (recall/list/search + remember/forget) returning the canonical record as a value, plus subscribe for live notification of external writes — so a host (e.g. a Tauri desktop app) reads and writes memory directly, without spawning nxm. The embedding surface is byte-for-byte identical to the nxm --json CLI over the same store (proven by a differential test) and carries a documented, versioned stability contract.

Changed

  • The CLI now shows item ids by their bare suffix for local items — the 4-char replica prefix, identical across every local item, is dropped as noise — and keeps the full <prefix>.<suffix> only for foreign items synced in from another replica. Bare ids are accepted as input too: nxf show 0001 resolves against your own prefix, while a full id (local or foreign) is taken as-is. --json, the engine, and embedding apps are unchanged — they always emit and accept the full id, so machine output and references stay stable. The --json msg of dep/mention/contributes now reports the resolved (canonical full) ids regardless of the input form. nxf prime now names your prefix and the convention. The facade gains backward-compatible display_id/resolve_id helpers (and matching Replica methods); existing callers need no changes.
  • The nxs/nxf init onboarding is now one calm, consistently branded manufakt-Forge moment. The nxf init plugin step uses the same shared arrow-key chooser as the suite tool picker (no more bespoke numbered stdin prompt). Ember is applied more sparingly — it marks only the cursor, while a selection is shown by weight, so a multi-select no longer reads as a wall of red. The welcome box has a calmer rhythm: generous whitespace, padding rows, and the title aligned flush with the body. Each tool now shows richer "learn more" decision-help in the picker. AGENTS.md is reduced from per-module blocks to a single discovery pointer ("run nxs prime …") naming the active tools; existing workspaces are migrated to it automatically on the next init. All non-interactive paths (--json, pipes, non-TTY) stay byte-stable.
  • The interactive nxs/nxf init onboarding gets more breathing room: two blank lines below the welcome box and below the "what each tool does" panel, a blank line between the "Which tools…?" question and the options, two blank lines before the final "nexus-flow is set up" summary and before its "your first move" call-to-action, and a trailing blank line so the shell prompt isn't glued to the last line. Purely visual; non-interactive (--json, pipes, non-TTY) output is unchanged.
  • Item types are now validated against the active plugin's declared type set instead of a fixed core project|task enum. The core is type-agnostic: it stores whatever type string an item is given, and the active plugin decides which types are valid. For the bundled issue-tracker and personal-todo plugins the accepted types and the --json record are unchanged; an unknown --type is still a loud validation error (now listing the active plugin's own types). This is the foundation for the plugin-configurable type system (E3).
  • Hierarchy parenthood now lives in the conflict-free edge set instead of a single-parent register, making the data model n:m-capable underneath (the CLI still enforces a single parent for now). This is a breaking schema upgrade: a workspace opened once by this version is migrated automatically and losslessly — existing parent links are preserved — but can no longer be opened by an older nxs/nxf build, so upgrade every machine that shares a workspace. The --json record and the parent/belongs_to fields are unchanged.
  • Parent validation is now driven by a plugin relationship matrix (allowed parent→child type pairs, parent cardinality per type, and a depth limit) enforced at write time, instead of the hardcoded "a parent must be a project, and only one" rule. The bundled issue-tracker and personal-todo plugins behave exactly as before — single parent, parent must be a project — so this is invisible in day-to-day use; only the wording of the rejection message changed. It's the foundation for plugins declaring their own hierarchy shapes (e.g. multi-parent), which a later change wires up.
  • Each bundled plugin now declares its own type system in a [types] table — the full set of item types, which parent→child pairs are allowed, how many parents each type may have, and a hierarchy depth limit — all enforced when you write, none hardcoded in the core. issue-tracker now offers epic, bug, feature, chore, decision: an epic is the only container, and every other type takes at most one epic parent (or none). personal-todo offers project, todo, termin, where a todo or termin may belong to any number of projects. That single-vs-many parent difference is now real behaviour, not just a label. Item types are stored under their declared names, so --json reports e.g. feature/todo instead of the former core task/project. Creating an item with a type the active plugin doesn't declare, attaching a parent the rules don't allow, or nesting deeper than the plugin permits is rejected with a clear validation error. Facade: PluginConfig gains a types field and the matrix module gains the [types] shape (type list + per-type cardinality, including "many").
  • The next recommendation ranking is now fully declarative — no precedence is hardcoded in the engine. A ranking key can express an enum-index precedence list (a value's position in the list is its rank), alongside the existing field keys. issue-tracker uses this to add type precedence: within a priority band, ready work now orders epic → bug → decision → feature → chore. The previously hardcoded "claimed work first" tier is now the leading status precedence key both bundled plugins declare, so behaviour is unchanged but the rule lives in the config, not in code. The full issue-tracker order is now status → priority → type → due → id; personal-todo stays field-based (no type ranking). The deterministic id tiebreaker and --json order are unchanged. Facade: RankKey gains a precedence field.
  • Hardening and clarity follow-ups on the E3 type system. When an item cannot have a parent, the rejection now self-explains — distinguishing a top-level type from one the active plugin doesn't declare (cross-plugin / synced data) — instead of an opaque "allowed parent types: (none)". A ranking key that combines a type/status precedence list with dir/nulls is now rejected loudly at config load (a precedence key orders by list position and ignores dir/nulls) rather than silently dropping them. Internally, the hierarchy-depth check is now linear on wide merged parent graphs instead of exponential, and an id carrying the internal edge separator is rejected at the write boundary rather than silently producing an edge that never materializes. The facade gains a RankSpec::validate method; existing callers need no changes.

Version 0.8.0

June 25, 2026

Added

  • nxf init now wires agent onboarding into the project: it writes a managed, clearly-marked nexus-flow block into AGENTS.md (created or augmented in place, idempotent) that points agents at nxf prime. If a CLAUDE.md is present it gains an @AGENTS.md import at the top; when both files already existed beforehand (likely duplicated content) the block is inlined into CLAUDE.md instead, avoiding a double-up. No SessionStart hook is required.
  • New command nxf setup claude wires Claude Code host integration into .claude/settings.json: a SessionStart hook that runs nxf prime so project context is injected automatically at the start of every session, plus an nxf permission allowlist entry so its commands don't prompt. It is idempotent and merge-only — existing hooks, permissions, and other keys are preserved, and a second run changes nothing. This is the deterministic counterpart to the declarative AGENTS.md block written by nxf init (which stays tool-agnostic); the hook is what makes session-start priming reliable rather than best-effort.
  • New nxf schema command: a machine-readable (--json) description of the active plugin's full field model — its types, statuses, and priority variants, and for every field its plugin label, whether it is required on create, whether it is settable via update --set, and how it is set (flag / alias). This is the agent-ergonomic answer to "what do create and update accept in this workspace", introspectable at runtime — which a static, compile-time --help cannot be. create --help and update --help now point to it, and nxf prime lists it.
  • New nxf contributes command exposes the n:m contributes-to relation the core already modeled: contributes add <from> <to>, contributes remove <from> <to>, and contributes list <id>. Like a mention it never blocks (it is not a dependency and never appears in blocked); both endpoints must exist. nxf show <id> now lists the contributes-to edges separately from deps — as a CONTRIBUTES TO line in the human view and a contributes_to array under --json.
  • nexus-flow now offers a programmatic, in-process engine API for embedding applications (UI / business logic — not agents): the nexus-flow-facade crate. Instead of spawning the nxf CLI per call, an app holds a single long-lived engine handle for its whole lifetime — it opens and owns the local workspace + store, reads the derivation (ready/blocked/next/show/list/prime), applies mutations (create/update/claim/close, dependencies, notes) with the same op-log-CRDT convergence as the CLI, and subscribes to file-based change notifications to react when another writer (the CLI agent, the MCP server, or sync) commits to the same store. The surface is a deliberate, versioned library contract (docs/specs/E5-embedding-host-api.md). No new semantics — the embed API, the CLI, and the MCP seam share one core and never diverge.
  • Escaping-free, agent-native input for the long-text fields (description, design, definition of done, and the closing comment) on nxf create, nxf update, nxf close and nxf note add. No more shell-quoting multi-line prose full of backticks, quotes or !. Three sources, resolved at one shared seam: (1) the - STDIN sentinel — a flag value of - reads that field from STDIN (cat design.md | nxf create … --design -, nxf update <id> --set description=-, nxf close <id> --reason -, nxf note add <id> -), stored verbatim; (2) file flags — --description-file / --design-file / --dod-file / --reason-file and nxf update --set-file field=path (UTF-8, verbatim, several files in one call); (3) a whole JSON payload over STDIN — <json> | nxf create --json - and nxf update <id> --json - write every field as one piped object. Each field takes exactly one source (a double assignment is rejected) and at most one field per call may read STDIN; every rejection happens before any write, so nothing is partially written. The JSON and file paths reuse the same validation as the flag path — no second code path, no divergence.
  • New command nxf agent-manifest emits nxf's declared contribution to the shared agent files (the AGENTS.md/CLAUDE.md section, the prime command, and the SessionStart hook) as data. It needs no workspace and is plugin-agnostic; --json is the machine contract. This is the Manifest contract (spec §6.2): each nxs module declares its agent-file contribution as data so the platform can assemble the shared files from it, rather than each tool writing them directly.
  • New platform umbrella binary `nxs` with its first, foundation-only verbs over the one shared .nxs/ workspace: nxs migrate raises the shared db to the current foundation schema version (the explicit CI/repair lever — auto-migrate-on-open stays the default — and reports the from → to transition, refusing fail-loud a db a newer nxs marked incompatible), and nxs doctor (alias nxs status) prints a cross-module diagnosis: the active modules, the schema version and this binary's standing against it (current/degraded/incompatible), the replica identity, whether a sync stream is bound, the op count, and a db integrity check. --json everywhere is deterministic. These run regardless of which products are active — nxs knows only the suite roster (which products exist and their binaries), never any product's vocabulary.
  • Per-module init now points you at the rest of the suite. After nxf init or nxm init, when a tool you haven't set up is still available, an interactive run shows a short call-to-action to add it with nxs init, and --json carries a new additive advertisement field whose copy tells the agent to make you aware of the value — but to set nothing up without your explicit permission. Only tools that can actually be added are advertised, so the nudge disappears once everything is active. No existing field or behavior changes.
  • New command `nxs init` — the suite's primary first-encounter. It asks which tools to set up in the workspace (an arrow-key multi-select, with the issue tracker recommended), then fans out to each module's own init and frames the whole result: the shared agent files are assembled and the single nxs prime SessionStart hook is wired. The umbrella owns the entire visible output — modules are set up silently, so no sub-init noise ever bleeds through. For agents and scripts it is non-interactive: nxs init --module flow --module memory (or --json) sets up the same state with no prompt.
  • New product nexus-memory (binary nxm) — agent-native, offline-first persistent project memory on the shared nxs foundation. Curate durable knowledge (conventions, gotchas, architecture decisions) as keyed text facts: nxm remember "<fact>" [--key <key>] (a stable key updates in place; without one, a content-hash key dedups byte-identical facts), nxm recall <key>, nxm memories [<search>], and nxm forget <key> (a reversible tombstone — a later remember revives it). nxm prime is the session bootstrap that replays every memory into context and states the rule that durable knowledge lives only in nxm remember, never a MEMORY.md. nxm init wires it up (a managed AGENTS.md/CLAUDE.md block + a SessionStart hook), the same contract nxf follows. Memory shares one .nxs/ workspace, op-log, and sync with flow, so facts synchronize across machines instead of being trapped per-repo; --json everywhere is deterministic.
  • nxf init now warns when it finds an orphaned legacy .nexusflow/ directory — one with a db.sqlite but no replica.toml, the trace of an init that crashed before it finished. Such a directory is not migrated automatically (it has no replica identity to carry over), so the warning points it out before a fresh .nxs/ is created, rather than silently leaving the old data stranded one directory over.
  • New command `nxs prime` — the session-bootstrap fan-out that the single SessionStart hook runs. It calls the prime of each *active* module (in registry order) with one shared now, so every module sees the same instant, and concatenates the results. Only the modules set up in the workspace appear: a flow-only workspace yields exactly flow's prime; memory's joins after nxm init. --json (each module's own prime record nested under its key) and the human form are both deterministic and byte-stable, so the hook output never churns. nxs reaches each module by running its standalone binary (nxf prime, nxm prime), not by linking it.
  • nxf next and the next block of nxf prime now show a child item's parent resolved, not just its raw belongs_to id — so a child no longer reads as a top-level item. In --json each record gains an additive parent object {id, title, type} (the raw core type, never a plugin label), or parent: null when there is no parent. In the human views a child gets an indented ↳ <parent-id> · <title> follow-up line. Parent resolution is live-only: a belongs_to pointing at a deleted/missing item resolves to null while the raw id is preserved. The generic item record (show/list) is unchanged — the parent join is attached only in the next/prime projection — and ranking order is untouched.
  • nxm import migrates an existing Claude-host memory store into nexus-memory. nxm prime forbids a MEMORY.md (durable knowledge lives only in nxm remember); this is the on-ramp that makes the rule a doorway instead of a dead end. It reads Claude Code's per-project memory directory (a MEMORY.md index plus one frontmatter file per fact) and brings each fact in under its frontmatter name: as a stable key — so a re-run upserts in place (idempotent, no duplicates) and the source files are never modified (non-destructive). nxm init now detects such a store and surfaces a one-line suggestion to run nxm import (no noise when there is none); the import itself is a separate, explicit verb. nxm import [--from <dir>] auto-detects this project's Claude memory directory, or takes an explicit path; --json is non-interactive and returns a deterministic count of what was imported.
  • New archive and unarchive verbs move work in and out of the archive. archive <ids…> cascades DOWN: a root and its whole belongs_to subtree are archived together, but only when the root is closed and every descendant is closed (an already-archived descendant counts as closed) — an open epic with closed children must be closed first. unarchive <ids…> cascades UP only: an item and its ancestor chain resurface so the item can become visible again, while its children and siblings stay archived (making something visible is deterministic). Both are partial batches — atomic per root (a root that fails its precondition writes nothing of its subtree) and independent between roots — and both report a per-root outcome (archived/unarchived or failed with a reason: not-found, not-closed, has-open-descendants, not-archived) plus the full list of ids actually moved, including the cascaded ones. Archiving is reversible, which is why an archived item is still resolvable via show.
  • Items now carry an archived tombstone — a nullable timestamp (the archive instant), modelled exactly like the existing deleted tombstone with convergent LWW semantics and surfaced as a new archived field on every --json item record. Archiving means "closed and put away": the enumerating reads (ready/blocked/next/list/search) exclude archived items by default, but an explicit show <id> still resolves an archived item and renders an ARCHIVED marker (unlike a deleted item, which stays not_found) — because it is reversible. This is the data-model foundation; the archive/unarchive verbs and the dedicated archived lane land in follow-up work. The workspace schema moves from v1 to v2 with a backward-readable, additive migration (the column is nullable, so older binaries keep opening the database — the compatibility floor is unchanged).
  • Three new read verbs complete the lane set so the read verbs partition the live board cleanly: deferred (open, unblocked work whose defer date is still in the future — the lane that is neither ready nor blocked, ordered soonest-first), closed (closed work excluding archived, newest close first), and archived (archived items of any status, newest archive first). Together with next and blocked these guarantee a clean partition of the live board across six lanes — ready ⊎ blocked ⊎ deferred ⊎ in_progress ⊎ closed ⊎ archived — so a consumer reads each lane directly instead of reconstructing engine-owned derivation. The in_progress lane has no dedicated verb: it is the raw status=in_progress set, read via list --status in_progress (next --include-in-progress is a workflow view that surfaces only the *actionable* in-progress subset alongside ready, not the whole lane). Every lane verb honours the --sort override from the ordering axis. Closing an item now also records a closed_at instant (a new field on every --json item record, alongside archived) so the closed lane can order by close-date; reopening an item (claim, or a status change away from closed) clears it again, so the field is present exactly when an item is closed. The workspace schema moves from v2 to v3 with the same backward-readable, additive migration (the column is nullable, so older binaries keep opening the database).
  • Ordering is now its own axis: every list-style read verb (list, next, blocked) takes an optional --sort override — --sort rank (the active plugin's next ranking policy) or --sort id (lexicographic, plugin-independent). An unknown key is a loud validation error that names the accepted set. The orderer lives in the shared facade, so the CLI and in-process consumers see the identical order. Per-verb defaults are unchanged where they were already sensible (next ranks, list stays id-ordered so list --json remains byte-identical across plugins); --sort lets you pick the other order on demand.

Changed

  • nxf prime and the related help texts now give first-time agents more context: prime leads with a one-line statement of what nxf is and how ready/blocked/next are derived, its create example uses the active plugin's own type vocabulary (e.g. --type <epic|issue> under issue-tracker, <list|todo> under personal-todo), and its dep entry spells out the dependency direction (A depends on B, so B blocks A). The create --type and dep command help were clarified to match. --json output stays deterministic.
  • The managed nexus-flow block that nxf init writes into AGENTS.md is now declarative with a recovery hint, instead of an imperative instruction. It states what nexus-flow is and that the project status comes from nxf prime (which runs automatically at session start where the SessionStart hook is set up via nxf setup claude), and tells the agent to re-run nxf prime after a context compaction to recover state. An instruction in a checked-in file is followed only intermittently; the deterministic delivery is the hook, and this block now complements it and covers hosts without hook support. The vocabulary is generic (projects and tasks).
  • nxf show and nxf blocked now explain blockers instead of just listing ids. show annotates every dependency with its target's status (e.g. deps: abc (closed), def (open)), so the open blocker is obvious at a glance; under --json, deps becomes structured entries ({"id","status"}). blocked now names each item's open blockers inline — human output appends ↳ blocked by: <id> (<status>), and --json adds a blockers array (id + status) to each entry. No more follow-up show per dependency just to learn why something is blocked.
  • The human list views (nxf ready, nxf next, nxf list) now show each item's type in square brackets, in the active plugin's vocabulary — [epic]/[issue] under issue-tracker, [project]/[todo] under personal-todo — so you can tell an epic from an issue at a glance. The column order is plugin-driven, and --json is unchanged (it keeps the canonical core type). Fixed: the personal-todo plugin now labels a project as "project" instead of the incorrect "list".
  • nxf prime is reshaped to orient an agent in one read. Its opening sentence is now plugin-determined ("nexus-flow is a software issue tracker for epics and issues …") instead of generic positioning prose, and the derivation sentence names priority and leads with next. The bare ready id list is replaced by the real next recommendation — the top 7 in full nxf next format (id, priority, status, type, title), with in-progress work first; --json returns next as canonical records plus a next_total so truncation is never hidden. The blocked section now explains *why* each item is blocked and surfaces leverage: each open blocker is shown with its status and how many items it blocks (↳ blocked by <id> (open, blocks 3)), highest-leverage first; --json carries structured blockers with blocks_count. A new create section shows a full, plugin-aware example with --priority and recommends always setting one (items without a priority rank last in next). The command reference is reordered by importance (next before ready), with create reduced to a pointer to its section.
  • nxf next now surfaces work you have already claimed: actionable in_progress items appear in the recommendation and are ranked above every not-yet-started open item, so an agent never loses sight of what it is in the middle of. Blocked or deferred claimed work is still excluded, and nxf ready is unchanged — it keeps showing only startable, not-yet-claimed work, so two agents never both treat the same item as free.
  • Priority is now a named variant of the active plugin instead of a bare integer. nxf create --priority and nxf update --set priority=… take a label (e.g. P0P4 under issue-tracker, now/soon/later/… under personal-todo), validated against the plugin's set; an unknown value is rejected with a validation error that lists the accepted labels. next ranking respects the plugin's variant order, and show/list display the label. The canonical --json record keeps the plugin-independent ordinal, so it stays byte-identical across plugins.
  • nxf create now builds a complete item in a single call. Title, description, and priority are required (a missing one fails loudly), and the same call may set the design, the definition of done (--dod), a parent, and one or more dependencies (--depends-on <id>, repeatable — each makes the new item depend on <id>, which must exist). Previously only --parent/--priority/--due/--defer were available at creation and an item was always born without a body or description, forcing a second update call. Dependency targets and the parent are existence-checked before anything is written.
  • nxf update now reaches the full field model. The longtext fields description and design are settable via --set (e.g. --set description="…"), --set parent=<id> now aliases to belongs_to (the same word create --parent uses; previously only defer was aliased and parent silently failed), and an unknown --set field is rejected with the settable set listed in the error so an agent self-corrects. The body keeps its dedicated full-replace path (--body/--body-file).
  • nxf prime and update --help now teach the stabilization convention: correct an item's fields once shortly after creating it (e.g. to fold in a review), then keep the fields stable and record what you learn while working as append-only notes (nxf note add) rather than further field edits. This is a convention for now — a future release may enforce it with an irreversible per-field lock.
  • nxf show now renders the full field model in the active plugin's language, not a subset. The human layout is a header (<id> <priority> <title>), the inline TYPE/STATUS (and PARENT/BLOCKED BY only when they apply), then the DESCRIPTION, DEFINITION OF DONE, DESIGN, and NOTES sections — with notes newest-first. The section headings are plugin-named: issue-tracker prints Description / Definition of Done / Design / Notes; personal-todo prints Why / Done when / Plan / Log. --json is unchanged — it remains the byte-exact, plugin-independent machine contract and already carries every field.
  • nxf close <id> now requires a --reason: closing is the only way an item leaves the board (no hard delete), so the reason is mandatory. Closing without one is rejected with a validation error in the standard error envelope (also under --json), and nothing is written. It records the "so this is how we closed it" half of the intent-vs-outcome pair you learn from later.
  • `nxf prime` is reshaped into a complete, bd-style session-bootstrap document — and `prime --json` now mirrors it 1:1. The human (non---json) output is valid, structured Markdown: an # nexus-flow title, a Context Recovery note, Core Rules (led by "track all work in nexus-flow"), the ranked Next and leverage-aware Blocked sections, a Create section (with Epic 95d's escaping-free long-text input: --description -, --description-file, nxf create --json -), grouped Essential Commands, Common Workflows recipes, a Sync section that appears only when the workspace is bound to a stream (.nexusflow/sync.toml), and a hybrid Session close bracket (note unfinished work, close with a reason, sync when bound, plus a non-prescriptive "commit & push if version-controlled" reminder — no git commands copied from other trackers). prime --json is now a lean, structured view of the same record: next carries only the displayed fields (id, type, status, priority, title) in canonical form instead of every ticket field — full records stay on nxf next --json — and the new sections are mirrored as fields (context_recovery, grouped commands, workflows, session_close; create.long_text_hint; sync only when bound). This changes the prime --json shape (the facade read::prime / Engine::prime now take a bound flag); nxf next/show/list --json are unchanged.
  • The workspace config.toml moved to the shared platform shape (spec §7): a generic active_modules list owned by the platform foundation, plus per-product config sections. flow's plugin selection now lives under a [flow] section (plugin = "...") and flow — not the foundation — owns the issue-tracker default. Existing workspaces are unaffected: a legacy top-level plugin = "..." is still read, so nothing needs migrating.
  • nxf init and nxm init no longer write the shared agent files or their own per-tool hook themselves. They now delegate to the one nxs assembler, which assembles AGENTS.md/CLAUDE.md from every active module's manifest and wires a single SessionStart hook → nxs prime — the umbrella fan-out that runs each active module's prime with one shared clock. So a flow-only workspace gets exactly one nxs prime hook, and running nxm init afterwards re-assembles both modules' blocks under that same one hook instead of leaving a second nxm prime hook. nxf setup claude and the bundled hooks/session-start.sh wrapper wire nxs prime too. Both inits gain a --quiet mode (no banner/prompt, structured output) so the umbrella can drive them and agents have a non-interactive entry. nxf prime/nxm prime still exist unchanged — they are the fan-out targets the hook dispatches to.
  • Sync moved from `nxf` to the `nxs` umbrella. With one shared op-log per workspace, syncing is a platform operation, not a flow-module one — so the verb is now `nxs sync bind` / `nxs sync run`, and nxf sync has been removed. The behavior is unchanged; only the command you type moves. Scripts that called nxf sync … must switch to nxs sync ….
  • `nxs migrate` now raises a pre-umbrella (v0.5.x) workspace to the v0.6.0 model, idempotently: it rewrites a legacy nxf prime SessionStart hook to the single umbrella hook nxs prime, and registers flow as an active module so nxs prime fans out to it as before. A workspace already on the umbrella is left untouched, and nxs migrate never wires a hook where you set none up. Existing workspaces upgrade their hook on the next nxs migrate.
  • The workspace directory was renamed from .nexusflow/ to .nxs/ — the on-disk home belongs to the platform, not to flow alone, ahead of the shared nxs substrate.
  • blocked now ranks by the active plugin's next policy by default, instead of listing in id order. Blocked work is real work waiting to start, so the highest-priority blocked item surfaces first — the same ordering next already uses. Pass --sort id to restore the previous lexicographic order.
  • search now returns results grouped by lane priority instead of an arbitrary order. Matches are ordered next + in-progress → blocked → deferred → closed, each group in its natural in-lane order; because the lanes partition the live board, every match appears in exactly one group with no duplicates. Selection is unchanged (a case-insensitive substring over title, description, design, definition-of-done, and notes). Archived items are excluded by default; --include-archived appends the archived group last and --archived-only searches only the archive. A --sort override flattens the grouping into one flat order, and --now sets the defer boundary used to group deferred matches. The ranking is now computed engine-side as a shared facade method, so the CLI and in-process consumers share one lane-ranked implementation.
  • Release notes now carry a dedicated Facade Contract section. A changelog fragment can flag a change to the nexus-flow-facade public API with facade: changed or facade: breaking and mark a security fix with security: true; the feed renders these in a dedicated, machine-readable section (EN+DE) so an embedding consumer can tell at a glance whether a release needs a facade re-review or can be fast-tracked on the patch lane. A facade: breaking change is, by construction, only ever shipped in a minor — a patch release that carries one is rejected.
  • The nexus-flow CLI suite now installs as a SINGLE binary. nxs contains the whole suite and the nxf and nxm commands are lightweight symlinks to it — each still works exactly as before (it knows which tool you meant from how you invoked it). install.sh and self-update deliver and update this one binary and (re)create the nxf/nxm links automatically, so the suite takes far less disk space and there is only one artifact to verify, update, and trust. There is no change to any command's behaviour or output; an existing install is migrated to the single-binary layout on its next self-update.
  • The nxs umbrella is now the single front door for the two suite-wide verbs. nxs prime is the one session-bootstrap command you and your agent run: every prompt, help text, and the assembled CLAUDE.md/AGENTS.md now point there instead of the per-tool nxf prime/nxm prime. nxs self-update becomes the canonical, suite-wide updater (it already swapped the whole suite — the verb now matches). The per-tool nxf prime, nxm prime, and nxf self-update still work exactly as before but are hidden from --help and deprecated, and a nxf self-update run now nudges you to nxs self-update. Nothing about the update or single-binary mechanics changed — only which verb is the advertised entry point.
  • Setting up the suite is now clearer about what is already there and what to do next. Re-running init in an existing workspace recognises the tools that are already active: the interactive chooser pre-checks and marks them "(already set up)", the summary flags them in its per-tool list, and nxs init --json reports them in a new already_active field — so a re-run is informative instead of a silent, ambiguous repeat. When you set up flow (the default), the frame now ends with a prominent, copy-paste first command to create your first item, and the welcome box carries each chosen tool's own short pitch. Non-interactive output stays byte-stable: the --json record only gains the additive already_active field, and the welcome copy and first-command prompt appear on the human path only.
  • When you set up the suite interactively — through nxs init, nxf init, or nxm init — each tool you pick now runs its OWN interactive configuration inside the shared frame. In particular, flow's plugin chooser (issue-tracker vs personal-todo) now appears via the umbrella path too, not only when you ran nxf init directly; the choice you make there lands in the workspace config as expected. Under the hood the umbrella composes the modules in-process instead of driving silent sub-processes, so a module's setup error (for example flow refusing to initialize inside an existing workspace) now surfaces directly and loudly rather than as a wrapped sub-process failure. Non-interactive runs (--json, piped, CI) are unchanged and stay prompt-free.
  • Typing nxf init or nxm init on a terminal now lands on the same nxs init suite chooser as nxs init itself — one consistent front door — with the tool you entered through pre-selected: nxf init starts with flow ticked, nxm init with memory, and you can add or remove the others before confirming. The front-door binaries re-exec the shared nxs umbrella (which inherits your terminal), so there is no longer a separate flow-only init screen. Non-interactive use is unchanged and flag-driven: --json, piped, and CI runs of nxf init/nxm init keep their existing module-native, byte-stable output, and the new nxs init --preselect <tool> flag pre-checks a tool in the chooser (or selects it outright when non-interactive).

Fixed

  • nxf update <id> --set parent=<id> (the belongs_to alias) now rejects a non-existent parent with a not_found error and writes nothing, matching nxf create --parent. Previously a dangling structural parent was accepted and only later surfaced by nxf validate; both verbs now enforce the same existence check up front, before any op is written. An item naming itself as parent is likewise rejected (a validation error), mirroring the self-edge guard on dep add.
  • nxf create --parent <id> and nxf update <id> --set parent=<id> (the belongs_to alias) now reject a parent that is not a project with a validation error, before any op is written. Previously a parent pointing at a task (a plugin "issue") was accepted and only later surfaced by nxf validate (the belongs_to_not_project invariant); both verbs now enforce the project-type check up front, matching the existing missing- and tombstoned-parent checks. The invariant stays as the convergence-time backstop for a violating state that can only arrive via sync.
  • Multi-device sync now surfaces a peer's changes in local reads. A nxs sync pull moves the whole shared op-log, but a foundation-only pull lands another product's ops (e.g. a peer's memories, or tasks) in the log without folding them into that product's materialized views — so nxm/nxf reads on the receiving device could miss what was just pulled. Each product store now carries a per-store folded-through watermark (the highest op-log row it has folded) and, on open, refolds the log into its views once when the log advanced past that watermark — otherwise reads stay on the pure view (no needless rebuild). The refold is order-independent and idempotent (keep-if-beats LWW + observed-remove), guarded by the differential oracle, so a view-refresh can never change the converged value. The shared op-log itself is never pruned — it stays the cross-replica convergence truth.

Removed

  • Removed the generic body item field — fully superseded by the structured field model (description = why + goal, design = path to the goal, completion_criterion = definition of done, plus append-only notes). The --body/--body-file flags are gone from nxf update, and the body key no longer appears in the canonical --json record. nxf search now matches over title + description + design + definition-of-done + notes. No migration path (no live data): delete .nexusflow and re-init.
  • The ready command is removed — it is folded into next. next now *is* the ready set (open, unblocked, not deferred), ranked by the active plugin's next policy, and the new next --include-in-progress flag additionally surfaces actionable claimed (in-progress) work, ranked ahead of ready. This is a hard cut, not a deprecated alias: nxf ready exits with a loud error pointing at nxf next (and nxf next --include-in-progress). nxf prime now uses next --include-in-progress for its snapshot. A board reads next --include-in-progress once and splits the Ready/In-Progress columns on the raw, stored status field.

Version 0.1.0

June 15, 2026

Added

  • The nexus-flow engine — an offline-first, convergent store for projects and tasks. Projects/epics and tasks, dependencies between any of them, belongs-to and contributes-to relations, due/defer dates, and full history with closing comments. ready, blocked and next are derived deterministically from the graph rather than stored, so they are always consistent. Built on an append-only op-log CRDT: concurrent edits from different replicas converge regardless of order (idempotent, observed-remove), with cycles rejected at write time.
  • nxf, the agent-native CLI: init, create, update, claim, close, show, list, search, ready, blocked, next (with a declarative ranking policy), dep add/remove, Markdown body editing, note add/list, and prime to load an agent's working context (optional SessionStart hook). Every command supports --json with a structured error envelope for deterministic, agent-friendly output, and tasks get short, readable IDs (4+4 Crockford base32). A plugin config maps the vocabulary to your domain and ships with issue-tracker and personal-todo presets.
  • Offline-first sync: work fully offline, then nxf sync reconciles replicas through nxf-relay — a small, self-hostable server with a SQLite or Postgres backend. Convergence holds regardless of order or connectivity, and short-ID prefixes stay unique across replicas.
  • Signed, multi-platform releases. Every release is built for macOS (Apple Silicon and Intel) and Linux (x86_64 and ARM64, static) and is cryptographically signed; the signing key never leaves our release secrets. nxf self-update checks that signature on every update with a verifier built into `nxf` — no external tool required — and refuses anything it cannot prove authentic. Releases move through two channels you choose between: stable (the default) and beta (the upcoming release, later promoted to stable from the very same signed bytes — never rebuilt).
  • One-line install: curl -fsSL https://nxf.nxsflow.com/install.sh | sh installs the nxf CLI without sudo. It detects your platform via uname, resolves the newest tarball through /latest (or a pinned NXF_VERSION), and always verifies the download's sha256 (mandatory; a mismatch aborts before anything is written). For authenticity it verifies the release signature whenever it can: with the minisign command-line tool if present, otherwise with a capable `openssl` (every Linux, and macOS with a Homebrew openssl) — so the friction is the *binary*, not the crypto. Only a host with neither (notably stock macOS, whose system openssl is LibreSSL and ships neither Ed25519 nor BLAKE2b) fails closed rather than proceed unverified — install minisign (on macOS: brew install minisign) and re-run, or set NXF_INSECURE=1 to explicitly bootstrap on the verified sha256 alone. Either way the gap is bounded to first install: every nxf self-update afterward verifies the signature unconditionally with the verifier built into nxf. It installs into ~/.local/bin (override NXF_INSTALL_DIR), is idempotent, optionally adds nxf-relay (NXF_INSTALL_RELAY=1), and points out a missing PATH entry; channel and origin are overridable (NXF_CHANNEL, NXF_BASE_URL).
  • nxf self-update updates the CLI in place from your release channel. Before the running binary is atomically swapped, every download is checked two ways: sha256 for integrity, and the release signature for authenticity — verified by a verifier built into `nxf` against a public key compiled into the binary, so no external tool is ever required. The check is unconditional and fail-closed: an unsigned, tampered, or off-origin build is refused, never silently downgraded to an integrity-only check, and an update never moves you to an older version. --check reports whether an update is available without installing; --channel stable|beta|alpha picks (and remembers) the ring. A discreet once-a-day reminder on stderr nudges you when a newer version exists — never in --json output, never in CI or non-interactive use, and silenceable with NXF_NO_UPDATE_CHECK=1.
  • nxf guide [topic] prints embedded, offline narrative docs (getting-started, core-concepts, commands, plugins, migration); with no topic it lists them, and --json gives agents a deterministic topic list or the raw markdown of one topic.

Changed

  • nxf init now requires a conscious plugin choice instead of silently defaulting: on a terminal it prompts with a described chooser, and non-interactively (--json/piped) --plugin is required and the available plugins are listed with descriptions. After init it prints the prefix, chosen plugin, and next steps (also under --json), and it self-ignores the workspace by writing .nexusflow/.gitignore so db.sqlite and the replica identity are never committed.
  • nxf now prints a blank line before and after its human-readable output (and around error messages), so results stand out instead of butting up against your prompt. Machine output (--json) is unchanged and stays byte-exact for scripts and agents.

Powered by nexus-flow

The foundation under a family of products.

nexus-flow is open core: the engine you can install above is the same one our products embed. They add the opinions — vocabulary, ranking, integrations, interface — while the engine keeps the state honest.