Repository navigation
Description
Summary
PortableWorkspaceContext — the contract added for GH-685 — is declared on CommandHandlerContext but is never populated when an extension command handler is invoked. All three fields are absent at runtime, so the original defect (extension output can only report an absolute pm_root, leaking host paths) is unchanged.
Verified against published @unbrained/pm-cli 2026.7.25.
Contract
dist/core/extensions/extension-types.d.ts:
export interface PortableWorkspaceContext {
/** Immutable source workspace root, distinct from a sandboxed tracker root. */
source_workspace_root?: string;
/** Source VCS repository root when one can be resolved. */
repo_root?: string;
/** POSIX tracker path relative to the source workspace when contained there. */
pm_root_rel?: string;
}
export interface CommandHandlerContext extends PortableWorkspaceContext { /* … */ }Reproduction
Minimal project-scope extension (.agents/pm/extensions/pm-flagprobe/):
{ "name": "pm-flagprobe", "version": "1.0.0", "entry": "./index.js",
"capabilities": ["commands", "schema"], "pm": { "compatibility": "v2" } }export default {
name: "pm-flagprobe", version: "1.0.0",
activate(api) {
api.registerCommand({
name: "flagprobe",
description: "Report portable workspace context.",
async run(ctx) {
return {
pm_root_rel: ctx.pm_root_rel ?? null,
repo_root: ctx.repo_root ?? null,
source_workspace_root: ctx.source_workspace_root ?? null,
pm_root: ctx.pm_root,
};
},
});
},
};$ git init -q . && pm init # plain git repo, tracker contained at .agents/pm
$ pm flagprobe --json
{
"pm_root_rel": null,
"repo_root": null,
"source_workspace_root": null,
"pm_root": "/abs/host/path/evt-test/.agents/pm"
}Expected
In a git repository whose tracker is contained in the checkout:
repo_root→ the resolved VCS rootsource_workspace_root→ the immutable source workspace rootpm_root_rel→.agents/pm
Actual
All three are undefined. Reproduces both with and without an explicit --pm-path, invoked from the repo root.
Impact
This is the whole point of the GH-685 contract: an extension that wants to record a re-runnable command, a portable file reference, or any user-visible path has nothing but the absolute pm_root. Every such string is machine-specific — it breaks re-runnability for another agent or a CI checkout, and it leaks host filesystem layout into committed tracker items and published output.
Concretely, in our fleet this blocks emitting checkout-relative test commands in tracker items; we currently have to post-process absolute paths out of extension output.
Suggestion
Populate the three fields in the same place the host builds CommandHandlerContext (alongside pm_root) and ExtensionCommandSdk. Since all three are optional, extensions cannot distinguish "host too old" from "not resolvable" — so leaving them unset in a resolvable git checkout is silently indistinguishable from a correct absent value. A contract test asserting pm_root_rel === ".agents/pm" for a contained tracker in a git repo would pin this.
Activity
coderabbitai commentedon Jul 25, 2026
🔗 Related PRs
#406 - feat(mcp): extension-aware built-in actions + action-scoped name schema (pm-zumn, pm-fq80) [merged]
#479 - feat(package): isolate project doctor diagnostics [merged]
#491 - Harden init target safety and package install verification [merged]
#545 - SDK contract integrity: workspace paths, dependency truth, validation, and MCP parity [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
Tracked and actively repaired in pm-fc9gm4, linked to the completed GH-685 lineage.