@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.
Files changed (123) hide show
  1. package/CHANGELOG.md +69 -15
  2. package/README.md +71 -18
  3. package/dist/block-api.d.ts +165 -18
  4. package/dist/block-api.d.ts.map +1 -1
  5. package/dist/block-api.js +800 -57
  6. package/dist/block-api.js.map +1 -1
  7. package/dist/citation-rot-scanner.d.ts +80 -0
  8. package/dist/citation-rot-scanner.d.ts.map +1 -0
  9. package/dist/citation-rot-scanner.js +421 -0
  10. package/dist/citation-rot-scanner.js.map +1 -0
  11. package/dist/content-hash.d.ts +25 -0
  12. package/dist/content-hash.d.ts.map +1 -0
  13. package/dist/content-hash.js +62 -0
  14. package/dist/content-hash.js.map +1 -0
  15. package/dist/context-dir.d.ts +126 -1
  16. package/dist/context-dir.d.ts.map +1 -1
  17. package/dist/context-dir.js +208 -4
  18. package/dist/context-dir.js.map +1 -1
  19. package/dist/context-registry.d.ts +122 -0
  20. package/dist/context-registry.d.ts.map +1 -0
  21. package/dist/context-registry.js +189 -0
  22. package/dist/context-registry.js.map +1 -0
  23. package/dist/context-sdk.d.ts +179 -12
  24. package/dist/context-sdk.d.ts.map +1 -1
  25. package/dist/context-sdk.js +536 -101
  26. package/dist/context-sdk.js.map +1 -1
  27. package/dist/context.d.ts +222 -4
  28. package/dist/context.d.ts.map +1 -1
  29. package/dist/context.js +244 -56
  30. package/dist/context.js.map +1 -1
  31. package/dist/git-env.d.ts +2 -0
  32. package/dist/git-env.d.ts.map +1 -0
  33. package/dist/git-env.js +29 -0
  34. package/dist/git-env.js.map +1 -0
  35. package/dist/index.d.ts +124 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +440 -1125
  38. package/dist/index.js.map +1 -1
  39. package/dist/lens-view.d.ts.map +1 -1
  40. package/dist/lens-view.js +5 -3
  41. package/dist/lens-view.js.map +1 -1
  42. package/dist/migration-registry-loader.d.ts +121 -0
  43. package/dist/migration-registry-loader.d.ts.map +1 -0
  44. package/dist/migration-registry-loader.js +309 -0
  45. package/dist/migration-registry-loader.js.map +1 -0
  46. package/dist/migrations-store.d.ts +141 -0
  47. package/dist/migrations-store.d.ts.map +1 -0
  48. package/dist/migrations-store.js +206 -0
  49. package/dist/migrations-store.js.map +1 -0
  50. package/dist/object-store.d.ts +26 -0
  51. package/dist/object-store.d.ts.map +1 -0
  52. package/dist/object-store.js +104 -0
  53. package/dist/object-store.js.map +1 -0
  54. package/dist/ops-registry.d.ts +44 -0
  55. package/dist/ops-registry.d.ts.map +1 -0
  56. package/dist/ops-registry.js +1223 -0
  57. package/dist/ops-registry.js.map +1 -0
  58. package/dist/orientation.d.ts +16 -0
  59. package/dist/orientation.d.ts.map +1 -0
  60. package/dist/orientation.js +49 -0
  61. package/dist/orientation.js.map +1 -0
  62. package/dist/promote-item.d.ts +28 -0
  63. package/dist/promote-item.d.ts.map +1 -0
  64. package/dist/promote-item.js +257 -0
  65. package/dist/promote-item.js.map +1 -0
  66. package/dist/read-element.d.ts +129 -0
  67. package/dist/read-element.d.ts.map +1 -0
  68. package/dist/read-element.js +296 -0
  69. package/dist/read-element.js.map +1 -0
  70. package/dist/rename-canonical-id.d.ts.map +1 -1
  71. package/dist/rename-canonical-id.js +22 -13
  72. package/dist/rename-canonical-id.js.map +1 -1
  73. package/dist/roadmap-plan.d.ts.map +1 -1
  74. package/dist/roadmap-plan.js +23 -13
  75. package/dist/roadmap-plan.js.map +1 -1
  76. package/dist/schema-validator.d.ts +1 -0
  77. package/dist/schema-validator.d.ts.map +1 -1
  78. package/dist/schema-validator.js +7 -3
  79. package/dist/schema-validator.js.map +1 -1
  80. package/dist/schema-write.d.ts +78 -4
  81. package/dist/schema-write.d.ts.map +1 -1
  82. package/dist/schema-write.js +297 -34
  83. package/dist/schema-write.js.map +1 -1
  84. package/dist/status-vocab.d.ts +1 -0
  85. package/dist/status-vocab.d.ts.map +1 -1
  86. package/dist/status-vocab.js +4 -0
  87. package/dist/status-vocab.js.map +1 -1
  88. package/dist/truncate.d.ts +34 -0
  89. package/dist/truncate.d.ts.map +1 -0
  90. package/dist/truncate.js +85 -0
  91. package/dist/truncate.js.map +1 -0
  92. package/dist/write-schema-migration-tool.d.ts +46 -0
  93. package/dist/write-schema-migration-tool.d.ts.map +1 -0
  94. package/dist/write-schema-migration-tool.js +115 -0
  95. package/dist/write-schema-migration-tool.js.map +1 -0
  96. package/package.json +35 -2
  97. package/samples/blocks/work-orders.json +3 -0
  98. package/samples/conception.json +22 -3
  99. package/samples/migrations.json +133 -0
  100. package/samples/schemas/context-contracts.schema.json +19 -4
  101. package/samples/schemas/conventions.schema.json +68 -12
  102. package/samples/schemas/decisions.schema.json +125 -28
  103. package/samples/schemas/features.schema.json +140 -26
  104. package/samples/schemas/framework-gaps.schema.json +171 -26
  105. package/samples/schemas/issues.schema.json +86 -13
  106. package/samples/schemas/layer-plans.schema.json +195 -35
  107. package/samples/schemas/phase.schema.json +18 -3
  108. package/samples/schemas/rationale.schema.json +37 -7
  109. package/samples/schemas/requirements.schema.json +77 -10
  110. package/samples/schemas/research.schema.json +169 -36
  111. package/samples/schemas/spec-reviews.schema.json +88 -18
  112. package/samples/schemas/story.schema.json +18 -3
  113. package/samples/schemas/tasks.schema.json +66 -10
  114. package/samples/schemas/verification.schema.json +70 -12
  115. package/samples/schemas/work-orders.schema.json +195 -0
  116. package/schemas/bootstrap.schema.json +18 -6
  117. package/schemas/config.schema.json +58 -26
  118. package/schemas/context-registry.schema.json +46 -0
  119. package/schemas/migrations.schema.json +123 -0
  120. package/schemas/relations.schema.json +41 -10
  121. package/skill-narrative.md +42 -21
  122. package/skills/pi-context/SKILL.md +159 -65
  123. package/skills/pi-context/references/bundled-resources.md +7 -2
@@ -1,34 +1,92 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "pi-context://schemas/verification",
4
- "version": "1.0.0",
4
+ "version": "1.0.1",
5
5
  "title": "Verification",
6
6
  "description": "Evidence that work meets its criteria. Per-item completion evidence linking implementation to acceptance via a verification_verifies_item edge.",
7
7
  "type": "object",
8
- "required": ["verifications"],
8
+ "required": [
9
+ "verifications"
10
+ ],
9
11
  "properties": {
10
12
  "verifications": {
11
13
  "type": "array",
12
14
  "items": {
13
15
  "type": "object",
14
- "required": ["id", "status", "method"],
16
+ "required": [
17
+ "id",
18
+ "status",
19
+ "method"
20
+ ],
15
21
  "properties": {
16
- "id": { "type": "string", "pattern": "^VER-\\d{3,}$" },
17
- "status": { "type": "string", "enum": ["passed", "failed", "partial", "skipped"] },
18
- "method": { "type": "string", "enum": ["command", "inspect", "test"] },
19
- "evidence": { "type": "string", "description": "What was checked and what was found" },
20
- "timestamp": { "type": "string" },
22
+ "id": {
23
+ "type": "string",
24
+ "pattern": "^VER-\\d{3,}$"
25
+ },
26
+ "status": {
27
+ "type": "string",
28
+ "enum": [
29
+ "passed",
30
+ "failed",
31
+ "partial",
32
+ "skipped"
33
+ ]
34
+ },
35
+ "method": {
36
+ "type": "string",
37
+ "enum": [
38
+ "command",
39
+ "inspect",
40
+ "test"
41
+ ]
42
+ },
43
+ "evidence": {
44
+ "type": "string",
45
+ "description": "What was checked and what was found"
46
+ },
47
+ "timestamp": {
48
+ "type": "string"
49
+ },
21
50
  "criteria_results": {
22
51
  "type": "array",
23
52
  "items": {
24
53
  "type": "object",
25
- "required": ["criterion", "status"],
54
+ "required": [
55
+ "criterion",
56
+ "status"
57
+ ],
26
58
  "properties": {
27
- "criterion": { "type": "string" },
28
- "status": { "type": "string", "enum": ["passed", "failed", "skipped"] },
29
- "evidence": { "type": "string" }
59
+ "criterion": {
60
+ "type": "string"
61
+ },
62
+ "status": {
63
+ "type": "string",
64
+ "enum": [
65
+ "passed",
66
+ "failed",
67
+ "skipped"
68
+ ]
69
+ },
70
+ "evidence": {
71
+ "type": "string"
72
+ }
30
73
  }
31
74
  }
75
+ },
76
+ "oid": {
77
+ "type": "string",
78
+ "pattern": "^[0-9a-f]{32}$",
79
+ "description": "Content-independent substrate-stable item identity (content-addressed substrate identity, Cycle 3). Minted once at item birth via mintOid(substrate_id); immutable across content versions. Optional in the schema so pre-Cycle-3 items validate; stamped on next write."
80
+ },
81
+ "content_hash": {
82
+ "type": "string",
83
+ "pattern": "^[0-9a-f]{64}$",
84
+ "description": "SHA-256 (hex) of the RFC-8785-canonical content projection of this item (metadata fields excluded). Recomputed on every stamping write; moves with content, stable across metadata-only churn."
85
+ },
86
+ "content_parent": {
87
+ "type": "string",
88
+ "pattern": "^[0-9a-f]{64}$",
89
+ "description": "content_hash of the immediately-prior version of this item; set on a content-changing update, absent on the first (v1) version. Forms the per-item content version chain."
32
90
  }
33
91
  }
34
92
  }
@@ -0,0 +1,195 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "pi-context://schemas/work-orders",
4
+ "version": "1.0.1",
5
+ "title": "Work Orders",
6
+ "description": "Orchestrator-authored work-order spec for the privileged JIT-agent that drives the in-pi bounded code-change loop. A work-order names the target agent, the typed input/output contracts, the substrate-block context handoff, the bounded scope within which the agent may operate, and the deterministic real-check criteria gating acceptance (deterministic verification; never LLM self-report — verdict comes from real checks the agent cannot fake). Substrate-block handoff to the consuming agent uses the ContextBlockRef shape: each context_blocks entry is either a string for whole-block injection, or an object { name, item?, depth?, focus? } for item-specific injection. To handoff a single work-order item to the consuming agent, the agent's .agent.yaml contextBlocks declares { name: \"work-orders\", item: \"WO-NNN\" }; the compiler injects the resolved item under template key _work_orders_item (with companion _work_orders_raw / _work_orders_depth / _work_orders_focus). Authorship: orchestrator is sole spec author; capability-widening edits are writer.kind=human.",
7
+ "type": "object",
8
+ "required": [
9
+ "work_orders"
10
+ ],
11
+ "additionalProperties": false,
12
+ "properties": {
13
+ "work_orders": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "required": [
19
+ "id",
20
+ "title",
21
+ "status",
22
+ "target_agent",
23
+ "input_contract",
24
+ "context_blocks",
25
+ "output_contract",
26
+ "scope",
27
+ "real_check_criteria"
28
+ ],
29
+ "properties": {
30
+ "id": {
31
+ "type": "string",
32
+ "pattern": "^WO-\\d{3,}$",
33
+ "description": "Canonical work-order id; WO-NNN uppercase + 3-digit zero-padded suffix."
34
+ },
35
+ "title": {
36
+ "type": "string"
37
+ },
38
+ "status": {
39
+ "type": "string",
40
+ "enum": [
41
+ "proposed",
42
+ "in-progress",
43
+ "real-check-passed",
44
+ "real-check-failed",
45
+ "completed",
46
+ "cancelled"
47
+ ],
48
+ "description": "Work-order lifecycle. Includes the real-check verdict states (real-check-passed / real-check-failed) — deterministic verification, never LLM self-report."
49
+ },
50
+ "target_agent": {
51
+ "type": "string",
52
+ "description": "Name of the privileged JIT-agent that consumes this work-order; resolves to <name>.agent.yaml in the agents tier."
53
+ },
54
+ "input_contract": {
55
+ "type": "object",
56
+ "description": "Typed JSON Schema describing what the agent receives as input at dispatch time."
57
+ },
58
+ "context_blocks": {
59
+ "type": "array",
60
+ "description": "Substrate-block references the privileged agent's .agent.yaml will consume via contextBlocks. Each entry: string for whole-block injection (_<name>), OR object { name, item?, depth?, focus? } for item-specific injection (per the existing ContextBlockRef shape in packages/pi-jit-agents/src/types.ts).",
61
+ "items": {
62
+ "oneOf": [
63
+ {
64
+ "type": "string"
65
+ },
66
+ {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "required": [
70
+ "name"
71
+ ],
72
+ "properties": {
73
+ "name": {
74
+ "type": "string"
75
+ },
76
+ "item": {
77
+ "type": "string"
78
+ },
79
+ "depth": {
80
+ "type": "integer",
81
+ "minimum": 0
82
+ },
83
+ "focus": {
84
+ "type": "object",
85
+ "additionalProperties": {
86
+ "type": "string"
87
+ }
88
+ }
89
+ }
90
+ }
91
+ ]
92
+ }
93
+ },
94
+ "output_contract": {
95
+ "type": "object",
96
+ "description": "Typed JSON Schema describing the agent's return contract."
97
+ },
98
+ "scope": {
99
+ "type": "object",
100
+ "additionalProperties": false,
101
+ "description": "Bounds within which the agent may make edits / run commands. Used by the capability composer to clamp the agent's grant at dispatch.",
102
+ "properties": {
103
+ "files": {
104
+ "type": "array",
105
+ "items": {
106
+ "type": "string"
107
+ }
108
+ },
109
+ "directories": {
110
+ "type": "array",
111
+ "items": {
112
+ "type": "string"
113
+ }
114
+ },
115
+ "operations": {
116
+ "type": "array",
117
+ "items": {
118
+ "type": "string"
119
+ }
120
+ }
121
+ }
122
+ },
123
+ "real_check_criteria": {
124
+ "type": "object",
125
+ "additionalProperties": false,
126
+ "required": [
127
+ "build_check_test"
128
+ ],
129
+ "description": "Deterministic real-check criteria gating acceptance. NEVER LLM self-report; verdict comes from deterministic real checks the agent cannot fake.",
130
+ "properties": {
131
+ "build_check_test": {
132
+ "type": "boolean",
133
+ "description": "Whether build+check+test exit-code gate applies (typically true)."
134
+ },
135
+ "runtime_demo": {
136
+ "type": "object",
137
+ "description": "Runtime demonstration command + expected outcome string-match.",
138
+ "properties": {
139
+ "invocation": {
140
+ "type": "string"
141
+ },
142
+ "expected": {
143
+ "type": "string"
144
+ }
145
+ }
146
+ },
147
+ "adversarial_probe": {
148
+ "type": "object",
149
+ "description": "Adversarial-probe target list — what artifacts a fresh-context agent should re-verify (deterministic real checks; never LLM self-report).",
150
+ "properties": {
151
+ "targets": {
152
+ "type": "array",
153
+ "items": {
154
+ "type": "string"
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+ },
161
+ "description": {
162
+ "type": "string"
163
+ },
164
+ "created_by": {
165
+ "type": "string"
166
+ },
167
+ "created_at": {
168
+ "type": "string"
169
+ },
170
+ "modified_by": {
171
+ "type": "string"
172
+ },
173
+ "modified_at": {
174
+ "type": "string"
175
+ },
176
+ "oid": {
177
+ "type": "string",
178
+ "pattern": "^[0-9a-f]{32}$",
179
+ "description": "Content-independent substrate-stable item identity (content-addressed substrate identity, Cycle 3). Minted once at item birth via mintOid(substrate_id); immutable across content versions. Optional in the schema so pre-Cycle-3 items validate; stamped on next write."
180
+ },
181
+ "content_hash": {
182
+ "type": "string",
183
+ "pattern": "^[0-9a-f]{64}$",
184
+ "description": "SHA-256 (hex) of the RFC-8785-canonical content projection of this item (metadata fields excluded). Recomputed on every stamping write; moves with content, stable across metadata-only churn."
185
+ },
186
+ "content_parent": {
187
+ "type": "string",
188
+ "pattern": "^[0-9a-f]{64}$",
189
+ "description": "content_hash of the immediately-prior version of this item; set on a content-changing update, absent on the first (v1) version. Forms the per-item content version chain."
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
@@ -1,22 +1,34 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "pi-context://schemas/bootstrap",
4
- "version": "1.0.0",
5
- "title": "pi-context bootstrap pointer",
6
- "description": "Per-cwd bootstrap pointer at <cwd>/.pi-context.json declaring the substrate dir name. Read by resolveContextDir(cwd) before any substrate operation; substrate dir is config-driven per DEC-0015 (no hardcoded substrate-dir paths anywhere in pi-context, pi-jit-agents, pi-workflows, pi-behavior-monitors). Atomic-safety mechanism per FGAP-026 closure phase 1.1: written for legacy .project/-using repos containing {contextDir: '.project'} so substrate stays reachable when Phase 1.2 lands resolveContextDir replacing PROJECT_DIR + SCHEMAS_DIR constants. For new repos: written by /context init (prompt-required for dirName per DEC-0015; defaulting reintroduces hardcode-dressed-as-default this DEC rejects). Mutable post-init via /context migrate (Phase 10 of FGAP-026 closure) which atomically renames the dir + rewrites this pointer + updates config.root.",
4
+ "version": "1.1.0",
5
+ "title": "pi-context bootstrap pointer",
6
+ "description": "Per-cwd bootstrap pointer at <cwd>/.pi-context.json declaring the substrate dir name. Read by resolveContextDir(cwd) before any substrate operation; substrate dir is config-driven (no hardcoded substrate-dir paths anywhere in pi-context, pi-jit-agents, pi-workflows, pi-behavior-monitors). Written for legacy .project/-using repos containing {contextDir: '.project'} so substrate stays reachable across the resolver-replacement migration. For new repos: written by /context init (prompt-required for dirName; defaulting reintroduces hardcode-dressed-as-default). Mutable post-init via /context switch which atomically rewrites this pointer + stamps previous_contextDir + switched_at + switched_by supporting bidirectional pointer-flip (parallel to git switch). Schema bump 1.0.0 -> 1.1.0 adds three optional pointer-history fields; older 1.0.0 pointers remain valid (required: ['contextDir'] unchanged; missing optional fields resolve to undefined in-process).",
7
7
  "type": "object",
8
8
  "properties": {
9
9
  "contextDir": {
10
10
  "type": "string",
11
- "description": "Directory name (relative to cwd) where the substrate lives. User-decided at /context init time per DEC-0015. For pre-existing repos using legacy .project/ convention, value is '.project' until /context migrate runs."
11
+ "description": "Directory name (relative to cwd) where the substrate lives. User-decided at /context init time. For pre-existing repos using legacy .project/ convention, value is '.project' until /context switch -c <new-dir> runs."
12
12
  },
13
13
  "version": {
14
14
  "type": "string",
15
- "description": "Bootstrap pointer format version. '1.0.0' for the initial format. Future format changes increment via semver per FGAP-006 schema versioning discipline; migration registry handles transitions if breaking."
15
+ "description": "Bootstrap pointer format version. '1.0.0' for the initial format; '1.1.0' once the pointer-history fields (previous_contextDir, switched_at, switched_by) are populated by /context switch family. Future format changes increment via semver schema versioning discipline; migration registry handles transitions if breaking."
16
16
  },
17
17
  "created_at": {
18
18
  "type": "string",
19
- "description": "ISO 8601 timestamp when the bootstrap pointer was first written. Forensic; helps trace when the substrate was bootstrapped for this repo."
19
+ "description": "ISO 8601 timestamp when the bootstrap pointer was first written. Forensic; helps trace when the substrate was bootstrapped for this repo. Preserved across /context switch operations (only switched_at + switched_by + previous_contextDir mutate on pointer-flip)."
20
+ },
21
+ "previous_contextDir": {
22
+ "type": "string",
23
+ "description": "ISO 8601 sibling: the contextDir value that this pointer carried IMMEDIATELY BEFORE the most-recent /context switch operation. Populated by flipBootstrapPointer; absent on freshly-bootstrapped pointers that have never been switched. Read by /context switch - to flip back to the prior substrate (parallel to git switch -)."
24
+ },
25
+ "switched_at": {
26
+ "type": "string",
27
+ "description": "ISO 8601 timestamp of the most-recent /context switch invocation that produced the current contextDir. Absent on freshly-bootstrapped pointers; populated by flipBootstrapPointer on every flip."
28
+ },
29
+ "switched_by": {
30
+ "type": "string",
31
+ "description": "Writer identity (verified terminal-operator stamped by auth-gate on confirm) attached to the most-recent /context switch invocation. Forensic; pairs with switched_at to attribute the pointer-flip. Absent on freshly-bootstrapped pointers."
20
32
  }
21
33
  },
22
34
  "required": ["contextDir"],
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "pi-context://schemas/config",
4
- "version": "1.4.0",
4
+ "version": "1.5.0",
5
5
  "title": "pi-context substrate config",
6
- "description": "Self-bootstrapping config block. Validates the config that configures the substrate. ConfigBlock is the canonical registry for block kinds, status buckets, relation types, display strings, layers, naming aliases, hierarchy declarations, and lens specs. Closes FGAP-001 (hierarchical block storage), FGAP-013 (status vocabulary registry), issue-089 class (PLAN- prefix collision) by making registries config-driven from line 1.",
6
+ "description": "Self-bootstrapping config block. Validates the config that configures the substrate. ConfigBlock is the canonical registry for block kinds, status buckets, relation types, display strings, layers, naming aliases, hierarchy declarations, and lens specs.",
7
7
  "type": "object",
8
8
  "required": ["schema_version", "block_kinds"],
9
9
  "additionalProperties": false,
@@ -11,11 +11,16 @@
11
11
  "schema_version": {
12
12
  "type": "string",
13
13
  "pattern": "^\\d+\\.\\d+\\.\\d+$",
14
- "description": "Semver of this config schema. Surfaces FGAP-006 at the meta-layer."
14
+ "description": "Semver of this config schema. Surfaces the schema-versioning gateway at the meta-layer."
15
15
  },
16
16
  "root": {
17
17
  "type": "string",
18
- "description": "Optional substrate-dir override. The substrate-dir name is set at /context init and recorded in the .pi-context.json bootstrap pointer (DEC-0015 — no shipped default); adoptConception writes this field at /context accept-all from the init-chosen dir. When absent, projectRoot resolves the substrate via the pointer (resolveContextDir). Not shipped by the packaged conception, which is a template. Closes GitHub issue #3 surface — relocatable per config."
18
+ "description": "Optional substrate-dir override. The substrate-dir name is set at /context init and recorded in the .pi-context.json bootstrap pointer; adoptConception writes this field at /context accept-all from the init-chosen dir. When absent, projectRoot resolves the substrate via the pointer (resolveContextDir). Not shipped by the packaged conception, which is a template. Relocatable per config."
19
+ },
20
+ "substrate_id": {
21
+ "type": "string",
22
+ "pattern": "^sub-[0-9a-f]{16}$",
23
+ "description": "Per-substrate root identity for content-addressed substrate identity (Cycle 3). Salts mintOid so item OIDs are distinct across substrates. Minted once via mintSubstrateId at /context init (Cycle 4) — established by hand for the active substrate + packaged samples this cycle — then immutable on disk; never re-minted on an item write. substrateIdForDir reads this field and throws loudly when absent (no degraded fallback)."
19
24
  },
20
25
  "naming": {
21
26
  "type": "object",
@@ -24,7 +29,7 @@
24
29
  },
25
30
  "layers": {
26
31
  "type": "array",
27
- "description": "Work-altitude tier registry (L1..L5 or user-defined). FGAP-016 layer registry surface.",
32
+ "description": "Work-altitude tier registry (L1..L5 or user-defined). Layer registry surface.",
28
33
  "items": {
29
34
  "type": "object",
30
35
  "required": ["id", "display_name"],
@@ -46,7 +51,7 @@
46
51
  "properties": {
47
52
  "canonical_id": { "type": "string", "description": "Opaque identifier (e.g. 'decisions-block')" },
48
53
  "display_name": { "type": "string", "description": "Mutable user-facing label (e.g. 'Design Decisions')" },
49
- "prefix": { "type": "string", "description": "Id-prefix token (e.g. 'DEC-'). Empty string is valid for slug-id blocks (e.g. conventions) that do not use prefix+number ids — such blocks are excluded from prefix-based id resolution (FGAP-062)." },
54
+ "prefix": { "type": "string", "description": "Id-prefix token (e.g. 'DEC-'). Empty string is valid for slug-id blocks (e.g. conventions) that do not use prefix+number ids — such blocks are excluded from prefix-based id resolution." },
50
55
  "schema_path": { "type": "string", "description": "Relative path to schema file" },
51
56
  "array_key": { "type": "string", "description": "Top-level array property in block JSON" },
52
57
  "data_path": { "type": "string", "description": "Relative path to block data file" },
@@ -56,7 +61,7 @@
56
61
  },
57
62
  "status_buckets": {
58
63
  "type": "object",
59
- "description": "Per-project status normalization. Maps raw status string → bucket. FGAP-013 closure surface.",
64
+ "description": "Per-project status normalization. Maps raw status string → bucket.",
60
65
  "additionalProperties": {
61
66
  "type": "string",
62
67
  "enum": ["complete", "in_progress", "blocked", "todo", "unknown"]
@@ -69,7 +74,7 @@
69
74
  },
70
75
  "relation_types": {
71
76
  "type": "array",
72
- "description": "Canonical relation_type registry (DEC-0013 single-source-of-truth pattern).",
77
+ "description": "Canonical relation_type registry.",
73
78
  "items": {
74
79
  "type": "object",
75
80
  "required": ["canonical_id", "display_name", "category"],
@@ -86,7 +91,7 @@
86
91
  },
87
92
  "invariants": {
88
93
  "type": "array",
89
- "description": "Config-declared substrate invariants enforced generically by validateProject. Each names block kinds / relation_types / status values purely as DATA — no vocabulary literal lives in source (DEC-0025). User-overridable: a project ships only the invariants its conception requires. Discriminated by `class`: requires-edge (item must occupy an endpoint on ≥1 edge of a given relation_type) or status-consistency (an item's status bucket must/must-not co-occur with a related item's status bucket across an edge).",
94
+ "description": "Config-declared substrate invariants enforced generically by validateProject. Each names block kinds / relation_types / status values purely as DATA — no vocabulary literal lives in source. User-overridable: a project ships only the invariants its conception requires. Discriminated by `class`: requires-edge (item must occupy an endpoint on ≥1 edge of a given relation_type) or status-consistency (an item's status bucket must/must-not co-occur with a related item's status bucket across an edge).",
90
95
  "items": {
91
96
  "oneOf": [
92
97
  {
@@ -94,14 +99,14 @@
94
99
  "required": ["id", "class", "block", "relation_types", "direction"],
95
100
  "additionalProperties": false,
96
101
  "properties": {
97
- "id": { "type": "string", "description": "Stable invariant id, surfaced in diagnostics + the issue code field." },
98
- "class": { "type": "string", "const": "requires-edge", "description": "Invariant class: qualifying items must occupy an endpoint on an edge of one of relation_types." },
99
- "block": { "type": "string", "description": "Data-file basename of the block whose items the invariant ranges over (matched against ItemLocation.block)." },
100
- "where": { "type": "object", "description": "Optional field-equality predicate. Item qualifies only when EVERY (field,value) matches item[field] === value. Absent → all items qualify.", "additionalProperties": { "type": ["string", "number", "boolean"] } },
102
+ "id": { "type": "string", "description": "Stable invariant id, surfaced in diagnostics + the issue code field." },
103
+ "class": { "type": "string", "const": "requires-edge", "description": "Invariant class: qualifying items must occupy an endpoint on an edge of one of relation_types." },
104
+ "block": { "type": "string", "description": "Data-file basename of the block whose items the invariant ranges over (matched against ItemLocation.block)." },
105
+ "where": { "type": "object", "description": "Optional field-equality predicate. Item qualifies only when EVERY (field,value) matches item[field] === value. Absent → all items qualify.", "additionalProperties": { "type": ["string", "number", "boolean"] } },
101
106
  "relation_types": { "type": "array", "minItems": 1, "items": { "type": "string" }, "description": "canonical_ids of relation_types that satisfy the invariant. Qualifying item passes if ≥1 incident edge (in direction) has relation_type in this set." },
102
- "direction": { "type": "string", "enum": ["as_parent", "as_child"], "description": "Which endpoint the qualifying item must occupy. as_parent → item.id === edge.parent; as_child → item.id === edge.child." },
103
- "severity": { "type": "string", "enum": ["error", "warning"], "default": "error", "description": "Diagnostic severity when unsatisfied." },
104
- "message": { "type": "string", "description": "Optional message template. Tokens {id} and {block} substitute. Absent → generic default." }
107
+ "direction": { "type": "string", "enum": ["as_parent", "as_child"], "description": "Which endpoint the qualifying item must occupy. as_parent → item.id === edge.parent; as_child → item.id === edge.child." },
108
+ "severity": { "type": "string", "enum": ["error", "warning"], "default": "error", "description": "Diagnostic severity when unsatisfied." },
109
+ "message": { "type": "string", "description": "Optional message template. Tokens {id} and {block} substitute. Absent → generic default." }
105
110
  }
106
111
  },
107
112
  {
@@ -109,16 +114,16 @@
109
114
  "required": ["id", "class", "block", "relation_types", "direction"],
110
115
  "additionalProperties": false,
111
116
  "properties": {
112
- "id": { "type": "string", "description": "Stable invariant id, surfaced in diagnostics + the issue code field." },
113
- "class": { "type": "string", "const": "status-consistency", "description": "Invariant class: a qualifying item's status bucket must (require_target_bucket) or must-not (forbid_target_bucket) co-occur with a related item's status bucket across an incident edge." },
114
- "block": { "type": "string", "description": "Data-file basename of the block whose items the invariant ranges over (matched against ItemLocation.block)." },
117
+ "id": { "type": "string", "description": "Stable invariant id, surfaced in diagnostics + the issue code field." },
118
+ "class": { "type": "string", "const": "status-consistency", "description": "Invariant class: a qualifying item's status bucket must (require_target_bucket) or must-not (forbid_target_bucket) co-occur with a related item's status bucket across an incident edge." },
119
+ "block": { "type": "string", "description": "Data-file basename of the block whose items the invariant ranges over (matched against ItemLocation.block)." },
115
120
  "relation_types": { "type": "array", "minItems": 1, "items": { "type": "string" }, "description": "canonical_ids of relation_types whose edges are inspected for the related (target) item." },
116
- "direction": { "type": "string", "enum": ["as_parent", "as_child"], "description": "Which endpoint the qualifying item occupies on the inspected edge; the target item is the other endpoint." },
117
- "when_bucket": { "type": "string", "enum": ["complete", "in_progress", "blocked", "todo", "unknown"], "description": "Optional gate: only items whose own status bucket equals this are checked. Absent → all items in block are checked." },
121
+ "direction": { "type": "string", "enum": ["as_parent", "as_child"], "description": "Which endpoint the qualifying item occupies on the inspected edge; the target item is the other endpoint." },
122
+ "when_bucket": { "type": "string", "enum": ["complete", "in_progress", "blocked", "todo", "unknown"], "description": "Optional gate: only items whose own status bucket equals this are checked. Absent → all items in block are checked." },
118
123
  "require_target_bucket": { "type": "string", "enum": ["complete", "in_progress", "blocked", "todo", "unknown"], "description": "Violation when the target item's status bucket differs from this. Mutually exclusive with forbid_target_bucket at runtime." },
119
- "forbid_target_bucket": { "type": "string", "enum": ["complete", "in_progress", "blocked", "todo", "unknown"], "description": "Violation when the target item's status bucket equals this. Mutually exclusive with require_target_bucket at runtime." },
120
- "severity": { "type": "string", "enum": ["error", "warning"], "default": "error", "description": "Diagnostic severity when violated." },
121
- "message": { "type": "string", "description": "Optional message template. Tokens {id} and {block} substitute. Absent → generic default." }
124
+ "forbid_target_bucket": { "type": "string", "enum": ["complete", "in_progress", "blocked", "todo", "unknown"], "description": "Violation when the target item's status bucket equals this. Mutually exclusive with require_target_bucket at runtime." },
125
+ "severity": { "type": "string", "enum": ["error", "warning"], "default": "error", "description": "Diagnostic severity when violated." },
126
+ "message": { "type": "string", "description": "Optional message template. Tokens {id} and {block} substitute. Absent → generic default." }
122
127
  }
123
128
  }
124
129
  ]
@@ -181,13 +186,40 @@
181
186
  },
182
187
  "installed_schemas": {
183
188
  "type": "array",
184
- "description": "Schemas the project has opted into via /context install (DEC-0011).",
189
+ "description": "Schemas the project has opted into via /context install.",
185
190
  "items": { "type": "string" }
186
191
  },
187
192
  "installed_blocks": {
188
193
  "type": "array",
189
- "description": "Blocks the project has opted into via /context install (DEC-0011).",
194
+ "description": "Blocks the project has opted into via /context install.",
190
195
  "items": { "type": "string" }
196
+ },
197
+ "tool_operations": {
198
+ "type": "array",
199
+ "description": "Operation-granular tool grant vocabulary. Each entry names a Pi tool (or coarser operation) that can be granted to a privileged JIT-agent. Operation-granular, opt-in from empty default.",
200
+ "items": {
201
+ "type": "object",
202
+ "additionalProperties": false,
203
+ "required": ["canonical_id"],
204
+ "properties": {
205
+ "canonical_id": { "type": "string" },
206
+ "display_name": { "type": "string" },
207
+ "category": { "type": "string" },
208
+ "kind": {
209
+ "type": "string",
210
+ "description": "Composite-tool KIND identifier. When present, composite-loader binds instance_params to the named KIND library function and registers a per-instance Pi tool."
211
+ },
212
+ "instance_params": {
213
+ "type": "object",
214
+ "description": "Instance-scoped parameters — fixed at registration time, closure-bound by composite-loader. Runtime callsites cannot widen scope."
215
+ }
216
+ }
217
+ }
218
+ },
219
+ "tool_operations_forbidden": {
220
+ "type": "array",
221
+ "items": { "type": "string" },
222
+ "description": "Project-specific operation tokens forbidden from registration as composite operations (extends framework FORBIDDEN_WHOLESALE_OPERATIONS list — L5 project layer; gated by author-tool-grant Pi tool writer.kind=human)."
191
223
  }
192
224
  }
193
225
  }
@@ -0,0 +1,46 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "pi-context://schemas/context-registry",
4
+ "version": "1.0.0",
5
+ "title": "pi-context project-root substrate registry",
6
+ "description": "Project-root locator file (<cwd>/.pi-context-registry.json) mapping each substrate's content-addressed substrate_id to its on-disk directory + alias list. Distinct from the per-substrate .pi-context.json bootstrap pointer: the pointer names the ACTIVE substrate dir, whereas this registry enumerates EVERY known substrate by its immutable substrate_id so a foreign <substrate_id>:<oid> / <alias>:<refname> locator can be resolved to a directory (Cycle-8 F2 resolver consumer). Written via registerSubstrate (upsert). The SoT-drift invariant in validateContext requires the active config.substrate_id to have an entry here whose dir resolves to the active substrate.",
7
+ "type": "object",
8
+ "required": ["version", "substrates"],
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "version": {
12
+ "type": "string",
13
+ "description": "Schema version of this registry file itself. Tracks REGISTRY_FILE_VERSION in context-registry.ts; decoupled from any individual substrate's identity or schema versions."
14
+ },
15
+ "substrates": {
16
+ "type": "object",
17
+ "description": "Map keyed by substrate_id (^sub-[0-9a-f]{16}$). Each value carries the substrate's directory (relative to the project root) + its alias list.",
18
+ "propertyNames": {
19
+ "pattern": "^sub-[0-9a-f]{16}$"
20
+ },
21
+ "additionalProperties": {
22
+ "$ref": "#/definitions/RegistryEntry"
23
+ }
24
+ }
25
+ },
26
+ "definitions": {
27
+ "RegistryEntry": {
28
+ "type": "object",
29
+ "required": ["dir", "aliases"],
30
+ "additionalProperties": false,
31
+ "properties": {
32
+ "dir": {
33
+ "type": "string",
34
+ "description": "Substrate directory. Resolved against the project root (path.resolve(cwd, dir)) when matched against the active substrate. Typically a project-root-relative bare dir name (e.g. '.context-jit-spec-v2')."
35
+ },
36
+ "aliases": {
37
+ "type": "array",
38
+ "description": "Human-facing alternate locators for this substrate (e.g. the legacy 'project' alias populated by the Phase-H migration). resolveAlias scans these to recover the substrate_id. Empty until aliases are assigned.",
39
+ "items": {
40
+ "type": "string"
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }