Repository navigation
Description
Summary
Since 2026.8.3, governance.require_close_reason is enforced on every programmatic transition into closed — both pm create --status closed and pm update <id> --status closed fail with close_reason_required. That is a good change: it stops tools inventing immutable closure evidence.
But pm create has no way to supply a reason, so there is no single command that can create an already-closed item. pm close accepts --close-reason, --completed-at, --resolution, --expected-result, --actual-result; pm create accepts none of them.
Every importer therefore has to implement the same dance:
pm create --status open ... --json- parse the id back out of the envelope
pm close <id> --reason "..." [--completed-at ...]
Why this is worth fixing
Absorbing 2026.8.3 across our fleet required implementing that identical workaround three separate times — in a GitHub importer, a CSV importer, and a Beads importer. It is not a niche path: importing history from another tracker is inherently full of already-closed records.
The cost is not just duplication:
- It is 3x the commands and round-trips for the common bulk case. A 500-row CSV of closed records goes from 500 to 1500 subprocess invocations.
- It forces every importer to parse the create envelope just to recover the id — an extra coupling to output shape that has nothing to do with the user intent. We shipped a real production bug through exactly this path: our parser read a
{item:{id}}wrapper that the CLI has never emitted,create"succeeded", the follow-up close silently never ran, and every imported closed record landed open while the import reported success. A single-command form removes that failure mode entirely. - It is not atomic. A crash between step 1 and step 3 leaves an item in the wrong state with no marker saying so. For an importer that is a correctness problem, not just an ergonomic one.
Proposed change
Let pm create accept the closure metadata it already understands on close, and require it when --status closed is requested under the governance policy:
pm create --title "Legacy ticket" --type Task \
--status closed \
--close-reason "Imported from Beads record bd-1421 (source status: done)" \
--completed-at 2026-03-04T11:02:00Z
Semantics that would preserve the policy intent:
--status closedwithout a reason keeps failing exactly as it does today — the governance guarantee is unchanged.--status closedwith--close-reasonsucceeds and records the reason as author-supplied closure evidence, identically topm close.- The same treatment for the sibling closure fields already on
close(--completed-at,--resolution,--expected-result/--actual-result), so a single create can carry the source record's real provenance.
This keeps the "tools must not invent closure evidence" rule fully intact — it only removes the requirement that the evidence arrive in a second command.
Alternative
If folding the flags into create is undesirable, an --emit-id-style guarantee plus a documented, stable create envelope would at least remove the parsing hazard — but it would not fix the atomicity or the round-trip count.
Context
Found while upgrading a 20-package extension fleet from 2026.7.29 to 2026.8.3. Happy to send a PR if the shape above is acceptable.
Activity
coderabbitai commentedon Aug 3, 2026
🔗 Related PRs
#146 - fix: agent never-block reliability, MCP/version coherence, and CI/docs hardening [closed]
#230 - Single-call mutation ergonomics: pm create/update --body-file, pm close -m/-r/-d, --resolution as close reason [closed]
#429 - Accept close message fallback and reduce compatibility complexity [merged]
#712 - SDK context integrity: atomic Plans, batch similarity, sparse settings, and tombstones [merged]
#846 - SDK-owned terminal lifecycle policy and durable project history [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 4, 2026
Tracked in pm-ykdt4m.