Skip to content

feat(cli): @nyuchi/mzizi-cli — first-party CLI with login/logout/whoami/add/search/list #81

@bryanfawcett

Description

@bryanfawcett

Purpose

Ship @nyuchi/mzizi-cli — the command-line tool for developers working with the Mzizi framework and any Mzizi-based project (the Nyuchi Design System, Fundi, external adopters' projects).

Naming rule (locked)

npm is infrastructure. Infrastructure is always Nyuchi. So the only npm scope used is @nyuchi. The package name after the slash carries the rest of the meaning — what the package works against, not who operates the publishing infrastructure.

  • @nyuchi/mzizi-cli — CLI for Mzizi
  • @nyuchi/mzizi-core — Mzizi framework primitives (when needed)
  • @nyuchi/bundu-tokens — Bundu canonical tokens, packaged for npm consumption
  • @nyuchi/fundi-sdk — Fundi client SDK

Same rule generalises to other infrastructure registries (PyPI, crates.io, container registries) — they all use the nyuchi namespace when Nyuchi operates the publish.

Depends on: #78, #79. Plays well with #80 but doesn't strictly require it.

Package details

  • Name: @nyuchi/mzizi-cli
  • Binary: mzizi (primary), nyuchi-mzizi (verbose alias for environments where mzizi collides)
  • Runtime: Node.js ≥ 20
  • Distribution: npm, public
  • Versioning: starts at 0.1.0, follows Mzizi cadence

Commands

mzizi login

Walks the user through pasting a first-party token into a stored config file.

$ mzizi login
? Paste your first-party API key: ********************
✓ Stored in ~/.mzizi/credentials (mode 0600)
✓ Verifying with portal…
✓ Recognised as first-party: clientId=nyuchi-cli-bryan, brand=nyuchi

Verification step calls the whoami MCP tool. Failure flow on a junk token:

✗ Token not recognised. Body: {"authenticated": false}
  The token was saved locally but you're not currently first-party.
  Contact a portal admin to be added to the allow-list.

mzizi logout

Removes stored credentials.

mzizi whoami

Shells out to the whoami MCP tool.

$ mzizi whoami
authenticated: true
firstParty:    true
clientId:      nyuchi-cli-bryan
brand:         nyuchi

For non-first-party: authenticated: false.

mzizi add <name> [...names]

Wraps shadcn@latest add with the bearer token attached. Works against the Mzizi resolver, so a component on Node 2 (primitive) gets fetched from its registered upstream (shadcn / shadcn-svelte / Material / crates.io / etc.) with any project-specific overrides applied at install time.

$ mzizi add nyuchi-fundi
✓ Adding nyuchi-fundi (node 9, registry:lib)
✓ Wrote lib/fundi/nyuchi-fundi.ts (8.2 KB)

mzizi search <query> [--node N]

Searches the registry through /api/v1/search with the auth header. Surfaces components visible to the current caller (first-party sees opt-in components; anon does not).

mzizi list --node N

Lists components in a given node (1–10) for the current caller.

mzizi convention [slug]

Prints a Bundu convention. With no slug, lists active conventions.

$ mzizi convention
ownership-convention    Bundu ecosystem ownership convention    v1.0.0

$ mzizi convention ownership-convention
[full text of the convention]

CLI surface for the get_bundu_convention / list_bundu_conventions MCP tools.

mzizi describe [tool-name]

Shells out to mcp_describe. With no tool name, prints the live catalogue grouped by category. With a tool name, prints the schema and gating rules for that tool. Subcommands are generated from the registry — adding a tool to mcp_tool_registry surfaces a new subcommand automatically (depends on #83 for auto-generation).

Credential storage

~/.mzizi/credentials      # mode 0600
{
  "token": "<raw bearer token>",
  "portalUrl": "https://design.nyuchi.com",
  "savedAt": "2026-04-28T..."
}
  • Mode 0600 enforced on write.
  • Override via MZIZI_TOKEN env var (CI use case). Env wins over file.
  • Override via MZIZI_PORTAL_URL for staging.
  • Token never echoed, logged, or visible in --verbose output.

Auth header

Every CLI call attaches:

Authorization: Bearer <token>

If the upstream environment strips Authorization, the CLI also sends:

X-Nyuchi-Key: <token>

Matches #79's token-extraction priority.

Implementation notes

  • TypeScript, compiled to single ESM bundle via tsup.
  • HTTP client: native fetch.
  • Arg parsing: commander.
  • Prompts: @inquirer/prompts for login.
  • No telemetry. If we want metrics later, prompt for opt-in.
  • Repo location: packages/mzizi-cli/ in the design-portal monorepo.

Acceptance criteria

  • npm install -g @nyuchi/mzizi-cli succeeds; mzizi --version prints 0.1.0.
  • mzizi login writes ~/.mzizi/credentials with mode 0600.
  • mzizi login verifies the token via whoami before declaring success.
  • mzizi logout removes the file.
  • mzizi whoami correctly reports first-party / public status.
  • mzizi add <public-component> works (parity with npx shadcn add).
  • mzizi add <opt-in-component> works only when first-party. Without auth: surfaces the 401 reason field with the hint URL.
  • mzizi search and list see opt-in components when first-party, do not when public.
  • mzizi convention and mzizi convention <slug> work against bundu_conventions.
  • mzizi describe works against mcp_describe.
  • MZIZI_TOKEN env var overrides the file.
  • MZIZI_PORTAL_URL env var overrides the default endpoint.
  • Token never appears in any output.
  • Verbose mode shows request URLs and status codes but redacts headers.
  • Cross-platform: macOS, Linux, Windows (PowerShell).
  • CI: lint, typecheck, unit tests, smoke test that runs whoami against the live portal as anon.

Documentation

Out of scope

  • Browser-based OAuth — future, when there's a portal user account system.
  • mzizi publish (component contribution) — future.
  • Per-machine token rotation — future.
  • Telemetry — explicitly never, unless opt-in.

Risks

  • Bundle size. Target < 2 MB compressed. Tsup + tree-shaking; avoid heavy deps.
  • shadcn version drift. Pin shadcn as a peer dep. Document supported range in README.
  • Allow-list provisioning bottleneck. Until a self-service UI exists, new first-party developers need an admin to insert a row. Acceptable for v1; flagged in README.

Sequencing

Can ship in parallel with #80 — the CLI doesn't depend on requires_auth existing, only on whoami (#79) being live so login can verify tokens. If #80 isn't done yet, first-party features still work; they just don't have opt-in components to flex against.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions