Repository navigation
Description
Summary
When an extension registers an importer/exporter with only a handler —
api.registerImporter("todos", handler) — and omits the optional third
options argument ({ arguments, flags, description, ... }), the derived
<name> import / <name> export command is completely unusable from the CLI,
even though the handler reads ctx.args[0] and ctx.options.* and works fine
through the SDK/MCP action path. Nothing warns the author, and the runtime
errors give an agent no actionable hint.
This is adjacent to #503 (flattened aliases dropping contracts on bundled
groups) but a distinct code path: here the canonical derived command of an
installed importer/exporter carries no argument or flag contract at all.
Reproduction
An importer registered the bare way:
api.registerImporter("todos", async (ctx) => {
const file = ctx.args?.[0] ?? readStringOption(ctx.options, "file");
const format = readStringOption(ctx.options, "format");
// ... handler fully supports a positional file + --file/--format/...
});Then, against pm-cli 2026.7.10:
$ pm todos import backlog.jsonl
Error: Too many arguments for extension command 'todos import': backlog.jsonl.
$ pm todos import --file backlog.jsonl --format jsonl
Error: Unknown option '--file' for extension command 'todos import'.
$ pm todos import --help
Usage: pm todos import [options]
Options:
-h, --help display help for command # <-- no flags, no <file> arg
The same handler invoked via the SDK works:
await runAction({ action: "todos-import", options: { file: "backlog.jsonl", format: "jsonl" } }) → OK.
By contrast, a registerCommand({ name: "todos sync", flags: [...] }) in the
same extension exposes its flags and accepts a positional file perfectly, and a
bundled importer that does pass options works too — confirming the derived
command faithfully reflects declared contracts, and the gap is purely the
missing declaration going undetected.
Why this is agent-hostile
pm <name> import --helpis empty, so an agent can't discover how to call it.Too many argumentsfor a positional file (the one thing an importer always
needs) gives no hint that the file must come via declaredarguments/--file.Unknown option '--file'contradicts the handler, which reads--file.- Green unit tests hide it entirely (handlers are tested directly, bypassing the
CLI parser), so it ships silently. (Real example: pm-todos import/export were
unusable via CLI for multiple releases; fixed in fix(todos): make CLI import/export usable + harden status/jsonl/sync semantics pm-todos#22 by
declaring the contracts.)
Proposed improvements (any subset)
pm package doctordiagnostic: warn when a derived importer/exporter
command declares zeroargumentsandflagswhile its handler reads
ctx.args/ctx.options— the exact authoring footgun above. This would have
caught it. (Todaydoctorreports collisions but nothing here.)- Sensible default for importers/exporters: since an importer inherently
consumes a source, have the derived<name> importcommand accept an optional
positionalfileand a--fileflag by default, even whenoptionsis
omitted. (Exporters similarly default--output.) - Better error text: on
Too many argumentsfor a derived import command
that declares no positional, hint: "this importer declares no file argument;
pass the source via its declared options or addarguments:[{name:'file'}]."
Improvement (1) is the highest-leverage: a single doctor rule turns a silent,
ships-to-production footgun into an author-time warning.
Environment
- pm-cli 2026.7.10 (installed extension path)
- Discovered while hardening pm-todos (fix: fix(todos): make CLI import/export usable + harden status/jsonl/sync semantics pm-todos#22)
Activity
coderabbitai commentedon Jul 10, 2026
🔗 Related PRs
#36 - [codex] Improve agent UX from manual pm audit [closed]
#51 - Polish CLI ergonomics, delete safety, and templates dedup [closed]
#418 - Refactor residual CodeFactor complexity hotspots [merged]
#422 - Eliminate remaining CodeFactor SDK and CLI issues [merged]
#428 - Harden SDK extension runtime packaging [merged]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
You can configure auto-planning by selecting labels in the issue_enrichment configuration.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
unbraind commentedon Jul 11, 2026
Fixed by #511 and merged to main in f1dafef. The implementation passed 5,533 tests at exact 100/100/100/100 coverage plus all required CI, security, static, smoke, and bot-review gates.
unbraind commentedon Jul 11, 2026
pm tracker item:
pm-0mjz— Agent UX: importer/exporter registered withoutoptionsyields an unusable CLI command (no arg/flag contracts, confusing "Too many arguments", no doctor diagnostic) #504: importer/exporter registered without options yields an unusable CLI command (no arg/flag contracts)