Symptom in cargo-hauler
ScriptedAlchemy/cargo-hauler#47 — an agent ran the routed CLI with an out-of-range flag, hauler await cc-3178 --max-wait-ms 300000, and got:
[ { "origin": "number", "code": "too_big", "maximum": 55000, "inclusive": true, "path": ["maxWaitMs"], "message": "Too big: expected number to be <=55000" } ]
Run 'cargo-hauler await --help' for usage.
That is ZodError.message (zod 4 serialises the issues array as JSON) printed verbatim. The reporter's ask: "print the cap in plain words, not the raw zod payload — an agent reading "too_big" maximum 55000 has to guess that it's milliseconds and that the fix is to loop." Every routed CLI generated by agent-bundle has this failure mode for every schema violation; the route author cannot intercept it.
Root cause in agent-bundle (main 10a98a0fb)
packages/agent-bundle/src/build/entry-shell.ts:292-298 — the generated bin's parseInput does route.module.inputSchema.parse(input) and rethrows new CliInputError(error.message); for a ZodError that message is the JSON issues array.
packages/agent-bundle/src/cli-entry.ts:684-689 — runGeneratedCliEntry writes error.message to stderr followed by Run '<name> <path> --help' for usage. and exits 2. Nothing formats issues.
- The same pattern is duplicated in
packages/agent-bundle/src/test/cli.ts:236 and packages/agent-bundle/src/test/render.ts:747, so the test harness shows the same raw text.
zod@4.5.4 (already a dependency of both packages) ships z.prettifyError(error) / z.treeifyError, which render ✖ Too big: expected number to be <=55000 → at maxWaitMs.
Workaround currently in cargo-hauler
None possible at the route level; the schema .max(awaitMaxWaitMs) at src/lib/protocol-schemas.ts:361-366 is what the generated CLI reports. cargo-hauler mitigates by repeating the ceiling in the flag description (src/cli/await.tsx:31-33), which only helps if the agent reads --help.
Proposed fix
- In
entry-shell.ts parseInput (and the two harness copies), detect ZodError (error instanceof z.ZodError or 'issues' in error) and build the CliInputError message from the issues: one line per issue, --flag-name: <issue.message> using the CLI's kebab-case spelling of path (the generated command already knows the flag ↔ field mapping), followed by the existing Run … --help hint. Fall back to z.prettifyError when the path cannot be mapped.
- Keep exit code 2 and the
--json/--ndjson machine modes unchanged (or emit the issues array as JSON only in those modes).
- Document the error shape in
website/docs/{en,zh}/guide/authoring/cli* (routed CLI section).
Acceptance
<bin> await x --max-wait-ms 300000 prints --max-wait-ms: Too big: expected number to be <=55000 (or equivalent prose) plus the usage hint; no [ { "origin": … on stderr.
- Multiple issues print one line each; the
path is rendered as the CLI flag, not a JSON pointer.
runCliCommand in agent-bundle/test returns the same formatted text so plugin tests can assert on it.
Symptom in cargo-hauler
ScriptedAlchemy/cargo-hauler#47 — an agent ran the routed CLI with an out-of-range flag,
hauler await cc-3178 --max-wait-ms 300000, and got:That is
ZodError.message(zod 4 serialises the issues array as JSON) printed verbatim. The reporter's ask: "print the cap in plain words, not the raw zod payload — an agent reading"too_big" maximum 55000has to guess that it's milliseconds and that the fix is to loop." Every routed CLI generated by agent-bundle has this failure mode for every schema violation; the route author cannot intercept it.Root cause in agent-bundle (main
10a98a0fb)packages/agent-bundle/src/build/entry-shell.ts:292-298— the generated bin'sparseInputdoesroute.module.inputSchema.parse(input)and rethrowsnew CliInputError(error.message); for aZodErrorthat message is the JSON issues array.packages/agent-bundle/src/cli-entry.ts:684-689—runGeneratedCliEntrywriteserror.messageto stderr followed byRun '<name> <path> --help' for usage.and exits 2. Nothing formats issues.packages/agent-bundle/src/test/cli.ts:236andpackages/agent-bundle/src/test/render.ts:747, so the test harness shows the same raw text.zod@4.5.4(already a dependency of both packages) shipsz.prettifyError(error)/z.treeifyError, which render✖ Too big: expected number to be <=55000 → at maxWaitMs.Workaround currently in cargo-hauler
None possible at the route level; the schema
.max(awaitMaxWaitMs)atsrc/lib/protocol-schemas.ts:361-366is what the generated CLI reports. cargo-hauler mitigates by repeating the ceiling in the flag description (src/cli/await.tsx:31-33), which only helps if the agent reads--help.Proposed fix
entry-shell.tsparseInput(and the two harness copies), detectZodError(error instanceof z.ZodErroror'issues' in error) and build theCliInputErrormessage from the issues: one line per issue,--flag-name: <issue.message>using the CLI's kebab-case spelling ofpath(the generated command already knows the flag ↔ field mapping), followed by the existingRun … --helphint. Fall back toz.prettifyErrorwhen the path cannot be mapped.--json/--ndjsonmachine modes unchanged (or emit the issues array as JSON only in those modes).website/docs/{en,zh}/guide/authoring/cli*(routed CLI section).Acceptance
<bin> await x --max-wait-ms 300000prints--max-wait-ms: Too big: expected number to be <=55000(or equivalent prose) plus the usage hint; no[ { "origin": …on stderr.pathis rendered as the CLI flag, not a JSON pointer.runCliCommandinagent-bundle/testreturns the same formatted text so plugin tests can assert on it.