@davidorex/pi-context 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -0
- package/README.md +27 -11
- package/dist/block-api.d.ts +13 -0
- package/dist/block-api.d.ts.map +1 -1
- package/dist/block-api.js +28 -3
- package/dist/block-api.js.map +1 -1
- package/dist/content-hash.d.ts +13 -0
- package/dist/content-hash.d.ts.map +1 -1
- package/dist/content-hash.js +16 -0
- package/dist/content-hash.js.map +1 -1
- package/dist/context-dir.d.ts +12 -0
- package/dist/context-dir.d.ts.map +1 -1
- package/dist/context-dir.js +14 -0
- package/dist/context-dir.js.map +1 -1
- package/dist/context-sdk.d.ts +71 -33
- package/dist/context-sdk.d.ts.map +1 -1
- package/dist/context-sdk.js +547 -149
- package/dist/context-sdk.js.map +1 -1
- package/dist/context.d.ts +213 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +119 -5
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +595 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2225 -55
- package/dist/index.js.map +1 -1
- package/dist/lens-view.d.ts +0 -5
- package/dist/lens-view.d.ts.map +1 -1
- package/dist/lens-view.js +43 -1
- package/dist/lens-view.js.map +1 -1
- package/dist/migration-registry-loader.d.ts +36 -12
- package/dist/migration-registry-loader.d.ts.map +1 -1
- package/dist/migration-registry-loader.js +79 -17
- package/dist/migration-registry-loader.js.map +1 -1
- package/dist/migrations-store.d.ts +45 -18
- package/dist/migrations-store.d.ts.map +1 -1
- package/dist/migrations-store.js +56 -22
- package/dist/migrations-store.js.map +1 -1
- package/dist/ops-registry.d.ts +16 -0
- package/dist/ops-registry.d.ts.map +1 -1
- package/dist/ops-registry.js +352 -117
- package/dist/ops-registry.js.map +1 -1
- package/dist/pending-blocked-store.d.ts +83 -0
- package/dist/pending-blocked-store.d.ts.map +1 -0
- package/dist/pending-blocked-store.js +93 -0
- package/dist/pending-blocked-store.js.map +1 -0
- package/dist/promote-item.d.ts.map +1 -1
- package/dist/promote-item.js +41 -12
- package/dist/promote-item.js.map +1 -1
- package/dist/roadmap-plan.d.ts +121 -99
- package/dist/roadmap-plan.d.ts.map +1 -1
- package/dist/roadmap-plan.js +281 -345
- package/dist/roadmap-plan.js.map +1 -1
- package/dist/schema-merge.d.ts +26 -0
- package/dist/schema-merge.d.ts.map +1 -0
- package/dist/schema-merge.js +176 -0
- package/dist/schema-merge.js.map +1 -0
- package/dist/status-vocab.d.ts +12 -2
- package/dist/status-vocab.d.ts.map +1 -1
- package/dist/status-vocab.js +14 -1
- package/dist/status-vocab.js.map +1 -1
- package/package.json +2 -1
- package/samples/blocks/milestone.json +3 -0
- package/samples/blocks/session-notes.json +1 -0
- package/samples/conception.json +358 -15
- package/samples/migrations.json +8 -0
- package/samples/schemas/context-contracts.schema.json +4 -0
- package/samples/schemas/conventions.schema.json +4 -0
- package/samples/schemas/decisions.schema.json +4 -0
- package/samples/schemas/features.schema.json +4 -0
- package/samples/schemas/framework-gaps.schema.json +5 -1
- package/samples/schemas/issues.schema.json +30 -2
- package/samples/schemas/layer-plans.schema.json +6 -2
- package/samples/schemas/milestone.schema.json +79 -0
- package/samples/schemas/phase.schema.json +4 -0
- package/samples/schemas/rationale.schema.json +4 -0
- package/samples/schemas/requirements.schema.json +4 -0
- package/samples/schemas/research.schema.json +5 -1
- package/samples/schemas/session-notes.schema.json +89 -0
- package/samples/schemas/spec-reviews.schema.json +4 -0
- package/samples/schemas/story.schema.json +8 -0
- package/samples/schemas/tasks.schema.json +4 -0
- package/samples/schemas/verification.schema.json +4 -0
- package/samples/schemas/work-orders.schema.json +6 -2
- package/schemas/config.schema.json +101 -3
- package/schemas/migrations.schema.json +25 -0
- package/schemas/pending-blocked.schema.json +190 -0
- package/skill-narrative.md +14 -10
- package/skills/pi-context/SKILL.md +127 -49
- package/skills/pi-context/references/bundled-resources.md +7 -2
|
@@ -36,14 +36,16 @@ Update fields on an item in a project block array. Finds by predicate field matc
|
|
|
36
36
|
</tool>
|
|
37
37
|
|
|
38
38
|
<tool name="append-relation">
|
|
39
|
-
Append a closure-table relation (edge:
|
|
39
|
+
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 (endpoints resolve, relation_type registered, no cycle) is NOT checked here — run context-validate after. Creates relations.json if absent.
|
|
40
40
|
|
|
41
|
-
*Create a relation/edge between two items (parent
|
|
41
|
+
*Create a relation/edge between two items (raw --parent/--child, or role-typed --primary/--counter mapped via role_direction)*
|
|
42
42
|
|
|
43
43
|
| Parameter | Type | Required | Description |
|
|
44
44
|
|-----------|------|----------|-------------|
|
|
45
|
-
| `parent` | string |
|
|
46
|
-
| `child` | string |
|
|
45
|
+
| `parent` | string | no | Parent-endpoint selector (canonical id / <alias>:<refname> / lens bin) — RAW orientation. Mutually exclusive with --primary/--counter. |
|
|
46
|
+
| `child` | string | no | Child-endpoint selector — RAW orientation. Mutually exclusive with --primary/--counter. |
|
|
47
|
+
| `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. |
|
|
48
|
+
| `counter` | string | no | Selector of the endpoint holding the relation's COUNTER role (ROLE-TYPED orientation). Requires --primary. |
|
|
47
49
|
| `relation_type` | string | yes | Registered relation_type canonical_id / hierarchy edge type / lens id |
|
|
48
50
|
| `ordinal` | integer | no | Optional sibling-ordering within (parent, relation_type) |
|
|
49
51
|
| `dryRun` | boolean | no | Preview without writing relations.json |
|
|
@@ -63,7 +65,7 @@ Remove the single closure-table relation (edge) matching parent+child+relation_t
|
|
|
63
65
|
</tool>
|
|
64
66
|
|
|
65
67
|
<tool name="replace-relation">
|
|
66
|
-
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.
|
|
68
|
+
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.
|
|
67
69
|
|
|
68
70
|
*Atomically swap one relation/edge for another in a single write*
|
|
69
71
|
|
|
@@ -80,13 +82,13 @@ Atomically replace one closure-table relation with another in a SINGLE write (no
|
|
|
80
82
|
</tool>
|
|
81
83
|
|
|
82
84
|
<tool name="append-relations">
|
|
83
|
-
Append MANY closure-table relations to relations.json in a single write. Each edge is an object { parent, child,
|
|
85
|
+
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 NOT checked here — run context-validate after. Creates relations.json if absent.
|
|
84
86
|
|
|
85
|
-
*Create many relations/edges between items in one write*
|
|
87
|
+
*Create many relations/edges between items in one write (raw or role-typed per edge)*
|
|
86
88
|
|
|
87
89
|
| Parameter | Type | Required | Description |
|
|
88
90
|
|-----------|------|----------|-------------|
|
|
89
|
-
| `edges` | unknown | yes | JSON array of { parent, child
|
|
91
|
+
| `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 / <alias>:<refname> / lens-bin. |
|
|
90
92
|
| `dryRun` | boolean | no | Preview without writing relations.json |
|
|
91
93
|
</tool>
|
|
92
94
|
|
|
@@ -211,6 +213,13 @@ Get derived context state — source metrics, block summaries, planning lifecycl
|
|
|
211
213
|
|
|
212
214
|
</tool>
|
|
213
215
|
|
|
216
|
+
<tool name="context-check-status">
|
|
217
|
+
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 into migrations.json (idempotent) before its first config read, so a version-lagging legacy substrate is diagnosable; beyond that seed it writes nothing.
|
|
218
|
+
|
|
219
|
+
*Report installed-vs-catalog schema drift + the version gap for behind schemas (read-only)*
|
|
220
|
+
|
|
221
|
+
</tool>
|
|
222
|
+
|
|
214
223
|
<tool name="context-validate">
|
|
215
224
|
Validate cross-block referential integrity — check that IDs referenced across blocks exist.
|
|
216
225
|
|
|
@@ -249,10 +258,20 @@ Enumerate installable sample block kinds (packaged view): per kind — title, de
|
|
|
249
258
|
| `kind` | string | no | Filter to one block_kind canonical_id (e.g. 'tasks') |
|
|
250
259
|
</tool>
|
|
251
260
|
|
|
261
|
+
<tool name="read-catalog-schema">
|
|
262
|
+
Fetch and print the verbatim catalog schema body (raw JSON Schema: properties/definitions/$id) for a named block kind — diffable locally against the installed `<substrate>/schemas/<name>.schema.json` without touching node_modules. Read-only; the projection-returning sibling is read-samples-catalog.
|
|
263
|
+
|
|
264
|
+
*Fetch and print the verbatim catalog schema body for a named block kind (raw JSON Schema, diffable locally)*
|
|
265
|
+
|
|
266
|
+
| Parameter | Type | Required | Description |
|
|
267
|
+
|-----------|------|----------|-------------|
|
|
268
|
+
| `kind` | string | yes | Catalog block_kind canonical_id (e.g. 'tasks') |
|
|
269
|
+
</tool>
|
|
270
|
+
|
|
252
271
|
<tool name="context-current-state">
|
|
253
|
-
Derive 'where are we + what's next' purely from the substrate — focus, in-flight
|
|
272
|
+
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 has not reached the complete bucket is reported in blockedBy and held out of nextActions; a target reaching its complete status releases it. A substrate whose config declares no `state_derivation` reports focus 'state-derivation not configured' with empty arrays. No writes; nothing hand-stored.
|
|
254
273
|
|
|
255
|
-
*Derive current project state — focus, in-flight, next actions, blocked*
|
|
274
|
+
*Derive current project state from the config-declared state_derivation registry — focus, in-flight, ranked next actions, blocked, milestone rollups*
|
|
256
275
|
|
|
257
276
|
</tool>
|
|
258
277
|
|
|
@@ -314,8 +333,29 @@ Create or replace a substrate block-kind JSON Schema. operation 'create' require
|
|
|
314
333
|
| `dryRun` | boolean | no | Meta-validate without writing |
|
|
315
334
|
</tool>
|
|
316
335
|
|
|
336
|
+
<tool name="resolve-conflict">
|
|
337
|
+
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. 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.
|
|
338
|
+
|
|
339
|
+
*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)*
|
|
340
|
+
|
|
341
|
+
| Parameter | Type | Required | Description |
|
|
342
|
+
|-----------|------|----------|-------------|
|
|
343
|
+
| `schemaName` | string | yes | Schema name without extension (e.g., 'tasks') |
|
|
344
|
+
| `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. |
|
|
345
|
+
</tool>
|
|
346
|
+
|
|
347
|
+
<tool name="resolve-blocked">
|
|
348
|
+
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.
|
|
349
|
+
|
|
350
|
+
*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)*
|
|
351
|
+
|
|
352
|
+
| Parameter | Type | Required | Description |
|
|
353
|
+
|-----------|------|----------|-------------|
|
|
354
|
+
| `schemaName` | string | yes | Schema name with a pending-blocked entry (from update's blocked report) |
|
|
355
|
+
</tool>
|
|
356
|
+
|
|
317
357
|
<tool name="write-schema-migration">
|
|
318
|
-
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 operations on dotted JSON paths. 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.
|
|
358
|
+
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.
|
|
319
359
|
|
|
320
360
|
*Declare a schema version-bump migration (identity or declarative-transform) into migrations.json*
|
|
321
361
|
|
|
@@ -347,6 +387,36 @@ Adopt the canonical packaged conception (samples/conception.json) as this substr
|
|
|
347
387
|
|
|
348
388
|
</tool>
|
|
349
389
|
|
|
390
|
+
<tool name="context-install">
|
|
391
|
+
Install (materialize) the schemas and starter blocks declared in config.json's installed_schemas / installed_blocks 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. 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.
|
|
392
|
+
|
|
393
|
+
*Install declared schemas + starter blocks from the samples catalog (skip-if-exists; --update re-syncs schemas + replaces empty blocks; records the config.installed_from baseline)*
|
|
394
|
+
|
|
395
|
+
| Parameter | Type | Required | Description |
|
|
396
|
+
|-----------|------|----------|-------------|
|
|
397
|
+
| `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. |
|
|
398
|
+
</tool>
|
|
399
|
+
|
|
400
|
+
<tool name="update">
|
|
401
|
+
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 AND advances the merge base to the catalog so update stops re-reporting it (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 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 seed of the catalog's config migration declarations 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). 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.
|
|
402
|
+
|
|
403
|
+
*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)*
|
|
404
|
+
|
|
405
|
+
| Parameter | Type | Required | Description |
|
|
406
|
+
|-----------|------|----------|-------------|
|
|
407
|
+
| `dryRun` | boolean | no | Preview the per-schema action plan without writing anything. |
|
|
408
|
+
</tool>
|
|
409
|
+
|
|
410
|
+
<tool name="validate-block-items">
|
|
411
|
+
Validate a block's items against the catalog schema version — returns the per-item failures (item id, field, constraint) without writing. Resolves the block's catalog block_kind, loads the installed block, forward-migrates its items in memory through the shipped chain when the block lags the catalog version (a fresh registry; never warms the project's cache), and validates against the catalog schema body. Returns block / from (the block's declared version) / to (the catalog version) / valid / failures[] (each: itemId — the failing item's id when the instancePath resolves to one — instancePath, keyword, message). Read-only: never overwrites the schema, the block, or migrations.json. An unknown block or a missing installed block file throws.
|
|
412
|
+
|
|
413
|
+
*Validate a block's items against the catalog schema version — returns the per-item failures (item id, field, constraint) without writing*
|
|
414
|
+
|
|
415
|
+
| Parameter | Type | Required | Description |
|
|
416
|
+
|-----------|------|----------|-------------|
|
|
417
|
+
| `block` | string | yes | Block name (e.g. 'tasks') |
|
|
418
|
+
</tool>
|
|
419
|
+
|
|
350
420
|
<tool name="context-switch">
|
|
351
421
|
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).
|
|
352
422
|
|
|
@@ -479,8 +549,21 @@ Materialize the Edge[] for a named lens — synthetic edges from derived_from_fi
|
|
|
479
549
|
| `lensId` | string | yes | Lens id from config.lenses[].id |
|
|
480
550
|
</tool>
|
|
481
551
|
|
|
552
|
+
<tool name="context-lens-view">
|
|
553
|
+
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.
|
|
554
|
+
|
|
555
|
+
*Project a config-declared lens as a binned item-view — bin->count summary, or one bin's items paged*
|
|
556
|
+
|
|
557
|
+
| Parameter | Type | Required | Description |
|
|
558
|
+
|-----------|------|----------|-------------|
|
|
559
|
+
| `lensId` | string | yes | Lens id from config.lenses[].id |
|
|
560
|
+
| `bin` | string | no | Return this bin's items paged; omit for a bin->count summary |
|
|
561
|
+
| `offset` | integer | no | Per-bin page start index (default 0) |
|
|
562
|
+
| `limit` | integer | no | Per-bin page size (default 50) |
|
|
563
|
+
</tool>
|
|
564
|
+
|
|
482
565
|
<tool name="context-walk-descendants">
|
|
483
|
-
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).
|
|
566
|
+
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.
|
|
484
567
|
|
|
485
568
|
*Walk closure-table descendants under a relation_type*
|
|
486
569
|
|
|
@@ -491,7 +574,7 @@ Walk closure-table descendants of a parent id under a given relation_type. Retur
|
|
|
491
574
|
</tool>
|
|
492
575
|
|
|
493
576
|
<tool name="walk-ancestors">
|
|
494
|
-
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).
|
|
577
|
+
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.
|
|
495
578
|
|
|
496
579
|
*Walk closure-table ancestors under a relation_type*
|
|
497
580
|
|
|
@@ -525,39 +608,23 @@ Compose a ContextBundle for a work-unit by reading its context-contract (by unit
|
|
|
525
608
|
</tool>
|
|
526
609
|
|
|
527
610
|
<tool name="context-roadmap-load">
|
|
528
|
-
Load
|
|
611
|
+
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), its member phases (parents of phase_positioned_in_milestone edges), each phase's tasks (parents of task_positioned_in_phase edges), and per-phase + per-milestone status rollups. Adjacency comes strictly from the authored edges — never inferred from order. Zero milestones is a valid empty view.
|
|
529
612
|
|
|
530
|
-
*Load
|
|
613
|
+
*Load the derived milestone roadmap view*
|
|
531
614
|
|
|
532
|
-
| Parameter | Type | Required | Description |
|
|
533
|
-
|-----------|------|----------|-------------|
|
|
534
|
-
| `roadmapId` | string | yes | ROADMAP-NNN id from <config.root>/roadmap.json |
|
|
535
615
|
</tool>
|
|
536
616
|
|
|
537
617
|
<tool name="context-roadmap-render">
|
|
538
|
-
Render
|
|
618
|
+
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 rollup 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.
|
|
539
619
|
|
|
540
|
-
*Render
|
|
620
|
+
*Render the derived milestone roadmap as markdown*
|
|
541
621
|
|
|
542
|
-
| Parameter | Type | Required | Description |
|
|
543
|
-
|-----------|------|----------|-------------|
|
|
544
|
-
| `roadmapId` | string | yes | ROADMAP-NNN id from <config.root>/roadmap.json |
|
|
545
622
|
</tool>
|
|
546
623
|
|
|
547
624
|
<tool name="context-roadmap-validate">
|
|
548
|
-
Validate
|
|
625
|
+
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 rollup buckets unknown with items present). 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. Display strings flow through config.display_strings (pi-context divergence).
|
|
549
626
|
|
|
550
|
-
*Validate
|
|
551
|
-
|
|
552
|
-
| Parameter | Type | Required | Description |
|
|
553
|
-
|-----------|------|----------|-------------|
|
|
554
|
-
| `roadmapId` | string | no | Filter to issues matching this roadmap_id (omit for full-project validation) |
|
|
555
|
-
</tool>
|
|
556
|
-
|
|
557
|
-
<tool name="context-roadmap-list">
|
|
558
|
-
List every roadmap in <config.root>/roadmap.json with id, title, optional status, and phase count. Returns [] when roadmap.json absent (opt-in block; absence is the truthful answer).
|
|
559
|
-
|
|
560
|
-
*List roadmaps*
|
|
627
|
+
*Validate the derived milestone roadmap*
|
|
561
628
|
|
|
562
629
|
</tool>
|
|
563
630
|
|
|
@@ -567,7 +634,7 @@ List every roadmap in <config.root>/roadmap.json with id, title, optional status
|
|
|
567
634
|
<command name="/context">
|
|
568
635
|
Context state management
|
|
569
636
|
|
|
570
|
-
Subcommands: `init`, `switch`, `list`, `archive`, `install`, `accept-all`, `view`, `lens-curate`, `roadmap-
|
|
637
|
+
Subcommands: `init`, `switch`, `list`, `archive`, `install`, `check-status`, `accept-all`, `view`, `lens-curate`, `roadmap-view`, `roadmap-validate`, `status`, `add-work`, `validate`, `help`
|
|
571
638
|
</command>
|
|
572
639
|
|
|
573
640
|
</commands_reference>
|
|
@@ -577,7 +644,7 @@ Subcommands: `init`, `switch`, `list`, `archive`, `install`, `accept-all`, `view
|
|
|
577
644
|
</events>
|
|
578
645
|
|
|
579
646
|
<bundled_resources>
|
|
580
|
-
|
|
647
|
+
12 schemas, 38 samples bundled.
|
|
581
648
|
See references/bundled-resources.md for full inventory.
|
|
582
649
|
</bundled_resources>
|
|
583
650
|
|
|
@@ -602,7 +669,9 @@ Names valid for the `installed_blocks` array in `<substrate-dir>/config.json`. I
|
|
|
602
669
|
| `context-contracts` | `samples/blocks/context-contracts.json` |
|
|
603
670
|
| `phase` | `samples/blocks/phase.json` |
|
|
604
671
|
| `story` | `samples/blocks/story.json` |
|
|
672
|
+
| `milestone` | `samples/blocks/milestone.json` |
|
|
605
673
|
| `work-orders` | `samples/blocks/work-orders.json` |
|
|
674
|
+
| `session-notes` | `samples/blocks/session-notes.json` |
|
|
606
675
|
|
|
607
676
|
</installable_blocks>
|
|
608
677
|
|
|
@@ -627,7 +696,9 @@ Names valid for the `installed_schemas` array in `<substrate-dir>/config.json`.
|
|
|
627
696
|
| `context-contracts` | `samples/schemas/context-contracts.schema.json` |
|
|
628
697
|
| `phase` | `samples/schemas/phase.schema.json` |
|
|
629
698
|
| `story` | `samples/schemas/story.schema.json` |
|
|
699
|
+
| `milestone` | `samples/schemas/milestone.schema.json` |
|
|
630
700
|
| `work-orders` | `samples/schemas/work-orders.schema.json` |
|
|
701
|
+
| `session-notes` | `samples/schemas/session-notes.schema.json` |
|
|
631
702
|
|
|
632
703
|
</installable_schemas>
|
|
633
704
|
|
|
@@ -641,7 +712,7 @@ Names valid for the `installed_schemas` array in `<substrate-dir>/config.json`.
|
|
|
641
712
|
| `framework-gaps` | Framework Gaps | `gaps` | id, title, status (string (identified|accepted|in-progress|closed|wontfix|superseded_by)), priority? (string (P0|P1|P2|P3)), package, layer? (string (L1|L2|L3|L4|L5)), description, evidence (array), impact, canonical_vocabulary?, proposed_resolution, related_features? (array), related_decisions? (array), related_issues? (array), created_by, created_at, closed_by?, closed_at?, oid?, content_hash?, content_parent? |
|
|
642
713
|
| `tasks` | Tasks | `tasks` | id, description, status (string (planned|in-progress|completed|blocked|cancelled)), files? (array), acceptance_criteria? (array), assigned_agent?, notes?, oid?, content_hash?, content_parent? |
|
|
643
714
|
| `verification` | Verification | `verifications` | id, status (string (passed|failed|partial|skipped)), method (string (command|inspect|test)), evidence?, timestamp?, criteria_results? (array), oid?, content_hash?, content_parent? |
|
|
644
|
-
| `issues` | Issues | `issues` | id, title, body, location, status (string (open|resolved|deferred)), category (string (primitive|issue|cleanup|capability|composition)), priority (string (low|medium|high|critical)), package, source? (string (human|agent|monitor|workflow)), resolved_by?, oid?, content_hash?, content_parent? |
|
|
715
|
+
| `issues` | Issues | `issues` | id, title, body, location, status (string (open|resolved|deferred)), category (string (primitive|issue|cleanup|capability|composition)), priority (string (low|medium|high|critical)), package, source? (string (human|agent|monitor|workflow)), resolved_by?, resolved_at?, oid?, content_hash?, content_parent? |
|
|
645
716
|
| `features` | Features | `features` | id, title, status (string (proposed|approved|in-progress|in-review|complete|blocked|cancelled)), layer (string (L1|L2|L3|L4|L5)), description, motivation?, acceptance_criteria (array), created_by, created_at, modified_by?, modified_at?, approved_by?, approved_at?, oid?, content_hash?, content_parent? |
|
|
646
717
|
| `research` | Research | `research` | id, title, status (string (planned|in-progress|complete|stale|superseded|revised)), layer (string (L1|L2|L3|L4|L5)), type (string (investigative|comparative|empirical|historical|audit|landscape|feasibility|curation)), question, method, scope? (array), findings_summary, findings_document?, grounding? (object), grounded_at?, stale_conditions? (array), citations? (array), conducted_by?, conducted_at?, created_by, created_at, modified_by?, modified_at?, oid?, content_hash?, content_parent? |
|
|
647
718
|
| `rationale` | Design Rationale | `rationales` | id, title, narrative, phase? (integer), oid?, content_hash?, content_parent? |
|
|
@@ -651,8 +722,10 @@ Names valid for the `installed_schemas` array in `<substrate-dir>/config.json`.
|
|
|
651
722
|
| `conventions` | Conventions | `rules` | id, description, enforcement (string (lint|test|review|manual)), severity (string (error|warning|info)), oid?, content_hash?, content_parent? |
|
|
652
723
|
| `context-contracts` | Context contracts | `contracts` | id, unit_kind, bundle_relation_types (array), description?, notes?, created_by, created_at, modified_by?, modified_at?, oid?, content_hash?, content_parent? |
|
|
653
724
|
| `phase` | Phases | `phases` | id, name, intent, goal?, status (string (planned|in-progress|completed)), success_criteria? (array), specs? (array), artifacts_produced? (array), oid?, content_hash?, content_parent? |
|
|
654
|
-
| `story` | Stories | `stories` | id, title, status (string (proposed|ready|in-progress|in-review|complete|blocked)), description?, acceptance_criteria? (array), created_by?, created_at?, modified_by?, modified_at?, oid?, content_hash?, content_parent? |
|
|
725
|
+
| `story` | Stories | `stories` | id, title, user_kind?, status (string (proposed|ready|in-progress|in-review|complete|blocked)), description?, acceptance_criteria? (array), created_by?, created_at?, modified_by?, modified_at?, oid?, content_hash?, content_parent? |
|
|
726
|
+
| `milestone` | Milestones | `milestones` | id, name, status (string (planned|reached)), release?, created_by?, created_at?, modified_by?, modified_at?, oid?, content_hash?, content_parent? |
|
|
655
727
|
| `work-orders` | Work Orders | `work_orders` | id, title, status (string (proposed|in-progress|real-check-passed|real-check-failed|completed|cancelled)), target_agent, input_contract (object), context_blocks (array), output_contract (object), scope (object), real_check_criteria (object), description?, created_by?, created_at?, modified_by?, modified_at?, oid?, content_hash?, content_parent? |
|
|
728
|
+
| `session-notes` | Session Notes | `sessions` | id, timestamp, focus, discoveries? (array), questions? (array), decisions_made? (array), current_status, next_steps (array), oid?, content_hash?, content_parent? |
|
|
656
729
|
|
|
657
730
|
**Status Enums:**
|
|
658
731
|
|
|
@@ -684,6 +757,7 @@ Names valid for the `installed_schemas` array in `<substrate-dir>/config.json`.
|
|
|
684
757
|
| `conventions` | `severity` | error, warning, info |
|
|
685
758
|
| `phase` | `status` | planned, in-progress, completed |
|
|
686
759
|
| `story` | `status` | proposed, ready, in-progress, in-review, complete, blocked |
|
|
760
|
+
| `milestone` | `status` | planned, reached |
|
|
687
761
|
| `work-orders` | `status` | proposed, in-progress, real-check-passed, real-check-failed, completed, cancelled |
|
|
688
762
|
|
|
689
763
|
</planning_vocabulary>
|
|
@@ -693,7 +767,7 @@ pi-context manages structured project state in the substrate directory — a dir
|
|
|
693
767
|
</objective>
|
|
694
768
|
|
|
695
769
|
<block_files>
|
|
696
|
-
Blocks are JSON files under the substrate root (one per block kind, each an array of items). Each block has a corresponding schema in `<root>/schemas/`. When you write to a block via the tools, the data is validated against its schema before persisting. Writes are atomic (tmp file + rename) and serialised per block via `withBlockLock`. The substrate root is the dir chosen at init (recorded in the `.pi-context.json` bootstrap pointer) and written to `config.json`'s `root` field by `/context accept-all`; the framework ships no default substrate-dir name. block-api routes through `resolveContextDir(cwd)` — which resolves `config.root` when set and otherwise falls back to the pointer — so a relocated root reaches every read/write site.
|
|
770
|
+
Blocks are JSON files under the substrate root (one per block kind, each an array of items). Each block has a corresponding schema in `<root>/schemas/`. When you write to a block via the tools, the data is validated against its schema before persisting. Writes are atomic (tmp file + rename) and serialised per block via `withBlockLock`. The substrate root is the dir chosen at init (recorded in the `.pi-context.json` bootstrap pointer) and written to `config.json`'s `root` field at init (skeleton config) and again by `/context accept-all`; the framework ships no default substrate-dir name. block-api routes through `resolveContextDir(cwd)` — which resolves `config.root` when set and otherwise falls back to the pointer — so a relocated root reaches every read/write site.
|
|
697
771
|
|
|
698
772
|
Each item in an identity-bearing block carries a three-layer identity, not a refname alone: `id` (the mutable human label, e.g. a kind-prefixed refname), `oid` (a content-independent 32-hex identity minted once at the item's birth and immutable thereafter, salted by the substrate's `substrate_id`), `content_hash` (a SHA-256 over the item's content projection — the item minus its metadata fields — so identical content deduplicates), and `content_parent` (the prior version's `content_hash`, forming a per-item version chain that advances only when content actually changed). A write carrying a different incoming `oid` is rejected. Identity stamping is a no-op unless the block's array subschema declares all three identity fields, scoping content-addressing to canonical schemas and leaving bespoke/test schemas untouched.
|
|
699
773
|
</block_files>
|
|
@@ -707,21 +781,23 @@ Every block write validates against `<root>/schemas/<blockname>.schema.json`. If
|
|
|
707
781
|
</schema_validation>
|
|
708
782
|
|
|
709
783
|
<context_init>
|
|
710
|
-
`/context init <substrate-dir>` creates the substrate skeleton: the `.pi-context.json` bootstrap pointer (declaring the chosen substrate-dir name)
|
|
784
|
+
`/context init <substrate-dir>` creates the substrate skeleton: the `.pi-context.json` bootstrap pointer (declaring the chosen substrate-dir name), the substrate root and its `schemas/` directory, a minimal SKELETON `config.json` (`schema_version`, empty `block_kinds`, `root`, and a minted + project-registered `substrate_id` — no vocabulary), and the catalog's `config` migration declarations seeded into `migrations.json`. No catalog vocabulary, schemas, or starter blocks are imposed (ship-no-defaults). Idempotent: re-running preserves existing dirs and never clobbers an existing `config.json`. Populate the substrate next with `/context accept-all` (adopt the canonical conception) followed by `/context install`.
|
|
711
785
|
</context_init>
|
|
712
786
|
|
|
713
787
|
<context_accept_all>
|
|
714
|
-
`/context accept-all` adopts the package's canonical packaged conception (`samples/conception.json`) as the substrate's `config.json` — the full vocabulary (`block_kinds`, `relation_types`, `lenses`, `invariants`) plus the `installed_schemas` / `installed_blocks` manifest — with `root` set to the actual substrate dir. It writes `config.json` only (run `/context install` after to materialize the schemas + starter blocks) and is idempotent: it never overwrites
|
|
788
|
+
`/context accept-all` adopts the package's canonical packaged conception (`samples/conception.json`) as the substrate's `config.json` — the full vocabulary (`block_kinds`, `relation_types`, `lenses`, `invariants`) plus the `installed_schemas` / `installed_blocks` manifest — with `root` set to the actual substrate dir. It writes `config.json` only (run `/context install` after to materialize the schemas + starter blocks) and is idempotent: it never overwrites a populated `config.json` (offer, don't impose); the vocabulary-empty skeleton `config.json` written by init IS overwritten by the catalog, with the skeleton's on-disk `substrate_id` preserved. This is the accept-all path; per-entry step-through curation is a separate surface.
|
|
715
789
|
</context_accept_all>
|
|
716
790
|
|
|
717
791
|
<context_install>
|
|
718
|
-
`/context install` reconciles the substrate against the `installed_schemas` and `installed_blocks` lists declared in `config.json`. For each declared name it copies the matching asset from the package-shipped samples catalog (`samples/schemas/` for schemas, `samples/blocks/` for starter blocks) into the substrate. Default behavior is skip-if-exists (preserves user edits)
|
|
792
|
+
`/context install` (reflected CLI op: `pi-context context-install [--update]`, `authGated`) reconciles the substrate against the `installed_schemas` and `installed_blocks` lists declared in `config.json`. The slash command and the CLI op run the same install engine — the op's `--update` maps to the same migration-aware overwrite the slash command's `--update` does. For each declared name it copies the matching asset from the package-shipped samples catalog (`samples/schemas/` for schemas, `samples/blocks/` for starter blocks) into the substrate. Default behavior is skip-if-exists (preserves user edits). Pass `--update` to re-sync installed SCHEMAS through the migration registry: a same-version body change (or a non-versioned schema) is a verbatim re-sync (reported `resynced`); a schema `version` bump forward-migrates the populated block's items through the shipped catalog migration chain and re-validates them against the new schema (reported `migrated`); a bump with no safe migration — no shipped chain reaching the catalog version, or items that would fail the new schema — is refused, leaving BOTH the installed schema file AND the block file byte-unchanged (reported `blocked`). Preview drift first with `/context check-status`. Populated block data is never overwritten — a block holding items is preserved (reported as `preserved`) regardless of `--update`, while empty or absent blocks receive the catalog starter. Sources missing from the catalog are reported as `notFound`. Empty install lists are not an error — the result is a clean no-op message instructing the user to edit `config.json`. Install also records an install baseline in `config.installed_from`: the catalog source (`catalog` = pi-context `name@version`, `catalog_version` = conception `schema_version`), a baseline timestamp, and a per-schema fingerprint (`assets[canonical_id]` = content hash + the schema's own version) of the installed SCHEMAS — the basis for installed-vs-catalog drift detection. The baseline covers schemas only (blocks are user data). A re-install on an unchanged substrate is idempotent: the existing baseline is preserved verbatim (timestamp included) so `config.json` stays byte-identical. `/context check-status` is a separate read-only command that previews drift between the installed schemas and the catalog: it compares each installed schema against its recorded baseline, the catalog's current schema, and the currently-installed file, and reports `in-sync` / `catalog-ahead` (the package shipped a newer schema) / `locally-modified` (the installed file was edited) / `both-diverged` / `no-baseline` / `missing-catalog` / `missing-installed`. For each schema behind the catalog (`catalog-ahead` / `both-diverged`) it additionally surfaces which schema is behind and by what version gap — `behind` plus a `version_delta` carrying the baseline → catalog version pair (a declared version bump) or a content-only basis when the catalog body moved with the version string unchanged. It writes nothing. The reflected CLI op is `pi-context context-check-status --json`.
|
|
719
793
|
|
|
720
|
-
The installable catalog IS the packaged conception (`samples/conception.json`): its `block_kinds` enumerate the available kinds, each carrying its schema (`samples/schemas/`) and starter block (`samples/blocks/`). The generated installable-catalog table below lists the authoritative names — declare any subset in `installed_*` and run `/context install`, or take the whole conception via `/context accept-all`.
|
|
794
|
+
The installable catalog IS the packaged conception (`samples/conception.json`): its `block_kinds` enumerate the available kinds, each carrying its schema (`samples/schemas/`) and starter block (`samples/blocks/`). The generated installable-catalog table below lists the authoritative names — declare any subset in `installed_*` and run `/context install`, or take the whole conception via `/context accept-all`. To inspect a catalog schema body itself, `pi-context read-catalog-schema --kind <canonical_id>` fetches and prints the verbatim bundled `*.schema.json` (the raw JSON Schema — `properties` / `definitions` / `$id`, distinct from the `read-samples-catalog` summary projection), so after `/context check-status` flags a schema behind the catalog you can diff that body locally against the installed `<substrate>/schemas/<name>.schema.json` without hunting through `node_modules`. It is read-only and package-intrinsic (reads the bundled catalog, mutates nothing).
|
|
721
795
|
</context_install>
|
|
722
796
|
|
|
723
797
|
<substrate_config>
|
|
724
|
-
`<substrate-dir>/config.json` is the substrate bootstrap. Its `root` field declares where every other block, schema, agent, and template lives — consumers resolve that dir via the `.pi-context.json` pointer plus `config.root`, never by assuming a fixed directory name. Its `substrate_id` field is the per-substrate root identity (pattern `sub-` followed by 16 hex), minted once and immutable on disk; it salts oid minting and identifies the substrate in the project-root registry. `naming` aliases canonical block ids to display names (used by `/context view` rendering). `hierarchy` declares legal closure-table edges (parent block → child block via relation_type). `lenses` declares named projections over a target block. `installed_schemas` / `installed_blocks` are the install manifest consumed by `/context install`.
|
|
798
|
+
`<substrate-dir>/config.json` is the substrate bootstrap. Its `root` field declares where every other block, schema, agent, and template lives — consumers resolve that dir via the `.pi-context.json` pointer plus `config.root`, never by assuming a fixed directory name. Its `substrate_id` field is the per-substrate root identity (pattern `sub-` followed by 16 hex), minted once and immutable on disk; it salts oid minting and identifies the substrate in the project-root registry. `naming` aliases canonical block ids to display names (used by `/context view` rendering). `hierarchy` declares legal closure-table edges (parent block → child block via relation_type). `lenses` declares named projections over a target block. `installed_schemas` / `installed_blocks` are the install manifest consumed by `/context install`. `installed_from` is the optional install baseline `/context install` records — the catalog source plus a per-schema content fingerprint of the installed schemas — for installed-vs-catalog drift detection.
|
|
799
|
+
|
|
800
|
+
A fresh substrate adopted via `/context accept-all` carries advisory (severity-`warning`) convention-articulation invariants: every decision, feature, and task should carry an `item_governed_by_convention` edge to a convention it follows, or an `item_acknowledges_missing_convention` edge to a missing-convention gap. `context-validate` reports an artifact that articulates neither as a warning (it does not error), so the advice surfaces without blocking writes; satisfy it by adding one of those two edges (`append-relation`) when filing or amending the artifact.
|
|
725
801
|
|
|
726
802
|
`config.json` and `relations.json` are exempt from `config.root` redirection — they always live at the substrate-dir root (the dir chosen at bootstrap, resolved via the `.pi-context.json` pointer, suggested `.context`) because they are the substrate that defines `root`. The substrate-dir root is whatever was chosen at bootstrap, not necessarily `.project`. All other state lives under `<config.root>/...` per `resolveContextDir(cwd)`. The package ships their schemas in `schemas/` (config.schema.json, relations.schema.json) and resolves them via three-tier search: project override > user override > package-shipped.
|
|
727
803
|
|
|
@@ -737,7 +813,7 @@ Source-of-truth-drift invariant: `validateContext` requires the active `config.s
|
|
|
737
813
|
</cross_substrate>
|
|
738
814
|
|
|
739
815
|
<schema_versioning>
|
|
740
|
-
Schemas are draft-07 JSON-Schema, one per block kind, under `<substrate-dir>/schemas/`. Package-shipped substrate-singleton schemas carry a `pi-context://schemas/<name>` `$id` plus a `version`. `<substrate-dir>/migrations.json` is the per-substrate schema-version migration registry. A schema `version` bump REQUIRES a companion migration declared via the `write-schema-migration` tool; without one, reading or writing an item that declares an older `schema_version` throws a version mismatch. Migration kinds are `identity` (shape-compatible, no transform) or `declarative-transform` (a TransformSpec of rename/set/delete/coerce on dotted paths). The loaded registry resolves the migration edge at the next read/write, so items walk forward without a process restart. A `block:<name>` reference resolves to `<contextDir>/schemas/<name>.schema.json`.
|
|
816
|
+
Schemas are draft-07 JSON-Schema, one per block kind, under `<substrate-dir>/schemas/`. Package-shipped substrate-singleton schemas carry a `pi-context://schemas/<name>` `$id` plus a `version`. `<substrate-dir>/migrations.json` is the per-substrate schema-version migration registry. A schema `version` bump REQUIRES a companion migration declared via the `write-schema-migration` tool; without one, reading or writing an item that declares an older `schema_version` throws a version mismatch. Migration kinds are `identity` (shape-compatible, no transform) or `declarative-transform` (a TransformSpec of rename/set/delete/coerce/map_each on dotted paths; `map_each` addresses an array — table mode maps each string element through a lookup, with unmatched elements becoming `{relation_type, item_endpoint}` under a parent/child fallback, and set-on-each mode sets a field on every object element). The loaded registry resolves the migration edge at the next read/write, so items walk forward without a process restart. Config loading is migration-aware: a `config.json` whose `schema_version` lags the bundled config schema is walked forward through the `config` migration chain in memory at load (the on-disk file is never rewritten); every substrate-lifecycle ceremony — init / accept-all / install / update / check-status / switch (existing-target and switch-back forms; the target substrate is seeded right after the pointer flip) / resolve-conflict / resolve-blocked — seeds the catalog's `config` identity declaration into `migrations.json` (idempotent) before its first config read, and a version mismatch with no resolvable chain throws. The ceremonies that reach identity-stamping writes (update, install, resolve-blocked) also establish substrate identity at entry: a config carrying no `substrate_id` gets one minted, persisted, and registered before the first stamping write — a pre-identity substrate heals on the sanctioned ceremony instead of refusing — reported in the ceremony result under `substrateIdEstablished` (live runs only; an established identity is never re-minted). On the write side, versioned-document envelopes converge: every block schema declares an optional top-level `schema_version`, and the write path stamps it (config.json's and migrations.json's included) to the owning schema's current `version` on every sanctioned write — an incoming envelope claiming an older version is first walked forward through the registered chain (or refused with the file left byte-unchanged when no chain reaches the current version), then persisted at the current version; reads of a stamped block validate the whole envelope migration-aware. A substrate whose installed schemas predate the `schema_version` property keeps writing unchanged until `/context update` lands it. A `block:<name>` reference resolves to `<contextDir>/schemas/<name>.schema.json`.
|
|
741
817
|
</schema_versioning>
|
|
742
818
|
|
|
743
819
|
<lens_views>
|
|
@@ -745,6 +821,8 @@ Lenses are named projections over a target block. A lens declares `id`, `target`
|
|
|
745
821
|
|
|
746
822
|
Edges live in `<substrate-dir>/relations.json` as a closure table — each row is `{ parent, child, relation_type, ordinal? }`. `relation_type` is a lens id, a hierarchy edge type, or a registered `relation_types[].canonical_id`; `ordinal` orders siblings within `(parent, relation_type)`. Endpoints (both `parent` and `child`) are dual-form: a legacy string (a canonical id, a lens bin name, or an `<alias>:<refname>` cross-substrate sentinel; disambiguation lives in `validateRelations`), OR a structured item endpoint `{ kind: "item", oid, refname?, substrate_id?, content_hash? }` where a present `substrate_id` marks a foreign endpoint and `content_hash` is carried for drift detection, OR a structured lens-bin endpoint `{ kind: "lens_bin", bin }` — a virtual parent that never resolves to an item.
|
|
747
823
|
|
|
824
|
+
Edge orientation is declared once, read everywhere. Storage is uniform (`edge.parent` = source endpoint, `edge.child` = target endpoint); which endpoint holds a relation's PRIMARY semantic role (prerequisite/predecessor/gate for `ordering`, container for `membership`, source for `data_flow`) is `config.relation_types[].role_direction` — `as_parent` (primary at `edge.parent`) or `as_child` (primary at `edge.child`), optional and set only for relations with a per-role consumer. The `primaryEndpoint(edge, role_direction)` / `counterEndpoint(edge, role_direction)` helpers read the endpoint under that declaration, and the blocked/ready deriver (`state_derivation.blocked_by` gate-vs-dependency split), the milestone rollup, the derived roadmap (precedes + membership), and `promote-item`'s lineage edge all route through it rather than hardcoding parent/child. Authoring: `append-relation` / `append-relations` take EITHER raw `--parent`/`--child` OR role-typed `--primary`/`--counter` (mapped to parent/child via `role_direction`; mutually exclusive) — a bare `--parent`/`--child` append of a relation that is BOTH role-bearing and orientation-ambiguous (its source/target kinds overlap, incl. `"*"`) is rejected in favor of `--primary`/`--counter`, while a role-less or disjoint-kind relation appends bare unchanged. Reading: `context-walk-descendants` / `walk-ancestors` on a disjoint-kind relation queried from the wrong endpoint THROWS naming the correct op instead of returning an ambiguous `[]`. `replace-relation` writes raw endpoints verbatim (bypassing the orientation gate) — the re-orient affordance; run `context-validate` after.
|
|
825
|
+
|
|
748
826
|
The single-form rule: ALL inter-item relationships are closure-table edges. Embedded nested id-bearing arrays and FK-as-field are forbidden — a nested id-bearing array in a schema is flagged `nested_id_bearing_array` by `validateContext` with the remediation "promote to a top-level entity + membership edge". Containment is a membership edge carrying `ordinal`; the nested id-bearing array → top-level entity block + ordinal-bearing membership edges promotion is performed by the canonicalizer (the context-dir-migration `canonicalizeSubstrate` machinery, run as a repo-side migration script under `scripts/migration/` — not a packaged pi-context tool). (Distinct from the `promote-item` tool, which is a cross-substrate derivation: it promotes a substrate item INTO another registered substrate as a new content-addressed item, recording an `item_derived_from_item` lineage edge in the destination.)
|
|
749
827
|
|
|
750
828
|
The lens-view algorithm: `edgesForLens(lens, items, authoredEdges)` returns synthetic edges (when `derived_from_field` is set) or filtered authored edges (otherwise). `groupByLens(items, lens, lensEdges)` produces a `Map<binName, ItemRecord[]>`. `walkDescendants(parentId, relationType, edges)` traverses the closure table from any parent.
|
|
@@ -765,7 +843,7 @@ The lens-view algorithm: `edgesForLens(lens, items, authoredEdges)` returns synt
|
|
|
765
843
|
|
|
766
844
|
`validateContext(cwd)` (the `context-validate` tool) layers the registry/identity invariants over cross-block referential integrity: `substrate_id_unregistered` and `substrate_id_registry_mismatch` (the source-of-truth-drift guard on the active substrate), `edge_endpoint_dangling` and `edge_endpoint_unregistered` (a structured endpoint naming a registered-but-absent or unregistered substrate), and `nested_id_bearing_array` (a schema embedding an id-bearing array instead of using a membership edge). Config-declared `invariants[]` and registered lens-validators are checked in the same pass.
|
|
767
845
|
|
|
768
|
-
|
|
846
|
+
Three derived substrate tools complement validation: `context-edges-for-lens` returns the materialized `Edge[]` for a named lens (synthetic from `derived_from_field` or filtered authored edges); `context-lens-view` projects a config-declared lens as a binned item-view — a bin→count summary, or one bin's items paged by `offset`/`limit`; `context-walk-descendants` returns the transitive descendant id list from a parent under a given relation_type.
|
|
769
847
|
</substrate_validation>
|
|
770
848
|
|
|
771
849
|
<block_item_reads>
|
|
@@ -818,8 +896,8 @@ On `session_start`, checks npm registry for newer versions of `@davidorex/pi-pro
|
|
|
818
896
|
</update_check>
|
|
819
897
|
|
|
820
898
|
<success_criteria>
|
|
821
|
-
- `<substrate-dir>/`, `<substrate-dir>/schemas/`,
|
|
822
|
-
- `installed_schemas` / `installed_blocks` declared in `config.json` are reified by `/context install`; `--update`
|
|
899
|
+
- `<substrate-dir>/`, `<substrate-dir>/schemas/`, the `.pi-context.json` bootstrap pointer, a skeleton `config.json`, and a seeded `migrations.json` exist after `/context init <substrate-dir>` (init imposes no catalog: no vocabulary, no schemas, no blocks until accept-all + install). Phases are not a directory — they live as an in-block array under `phase.json` (plural `phases` key); there is no `phases/` dir.
|
|
900
|
+
- `installed_schemas` / `installed_blocks` declared in `config.json` are reified by `/context install`; `--update` re-syncs installed schemas through the migration registry (forward-migrate block items on a version bump, or refuse and leave unchanged when items can't be safely migrated), but populated block data is never overwritten (preserved) — only empty or absent blocks receive the catalog starter
|
|
823
901
|
- Block writes validate against schemas — invalid data rejected with specific error
|
|
824
902
|
- `/context status` returns current derived state without errors
|
|
825
903
|
- `/context validate` returns no errors for well-formed cross-block references
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Bundled Resources
|
|
2
2
|
|
|
3
|
-
## schemas/ (
|
|
3
|
+
## schemas/ (12 files)
|
|
4
4
|
|
|
5
5
|
- `schemas/bootstrap.schema.json`
|
|
6
6
|
- `schemas/config.schema.json`
|
|
7
7
|
- `schemas/context-registry.schema.json`
|
|
8
8
|
- `schemas/layer.schema.json`
|
|
9
9
|
- `schemas/migrations.schema.json`
|
|
10
|
+
- `schemas/pending-blocked.schema.json`
|
|
10
11
|
- `schemas/priority.schema.json`
|
|
11
12
|
- `schemas/relations.schema.json`
|
|
12
13
|
- `schemas/severity.schema.json`
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
- `schemas/status.schema.json`
|
|
15
16
|
- `schemas/verification-method.schema.json`
|
|
16
17
|
|
|
17
|
-
## samples/ (
|
|
18
|
+
## samples/ (38 files)
|
|
18
19
|
|
|
19
20
|
- `samples/blocks/context-contracts.json`
|
|
20
21
|
- `samples/blocks/conventions.json`
|
|
@@ -23,10 +24,12 @@
|
|
|
23
24
|
- `samples/blocks/framework-gaps.json`
|
|
24
25
|
- `samples/blocks/issues.json`
|
|
25
26
|
- `samples/blocks/layer-plans.json`
|
|
27
|
+
- `samples/blocks/milestone.json`
|
|
26
28
|
- `samples/blocks/phase.json`
|
|
27
29
|
- `samples/blocks/rationale.json`
|
|
28
30
|
- `samples/blocks/requirements.json`
|
|
29
31
|
- `samples/blocks/research.json`
|
|
32
|
+
- `samples/blocks/session-notes.json`
|
|
30
33
|
- `samples/blocks/spec-reviews.json`
|
|
31
34
|
- `samples/blocks/story.json`
|
|
32
35
|
- `samples/blocks/tasks.json`
|
|
@@ -41,10 +44,12 @@
|
|
|
41
44
|
- `samples/schemas/framework-gaps.schema.json`
|
|
42
45
|
- `samples/schemas/issues.schema.json`
|
|
43
46
|
- `samples/schemas/layer-plans.schema.json`
|
|
47
|
+
- `samples/schemas/milestone.schema.json`
|
|
44
48
|
- `samples/schemas/phase.schema.json`
|
|
45
49
|
- `samples/schemas/rationale.schema.json`
|
|
46
50
|
- `samples/schemas/requirements.schema.json`
|
|
47
51
|
- `samples/schemas/research.schema.json`
|
|
52
|
+
- `samples/schemas/session-notes.schema.json`
|
|
48
53
|
- `samples/schemas/spec-reviews.schema.json`
|
|
49
54
|
- `samples/schemas/story.schema.json`
|
|
50
55
|
- `samples/schemas/tasks.schema.json`
|