Skip to content

feat(help): a --help that works, from the schema (PRD 0006) - #257

Merged
ralyodio merged 1 commit into
mainfrom
feat/help
Aug 3, 2026
Merged

feat(help): a --help that works, from the schema (PRD 0006)#257
ralyodio merged 1 commit into
mainfrom
feat/help

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Implements PRD 0006 (included in this PR as prd/0006-help.md — it was sitting untracked in the working copy, and its 0005 collided with the hosted-resolver PRD that landed meanwhile).

The bug worth leading with

moshcode prd --help published a document. --help was parsed as the PRD's idea, so asking how the command worked ran it: wrote prd/NNNN---help.md, committed it, and handed it to an engine to author. That is literally how PRD 0006's own file got its name.

It wasn't alone. run/mcp/skill/completion answered --help with exit 1; console and install wrote usage to stderr; commands ignored the flag; moshcode bogus dumped 127 lines to stdout, polluting any pipe with a typo in it.

One cause underneath all of it: nothing recognised --help, so every command's own argument parser met it and improvised.

What changed

Help is recognised before dispatch, at every depth, wherever the flag sits among that level's args. No parser ever sees it, so none of them can act on it.

Two boundaries it deliberately doesn't cross:

  • moshcode gh --help still reaches gh byte-for-byte; moshcode help gh answers the wrapper question instead.
  • moshcode run --help is the runner's. After the filename, --help is the script's argv (PRD 0004 R13).

One stream, one code. Asked for → stdout, exit 0. Usage error → that command's own block on stderr, exit 1, never the top-level wall.

The 87-line template literal is deleted, not supplemented. It had already drifted — dns and version were dispatchable, completable, and absent from it, as were every alias and most flags. Help now renders from CORE_CLI_COMMANDS, which the dispatcher and shell completion already share, so a verb that exists is documented by construction. A drift test scrapes cmd === "…" out of the dispatcher and fails when a dispatched command has no schema entry — same shape as the existing completion drift test.

Fits a screen. 21 lines, wrapped at 80 columns (was 127 lines, 28 over-length). --all keeps the full text for people who grep it. --json is the better grep target and the real point: the whole model, for the consumer that is now an agent shelling back in to learn the interface.

Typos get one line: moshcode instaldid you mean install?, drawn from the same command set completion uses so the two can't disagree.

Before / after

$ moshcode prd --help          # before: published and committed a PRD
$ moshcode prd --help          # after:  18 lines of usage, exit 0, nothing written

$ moshcode instal claude       # before: 127 lines to stdout, exit 1
✗ unknown command "instal" — did you mean install?
  moshcode help          list commands

One deliberate contract change

test/help-stream.test.mjs asserted the old behaviour — the full banner on stderr for an unknown verb. R11 replaces that with one line and a pointer, so I updated the assertion: what has to survive a typo is the way forward, not the wall. The test still enforces exit≠0, clean stdout, and now a ≤3-line stderr.

Deferred

Marked P1/P2 in the PRD and not attempted here: the pit's own /help (R12), the README drift test (R13), moshscript verb help (R14), NO_COLOR (R15), completing help topics (R16).

Tests

22 new in test/help.test.mjs, including the no-side-effect ones that spawn the real binary against a temp directory — the bug was in dispatch, so dispatch is what gets exercised.

Full suite: 1073 tests, 861 pass, 0 fail (212 skipped — the pre-existing environment-dependent ones).

🤖 Generated with Claude Code

Asking moshcode how it works could change your repo. `moshcode prd --help`
parsed `--help` as the PRD's idea, so it published prd/NNNN---help.md,
committed it, and handed it to an engine to author — which is how PRD 0006
got its own filename. Four other commands answered --help with exit 1, two
wrote usage to stdout, and `moshcode bogus` dumped 127 lines to *stdout*,
polluting any pipe with a typo in it.

Underneath was one cause: nothing recognised --help, so every command's own
argument parser met it and improvised.

  - Help is recognised before dispatch, at every depth, wherever the flag
    sits among that level's arguments. No parser ever sees it, so no parser
    can act on it. `prd --help` now prints usage and writes nothing; the
    test spawns the real binary against a temp directory and asserts the
    directory is untouched.
  - Two boundaries it does not cross. `moshcode gh --help` still reaches
    gh byte-for-byte, and `moshcode help gh` answers the wrapper question
    instead. `moshcode run --help` is the runner's; after the filename it
    belongs to the script's argv (PRD 0004 R13).
  - One stream, one code: asked for → stdout, exit 0. A usage error → that
    command's own block on stderr, exit 1, never the top-level wall.
  - The 87-line template literal is deleted, not supplemented. It had
    already drifted: `dns` and `version` were dispatchable, completable and
    absent from it, as were every alias and most flags. Help now renders
    from CORE_CLI_COMMANDS, which the dispatcher and shell completion
    already share, so a verb that exists is documented by construction.
  - A drift test scrapes `cmd === "…"` out of the dispatcher and fails when
    a dispatched command has no schema entry — the same shape as the
    existing completion drift test.
  - The overview is 21 lines and wraps at 80 columns (was 127 lines, 28 of
    them over-length). `--all` keeps the full text for people who grep it,
    and `--json` is the better grep target: the whole model, for the
    consumer that is now an agent shelling back in to learn the interface.
  - A typo gets one line and a suggestion — `moshcode instal` → did you
    mean install? — drawn from the same command set completion uses.

test/help-stream.test.mjs asserted the old contract (the full banner on
stderr for an unknown verb). Updated to the new one: the pointer to
`moshcode help` is what has to survive a typo, not the wall.

Deferred, and marked P1/P2 in the PRD: the pit's own /help (R12), the
README drift test (R13), moshscript verb help (R14), NO_COLOR (R15), and
completing help topics (R16).

1073 tests, 861 pass, 0 fail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

vu1nz Security Review

NOT RUNANTHROPIC_API_KEY was not found in the ENV_FILE secret, so no review was performed. This is not a clean result; this diff was not examined.

Add ANTHROPIC_API_KEY=… to the repository's ENV_FILE secret to enable the review.

@ralyodio
ralyodio merged commit 889faf9 into main Aug 3, 2026
3 checks passed
@ralyodio
ralyodio deleted the feat/help branch August 3, 2026 10:49
ralyodio added a commit that referenced this pull request Aug 3, 2026
#263)

The tail of PRD 0006 — R14, R15, R16.

R14. `moshcode help ask` answered "no help for ask". `ask()` is as much
part of the interface as `moshcode prd`, but the vocabulary lives in a
registry help had never been introduced to. Verbs now carry an optional
`usage` — `ai(prompt, { engine })`, `ask(...prompt)` — and help renders it
with the summary and a note that this one is called from a .mosh file, not
a shell. `usage` stays optional, so a verb registered by a host that has
not declared one still renders as `name(…)`.

cliVerb() derives its own signature rather than repeating it twenty times:
every CLI verb forwards its arguments to `moshcode <name>`, so adding a
line to the vocabulary documents it.

R15 turned out to be already true and is now nailed down. src/ui.mjs
gates colour on `NO_COLOR == null && process.stdout.isTTY`, so both the CLI
and the pit already emit plain text to a pipe. Three tests keep it that
way, including one for the pit — which needs spawnSync rather than the
execFile helper the rest of the file uses, because the pit reads stdin and
execFile has no way to supply it. Nothing paginates.

R16. `moshcode help <tab>` now completes topics, in all four shells. The
list is what help itself accepts — commands, engines, tools and moshscript
verbs — so tab-completion and help cannot disagree about what is
answerable. A test asserts exactly that: every offered topic resolves.

1099 tests, 887 pass, 0 fail.

That closes PRD 0006. R1–R16 are implemented across #257, #258, #260 and
this.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
ralyodio added a commit that referenced this pull request Aug 3, 2026
…260)

* docs: generate README's command table from the schema (PRD 0006 R13)

The README described the CLI from memory. Nothing connected its command
listings to the table the dispatcher actually reads, so a renamed verb
stayed documented and a new one stayed invisible — the same drift that had
already happened inside `moshcode help` itself.

Generated rather than checked, which R13 offers as the alternative and is
the better half of it: a checker tells you the README is wrong, a generator
makes it right. `moshcode help --markdown` emits the table, and it goes
between markers in README.md exactly like the PRD index this repo already
maintains, so the convention is one people here already know.

Three tests, in both directions:

  - the table is regenerated and compared, so adding a verb without
    regenerating fails with the command that fixes it;
  - every command named in the table resolves in the schema;
  - every `moshcode <verb>` invoked in a fenced code block anywhere in the
    README is a real command, engine or tool. Scoped to fenced blocks
    because the prose also contains sentences like "moshcode warns you",
    and a grep that cannot tell those apart is a test nobody trusts.

Verified the guard bites: adding a command to the schema without
regenerating fails the suite, and the failure names `moshcode help
--markdown` as the fix.

1089 tests, 877 pass, 0 fail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(help): moshscript verbs, terminal manners, and completable topics (#263)

The tail of PRD 0006 — R14, R15, R16.

R14. `moshcode help ask` answered "no help for ask". `ask()` is as much
part of the interface as `moshcode prd`, but the vocabulary lives in a
registry help had never been introduced to. Verbs now carry an optional
`usage` — `ai(prompt, { engine })`, `ask(...prompt)` — and help renders it
with the summary and a note that this one is called from a .mosh file, not
a shell. `usage` stays optional, so a verb registered by a host that has
not declared one still renders as `name(…)`.

cliVerb() derives its own signature rather than repeating it twenty times:
every CLI verb forwards its arguments to `moshcode <name>`, so adding a
line to the vocabulary documents it.

R15 turned out to be already true and is now nailed down. src/ui.mjs
gates colour on `NO_COLOR == null && process.stdout.isTTY`, so both the CLI
and the pit already emit plain text to a pipe. Three tests keep it that
way, including one for the pit — which needs spawnSync rather than the
execFile helper the rest of the file uses, because the pit reads stdin and
execFile has no way to supply it. Nothing paginates.

R16. `moshcode help <tab>` now completes topics, in all four shells. The
list is what help itself accepts — commands, engines, tools and moshscript
verbs — so tab-completion and help cannot disagree about what is
answerable. A test asserts exactly that: every offered topic resolves.

1099 tests, 887 pass, 0 fail.

That closes PRD 0006. R1–R16 are implemented across #257, #258, #260 and
this.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant