Skip to content

Agent UX: batch item creation is shape-uniform — pm plan materialize forces one type and one field set on every child, so authoring a real specification set costs one process per item #896

Closed

Description

@unbraind

Summary

pm plan materialize is the only way to create more than one item in a single invocation, and every item it creates has the same shape: one --materialize-type for all children, one --materialize-tags, and --field values forwarded to every child identically.

Any specification set worth writing down is heterogeneous — a mix of types, each with its own description, acceptance criteria, priority and estimate. There is no CLI path for that, so it degrades to one pm create process per item.

Reproduction

Batch creation works, and is uniform:

pm plan create --title "Bench plan" --step "Step one" --step "Step two" --author bench
pm plan materialize <plan-id> --steps all --materialize-type Feature --author bench
# → two Features, identical in every field except title

There is no way to make step one a Decision with its own --acceptance-criteria and step two a Feature with a different one. --materialize-type is singular by construction, and --field name=value is documented as "forwarded to every materialized child".

What it cost in practice

Specifying one epic and its six children (1 Epic, 4 Feature, 1 Decision, each with its own --description, --acceptance-criteria, --priority, --estimated-minutes and a parent dependency) took seven separate pm create invocations. Nothing about the work is sequential — it is one coherent specification authored in one thought.

Wall-clock is not the complaint: pm create measured 0.35 s end-to-end on a warm workspace, and startup alone is ~0.27 s. The cost is agent-shaped:

  • Seven tool calls instead of one. For an agent, each is a turn boundary with its own latency, its own output payload to parse, and its own failure mode to handle.
  • Seven ids to carry forward. pm create --json returns {id, status, changed_field_count} per call, so the caller must correlate seven separate responses back to seven intents by ordering alone. Batching one invocation per item is precisely where an agent loses an id and silently orphans a child.
  • No atomicity. If invocation five fails validation, four items already exist. There is no dry-run over the set and no rollback, though close-many and update-many both offer exactly that for their verbs.

This is a project management = context management problem: authoring a specification is the moment an agent has the most context, and the CLI makes that the most expensive moment to spend it.

The asymmetry

The mutating verbs are already asymmetric:

verb bulk form heterogeneous?
update pm update-many matched set, shared changes
close pm close-many matched set, shared reason
create pm plan materialize no — one type, one tag set, one field set for all

update-many and close-many also ship dry-run plans and rollback checkpoints. Create, the only verb that brings new state into existence, has neither.

Worth noting the SDK side is already solved: #613 asked for a bulk multi-item atomic-mutation helper over commitWorkspaceTransaction and is closed. So the primitive exists — the gap is that no CLI surface reaches it for heterogeneous create.

Proposed shape

A batch create that reads a document on stdin or --from-file, one object per item, keys matching the existing flag names:

pm create --batch - --author claude --json <<'EOF'
{"title":"...","type":"Epic","priority":1,"acceptance_criteria":"...","estimated_minutes":5400}
{"title":"...","type":"Feature","dep":[{"id":"<epic>","kind":"parent"}],"acceptance_criteria":"..."}
{"title":"...","type":"Decision","dep":[{"id":"<epic>","kind":"parent"}],"description":"..."}
EOF

Three properties would make it worth shipping over what exists today:

  1. Heterogeneous — every item carries its own type and its own field values.
  2. Atomic, with a dry run — all-or-nothing over the set, matching update-many and close-many, on the commitWorkspaceTransaction primitive from SDK: add a bulk multi-item atomic-mutation helper on top of commitWorkspaceTransaction (create/update/close batch) — sync packages reinvent step+compensation wiring #613.
  3. Forward references within the batch — let a child name its parent by a batch-local alias so an epic and its children commit in one call. Without this the caller still needs two invocations, which removes most of the benefit for the exact case that motivates the feature.

NDJSON in and an array of {id, status} out would also match pm events, which is already newline-delimited JSON, so the format is not new vocabulary.

Environment

  • pm CLI 2026.8.4, Node 22, Linux.
  • Measured on a fresh pm init workspace: pm create ×5 sequential = 1.76 s total (0.35 s each).

Activity

  1. coderabbitai commented on Aug 4, 2026

    @coderabbitai
    🔗 Related PRs

    #196 - Add linked-test selectors and aggregate completion [closed]
    #431 - Add SDK boundary inventory ratchet [merged]
    #512 - Expose governed plan workflows through the public SDK [merged]
    #624 - SDK atomic structured mutations, lean output, and agent-first envelopes [merged]
    #712 - SDK context integrity: atomic Plans, batch similarity, sparse settings, and tombstones [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 5, 2026

    @unbraind
    OwnerAuthor

    Tracked as pm-o8z748. The implementation will extend the existing SDK-owned transaction surface with heterogeneous batch-local references and discovery guidance, rather than add a competing batch grammar.

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