@nifrajs/cli
v5.11.0
Published
The nifra CLI - zero-config dev/build/start for a nifra app (`nifra dev`, `nifra build`, `nifra start`).
Maintainers
Readme
@nifrajs/cli
The nifra CLI - zero-config dev/build/start for a nifra app, plus the agent surfaces (nifra context,
nifra mcp). Run from your project root (it reads nifra.config.ts/framework.ts, backend.ts, and
routes/).
nifra dev [--port <n>] [--poll] True-HMR dev server (Bun + nifra SSR; Vite for a Vite-only app).
nifra build [--out <dir>] [--target <t>] Complete deploy directory; target defaults to Bun.
nifra start [--port <n>] [--out <dir>] Run the generated Bun server at <out>/server.js.
nifra context Print this project's API + page routes + conventions.
nifra mcp MCP server (stdio) exposing this project to a coding agent.
nifra check [--json] Gate: typecheck + lints; --json includes fixes/suggestions.
nifra migrate --from tailwind --to stylex Dry-run safe static Tailwind → StyleX migration; --write applies it.
nifra assure [--config <file>] [--json] Gate reflected routes against enforcement evidence.
nifra capabilities check [--json] Gate effect provenance + the reviewed capability lockfile.
nifra manifest emit [--sign <key-ref>] Emit the hash-verified route trust artifact after assurance.
nifra manifest diff <before> <after> Block promotion on contract/governance regressions.
nifra sdk --lang <python|go> [--strict]
Generate typed Python dataclass or Go SDK from `backend.ts`; strict mode
fails on opaque schemas and unsupported SSE contracts.
nifra doctor [--json] [--auto-fix] Catch undeclared imports and duplicate Nifra/React installs.nifra dev, build and start take a flag's value as --target vercel or --target=vercel, and refuse
a flag or argument they do not know instead of ignoring it.
nifra doctor - dependency health
Doctor diffs source imports against declared dependencies, then resolves identity-sensitive
dependencies from every workspace package. More than one physical @nifrajs/*, react, or
react-dom copy fails even when versions match; module identity is path-based. Doctor reports
paths/importers and never deletes installations.
nifra assure - the route-enforcement gate
Create nifra.assurance.ts with a default defineAssuranceConfig({ source, policy }) export, then run
nifra assure in CI. Official middleware publishes evidence at the same seam where it installs its
hooks; the gate classifies every reflected route with the first matching rule and exits non-zero for an
unclassified route, missing evidence, or forbidden evidence. Evaluation is startup/CI-only and adds no
request-path overhead. Use --json for the complete per-route report or --config for another file.
nifra manifest - the deploy trust artifact
Add optional manifest: { path, signer } settings to nifra.assurance.ts, then run
nifra manifest emit. Emission refuses failing route or capability assurance and joins the route
schemas, enforcement evidence, effect tokens, and field-level response classification into one
deterministic SHA-256 artifact. --sign <key-ref> asks the configured callback to produce a detached
Ed25519 sidecar, so the private key can stay inside KMS/HSM infrastructure.
At promotion time, nifra manifest diff previous.json candidate.json hash-verifies both files and exits
non-zero on a breaking API change, removed assurance, expanded effect, lost provenance coverage, or
increased data sensitivity. A new route counts as well: one that declares a capability or returns pii
or secret data blocks promotion as the same change to an existing route would. This is separate from
the frontend asset dist/manifest.json.
nifra verify - verification tiers
nifra check is the fast project done-gate: TypeScript plus static contract and boundary diagnostics.
It reads source without running it, with one exception: when the project has a contracts.lock.json,
nifra check (with --lints-only too) imports backend/app.ts, running its top-level code, to compare
the routes it serves against the lock.
It is not a release claim. nifra verify runs the ordered local verification plan; its default mode
is the feedback plan and reports which release gates it omits. CI and release automation should run
nifra verify --release (or bun run check:release), which includes build, coverage, corpus,
consumer, publish, and cross-runtime gates. Each gate runs a package.json script (bun run lint,
bun run check:docs, ...); a gate whose script the project does not declare is reported as
undeclared and does not fail the run. The nifra repository's own bun run verify and
bun run check:release fail that gate instead, so a renamed script cannot drop it. A line on stderr
marks each gate as it starts and finishes, with its time. Run nifra port --ci --target <target> for an app's
resolved deployment target; CI never guesses a target when none is configured.
nifra check - the drift gate (run as "done")
nifra check makes nifra's anti-drift guarantees actually fire instead of relying on the agent to
remember them. It does three things and exits non-zero if any fails:
- Typecheck (
tsc --noEmit, using the project's own TypeScript) - the frontend↔backend contract is compiler-enforced.client<typeof app>derives request inputs andres.datafrom your routes, so a screen that expects the wrong shape is a type error. Running the typecheck is what turns that latent guarantee into an enforced one. TypeScript sources with notsconfig.jsonbeside them fail this step, as a missingtypescriptinstall does: nothing typechecked them. A JavaScript-only project skips it. Every projecttsconfig.jsonreferences is typechecked too, each as its own program; a project that splits its code across sibling configs lists them innifra.check.json:{ "tsconfigs": ["tsconfig.json", "tsconfig.server.json"] }. A zoned file no program reads fails it. - Typed-client lint - flags any hand-rolled
fetch()to your own API (a relative URL likefetch("/users")), which bypasses the typed client so the compiler can't see the drift. External absolute-URL fetches are not flagged. - Server-only-import lint - flags a top-level import of server-only code (a DB driver,
node:/bun:builtins, the./dbmodule) into aroutes/page module. Those modules are bundled for the browser, so the import ships server code to the client. Reach it viac.db/ctx.apiinside a loader instead.
Pass --json for a machine-readable result ({ ok, typecheck, diagnostics[] }) - what the
nifra_check MCP tool returns, so an agent acts on diagnostics instead of scraping output. Each diagnostic
has a short fix string and, when safe, a structured suggestion: an exact one-line diff, an argv command
array (for example ["bun","add","react"]), or concrete manual steps. Tell a coding agent to run
nifra check as its definition of done (the scaffolded AGENTS.md already does), and wire it into CI - a
green check means the frontend and backend can't have silently diverged.
For hand-rolled own-API fetch() calls, nifra check stays conservative: simple string-literal calls
that match a statically visible Nifra route get an exact typed-client rewrite diff; dynamic URLs, custom
headers, bodies, query strings, or ambiguous routes fall back to manual steps.
nifra i18n check - the catalog gate
nifra i18n check [entry] imports the module that exports your locales (from defineLocales) and
catalogs - unlike nifra check, it runs that code - and reports per-locale coverage, missing and
unused keys, ICU syntax errors, placeholder and rich-tag parity with the default message, plural cases
the locale's grammar needs, script purity (letters from a script the locale does not write in), and
untranslated messages. It exits 1 on an error, --strict also fails on warnings, and --json prints
the result. The checks are checkCatalogs() from @nifrajs/i18n/check, usable in a test.
nifra migrate --from tailwind --to stylex
This command is a dry run by default. It rewrites static className attributes whose utilities have a
direct StyleX equivalent into stylex.props(...) plus a local stylex.create(...) table. Use
--write to apply the safe changes, and --dir to scan a project subdirectory. Responsive breakpoints
and element-local pseudo-classes are supported; dynamic expressions, arbitrary values, parent-dependent
variants, and unknown utilities are left untouched and reported with file and line evidence. A non-zero
exit status means manual migration issues remain.
When a library such as Better Auth intentionally owns a mounted prefix outside the Nifra contract,
declare that prefix in nifra.check.json so its relative calls do not keep CI red:
{ "externalMounts": ["/auth"] }The match is segment-anchored (/auth never suppresses /authors) and traversal paths are rejected.
The normalized prefixes are echoed in human, JSON, and MCP results so the lint bypass stays auditable.
This suppresses only the typed-client diagnostic; it does not mount or authorize the external handler.
For AI coding agents
nifra context prints this project's actual surface - API routes (from backend.routes()), page
routes (from routes/), and the framework conventions - as Markdown. Pipe it into a prompt:
nifra context | pbcopy # or: nifra context > .agent-context.mdnifra mcp runs a Model Context Protocol server over stdio, so
an agent can act on the project, not just read about it. Core tools:
nifra_context- the same project surface as above.nifra_routes/nifra_openapi- structured API route contracts and an OpenAPI 3.1 document.nifra_docs/nifra_example- token-efficient docs slices and verified code snippets.nifra_scaffold- map a URL to the correctroutes/files and a route pair (the page + its.backend.tsloader with an output schema); optionally write them.nifra_run- run HTTP requests through this project's backend and get structured results (status, headers, parsed body, and any thrown error). The backend is re-loaded in a fresh process each call by default, so it reflects the agent's latest edits - the write → run → see-the-failure → fix loop. Passwarm:trueto reuse a hot worker while source files are unchanged.nifra_render- SSR a page route and return rendered HTML for quick page verification.nifra_ws- verify a WebSocket route with a real Bun WebSocket round-trip and structured output.nifra_test- run boundedbun testwith structured output.nifra_check- run the drift gate and get the structured{ ok, typecheck, diagnostics[] }result with suggestions, so the agent verifies its own work and fixes each diagnostic before finishing.nifra_assure- evaluatenifra.assurance.tsand return the complete per-route evidence report.nifra_levels- compute the cumulative verification ladder (L0 typed contract, L1 route assurance, L2 capability lockfile, L3 trust manifest, L4 contract invariants) and return{ achieved, levels[] }, so an agent can see what its change proves and read why a level it lost no longer holds.nifra_doctor- catch imported packages missing frompackage.json; withautoFix:true, write safe dependency entries when a version can be inferred locally and return exactbun addcommands for anything that needs a package-manager decision.
The MCP server also exposes compact resources (nifra://routes, nifra://openapi, nifra://package-json,
nifra://agents-md) and prompt templates for common tasks.
For long-running stdio tool calls, nifra follows MCP's standard _meta.progressToken progress
notifications and notifications/cancelled request cancellation. nifra_run, nifra_render,
nifra_test, and full nifra_check calls stop their subprocess work when cancelled.
For token-sensitive clients, tools/list also accepts the opt-in extension { "compact": true };
call tools/describe with a tool name when you need the full schema and description.
Wire it into a client. Claude Desktop / Cursor (mcp.json):
{
"mcpServers": {
"nifra": { "command": "nifra", "args": ["mcp"] }
}
}Claude Code:
claude mcp add nifra -- nifra mcpThe server answers for the nifra the project installs. When the project has its own @nifrajs/cli at
a different version than the nifra the client spawned (a global install, say), the session is handed
to ./node_modules/.bin/nifra mcp. When that is impossible, nifra_check, nifra_types,
nifra_docs, nifra_example, nifra_assure and nifra_contracts refuse with the fix instead of
describing a different release.
The server runs none of the project's code and keeps none of its .env. Every tool, resource and
prompt that loads the app, including the ones the app declares with .tool(), runs in a fresh process
started in the project's directory, which loads that directory's .env files, answers and exits; a
config that exits or hangs fails only that call. Values from the environment and from
nifra mcp --env-file <path> reach every such process. In a monorepo each app's tools see that app's
.env, not the root's. A call that loads the app costs one process start, and warm: true on
nifra_run/nifra_render keeps one worker with the app loaded until a source file changes. Details
and limits: Where your code and secrets run.
Structured verification
nifra check --json returns stable diagnostic codes and machine-actionable evidence. nifra assure --json --strict returns one versioned bundle with explicit pass, fail, and skip gate results plus a green or red verdict. Use nifra fix --code NF-... for a registered fix recipe, and nifra contracts snapshot to opt into route contract drift detection.
Assurance configs may append application-supplied rule packs. Pack codes must not use the reserved NF- prefix. Rules are pure source scans and run after the built-in rules.
Run the client from (or point it at) your project root. The protocol is hand-rolled (newline-delimited JSON-RPC 2.0) - no SDK dependency.
For AI agents
Start with LLM.md - this package's contract card (the exports you call + its footguns),
one cheap read instead of the whole corpus. For the wider framework: the repo's
AGENTS.md is the copy-paste quick reference, and
llms-full.txt is the full machine-readable corpus. Run nifra check as the
done-gate, or nifra mcp to give the agent live project tools.
