moshcode 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +580 -0
  3. package/bin/moshcode.mjs +674 -0
  4. package/bin/moshscript.mjs +29 -0
  5. package/examples/alive.mosh +6 -0
  6. package/examples/scripting-the-cli.mosh +21 -0
  7. package/examples/team-secrets.mosh +20 -0
  8. package/examples/templates/bun-caddy-sqlite/.env.example +14 -0
  9. package/examples/templates/bun-caddy-sqlite/Caddyfile +18 -0
  10. package/examples/templates/bun-caddy-sqlite/README.md +97 -0
  11. package/examples/templates/bun-caddy-sqlite/deploy/moshcode-dns.service +39 -0
  12. package/examples/templates/bun-caddy-sqlite/deploy/moshpit-service.service +38 -0
  13. package/examples/templates/bun-caddy-sqlite/package.json +15 -0
  14. package/examples/templates/bun-caddy-sqlite/src/db.ts +47 -0
  15. package/examples/templates/bun-caddy-sqlite/src/server.ts +44 -0
  16. package/examples/templates/bun-caddy-sqlite/template.json +10 -0
  17. package/examples/templates/caddy-proxy/Caddyfile +36 -0
  18. package/examples/templates/caddy-proxy/README.md +104 -0
  19. package/examples/templates/caddy-proxy/deploy/moshcode-dns.service +39 -0
  20. package/examples/templates/caddy-proxy/template.json +8 -0
  21. package/examples/templates/caddy-static/Caddyfile +16 -0
  22. package/examples/templates/caddy-static/README.md +90 -0
  23. package/examples/templates/caddy-static/deploy/moshcode-dns.service +39 -0
  24. package/examples/templates/caddy-static/site/index.html +11 -0
  25. package/examples/templates/caddy-static/template.json +8 -0
  26. package/install.sh +194 -0
  27. package/package.json +28 -0
  28. package/prd/0000-template.md +49 -0
  29. package/prd/0001-wrap-ugig-and-coinpay-clis.md +121 -0
  30. package/prd/0002-separate-agent-and-raw-engine-launches.md +113 -0
  31. package/prd/0003-cross-engine-mcp-and-skill-installation.md +165 -0
  32. package/prd/0004-moshscript-run-programmable-moshcode.md +344 -0
  33. package/prd/0005-hosted-moshpit-resolver.md +192 -0
  34. package/prd/0006-help.md +359 -0
  35. package/prd/0007-profullstack-site-init.md +1183 -0
  36. package/prd/README.md +26 -0
  37. package/src/ads.mjs +58 -0
  38. package/src/auth.mjs +193 -0
  39. package/src/cli-schema.mjs +533 -0
  40. package/src/cli.mjs +118 -0
  41. package/src/commands.mjs +259 -0
  42. package/src/completion.mjs +594 -0
  43. package/src/console.mjs +244 -0
  44. package/src/dns-system.mjs +404 -0
  45. package/src/dns.mjs +2872 -0
  46. package/src/doh-server.mjs +256 -0
  47. package/src/doh.mjs +218 -0
  48. package/src/engines.mjs +385 -0
  49. package/src/escalate.mjs +85 -0
  50. package/src/help.mjs +443 -0
  51. package/src/integrations.mjs +265 -0
  52. package/src/mcp-catalog.mjs +50 -0
  53. package/src/mcp.mjs +155 -0
  54. package/src/mirror.mjs +187 -0
  55. package/src/notify.mjs +86 -0
  56. package/src/open-url.mjs +34 -0
  57. package/src/parking-http.mjs +65 -0
  58. package/src/pins.mjs +190 -0
  59. package/src/pit-url.mjs +13 -0
  60. package/src/prd.mjs +341 -0
  61. package/src/pty.mjs +176 -0
  62. package/src/pwd.mjs +103 -0
  63. package/src/registry.mjs +37 -0
  64. package/src/release-install.mjs +191 -0
  65. package/src/runtime.mjs +161 -0
  66. package/src/selfupdate.mjs +215 -0
  67. package/src/serve.mjs +502 -0
  68. package/src/skills.mjs +93 -0
  69. package/src/tabs.mjs +144 -0
  70. package/src/templates.mjs +456 -0
  71. package/src/tools.mjs +231 -0
  72. package/src/trade.mjs +137 -0
  73. package/src/trust.mjs +712 -0
  74. package/src/tui.mjs +736 -0
  75. package/src/ui.mjs +49 -0
  76. package/src/uninstall.mjs +113 -0
  77. package/src/upgrade.mjs +217 -0
@@ -0,0 +1,192 @@
1
+ ---
2
+ openprd: "0.2"
3
+ id: "0005"
4
+ title: A hosted Moshpit resolver, for the devices that cannot run the bridge
5
+ status: Draft
6
+ authors:
7
+ - anthony@chovy.com
8
+ created: 2026-08-01
9
+ updated: 2026-08-01
10
+ repo: https://github.com/moshcoder/moshcode
11
+ discussion:
12
+ implementation: apps/pwa/src/lib/moshpit-resolvers.mjs, apps/pwa/src/routes/moshpit.mjs, src/dns.mjs
13
+ tags:
14
+ - moshpit
15
+ - dns
16
+ - infrastructure
17
+ - privacy
18
+ supersedes:
19
+ superseded-by:
20
+ ---
21
+
22
+ ## Problem
23
+
24
+ A Moshpit ending is not in the ICANN root, so nothing resolves it until the
25
+ client is told something. Today there is exactly one way to be told: run
26
+ `moshcode dns enable`, which installs a local bridge and points the machine's
27
+ resolver at it.
28
+
29
+ That works on a laptop or a VPS. It is unavailable on the devices where most
30
+ people would actually meet a Moshpit name:
31
+
32
+ - a **phone**, which cannot run a daemon or edit `resolved.conf.d`
33
+ - a **router**, where you can set a DNS server and nothing else
34
+ - **someone else's machine** — the person you sent the link to
35
+
36
+ For all of them the only answer is `pit.moshcode.sh/n/<name>`, which fetches the
37
+ origin server-side and hands back the page. It works, and it is not resolution:
38
+ the URL bar reads `pit.moshcode.sh`, not `chovy.hacker`. The name never becomes
39
+ the visitor's address, which is the entire point of holding one.
40
+
41
+ The infrastructure for the missing piece is already half-built and unused.
42
+ `MOSHPIT_DNS_RESOLVERS` and `MOSHPIT_DOH_URL` are read, validated as real
43
+ addresses, and rendered on `/pit/dns` — and both are unset in production, so the
44
+ page publishes nothing. The shop window was built before the shop.
45
+
46
+ This PRD is deliberately **not** a replacement for the local bridge. It is the
47
+ answer for clients that cannot run one, and the difference matters because the
48
+ tradeoff is real and permanent: a hosted resolver sees every DNS query the
49
+ device makes.
50
+
51
+ ## Goals
52
+
53
+ - A Moshpit name resolves on a device that can only be handed a DNS server.
54
+ - The URL bar keeps the name. `http://chovy.hacker/` stays `chovy.hacker`.
55
+ - Non-Moshpit lookups are answered correctly and are not the product.
56
+ - The privacy cost is stated plainly, in the UI, before anyone opts in.
57
+ - An outage degrades to "Moshpit names stop working", never "the internet stops
58
+ working", for as long as that is within our control.
59
+
60
+ ## Non-Goals
61
+
62
+ - **Replacing the local bridge.** Where a bridge can run it stays the better
63
+ answer: no third party sees the queries, no round trip, no shared outage.
64
+ `moshcode dns enable` remains the recommended path and the docs say so.
65
+ - **Being a general-purpose public resolver.** We are not competing with
66
+ 1.1.1.1. Forwarding exists so Moshpit names can resolve, not as a service.
67
+ - **Logging queries for analytics.** See Requirements — this is the one place
68
+ where the tempting feature is the one that kills the product.
69
+ - **DNSSEC-signing the Moshpit zone.** Out of scope for v1; the endings are not
70
+ in the root, so there is no chain to anchor to.
71
+
72
+ ## Users
73
+
74
+ **Someone sent a link.** They open `http://seo.rank/` on a phone. Today: a
75
+ browser error, or a `pit.moshcode.sh` URL. With this: the page, at its own name.
76
+
77
+ **A household or office.** One DNS setting on the router, and every device on
78
+ the network resolves Moshpit names with nothing installed on any of them.
79
+
80
+ **A name holder demonstrating one.** The reason to hold `chovy.hacker` is that
81
+ it is an address you can give people. Today giving it away requires asking them
82
+ to install software first.
83
+
84
+ ## Requirements
85
+
86
+ ### R1 — Two protocols, both public
87
+
88
+ `Do53` (plain UDP/TCP 53) for routers and OS settings, and **DNS-over-HTTPS**
89
+ for phones and browsers, which increasingly will not accept anything else.
90
+ iOS and Android both accept a DoH profile; neither will run our daemon.
91
+
92
+ DoH is the one that unlocks phones, so it is not optional.
93
+
94
+ ### R2 — Anycast or nothing
95
+
96
+ A single box is a single point of failure for the DNS of every device pointed
97
+ at it. If the deployment cannot be multi-region behind one address, this ships
98
+ as "best effort, do not set it as your only resolver" and says so in the UI.
99
+
100
+ ### R3 — Forwarding is the dangerous part
101
+
102
+ The resolver answers Moshpit endings from the registry and forwards everything
103
+ else. That forwarding is what makes it usable as a device's only DNS server —
104
+ and what makes it a privacy problem, a latency tax, and a shared outage.
105
+
106
+ Three requirements follow, and R3.3 is the one worth arguing about:
107
+
108
+ - **R3.1** — the claimed-ending gate from `isOurs` applies here identically.
109
+ `google.com` has two labels exactly like `blue.eggs`; only an ending someone
110
+ has actually claimed is ours. An unknown ending set means *not* ours.
111
+ - **R3.2** — forwarded answers are relayed unmodified. No injected records, no
112
+ rewritten NXDOMAIN, no "helpful" search page. The moment a resolver edits
113
+ answers it is spyware with a nice landing page.
114
+ - **R3.3** — **no query logging beyond aggregate counters.** No per-query
115
+ storage of name, source address, or the pair. This is the requirement that
116
+ will be under pressure the first time someone asks "which endings are people
117
+ looking up?" — and the honest answer is that we cannot know without becoming
118
+ the thing the local bridge exists to avoid. Counters (queries/sec, hit rate,
119
+ error rate) are fine. The tuple is not.
120
+
121
+ ### R4 — Say the cost before the click
122
+
123
+ `/pit/dns` publishes the addresses. It must also state, in the same visual
124
+ weight as the addresses themselves:
125
+
126
+ > This resolver sees every DNS lookup your device makes, not just Moshpit ones.
127
+ > If you can run `moshcode dns enable`, do that instead — it keeps your lookups
128
+ > on your own machine.
129
+
130
+ A page that lists an IP with no context gets pasted into a router by someone who
131
+ has not thought about it. That is the failure mode to design against.
132
+
133
+ ### R5 — Reuse the bridge, do not fork it
134
+
135
+ The hosted resolver is the same code as `src/dns.mjs` with upstreams
136
+ configured, deployed. The forwarding, the ending gate, the NODATA/NXDOMAIN
137
+ distinction and the AAAA support all already exist and are tested. A second
138
+ implementation would drift from the first, which is the failure this codebase
139
+ has already had five times over with one regex.
140
+
141
+ ### R6 — Never the default
142
+
143
+ Nothing in `moshcode dns enable`, the CLI, or the extension silently points at
144
+ the hosted resolver. It is a documented address a person chooses to use. A
145
+ resolver that installs itself as your DNS without asking is malware behaviour
146
+ regardless of intent.
147
+
148
+ ## UX Notes
149
+
150
+ `/pit/dns` already renders `.pit-addrs` cards for published resolvers, so the
151
+ page work is mostly copy plus the DoH URL. The order should be:
152
+
153
+ 1. **`moshcode dns enable`** — recommended, keeps lookups local
154
+ 2. **`pit.moshcode.sh/n/<name>`** — works with nothing installed, URL changes
155
+ 3. **the hosted resolver** — for devices that cannot do (1), with R4's warning
156
+
157
+ Today the page has only (1) and publishes nothing for (3).
158
+
159
+ ## Success Metrics
160
+
161
+ - A stock phone, given only a DoH profile, loads `http://chovy.hacker/` with
162
+ `chovy.hacker` in the URL bar.
163
+ - Resolver p50 latency for a forwarded (non-Moshpit) query stays within ~10ms of
164
+ the device's previous resolver, or the tax is visible enough that people turn
165
+ it off.
166
+ - Zero per-query records in storage, demonstrable from the deployment config
167
+ rather than from a policy document.
168
+
169
+ ## Risks & Open Questions
170
+
171
+ **The privacy tradeoff is not fixable, only disclosed.** Anyone using this hands
172
+ us their full DNS history. R3.3 and R4 are mitigations, not solutions. If that
173
+ is unacceptable, the honest outcome is to not ship this and leave `/n/` as the
174
+ answer for phones.
175
+
176
+ **Shared outage.** A device with this as its only DNS server loses the whole
177
+ internet when we go down, not just Moshpit names. R2 exists for this and may
178
+ well be the reason to delay.
179
+
180
+ **Abuse.** An open forwarding resolver is a DDoS amplifier. Rate limiting and
181
+ response-size limits are required before anything is published, and this is not
182
+ optional or deferrable — an open resolver is found by scanners in hours.
183
+
184
+ **Does the demand exist?** The cheapest version of this experiment is to publish
185
+ nothing and instead measure how often `/n/` is loaded from mobile user agents.
186
+ If nobody is meeting Moshpit names on phones, this is infrastructure and risk
187
+ bought for an audience that is not there.
188
+
189
+ **Open:** does the ending gate consult the registry per query, or hold a cached
190
+ ending set refreshed on an interval? Per query is simpler and always current;
191
+ cached is faster and survives a registry outage. The local bridge faces the same
192
+ choice and has not resolved it either.
@@ -0,0 +1,359 @@
1
+ ---
2
+ openprd: "0.2"
3
+ id: "0006"
4
+ title: "--help"
5
+ status: Draft
6
+ authors:
7
+ - anthony@chovy.com
8
+ created: 2026-08-01
9
+ updated: 2026-08-01
10
+ repo: https://github.com/moshcoder/moshcode
11
+ discussion:
12
+ 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
13
+ tags:
14
+ - cli
15
+ - help
16
+ - dx
17
+ - discoverability
18
+ supersedes:
19
+ superseded-by:
20
+ ---
21
+
22
+ ## Problem
23
+
24
+ `--help` is the first command anyone types and the last one we maintain. In
25
+ moshcode today it is a single 87-line template literal — `help()` in
26
+ `bin/moshcode.mjs:125-211` — hand-written prose that is neither derived from the
27
+ command table nor reachable from anywhere except the top level. Four things are
28
+ broken, and one of them writes to disk.
29
+
30
+ **1. `--help` only works at `argv[2]`.** Every subcommand handles it by accident,
31
+ and each accident is different:
32
+
33
+ | command | today | |
34
+ |---|---|---|
35
+ | `moshcode prd --help` | **creates `prd/0006---help.md`, commits it, and hands it to Claude to author** | side effect |
36
+ | `moshcode run --help` | `moshcode run: unknown option --help`, exit 1 | error |
37
+ | `moshcode mcp --help` | `✗ unknown mcp verb "--help" — try install, add, catalog, or list`, exit 1 | error |
38
+ | `moshcode skill --help` | `✗ unknown skill verb "--help"`, exit 1 | error |
39
+ | `moshcode completion --help` | `unsupported shell "--help"`, exit 1 | error |
40
+ | `moshcode console --help` | usage on **stderr**, exit 1 | wrong stream + code |
41
+ | `moshcode install --help` | usage on **stderr**, exit 0 | wrong stream |
42
+ | `moshcode commands --help` | silently ignores the flag and runs | ignored |
43
+ | `moshcode dns --help` | correct usage, stdout, exit 0 | the one that works |
44
+
45
+ `moshcode prd --help` is the sharp edge: `--help` is parsed as the PRD *idea*, so
46
+ asking for help publishes a document. (It is how this PRD's own file got its
47
+ title.)
48
+
49
+ **2. The help text has already drifted from the CLI.** `moshcode dns` and
50
+ `moshcode version` are dispatched in `bin/moshcode.mjs` and present in
51
+ `CORE_CLI_COMMANDS` (`src/cli-schema.mjs`) and in shell completion — and appear
52
+ nowhere in `moshcode help`. Neither do the aliases (`where`, `remove`, `update`,
53
+ `skills`, `agent`), nor `uninstall --yes` / `--dry-run`. `src/cli-schema.mjs`
54
+ already exists as the structured command table with descriptions, and
55
+ `src/completion.mjs` already derives bash/zsh/fish completion from it — help is
56
+ the one consumer that re-types everything by hand.
57
+
58
+ **3. There is no help at any level below the top.** `moshcode help mcp` prints
59
+ the same 127-line wall as `moshcode help`. There is no synopsis, no flag list,
60
+ and no example for any individual command, so the flags that exist only in code
61
+ (`--json`, `--bind`, `--ttyd`, `--max`, `--dry-run`, `--device`, `--browser`,
62
+ `--yes`, `--`) are undiscoverable without reading the source.
63
+
64
+ **4. Failure prints the wall.** `moshcode bogus` dumps all 127 lines — to
65
+ **stdout**, so it pollutes pipes — and exits 1, with no "did you mean install?".
66
+ 28 of those lines exceed 80 columns and wrap badly in a narrow terminal.
67
+
68
+ The pit has the same problem in a second copy: `printHelp()` in `src/tui.mjs`
69
+ hardcodes `/railway /gh /supabase /doppler /doctl /turso /tailscale` immediately
70
+ below a `printTools()` whose own comment explains why hardcoding the tool roster
71
+ goes stale. `/help` also omits `/logout` and `/uninstall`, and lists no `/dns` or
72
+ `/console` because the TUI never implemented them.
73
+
74
+ This matters now because moshcode's surface just tripled — engines, eleven
75
+ workflow tools, MCP/skill fan-out ([[0003-cross-engine-mcp-and-skill-installation]]),
76
+ PRDs, `console`, `dns`, and the moshscript vocabulary
77
+ ([[0004-moshscript-run-programmable-moshcode]]) — and because the primary
78
+ consumer of `--help` is now an *agent*. A coding engine driving moshcode reads
79
+ `--help` to learn the interface; it gets a wall on stdout, an exit 1, or a
80
+ committed PRD.
81
+
82
+ ## Goals
83
+
84
+ - `--help` is safe, uniform, and total: the same flag works at every level, on
85
+ every command and subcommand, and never changes anything on disk or over the
86
+ network.
87
+ - A newcomer can discover any moshcode capability — including every flag — from
88
+ the terminal alone, without opening `README.md` or the source.
89
+ - Help text can no longer drift from the CLI, because it is rendered from the
90
+ same schema the dispatcher and shell completion already use.
91
+ - An agent can consume the interface mechanically (`--json`) as reliably as it
92
+ consumes `moshcode engines --json` and `moshcode commands --json`.
93
+ - Failure is short and actionable: a mistyped command yields one line of
94
+ correction and one usage block, not a screenful.
95
+ - The pit and the CLI describe the same product, from one source.
96
+
97
+ ## Non-Goals
98
+
99
+ - A CLI framework. No commander/yargs/oclif; moshcode's hand-rolled dispatch and
100
+ zero-runtime-dependency posture stay ([[0004-moshscript-run-programmable-moshcode]]).
101
+ - Restructuring the command surface. This PRD documents what exists; renaming
102
+ verbs, changing flags, or adding TUI commands (`/dns`, `/console`) is separate
103
+ work. Where help exposes an omission, help notes it — it doesn't fix it.
104
+ - Localization / i18n. English, metal, one voice.
105
+ - `man` pages, HTML docs, or a docs site. `--markdown` output (R13) is a
106
+ build-time convenience, not a docs pipeline.
107
+ - Help for the *wrapped* tools. `moshcode gh --help` is and remains a byte-exact
108
+ passthrough to `gh --help`; moshcode never intercepts a tool's own help.
109
+ - Rewriting `README.md` prose. Its command listings become schema-checked; its
110
+ narrative stays hand-written.
111
+
112
+ ## Users
113
+
114
+ - **The first-run human** who installs moshcode and types `moshcode --help`.
115
+ They need one screen, not 127 lines, and a way to drill in.
116
+ - **The returning user** who knows the verb and forgot the flag — "was it
117
+ `--bind` or `--host`?" — and wants `moshcode console --help` to answer in four
118
+ lines.
119
+ - **The coding engine** (Claude, Codex, Gemini, opencode, aider) that moshcode
120
+ itself launched, now shelling back into `moshcode --help` to learn what it can
121
+ drive. Structured output, correct exit codes, and stdout/stderr discipline are
122
+ the whole interface for this user.
123
+ - **The moshscript author** who needs the vocabulary and its call signatures —
124
+ today split across `moshcode commands`, the tail of `moshcode help`, and
125
+ `README.md`.
126
+ - **The contributor** adding an engine, a tool, or a verb, who must not have to
127
+ remember that the roster is written down in five places.
128
+
129
+ ## Requirements
130
+
131
+ - R1 [P0] `--help`, `-h`, and `help` MUST be recognized *before* any dispatch or
132
+ argument parsing, at every level: `moshcode --help`, `moshcode <cmd> --help`,
133
+ and `moshcode <cmd> <verb> --help` (e.g. `mcp install --help`). Recognition
134
+ MUST NOT depend on flag position among that level's own arguments.
135
+ - R2 [P0] Help MUST be free of side effects. `moshcode prd --help` MUST print
136
+ usage and MUST NOT call `createPrd()`, write to `prd/`, git-commit, or spawn an
137
+ engine. A regression test MUST assert `prd/` is unchanged after `prd --help`,
138
+ `prd -h`, and `prd help`. Equivalent no-side-effect assertions MUST cover
139
+ `install`, `uninstall`, `upgrade`, `mcp`, `skill`, `console`, `dns`, and `run`.
140
+ - R3 [P0] Stream and exit-code discipline MUST be uniform:
141
+ - help asked for explicitly → **stdout**, exit **0**;
142
+ - help printed because of a usage error → **stderr**, exit **1**, and the
143
+ message MUST be the offending command's own usage block (target: ≤ 12
144
+ lines), never the full top-level wall.
145
+ This fixes `console --help` (stderr/exit 1), `install --help` (stderr), and
146
+ `moshcode bogus` (127 lines to stdout).
147
+ - R4 [P0] Per-command help MUST exist for every dispatched command, reachable
148
+ both as `moshcode <cmd> --help` and `moshcode help <cmd>`. Each MUST render:
149
+ one-line description, synopsis with positional arguments, every flag it
150
+ actually parses with its default, at least one runnable example, and a
151
+ `see also` line. Sub-verbs (`mcp install`, `skill list`, `dns enable`,
152
+ `console serve`, `upgrade engines`) MUST each get their own.
153
+ - R5 [P0] Help MUST be rendered from a single structured schema, not prose. The
154
+ existing `CORE_CLI_COMMANDS` in `src/cli-schema.mjs` MUST be extended with
155
+ `synopsis`, `args`, `flags`, `examples`, `aliasOf`, and `seeAlso`, and a new
156
+ `src/help.mjs` MUST own rendering. The 87-line template literal at
157
+ `bin/moshcode.mjs:125-211` MUST be deleted, not merely supplemented. Engine and
158
+ tool rosters MUST continue to be derived from `ENGINES` / `TOOLS`, and the
159
+ moshscript vocabulary from `moshVocabulary()`, exactly as `help()` does today.
160
+ - R6 [P0] A drift test MUST make missing help a build failure, mirroring the
161
+ existing `completion schema covers every explicitly dispatched CLI command`
162
+ test (`test/completion.test.mjs:71`): every `cmd === "…"` literal in
163
+ `bin/moshcode.mjs`, every entry in `MCP_VERBS` / `SKILL_VERBS` /
164
+ `UPGRADE_TARGETS`, every key of `ENGINES` and `TOOLS`, and every registered
165
+ moshscript verb MUST have a schema entry with a non-empty description.
166
+ - R7 [P0] The commands missing from today's help MUST be covered by the schema
167
+ and therefore appear: `dns` (and its `enable`/`disable`/`tlds`/`resolve`
168
+ sub-verbs), `version`, and every alias — `where`→`pwd`, `remove`→`uninstall`,
169
+ `update`→`upgrade`, `skills`→`skill`, `agent`/`engines`→`agents`, `-v`/`-h`.
170
+ Aliases MUST be rendered as aliases, not duplicated as peers.
171
+ - R8 [P0] Currently undocumented flags MUST be documented by R4's flag lists, at
172
+ minimum: `--json` (`engines`, `tools`, `commands`, `mcp list`, `skill list`),
173
+ `run --max N|-n N` (default 3), `run --dry-run`, `run --` and `-` for stdin,
174
+ `uninstall --yes|-y` and `--dry-run`, `login --device|-d` and `--browser|-b`,
175
+ `console --port|--ttyd|--bind|--url`, `mcp --name|-t|-e|-H|--`, and
176
+ `dns --port|--registry`.
177
+ - R9 [P1] `moshcode help --json` and `moshcode <cmd> --help --json` MUST emit the
178
+ help model as JSON on stdout, exit 0, with no decoration — the same contract
179
+ `engines --json`, `tools --json`, and `commands --json` already honor (and the
180
+ same reason `moshcode tools` suppresses its trailing note under `--json`).
181
+ This is the agent-facing interface.
182
+ - R10 [P1] Top-level `moshcode --help` MUST fit one screen: a target of ≤ 40
183
+ lines covering usage, grouped command names with one-line descriptions, and a
184
+ pointer to `moshcode help <command>`. Full output MUST remain available via
185
+ `moshcode help --all`. All rendered help MUST wrap at 80 columns (127 lines
186
+ today, 28 of them over 80).
187
+ - R11 [P1] An unrecognized command or sub-verb MUST print, to stderr with exit 1,
188
+ a one-line error, a nearest-match suggestion computed from the schema
189
+ (`moshcode instal` → `did you mean install?`), and a pointer to
190
+ `moshcode help` — instead of the current full-wall dump. The suggestion MUST
191
+ draw on the same command set completion uses, so the two never disagree.
192
+ - R12 [P1] The pit MUST render from the same schema. `printHelp()` in
193
+ `src/tui.mjs` MUST stop hardcoding tool names (`/ugig /coinpay /railway /gh
194
+ /supabase /doppler /doctl /turso /tailscale`) and derive them from `TOOLS` as
195
+ `printTools()` already does; `/help <command>` and `/<command> --help` MUST
196
+ work; and `/help` MUST list every dispatched pit command, including the
197
+ currently omitted `/logout` and `/uninstall`. Where a CLI command has no pit
198
+ equivalent (`dns`, `console`, `completion`), `/help` MUST say so rather than
199
+ imply it exists.
200
+ - R13 [P1] `README.md`'s command listings MUST be checked against the schema by a
201
+ test (or generated from it via `moshcode help --markdown`), so a new verb
202
+ cannot ship documented in one place and absent in the other.
203
+ - R14 [P2] moshscript vocabulary help: `moshcode help <verb>` MUST resolve
204
+ moshscript verbs too (`moshcode help ai`, `help ask`, `help notify`), rendering
205
+ a call signature — `ai(prompt, { engine })` — from an optional `usage` field on
206
+ the registry command object (`src/registry.mjs`), alongside its existing
207
+ `summary`. Verbs without a `usage` fall back to the summary.
208
+ - R15 [P2] Rendering MUST respect the terminal: honor `NO_COLOR` and non-TTY
209
+ stdout by emitting plain text (the CLI's `help()` is already plain; the pit's
210
+ is not), and MUST NOT paginate or require a pager.
211
+ - R16 [P2] `moshcode completion` MUST offer help topics after `moshcode help `,
212
+ so tab-completion and `help` share the same discoverability surface.
213
+
214
+ ## UX Notes
215
+
216
+ Top level — one screen, grouped, with a way in (R10):
217
+
218
+ ```
219
+ moshcode — metal scripting toolkit 🤘
220
+
221
+ usage: moshcode [command] [args…] no command → open the mosh pit
222
+
223
+ engines agents · start · install · uninstall · upgrade · engines
224
+ tools tools · ugig · coinpay · c0mpute · secrets · gh · railway · …
225
+ extend mcp · skill · commands · completion
226
+ script run · prd
227
+ account login · whoami · logout · console
228
+ system dns · pwd · version · help
229
+
230
+ moshcode help <command> drill into one (flags, examples)
231
+ moshcode help --all the whole wall
232
+ moshcode help --json the machine-readable model
233
+
234
+ engines are installed and driven by moshcode — 🤘 no bugs, only features
235
+ ```
236
+
237
+ Per-command help — the shape every command gets (R4), and the case that today
238
+ publishes a document instead:
239
+
240
+ ```
241
+ $ moshcode prd --help
242
+ moshcode prd — publish the next numbered PRD (OpenPRD) and author it
243
+
244
+ usage:
245
+ moshcode prd list existing PRDs
246
+ moshcode prd <idea…> publish prd/NNNN-slug.md (status: Draft) and hand
247
+ it to an installed engine to author
248
+
249
+ examples:
250
+ moshcode prd # the index
251
+ moshcode prd "a --help that works" # publish + author
252
+
253
+ see also: moshcode help run · prd/README.md · https://github.com/profullstack/logicsrc/blob/master/docs/openprd.md
254
+ ```
255
+
256
+ Failure — short, corrective, on stderr, exit 1 (R3, R11):
257
+
258
+ ```
259
+ $ moshcode instal claude
260
+ ✗ unknown command "instal" — did you mean install?
261
+ moshcode help list commands
262
+ $ echo $?
263
+ 1
264
+ ```
265
+
266
+ Sub-verb help, reachable at depth (R1):
267
+
268
+ ```
269
+ $ moshcode mcp install --help
270
+ moshcode mcp install — register an MCP server across every engine that supports it
271
+
272
+ usage:
273
+ moshcode mcp install <url> remote server (http/sse)
274
+ moshcode mcp install --name <n> -- <cmd…> local stdio server
275
+ moshcode mcp install <catalog-name> e.g. porkbun, sentry
276
+
277
+ flags:
278
+ --name <n> override the derived server name
279
+ -t, --transport http | sse | stdio (default: inferred from target)
280
+ -e, --env K=V repeatable
281
+ -H, --header 'K: V' repeatable
282
+ -- everything after this is the server's argv
283
+
284
+ fans out to: claude, gemini, codex, opencode (moshcode mcp list)
285
+ ```
286
+
287
+ Constraints that shape all of it: the voice stays irreverent-metal (`the pit`,
288
+ `no bugs only features`, 🤘) but never at the cost of scanability — emoji are
289
+ decoration on headers, never load-bearing in a synopsis. Help is the one command
290
+ guaranteed to run before anything is installed and before anyone has logged in,
291
+ so it MUST NOT touch the network, read credentials, or probe for binaries beyond
292
+ the local `engineStatus()` / `toolStatus()` checks help already makes. And
293
+ because `moshcode run --help` and `./script.mosh --help` are different questions
294
+ (the runner's help vs. the script's argv), the runner MUST claim `--help` only
295
+ before the script filename; after it, `--help` belongs to the script (`argv`, per
296
+ [[0004-moshscript-run-programmable-moshcode]] R13).
297
+
298
+ ## Success Metrics
299
+
300
+ - **Zero side effects from help.** `prd --help` leaves `git status` clean;
301
+ asserted in tests (R2). This is the one that must be true on day one.
302
+ - **Total coverage, enforced.** The R6 drift test passes with an empty allowlist:
303
+ every dispatched command, sub-verb, alias, engine, tool, and moshscript verb
304
+ has help. Adding a command without help fails `pnpm test`.
305
+ - **Uniformity.** For all N dispatched commands, `moshcode <cmd> --help` exits 0
306
+ and writes to stdout — today 5 of 9 sampled commands exit 1, and 2 more write
307
+ to stderr.
308
+ - **Flag discoverability.** Every flag parsed anywhere in `bin/moshcode.mjs`,
309
+ `src/console.mjs`, `src/dns.mjs`, and `src/integrations.mjs` appears in some
310
+ help output; verified by a test that greps the parsers for flag literals and
311
+ looks each one up in the schema.
312
+ - **Fits the screen.** `moshcode --help` ≤ 40 lines and no line over 80 columns
313
+ (127 lines / 28 over-length today); `moshcode help --all` unbounded.
314
+ - **Agent-consumable.** `moshcode help --json` parses, and a round-trip test
315
+ confirms every command in the JSON is dispatchable and every dispatched
316
+ command is in the JSON.
317
+ - **One source.** `grep -c "usage:" bin/moshcode.mjs src/tui.mjs` trends to 0 as
318
+ the hand-written blocks move into `src/cli-schema.mjs`.
319
+ - **README can't drift.** R13's test passes against the committed `README.md`.
320
+
321
+ ## Risks & Open Questions
322
+
323
+ - **Losing the wall people grep.** `moshcode help | grep console` works today
324
+ precisely *because* everything is on one screen dump. Collapsing to a one-page
325
+ overview (R10) breaks that muscle memory. Mitigation: `moshcode help --all`
326
+ keeps the full text, and `--json` is the better grep target. Open: should
327
+ `--all` be the default when stdout is not a TTY, so pipes keep seeing
328
+ everything?
329
+ - **Schema verbosity.** Turning `CORE_CLI_COMMANDS` into full help entries makes
330
+ `src/cli-schema.mjs` the largest file describing the smallest amount of
331
+ behavior, and every new flag becomes a two-place edit (parser + schema).
332
+ R6/R8's tests are what make the second place non-optional — but a test that
333
+ greps parsers for flag literals is itself brittle. Open: is a stricter seam
334
+ worth it, where the schema *is* the parser (each command declares its flags and
335
+ the dispatcher parses from that), or does that quietly become the CLI framework
336
+ this PRD calls a Non-Goal?
337
+ - **`moshcode <tool> --help` ambiguity.** `moshcode gh --help` must reach `gh`,
338
+ not moshcode (Non-Goals) — but then there is no way to ask moshcode how *it*
339
+ wraps `gh`. Proposal: `moshcode help gh` answers the wrapper question and
340
+ `moshcode gh --help` passes through. Needs a decision, and it is the single
341
+ most likely source of user confusion in this design.
342
+ - **Same ambiguity for engines.** `moshcode claude --help` is a raw launch
343
+ shorthand that will pass `--help` to Claude Code. Same proposed split, same
344
+ risk.
345
+ - **`moshcode help` with an unknown topic.** Exit 0 with the overview, or exit 1
346
+ with a suggestion? R11 implies the latter for commands; `help` itself asking a
347
+ question is arguably not an error. Undecided.
348
+ - **The pit's missing commands.** R12 exposes that `/dns` and `/console` don't
349
+ exist in the TUI. Saying so in `/help` is honest but reads as a to-do list in
350
+ the product. Do we ship the disclosure, or implement the two commands first
351
+ (out of scope here)?
352
+ - **`-h` collisions.** Some wrapped CLIs use `-h` for `--host`. Since moshcode
353
+ claims `-h` only before the tool/engine name (R1), this should be safe — but
354
+ it needs a test per tool, and `console --ttyd host:port` is a reminder that we
355
+ have host-shaped flags of our own.
356
+ - **Who owns `--help` inside `moshcode run`?** Stated as a constraint in UX
357
+ Notes, but a shebang script (`./deploy.mosh --help`) currently gets `--help` in
358
+ `argv` with no convention for what to do with it. Should moshscript ship a
359
+ `usage()` verb so scripts can answer for themselves?