| name | pi-context |
| description | Schema-driven project state management with typed JSON blocks, schema validation, substrate config, lens views, closure-table relations, and cross-block referential integrity. Use when managing substrate blocks, scaffolding project structure, installing block kinds from the packaged samples catalog, validating project state, rendering lens views, or adding work items.
|
<tools_reference>
Append an item to an array in a project block file. Schema validation is automatic. Set autoId:true to allocate the next id from the block's id pattern when the item has no id. Optional relations file the item's BIRTH edges in the same op run, after id allocation — each entry names the relation_type, the other endpoint's selector, and EXACTLY ONE orientation: direction (as_parent | as_child — the raw endpoint the new item occupies) or role (primary | counter — the semantic role the new item holds, mapped via the relation's declared role_direction; required for role-bearing orientation-ambiguous relation_types such as the gated-by / derived-from / supersedes / depends families, where the raw form is rejected). Filing item + edges as one atom lets a new item satisfy error-severity birth-edge invariants (e.g. a decision must cite a forcing artifact) that would refuse the bare item under the write-time gate. dryRun previews the append without writing: the exact prospective file (stamped, whole-schema-validated) plus the birth-relations gate — orientation, counter-endpoint resolution (a dangling/unregistered counter-endpoint is refused with the live rejection text), and the prospective-cycle check; the new item's own endpoint is exempt from existence checking (unwritten by definition — it resolves once the live run appends the edges after the item write) while its edges still count in the cycle set. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Append items to project blocks (issues, decisions, or any user-defined block), with optional atomic birth edges
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'issues', 'decisions') |
arrayKey | string | yes | Array key in the block (e.g., 'issues', 'decisions') |
item | unknown | yes | Item object to append — must conform to block schema |
autoId | boolean | no | When true and the item has no id, allocate the next id from the block's id pattern |
dryRun | boolean | no | Preview the append without writing — validates the exact prospective file and runs the birth-relations gate (orientation + counter-endpoint resolution + prospective cycles; the new item's endpoint is exempt from existence checking) |
relations | array | no | Birth edges filed atomically with the item, after id allocation, via the same validated append-relation porcelain (each entry oriented by direction OR role) |
Update fields on an item in a project block array. Finds by predicate field match. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Update items in project blocks — change status, add details, mark resolved
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'issues', 'decisions') |
arrayKey | string | yes | Array key in the block |
match | object | yes | Fields to match (e.g., { id: 'ISSUE-NNN' }) |
updates | object | yes | Fields to update (e.g., { status: 'resolved' }) |
Append a closure-table relation (edge: relation_type, optional ordinal) to relations.json. Orient the edge with EITHER raw --parent/--child OR the role-typed --primary/--counter (which maps to parent/child via the relation's declared role_direction); the two pairs are mutually exclusive. A bare --parent/--child append of a relation that is BOTH role-bearing and orientation-ambiguous (its source/target kinds overlap) is rejected — re-issue with --primary/--counter. Shape is AJV-validated; an exact-duplicate edge (same parent+child+relation_type) is a no-op. Reference integrity is enforced at write time (when config.json is present), mirroring context-validate's edge surface: the relation_type must be registered, endpoint kinds must match its declared source/target kinds, BOTH endpoints must already resolve — an edge to a not-yet-filed item is rejected (file the item first, or file the edge atomically as birth relations on append-block-item); registered foreign endpoints and lens bins pass — and an edge that would land a relation cycle is rejected (cycle_allowed relation_types exempt). --dryRun runs this same edge gate (registration, endpoint kinds/resolution, cycles) with the live rejection texts; the write pipeline's delta-scoped invariant gate runs only on the live write, so a live write can still be refused where the preview reported would-append. Creates relations.json if absent. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Create a relation/edge between two items (raw --parent/--child, or role-typed --primary/--counter mapped via role_direction)
| Parameter | Type | Required | Description |
|---|
parent | string | no | Parent-endpoint selector (canonical id / : / lens bin) — RAW orientation. Mutually exclusive with --primary/--counter. |
child | string | no | Child-endpoint selector — RAW orientation. Mutually exclusive with --primary/--counter. |
primary | string | no | Selector of the endpoint holding the relation's PRIMARY semantic role (ROLE-TYPED orientation; mapped to parent/child via the relation's declared role_direction). Requires --counter; the relation_type must declare role_direction. |
counter | string | no | Selector of the endpoint holding the relation's COUNTER role (ROLE-TYPED orientation). Requires --primary. |
relation_type | string | yes | Registered relation_type canonical_id / hierarchy edge type / lens id |
ordinal | integer | no | Optional sibling-ordering within (parent, relation_type) |
dryRun | boolean | no | Preview without writing relations.json |
Remove the single closure-table relation (edge) matching parent+child+relation_type from relations.json. Matches on the SAME (parent, child, relation_type) dedup identity append-relation uses, so it is the symmetric inverse of append-relation (ordinal is NOT part of identity). An absent edge is an idempotent no-op. Reference integrity is NOT checked here — run context-validate after if the removal changes resolvability. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Remove a relation/edge between two items (the inverse of append-relation)
| Parameter | Type | Required | Description |
|---|
parent | string | yes | Canonical id (or lens bin name) of the parent endpoint |
child | string | yes | Canonical id of the child endpoint |
relation_type | string | yes | Registered relation_type canonical_id / hierarchy edge type / lens id |
dryRun | boolean | no | Preview without writing relations.json |
Atomically replace one closure-table relation with another in a SINGLE write (no half-state: the old edge and the new edge never coexist on disk). The old edge is matched on the (parent, child, relation_type) dedup identity; the new edge is written with its optional ordinal. If the old edge is absent the call is effectively an append of the new edge. This op takes RAW parent/child (old + new) and BYPASSES the write-time orientation gate that append-relation applies — it writes the endpoints verbatim, so it is the affordance for re-orienting an existing edge; reference integrity is NOT checked here — run context-validate after. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Atomically swap one relation/edge for another in a single write
| Parameter | Type | Required | Description |
|---|
old_parent | string | yes | Parent endpoint selector of the edge to remove |
old_child | string | yes | Child endpoint selector of the edge to remove |
old_relation_type | string | yes | relation_type of the edge to remove |
parent | string | yes | Parent endpoint selector of the replacement edge |
child | string | yes | Child endpoint selector of the replacement edge |
relation_type | string | yes | relation_type of the replacement edge |
ordinal | integer | no | Optional sibling-ordering within (parent, relation_type) for the new edge |
dryRun | boolean | no | Preview without writing relations.json |
Append MANY closure-table relations to relations.json in a single write. Each edge is an object with { relation_type, ordinal? } plus EITHER a raw { parent, child } pair OR the role-typed { primary, counter } pair (mapped to parent/child via the relation's declared role_direction); the two pairs are mutually exclusive per edge, and a bare { parent, child } for an orientation-ambiguous role-bearing relation rejects the whole batch before any write. Per-(parent, child, relation_type) duplicates are skipped (against on-disk edges AND earlier edges in the same batch). Returns appended/skipped counts. Reference integrity is enforced at write time over the WHOLE batch (when config.json is present), mirroring context-validate's edge surface: every relation_type must be registered, endpoint kinds must match, every endpoint must already resolve — an edge to a not-yet-filed item rejects the batch (file the item first, or file the edge atomically as birth relations on append-block-item) — and a relation cycle rejects the batch, intra-batch cycles included (cycle_allowed relation_types exempt); all-or-nothing. --dryRun runs this same batch edge gate with the live rejection texts; the write pipeline's delta-scoped invariant gate runs only on the live write, so a live write can still be refused where the preview reported would-append. Creates relations.json if absent. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Create many relations/edges between items in one write (raw or role-typed per edge)
| Parameter | Type | Required | Description |
|---|
edges | unknown | yes | JSON array of edge objects. Each edge is { relation_type, ordinal? } plus EITHER a raw { parent, child } pair OR the role-typed { primary, counter } pair (mapped to parent/child via the relation's declared role_direction); the two orientation pairs are mutually exclusive per edge. Selectors are id / : / lens-bin. |
dryRun | boolean | no | Preview without writing relations.json |
Append-or-replace an item in a project block array by id: if an item with the same idField value exists it is REPLACED (full-shape replacement, not shallow-merge — use update-block-item for merge); otherwise the item is appended. Schema validation is automatic. idField defaults to 'id'. Optional relations file BIRTH edges in the same op run when the upsert resolves to an APPEND — each entry names the relation_type, the other endpoint's selector, and EXACTLY ONE orientation: direction (as_parent | as_child, raw) or role (primary | counter, mapped via the relation's declared role_direction; required for role-bearing orientation-ambiguous relation_types) — one atom under the write-time gate, so a new filing can satisfy error-severity birth-edge invariants. dryRun previews the upsert AND runs the birth-relations gate over the entries — orientation, counter-endpoint resolution (a dangling/unregistered counter-endpoint is refused with the live rejection text), and the prospective-cycle check — with the new item's own endpoint exempt from existence checking (unwritten by definition; it resolves once the live run appends the edges after the item write) while its edges still count in the cycle set. When the upsert resolves to a REPLACE, supplying relations refuses the write (birth edges are for new items; file edges on an existing item via append-relation). Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Append-or-replace a full block item by id (replacement, not merge), with optional atomic birth edges
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'issues', 'decisions') |
arrayKey | string | yes | Array key in the block (e.g., 'issues', 'decisions') |
item | unknown | yes | Full item object to upsert — must conform to block schema |
idField | string | no | Field used as the upsert key (default 'id') |
dryRun | boolean | no | Preview the upsert without writing |
relations | array | no | Birth edges filed atomically with an APPEND-mode upsert, each entry oriented by direction OR role (refused on replace mode — use append-relation for existing items) |
Promote a substrate item into another (registered) substrate as a NEW content-addressed item, recording the 'item_derived_from_item' lineage edge in the destination relations.json (parent = the new derived item, child = the source, carrying the source content_hash). The destination write-path mints a fresh oid + content_hash + content object. When the source block's status enum supports it, the source is marked superseded. Preconditions (unresolvable/non-item source, unregistered destination alias, unregistered destination relation_type, refname collision) throw. Pass dryRun to compute the destination without writing. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Promote an item into another substrate as a derived copy with a lineage edge
| Parameter | Type | Required | Description |
|---|
source | string | yes | Source item selector (bare refname / :) |
destinationSubstrate | string | yes | Registered destination substrate alias |
newRefname | string | no | Explicit destination refname (else allocated from the dest block id pattern) |
dryRun | boolean | no | Compute the destination without writing any channel |
writer | object | yes | DispatchContext.writer per pi-context/src/dispatch-context.ts. |
Append an item to a nested array on a parent-array item in a project block. Schema validation is automatic.
Append items to nested arrays inside parent items (e.g., findings inside a review)
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'spec-reviews') |
arrayKey | string | yes | Parent array key (e.g., 'reviews') |
match | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-NNN' }) |
nestedKey | string | yes | Nested array key on the matched parent (e.g., 'findings') |
item | unknown | yes | Item object to append to the nested array — must conform to schema |
Update fields on a nested-array item inside a parent-array item in a project block. Finds parent and nested by predicate field match. Throws on parent or nested miss (mirrors update-block-item semantics).
Update items inside nested arrays — change finding state, mark resolved
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'spec-reviews') |
arrayKey | string | yes | Parent array key (e.g., 'reviews') |
match | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-NNN' }) |
nestedKey | string | yes | Nested array key on the matched parent (e.g., 'findings') |
nestedMatch | object | yes | Fields to match the nested item (e.g., { id: 'F-001' }) |
updates | object | yes | Fields to update on the nested item (e.g., { state: 'resolved' }) |
Remove items matching a predicate from a top-level array in a project block. Idempotent — returns { removed: 0 } on no match without throwing. Schema validation runs after removal. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Remove items from project blocks — prune retracted issues, dedupe entries
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'issues') |
arrayKey | string | yes | Top-level array key (e.g., 'issues') |
match | object | yes | Fields to match (e.g., { id: 'ISSUE-NNN' }) |
Remove items matching a predicate from a nested array on a parent-array item in a project block. Throws on parent miss; returns { removed: 0 } on nested miss without throwing.
Remove nested items — drop rejected findings, retract nested references
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'spec-reviews') |
arrayKey | string | yes | Parent array key (e.g., 'reviews') |
match | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-NNN' }) |
nestedKey | string | yes | Nested array key on the matched parent (e.g., 'findings') |
nestedMatch | object | yes | Fields to match the nested items to remove (e.g., { id: 'F-001' }) |
Enumerate and parse all .json files in a // directory, returned as a sorted array. Missing directories return [].
Enumerate project block subdirectories (phases, schemas, etc.) as parsed JSON
| Parameter | Type | Required | Description |
|---|
subdir | string | yes | Subdirectory under the substrate dir (e.g., 'phases', 'schemas') |
Read a project block file as structured JSON.
Read a project block as structured JSON
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'issues', 'tasks', 'requirements') |
Write or replace an entire project block with schema validation. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Write or replace a project block with schema validation
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'project', 'architecture') |
data | unknown | yes | Complete block data — must conform to block schema |
Get derived context state — source metrics, block summaries, planning lifecycle status.
Get context state — source metrics, block summaries, planning lifecycle status
Read-only installed-vs-catalog schema drift report — per installed schema the drift state, the baseline and catalog versions, and for behind schemas (catalog-ahead / both-diverged) the version delta (baseline -> catalog) or the content-only basis when the version string is unchanged. The front of the check-status -> update --dryRun -> update sequence. Like every substrate-lifecycle ceremony it seeds the catalog's config migration declarations AND the block-schema migration chains implied by each installed schema's catalog starter+schema version pair into migrations.json (idempotent) before its first config read, so a version-lagging legacy substrate is diagnosable and a substrate missing a catalog-implied block-schema chain self-heals; beyond those seeds it writes nothing.
Report installed-vs-catalog schema drift + the version gap for behind schemas (read-only)
Validate the substrate project-wide — source-of-truth drift (config.substrate_id vs the project-root registry), edge integrity over the closure table (endpoint resolution, relation_type registration, endpoint-kind membership), cycle detection, config-declared invariants (requires-edge, status-consistency, and derived-status stored-vs-derived rollup divergence), status-vocabulary membership, the declared-baseline staleness sweep (fired typed stale_conditions, warning-only), the nested id-bearing-array schema warning (an array at depth ≥ 1 whose item shape carries an id), a whole-block schema-validity sweep against each installed schema, and registered lens validators. Read-only; never mutates. Residue is explicit: prose truth, acceptance-criteria judgment, off-repo conditions, and engine-bypassing writes are at best flagged for human review — never prevented, and for off-repo facts not even observable — by any state engine; a bypass write surfaces only indirectly, through whichever of the checks above its damage trips (a bypass edit that trips none of them produces no issue), and no verdict asserts total semantic currency. Optional narrowing (severity / block / code filter, offset+limit pagination) bounds ONLY the returned issues[] slice and adds a `slice` head (totalIssues / matching / returned / offset / hasMore); the result's `status` ALWAYS reflects the FULL evaluation — a filtered or paginated read never hides the substrate's true verdict. Unparameterized calls return the exact prior shape.
Validate cross-block referential integrity — optionally narrow the returned issues by severity/block/code or offset+limit (status always reflects the full evaluation)
| Parameter | Type | Required | Description |
|---|
severity | unknown | no | Return only issues of this severity (issue families without a severity field classify by the same code→severity mapping their status computation uses) |
block | string | no | Return only issues whose block field equals this block name |
code | string | no | Return only issues carrying this diagnostic code |
offset | integer | no | Slice start within the filtered issue list (default 0) |
limit | integer | no | Slice size within the filtered issue list |
Read the substrate config.json as structured JSON — vocabulary, lenses, relation_types, status_buckets, display_strings, layers, block_kinds, installed_schemas, installed_blocks, installed_agents. Address ONE registry/map via `registry` (e.g. relation_types) and ONE entry within it via `id` (canonical_id) instead of reading the whole config.
Read project config — vocabulary, lenses, relation_types, status_buckets
| Parameter | Type | Required | Description |
|---|
registry | string | no | Address ONE config registry/map by key (e.g. 'relation_types', 'lenses', 'block_kinds', 'status_buckets') |
id | string | no | With registry: address ONE entry within it by canonical_id |
Discover the agent's own tool surface (all loaded extensions + builtins). Default returns a COMPACT index — one line per tool (name · param-count · one-line description) plus the active set — not the full JSON-schemas. Pass `name` to fetch ONE tool's full descriptor (name + description + parameter JSON-schema + sourceInfo). Index-then-detail pattern.
Discover available tools — compact index, or one tool's full descriptor via name
| Parameter | Type | Required | Description |
|---|
name | string | no | Address ONE tool by name → full descriptor (params schema + sourceInfo) |
Enumerate installable sample block kinds (packaged view): per kind — title, description, item shape, applicable relation_types (as source/target), invariants, lenses — plus top-level relation_type/lens/invariant/layer/status_bucket registries. Package-intrinsic: reads the extension's bundled samples catalog, independent of any project. Optional `kind` returns one packaged kind.
Discover installable sample block kinds — title, shape, relation_types, invariants, lenses
| Parameter | Type | Required | Description |
|---|
kind | string | no | Filter to one block_kind canonical_id (e.g. 'tasks') |
Fetch and print the verbatim catalog schema body (raw JSON Schema: properties/definitions/$id) for a named block kind — diffable locally against the installed `/schemas/.schema.json` without touching node_modules. Read-only; the projection-returning sibling is read-samples-catalog.
Fetch and print the verbatim catalog schema body for a named block kind (raw JSON Schema, diffable locally)
| Parameter | Type | Required | Description |
|---|
kind | string | yes | Catalog block_kind canonical_id (e.g. 'tasks') |
Derive 'where are we + what's next' purely from the substrate — focus, in-flight items, ranked atomic-next actions, blocked items, and milestone rollups. Every facet derives from the config-declared `state_derivation` registry: which block kinds + status bucket count as in-flight, the focus fallback kind + bucket, the ordered cross-kind next-actions push order with per-entry ranking (a named field + ordered value list, e.g. gap priority P0..P3) or topo ordering over the blocking-relation graph, the relation_types whose edges contribute blockers (the stock set being `task_depends_on_task` dependencies + `task_gated_by_item` gates), the membership rollups (e.g. milestones over `phase_positioned_in_milestone`) with their complete/incomplete status strings, and the next-actions head-size cap. A blocked item's dependency/gate target that is not complete is reported in blockedBy and held out of nextActions; completeness follows the target kind's truth model — a rollup-declared kind (state_derivation.rollups, e.g. milestone) completes by its DERIVED membership rollup, the same verdict the milestones facet reports, so one read never self-contradicts and a derived-status kind's stored status field is never consulted; every other kind completes by its status bucketing to complete. Drift is surfaced always-on in the same read: a rollup item whose stored status string differs from the derived primary carries `stored_status` alongside on its milestones[] entry, and a `driftWarnings` head rides the payload — one entry per divergent item covered by a config-declared derived-status invariant, classified exactly as context-validate classifies the same state (severity, message, block, field, code) but computed from this derivation's own working set, no separate validate run; a converged substrate carries no stored_status fields and no head. Drift surfacing flags stored-vs-derived rollup divergence for review; the read never asserts the stored value is wrong. A substrate whose config declares no `state_derivation` reports focus 'state-derivation not configured' with empty arrays. No writes; nothing hand-stored.
Derive current project state from the config-declared state_derivation registry — focus, in-flight, ranked next actions, blocked, milestone rollups with always-on drift surfacing (stored_status alongside a divergent entry + an invariant-classified driftWarnings head, flagged for review, never asserting the stored value wrong)
Derive the substrate bootstrap state for the cwd, purely from the filesystem: 'no-pointer' | 'no-config' | 'skeleton' | 'not-installed' | 'ready', plus the resolved contextDir and any declared-but-unmaterialized installed assets. Bootstrap (/context init or /context switch -c ) now writes a minimal schema-valid config empty of vocabulary, so a freshly-bootstrapped substrate lands at 'skeleton' — onward via /context accept-all (adopt the packaged catalog, then /context install) OR amend-config / edit (build a custom vocabulary). Unlike every other tool, this NEVER throws on an un-bootstrapped substrate — it returns 'no-pointer' so you can detect a fresh substrate and tell the user to run /context init → /context accept-all → /context install (bootstrap requires user authorization via interactive confirmation). No writes.
Derive substrate bootstrap state — no-pointer | no-config | skeleton | not-installed | ready (never throws pre-bootstrap)
Rename a canonical_id (kind: item | relation_type | lens | layer) from oldId to newId across all substrate surfaces that carry it as DATA — item home block + relations.json edges, or the relevant config registries. Out-of-substrate occurrences (analysis MDs, git history) are REPORTED, never rewritten. block_kind renames are unsupported (filesystem cascade). Use dryRun to preview the would-change counts without writing. Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Rename a canonical_id (item/relation_type/lens/layer) across substrate; dryRun to preview
| Parameter | Type | Required | Description |
|---|
kind | string | yes | One of: item |
oldId | string | yes | Current canonical_id to rename from |
newId | string | yes | New canonical_id to rename to |
dryRun | boolean | no | Compute would-change counts without writing |
Scoped add / replace / remove of ONE entry in ONE config.json registry (block_kinds, relation_types, lenses, layers, invariants, status_buckets, display_strings, naming, installed_schemas, installed_blocks, installed_agents, hierarchy). The whole resulting config is AJV-validated (SHAPE) and op-correctness is enforced (add ⇒ key absent, replace/remove ⇒ key present). Cross-registry referential integrity (removing a still-referenced relation_type / lens / layer / block_kind) is NOT checked here — run context-validate after. dryRun previews without writing.
Add/replace/remove one entry in a config.json registry (vocabulary, lenses, invariants, status_buckets)
| Parameter | Type | Required | Description |
|---|
registry | string | yes | One of: block_kinds |
operation | string | yes | add |
key | string | yes | Entry key: id for keyed-array (block_kinds/relation_types/lenses/layers/invariants), map key for map (status_buckets/display_strings/naming), the string value for string-array (installed_schemas/installed_blocks/installed_agents), or a JSON {parent_block, child_block, relation_type} for hierarchy |
entry | unknown | no | Entry payload: object for keyed-array/hierarchy, string for map value; omit for remove. For keyed-array its id field must equal key; for string-array (when given) it must equal key |
dryRun | boolean | no | Preview the op without writing config.json |
Read a substrate schema by name as parsed JSON. Returns null when the schema file is absent. Address ONE property via `path` (dotted/bracket, e.g. properties.tasks.items.properties.status) instead of reading the whole schema.
Read a block schema as structured JSON — optionally address one property via path
| Parameter | Type | Required | Description |
|---|
schemaName | string | yes | Schema name without extension (e.g., 'tasks', 'decisions', 'issues') |
path | string | no | Address ONE property by dotted/bracket path (e.g. 'properties.tasks.items.properties.status') |
Create or replace a substrate block-kind JSON Schema. operation 'create' requires the schema absent; 'replace' requires it present. The body is AJV draft-07 meta-validated before an atomic write. When a replace advances the schema's declared version and the packaged catalog ships a migration chain reaching the new version, that chain is registered automatically so items declaring the prior schema_version keep reading; a version bump the catalog does not cover (a non-catalog schema, or an unknown transition) still requires a companion migration declaration via write-schema-migration, without which read/write of items declaring the older schema_version throws version-mismatch. Registering the block_kind that points at this schema is a separate step (amend-config block_kinds).
Create or replace a block-kind JSON Schema (meta-validated, atomic)
| Parameter | Type | Required | Description |
|---|
operation | string | yes | create |
schemaName | string | yes | Schema name without extension (e.g., 'tasks') |
schema | unknown | yes | The whole JSON Schema object (draft-07). Accepts a JSON string. |
dryRun | boolean | no | Meta-validate without writing |
Commit the reconciliation of a schema merge conflict surfaced by update. Run this AFTER reconciling a both-diverged conflict update reported: it writes the reconciled schema body (meta-validated, atomic, operation 'replace') AND advances the merge base for that schema to the packaged catalog body AND, when the resolution advances the schema's declared version and the packaged catalog ships a migration chain reaching it, registers that chain into migrations.json (reported under migrationsRegistered) — the same registration update's catalog-ahead resync performs, so the resolved schema's block data can still forward-migrate on read. Advancing the base is the step a bare write-schema lacks — without it, update's 3-way merge re-derives the SAME conflict on every subsequent run because the base never moves off the original pre-conflict body. With the base advanced to the catalog, the next update sees the schema as locally-modified (base === catalog ≠ your body) and the deterministic merge takes your reconciled body (base === theirs → ours) — auto-merging with zero conflicts and preserving your resolution. If schema is omitted, the current on-disk schema is treated as already reconciled and only the base is advanced. The calling agent runs this; no subordinate resolver is spawned.
Commit a reconciled schema conflict: write the resolved body + advance the merge base to the catalog so update stops re-reporting it (run after reconciling an update conflict)
| Parameter | Type | Required | Description |
|---|
schemaName | string | yes | Schema name without extension (e.g., 'tasks') |
schema | unknown | no | The reconciled schema body R (whole JSON Schema object, draft-07; accepts a JSON string). If omitted, the current on-disk schema is treated as already reconciled and only the merge base is advanced. |
Commit the resolution of a blocked schema surfaced by update. Run AFTER fixing the block's items (or widening the local schema): when the block file carries git-style failure markers (written by update), strips the full-line marker sentinels first, then re-validates the corrected block against the pinned target schema from the pending-blocked record; on pass registers the migration chain, writes the target schema, advances the merge base to the target (so a subsequent update converges instead of re-blocking), and clears the pending entry; on fail reports the remaining per-item failures and writes nothing. The commit is all-or-nothing: a throw partway through it restores every touched file byte-exact — migrations.json, the installed schema, the block file, config.json, and the pending record — and reports the failure, never a partial commit. On a substrate whose config carries no substrate_id, resolve-blocked establishes the identity at entry (mints, persists, registers) before the commit's stamping write and reports it under substrateIdEstablished.
Commit a blocked schema's resolution: strip any git-style failure markers, re-validate the corrected block against the pinned target, then write the target schema + advance the base + clear the pending record (run after fixing the items update reported blocked)
| Parameter | Type | Required | Description |
|---|
schemaName | string | yes | Schema name with a pending-blocked entry (from update's blocked report) |
Declare a schema version-bump migration into substrate (migrations.json). operation 'create' appends a new declaration; 'replace' overwrites an existing declaration matched by (schemaName, fromVersion); 'remove' drops a declaration. kind='identity' asserts the bump is shape-compatible (no data transform); kind='declarative-transform' carries a TransformSpec of rename/set/delete/coerce/map_each operations on dotted JSON paths; map_each addresses an array — table mode maps each string element through a lookup (unmatched elements become {relation_type, item_endpoint} with parent/child fallback), set-on-each mode sets a field on every object element. The loaded MigrationRegistry resolves the recorded edge at next read/write so block items declaring an older schema_version walk forward without process restart. Requires user authorization via interactive confirmation at the pi-dispatch auth-gate; on confirm, the verified terminal-operator identity is stamped as writer.
Declare a schema version-bump migration (identity or declarative-transform) into migrations.json
| Parameter | Type | Required | Description |
|---|
operation | string | yes | create |
schemaName | string | yes | Schema name without extension (e.g., 'tasks'). |
fromVersion | string | yes | Source schema semver this migration walks forward FROM. |
toVersion | string | yes | Destination schema semver this migration produces. Must differ from fromVersion. Ignored for operation=remove. |
kind | string | no | identity |
transform | unknown | no | TransformSpec body — required when kind='declarative-transform'; forbidden when kind='identity'. Accepts a JSON string. |
writer | object | yes | DispatchContext.writer per pi-context/src/dispatch-context.ts. |
Initialize the substrate dir: bootstrap pointer + dirs + a minimal schema-valid SKELETON config empty of vocabulary. Lands at the 'skeleton' bootstrap state — onward via accept-all (adopt the packaged catalog, then install) OR amend-config / edit (build a custom vocabulary).
Initialize the substrate dir (bootstrap pointer + dirs + skeleton config; onward via accept-all OR amend-config/edit)
| Parameter | Type | Required | Description |
|---|
contextDir | string | yes | Substrate dir name (e.g. .context). Required — no default. |
Adopt the canonical packaged conception (samples/conception.json) as this substrate's config.json (accept-all). Writes config only — run install after. Skeleton-aware: overwrites a SKELETON config (the empty-of-vocabulary config init / switch -c writes) but never a POPULATED one.
Adopt the canonical conception as config (accept-all)
Install (materialize) the schemas, starter blocks, and agent specs declared in config.json's installed_schemas / installed_blocks / installed_agents from the package samples catalog. Default skip-if-exists (installed files never overwritten without --update); populated block data is always preserved (even with --update); empty or absent blocks get the catalog starter. Agent specs materialize as editable project files under agents/ (with their output schemas under agents/schemas/) and are NEVER overwritten — not even with --update (an existing spec is reported skipped) — and are not recorded in the install baseline; deleting a materialized spec falls back to the bundled tier and re-running install re-materializes it. Records the install baseline (config.installed_from: catalog source + per-schema fingerprint) for installed-vs-catalog drift detection (schemas only). A re-install on an unchanged substrate is idempotent. On a substrate whose config carries no substrate_id, install establishes the identity at entry (mints, persists to config.json, registers in the project registry) and reports it under substrateIdEstablished; an established identity is never re-minted.
Install declared schemas + starter blocks + agent specs from the samples catalog (skip-if-exists; --update re-syncs schemas + replaces empty blocks; agent specs are never overwritten; records the config.installed_from baseline)
| Parameter | Type | Required | Description |
|---|
update | boolean | no | When true, re-sync existing installed schemas (migration-aware) and replace empty blocks with the catalog starter; populated block data is never overwritten. When false (default), skip existing files. |
Bring the installed substrate model (schemas) current with the packaged catalog. Per installed schema, consults the read-only drift check and routes by state: an already-current (in-sync) schema is a no-op; a schema the package shipped a newer version of (catalog-ahead) is re-synced through the migration-aware path; a schema edited locally (locally-modified / both-diverged) is reconciled by a deterministic 3-way merge of base (the as-installed body in the object store, keyed by the recorded baseline content_hash) × ours (the installed schema) × theirs (the catalog schema) — disjoint edits auto-merge so both the user's and the catalog's changes survive (required / enum / array-valued type nodes merge as sets), and a schema with irreconcilable per-path conflicts is left unmodified — the conflict set is returned in the op output (under conflicts) alongside a readable report, and the calling agent reconciles it then commits via resolve-conflict — which writes the reconciled body, advances the merge base to the catalog so update stops re-reporting it, and registers a known catalog migration chain when the reconciliation advances the schema's version (no subordinate resolver is spawned); undecidable / absent schemas (no-baseline / missing-catalog / missing-installed) are reported, not touched. Update also additively propagates catalog-new config-registry entries (relation_types / invariants / block_kinds / lenses) that are absent from the substrate config, preserving every user-authored entry and any locally-diverged body of an existing entry (additive-only — present entries are never overwritten). Update reports, under migrationsRegistered, the migration declarations a version-bump resync or a version-advancing 3-way merge registers into migrations.json (each as schema / from / to). A blocked (refused) catalog-ahead schema additionally carries its diagnostic detail under blockedDetail (one entry per blocked schema): the refusal reason — no-migration-chain (no shipped chain reaches the catalog version) vs validation-failed (the forward-migrated items fail the catalog schema) vs write-failed (a non-validation throw at the write boundary, e.g. the block writer's duplicate-item-id guard; the failures entry carries the thrown message, the items were NOT flagged invalid, and no markers or pending-blocked record are produced) — the installed -> catalog version pair, and for a validation failure the per-item failures naming the failing item id, field, and constraint. A live blocked resync also persists a pending-blocked record (pinning the target catalog schema + the chain reaching it) consumable by resolve-blocked, which commits the resolution once the block's items are fixed. Pass dryRun to preview the per-schema action plan; dryRun predicts the precise per-schema catalog-ahead outcome (resync / migrate / block / merge / conflict) by running the forward-migration + re-validation in memory, the per-blocked-schema diagnostic detail, the config-registry entries that would be added, AND the migration declarations that would be registered, writing nothing beyond the idempotent ceremony seeds of the catalog's config migration declarations and the block-schema migration chains implied by each installed schema's catalog starter+schema version pair into migrations.json (every substrate-lifecycle ceremony seeds at entry, before its first config read, so a version-lagging legacy substrate heals instead of throwing and a substrate missing a catalog-implied block-schema chain self-heals). When a catalog-ahead resync is blocked because the block's items fail the catalog schema (validation-failed), update inscribes git-style failure markers INTO the block file at the offending items (full-line `<<<<<<< BLOCKED …` / `>>>>>>> target: …` sentinels), pinning the pre-marker bytes so resolve-blocked can strip the markers and re-validate; the schema and migrations.json stay byte-unchanged. A dryRun preview writes no markers. Because update applies per-component (a blocked schema rolls back only itself; the additive registry propagation writes regardless), a run that refuses any schema while applying registry additions or other-schema resyncs/migrations/merges reports the partiality under partialApplication — applied and notApplied channel mirrors plus a one-line summary naming what was applied alongside what was refused and why — so a blocked run never reads as a no-op; dryRun reports the predicted partiality in the same shape. On a substrate whose config carries no substrate_id, a LIVE update establishes the identity at entry (mints, persists to config.json, registers in the project registry) before its first identity-stamping write — so a pre-identity substrate heals on the ceremony instead of refusing — and reports it under substrateIdEstablished; an established identity is never re-minted, and dryRun (no stamping writes) establishes nothing.
Update the installed schema model from the catalog (3-way merges locally-modified schemas, preserving non-conflicting edits; conflicts → returned in the op output + a report for the calling agent to reconcile and commit via resolve-conflict; a blocked resync carries blockedDetail — reason (no-migration-chain / validation-failed / write-failed for a non-validation write-boundary throw), version pair, per-item failures — and a validation-failed block persists a pending-blocked record (target catalog schema + the chain reaching it) resolved via resolve-blocked once the block's items are fixed; a validation-failed block is marked in place with git-style failure markers (recoverable; stripped + re-validated by resolve-blocked); --dry-run predicts the precise per-schema outcome — resync / migrate / block / merge / conflict — via in-memory forward-migration + re-validation, writing nothing; a run that refuses any schema while applying registry additions or other-schema updates surfaces the partiality under partialApplication with a one-line summary, so a blocked run never reads as a no-op)
| Parameter | Type | Required | Description |
|---|
dryRun | boolean | no | Preview the per-schema action plan without writing anything. |
Converge stored substrate state with its derivation (the repair half of the derived-status invariant class). For every block kind a derived-status invariant declares (paired with its state_derivation.rollups entry), computes each item's stored-vs-derived status delta using the SAME completeness helper the state derivation's gate satisfaction and context-validate use — the preview, the detector, and the repair cannot disagree. The sweep also includes declared-baseline STALENESS: every stale_conditions-bearing item whose status buckets complete and whose typed condition fired (item-status / file-changed) transitions to stale — the same evaluateStalenessCandidates verdict context-validate flags with. --dryRun returns the exact delta + transition sets a live run would apply (deltas: id, block, from stored value, to derived value, declaring invariant; stalenessTransitions: id, block, from, to stale, firing reasons), writing nothing. A live run applies exactly those sets through the standard validated write path — identity-stamped, envelope-stamped, attested to the invoking writer — and reports the applied counts; a converge-write is not authoring, the written value IS the derivation, and the stale transition applies a condition the item itself declared. Scope: derived-status deltas + declared-staleness transitions ONLY — the op never writes an authored-status kind (feature/gap/issue/task buckets are human judgment) and never touches prose; authored statuses surface for review through context-validate's signals — among them declared invariant violations, the status-vocabulary warning, and for stale_conditions-bearing items the staleness sweep — and prose is not validated at all — its review is human. The residue is explicit: prose truth, acceptance-criteria judgment, off-repo conditions, and engine-bypassing writes are at best flagged for human review — never prevented, and for off-repo facts not even observable — by any state engine; neither reconcile nor validate forecloses semantic currency. Ceremony discipline: seeds the catalog config migration declarations and the block-schema migration chains implied by each installed schema's catalog starter+schema version pair at entry, and a live run on a substrate with no substrate_id establishes the identity first (reported under substrateIdEstablished). A converged substrate is a clean no-op both ways.
Converge stored rollup-kind statuses with their derivation and apply declared complete-to-stale transitions (--dryRun previews the exact sets; live applies through the validated write path; never touches authored statuses or prose)
| Parameter | Type | Required | Description |
|---|
dryRun | boolean | no | Preview the exact delta set without writing anything. |
Validate a block's items against a named basis, read-only, returning the per-item failures (item id, field, constraint). Every result carries a resolution field disclosing the basis the verdict was computed against. Default basis 'catalog' (resolution: 'catalog-forward-preview') is a catalog-forward UPDATE-PREVIEW, not a readability check: it validates against the CATALOG schema body after forward-migrating the items in memory through the shipped catalog chain via a fresh self-seeded registry (never the project's migrations.json), so its valid:true means 'would pass the catalog schema after a catalog update' and can differ from whether the block currently reads. Basis 'installed' (resolution: 'installed-read-path') answers 'does this block read?': it validates against the INSTALLED schema plus the PROJECT migration registry via the same validateBlockWithMigrationForDir resolution the canonical read gate uses, non-throwing — where a read would throw (e.g. a version-lagging block with no project migration chain) it returns valid:false with the failure detail. Returns block / from (the block's declared version) / to (the catalog version for basis=catalog, the installed schema version for basis=installed) / valid / failures[] (each: itemId — the failing item's id when the instancePath resolves to one — instancePath, keyword, message) / resolution. Read-only: never overwrites the schema, the block, or migrations.json. An unknown block or a missing installed block file throws.
Validate a block's items read-only against a disclosed basis — default 'catalog' previews the catalog-forward update (catalog schema + self-seeded catalog-chain registry); basis 'installed' answers 'does this block read?' via the read path's installed schema + project registry, returning valid:false where a read would throw; every result names its resolution
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g. 'tasks') |
basis | unknown | no | Validation basis: 'catalog' (default) previews the catalog-forward update against the catalog schema + shipped chain; 'installed' validates against the installed schema + project migration registry (the canonical read path's resolution), non-throwing. |
Flip the bootstrap pointer to a different substrate dir (parallel to git switch). Default: flip to an existing substrate at target_dir (requires config.json present). create_new=true: bootstrap a fresh substrate at target_dir AND flip in one operation. to_previous=true: flip back to the pointer's previous_contextDir (target_dir ignored).
Switch the bootstrap pointer to a different substrate dir
| Parameter | Type | Required | Description |
|---|
target_dir | string | yes | Substrate dir name to switch to (e.g. '.context'). Required for default + create_new modes; ignored for to_previous mode. |
create_new | boolean | no | When true, bootstrap target_dir as a fresh substrate (dirs + a minimal schema-valid SKELETON config empty of vocabulary — onward via accept-all OR amend/edit) AND flip the pointer in one operation (parallel to 'git switch -c '). Default false (flip to existing substrate; fails if target_dir lacks config.json). |
to_previous | boolean | no | When true, flip the pointer back to its previous_contextDir (parallel to 'git switch -'). Requires the pointer to carry a previous_contextDir (a prior switch must have populated it). When true, target_dir is ignored. |
writer | object | no | DispatchContext.writer — stamped by auth-gate on operator confirm; in-body trusts the stamped value. |
Enumerate top-level dirs under cwd containing a config.json (switchable substrates). Marks the active one with isActive=true. Read-only.
List switchable substrate dirs under cwd
Move a non-active substrate dir to archive//. Refuses to archive the active substrate (the dir the bootstrap pointer currently names) or to clobber an existing archive//.
Archive a non-active substrate dir to archive/
/
| Parameter | Type | Required | Description |
|---|
target_dir | string | yes | Substrate dir name to archive (e.g. '.project'). Refused if it is the active substrate. |
Filter the array items of a block by a single-field predicate (eq / neq / in / matches). Discovers the single top-level array property in the block; items missing the predicate field are never matched. Wraps the canonical readBlock + caller-side filter into one queryable surface; never mutates the block.
Filter a block's items by a predicate — eq / neq / in / matches against a single field
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'tasks', 'decisions', 'framework-gaps', 'context-contracts') |
field | string | yes | Item field to test (e.g., 'status', 'priority', 'id') |
op | unknown | yes | Comparison operator: eq (===), neq (!==), in (value is array, item[field] in it), matches (regexp test on string) |
value | unknown | yes | Comparison value — scalar for eq/neq, array for in, regexp pattern string for matches |
Look up the block, array key, and item payload for a given ID across all blocks in the substrate dir. Returns null when no item matches. Mirrors the resolveItemById SDK function and shares its prefix-vs-block invariant — IDs whose prefix maps to a known block but live elsewhere throw at index-build time.
Resolve a kind-prefixed ID (DEC-/FEAT-/FGAP-/issue-/REQ-/TASK-/etc.) to its owning block and item
| Parameter | Type | Required | Description |
|---|
id | string | yes | Kind-prefixed ID, e.g., DEC-NNNN / FEAT-NNN / FGAP-NNN / ISSUE-NNN |
Read a single item from a named block by its id — returns the item or null. Block-scoped (unlike resolve-item-by-id, which searches all blocks by kind-prefixed id). Avoids fetching a whole large block to get one item.
Read one item from a block by id (block-scoped; null if absent)
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'tasks', 'decisions', 'framework-gaps') |
id | string | yes | Item id within the block (e.g., 'TASK-NNN') |
Paginate a block's items: returns { items, total, hasMore }. offset default 0, limit default 50. Use for blocks too large to fetch whole (past the 50KB read-block cap). total is the full item count; hasMore signals another page.
Paginate a block's items — offset + limit; returns {items,total,hasMore}
| Parameter | Type | Required | Description |
|---|
block | string | yes | Block name (e.g., 'framework-gaps', 'decisions', 'issues') |
offset | integer | no | Start index (default 0) |
limit | integer | no | Max items to return (default 50) |
Join two blocks in one call. EDGE mode: pass `relationType` — pairs left items with right-block items connected by that relations.json edge (`leftEndpoint` parent|child, default parent). FIELD mode: pass `leftField`+`rightField` — pairs where left[leftField] === right[rightField]. Optional left pre-filter via where{Field,Op,Value}. Returns [{left, right:[]}] (right always an array; one-to-many). Use instead of N+1 read-block + resolve calls.
Join two blocks in one call — by relation edge or shared field; returns {left,right[]} pairs
| Parameter | Type | Required | Description |
|---|
leftBlock | string | yes | Left block name (e.g., 'tasks') |
rightBlock | string | yes | Right block name (e.g., 'verification') |
relationType | string | no | Edge mode: relations.json relation_type |
leftField | string | no | Field mode: left item field |
rightField | string | no | Field mode: right item field |
leftEndpoint | unknown | no | Edge mode: is the left item the edge parent (default) or child |
whereField | string | no | Optional left pre-filter field |
whereOp | unknown | no | |
whereValue | unknown | no | Optional left pre-filter value |
Bulk variant of resolve-item-by-id — resolve N kind-prefixed ids against a single buildIdIndex traversal. Returns an object mapping each input id to its ItemLocation (block / arrayKey / item) or null when not found. Coexists with the singular resolve-item-by-id tool; bulk collapses the N×singular-call pattern for callers resolving multiple ids in one render pass.
Resolve a batch of kind-prefixed ids (DEC-/FGAP-/TASK-/issue-/REQ-/...) in one call
| Parameter | Type | Required | Description |
|---|
ids | array | yes | Array of kind-prefixed ids (DEC-/FGAP-/TASK-/issue-/REQ-/...) to resolve in one call |
Complete a task with verification gate — the closure ATOM. Requires a passing verification entry, then FILES the verification_verifies_item edge itself (idempotent — a pre-existing exact edge is a no-op) and flips the task status to completed in one op run, so the write-time invariant gate judges the joint end-state. No prior append-relation step is needed (a standalone edge or status write would be refused by error-severity closure invariants; this op IS the legal transition). Write pipeline: after this op's write, rollup-kind stored statuses converge with their derivation, and the config invariants are re-evaluated delta-scoped — a violation newly introduced by this write refuses it at error severity (substrate byte-restored) or is surfaced on the result at warning severity (write-warning lines / writeWarnings); pre-existing violations never block.
Complete a task — gates on passing verification, files the verification edge itself, then flips status (one atom)
| Parameter | Type | Required | Description |
|---|
taskId | string | yes | Task ID to complete |
verificationId | string | yes | Verification entry ID (must have status 'passed'; the op files the linking edge itself) |
Validate substrate relations.json edges against config-declared lenses + hierarchy + relation_types and the cross-block id index. Returns SubstrateValidationResult with status (clean/warnings/invalid) and per-issue diagnostics. Optional narrowing (severity / code filter, offset+limit pagination) bounds ONLY the returned issues[] slice and adds a `slice` head (totalIssues / matching / returned / offset / hasMore); the result's `status` ALWAYS reflects the FULL evaluation — a filtered or paginated read never hides the substrate's true verdict. Unparameterized calls return the exact prior shape.
Validate substrate relations against config + items — optionally narrow the returned issues by severity/code or offset+limit (status always reflects the full evaluation)
| Parameter | Type | Required | Description |
|---|
severity | unknown | no | Return only issues of this severity (issue families without a severity field classify by the same code→severity mapping their status computation uses) |
code | string | no | Return only issues carrying this diagnostic code |
offset | integer | no | Slice start within the filtered issue list (default 0) |
limit | integer | no | Slice size within the filtered issue list |
Materialize the Edge[] for a named lens — synthetic edges from derived_from_field for auto-derived lenses; authored edges filtered by relation_type for hand-curated lenses; unioned items from composition members for kind=composition lenses.
Materialize edges for a named lens (auto-derived or hand-curated)
| Parameter | Type | Required | Description |
|---|
lensId | string | yes | Lens id from config.lenses[].id |
Project a config-declared lens (config.lenses[]) as a binned item-view. Without --bin, a bin->count summary (always under the read cap). With --bin, that bin's items paged by --offset/--limit. Serves target, composition, and hand-curated lenses.
Project a config-declared lens as a binned item-view — bin->count summary, or one bin's items paged
| Parameter | Type | Required | Description |
|---|
lensId | string | yes | Lens id from config.lenses[].id |
bin | string | no | Return this bin's items paged; omit for a bin->count summary |
offset | integer | no | Per-bin page start index (default 0) |
limit | integer | no | Per-bin page size (default 50) |
Walk closure-table descendants of a parent id under a given relation_type. Returns string[] of descendant ids (may be empty if no children or relations.json absent). For a DISJOINT-kind relation, querying from the wrong (target-kind) end THROWS naming walk-ancestors instead of silently returning []; same-kind / wildcard relations return [] honestly.
Walk closure-table descendants under a relation_type
| Parameter | Type | Required | Description |
|---|
parentId | string | yes | Parent id (canonical id or lens bin name) |
relationType | string | yes | Relation type from config.relation_types[].canonical_id |
Walk closure-table ancestors of an item id under a given relation_type — reverse-direction counterpart to context-walk-descendants. Returns string[] of ancestor ids (may be empty if no parents or relations.json absent). For a DISJOINT-kind relation, querying from the wrong (source-kind) end THROWS naming context-walk-descendants instead of silently returning []; same-kind / wildcard relations return [] honestly.
Walk closure-table ancestors under a relation_type
| Parameter | Type | Required | Description |
|---|
itemId | string | yes | Child item id whose ancestors are sought |
relationType | string | yes | Relation type from config.relation_types[].canonical_id |
Find all closure-table edges incident on an item id (inbound, outbound, or both). Returns Edge[] preserving relation_type + ordinal per record — edge-level view, not the id-chain projection that walk-ancestors / context-walk-descendants emit.
Find closure-table edges incident on an item id
| Parameter | Type | Required | Description |
|---|
itemId | string | yes | Item id whose incident edges are sought |
direction | unknown | no | inbound: edges where child === itemId; outbound: edges where parent === itemId; both: union (default). |
Compose a ContextBundle for a work-unit by reading its context-contract (by unit_kind) and walking declared relation_types bidirectionally per direction semantic. Returns unit + perRelationType buckets of resolved items + traversal_depth + scoped_at. Substrate primitive serving harness-confined dispatch.
Compose ContextBundle for unit + context-contract-declared bundle_relation_types
| Parameter | Type | Required | Description |
|---|
unitId | string | yes | Work-unit id (e.g. TASK-NNN / DEC-NNNN / FGAP-NNN) |
kind | string | yes | Unit-kind type tag (e.g. 'task', 'decision', 'verification') matching a context-contract entry's unit_kind |
maxDepth | integer | no | Override per-relation-type max_depth via Math.min against each spec.max_depth |
Load the derived roadmap view over the milestone_precedes_milestone DAG: milestone-block items topo-ordered by the authored precedes edges (order + cycles), each milestone carrying its derived `status`/phaseCount (currentState's milestone rollup — `status` is the authoritative completeness verdict), its member phases (parents of phase_positioned_in_milestone edges, each with its authored phase `status`), each phase's tasks (parents of task_positioned_in_phase edges), and per-phase + per-milestone `taskProgress` (a task-status aggregation for PROGRESS display ONLY — NOT a completeness verdict; read `status` for completeness, never taskProgress). Adjacency comes strictly from the authored edges — never inferred from order. Zero milestones is a valid empty view.
Load the derived milestone roadmap view
Render the derived roadmap as pure-textual markdown — milestone order list (topo over the authored milestone_precedes_milestone edges), per-milestone sections with **Preceded by:** adjacency lines sourced strictly from those edges (alphabetically sorted; '—' when none), per-milestone **Task progress:** counts (a task-status aggregation for progress display only — the completeness verdict is the milestone/phase `status` printed in the section heading, not the task-progress counts), and per-phase task tables. Cycle participants surface under a separate heading with a Cycles-detected line. NO mermaid / graph syntax; adjacency is never inferred from order consecutive pairs.
Render the derived milestone roadmap as markdown
Validate the derived roadmap over the milestone_precedes_milestone edges. Error codes: roadmap_precedes_endpoint_missing (a precedes-edge endpoint that is not a milestone-block item), roadmap_milestone_cycle (a cycle in the precedes graph), roadmap_milestone_missing (a phase_positioned_in_milestone edge whose child is not a known milestone). Warning: roadmap_status_unknown_value (a member phase whose task-progress rollup buckets unknown with tasks present — a task-progress / data-quality warning, NOT a completeness check). Info: roadmap_milestone_isolated (a milestone with zero precedes edges while others are ordered) — info never affects status (invalid iff any error-code issue, warnings iff any warning-code issue, else clean) and matches no severity filter. Display strings flow through config.display_strings (pi-context divergence). Optional narrowing (severity / code filter, offset+limit pagination) bounds ONLY the returned issues[] slice and adds a `slice` head (totalIssues / matching / returned / offset / hasMore); the result's `status` ALWAYS reflects the FULL evaluation — a filtered or paginated read never hides the substrate's true verdict. Unparameterized calls return the exact prior shape.
Validate the derived milestone roadmap — optionally narrow the returned issues by severity/code or offset+limit (status always reflects the full evaluation)
| Parameter | Type | Required | Description |
|---|
severity | unknown | no | Return only issues of this severity (issue families without a severity field classify by the same code→severity mapping their status computation uses) |
code | string | no | Return only issues carrying this diagnostic code |
offset | integer | no | Slice start within the filtered issue list (default 0) |
limit | integer | no | Slice size within the filtered issue list |
</tools_reference>
<commands_reference>
Context state management
Subcommands: init, switch, list, archive, install, check-status, accept-all, view, lens-curate, roadmap-view, roadmap-validate, status, add-work, validate, help
</commands_reference>
`session_start`, `before_agent_start`, `resources_discover`
<bundled_resources>
12 schemas, 79 samples bundled.
See references/bundled-resources.md for full inventory.
</bundled_resources>
<installable_blocks>
Names valid for the installed_blocks array in <substrate-dir>/config.json. Install with /context install <block>.
| Block | Source File |
|---|
decisions | samples/blocks/decisions.json |
framework-gaps | samples/blocks/framework-gaps.json |
tasks | samples/blocks/tasks.json |
verification | samples/blocks/verification.json |
issues | samples/blocks/issues.json |
features | samples/blocks/features.json |
research | samples/blocks/research.json |
rationale | samples/blocks/rationale.json |
spec-reviews | samples/blocks/spec-reviews.json |
layer-plans | samples/blocks/layer-plans.json |
requirements | samples/blocks/requirements.json |
conventions | samples/blocks/conventions.json |
context-contracts | samples/blocks/context-contracts.json |
phase | samples/blocks/phase.json |
story | samples/blocks/story.json |
milestone | samples/blocks/milestone.json |
work-orders | samples/blocks/work-orders.json |
session-notes | samples/blocks/session-notes.json |
</installable_blocks>
<installable_schemas>
Names valid for the installed_schemas array in <substrate-dir>/config.json. Schemas back block validation; install with /context install <schema>.
| Schema | Source File |
|---|
decisions | samples/schemas/decisions.schema.json |
framework-gaps | samples/schemas/framework-gaps.schema.json |
tasks | samples/schemas/tasks.schema.json |
verification | samples/schemas/verification.schema.json |
issues | samples/schemas/issues.schema.json |
features | samples/schemas/features.schema.json |
research | samples/schemas/research.schema.json |
rationale | samples/schemas/rationale.schema.json |
spec-reviews | samples/schemas/spec-reviews.schema.json |
layer-plans | samples/schemas/layer-plans.schema.json |
requirements | samples/schemas/requirements.schema.json |
conventions | samples/schemas/conventions.schema.json |
context-contracts | samples/schemas/context-contracts.schema.json |
phase | samples/schemas/phase.schema.json |
story | samples/schemas/story.schema.json |
milestone | samples/schemas/milestone.schema.json |
work-orders | samples/schemas/work-orders.schema.json |
session-notes | samples/schemas/session-notes.schema.json |
</installable_schemas>
<planning_vocabulary>
Block Types:
| Block | Title | Array Key | Item Fields |
|---|
decisions | Decisions | decisions | id, title, status (string (open |
framework-gaps | Framework Gaps | gaps | id, title, status (string (identified |
tasks | Tasks | tasks | id, description, status (string (planned |
verification | Verification | verifications | id, status (string (passed |
issues | Issues | issues | id, title, body, location, status (string (open |
features | Features | features | id, title, status (string (proposed |
research | Research | research | id, title, status (string (planned |
rationale | Design Rationale | rationales | id, title, narrative, phase? (integer), oid?, content_hash?, content_parent? |
spec-reviews | Spec Reviews | reviews | id, target, target_revision?, reviewer?, status (string (not-started |
layer-plans | Layer Restructure Plans | plans | id, title, status (string (draft |
requirements | Requirements | requirements | id, description, type (string (functional |
conventions | Conventions | rules | id, description, enforcement (string (lint |