Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .agents/pm/decisions/pm-muhw.toon
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ id: pm-muhw
title: "ADR: the pm SDK is the single public API — CLI and MCP are presentation layers (proposed)"
description: "Target layering for SDK-first pm: src/core is private, src/sdk is the public programmatic surface, and CLI/MCP should become SDK presentation layers. Current CI enforcement is a baseline ratchet: no new private src/core imports, no computed dynamic imports from boundary sources, and no stale baseline entries while promotion tasks burn down existing edges. Status open = proposed; close = accepted."
type: Decision
status: open
status: closed
priority: 1
tags[5]: adr,architecture,"area:cli","area:mcp","area:sdk"
created_at: "2026-07-05T04:52:19.856Z"
updated_at: "2026-07-05T06:29:36.871Z"
updated_at: "2026-07-05T18:26:47.514Z"
author: maintainer-agent
estimated_minutes: 90
acceptance_criteria: "ADR body records context, target layering rules, current ratchet enforcement, considered alternatives (status quo core-direct imports; publish core as-is; separate npm package for primitives), promotion criteria for a primitive to enter the SDK, semver/stability policy for the SDK surface, and the boundary-gate mechanism; accepted (closed) before promotion tasks under pm-usfg merge"
parent: pm-m2u1
risk: low
confidence: high
close_reason: "Accepted ADR before SDK primitive promotion: live item body records target layering, rejected alternatives, promotion criteria, semver policy, and boundary-gate ratchet; pm-xzhz now implements the first public execution primitive against that decision."
body: "## Context\nThe SDK (src/sdk) currently serves extension/package AUTHORS (compose/define/runtime/testing/cli-contracts). The PM primitives themselves — item store, list/query, search, history, governance, schema/config/profile — live in src/core and are still imported directly by parts of src/cli and src/mcp. Integrators who want a custom PM tool must shell out to the CLI; the product goal says the SDK should deliver the universal baseline.\n\n## Decision (proposed)\n1. Target architecture: src/sdk is the public programmatic API; src/core remains private implementation.\n2. Target presentation boundary: src/cli and src/mcp become thin presentation layers over src/sdk primitives as each primitive family is promoted.\n3. Current enforcement is a ratchet, not a completed SDK-only whitelist: CI records the existing src/cli/src/mcp -> src/core edges in scripts/release/sdk-import-boundary-baseline.json and blocks new private core edges, computed dynamic imports from boundary sources, and stale baseline entries.\n4. A primitive enters the SDK with: typed input/result contracts, docstring coverage, linked tests, and reference docs — same bar as existing sdk/testing helpers.\n5. SDK surface is semver-meaningful: breaking changes to promoted primitives require a deprecation cycle.\n6. MCP tools and CLI commands map 1:1 onto SDK primitives wherever a primitive exists (no logic forks in presentation layers).\n\n## Alternatives considered\n- Status quo (CLI imports core): rejected — SDK can never reach feature parity; universality goal unreachable.\n- Export src/core wholesale: rejected — freezes internals, no stability contract, huge accidental API.\n- Separate @unbrained/pm-core package: rejected for now — split repos/version skew; can revisit after boundary is stable.\n\n## Consequences\n+ CLI/MCP/SDK converge on one implementation as the baseline shrinks.\n+ Any project can compose its own PM tool from primitives (universality goal).\n+ The ratchet is enforceable before the migration is complete.\n- Promotion work is a wide mechanical refactor (mitigated by domain-by-domain child tasks under pm-usfg and a zero-behavior-change test bar)."
82 changes: 82 additions & 0 deletions .agents/pm/features/pm-xzhz.toon

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .agents/pm/history/pm-muhw.jsonl
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
{"ts":"2026-07-05T04:52:19.856Z","author":"maintainer-agent","op":"create","patch":[{"op":"replace","path":"/body","value":"## Context\nThe SDK (src/sdk) currently serves extension/package AUTHORS (compose/define/runtime/testing/cli-contracts). The PM primitives themselves — item store, list/query, search, history, governance, schema/config/profile — live in src/core and are imported directly by src/cli/commands/*. Integrators who want a custom PM tool must shell out to the CLI; the product goal says the SDK should deliver the universal baseline.\n\n## Decision (proposed)\n1. src/sdk is the ONLY public programmatic API; everything in src/core is private implementation.\n2. src/cli and src/mcp may import ONLY from src/sdk (and their own presentation modules). Enforced by lint boundary rule + CI gate.\n3. A primitive enters the SDK with: typed input/result contracts, docstring coverage, linked tests, and reference docs — same bar as existing sdk/testing helpers.\n4. SDK surface is semver-meaningful: breaking changes to promoted primitives require a deprecation cycle.\n5. MCP tools and CLI commands map 1:1 onto SDK primitives wherever a primitive exists (no logic forks in presentation layers).\n\n## Alternatives considered\n- Status quo (CLI imports core): rejected — SDK can never reach feature parity; universality goal unreachable.\n- Export src/core wholesale: rejected — freezes internals, no stability contract, huge accidental API.\n- Separate @unbrained/pm-core package: rejected for now — split repos/version skew; can revisit after boundary is stable.\n\n## Consequences\n+ CLI/MCP/SDK share one implementation — feature drift becomes impossible.\n+ Any project can compose its own PM tool from primitives (universality goal).\n- Promotion work is a wide mechanical refactor (mitigated by domain-by-domain child tasks under pm-usfg and a zero-behavior-change test bar)."},{"op":"add","path":"/metadata/id","value":"pm-muhw"},{"op":"add","path":"/metadata/title","value":"ADR: the pm SDK is the single public API — CLI and MCP are presentation layers (proposed)"},{"op":"add","path":"/metadata/description","value":"Fixes the layering contract for the SDK-first epic pm-usfg: src/core is private, src/sdk is the only public programmatic surface, src/cli and src/mcp import exclusively from src/sdk, enforced by a CI boundary gate. Status open = proposed; close = accepted. Duplicate check: no existing ADR covers public-API layering."},{"op":"add","path":"/metadata/type","value":"Decision"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":["adr","architecture","area:cli","area:mcp","area:sdk"]},{"op":"add","path":"/metadata/created_at","value":"2026-07-05T04:52:19.856Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-07-05T04:52:19.856Z"},{"op":"add","path":"/metadata/author","value":"maintainer-agent"},{"op":"add","path":"/metadata/estimated_minutes","value":90},{"op":"add","path":"/metadata/acceptance_criteria","value":"ADR body records context, layering rules, considered alternatives (status quo core-direct imports; publish core as-is; separate npm package for primitives), promotion criteria for a primitive to enter the SDK, semver/stability policy for the SDK surface, and the boundary-gate enforcement mechanism; accepted (closed) before promotion tasks under pm-usfg merge"},{"op":"add","path":"/metadata/parent","value":"pm-m2u1"},{"op":"add","path":"/metadata/risk","value":"low"},{"op":"add","path":"/metadata/confidence","value":"high"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"dd99b2b88a5953a844086a0fd932980aa96efd481720941127b1f1e6dcd358cc","message":""}
{"ts":"2026-07-05T06:29:36.871Z","author":"claude-code-agent","op":"update","patch":[{"op":"replace","path":"/body","value":"## Context\nThe SDK (src/sdk) currently serves extension/package AUTHORS (compose/define/runtime/testing/cli-contracts). The PM primitives themselves — item store, list/query, search, history, governance, schema/config/profile — live in src/core and are still imported directly by parts of src/cli and src/mcp. Integrators who want a custom PM tool must shell out to the CLI; the product goal says the SDK should deliver the universal baseline.\n\n## Decision (proposed)\n1. Target architecture: src/sdk is the public programmatic API; src/core remains private implementation.\n2. Target presentation boundary: src/cli and src/mcp become thin presentation layers over src/sdk primitives as each primitive family is promoted.\n3. Current enforcement is a ratchet, not a completed SDK-only whitelist: CI records the existing src/cli/src/mcp -> src/core edges in scripts/release/sdk-import-boundary-baseline.json and blocks new private core edges, computed dynamic imports from boundary sources, and stale baseline entries.\n4. A primitive enters the SDK with: typed input/result contracts, docstring coverage, linked tests, and reference docs — same bar as existing sdk/testing helpers.\n5. SDK surface is semver-meaningful: breaking changes to promoted primitives require a deprecation cycle.\n6. MCP tools and CLI commands map 1:1 onto SDK primitives wherever a primitive exists (no logic forks in presentation layers).\n\n## Alternatives considered\n- Status quo (CLI imports core): rejected — SDK can never reach feature parity; universality goal unreachable.\n- Export src/core wholesale: rejected — freezes internals, no stability contract, huge accidental API.\n- Separate @unbrained/pm-core package: rejected for now — split repos/version skew; can revisit after boundary is stable.\n\n## Consequences\n+ CLI/MCP/SDK converge on one implementation as the baseline shrinks.\n+ Any project can compose its own PM tool from primitives (universality goal).\n+ The ratchet is enforceable before the migration is complete.\n- Promotion work is a wide mechanical refactor (mitigated by domain-by-domain child tasks under pm-usfg and a zero-behavior-change test bar)."},{"op":"replace","path":"/metadata/acceptance_criteria","value":"ADR body records context, target layering rules, current ratchet enforcement, considered alternatives (status quo core-direct imports; publish core as-is; separate npm package for primitives), promotion criteria for a primitive to enter the SDK, semver/stability policy for the SDK surface, and the boundary-gate mechanism; accepted (closed) before promotion tasks under pm-usfg merge"},{"op":"replace","path":"/metadata/updated_at","value":"2026-07-05T06:29:36.871Z"},{"op":"replace","path":"/metadata/description","value":"Target layering for SDK-first pm: src/core is private, src/sdk is the public programmatic surface, and CLI/MCP should become SDK presentation layers. Current CI enforcement is a baseline ratchet: no new private src/core imports, no computed dynamic imports from boundary sources, and no stale baseline entries while promotion tasks burn down existing edges. Status open = proposed; close = accepted."}],"before_hash":"dd99b2b88a5953a844086a0fd932980aa96efd481720941127b1f1e6dcd358cc","after_hash":"d3af4d8556eec858c0fe9099fe2bc96abec6132319986fe07f1f5ca2ba19ee61","message":"Align ADR wording with current SDK boundary ratchet enforcement"}
{"ts":"2026-07-05T18:26:22.707Z","author":"codex-agent","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-07-05T18:26:22.707Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"}],"before_hash":"d3af4d8556eec858c0fe9099fe2bc96abec6132319986fe07f1f5ca2ba19ee61","after_hash":"2fff2b2cebdbd695804857b10848fe29b56d32df8a263283683f35194e51459d"}
{"ts":"2026-07-05T18:26:47.514Z","author":"codex-agent","op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-07-05T18:26:47.514Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/close_reason","value":"Accepted ADR before SDK primitive promotion: live item body records target layering, rejected alternatives, promotion criteria, semver policy, and boundary-gate ratchet; pm-xzhz now implements the first public execution primitive against that decision."}],"before_hash":"2fff2b2cebdbd695804857b10848fe29b56d32df8a263283683f35194e51459d","after_hash":"fb42fc1ec4611c0be3e569123514ac4279df46acf03c5d3c8bdd48d4b0c27a20"}
Loading
Loading