NNO CLI
Documentation for NNO CLI
Date: 2026-03-30
Status: Detailed Design — Updated Architecture
Parent: System Architecture
Package: packages/cli (published as nno binary)
Overview
The NNO CLI (nno) is the universal command-line interface for the Neutrino platform. It is designed as a namespaced, extensible CLI — starting with project tooling and growing to cover feature development, platform management, marketplace operations, and NNO ops as the platform matures.
nno <namespace> <command> [options]Audiences
| Audience | Namespace | Use Case |
|---|---|---|
| Project developer | nno project | Local dev, build, and deploy for a Neutrino platform project |
| Feature developer | nno feature | Scaffold, develop, validate, and submit feature packages |
| Platform admin | nno platform | Manage platform provisioning, tenants, feature activation (P2) |
| Marketplace browser | nno marketplace | Browse catalogue, check submission status |
| NNO operator | nno ops | Manage infra (P2) |
Namespace Roadmap
| Namespace | Phase | Status |
|---|---|---|
nno project | P1 | ✅ Current scope |
nno feature | P1 | ✅ Current scope |
nno marketplace | P1 | ✅ Current scope (read + operator actions) |
nno platform | P2 | 🔜 When NNO Registry is live |
nno ops | P2 | 🔜 NNO internal tooling |
1. Installation
# Global install (recommended)
npm install -g @neutrino-io/cli
# or
pnpm add -g @neutrino-io/cli
# Verify
nno --versionThe CLI is a Node.js binary published as @neutrino-io/cli and installed globally. The binary name is nno (defined in package.json bin field).
2. Package Architecture
The CLI is built with Citty — TypeScript-first, lightweight, used by the Nuxt/Nitro ecosystem.
All namespaces live inside a single @neutrino-io/cli package. Each domain is a self-contained plugin (NnoPlugin) registered at startup — keeping domains portable and independently testable without splitting into separate packages.
packages/
└── cli/ ← single binary + plugin registry
└── src/
├── index.ts ← register plugins + runMain
├── cli.ts ← registerPlugin(), createCli()
├── types.ts ← NnoPlugin interface, definePlugin()
├── plugins/
│ ├── project.ts ← nno project namespace
│ ├── feature.ts ← nno feature namespace
│ └── marketplace.ts ← nno marketplace namespace
├── commands/
│ ├── auth/ ← login, logout, whoami (core, not namespaced)
│ ├── project/ ← check, dev, build, deploy
│ ├── feature/ ← init, dev, test, build, validate, submit, status
│ └── marketplace/ ← list
└── utils/
├── credentials.ts
└── exec.tsPlugin interface (packages/cli/src/types.ts):
import type { SubCommandsDef } from 'citty'
export interface NnoPlugin {
name: string // namespace (top-level CLI command)
description?: string
commands: SubCommandsDef // citty subcommands
}
export function definePlugin(plugin: NnoPlugin): NnoPluginExternal plugin authoring:
import { definePlugin, registerPlugin } from '@neutrino-io/cli/plugin'
import { defineCommand } from 'citty'
const analyticsPlugin = definePlugin({
name: 'analytics',
description: 'Analytics management',
commands: {
report: defineCommand({ ... }),
},
})
// Register before runMain in your entry point
registerPlugin(analyticsPlugin)Core entry point (packages/cli/src/index.ts):
import { runMain } from 'citty'
import { registerPlugin, createCli } from './cli.js'
import { projectPlugin } from './plugins/project.js'
import { featurePlugin } from './plugins/feature.js'
import { marketplacePlugin } from './plugins/marketplace.js'
registerPlugin(projectPlugin)
registerPlugin(featurePlugin)
registerPlugin(marketplacePlugin)
runMain(createCli())3. Authentication
Commands that interact with NNO services require authentication:
nno login # interactive login to NNO account
nno logout
nno whoami # show current auth statusnno whoami
# → Authenticated as developer@acme.com
# → Platform: r4xk9m2zt5 (Foresight)
# → Role: platform-adminAuth tokens stored in ~/.nno/credentials.json. Auto-refreshed before expiry.
nno project commands do not require NNO auth — they operate locally against wrangler and Vite.
4. nno project — Project Dev, Build & Deploy [Phase 1]
Current focus. Wraps wrangler and Vite with validation, context injection, and migration handling for a Neutrino platform project.
Commands
nno project check [--env <local|dev|stg|prod>]
nno project dev [--service <name|all>] [--env <local|dev>]
nno project build [--env <stg|prod>]
nno project deploy [--service <name|all>] [--env <stg|prod>]4.1 nno project check
Validates the project config for the target environment before any operation. Runs implicitly before build and deploy.
nno project check --env stgChecks performed:
| # | Check | Severity |
|---|---|---|
| P01 | wrangler.toml exists for each service | Error |
| P02 | [env.<target>] section exists in wrangler.toml | Error |
| P03 | No placeholder D1 IDs (local-dev-db not used in non-local env) | Error |
| P04 | PLATFORM_ID and TENANT_ID vars are 10-char [a-z0-9] NanoIDs | Error |
| P05 | Required env vars present (VITE_AUTH_API_URL etc. for the target env) | Warning |
| P06 | Wrangler secrets exist for target env (wrangler secret list --env <env>) | Warning |
| P07 | D1 migration state — pending migrations detected | Info |
| P08 | CF Pages project name matches naming convention | Warning |
Example output:
nno project check --env stg
Checking project config for env: stg
✓ P01 wrangler.toml found (auth, console)
✓ P02 [env.stg] defined in all service configs
✓ P03 D1 IDs populated (no placeholders)
✓ P04 PLATFORM_ID=r4xk9m2zt5, TENANT_ID=n7wp3fy8q1
⚠ P05 VITE_AUTH_API_URL not set for stg — set in CF Pages dashboard
⚠ P06 AUTH_SECRET not set for stg — run: nno project deploy --env stg (will prompt)
✓ P08 Pages project name follows convention
0 errors, 2 warnings — project is deployable with caveats4.2 nno project dev
Start local development. Validates local config, applies pending migrations, then starts all services.
nno project dev # start all services
nno project dev --service auth # auth worker only
nno project dev --env dev # target dev CF environmentWhat it does:
nno project dev
│
├─ nno project check --env local
├─ Apply pending local D1 migrations (wrangler d1 migrations apply --local)
│
├─ wrangler dev (platform auth Worker) → localhost:8787 (per-platform auth)
│ Note: services/auth/ is a TEMPLATE with REPLACE_WITH_* placeholders —
│ it is NOT deployed from this repo. Each platform project supplies its
│ own deployed auth Worker; local dev starts a wrangler instance of it.
└─ vite dev (apps/console) → localhost:5174
└─ /api/auth proxied to localhost:87874.3 nno project build
Build the console shell for the target environment.
nno project build --env stg
nno project build --env prodWhat it does:
nno project build --env stg
│
├─ nno project check --env stg
└─ vite build --mode stg (apps/console)
→ outputs apps/console/dist/Vite loads apps/console/.env.stg for environment-specific vars.
4.4 nno project deploy
Full deployment pipeline: check → build → deploy workers → apply migrations → deploy Pages.
nno project deploy --env stg
nno project deploy --env prod
nno project deploy --env stg --service auth # single service onlyWhat it does:
nno project deploy --env stg
│
├─ nno project check --env stg
├─ nno project build --env stg
│
├─ wrangler deploy --env stg (services/auth/) (per-platform auth)
│
├─ wrangler d1 migrations apply --env stg --remote (if P07 flagged pending)
│
└─ wrangler pages deploy apps/console/dist
--project-name=r4xk9m2zt5-n7wp3fy8q1-portal-stg
--branch=develop5. nno feature — Feature Package Development [Phase 1]
Scaffold, develop, test, validate, and submit feature packages to the NNO Marketplace.
Commands
nno feature init <feature-name> [options]
nno feature dev [--no-service] [--platform <id>] [--env <dev|stg>]
nno feature test [--watch] [--coverage]
nno feature build [--analyze]
nno feature validate [--fix] [--json]
nno feature submit [--message <msg>] [--private] [--dry-run]
nno feature status [<submission-id>]5.1 nno feature init
Scaffold a new feature package from the NNO template.
nno feature init analytics
nno feature init inventory --no-service
nno feature init crm --dir ./packages/ui-crmOptions: --no-service, --no-database, --dir <path>, --template <id>
Generates the full scaffold structure, runs pnpm install, prints next steps.
5.2 nno feature dev
Start the local feature development environment — runs a mock NNO shell alongside the feature's Vite dev server and optional Wrangler service.
nno feature dev
nno feature dev --no-service
nno feature dev --platform r4xk9m2zt5 --env stgDefault mode:
nno feature dev
│
├─ NNO Mock Shell localhost:5100 (ShellContextProvider + mock user/tenant)
├─ Feature Vite Dev localhost:5180 (mounted inside mock shell, full HMR)
└─ Wrangler Service localhost:8790 (local D1, hot-restart)Mock shell config (~/.nno/mock-shell.json):
{
"platform": { "id": "dev-platform", "name": "Local Dev Platform" },
"tenant": { "id": "dev-tenant", "name": "Local Dev Tenant" },
"user": { "id": "dev-user", "email": "dev@local.test", "permissions": ["*"] }
}Real platform mode (--platform): connects mock shell to actual NNO auth service; uses real tenant config from NNO Registry.
Port assignments:
| Service | Default Port | Config key |
|---|---|---|
| Mock shell | 5100 | fixed |
| Feature Vite dev | 5180 | dev.port in nno.config.ts |
| Feature Wrangler service | 8790 | dev.servicePort in nno.config.ts |
5.3 nno feature test
Run tests with vitest — correct configuration for both UI (jsdom) and service (CF Workers pool) targets.
nno feature test
nno feature test --watch
nno feature test --coverage
nno feature test --service-only
nno feature test --ui-only5.4 nno feature build
Build the feature package for distribution using tsup (UI) and wrangler build (service).
nno feature build
nno feature build --analyzeOutput:
dist/
├── index.js ← UI package (ESM)
├── index.d.ts ← Type declarations
├── feature.js ← FeatureDefinition (tree-shakeable)
└── service/
└── worker.js ← Compiled Hono Worker (if service present)5.5 nno feature validate
Validate the feature package against the NNO SDK contract. Must pass before nno feature submit.
nno feature validate
nno feature validate --fix
nno feature validate --jsonValidation rules:
| # | Rule | Severity |
|---|---|---|
| V01 | nno.config.ts exists and parses without error | Error |
| V02 | feature.id matches ^[a-z][a-z0-9-]*$ | Error |
| V03 | feature.id matches nno.config.ts id field | Error |
| V04 | feature.version is valid semver | Error |
| V05 | feature.version matches package.json version | Error |
| V06 | All permissions[].key values match ^\{id\}:[a-z-]+$ | Error |
| V07 | At least one required: true permission declared | Error |
| V08 | serviceEnvKey present when requiresService: true | Error |
| V09 | service/ directory exists when requiresService: true | Error |
| V10 | service/wrangler.toml is a valid template (no hardcoded IDs) | Error |
| V11 | All navigation[].path values exist in routes[].path | Error |
| V12 | No duplicate route paths | Error |
| V13 | No route path starts with /\{feature-id\} (shell prefixes automatically) | Error |
| V14 | No imports from shell internal paths (@/, apps/console/) | Error |
| V15 | No hardcoded API URLs (must use serviceEnvKey + useServiceUrl) | Warning |
| V16 | feature.ts default export is a valid FeatureDefinition (Zod) | Error |
| V17 | nno.config.ts compatibility.shellVersion is valid semver range | Warning |
| V18 | package.json has publishConfig | Warning |
| V19 | README.md exists and is non-empty | Warning |
| V20 | Build succeeds (nno feature build exits 0) | Error |
5.6 nno feature submit (Phase 2)
Provisional design — subject to revision.
nno feature submitand the associated submission/review pipeline are Phase 2 capabilities, contingent on lifting the Q4 NNO-only authorship restriction. NNO currently authors all feature packages internally; external feature submissions are not yet supported. The design below documents the intended future workflow.
Submit the feature package to NNO Marketplace for review.
nno feature submit
nno feature submit --message "Initial submission — analytics v1"
nno feature submit --private
nno feature submit --dry-runFlow:
nno feature submit
├─ nno feature validate (fails fast on errors)
├─ nno feature build
├─ Package dist/ + nno.config.ts + README.md → submission bundle (.nno)
├─ Upload to NNO Marketplace review queue
└─ Returns submission ID + tracking URL5.7 nno feature status (Phase 2)
Provisional design — subject to revision.
nno feature statusis a Phase 2 capability tied to the external submission workflow. It is not available until the submission pipeline is enabled.
Check marketplace submission status.
nno feature status # all pending submissions for your platform
nno feature status sub_9x2m4k7p1q # specific submissionStatuses: PENDING → IN_REVIEW → APPROVED | REJECTED
6. nno marketplace — Stack Template Catalogue [Phase 3]
Commands
nno marketplace list [--search <term>]
nno marketplace approve <submission-id>
nno marketplace reject <submission-id> [--reason <msg>]nno marketplace list is available to all authenticated users. It browses NNO-authored stack templates from services/stack-registry. nno marketplace approve and nno marketplace reject are operator commands — they are registered in the CLI and available as stubs for NNO operators to approve or reject marketplace submissions.
7. nno platform — Platform Management [Phase 2]
Available when NNO Registry is live. Handles provisioning, tenant management, and feature activation.
nno platform deploy --platform <id> --env <stg|prod> [--wait]
nno platform status --platform <id>
nno platform tenants --platform <id>nno platform deploy supersedes the nno project deploy wrangler wrapper — it calls the NNO CLI Service API which orchestrates the full GitHub commit → CF Pages build cycle.
8. Configuration
Project: nno.config.ts
See Feature Package SDK — Section 5 for the full schema.
Global: ~/.nno/config.json
{
"apiUrl": "https://api.stack.nno.app",
"defaultPlatform": "r4xk9m2zt5",
"defaultEnv": "stg"
}9. CI/CD Integration
Feature Package CI (GitHub Actions)
jobs:
validate-and-test:
steps:
- run: npm install -g @neutrino-io/cli
- run: pnpm install
- run: nno feature validate --json
- run: nno feature test --coverage
- run: nno feature build
Platform Project CI (GitHub Actions)
jobs:
deploy-stg:
if: github.ref == 'refs/heads/develop'
steps:
- run: nno project check --env stg
- run: nno project deploy --env stg
deploy-prod:
if: github.ref == 'refs/heads/main'
steps:
- run: nno project check --env prod
- run: nno project deploy --env prod10. NNO Backend Services (CLI calls)
CLI commands that interact with NNO cloud services route to their respective backend services. The CLI binary calls these services directly (via the NNO Gateway or directly):
| CLI Command | NNO Service | Endpoint | Action |
|---|---|---|---|
nno login | services/iam | POST /api/auth/sign-in/email | Authenticates user, returns session token (Designed, not yet available) |
nno whoami | services/iam | GET /api/nno/session | Returns current session + permissions |
nno marketplace list | services/stack-registry | GET /api/v1/stacks | Lists NNO-authored stack templates |
nno platform deploy | services/cli | POST /api/v1/platforms/\{id\}/deploy | Triggers CF Pages rebuild (P2) |
nno project commands are fully local — no NNO service calls.
11. Error Handling & Exit Codes
| Exit Code | Meaning |
|---|---|
0 | Success |
1 | General error (network, auth, unexpected) |
2 | Validation failure (validate or check found errors) |
3 | Build failure |
4 | Submission rejected by server (conflict, quota, etc.) |
All errors include an actionable message:
✗ Error [V08]: serviceEnvKey is required when requiresService is true
Add serviceEnvKey to your FeatureDefinition:
→ serviceEnvKey: 'VITE_ANALYTICS_API_URL'
Docs: https://docs.nno.app/sdk/feature-definition#serviceenvkey12. Command Migration Reference
Flat commands from the original spec map to namespaced commands:
| Original (flat) | Namespaced |
|---|---|
nno dev | nno project dev |
nno build | nno project build / nno feature build |
nno deploy | nno project deploy / nno platform deploy (P2) |
nno validate | nno project check / nno feature validate |
nno init | nno feature init |
nno test | nno feature test |
nno submit | nno feature submit (Phase 2) |
nno status | nno feature status (Phase 2) |
nno list | nno marketplace list |
Status: Detailed design — single-package plugin architecture
Tech stack: Citty (TypeScript-first CLI framework)
Implementation target: packages/cli/
Related: Feature Package SDK · System Architecture · NNO CLI Service