Summary
pm update --dep writes dependency edges with author: null, while the very same field, on the same item, written through pm update --blocked-by, is correctly attributed. Every other appended collection (notes, comments, learnings) resolves the author automatically.
Dependency.author exists in the public type and --dep accepts author=<value> explicitly — it is simply never defaulted on that code path.
Reproduction
pm-cli 2026.7.26, fresh pm init. Both edges below are kind=blocked_by, on the same item, written seconds apart:
pm update "$H" --dep "id=$X,kind=blocked_by" # exit 0
pm update "$H" --blocked-by "$Y" # exit 0
pm notes "$H" --add "note for author comparison"
dependencies[2]{id,kind,created_at,author,source_kind}:
pm-vx91,blocked_by,"2026-07-26T21:00:29.015Z",null,null # --dep
pm-b8sc,blocked_by,"2026-07-26T21:00:29.582Z","harness:claude-code",null # --blocked-by
notes[1]{created_at,author,text}:
"2026-07-26T21:00:30.050Z","harness:claude-code",note for author comparison # notes
Same command, same field, same kind — two flags, two different attribution outcomes.
Why the inconsistency exists
--blocked-by goes through reconcileBlockedByDependency(current, nextBlockedById, nowIsoValue, author), which takes and applies a resolved author. parseDependencyAdditions(raw, prefix, nowIso) — the --dep path — has no author parameter at all, so it can only ever emit what the user typed.
Impact on multi-agent workspaces
This is not cosmetic, for two compounding reasons:
-
--dep is the only way to add any non-blocked_by kind. blocks, parent, child, related_to, implements, supersedes, verifies, discovered_from, … are reachable exclusively through the unattributed path. So in practice the overwhelming majority of the relationship graph is unattributed, and the one attributed kind is the one with a dedicated flag.
-
The merge driver unions dependencies across branches (correct behaviour, verified). After N agents merge, the item holds a combined edge set with no provenance:
dependencies[2]{id,kind,created_at,author,source_kind}:
pm-djzp,blocked_by,"2026-07-26T20:57:41.001Z",null,null # which agent?
pm-idik,blocked_by,"2026-07-26T20:57:42.367Z",null,null # which agent?
created_at is the only discriminator, and it is useless when agents work concurrently. Notes merged in the same operation are attributed, so the item ends up self-inconsistent: you can tell who wrote a note but not who asserted a blocking relationship — which is the higher-stakes claim of the two, since blocked_by drives pm next and the scheduling surface.
For a tool whose stated purpose is coordinating multiple agents, "who claimed this dependency" is exactly the question the graph should be able to answer. It's also the natural input to any later dispute/reconciliation flow.
Suggested fix
Thread the already-resolved author into parseDependencyAdditions and default Dependency.author to it when the caller did not supply author= explicitly — i.e. make --dep behave like --blocked-by, --note, --comment, and --learning, all of which already do this.
Explicit author= should keep winning, so importer paths (e.g. pm-github --link-deps, which sets source_kind) can continue to attribute edges to their true origin.
Backfill is not required: existing null authors can stay as "unknown, pre-fix", since the field is already optional.
Environment
- pm-cli 2026.7.26 (npm
@unbrained/pm-cli)
- Node 22, Linux
- Fresh
pm init; single workspace, no merge involved in the repro above (the merge case is only what makes it hurt).
Summary
pm update --depwrites dependency edges withauthor: null, while the very same field, on the same item, written throughpm update --blocked-by, is correctly attributed. Every other appended collection (notes,comments,learnings) resolves the author automatically.Dependency.authorexists in the public type and--depacceptsauthor=<value>explicitly — it is simply never defaulted on that code path.Reproduction
pm-cli 2026.7.26, fresh
pm init. Both edges below arekind=blocked_by, on the same item, written seconds apart:Same command, same field, same kind — two flags, two different attribution outcomes.
Why the inconsistency exists
--blocked-bygoes throughreconcileBlockedByDependency(current, nextBlockedById, nowIsoValue, author), which takes and applies a resolvedauthor.parseDependencyAdditions(raw, prefix, nowIso)— the--deppath — has no author parameter at all, so it can only ever emit what the user typed.Impact on multi-agent workspaces
This is not cosmetic, for two compounding reasons:
--depis the only way to add any non-blocked_bykind.blocks,parent,child,related_to,implements,supersedes,verifies,discovered_from, … are reachable exclusively through the unattributed path. So in practice the overwhelming majority of the relationship graph is unattributed, and the one attributed kind is the one with a dedicated flag.The merge driver unions
dependenciesacross branches (correct behaviour, verified). After N agents merge, the item holds a combined edge set with no provenance:created_atis the only discriminator, and it is useless when agents work concurrently. Notes merged in the same operation are attributed, so the item ends up self-inconsistent: you can tell who wrote a note but not who asserted a blocking relationship — which is the higher-stakes claim of the two, sinceblocked_bydrivespm nextand the scheduling surface.For a tool whose stated purpose is coordinating multiple agents, "who claimed this dependency" is exactly the question the graph should be able to answer. It's also the natural input to any later dispute/reconciliation flow.
Suggested fix
Thread the already-resolved author into
parseDependencyAdditionsand defaultDependency.authorto it when the caller did not supplyauthor=explicitly — i.e. make--depbehave like--blocked-by,--note,--comment, and--learning, all of which already do this.Explicit
author=should keep winning, so importer paths (e.g.pm-github --link-deps, which setssource_kind) can continue to attribute edges to their true origin.Backfill is not required: existing
nullauthors can stay as "unknown, pre-fix", since the field is already optional.Environment
@unbrained/pm-cli)pm init; single workspace, no merge involved in the repro above (the merge case is only what makes it hurt).