Self-Describing Context Contracts
Tracker references: pm-cxr0jb, pm-11phn1, pm-kxci8x, pm-6j7r1a, and pm-x4nn3z.
Agent Quick Context
pm treats project management as context management. Its CLI, SDK, MCP, and package surfaces therefore publish the same answers to four questions:
- Which command or alias is invocable?
- How is each flag supplied?
- Which bounded context projection fits the caller's intent?
- Which stable error code and recovery path can be returned?
Use pm contracts --summary --json for the bounded bootstrap and pm contracts --full --json for the complete context-intent, error-code, runtime, and MCP catalogs.
Intent-Scoped Reads
The read primitives accept --for <intent>:
| Command | Built-in intent | Purpose |
|---|---|---|
context |
orient, handoff |
Active hierarchy or continuation context |
get |
inspect |
Complete item lifecycle and relationship context |
list and list aliases |
triage |
Compact governance and ownership fields |
next |
execute |
One actionable recommendation |
search |
discover |
Ranked canonical-lineage candidates |
Explicit projection and token flags win over intent defaults:
pm context --for orient --section hierarchy --token-budget 900
pm next --for execute --ready-only --json
pm search "output projection" --for discover --json
Active package modules declare intents by exporting contextIntents (or context_intents) as an array of contracts; the runtime collects and composes them automatically for each request. Workspaces may declare an array, or { "intents": [...] }, in .agents/pm/context-intents.json. Package declarations extend the built-ins; workspace declarations have final precedence and can intentionally override a matching command/intent pair. Invalid or duplicate declarations fail closed. Unknown CLI intent names return nearest-name guidance.
export const contextIntents = [
{
command: "search",
intent: "security-triage",
description: "Find likely security lineage with a bounded evidence set.",
included_field_groups: ["identity", "status", "relevance", "evidence"],
token_budget: 900,
},
];
Discovery is request-scoped for concurrent SDK clients: built-ins, active packages, and the selected workspace cannot leak declarations into another request. See Universal Read Output Contracts for the four output dimensions shared by every read surface.
Flag Invocation Metadata
A command-scoped command_flags row retains the stable vocabulary in flags and adds flag_invocations. The unscoped and --full projections omit this repeated semantic payload; select a command to retrieve its invocation metadata within the context budget. Each invocation row declares:
- description and aliases;
- whether it consumes and requires a value;
- value name and type;
- option requiredness and repeatability;
- accepted input channels (
argv,stdin, orfile); - the
-stdin sentinel where supported.
For example, --description - reads multiline text from stdin for create and update; --body-file declares file input; and --stdin-json declares stdin-only input.
Visibility and Enumeration
Every command surface carries one tier: core, standard, full, or internal. The same declaration drives SDK/MCP profiles and generated agent docs. Contract enumeration includes accepted aliases rather than silently compacting them, and each row reports its canonical command.
The default summary stays bounded. Larger intent and error catalogs are emitted only by --full.
Error Vocabulary
PM_ERROR_CODE_CATALOG is generated from executable structured error declarations. Each row includes:
- the stable snake-case code;
- meaning and stability;
- CLI exit code;
- semantic exit class (
generic_failure,usage,not_found,conflict, ordependency_failed); - recovery guidance;
- source modules that emit the code.
- inferred CLI command roots (
*for cross-cutting runtime failures). - canonical code and compatibility aliases for concept-level handling.
Existing catalog entries are recorded in scripts/error-code-stability.json.
The generator refuses to remove one of those stable codes unless the reviewed
compatibility ledger is changed explicitly. Newly discovered codes are emitted
as provisional until deliberately promoted, so adding a runtime declaration
does not accidentally promise permanent compatibility.
The compatibility ledger also pins every stable code to its reviewed process
exit. An executable PmCliError declaration that disagrees with that mapping
fails generation, and a stable code without a mapping fails the drift check.
Reviewed alias groups preserve every emitted legacy spelling while exposing one
canonical concept to SDK, package, CLI-contract, and observability consumers.
Aliases must resolve directly to a declared stable canonical code and share its
exit class; cycles, missing targets, and transport mismatches fail closed.
Use resolvePmErrorCodeContract when the exact emitted spelling matters, and
resolveCanonicalPmErrorCodeContract when one handler should cover a complete
compatibility group.
PM_ERROR_CODE_EXIT_CLASS_CONTRACTS is the portable shell taxonomy: exit 1 is
generic failure, 2 is usage, 3 is not-found, 4 is conflict, and 5 is dependency
failure. Catalog validation rejects a code whose declared semantic class and
transport exit disagree.
Run the drift gate after adding or removing a structured error:
pnpm contracts:errors:update
pnpm contracts:errors:check
Package consumers can import the primitive catalog and validators from @unbrained/pm-cli/sdk/contracts without loading the CLI runtime.