Skip to content

Agent UX: pm notes add <id> … reports a note-text collision instead of naming the transposed subcommand, and the item id is silently consumed as note text #979

Closed

Description

@unbraind

Reproduced on 2026.8.7, 2026.8.10 and 2026.8.11 (latest published).

What happens

Collection commands take the form pm <collection> <id> --add <text>. Agents habitually type the subcommand form pm notes add <id> … instead, because almost every other CLI they drive uses noun verb object. When they do, the id lands in the [text] positional and add lands in <id>:

$ pm notes add tst-y0bb --note "hello" --pm-path /tmp/w/.pm
Error: Command failed

What happened:
  Specify note text either as positional [text] or with --add, not both

Recovery bundle:
  attempted_command: pm notes add tst-y0bb --add hello --pm-path /tmp/w/.pm
  normalized_args: notes add tst-y0bb --add hello --pm-path /tmp/w/.pm

Exit code is 2, so the failure is detectable. The problem is the diagnosis.

Why this costs agent turns

The message describes a collision between two ways of supplying note text. That is literally true of the parsed arguments, and completely unrelated to the mistake. Nothing in the output says notes has no add subcommand, and nothing points out that tst-y0bb — sitting in the [text] slot — is a resolvable item id in this very workspace.

An agent reading this reasonably concludes it passed the text twice and retries by dropping one of them:

$ pm notes add tst-y0bb --pm-path /tmp/w/.pm      # drops --add; still wrong
$ pm notes add --add "hello" --pm-path /tmp/w/.pm
What happened:
  Item add not found

Only the second variant produces the message that would have solved it immediately — and it is reachable only by also dropping the id. So the closer the agent gets to the right invocation, the worse the error it receives. In my session this cost two round trips per collection command, on notes and again on test, and the first attempt wrote nothing while returning a receipt that looked like output.

Why the receipt makes it worse

The recovery bundle prints normalized_args: notes add tst-y0bb --add hello. Read quickly, that looks like pm understood the command — id tst-y0bb, text hello — and objected to something incidental. It is actually showing add as the id and tst-y0bb as the text, but the flat rendering gives no cue which token filled which slot.

Suggested fix

When the <id> argument fails to resolve and the [text] positional does resolve to an existing item, say so instead of reporting the collision:

What happened:
  pm notes has no "add" subcommand, and "tst-y0bb" is an item id, not note text.

What is required:
  pm notes tst-y0bb --add "hello"

Resolving the id before checking the text-source collision would be enough to make this fire. The same transposition applies to pm learnings, pm files, pm docs, pm comments and pm test, so the check belongs wherever <id> [text] is parsed rather than in notes alone.

Two smaller points found alongside it:

  • pm notes --help lists only --add <text> and --add-json <json>, but --note <text> is accepted and behaves as --add. An undocumented working alias is not discoverable from help, and an agent using it has no way to confirm it is supported rather than tolerated. Either document it or reject it.
  • Unknown flags are rejected cleanly (Commander does not recognize option --bogus for this command path.), so the alias above is a deliberate mapping rather than lenient parsing — which is exactly why it should appear in --help.

Environment

@unbrained/pm-cli 2026.8.7 / 2026.8.10 / 2026.8.11, Node 22 and 26, Linux.

Activity

  1. coderabbitai commented on Aug 11, 2026

    @coderabbitai
    🔗 Related PRs

    #475 - Improve package install and annotation agent UX [merged]
    #502 - Atomic agent work selection, dependency integrity, and recovery primitives [merged]
    #593 - SDK-first agent UX graph, ownership, and recovery contracts [merged]
    #957 - SDK agent command contracts, lossless recovery, and truthful context policy [merged]
    #968 - SDK refusal recovery and executable reachability contracts [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 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:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. unbraind commented on Aug 11, 2026

    @unbraind
    OwnerAuthor

    Canonical pm item: pm-rncuf7. It is filed as an open, unclaimed child of the CLI ergonomics capability and linked to the shipped subcommand-recovery, positional-grammar, and annotation-safety lineage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions