Documentation

Guides and the full command reference for nxf — always in sync with the shipped version.v0.27.0

Getting Started

nxf is the nexus-flow agent CLI: a thin, deterministic, offline-first interface over the engine core. This guide takes you from an empty directory to a planned, tracked piece of work. Every command supports --json for machine-readable, byte-stable output — that is the contract agents build on.

Install

Download and install the latest release with the install script:

curl -fsSL https://nxf.nxsflow.com/install.sh | sh

It detects your platform, verifies the download (sha256 + signature), and drops the three suite binaries on your PATH: `nxf` (the issue tracker), `nxm` (durable agent memory), and `nxs` (the umbrella that ties them together). You install once and choose which tools to activate per workspace. Check it:

nxf --version

Initialize a workspace

A workspace is a .nxs/ directory in your project — one shared store that every tool you activate writes into. The quickest way to set one up is the umbrella, which asks which tools to use and wires everything together:

nxs init

It assembles the shared agent files and sets a single nxs prime SessionStart hook, so from then on your agent loads the context of every active tool with one call (see the nxs umbrella). On an agent or in a script it is non-interactive — nxs init --module flow --module memory (or --json) sets up the same state with no prompt.

If you only want the issue tracker, initialize it directly. This is a deliberate plugin choice — there is no default, because the plugin decides the vocabulary you read and write (see plugins). For software work, pick issue-tracker:

nxf init --plugin issue-tracker

Either path lands on the same .nxs/ workspace and the same nxs prime hook. Every id in this workspace is minted under a short, stable namespace called the prefix (the examples below use ab12). Run nxf init --help to see the available plugins and their descriptions.

Create your first items

Items are projects and tasks. Create a project to group the work, then the tasks under it. The --json record is the canonical shape — note the engine-level field names (type, belongs_to, status), which never change regardless of the active plugin:

$ nxf create --type epic --title "Ship v1" --description "Cut the first release" --priority P1 --json
{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Cut the first release","design":null,"due":null,"id":"ab12.0001","priority":"1","status":"open","title":"Ship v1","type":"epic"}
$ nxf create --type feature --title "Write the CLI" --description "Build the command-line tool" --priority P1 --due 2026-12-31 --parent ab12.0001 --json
{"archived":null,"assignee":null,"belongs_to":"ab12.0001","closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Build the command-line tool","design":null,"due":"2026-12-31","id":"ab12.0002","priority":"1","status":"open","title":"Write the CLI","type":"feature"}

The new task belongs_to the project (via --parent), is due by a date, and carries priority 1.

Long fields need no shell-escaping: pass - to read one from STDIN (cat design.md | nxf create … --design -), use --description-file ./desc.md, or pipe the whole item as JSON with nxf create --json -. See commands for the full set.

See what to work on

State like *ready* and *next* is derived, never stored (see core-concepts). With nothing blocking it, the work is ready, and next ranks it by the plugin's policy. The human view speaks the issue-tracker vocabulary — P1, open:

$ nxf next

0001  P1  open  [epic]  Ship v1
0002  P1  open  [feature]  Write the CLI
    ↳ 0001 · Ship v1

That is the whole loop: init once, create work, then let ready/next tell you where to go. From here, read core-concepts for the model, or commands for a full working session.

The nxs umbrella

nxs is the platform umbrella over the suite. The same install ships all three binaries; nxs ties together whichever you activate in a workspace, over the one shared .nxs/ store:

  • nxs init — set up the suite: pick which tools to use (interactively, or --module …/--json

for an agent), assemble the shared agent files, and wire the single nxs prime hook.

  • nxs prime — the session bootstrap the hook runs: it fans out to the prime of each active

tool with one shared clock and concatenates the results. A flow-only workspace yields exactly flow's prime; memory's joins after you add it.

  • nxs sync bind / nxs sync run — sync the shared store with a relay (one op-log, so syncing is

a platform operation, not a per-tool one).

  • nxs migrate — raise the workspace to the current schema, and upgrade a pre-v0.6.0 workspace to

the umbrella model (it rewrites a legacy nxf prime hook to nxs prime). Idempotent.

  • nxs doctor (alias nxs status) — a cross-tool diagnosis: active modules, schema version,

replica identity, sync state, and store integrity.

Each tool keeps its own branded init when you type it directly (nxf init, nxm init); they all land on the same .nxs/ store and the same single nxs prime hook.

Connect an MCP host

MCP-native hosts — Claude Desktop, Claude Code, Cursor, Windsurf — can't drive the nxf CLI, so nexus-flow ships an MCP server (nxs mcp serve) that exposes your board's read and write ops as MCP tools over the same shared .nxs/ store. This guide connects a host to it, including the case where nothing is installed yet.

A host config only launches a *command*. So connecting a host is two decisions: which command launches the server, and which workspace it opens.

The quickest path: the npx runner (no install)

If you have Node (most machines do) you don't need to install anything first. Point the host at the @nexus-flow/mcp runner — it fetches the signed nxs, verifies it, caches it, and starts the server on first launch.

For Claude Desktop, add this to claude_desktop_config.json and restart:

{
  "mcpServers": {
    "nxs": {
      "command": "npx",
      "args": ["-y", "@nexus-flow/mcp"]
    }
  }
}

That serves your default board — a per-user workspace nexus-flow creates automatically on first start (the same one the nexflow.it desktop app uses, so you see one board in both). To point it at a specific project instead, append the workspace after --:

{
  "mcpServers": {
    "nxs": {
      "command": "npx",
      "args": ["-y", "@nexus-flow/mcp", "--", "--workspace", "/absolute/path/to/your/project"]
    }
  }
}

Everything after -- is passed straight to nxs mcp serve. The first launch downloads and verifies nxs (a few seconds); later launches use the cache and start instantly, offline.

If you already have nxs: nxs mcp install

With nxs on your PATH, one command registers the server in every installed host for you — no hand-editing JSON:

nxs mcp install

It writes an idempotent entry naming the absolute path of your nxs binary plus mcp serve, and patches Claude Desktop, Cursor, and Windsurf if it finds them (re-running changes nothing). Add --setup to also create the board in the same step — one command that both registers the server and materializes the workspace it opens:

# Register + create a personal-todo board at the per-user default (knowledge-worker default):
nxs mcp install --setup

# Register + create a coding board pinned to this project:
nxs mcp install --setup --workspace "$PWD" --plugin issue-tracker

To write the portable, machine-independent npx entry from the command line instead of the direct binary path, add --runner npx.

Choosing the workspace

Because a host has no working directory, the server can't guess "this project" — you say which board it opens:

  • Omit `--workspace` → the per-user default workspace, created automatically on first start.

Best for a single personal board shared across your hosts and the desktop app.

  • `--workspace <absolute-path>` → that project's board. Create it first (`nxs mcp install --setup

--workspace <path>, or nxs init` there) — an explicit path with no board is an error, not an auto-create.

  • A single running server can also be pointed at a different board per tool call by passing a

workspace argument to any tool — one server, many projects, no re-registration.

Bootstrapping nxs when it isn't installed

Two signed ways to get nxs, both fail-closed:

  • The one-line installer (installs nxf/nxm/nxs under ~/.local/bin, no sudo):

``bash curl -fsSL https://nxf.nxsflow.com/install.sh | sh ``

  • The `npx` runner (above) — it *is* the bootstrap for GUI hosts: it downloads and verifies nxs

on demand, so the host config is the only thing you add.

Security

Every fetch path verifies before it runs, and there is no insecure escape hatch on the npx route:

  • sha256 proves the bytes weren't mangled in transit.
  • minisign (an Ed25519 signature over the tarball, checked against a public key baked into the

installer and the runner) proves the bytes are genuinely ours. A tampered artifact, a wrong key, or a missing signature aborts before anything runs.

Only bytes that pass both gates are cached and executed. install.sh fails closed on a host with no verifier available (rather than install unverified bytes), and nxs self-update always re-verifies.

Other hosts

The same entries work for Cursor and Windsurf (and any MCP host that launches a stdio command). nxs mcp install detects and patches all three; to target one explicitly, pass --host claude-desktop | cursor | windsurf. Once connected, the server sends usage instructions at connect time, and flow_next returns your ready work — call it first in each session.

Core Concepts

This is the plugin-free heart of nexus-flow. Everything here is universal — the same model underlies every plugin; only the words on top change (plugins).

The data model

There are two kinds of item:

  • A project groups work (a plugin may call it an *epic* or a *project*).
  • A task is a unit of work (an *issue*, a *todo*).

Items carry a small, fixed set of engine-level fields — visible verbatim in any --json record: id, type, title, description, design, status (open / in_progress / closed), priority, due, defer_until, assignee, belongs_to, and a closing_comment. Two relationships connect items:

  • belongs-to: a task or project belongs to one parent project (set with --parent). This is

containment — the breakdown of work.

  • dependencies: a directed *must-finish-first* edge between any two items (project or task),

independent of containment.

Beyond dependencies, items can carry mentions — free-text short-id references that record "this text talks about that item" without ever blocking it. Every change is kept as history, and closing an item records a closing comment (the *why*, not just the *that*).

Preserving the original intent

A title and description are fixed shortly after you create an item and then kept stable — they are the record of *what you set out to do*. Correct them once right after creation (for example to fold in a review), and after that leave them alone. New context and everything you learn while working go into the append-only notes stream (nxf note add), not into a rewrite of the original fields. (This is a convention today; a future release may enforce it with an irreversible per-field lock.)

When an item genuinely no longer makes sense, do not reshape it into something unrelated — that would erase its history. Instead open a new item and close the old one with a reason that points to the new one (closing is the only way an item leaves the board; there is no hard delete). The original item stays, closed, as part of the record.

Why this matters: over time it builds the pair "this is what we wanted to achieve" (the description and design) ↔ "this is how we actually closed it" (the closing comment and notes). That intent-vs-outcome pair is exactly what you learn from later. Overwrite the original intent and you lose half of it — and with it the ability to learn. (Preserving intent is only useful if you can find it again: nxf search looks through closed items too, so the pair stays retrievable.)

Dependencies and blocking

A dependency says the *from* item must wait for the *to* item. Suppose ab12.0002 ("Write the CLI") cannot start until ab12.0003 ("Spec sign-off") is done — add the edge:

$ nxf dep add ab12.0002 ab12.0003 --json
{"msg":"ab12.0002 -> ab12.0003","ok":true}

While the blocker is open, the dependent item is blocked:

$ nxf blocked --json
[{"archived":null,"assignee":null,"belongs_to":"ab12.0001","blockers":[{"id":"ab12.0003","status":"open"}],"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Build the command-line tool","design":null,"due":"2026-12-31","id":"ab12.0002","priority":"1","priority_label":"P1","status":"open","title":"Write the CLI","type":"feature","type_label":"feature"}]

Derivation: ready / blocked / next

ready, blocked, and next are derived, never stored. They are a deterministic computation over the items and their edges — there is no ready flag to set or forget. An item is ready when it is open and has no open blocker; the project and the unblocked task are ready, while the blocked task is absent:

$ 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":"Cut the first release","design":null,"due":null,"id":"ab12.0001","parent":null,"priority":"1","priority_label":"P1","status":"open","title":"Ship v1","type":"epic","type_label":"epic"},{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Approve the final spec","design":null,"due":null,"id":"ab12.0003","parent":null,"priority":"2","priority_label":"P2","status":"open","title":"Spec sign-off","type":"feature","type_label":"feature"}]

next is ready put in order by the active plugin's ranking policy — same derivation, one more step. Because it is all computed, closing the blocker instantly makes the dependent item ready on the next query; nothing has to be re-flagged.

Time: due and defer

Two date fields shape an item over time. due is a target date (it can influence ranking). defer_until hides an item until a date arrives — useful for work you cannot start yet. Derivation is time-sensitive but still deterministic: pass --now to pin the reference instant. In a fresh workspace, a deferred task:

$ nxf create --type feature --title "Pay quarterly taxes" --description "File the quarterly tax return" --priority P3 --defer 2026-07-01 --json
{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":"2026-07-01","deleted":null,"description":"File the quarterly tax return","design":null,"due":null,"id":"ab12.0001","priority":"3","status":"open","title":"Pay quarterly taxes","type":"feature"}

Before the defer date it is not ready:

$ nxf next --now 2026-06-15T00:00:00Z --json
[]

On or after it, the very same query returns the task — only --now changed:

$ nxf next --now 2026-08-01T00:00:00Z --json
[{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":"2026-07-01","deleted":null,"description":"File the quarterly tax return","design":null,"due":null,"id":"ab12.0001","parent":null,"priority":"3","priority_label":"P3","status":"open","title":"Pay quarterly taxes","type":"feature","type_label":"feature"}]

That determinism — same inputs, same --now, byte-identical output — is what makes nexus-flow safe for agents to drive. Next: see how a plugin renders all of this in plugins, or walk the full command set in commands.

Commands

A tour of the most-used nxf commands, in the order a session tends to use them. Run nxf <command> --help for the terse, generated reference (flags, types, defaults); this guide adds the narrative. Pair any command with --json for deterministic, agent-friendly output.

The session below continues the getting-started workspace under the issue-tracker plugin.

Inspect

show is the full human detail of one item — fields, description, dependencies, and notes:

$ nxf show ab12.0002

0002 P1 Write the CLI
=====================

TYPE: feature
STATUS: in progress
PARENT: 0001

DESCRIPTION
-----------

Build the command-line tool

DEFINITION OF DONE
------------------



DESIGN
------

Thin CLI over the core.

NOTES
-----

- started on the command layer

list dumps every item; with --json it is the canonical, byte-stable snapshot (id-ordered, not ranked):

$ nxf list --json
[{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Cut the first release","design":null,"due":null,"id":"ab12.0001","priority":"1","priority_label":"P1","status":"in_progress","title":"Ship v1","type":"epic","type_label":"epic"},{"archived":null,"assignee":"dev","belongs_to":"ab12.0001","closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Build the command-line tool","design":"Thin CLI over the core.","due":"2026-12-31","id":"ab12.0002","priority":"1","priority_label":"P1","status":"in_progress","title":"Write the CLI","type":"feature","type_label":"feature"},{"archived":null,"assignee":null,"belongs_to":null,"closed_at":"2026-06-23T00:00:00Z","closing_comment":"approved","completion_criterion":null,"defer_until":null,"deleted":null,"description":"Approve the final spec","design":null,"due":null,"id":"ab12.0003","priority":"2","priority_label":"P2","status":"closed","title":"Spec sign-off","type":"feature","type_label":"feature"}]

search matches across title, description, and notes:

$ nxf search "thin cli" --json
[{"archived":null,"assignee":"dev","belongs_to":"ab12.0001","closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Build the command-line tool","design":"Thin CLI over the core.","due":"2026-12-31","id":"ab12.0002","priority":"1","priority_label":"P1","status":"in_progress","title":"Write the CLI","type":"feature","type_label":"feature"}]

Work an item

claim marks an item in progress and assigns it:

$ nxf claim ab12.0002 --assignee dev --json
{"archived":null,"assignee":"dev","belongs_to":"ab12.0001","closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Build the command-line tool","design":null,"due":"2026-12-31","id":"ab12.0002","priority":"1","status":"in_progress","title":"Write the CLI","type":"feature"}

update edits fields — here the design:

$ nxf update ab12.0002 --set "design=Thin CLI over the core." --json
{"archived":null,"assignee":"dev","belongs_to":"ab12.0001","closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Build the command-line tool","design":"Thin CLI over the core.","due":"2026-12-31","id":"ab12.0002","priority":"1","status":"in_progress","title":"Write the CLI","type":"feature"}

note add appends a worklog note; note list reads them back:

$ nxf note add ab12.0002 "started on the command layer" --json
{"body":"started on the command layer","id":"[..]"}
$ nxf note list ab12.0002

- started on the command layer

close finishes an item and records a closing comment (the *why*):

$ nxf close ab12.0002 --reason done --json
{"archived":null,"assignee":"dev","belongs_to":"ab12.0001","closed_at":"2026-06-23T00:00:00Z","closing_comment":"done","completion_criterion":null,"defer_until":null,"deleted":null,"description":"Build the command-line tool","design":"Thin CLI over the core.","due":"2026-12-31","id":"ab12.0002","priority":"1","status":"closed","title":"Write the CLI","type":"feature"}

Long text without escaping

description, design, the definition of done (--dod), and the closing comment are long, often multi-line prose full of backticks, quotes, and !. Rather than wrestle that through the shell, give any long-text field its value escaping-free from one of three sources. The rule is the same everywhere: exactly one source per field, and at most one field per call may read STDIN; anything ambiguous is rejected before a single write.

Pipe one field from STDIN with the - sentinel — it works on create, update, close, and note add, and the content is stored byte-for-byte:

cat design.md | nxf create --type issue --title "Write the parser" --priority P1 --design -
printf '%s' "$LONG_TEXT" | nxf update ab12.0002 --set description=-
nxf close ab12.0002 --reason -        # closing comment from STDIN
nxf note add ab12.0002 -              # worklog note from STDIN

Read fields from files (UTF-8, verbatim) — and unlike STDIN, several fields may each come from their own file in one call:

nxf create --type issue --title "Write the parser" --priority P1 \
  --description-file ./desc.md --design-file ./design.md --dod-file ./dod.md
nxf update ab12.0002 --set-file design=./design.md

Or write the whole item as one JSON object on STDIN — no flag combinatorics at all. Pair it with --json (the canonical form --json -) for JSON output too:

echo '{"type":"issue","title":"Write the parser","description":"…","design":"…","priority":"P1"}' \
  | nxf create --json -
echo '{"description":"…","design":"…"}' | nxf update ab12.0002 --json -

A file path of - is the STDIN sentinel as well; a field given two sources (or a second field also asking for STDIN) is a clear error, and nothing is written.

Structure the work

dep add / dep remove manage the *must-finish-first* edges that drive blocking (see core-concepts):

$ nxf dep add ab12.0002 ab12.0003 --json
{"msg":"ab12.0002 -> ab12.0003","ok":true}
$ nxf dep remove ab12.0002 ab12.0003 --json
{"msg":"removed ab12.0002 -> ab12.0003","ok":true}

mention add / mention list / mention remove record free-text short-id references — a citation that never blocks:

$ nxf mention add ab12.0002 ab12.0001 --json
{"msg":"ab12.0002 mentions ab12.0001","ok":true}
$ nxf mention list ab12.0002 --json
["ab12.0001"]
$ nxf mention remove ab12.0002 ab12.0001 --json
{"msg":"removed mention ab12.0002 -> ab12.0001","ok":true}

Bootstrap an agent

prime is one call that hands an agent the plugin-determined statement of what nxf is (purpose), the working rules, the ranked next recommendation (top 7, in-progress work first), a leverage-aware blocked snapshot, a create example carrying the active plugin's type vocabulary and priority range, and the command reference (whose dep entry spells out the dependency direction). The deterministic entry point for an automated session:

$ nxf prime --json
{"blocked":[],"commands":[{"group":"Finding work","items":[{"name":"next","summary":"ready work in priority order (start here); add --include-in-progress for claimed work"},{"name":"blocked","summary":"list blocked work"},{"name":"show <id>","summary":"item detail with deps and notes"}]},{"group":"Creating & updating","items":[{"name":"create","summary":"create an item — see the `create` section above"},{"name":"update <id> --set k=v","summary":"edit fields"},{"name":"claim <id>","summary":"mark in progress"},{"name":"close <id> --reason","summary":"close with a comment"},{"name":"schema","summary":"introspect this plugin's field model (--json) before create/update"}]},{"group":"Dependencies & references","items":[{"name":"dep add <from> <to>","summary":"<from> depends on <to> (so <to> blocks <from> and must close first)"},{"name":"mention add <from> <to>","summary":"record a free-text short-id reference"}]},{"group":"Notes & search","items":[{"name":"note add <id> <text>","summary":"append a worklog note"},{"name":"search <query>","summary":"search title/description/design/DoD/notes"}]}],"context_recovery":"Run `nxs prime` after a context compaction, /clear, or a new session — hosts auto-call it in Claude Code when a nexus-flow workspace is resolved.","create":{"example":"nxf create --type <bug|chore|decision|epic|feature> --title /".../" --priority <P0|P1|P2|P3|P4>","long_text_hint":"Long text without shell escaping: pipe a field via STDIN (`--description -`), read it from a file (`--description-file <path>`), or pipe the whole item as JSON (`nxf create --json -`).","recommendation":"Always set --priority (named variants, highest first: P0 … P4); an item created without a priority ranks last in `next`."},"next":[{"id":"ab12.0001","parent":null,"priority":"1","status":"in_progress","title":"Ship v1","type":"epic"}],"next_total":1,"purpose":"nexus-flow is a software issue tracker for epics and issues. You record items, the dependencies between them, due/defer dates, and priority; `next` and `blocked` are then derived deterministically from that graph rather than stored, so the work list is always consistent.","rules":["Track all work in nexus-flow itself: open an item for every task rather than keeping a separate TODO list or scratch notes — the board is the single source of truth.","Find what to work on next: `nxf next`.","Claim work before starting it: `nxf claim <id>`.","Close with a reason: `nxf close <id> --reason <text>`.","Use `--json` everywhere for deterministic, machine-readable output.","Choose the containment edge deliberately: `parent` is gating — a child rests when its container rests (a deferred, blocked, or closed parent propagates down and hides or masks the child). For a loose association that must NOT gate the child, use `contributes_to` (e.g. cream belongs to the shopping list but only contributes to the birthday plan, so deferring the birthday never hides the cream).","Defer only for a real calendar date — a day before which the item genuinely cannot start (`--defer <date>` on create, or `nxf update <id> --set defer=<date>`); a placeholder date for /"someday, once X ships/" is an anti-pattern that hides the item on a false promise. To wait on an external DELIVERY instead — there are no cross-workspace dependencies — model the delivery as an open WAIT chore in this workspace (title it `WAIT: <what ships>`, e.g. `WAIT: acme-api v2`), have the dependents `nxf dep add <id> <wait-chore>` onto it, and CLOSE the chore — with the delivered version in the reason — to release the whole chain. Each workspace keeps its own anchor; see `nxf guide deferring-and-waiting`.","Correct an item's fields once shortly after creating it (e.g. to fold in a review); after that keep the fields stable and record what you learn while working as append-only notes (`nxf note add <id> <text>`), not field edits. The original title and description are preserved on purpose: paired with the closing comment they form the intent-vs-outcome pair you learn from, so when an item no longer fits, open a new one and close the old with a reason instead of rewriting it past recognition.","When you cite a task's short-id in free text (body or note), also record the reference: `nxf mention add <this-item> <cited-id>`. It keeps the citation resolvable if ids are remapped on sync, and never blocks (it is not a dependency)."],"session_close":["Capture unfinished work as a note so the next session has the context: `nxf note add <id> <text>`.","Close finished items with the reason they're done: `nxf close <id> --reason <text>`.","If the project is under version control, commit and push your code changes."],"workflows":[{"name":"Starting work","steps":["nxf next","nxf show <id>","nxf claim <id>"]},{"name":"Completing work","steps":["nxf close <id> --reason /".../"","nxf next   # pick up the next unblocked item"]},{"name":"Creating dependent work","steps":["nxf create --type <type> --title /".../" --priority <P…>","nxf create --type <type> --title /".../" --priority <P…>","nxf dep add <child> <prereq>   # child depends on prereq; prereq must close first"]}]}

Plugins

A plugin maps the universal core to a consumer's language and policy. Nothing in the CLI hardcodes vocabulary — it all flows from the active plugin config, chosen once at nxf init. A plugin sets four things:

  • Vocabulary: the words for the two item types and the three statuses.
  • Priority labels: the names for priority levels 0–4.
  • Ranking: how next orders the ready set.
  • Presentation: which fields list and show display.

The two shipped plugins

  • issue-tracker — Software issue tracking: epics and issues, P0–P4 priorities,

dependency-aware ranking.

  • personal-todo — Personal to-do list: lists and todos, now/soon/later priorities for

everyday tasks.

Their vocabularies differ:

  • issue-tracker: a project is an epic, a task is an issue; statuses are

open / in progress / closed; priorities are P0P4; next ranks by priority, then due date, then id.

  • personal-todo: a project is a project, a task is a todo; statuses are

todo / doing / done; priorities are now / soon / later / someday / icebox; next ranks by priority, then id (no due-date tiebreak).

Resolving named variants: types and priorities

type and priority are both *named variants* — a small, plugin-defined set with a fixed order. nxf schema --json exposes both as a keyed map, so one rule resolves either field on any item:

schema.types[item.type]           # "task" -> "issue"
schema.priorities[item.priority]  # "0"    -> "P0"

The value stored on an item is the *handle*, not the label. For priority that handle is an ordinal"0" is the highest priority, counting up — deliberately plugin-independent so next can rank numerically and synced items never carry another plugin's labels. The schema.priorities map is what turns the ordinal back into a human label.

Ordinal-stability contract. Within a schema version the ordinal→meaning binding is stable and append-only: priority.labels may gain entries at the end, but reordering or inserting shifts the meaning of already-stored items and is therefore a breaking schema change — a schema-version bump with migration, not an in-place edit.

Same data, side by side

The seam is clearest when you run the same commands on the same data under each plugin. Both workspaces below hold three tasks: two at priority 1 (one due 2026-02-01, one due 2026-03-01) and one at priority 2.

next shows two differences at once — the vocabulary and the ranking. Under issue-tracker, the earlier-due P1 issue (Book venue) wins the tiebreak:

$ nxf next

0002  P1  open  [feature]  Book venue
0001  P1  open  [feature]  Draft proposal
0003  P2  open  [feature]  Order badges

Under personal-todo, the same two soon todos tie on priority and fall back to id, so the first-created (Draft proposal) comes first — and the labels are now/soon/later, todo/doing/done:

$ nxf next

0001  soon  todo  [todo]  Draft proposal
0002  soon  todo  [todo]  Book venue
0003  later  todo  [todo]  Order badges

Yet the stored record is the same — list --json is id-ordered and does not depend on the active plugin. The plugin overlays presentation and ranking; it never changes the data. The one field a plugin owns is type: the type set is plugin-declared, so issue-tracker stores feature where personal-todo stores todo. Strip that one field and the records are byte-for-byte the same:

$ nxf list --json
[{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Outline the event proposal","design":null,"due":"2026-03-01","id":"ab12.0001","priority":"1","priority_label":"P1","status":"open","title":"Draft proposal","type":"feature","type_label":"feature"},{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Reserve the event space","design":null,"due":"2026-02-01","id":"ab12.0002","priority":"1","priority_label":"P1","status":"open","title":"Book venue","type":"feature","type_label":"feature"},{"archived":null,"assignee":null,"belongs_to":null,"closed_at":null,"closing_comment":null,"completion_criterion":null,"defer_until":null,"deleted":null,"description":"Print attendee name badges","design":null,"due":null,"id":"ab12.0003","priority":"2","priority_label":"P2","status":"open","title":"Order badges","type":"feature","type_label":"feature"}]

show makes the vocabulary difference concrete on a single item. Issue-tracker:

$ nxf show ab12.0002

0002 P1 Book venue
==================

TYPE: feature
STATUS: open

DESCRIPTION
-----------

Reserve the event space

DEFINITION OF DONE
------------------



DESIGN
------



NOTES
-----

personal-todo, the same ab12.0002:

$ nxf show ab12.0002

0002 soon Book venue
====================

TYPE: todo
STATUS: todo

WHY
---

Reserve the event space

DONE WHEN
---------



PLAN
----



LOG
---

That doubling is not redundancy — it *is* the explanation. The --json is the meaning; the plugin is how a particular audience reads and ranks it. Picking a plugin at init is therefore a real choice; run nxf init --help to see the options before you commit.

Migration

This guide covers two kinds of migration: bringing existing work into nexus-flow, and moving between major versions of nexus-flow itself.

Bringing an existing tracker in

nexus-flow has no bulk importer — and does not need one. Items are created through the same nxf create you use day to day, so a migration is a short script that walks your old tracker and calls nxf once per item, mapping each record onto the core model: a --type (project or task), a --title, optionally a --parent, --priority, --due, and --description. Re-create dependencies afterward with nxf dep add. Because every command takes --json and is deterministic, the script is easy to write and verify:

# sketch: one create per legacy ticket, then wire dependencies
nxf create --type project --title "Imported backlog" --json
nxf create --type task --title "Legacy #1234" --parent ab12.0001 --priority P2 --json
nxf dep add ab12.0002 ab12.0003

Pick the plugin whose vocabulary matches the source tracker at nxf init — that is the only up-front decision the import depends on.

Binding a sync stream

nexus-flow is offline-first: you work locally against .nxs/, and a sync stream converges every replica on the durable server truth. Bind a stream once, then run sync whenever you reconnect:

nxs sync bind --create
nxs sync run --remote https://your-relay.example.com

Work continues offline between runs; sync run exchanges changes and merges them deterministically (the engine is a CRDT, so concurrent edits converge without a coordinator). The server is the durable record, not a lock — no one has to be online for you to make progress.

Migrating across major versions

nexus-flow follows plain SemVer. Within a major version, upgrades (nxs self-update) are drop-in. A major version bump (e.g. 1.x2.0) is the only place a breaking change may land, and every such change ships a migration note describing what is automatic and what needs your attention. Those notes are aggregated per major version into a single upgrade guide.

Read the aggregated notes for a major before upgrading to it — they live alongside this guide on the website /docs and in the release notes for the version. Within a 0.x series there is no stability guarantee yet, so review the changelog on each update.

Command reference

Generated from the CLI's own command tree. Run a command with --help for its full flags and types.

nxf agent-manifest
Emit nxf's declared contribution to the shared agent files (the AGENTS.md/CLAUDE.md section, the prime command, the SessionStart hook) as data. The `nxs` umbrella assembles the shared files from each active module's manifest (spec §6.2); `--json` is the machine contract
nxf archive
Archive one or more items — "closed and put away". Cascades DOWN: each root and its whole `belongs_to` subtree are archived, but only when the root is closed and every descendant is closed (already-archived counts as closed). Atomic per root, independent between roots; the result reports each root's outcome plus the full list of ids actually archived (incl. cascaded). Archiving is reversible — see `unarchive`
nxf archived
List archived items (any status). Ordered by archive-date descending (most recent first); override with `--sort`
nxf blocked
List blocked items (open, with an open blocker or in a cycle). Ranked by default; override with `--sort id`
nxf claim
Claim an item: mark it in progress (and optionally assign it)
nxf close
Close an item, recording why. Closing is final (no hard delete), so a reason is required
nxf closed
List closed items (excluding archived). Ordered by close-date descending (most recent first); override with `--sort`
nxf contributes add
Record that `from` contributes to `to` (both must exist; never blocks)
nxf contributes list
List the items `id` contributes to
nxf contributes remove
Remove the `from -> to` contributes-to edge
nxf create
Create a new item — a complete item in one call. Title, description, and priority are required; design, the definition of done, a parent, and dependencies are optional. Run `nxf schema` for the active plugin's field model (labels, constraints, required fields)
nxf deferred
List deferred items (open, unblocked, with a future defer date) — the lane that is neither ready nor blocked. Ordered by defer-date ascending (soonest first); override with `--sort`
nxf dep add
Make `from` depend on `to`: `to` blocks `from`, so `from` stays blocked until `to` closes. Rejected if it would create a cycle
nxf dep remove
Remove the dependency where `from` depends on `to`
nxf guide
Print an embedded, offline guide; no topic lists the available topics
nxf init
Initialize a `.nxs` workspace in the current directory: set up flow, then delegate the shared agent files + the single `nxs prime` SessionStart hook to the `nxs` assembler. To set up the whole suite (and pick tools interactively), use `nxs init` instead
nxf label add
Attach a label to an item (idempotent). The label is trimmed; a blank label is rejected
nxf label list
List an item's labels (sorted)
nxf label remove
Detach a label from an item (observed-remove)
nxf list
List items, optionally filtered by status and/or type. Id-ordered by default (so the `--json` record stays plugin-independent); override with `--sort rank`
nxf mention add
Record that `from` cites the short-id `to` in its free text (no blocking)
nxf mention list
List the short-ids `id` mentions
nxf mention remove
Remove the `from -> to` reference
nxf next
List ready work — open, unblocked, not deferred — ranked by the active plugin's `next` policy. Add `--include-in-progress` to fold in actionable claimed work; override the order with `--sort id`
nxf note add
Append a note to an item. Pass `-` as the text to read the note body from STDIN (escaping-free, multi-line)
nxf note list
List an item's notes
nxf schema
Describe the active plugin's field model — vocabulary, priorities, and per field whether it is required on create / settable on update and how. `--json` is the machine contract; run it to learn what `create`/`update` accept in this workspace (the static `--help` cannot carry the active plugin's vocabulary)
nxf search
Search items by substring over title, description, design, DoD, and notes. Results are grouped by lane priority (next+in-progress → blocked → deferred → closed), each group in its natural order; archived items are excluded by default
nxf setup claude
Wire Claude Code: (re)assemble the shared agent files (AGENTS.md/CLAUDE.md) and the single SessionStart hook that runs `nxs prime` (the umbrella fan-out) plus the `nxs`/module permission allowlist, merged into `.claude/settings.json` (idempotent, never overwriting). The canonical verb is `nxs setup claude`; this delegates to it (host setup is an umbrella responsibility)
nxf show
Show one item with its dependencies and notes
nxf unarchive
Unarchive one or more items, making them visible again. Cascades UP only: each item and its ancestor chain resurface, but its children/siblings stay archived. Partial per root; the result reports each root's outcome plus the full list of ids actually unarchived
nxf update
Update item fields via `--set field=value` (repeatable). The long-form `description`/`design`/`completion_criterion` are ordinary `--set` fields. Run `nxf schema` for the settable fields and their plugin names. Convention: correct the field model once shortly after creation; once it is stable, record what you learn as append-only notes (`nxf note add`) rather than further field edits