@davidorex/pi-context 0.26.0 → 0.28.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 +69 -15
- package/README.md +71 -18
- package/dist/block-api.d.ts +165 -18
- package/dist/block-api.d.ts.map +1 -1
- package/dist/block-api.js +800 -57
- package/dist/block-api.js.map +1 -1
- package/dist/citation-rot-scanner.d.ts +80 -0
- package/dist/citation-rot-scanner.d.ts.map +1 -0
- package/dist/citation-rot-scanner.js +421 -0
- package/dist/citation-rot-scanner.js.map +1 -0
- package/dist/content-hash.d.ts +25 -0
- package/dist/content-hash.d.ts.map +1 -0
- package/dist/content-hash.js +62 -0
- package/dist/content-hash.js.map +1 -0
- package/dist/context-dir.d.ts +126 -1
- package/dist/context-dir.d.ts.map +1 -1
- package/dist/context-dir.js +208 -4
- package/dist/context-dir.js.map +1 -1
- package/dist/context-registry.d.ts +122 -0
- package/dist/context-registry.d.ts.map +1 -0
- package/dist/context-registry.js +189 -0
- package/dist/context-registry.js.map +1 -0
- package/dist/context-sdk.d.ts +179 -12
- package/dist/context-sdk.d.ts.map +1 -1
- package/dist/context-sdk.js +536 -101
- package/dist/context-sdk.js.map +1 -1
- package/dist/context.d.ts +222 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +244 -56
- package/dist/context.js.map +1 -1
- package/dist/git-env.d.ts +2 -0
- package/dist/git-env.d.ts.map +1 -0
- package/dist/git-env.js +29 -0
- package/dist/git-env.js.map +1 -0
- package/dist/index.d.ts +124 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +440 -1125
- package/dist/index.js.map +1 -1
- package/dist/lens-view.d.ts.map +1 -1
- package/dist/lens-view.js +5 -3
- package/dist/lens-view.js.map +1 -1
- package/dist/migration-registry-loader.d.ts +121 -0
- package/dist/migration-registry-loader.d.ts.map +1 -0
- package/dist/migration-registry-loader.js +309 -0
- package/dist/migration-registry-loader.js.map +1 -0
- package/dist/migrations-store.d.ts +141 -0
- package/dist/migrations-store.d.ts.map +1 -0
- package/dist/migrations-store.js +206 -0
- package/dist/migrations-store.js.map +1 -0
- package/dist/object-store.d.ts +26 -0
- package/dist/object-store.d.ts.map +1 -0
- package/dist/object-store.js +104 -0
- package/dist/object-store.js.map +1 -0
- package/dist/ops-registry.d.ts +44 -0
- package/dist/ops-registry.d.ts.map +1 -0
- package/dist/ops-registry.js +1223 -0
- package/dist/ops-registry.js.map +1 -0
- package/dist/orientation.d.ts +16 -0
- package/dist/orientation.d.ts.map +1 -0
- package/dist/orientation.js +49 -0
- package/dist/orientation.js.map +1 -0
- package/dist/promote-item.d.ts +28 -0
- package/dist/promote-item.d.ts.map +1 -0
- package/dist/promote-item.js +257 -0
- package/dist/promote-item.js.map +1 -0
- package/dist/read-element.d.ts +129 -0
- package/dist/read-element.d.ts.map +1 -0
- package/dist/read-element.js +296 -0
- package/dist/read-element.js.map +1 -0
- package/dist/rename-canonical-id.d.ts.map +1 -1
- package/dist/rename-canonical-id.js +22 -13
- package/dist/rename-canonical-id.js.map +1 -1
- package/dist/roadmap-plan.d.ts.map +1 -1
- package/dist/roadmap-plan.js +23 -13
- package/dist/roadmap-plan.js.map +1 -1
- package/dist/schema-validator.d.ts +1 -0
- package/dist/schema-validator.d.ts.map +1 -1
- package/dist/schema-validator.js +7 -3
- package/dist/schema-validator.js.map +1 -1
- package/dist/schema-write.d.ts +78 -4
- package/dist/schema-write.d.ts.map +1 -1
- package/dist/schema-write.js +297 -34
- package/dist/schema-write.js.map +1 -1
- package/dist/status-vocab.d.ts +1 -0
- package/dist/status-vocab.d.ts.map +1 -1
- package/dist/status-vocab.js +4 -0
- package/dist/status-vocab.js.map +1 -1
- package/dist/truncate.d.ts +34 -0
- package/dist/truncate.d.ts.map +1 -0
- package/dist/truncate.js +85 -0
- package/dist/truncate.js.map +1 -0
- package/dist/write-schema-migration-tool.d.ts +46 -0
- package/dist/write-schema-migration-tool.d.ts.map +1 -0
- package/dist/write-schema-migration-tool.js +115 -0
- package/dist/write-schema-migration-tool.js.map +1 -0
- package/package.json +35 -2
- package/samples/blocks/work-orders.json +3 -0
- package/samples/conception.json +22 -3
- package/samples/migrations.json +133 -0
- package/samples/schemas/context-contracts.schema.json +19 -4
- package/samples/schemas/conventions.schema.json +68 -12
- package/samples/schemas/decisions.schema.json +125 -28
- package/samples/schemas/features.schema.json +140 -26
- package/samples/schemas/framework-gaps.schema.json +171 -26
- package/samples/schemas/issues.schema.json +86 -13
- package/samples/schemas/layer-plans.schema.json +195 -35
- package/samples/schemas/phase.schema.json +18 -3
- package/samples/schemas/rationale.schema.json +37 -7
- package/samples/schemas/requirements.schema.json +77 -10
- package/samples/schemas/research.schema.json +169 -36
- package/samples/schemas/spec-reviews.schema.json +88 -18
- package/samples/schemas/story.schema.json +18 -3
- package/samples/schemas/tasks.schema.json +66 -10
- package/samples/schemas/verification.schema.json +70 -12
- package/samples/schemas/work-orders.schema.json +195 -0
- package/schemas/bootstrap.schema.json +18 -6
- package/schemas/config.schema.json +58 -26
- package/schemas/context-registry.schema.json +46 -0
- package/schemas/migrations.schema.json +123 -0
- package/schemas/relations.schema.json +41 -10
- package/skill-narrative.md +42 -21
- package/skills/pi-context/SKILL.md +159 -65
- package/skills/pi-context/references/bundled-resources.md +7 -2
|
@@ -3,7 +3,7 @@ name: pi-context
|
|
|
3
3
|
description: >
|
|
4
4
|
Schema-driven project state management with typed JSON blocks, schema
|
|
5
5
|
validation, substrate config, lens views, closure-table relations, and
|
|
6
|
-
cross-block referential integrity. Use when managing
|
|
6
|
+
cross-block referential integrity. Use when managing substrate blocks,
|
|
7
7
|
scaffolding project structure, installing block kinds from the packaged samples
|
|
8
8
|
catalog, validating project state, rendering lens views, or adding work items.
|
|
9
9
|
---
|
|
@@ -31,7 +31,7 @@ Update fields on an item in a project block array. Finds by predicate field matc
|
|
|
31
31
|
|-----------|------|----------|-------------|
|
|
32
32
|
| `block` | string | yes | Block name (e.g., 'issues', 'decisions') |
|
|
33
33
|
| `arrayKey` | string | yes | Array key in the block |
|
|
34
|
-
| `match` | object | yes | Fields to match (e.g., { id: '
|
|
34
|
+
| `match` | object | yes | Fields to match (e.g., { id: 'ISSUE-NNN' }) |
|
|
35
35
|
| `updates` | object | yes | Fields to update (e.g., { status: 'resolved' }) |
|
|
36
36
|
</tool>
|
|
37
37
|
|
|
@@ -48,6 +48,20 @@ Append a closure-table relation (edge: parent, child, relation_type, optional or
|
|
|
48
48
|
| `ordinal` | integer | no | Optional sibling-ordering within (parent, relation_type) |
|
|
49
49
|
</tool>
|
|
50
50
|
|
|
51
|
+
<tool name="promote-item">
|
|
52
|
+
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.
|
|
53
|
+
|
|
54
|
+
*Promote an item into another substrate as a derived copy with a lineage edge*
|
|
55
|
+
|
|
56
|
+
| Parameter | Type | Required | Description |
|
|
57
|
+
|-----------|------|----------|-------------|
|
|
58
|
+
| `source` | string | yes | Source item selector (bare refname / <alias>:<refname>) |
|
|
59
|
+
| `destinationSubstrate` | string | yes | Registered destination substrate alias |
|
|
60
|
+
| `newRefname` | string | no | Explicit destination refname (else allocated from the dest block id pattern) |
|
|
61
|
+
| `dryRun` | boolean | no | Compute the destination without writing any channel |
|
|
62
|
+
| `writer` | object | yes | DispatchContext.writer per pi-context/src/dispatch-context.ts. |
|
|
63
|
+
</tool>
|
|
64
|
+
|
|
51
65
|
<tool name="append-block-nested-item">
|
|
52
66
|
Append an item to a nested array on a parent-array item in a project block. Schema validation is automatic.
|
|
53
67
|
|
|
@@ -57,7 +71,7 @@ Append an item to a nested array on a parent-array item in a project block. Sche
|
|
|
57
71
|
|-----------|------|----------|-------------|
|
|
58
72
|
| `block` | string | yes | Block name (e.g., 'spec-reviews') |
|
|
59
73
|
| `arrayKey` | string | yes | Parent array key (e.g., 'reviews') |
|
|
60
|
-
| `match` | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-
|
|
74
|
+
| `match` | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-NNN' }) |
|
|
61
75
|
| `nestedKey` | string | yes | Nested array key on the matched parent (e.g., 'findings') |
|
|
62
76
|
| `item` | unknown | yes | Item object to append to the nested array — must conform to schema |
|
|
63
77
|
</tool>
|
|
@@ -71,7 +85,7 @@ Update fields on a nested-array item inside a parent-array item in a project blo
|
|
|
71
85
|
|-----------|------|----------|-------------|
|
|
72
86
|
| `block` | string | yes | Block name (e.g., 'spec-reviews') |
|
|
73
87
|
| `arrayKey` | string | yes | Parent array key (e.g., 'reviews') |
|
|
74
|
-
| `match` | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-
|
|
88
|
+
| `match` | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-NNN' }) |
|
|
75
89
|
| `nestedKey` | string | yes | Nested array key on the matched parent (e.g., 'findings') |
|
|
76
90
|
| `nestedMatch` | object | yes | Fields to match the nested item (e.g., { id: 'F-001' }) |
|
|
77
91
|
| `updates` | object | yes | Fields to update on the nested item (e.g., { state: 'resolved' }) |
|
|
@@ -86,7 +100,7 @@ Remove items matching a predicate from a top-level array in a project block. Ide
|
|
|
86
100
|
|-----------|------|----------|-------------|
|
|
87
101
|
| `block` | string | yes | Block name (e.g., 'issues') |
|
|
88
102
|
| `arrayKey` | string | yes | Top-level array key (e.g., 'issues') |
|
|
89
|
-
| `match` | object | yes | Fields to match (e.g., { id: '
|
|
103
|
+
| `match` | object | yes | Fields to match (e.g., { id: 'ISSUE-NNN' }) |
|
|
90
104
|
</tool>
|
|
91
105
|
|
|
92
106
|
<tool name="remove-block-nested-item">
|
|
@@ -98,19 +112,19 @@ Remove items matching a predicate from a nested array on a parent-array item in
|
|
|
98
112
|
|-----------|------|----------|-------------|
|
|
99
113
|
| `block` | string | yes | Block name (e.g., 'spec-reviews') |
|
|
100
114
|
| `arrayKey` | string | yes | Parent array key (e.g., 'reviews') |
|
|
101
|
-
| `match` | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-
|
|
115
|
+
| `match` | object | yes | Fields to match the parent item (e.g., { id: 'REVIEW-NNN' }) |
|
|
102
116
|
| `nestedKey` | string | yes | Nested array key on the matched parent (e.g., 'findings') |
|
|
103
117
|
| `nestedMatch` | object | yes | Fields to match the nested items to remove (e.g., { id: 'F-001' }) |
|
|
104
118
|
</tool>
|
|
105
119
|
|
|
106
120
|
<tool name="read-block-dir">
|
|
107
|
-
Enumerate and parse all .json files in a
|
|
121
|
+
Enumerate and parse all .json files in a <substrate-dir>/<subdir>/ directory, returned as a sorted array. Missing directories return [].
|
|
108
122
|
|
|
109
123
|
*Enumerate project block subdirectories (phases, schemas, etc.) as parsed JSON*
|
|
110
124
|
|
|
111
125
|
| Parameter | Type | Required | Description |
|
|
112
126
|
|-----------|------|----------|-------------|
|
|
113
|
-
| `subdir` | string | yes | Subdirectory under
|
|
127
|
+
| `subdir` | string | yes | Subdirectory under the substrate dir (e.g., 'phases', 'schemas') |
|
|
114
128
|
</tool>
|
|
115
129
|
|
|
116
130
|
<tool name="read-block">
|
|
@@ -149,21 +163,28 @@ Validate cross-block referential integrity — check that IDs referenced across
|
|
|
149
163
|
</tool>
|
|
150
164
|
|
|
151
165
|
<tool name="read-config">
|
|
152
|
-
Read the substrate config.json as structured JSON — vocabulary, lenses, relation_types, status_buckets, display_strings, layers, block_kinds, installed_schemas, installed_blocks.
|
|
166
|
+
Read the substrate config.json as structured JSON — vocabulary, lenses, relation_types, status_buckets, display_strings, layers, block_kinds, installed_schemas, installed_blocks. 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.
|
|
153
167
|
|
|
154
168
|
*Read project config — vocabulary, lenses, relation_types, status_buckets*
|
|
155
169
|
|
|
170
|
+
| Parameter | Type | Required | Description |
|
|
171
|
+
|-----------|------|----------|-------------|
|
|
172
|
+
| `registry` | string | no | Address ONE config registry/map by key (e.g. 'relation_types', 'lenses', 'block_kinds', 'status_buckets') |
|
|
173
|
+
| `id` | string | no | With `registry`: address ONE entry within it by canonical_id |
|
|
156
174
|
</tool>
|
|
157
175
|
|
|
158
176
|
<tool name="list-tools">
|
|
159
|
-
|
|
177
|
+
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.
|
|
160
178
|
|
|
161
|
-
*Discover available tools —
|
|
179
|
+
*Discover available tools — compact index, or one tool's full descriptor via `name`*
|
|
162
180
|
|
|
181
|
+
| Parameter | Type | Required | Description |
|
|
182
|
+
|-----------|------|----------|-------------|
|
|
183
|
+
| `name` | string | no | Address ONE tool by name → full descriptor (params schema + sourceInfo) |
|
|
163
184
|
</tool>
|
|
164
185
|
|
|
165
186
|
<tool name="read-samples-catalog">
|
|
166
|
-
Enumerate installable sample block kinds (
|
|
187
|
+
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.
|
|
167
188
|
|
|
168
189
|
*Discover installable sample block kinds — title, shape, relation_types, invariants, lenses*
|
|
169
190
|
|
|
@@ -173,14 +194,14 @@ Enumerate installable sample block kinds (DEC-0037 packaged view): per kind —
|
|
|
173
194
|
</tool>
|
|
174
195
|
|
|
175
196
|
<tool name="context-current-state">
|
|
176
|
-
Derive 'where are we + what's next' purely from
|
|
197
|
+
Derive 'where are we + what's next' purely from the substrate — focus, in-flight tasks, ranked atomic-next actions (open framework-gaps then unblocked planned tasks), and blocked tasks. No writes; nothing hand-stored.
|
|
177
198
|
|
|
178
199
|
*Derive current project state — focus, in-flight, next actions, blocked*
|
|
179
200
|
|
|
180
201
|
</tool>
|
|
181
202
|
|
|
182
203
|
<tool name="context-bootstrap-state">
|
|
183
|
-
Derive the substrate bootstrap state for the cwd, purely from the filesystem
|
|
204
|
+
Derive the substrate bootstrap state for the cwd, purely from the filesystem: 'no-pointer' | 'no-config' | 'not-installed' | 'ready', plus the resolved contextDir and any declared-but-unmaterialized installed assets. 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 <substrate-dir> → /context accept-all → /context install (bootstrap requires user authorization via interactive confirmation). No writes.
|
|
184
205
|
|
|
185
206
|
*Derive substrate bootstrap state — no-pointer | no-config | not-installed | ready (never throws pre-bootstrap)*
|
|
186
207
|
|
|
@@ -214,17 +235,18 @@ Scoped add / replace / remove of ONE entry in ONE config.json registry (block_ki
|
|
|
214
235
|
</tool>
|
|
215
236
|
|
|
216
237
|
<tool name="read-schema">
|
|
217
|
-
Read a substrate schema by name as parsed JSON. Returns null when the schema file is absent.
|
|
238
|
+
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.
|
|
218
239
|
|
|
219
|
-
*Read a block schema as structured JSON
|
|
240
|
+
*Read a block schema as structured JSON — optionally address one property via `path`*
|
|
220
241
|
|
|
221
242
|
| Parameter | Type | Required | Description |
|
|
222
243
|
|-----------|------|----------|-------------|
|
|
223
244
|
| `schemaName` | string | yes | Schema name without extension (e.g., 'tasks', 'decisions', 'issues') |
|
|
245
|
+
| `path` | string | no | Address ONE property by dotted/bracket path (e.g. 'properties.tasks.items.properties.status') |
|
|
224
246
|
</tool>
|
|
225
247
|
|
|
226
248
|
<tool name="write-schema">
|
|
227
|
-
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.
|
|
249
|
+
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. Schema version bumps require a companion migration declaration via write-schema-migration; without one, read/write of items declaring an older schema_version throws version-mismatch. Registering the block_kind that points at this schema is a separate step (amend-config block_kinds).
|
|
228
250
|
|
|
229
251
|
*Create or replace a block-kind JSON Schema (meta-validated, atomic)*
|
|
230
252
|
|
|
@@ -236,6 +258,22 @@ Create or replace a substrate block-kind JSON Schema. operation 'create' require
|
|
|
236
258
|
| `dryRun` | boolean | no | Meta-validate without writing |
|
|
237
259
|
</tool>
|
|
238
260
|
|
|
261
|
+
<tool name="write-schema-migration">
|
|
262
|
+
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.
|
|
263
|
+
|
|
264
|
+
*Declare a schema version-bump migration (identity or declarative-transform) into migrations.json*
|
|
265
|
+
|
|
266
|
+
| Parameter | Type | Required | Description |
|
|
267
|
+
|-----------|------|----------|-------------|
|
|
268
|
+
| `operation` | string | yes | create | replace | remove |
|
|
269
|
+
| `schemaName` | string | yes | Schema name without extension (e.g., 'tasks'). |
|
|
270
|
+
| `fromVersion` | string | yes | Source schema semver this migration walks forward FROM. |
|
|
271
|
+
| `toVersion` | string | yes | Destination schema semver this migration produces. Must differ from fromVersion. Ignored for operation=remove. |
|
|
272
|
+
| `kind` | string | no | identity | declarative-transform. Required for operation=create/replace; ignored for remove. |
|
|
273
|
+
| `transform` | unknown | no | TransformSpec body — required when kind='declarative-transform'; forbidden when kind='identity'. Accepts a JSON string. |
|
|
274
|
+
| `writer` | object | yes | DispatchContext.writer per pi-context/src/dispatch-context.ts. |
|
|
275
|
+
</tool>
|
|
276
|
+
|
|
239
277
|
<tool name="context-init">
|
|
240
278
|
Initialize the substrate dir (bootstrap pointer + dirs only; run accept-all + install to populate).
|
|
241
279
|
|
|
@@ -243,7 +281,7 @@ Initialize the substrate dir (bootstrap pointer + dirs only; run accept-all + in
|
|
|
243
281
|
|
|
244
282
|
| Parameter | Type | Required | Description |
|
|
245
283
|
|-----------|------|----------|-------------|
|
|
246
|
-
| `contextDir` | string | yes | Substrate dir name (e.g. .
|
|
284
|
+
| `contextDir` | string | yes | Substrate dir name (e.g. .context). Required — no default. |
|
|
247
285
|
</tool>
|
|
248
286
|
|
|
249
287
|
<tool name="context-accept-all">
|
|
@@ -253,6 +291,37 @@ Adopt the canonical packaged conception (samples/conception.json) as this substr
|
|
|
253
291
|
|
|
254
292
|
</tool>
|
|
255
293
|
|
|
294
|
+
<tool name="context-switch">
|
|
295
|
+
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).
|
|
296
|
+
|
|
297
|
+
*Switch the bootstrap pointer to a different substrate dir*
|
|
298
|
+
|
|
299
|
+
| Parameter | Type | Required | Description |
|
|
300
|
+
|-----------|------|----------|-------------|
|
|
301
|
+
| `target_dir` | string | yes | Substrate dir name to switch to (e.g. '.context'). Required for default + create_new modes; ignored for to_previous mode. |
|
|
302
|
+
| `create_new` | boolean | no | When true, bootstrap target_dir as a fresh substrate AND flip the pointer in one operation (parallel to 'git switch -c <branch>'). Default false (flip to existing substrate; fails if target_dir lacks config.json). |
|
|
303
|
+
| `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. |
|
|
304
|
+
| `writer` | object | no | DispatchContext.writer — stamped by auth-gate on operator confirm; in-body trusts the stamped value. |
|
|
305
|
+
</tool>
|
|
306
|
+
|
|
307
|
+
<tool name="context-list">
|
|
308
|
+
Enumerate top-level dirs under cwd containing a config.json (switchable substrates). Marks the active one with isActive=true. Read-only.
|
|
309
|
+
|
|
310
|
+
*List switchable substrate dirs under cwd*
|
|
311
|
+
|
|
312
|
+
</tool>
|
|
313
|
+
|
|
314
|
+
<tool name="context-archive">
|
|
315
|
+
Move a non-active substrate dir to archive/<dir>/. Refuses to archive the active substrate (the dir the bootstrap pointer currently names) or to clobber an existing archive/<dir>/.
|
|
316
|
+
|
|
317
|
+
*Archive a non-active substrate dir to archive/<dir>/*
|
|
318
|
+
|
|
319
|
+
| Parameter | Type | Required | Description |
|
|
320
|
+
|-----------|------|----------|-------------|
|
|
321
|
+
| `target_dir` | string | yes | Substrate dir name to archive (e.g. '.project'). Refused if it is the active substrate. |
|
|
322
|
+
| `writer` | object | no | DispatchContext.writer — stamped by auth-gate on operator confirm. |
|
|
323
|
+
</tool>
|
|
324
|
+
|
|
256
325
|
<tool name="filter-block-items">
|
|
257
326
|
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.
|
|
258
327
|
|
|
@@ -267,13 +336,13 @@ Filter the array items of a block by a single-field predicate (eq / neq / in / m
|
|
|
267
336
|
</tool>
|
|
268
337
|
|
|
269
338
|
<tool name="resolve-item-by-id">
|
|
270
|
-
Look up the block, array key, and item payload for a given ID across all
|
|
339
|
+
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.
|
|
271
340
|
|
|
272
341
|
*Resolve a kind-prefixed ID (DEC-/FEAT-/FGAP-/issue-/REQ-/TASK-/etc.) to its owning block and item*
|
|
273
342
|
|
|
274
343
|
| Parameter | Type | Required | Description |
|
|
275
344
|
|-----------|------|----------|-------------|
|
|
276
|
-
| `id` | string | yes | Kind-prefixed ID, e.g., DEC-
|
|
345
|
+
| `id` | string | yes | Kind-prefixed ID, e.g., DEC-NNNN / FEAT-NNN / FGAP-NNN / ISSUE-NNN |
|
|
277
346
|
</tool>
|
|
278
347
|
|
|
279
348
|
<tool name="read-block-item">
|
|
@@ -284,7 +353,7 @@ Read a single item from a named block by its id — returns the item or null. Bl
|
|
|
284
353
|
| Parameter | Type | Required | Description |
|
|
285
354
|
|-----------|------|----------|-------------|
|
|
286
355
|
| `block` | string | yes | Block name (e.g., 'tasks', 'decisions', 'framework-gaps') |
|
|
287
|
-
| `id` | string | yes | Item id within the block (e.g., 'TASK-
|
|
356
|
+
| `id` | string | yes | Item id within the block (e.g., 'TASK-NNN') |
|
|
288
357
|
</tool>
|
|
289
358
|
|
|
290
359
|
<tool name="read-block-page">
|
|
@@ -300,7 +369,7 @@ Paginate a block's items: returns { items, total, hasMore }. offset default 0, l
|
|
|
300
369
|
</tool>
|
|
301
370
|
|
|
302
371
|
<tool name="join-blocks">
|
|
303
|
-
Join two blocks in one call
|
|
372
|
+
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.
|
|
304
373
|
|
|
305
374
|
*Join two blocks in one call — by relation edge or shared field; returns {left,right[]} pairs*
|
|
306
375
|
|
|
@@ -389,7 +458,7 @@ Find all closure-table edges incident on an item id (inbound, outbound, or both)
|
|
|
389
458
|
</tool>
|
|
390
459
|
|
|
391
460
|
<tool name="gather-execution-context">
|
|
392
|
-
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.
|
|
461
|
+
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.
|
|
393
462
|
|
|
394
463
|
*Compose ContextBundle for unit + context-contract-declared bundle_relation_types*
|
|
395
464
|
|
|
@@ -401,7 +470,7 @@ Compose a ContextBundle for a work-unit by reading its context-contract (by unit
|
|
|
401
470
|
</tool>
|
|
402
471
|
|
|
403
472
|
<tool name="context-roadmap-load">
|
|
404
|
-
Load a roadmap by id and return the materialized RoadmapView (phases, lens-views, status rollup, milestone resolution, scoped phase_depends_on edges, topo-ordered phaseOrder + cycles).
|
|
473
|
+
Load a roadmap by id and return the materialized RoadmapView (phases, lens-views, status rollup, milestone resolution, scoped phase_depends_on edges, topo-ordered phaseOrder + cycles). Phase ordering lives in relations.json with relation_type='phase_depends_on'.
|
|
405
474
|
|
|
406
475
|
*Load a roadmap by id*
|
|
407
476
|
|
|
@@ -443,23 +512,23 @@ List every roadmap in <config.root>/roadmap.json with id, title, optional status
|
|
|
443
512
|
<command name="/context">
|
|
444
513
|
Context state management
|
|
445
514
|
|
|
446
|
-
Subcommands: `init`, `install`, `accept-all`, `view`, `lens-curate`, `roadmap-list`, `roadmap-view`, `roadmap-validate`, `status`, `add-work`, `validate`, `help`
|
|
515
|
+
Subcommands: `init`, `switch`, `list`, `archive`, `install`, `accept-all`, `view`, `lens-curate`, `roadmap-list`, `roadmap-view`, `roadmap-validate`, `status`, `add-work`, `validate`, `help`
|
|
447
516
|
</command>
|
|
448
517
|
|
|
449
518
|
</commands_reference>
|
|
450
519
|
|
|
451
520
|
<events>
|
|
452
|
-
`session_start`
|
|
521
|
+
`session_start`, `before_agent_start`, `resources_discover`
|
|
453
522
|
</events>
|
|
454
523
|
|
|
455
524
|
<bundled_resources>
|
|
456
|
-
|
|
525
|
+
11 schemas, 34 samples bundled.
|
|
457
526
|
See references/bundled-resources.md for full inventory.
|
|
458
527
|
</bundled_resources>
|
|
459
528
|
|
|
460
529
|
<installable_blocks>
|
|
461
530
|
|
|
462
|
-
Names valid for the `installed_blocks` array in
|
|
531
|
+
Names valid for the `installed_blocks` array in `<substrate-dir>/config.json`. Install with `/context install <block>`.
|
|
463
532
|
|
|
464
533
|
| Block | Source File |
|
|
465
534
|
|-------|-------------|
|
|
@@ -478,12 +547,13 @@ Names valid for the `installed_blocks` array in `.project/config.json`. Install
|
|
|
478
547
|
| `context-contracts` | `samples/blocks/context-contracts.json` |
|
|
479
548
|
| `phase` | `samples/blocks/phase.json` |
|
|
480
549
|
| `story` | `samples/blocks/story.json` |
|
|
550
|
+
| `work-orders` | `samples/blocks/work-orders.json` |
|
|
481
551
|
|
|
482
552
|
</installable_blocks>
|
|
483
553
|
|
|
484
554
|
<installable_schemas>
|
|
485
555
|
|
|
486
|
-
Names valid for the `installed_schemas` array in
|
|
556
|
+
Names valid for the `installed_schemas` array in `<substrate-dir>/config.json`. Schemas back block validation; install with `/context install <schema>`.
|
|
487
557
|
|
|
488
558
|
| Schema | Source File |
|
|
489
559
|
|--------|-------------|
|
|
@@ -502,6 +572,7 @@ Names valid for the `installed_schemas` array in `.project/config.json`. Schemas
|
|
|
502
572
|
| `context-contracts` | `samples/schemas/context-contracts.schema.json` |
|
|
503
573
|
| `phase` | `samples/schemas/phase.schema.json` |
|
|
504
574
|
| `story` | `samples/schemas/story.schema.json` |
|
|
575
|
+
| `work-orders` | `samples/schemas/work-orders.schema.json` |
|
|
505
576
|
|
|
506
577
|
</installable_schemas>
|
|
507
578
|
|
|
@@ -511,28 +582,29 @@ Names valid for the `installed_schemas` array in `.project/config.json`. Schemas
|
|
|
511
582
|
|
|
512
583
|
| Block | Title | Array Key | Item Fields |
|
|
513
584
|
|-------|-------|-----------|-------------|
|
|
514
|
-
| `decisions` | Decisions | `decisions` | id, title, status (string (open|enacted|superseded)), context, decision, options_considered? (array), consequences (array), references? (array), created_by, created_at, enacted_by?, enacted_at? |
|
|
515
|
-
| `framework-gaps` | Framework Gaps | `gaps` | id, title, status (string (identified|accepted|in-progress|closed|wontfix)), priority? (string (P0|P1|P2|P3)), package, layer? (string (L1|L2|L3|L4|L5)), description, evidence (array), impact, canonical_vocabulary?, proposed_resolution, created_by, created_at, closed_by?, closed_at? |
|
|
516
|
-
| `tasks` | Tasks | `tasks` | id, description, status (string (planned|in-progress|completed|blocked|cancelled)), files? (array), acceptance_criteria? (array), assigned_agent?, notes? |
|
|
517
|
-
| `verification` | Verification | `verifications` | id, status (string (passed|failed|partial|skipped)), method (string (command|inspect|test)), evidence?, timestamp?, criteria_results? (array) |
|
|
518
|
-
| `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? |
|
|
519
|
-
| `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? |
|
|
520
|
-
| `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? |
|
|
521
|
-
| `rationale` | Design Rationale | `rationales` | id, title, narrative, phase? (integer) |
|
|
522
|
-
| `spec-reviews` | Spec Reviews | `reviews` | id, target, target_revision?, reviewer?, status (string (not-started|in-progress|complete|abandoned)), scope? (array), method?, clean? (boolean), created_by, created_at, completed_at? |
|
|
523
|
-
| `layer-plans` | Layer Restructure Plans | `plans` | id, title, status (string (draft|proposed|decided|in-progress|complete|abandoned)), model, description?, layers (array), migration_phases (array), created_by, created_at |
|
|
524
|
-
| `requirements` | Requirements | `requirements` | id, description, type (string (functional|non-functional|constraint|integration)), status (string (proposed|accepted|deferred|implemented|verified)), priority (string (must|should|could|wont)), acceptance_criteria? (array), source? (string (human|agent|analysis)) |
|
|
525
|
-
| `conventions` | Conventions | `rules` | id, description, enforcement (string (lint|test|review|manual)), severity (string (error|warning|info)) |
|
|
526
|
-
| `context-contracts` | Context contracts | `contracts` | id, unit_kind, bundle_relation_types (array), description?, notes?, created_by, created_at, modified_by?, modified_at? |
|
|
527
|
-
| `phase` | Phases | `phases` | id, name, intent, goal?, status (string (planned|in-progress|completed)), success_criteria? (array), specs? (array), artifacts_produced? (array) |
|
|
528
|
-
| `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? |
|
|
585
|
+
| `decisions` | Decisions | `decisions` | id, title, status (string (open|enacted|superseded)), context, decision, options_considered? (array), consequences (array), references? (array), created_by, created_at, enacted_by?, enacted_at?, oid?, content_hash?, content_parent? |
|
|
586
|
+
| `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? |
|
|
587
|
+
| `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? |
|
|
588
|
+
| `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? |
|
|
589
|
+
| `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? |
|
|
590
|
+
| `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? |
|
|
591
|
+
| `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? |
|
|
592
|
+
| `rationale` | Design Rationale | `rationales` | id, title, narrative, phase? (integer), oid?, content_hash?, content_parent? |
|
|
593
|
+
| `spec-reviews` | Spec Reviews | `reviews` | id, target, target_revision?, reviewer?, status (string (not-started|in-progress|complete|abandoned)), scope? (array), method?, clean? (boolean), created_by, created_at, completed_at?, oid?, content_hash?, content_parent? |
|
|
594
|
+
| `layer-plans` | Layer Restructure Plans | `plans` | id, title, status (string (draft|proposed|decided|in-progress|complete|abandoned)), model, description?, layers (array), migration_phases (array), created_by, created_at, oid?, content_hash?, content_parent? |
|
|
595
|
+
| `requirements` | Requirements | `requirements` | id, description, type (string (functional|non-functional|constraint|integration)), status (string (proposed|accepted|deferred|implemented|verified)), priority (string (must|should|could|wont)), acceptance_criteria? (array), source? (string (human|agent|analysis)), oid?, content_hash?, content_parent? |
|
|
596
|
+
| `conventions` | Conventions | `rules` | id, description, enforcement (string (lint|test|review|manual)), severity (string (error|warning|info)), oid?, content_hash?, content_parent? |
|
|
597
|
+
| `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? |
|
|
598
|
+
| `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? |
|
|
599
|
+
| `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? |
|
|
600
|
+
| `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? |
|
|
529
601
|
|
|
530
602
|
**Status Enums:**
|
|
531
603
|
|
|
532
604
|
| Block | Field | Values |
|
|
533
605
|
|-------|-------|--------|
|
|
534
606
|
| `decisions` | `status` | open, enacted, superseded |
|
|
535
|
-
| `framework-gaps` | `status` | identified, accepted, in-progress, closed, wontfix |
|
|
607
|
+
| `framework-gaps` | `status` | identified, accepted, in-progress, closed, wontfix, superseded_by |
|
|
536
608
|
| `framework-gaps` | `priority` | P0, P1, P2, P3 |
|
|
537
609
|
| `framework-gaps` | `layer` | L1, L2, L3, L4, L5 |
|
|
538
610
|
| `tasks` | `status` | planned, in-progress, completed, blocked, cancelled |
|
|
@@ -557,23 +629,30 @@ Names valid for the `installed_schemas` array in `.project/config.json`. Schemas
|
|
|
557
629
|
| `conventions` | `severity` | error, warning, info |
|
|
558
630
|
| `phase` | `status` | planned, in-progress, completed |
|
|
559
631
|
| `story` | `status` | proposed, ready, in-progress, in-review, complete, blocked |
|
|
632
|
+
| `work-orders` | `status` | proposed, in-progress, real-check-passed, real-check-failed, completed, cancelled |
|
|
560
633
|
|
|
561
634
|
</planning_vocabulary>
|
|
562
635
|
|
|
563
636
|
<objective>
|
|
564
|
-
pi-context manages structured project state in
|
|
637
|
+
pi-context manages structured project state in the substrate directory — a directory of JSON block files validated against schemas. The substrate (config + lenses + closure-table relations) is degree-zero state that defines where the rest lives and how items group into views.
|
|
565
638
|
</objective>
|
|
566
639
|
|
|
567
640
|
<block_files>
|
|
568
|
-
Blocks are JSON files under the substrate root (
|
|
641
|
+
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.
|
|
642
|
+
|
|
643
|
+
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.
|
|
569
644
|
</block_files>
|
|
570
645
|
|
|
646
|
+
<content_addressing>
|
|
647
|
+
On a stamping write the item's content projection (a shallow copy with the metadata fields removed) is persisted to `<substrate-dir>/objects/<content_hash>.json` — a content-addressed object store (idempotent, atomic tmp+rename; identical content yields a byte-identical file). The store is git-tracked: it is the integrity/version store, and gitignoring it would lose pinning. Object persistence is deferred until after the whole block clears schema validation, so a validation failure never orphans an object. The metadata fields excluded from the content hash are the mandatory floor `{id, oid, content_hash, content_parent}` (never hashable, never pullable into the hash by an override) plus a discretionary set (the author fields and `closed_by`/`closed_at`); a schema's item subschema may redefine the discretionary set via `x-identity.metadata_fields`, but the floor is always unioned in.
|
|
648
|
+
</content_addressing>
|
|
649
|
+
|
|
571
650
|
<schema_validation>
|
|
572
651
|
Every block write validates against `<root>/schemas/<blockname>.schema.json`. If the schema file doesn't exist, writes proceed without validation. Validation errors include the specific JSON Schema violations.
|
|
573
652
|
</schema_validation>
|
|
574
653
|
|
|
575
654
|
<context_init>
|
|
576
|
-
`/context init <dir>` creates the substrate skeleton: the `.pi-context.json` bootstrap pointer (declaring the substrate-dir name
|
|
655
|
+
`/context init <substrate-dir>` creates the substrate skeleton: the `.pi-context.json` bootstrap pointer (declaring the chosen substrate-dir name) plus the substrate root and its `schemas/` directory. Nothing is imposed — no `config.json`, no schemas, and no starter blocks are written (ship-no-defaults). Idempotent: re-running preserves existing dirs. Populate the substrate next with `/context accept-all` (adopt the canonical conception) followed by `/context install`.
|
|
577
656
|
</context_init>
|
|
578
657
|
|
|
579
658
|
<context_accept_all>
|
|
@@ -587,17 +666,31 @@ The installable catalog IS the packaged conception (`samples/conception.json`):
|
|
|
587
666
|
</context_install>
|
|
588
667
|
|
|
589
668
|
<substrate_config>
|
|
590
|
-
|
|
669
|
+
`<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`.
|
|
591
670
|
|
|
592
|
-
`config.json` and `relations.json` are exempt from `root` redirection — they always live at `.
|
|
671
|
+
`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.
|
|
593
672
|
|
|
594
673
|
The `loadContext(cwd)` SDK returns an mtime-keyed cached snapshot of `{ config, relations, configMtime, relationsMtime }` for one cwd. Consumers must not mutate.
|
|
595
674
|
</substrate_config>
|
|
596
675
|
|
|
676
|
+
<cross_substrate>
|
|
677
|
+
A project can carry multiple substrates. The `.pi-context.json` bootstrap pointer names the single ACTIVE substrate dir; a separate project-root, git-tracked `.pi-context-registry.json` enumerates ALL substrates — a version plus `substrates: { <substrate_id>: { dir, aliases[] } }`. `resolveSubstrateDir(cwd, substrate_id)` and `resolveAlias(cwd, alias)` look up the registry and return null on a clean miss.
|
|
678
|
+
|
|
679
|
+
`resolveRef(cwd, ref)` classifies any endpoint into one of four statuses: `active` — resolved in the active substrate's index (a bare oid/refname, or any lens_bin endpoint, which is always active without an item lookup); `foreign` — a structured endpoint carrying a `substrate_id`, or an `<alias>:<refname>` string whose alias is registered, resolved in the foreign substrate's index; `dangling` — a locator naming a registered substrate where the oid/refname is absent; `unregistered` — a `substrate_id` or alias the registry does not carry. A string with a NON-leading `:` (the parse gates on `colon > 0`) is first attempted as an `<alias>:<refname>` parse; a leading-colon string is not alias-parsed.
|
|
680
|
+
|
|
681
|
+
Source-of-truth-drift invariant: `validateContext` requires the active `config.substrate_id` to have a registry entry whose `dir` resolves to the active substrate. A mismatch yields `substrate_id_registry_mismatch`; a missing entry yields `substrate_id_unregistered`.
|
|
682
|
+
</cross_substrate>
|
|
683
|
+
|
|
684
|
+
<schema_versioning>
|
|
685
|
+
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`.
|
|
686
|
+
</schema_versioning>
|
|
687
|
+
|
|
597
688
|
<lens_views>
|
|
598
689
|
Lenses are named projections over a target block. A lens declares `id`, `target` (block name), `relation_type`, `derived_from_field` (optional — synthesizes edges from a per-item field instead of requiring authored edges), `bins` (named groupings), and `render_uncategorized`.
|
|
599
690
|
|
|
600
|
-
Edges live in
|
|
691
|
+
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.
|
|
692
|
+
|
|
693
|
+
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.)
|
|
601
694
|
|
|
602
695
|
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.
|
|
603
696
|
|
|
@@ -613,7 +706,9 @@ The lens-view algorithm: `edgesForLens(lens, items, authoredEdges)` returns synt
|
|
|
613
706
|
</context_view>
|
|
614
707
|
|
|
615
708
|
<substrate_validation>
|
|
616
|
-
`validateRelations(cwd)` (exposed as the `context-validate-relations` tool) checks the closure-table edges in `relations.json` against the config + per-block item snapshots. Diagnostics codes: `edge_unknown_relation_type`, `edge_parent_not_in_bins`, `edge_unresolved_parent`, `edge_unresolved_child`, `edge_parent_wrong_block`, `edge_child_wrong_block`, `edge_cycle_detected`. Returns `{ status: "clean" | "warnings" | "invalid", issues[] }` where each issue carries the offending edge or cycle path.
|
|
709
|
+
`validateRelations(cwd)` (exposed as the `context-validate-relations` tool) checks the closure-table edges in `relations.json` against the config + per-block item snapshots, with the `resolveRef` hook classifying foreign endpoints. Diagnostics codes: `edge_unknown_relation_type`, `edge_parent_not_in_bins`, `edge_unresolved_parent`, `edge_unresolved_child`, `edge_parent_wrong_block`, `edge_child_wrong_block`, `edge_cycle_detected`. Returns `{ status: "clean" | "warnings" | "invalid", issues[] }` where each issue carries the offending edge or cycle path.
|
|
710
|
+
|
|
711
|
+
`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.
|
|
617
712
|
|
|
618
713
|
Two 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-walk-descendants` returns the transitive descendant id list from a parent under a given relation_type.
|
|
619
714
|
</substrate_validation>
|
|
@@ -647,21 +742,20 @@ Item-level reads complement whole-block `read-block` (which is all-or-nothing an
|
|
|
647
742
|
</duplicate_detection>
|
|
648
743
|
|
|
649
744
|
<context_validate>
|
|
650
|
-
Two
|
|
745
|
+
Two surfaces address related concerns. Cross-block referential integrity is EDGE-based: there are no per-block inline-FK field checks (no `task.phase`, `task.depends_on`, `decision.phase`, `gap.resolved_by`, `requirement.traces_to`/`depends_on`, `verification.target`, `rationale.related_decisions` scans) — `relations.json` closure-table edges are the sole reference surface.
|
|
651
746
|
|
|
652
|
-
`/context validate` (the `context-validate` tool)
|
|
653
|
-
-
|
|
654
|
-
-
|
|
655
|
-
-
|
|
656
|
-
-
|
|
657
|
-
-
|
|
658
|
-
-
|
|
659
|
-
-
|
|
660
|
-
- rationale.related_decisions references valid decision IDs
|
|
747
|
+
`/context validate` (the `context-validate` tool → `validateContext`) is the project-wide check. It runs:
|
|
748
|
+
- Source-of-truth drift: when the active `config.substrate_id` is set, the project-root `.pi-context-registry.json` must carry an entry whose dir resolves to the active substrate dir (`substrate_id_unregistered`, `substrate_id_registry_mismatch`).
|
|
749
|
+
- Edge integrity: each edge's `parent`/`child` is classified via the unified id index across substrates — an endpoint naming an unregistered substrate alias/id errors (`edge_endpoint_unregistered`), one that resolves to no item errors (`edge_endpoint_dangling`); a `relation_type` absent from `config.relation_types[]` errors; when a relation_type declares `source_kinds`/`target_kinds`, an endpoint whose resolved block kind is outside the (non-`*`) declared set errors.
|
|
750
|
+
- Cycle detection: delegated to `validateRelations`; only its `edge_cycle_detected` diagnostics are merged in.
|
|
751
|
+
- Config-declared invariants: `requires-edge` and `status-consistency` classes are enforced generically from `config.invariants[]` DATA — no block/status/relation_type vocabulary is hardcoded in source; each invariant's emitted code is its own `inv.id`.
|
|
752
|
+
- Status-vocabulary: an item `status` value with no key in the declared vocabulary is a warning (`status_unknown_value`).
|
|
753
|
+
- Nested id-bearing array: a schema array at nesting depth ≥ 1 whose item shape carries an `id` is a warning to promote it to a top-level entity + membership edge (`nested_id_bearing_array`).
|
|
754
|
+
- Lens validators: every validator registered via `registerLensValidator` is dispatched and its issues merged; a throwing validator surfaces as a warning (`lens_validator_failed:<name>`).
|
|
661
755
|
|
|
662
|
-
Returns
|
|
756
|
+
Returns issues with `severity` error/warning; status is `invalid` (any error), `warnings`, or `clean`.
|
|
663
757
|
|
|
664
|
-
The `context-validate-relations` tool (see `<substrate_validation>`)
|
|
758
|
+
The lower-level `context-validate-relations` tool (→ `validateRelations`, see `<substrate_validation>`) checks the closure-table edges in `relations.json` in isolation: unregistered relation_type (`edge_unknown_relation_type`), lens-bin parent not among a lens's bins (`edge_parent_not_in_bins`), unresolved/wrong-block parent or child (`edge_unresolved_parent`, `edge_unresolved_child`, `edge_parent_wrong_block`, `edge_child_wrong_block`), and cycles (`edge_cycle_detected`).
|
|
665
759
|
</context_validate>
|
|
666
760
|
|
|
667
761
|
<update_check>
|
|
@@ -669,7 +763,7 @@ On `session_start`, checks npm registry for newer versions of `@davidorex/pi-pro
|
|
|
669
763
|
</update_check>
|
|
670
764
|
|
|
671
765
|
<success_criteria>
|
|
672
|
-
-
|
|
766
|
+
- `<substrate-dir>/`, `<substrate-dir>/schemas/`, and the `.pi-context.json` bootstrap pointer exist after `/context init <substrate-dir>` (init is skeleton-only: no `config.json`, 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.
|
|
673
767
|
- `installed_schemas` / `installed_blocks` declared in `config.json` are reified by `/context install`; `--update` overwrites
|
|
674
768
|
- Block writes validate against schemas — invalid data rejected with specific error
|
|
675
769
|
- `/context status` returns current derived state without errors
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Bundled Resources
|
|
2
2
|
|
|
3
|
-
## schemas/ (
|
|
3
|
+
## schemas/ (11 files)
|
|
4
4
|
|
|
5
5
|
- `schemas/bootstrap.schema.json`
|
|
6
6
|
- `schemas/config.schema.json`
|
|
7
|
+
- `schemas/context-registry.schema.json`
|
|
7
8
|
- `schemas/layer.schema.json`
|
|
9
|
+
- `schemas/migrations.schema.json`
|
|
8
10
|
- `schemas/priority.schema.json`
|
|
9
11
|
- `schemas/relations.schema.json`
|
|
10
12
|
- `schemas/severity.schema.json`
|
|
@@ -12,7 +14,7 @@
|
|
|
12
14
|
- `schemas/status.schema.json`
|
|
13
15
|
- `schemas/verification-method.schema.json`
|
|
14
16
|
|
|
15
|
-
## samples/ (
|
|
17
|
+
## samples/ (34 files)
|
|
16
18
|
|
|
17
19
|
- `samples/blocks/context-contracts.json`
|
|
18
20
|
- `samples/blocks/conventions.json`
|
|
@@ -29,7 +31,9 @@
|
|
|
29
31
|
- `samples/blocks/story.json`
|
|
30
32
|
- `samples/blocks/tasks.json`
|
|
31
33
|
- `samples/blocks/verification.json`
|
|
34
|
+
- `samples/blocks/work-orders.json`
|
|
32
35
|
- `samples/conception.json`
|
|
36
|
+
- `samples/migrations.json`
|
|
33
37
|
- `samples/schemas/context-contracts.schema.json`
|
|
34
38
|
- `samples/schemas/conventions.schema.json`
|
|
35
39
|
- `samples/schemas/decisions.schema.json`
|
|
@@ -45,3 +49,4 @@
|
|
|
45
49
|
- `samples/schemas/story.schema.json`
|
|
46
50
|
- `samples/schemas/tasks.schema.json`
|
|
47
51
|
- `samples/schemas/verification.schema.json`
|
|
52
|
+
- `samples/schemas/work-orders.schema.json`
|