Repository navigation
Description
Filed from real usage while building a merge-preview extension against @unbrained/pm-cli 2026.7.24-3.
The inconsistency
Core pm commands are careful never to put host filesystem paths in agent-facing output. Verified in a scratch workspace at /tmp/.../divtest:
pm context --json -> host-path occurrences: 0
pm stats --json -> host-path occurrences: 0
pm list --json -> host-path occurrences: 0
pm activity --from -7d --json -> host-path occurrences: 0
That is a genuinely valuable property: pm output is portable, diffable, and safe to paste between agents, commit into a repo, or attach to a PR.
Extensions cannot match it. The only workspace location an extension receives is context.pm_root, and it is the resolved absolute path — per dist/sdk/testing.d.ts, "Resolved pm workspace root forwarded as context.pm_root". There is no repo-relative counterpart anywhere on the context object, and pm context --json exposes no root/workspace/path field an extension could read instead.
So any extension that renders its workspace into output emits something like:
{ "workspace": "/tmp/claude-1000/-home-steve-container-pm-cli/e78b6f60/scratchpad/divtest/.agents/pm" }where every core command would have emitted .agents/pm or nothing at all.
Why this matters beyond cosmetics
- It leaks the host path into shared artifacts. Extension output is exactly the kind of thing that gets committed, posted to a PR, or handed to another agent.
/home/<user>/...in a published changelog or brief is a privacy leak, and it is one that core commands are already designed to avoid. - It breaks portability of recorded commands. Agents record the command and its output as evidence. An absolute path pins that record to one machine, so a teammate or a CI runner re-running it gets a different answer or none.
- Every extension author reimplements the same non-trivial resolution. To be well-behaved, an extension must locate the git root itself (
git rev-parse --show-toplevel), relativizepm_rootagainst it, normalize separators for Windows, and reject the out-of-repo and equal-to-repo-root cases. I wrote exactly that (pmRootRelFromCtx) and needed two review rounds to get the edge cases right — a sibling directory named..cache/pmwas rejected by a naivestartsWith(".."), and a pm root equal to the repo root produced an empty prefix that silently matched nothing. Each extension re-deriving this will get a different subset of those wrong.
Suggested fix
Add the relative form to the context the CLI already computes, e.g.:
interface CommandContext {
pm_root: string; // absolute, unchanged
pm_root_rel?: string; // POSIX-separated, relative to the repo root when inside one
repo_root?: string; // absolute repo root, or undefined when not in a repo
}The CLI already knows all three at dispatch time, so this costs nothing to provide and lets extensions default to the portable form. If adding context fields is undesirable, an exported SDK helper (resolvePmRootRelative(pmRoot, cwd)) with the edge cases handled once would solve the duplication, though it would not nudge authors toward the portable default the way a context field does.
Either way the goal is that an extension can be host-path-free as easily as core already is.
Reproducing
mkdir /tmp/pmroot-demo && cd /tmp/pmroot-demo && git init -q
pm init --pm-path .agents/pm
# in any extension command handler, log context.pm_root:
# -> /tmp/pmroot-demo/.agents/pm (absolute)
# compare: pm context --json contains no absolute path at allEnvironment
@unbrained/pm-cli2026.7.24-3- Linux, Node 22
Happy to send a PR if the pm_root_rel + repo_root context shape is the direction you would want.
Activity
coderabbitai commentedon Jul 24, 2026
🔗 Related PRs
#73 - Fix nightly macOS realpath + Windows .cmd EINVAL and dedup extension-policy override builder [closed]
#142 - Guard pm tracker path targeting for agents [closed]
#302 - Optimize npm package SDK installs [merged]
#428 - Harden SDK extension runtime packaging [merged]
#561 - SDK: unify extension input and output host contracts [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 25, 2026
pm tracker item:\n- pm-j4ac9a — GH-685: extension CommandContext needs portable source and tracker workspace coordinates
unbraind commentedon Jul 25, 2026
Fixed by PR #693: extension CommandContext now exposes portable source workspace/repository/tracker-relative coordinates instead of requiring host-absolute pm_root output.