Repository navigation
Description
Summary
governance.duplicate_detection_mode=advisory warns when a new item resembles an existing one. There is no CLI surface that answers the complementary question: "which duplicates does this workspace already contain?"
That matters because the advisory only ever fires at create time. Any workspace that accumulated duplicates before the mode was enabled — which is every workspace initialized with the minimal governance preset, since it defaults to off — carries those duplicates permanently invisible to the CLI.
The capability is not missing from the codebase. findDuplicateClusters is exported from @unbrained/pm-cli/sdk/governance and returns fully-formed clusters immediately. It simply has no command in front of it.
Reproduction
mkdir /tmp/dup && cd /tmp/dup && pm init tst
# minimal preset => duplicate_detection_mode defaults to "off"
pm config get governance.duplicate_detection_mode --json | grep '"value"'
# "value": "off"
# create three identical items — no warning of any kind
for i in 1 2 3; do pm create --title "Implement OAuth login flow for the web dashboard" --type Feature; done
# turn the advisory on; a NEW duplicate is correctly flagged
pm config set governance.duplicate_detection_mode advisory
pm create --title "Implement OAuth login flow for the web dashboard" --type Feature
# warnings:
# - "likely_duplicates:tst-cn9f,tst-dlwo,tst-z81x" <-- works
# ...but nothing reports the four duplicates now sitting in the workspace:
for c in health validate stats aggregate context next; do
echo "pm $c -> $(pm $c 2>&1 | grep -ciE 'likely_dup|duplicate_cluster|similar_to')"
done
# pm health -> 0
# pm validate -> 0
# pm stats -> 0
# pm aggregate -> 0
# pm context -> 0
# pm next -> 0Note that pm validate does emit a duplicate_issue_codes_count field, which is a different concept (duplicate issue codes, not duplicate items) and is easy to mistake for coverage of this.
Meanwhile, against that same workspace:
const g = await import('@unbrained/pm-cli/sdk/governance');
const r = await g.findDuplicateClusters({ pmRoot: '/tmp/dup/.agents/pm' });
// {"clusters":[{"id":"tst-cn9f","items":[
// {"id":"tst-cn9f","title":"Implement OAuth login flow for the web dashboard","status":"open","type":"Feature"},
// {"id":"tst-dlwo",...},{"id":"tst-z81x",...}],"matches":[...]}]}Complete, structured, and already tested — just unreachable from the CLI.
Why this matters for agents specifically
An agent starting a session on an unfamiliar workspace cannot establish whether the backlog is clean. The failure is silent and compounding: the agent picks up tst-cn9f, does the work, closes it, and the two identical siblings stay open — so the next agent redoes the same work. Nothing in pm context or pm next (the two commands an agent actually runs at session start) hints that the item it just selected has twins.
This is the reverse of how the rest of the governance surface behaves: pm health and pm validate are backward-looking audits over existing state, and duplicates are conspicuously the one governance signal that has no backward-looking mode.
Suggested fixes
-
Add duplicate clusters to
pm health(orpm validate) as an advisory check, gated ongovernance.duplicate_detection_mode != offso it stays opt-in and costs nothing for workspaces that do not want it. This is the smallest change and puts the signal where agents already look for workspace-quality problems. -
Or add an explicit command —
pm duplicates/pm graph duplicates— wrappingfindDuplicateClusterswith--threshold/--limit(the config keysgovernance.duplicate_detection_thresholdand..._limitalready exist) and clean--jsonoutput. -
Either way, emit the resolving command per cluster. A cluster is only actionable if the agent is told how to collapse it; printing cluster members without the follow-up command forces another roundtrip to work out the right
pm close/merge invocation.
Adding a duplicate_clusters count to pm context would close the loop for the session-start case, though I would understand keeping that out of the default context budget and behind a flag.
Environment
@unbrained/pm-cli2026.7.26 (global install, npm)- Node 22, Linux
- Fresh
pm initworkspace,governance.preset = minimal
Context
Found while auditing SDK adoption across the 18-package pm-* extension fleet — sdk/governance had zero adopters across the fleet despite exporting exactly the scanners several packages needed. Related to #715, which is the same shape of problem on a different governance surface (mutation_guard block mode being reachable in config but undiscoverable from --help).
Activity
coderabbitai commentedon Jul 26, 2026
🔗 Related PRs
#581 - feat(sdk): graph governance completeness, dry-run remediation plans, incremental graph cache, MCP nested-option warnings [merged]
#593 - SDK-first agent UX graph, ownership, and recovery contracts [merged]
#622 - feat(graph): durable indexes, governance baselines, and mutation advisories [merged]
#673 - feat(sdk): harden workspace mutation and migration primitives [merged]
#684 - SDK context coordination: mutation events, duplicate governance, and startup budgets [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 26, 2026
Follow-up data point, offered as evidence for the feature rather than as a complaint: I ran
findDuplicateClustersacross all 19 pm workspaces I have locally, including pm-cli's own.agents/pm.The 18 extension workspaces are essentially clean — 15 fully clean, 3 with a single all-closed cluster each. pm-cli's own workspace has 26 clusters, and this is the part that makes the case:
Ten open items for one Semgrep finding, six for another — 29 open duplicates in total, presumably from an ingestion job that re-filed on each run without a dedupe check.
This is exactly the failure mode described above, and it illustrates the point better than my synthetic repro: the duplicates are invisible to
pm health,pm validate,pm stats,pm context, andpm next, so nothing surfaces them during normal use — but a single SDK call enumerates all of them in well under a second. An agent runningpm nextin this workspace can be handed one of ten identical items with no indication the other nine exist.It also suggests the create-time advisory alone would not have prevented this: a bulk importer that constructs items programmatically is precisely the path most likely to run with
duplicate_detection_mode=off, which is theminimalpreset default. That is an argument for the backward-looking scan (option 1 or 2 above) being the more valuable half of the fix.Happy to open a separate housekeeping issue for the 29 items themselves if that is useful — I did not want to conflate workspace cleanup with the CLI gap.
unbraind commentedon Jul 26, 2026
Tracked by
pm-n13lzc, linked to the shipped batch duplicate-cluster primitive, create-time advisory, and dedupe-merge lineage.