---
openprd: "0.2"
id: "0006"
title: "--help"
status: Draft
authors:
  - anthony@chovy.com
created: 2026-08-01
updated: 2026-08-01
repo: https://github.com/moshcoder/moshcode
discussion:
implementation: src/cli-schema.mjs, src/help.mjs, bin/moshcode.mjs, src/tui.mjs, src/integrations.mjs, src/console.mjs, src/dns.mjs, src/completion.mjs, test/help.test.mjs
tags:
  - cli
  - help
  - dx
  - discoverability
supersedes:
superseded-by:
---

## Problem

`--help` is the first command anyone types and the last one we maintain. In
moshcode today it is a single 87-line template literal — `help()` in
`bin/moshcode.mjs:125-211` — hand-written prose that is neither derived from the
command table nor reachable from anywhere except the top level. Four things are
broken, and one of them writes to disk.

**1. `--help` only works at `argv[2]`.** Every subcommand handles it by accident,
and each accident is different:

| command | today | |
|---|---|---|
| `moshcode prd --help` | **creates `prd/0006---help.md`, commits it, and hands it to Claude to author** | side effect |
| `moshcode run --help` | `moshcode run: unknown option --help`, exit 1 | error |
| `moshcode mcp --help` | `✗ unknown mcp verb "--help" — try install, add, catalog, or list`, exit 1 | error |
| `moshcode skill --help` | `✗ unknown skill verb "--help"`, exit 1 | error |
| `moshcode completion --help` | `unsupported shell "--help"`, exit 1 | error |
| `moshcode console --help` | usage on **stderr**, exit 1 | wrong stream + code |
| `moshcode install --help` | usage on **stderr**, exit 0 | wrong stream |
| `moshcode commands --help` | silently ignores the flag and runs | ignored |
| `moshcode dns --help` | correct usage, stdout, exit 0 | the one that works |

`moshcode prd --help` is the sharp edge: `--help` is parsed as the PRD *idea*, so
asking for help publishes a document. (It is how this PRD's own file got its
title.)

**2. The help text has already drifted from the CLI.** `moshcode dns` and
`moshcode version` are dispatched in `bin/moshcode.mjs` and present in
`CORE_CLI_COMMANDS` (`src/cli-schema.mjs`) and in shell completion — and appear
nowhere in `moshcode help`. Neither do the aliases (`where`, `remove`, `update`,
`skills`, `agent`), nor `uninstall --yes` / `--dry-run`. `src/cli-schema.mjs`
already exists as the structured command table with descriptions, and
`src/completion.mjs` already derives bash/zsh/fish completion from it — help is
the one consumer that re-types everything by hand.

**3. There is no help at any level below the top.** `moshcode help mcp` prints
the same 127-line wall as `moshcode help`. There is no synopsis, no flag list,
and no example for any individual command, so the flags that exist only in code
(`--json`, `--bind`, `--ttyd`, `--max`, `--dry-run`, `--device`, `--browser`,
`--yes`, `--`) are undiscoverable without reading the source.

**4. Failure prints the wall.** `moshcode bogus` dumps all 127 lines — to
**stdout**, so it pollutes pipes — and exits 1, with no "did you mean install?".
28 of those lines exceed 80 columns and wrap badly in a narrow terminal.

The pit has the same problem in a second copy: `printHelp()` in `src/tui.mjs`
hardcodes `/railway /gh /supabase /doppler /doctl /turso /tailscale` immediately
below a `printTools()` whose own comment explains why hardcoding the tool roster
goes stale. `/help` also omits `/logout` and `/uninstall`, and lists no `/dns` or
`/console` because the TUI never implemented them.

This matters now because moshcode's surface just tripled — engines, eleven
workflow tools, MCP/skill fan-out ([[0003-cross-engine-mcp-and-skill-installation]]),
PRDs, `console`, `dns`, and the moshscript vocabulary
([[0004-moshscript-run-programmable-moshcode]]) — and because the primary
consumer of `--help` is now an *agent*. A coding engine driving moshcode reads
`--help` to learn the interface; it gets a wall on stdout, an exit 1, or a
committed PRD.

## Goals

- `--help` is safe, uniform, and total: the same flag works at every level, on
  every command and subcommand, and never changes anything on disk or over the
  network.
- A newcomer can discover any moshcode capability — including every flag — from
  the terminal alone, without opening `README.md` or the source.
- Help text can no longer drift from the CLI, because it is rendered from the
  same schema the dispatcher and shell completion already use.
- An agent can consume the interface mechanically (`--json`) as reliably as it
  consumes `moshcode engines --json` and `moshcode commands --json`.
- Failure is short and actionable: a mistyped command yields one line of
  correction and one usage block, not a screenful.
- The pit and the CLI describe the same product, from one source.

## Non-Goals

- A CLI framework. No commander/yargs/oclif; moshcode's hand-rolled dispatch and
  zero-runtime-dependency posture stay ([[0004-moshscript-run-programmable-moshcode]]).
- Restructuring the command surface. This PRD documents what exists; renaming
  verbs, changing flags, or adding TUI commands (`/dns`, `/console`) is separate
  work. Where help exposes an omission, help notes it — it doesn't fix it.
- Localization / i18n. English, metal, one voice.
- `man` pages, HTML docs, or a docs site. `--markdown` output (R13) is a
  build-time convenience, not a docs pipeline.
- Help for the *wrapped* tools. `moshcode gh --help` is and remains a byte-exact
  passthrough to `gh --help`; moshcode never intercepts a tool's own help.
- Rewriting `README.md` prose. Its command listings become schema-checked; its
  narrative stays hand-written.

## Users

- **The first-run human** who installs moshcode and types `moshcode --help`.
  They need one screen, not 127 lines, and a way to drill in.
- **The returning user** who knows the verb and forgot the flag — "was it
  `--bind` or `--host`?" — and wants `moshcode console --help` to answer in four
  lines.
- **The coding engine** (Claude, Codex, Gemini, opencode, aider) that moshcode
  itself launched, now shelling back into `moshcode --help` to learn what it can
  drive. Structured output, correct exit codes, and stdout/stderr discipline are
  the whole interface for this user.
- **The moshscript author** who needs the vocabulary and its call signatures —
  today split across `moshcode commands`, the tail of `moshcode help`, and
  `README.md`.
- **The contributor** adding an engine, a tool, or a verb, who must not have to
  remember that the roster is written down in five places.

## Requirements

- R1 [P0] `--help`, `-h`, and `help` MUST be recognized *before* any dispatch or
  argument parsing, at every level: `moshcode --help`, `moshcode <cmd> --help`,
  and `moshcode <cmd> <verb> --help` (e.g. `mcp install --help`). Recognition
  MUST NOT depend on flag position among that level's own arguments.
- R2 [P0] Help MUST be free of side effects. `moshcode prd --help` MUST print
  usage and MUST NOT call `createPrd()`, write to `prd/`, git-commit, or spawn an
  engine. A regression test MUST assert `prd/` is unchanged after `prd --help`,
  `prd -h`, and `prd help`. Equivalent no-side-effect assertions MUST cover
  `install`, `uninstall`, `upgrade`, `mcp`, `skill`, `console`, `dns`, and `run`.
- R3 [P0] Stream and exit-code discipline MUST be uniform:
  - help asked for explicitly → **stdout**, exit **0**;
  - help printed because of a usage error → **stderr**, exit **1**, and the
    message MUST be the offending command's own usage block (target: ≤ 12
    lines), never the full top-level wall.
  This fixes `console --help` (stderr/exit 1), `install --help` (stderr), and
  `moshcode bogus` (127 lines to stdout).
- R4 [P0] Per-command help MUST exist for every dispatched command, reachable
  both as `moshcode <cmd> --help` and `moshcode help <cmd>`. Each MUST render:
  one-line description, synopsis with positional arguments, every flag it
  actually parses with its default, at least one runnable example, and a
  `see also` line. Sub-verbs (`mcp install`, `skill list`, `dns enable`,
  `console serve`, `upgrade engines`) MUST each get their own.
- R5 [P0] Help MUST be rendered from a single structured schema, not prose. The
  existing `CORE_CLI_COMMANDS` in `src/cli-schema.mjs` MUST be extended with
  `synopsis`, `args`, `flags`, `examples`, `aliasOf`, and `seeAlso`, and a new
  `src/help.mjs` MUST own rendering. The 87-line template literal at
  `bin/moshcode.mjs:125-211` MUST be deleted, not merely supplemented. Engine and
  tool rosters MUST continue to be derived from `ENGINES` / `TOOLS`, and the
  moshscript vocabulary from `moshVocabulary()`, exactly as `help()` does today.
- R6 [P0] A drift test MUST make missing help a build failure, mirroring the
  existing `completion schema covers every explicitly dispatched CLI command`
  test (`test/completion.test.mjs:71`): every `cmd === "…"` literal in
  `bin/moshcode.mjs`, every entry in `MCP_VERBS` / `SKILL_VERBS` /
  `UPGRADE_TARGETS`, every key of `ENGINES` and `TOOLS`, and every registered
  moshscript verb MUST have a schema entry with a non-empty description.
- R7 [P0] The commands missing from today's help MUST be covered by the schema
  and therefore appear: `dns` (and its `enable`/`disable`/`tlds`/`resolve`
  sub-verbs), `version`, and every alias — `where`→`pwd`, `remove`→`uninstall`,
  `update`→`upgrade`, `skills`→`skill`, `agent`/`engines`→`agents`, `-v`/`-h`.
  Aliases MUST be rendered as aliases, not duplicated as peers.
- R8 [P0] Currently undocumented flags MUST be documented by R4's flag lists, at
  minimum: `--json` (`engines`, `tools`, `commands`, `mcp list`, `skill list`),
  `run --max N|-n N` (default 3), `run --dry-run`, `run --` and `-` for stdin,
  `uninstall --yes|-y` and `--dry-run`, `login --device|-d` and `--browser|-b`,
  `console --port|--ttyd|--bind|--url`, `mcp --name|-t|-e|-H|--`, and
  `dns --port|--registry`.
- R9 [P1] `moshcode help --json` and `moshcode <cmd> --help --json` MUST emit the
  help model as JSON on stdout, exit 0, with no decoration — the same contract
  `engines --json`, `tools --json`, and `commands --json` already honor (and the
  same reason `moshcode tools` suppresses its trailing note under `--json`).
  This is the agent-facing interface.
- R10 [P1] Top-level `moshcode --help` MUST fit one screen: a target of ≤ 40
  lines covering usage, grouped command names with one-line descriptions, and a
  pointer to `moshcode help <command>`. Full output MUST remain available via
  `moshcode help --all`. All rendered help MUST wrap at 80 columns (127 lines
  today, 28 of them over 80).
- R11 [P1] An unrecognized command or sub-verb MUST print, to stderr with exit 1,
  a one-line error, a nearest-match suggestion computed from the schema
  (`moshcode instal` → `did you mean install?`), and a pointer to
  `moshcode help` — instead of the current full-wall dump. The suggestion MUST
  draw on the same command set completion uses, so the two never disagree.
- R12 [P1] The pit MUST render from the same schema. `printHelp()` in
  `src/tui.mjs` MUST stop hardcoding tool names (`/ugig /coinpay /railway /gh
  /supabase /doppler /doctl /turso /tailscale`) and derive them from `TOOLS` as
  `printTools()` already does; `/help <command>` and `/<command> --help` MUST
  work; and `/help` MUST list every dispatched pit command, including the
  currently omitted `/logout` and `/uninstall`. Where a CLI command has no pit
  equivalent (`dns`, `console`, `completion`), `/help` MUST say so rather than
  imply it exists.
- R13 [P1] `README.md`'s command listings MUST be checked against the schema by a
  test (or generated from it via `moshcode help --markdown`), so a new verb
  cannot ship documented in one place and absent in the other.
- R14 [P2] moshscript vocabulary help: `moshcode help <verb>` MUST resolve
  moshscript verbs too (`moshcode help ai`, `help ask`, `help notify`), rendering
  a call signature — `ai(prompt, { engine })` — from an optional `usage` field on
  the registry command object (`src/registry.mjs`), alongside its existing
  `summary`. Verbs without a `usage` fall back to the summary.
- R15 [P2] Rendering MUST respect the terminal: honor `NO_COLOR` and non-TTY
  stdout by emitting plain text (the CLI's `help()` is already plain; the pit's
  is not), and MUST NOT paginate or require a pager.
- R16 [P2] `moshcode completion` MUST offer help topics after `moshcode help `,
  so tab-completion and `help` share the same discoverability surface.

## UX Notes

Top level — one screen, grouped, with a way in (R10):

```
moshcode — metal scripting toolkit 🤘

usage: moshcode [command] [args…]        no command → open the mosh pit

  engines    agents · start · install · uninstall · upgrade · engines
  tools      tools · ugig · coinpay · c0mpute · secrets · gh · railway · …
  extend     mcp · skill · commands · completion
  script     run · prd
  account    login · whoami · logout · console
  system     dns · pwd · version · help

  moshcode help <command>     drill into one (flags, examples)
  moshcode help --all         the whole wall
  moshcode help --json        the machine-readable model

engines are installed and driven by moshcode — 🤘 no bugs, only features
```

Per-command help — the shape every command gets (R4), and the case that today
publishes a document instead:

```
$ moshcode prd --help
moshcode prd — publish the next numbered PRD (OpenPRD) and author it

usage:
  moshcode prd                 list existing PRDs
  moshcode prd <idea…>         publish prd/NNNN-slug.md (status: Draft) and hand
                               it to an installed engine to author

examples:
  moshcode prd                         # the index
  moshcode prd "a --help that works"   # publish + author

see also: moshcode help run · prd/README.md · https://github.com/profullstack/logicsrc/blob/master/docs/openprd.md
```

Failure — short, corrective, on stderr, exit 1 (R3, R11):

```
$ moshcode instal claude
✗ unknown command "instal" — did you mean install?
  moshcode help          list commands
$ echo $?
1
```

Sub-verb help, reachable at depth (R1):

```
$ moshcode mcp install --help
moshcode mcp install — register an MCP server across every engine that supports it

usage:
  moshcode mcp install <url>                     remote server (http/sse)
  moshcode mcp install --name <n> -- <cmd…>      local stdio server
  moshcode mcp install <catalog-name>            e.g. porkbun, sentry

flags:
  --name <n>          override the derived server name
  -t, --transport     http | sse | stdio      (default: inferred from target)
  -e, --env K=V       repeatable
  -H, --header 'K: V' repeatable
  --                  everything after this is the server's argv

fans out to: claude, gemini, codex, opencode   (moshcode mcp list)
```

Constraints that shape all of it: the voice stays irreverent-metal (`the pit`,
`no bugs only features`, 🤘) but never at the cost of scanability — emoji are
decoration on headers, never load-bearing in a synopsis. Help is the one command
guaranteed to run before anything is installed and before anyone has logged in,
so it MUST NOT touch the network, read credentials, or probe for binaries beyond
the local `engineStatus()` / `toolStatus()` checks help already makes. And
because `moshcode run --help` and `./script.mosh --help` are different questions
(the runner's help vs. the script's argv), the runner MUST claim `--help` only
before the script filename; after it, `--help` belongs to the script (`argv`, per
[[0004-moshscript-run-programmable-moshcode]] R13).

## Success Metrics

- **Zero side effects from help.** `prd --help` leaves `git status` clean;
  asserted in tests (R2). This is the one that must be true on day one.
- **Total coverage, enforced.** The R6 drift test passes with an empty allowlist:
  every dispatched command, sub-verb, alias, engine, tool, and moshscript verb
  has help. Adding a command without help fails `pnpm test`.
- **Uniformity.** For all N dispatched commands, `moshcode <cmd> --help` exits 0
  and writes to stdout — today 5 of 9 sampled commands exit 1, and 2 more write
  to stderr.
- **Flag discoverability.** Every flag parsed anywhere in `bin/moshcode.mjs`,
  `src/console.mjs`, `src/dns.mjs`, and `src/integrations.mjs` appears in some
  help output; verified by a test that greps the parsers for flag literals and
  looks each one up in the schema.
- **Fits the screen.** `moshcode --help` ≤ 40 lines and no line over 80 columns
  (127 lines / 28 over-length today); `moshcode help --all` unbounded.
- **Agent-consumable.** `moshcode help --json` parses, and a round-trip test
  confirms every command in the JSON is dispatchable and every dispatched
  command is in the JSON.
- **One source.** `grep -c "usage:" bin/moshcode.mjs src/tui.mjs` trends to 0 as
  the hand-written blocks move into `src/cli-schema.mjs`.
- **README can't drift.** R13's test passes against the committed `README.md`.

## Risks & Open Questions

- **Losing the wall people grep.** `moshcode help | grep console` works today
  precisely *because* everything is on one screen dump. Collapsing to a one-page
  overview (R10) breaks that muscle memory. Mitigation: `moshcode help --all`
  keeps the full text, and `--json` is the better grep target. Open: should
  `--all` be the default when stdout is not a TTY, so pipes keep seeing
  everything?
- **Schema verbosity.** Turning `CORE_CLI_COMMANDS` into full help entries makes
  `src/cli-schema.mjs` the largest file describing the smallest amount of
  behavior, and every new flag becomes a two-place edit (parser + schema).
  R6/R8's tests are what make the second place non-optional — but a test that
  greps parsers for flag literals is itself brittle. Open: is a stricter seam
  worth it, where the schema *is* the parser (each command declares its flags and
  the dispatcher parses from that), or does that quietly become the CLI framework
  this PRD calls a Non-Goal?
- **`moshcode <tool> --help` ambiguity.** `moshcode gh --help` must reach `gh`,
  not moshcode (Non-Goals) — but then there is no way to ask moshcode how *it*
  wraps `gh`. Proposal: `moshcode help gh` answers the wrapper question and
  `moshcode gh --help` passes through. Needs a decision, and it is the single
  most likely source of user confusion in this design.
- **Same ambiguity for engines.** `moshcode claude --help` is a raw launch
  shorthand that will pass `--help` to Claude Code. Same proposed split, same
  risk.
- **`moshcode help` with an unknown topic.** Exit 0 with the overview, or exit 1
  with a suggestion? R11 implies the latter for commands; `help` itself asking a
  question is arguably not an error. Undecided.
- **The pit's missing commands.** R12 exposes that `/dns` and `/console` don't
  exist in the TUI. Saying so in `/help` is honest but reads as a to-do list in
  the product. Do we ship the disclosure, or implement the two commands first
  (out of scope here)?
- **`-h` collisions.** Some wrapped CLIs use `-h` for `--host`. Since moshcode
  claims `-h` only before the tool/engine name (R1), this should be safe — but
  it needs a test per tool, and `console --ttyd host:port` is a reminder that we
  have host-shaped flags of our own.
- **Who owns `--help` inside `moshcode run`?** Stated as a constraint in UX
  Notes, but a shebang script (`./deploy.mosh --help`) currently gets `--help` in
  `argv` with no convention for what to do with it. Should moshscript ship a
  `usage()` verb so scripts can answer for themselves?
