Repository navigation
Description
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 titleThere 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 --jsonreturns{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-manyandupdate-manyboth 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":"..."}
EOFThree properties would make it worth shipping over what exists today:
- Heterogeneous — every item carries its own type and its own field values.
- Atomic, with a dry run — all-or-nothing over the set, matching
update-manyandclose-many, on thecommitWorkspaceTransactionprimitive 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. - 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 initworkspace:pm create×5 sequential = 1.76 s total (0.35 s each).
Activity
coderabbitai commentedon Aug 4, 2026
🔗 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 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 Aug 5, 2026
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.