@llblab/pi-kit 0.15.0 → 0.17.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 (120) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +2 -2
  3. package/node_modules/@llblab/pi-state-flow/AGENTS.md +12 -12
  4. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +2 -13
  5. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +31 -0
  6. package/node_modules/@llblab/pi-state-flow/README.md +11 -7
  7. package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +5 -2
  8. package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +17 -16
  9. package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +8 -0
  10. package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +24 -0
  11. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +4 -3
  12. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +2 -1
  13. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +15 -3
  14. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.d.ts +2 -0
  15. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.js +4 -0
  16. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.d.ts +7 -4
  17. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +124 -274
  18. package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +20 -23
  19. package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +8 -4
  20. package/node_modules/@llblab/pi-state-flow/dist/lib/json.js +29 -3
  21. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.d.ts +18 -0
  22. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.js +44 -1
  23. package/node_modules/@llblab/pi-state-flow/dist/lib/migration.d.ts +2 -2
  24. package/node_modules/@llblab/pi-state-flow/dist/lib/migration.js +55 -21
  25. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +7 -0
  26. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +65 -17
  27. package/node_modules/@llblab/pi-state-flow/dist/lib/publication.d.ts +17 -0
  28. package/node_modules/@llblab/pi-state-flow/dist/lib/publication.js +102 -0
  29. package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +43 -1
  30. package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +268 -10
  31. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +2 -0
  32. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +34 -5
  33. package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +17 -0
  34. package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +38 -0
  35. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +5 -5
  36. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +20 -24
  37. package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +11 -3
  38. package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +14 -4
  39. package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +1 -1
  40. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +2 -0
  41. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +55 -20
  42. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +9 -6
  43. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +10 -3
  44. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +8 -3
  45. package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
  46. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +79 -0
  47. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +23 -121
  48. package/node_modules/@llblab/pi-state-flow/docs/README.md +1 -0
  49. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +27 -20
  50. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +1 -1
  51. package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +3 -2
  52. package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +513 -0
  53. package/node_modules/@llblab/pi-state-flow/docs/usage.md +13 -10
  54. package/node_modules/@llblab/pi-state-flow/lib/config.ts +18 -15
  55. package/node_modules/@llblab/pi-state-flow/lib/context.ts +24 -0
  56. package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +4 -3
  57. package/node_modules/@llblab/pi-state-flow/lib/durable.ts +14 -5
  58. package/node_modules/@llblab/pi-state-flow/lib/episode.ts +5 -0
  59. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +119 -262
  60. package/node_modules/@llblab/pi-state-flow/lib/git.ts +23 -22
  61. package/node_modules/@llblab/pi-state-flow/lib/history.ts +8 -4
  62. package/node_modules/@llblab/pi-state-flow/lib/json.ts +31 -3
  63. package/node_modules/@llblab/pi-state-flow/lib/logging.ts +53 -1
  64. package/node_modules/@llblab/pi-state-flow/lib/migration.ts +51 -20
  65. package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +61 -17
  66. package/node_modules/@llblab/pi-state-flow/lib/publication.ts +96 -0
  67. package/node_modules/@llblab/pi-state-flow/lib/query.ts +261 -9
  68. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +32 -4
  69. package/node_modules/@llblab/pi-state-flow/lib/session.ts +45 -0
  70. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +22 -25
  71. package/node_modules/@llblab/pi-state-flow/lib/state.ts +22 -6
  72. package/node_modules/@llblab/pi-state-flow/lib/status.ts +1 -1
  73. package/node_modules/@llblab/pi-state-flow/lib/storage.ts +46 -18
  74. package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +20 -6
  75. package/node_modules/@llblab/pi-state-flow/lib/transition.ts +8 -3
  76. package/node_modules/@llblab/pi-state-flow/package.json +1 -1
  77. package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +79 -0
  78. package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +23 -121
  79. package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
  80. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
  81. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +7 -0
  82. package/node_modules/@llblab/pi-telegram/README.md +1 -0
  83. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +2 -1
  84. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +2 -1
  85. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +134 -2
  86. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +297 -16
  87. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +2 -0
  88. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +11 -0
  89. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +68 -8
  90. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +4 -3
  91. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +17 -13
  92. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -1
  93. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +1 -0
  94. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +1 -0
  95. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +55 -5
  96. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +23 -0
  97. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +20 -0
  98. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +18 -0
  99. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +152 -6
  100. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +1 -0
  101. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +5 -3
  102. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  103. package/node_modules/@llblab/pi-telegram/docs/architecture.md +3 -3
  104. package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +1 -1
  105. package/node_modules/@llblab/pi-telegram/docs/public-api.md +4 -3
  106. package/node_modules/@llblab/pi-telegram/docs/sections.md +2 -2
  107. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +2 -1
  108. package/node_modules/@llblab/pi-telegram/docs/updates.md +1 -1
  109. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +3 -0
  110. package/node_modules/@llblab/pi-telegram/lib/commands.ts +466 -21
  111. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +15 -0
  112. package/node_modules/@llblab/pi-telegram/lib/extension.ts +77 -9
  113. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +25 -10
  114. package/node_modules/@llblab/pi-telegram/lib/pi.ts +3 -0
  115. package/node_modules/@llblab/pi-telegram/lib/routing.ts +84 -17
  116. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +30 -0
  117. package/node_modules/@llblab/pi-telegram/lib/threads.ts +199 -6
  118. package/node_modules/@llblab/pi-telegram/lib/updates.ts +5 -2
  119. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  120. package/package.json +3 -3
@@ -0,0 +1,513 @@
1
+ # Lazy state through progressive `read_state`
2
+
3
+ **Status**: Implemented architecture for the next minor release. Final release validation and publication remain open.
4
+
5
+ ## Thesis
6
+
7
+ State Flow should add `lazy` as a fifth semantic plane in every scope. Lazy values are ordinary JSON: durable and versioned with the same causal lineage as hot state, but excluded from ordinary baseline hydration.
8
+
9
+ The model-facing surface remains small:
10
+
11
+ - `read_state` reads one path or an ordered list of paths using one explicit projection.
12
+ - `value` and `patch` return only the requested semantic snapshot or patch; `keys` returns narrowly bounded structural `meta` followed by `keys`.
13
+ - `patch_state` remains a recursive semantic patch, not an edit-command language.
14
+ - Array index selectors extend ordinary patch addressing; there are no `insert`, `remove`, `move`, or generalized query operations.
15
+
16
+ > Retention is not activation. Hot state carries what must matter now; lazy state preserves what may matter later; an explicit read activates only the current trajectory.
17
+
18
+ ## Goals
19
+
20
+ - Preserve large or infrequently needed semantic state without linearly growing baseline context.
21
+ - Keep values domain-native: strings remain strings, arrays of strings remain arrays of strings, and objects exist only when the domain needs objects.
22
+ - Navigate current, scoped, effective, and retained historical state through one read protocol.
23
+ - Make every successful read exact: return everything requested or fail, never silently truncate.
24
+ - Keep runtime revision, CAS, and publication mechanics out of model-facing results.
25
+ - Preserve one lock/CAS publication cohort and one causal lineage across hot and lazy mutations.
26
+
27
+ ## Non-goals
28
+
29
+ - Mandatory entry objects, stable IDs, timestamps, or provenance fields inside lazy values.
30
+ - A generalized typed query language, free-text search, tags, ranking, or a separate memory subsystem.
31
+ - Product-level element limits, pagination, cursors, or partial successful range reads.
32
+ - A separate array-edit algebra or mutation tool.
33
+ - Automatic promotion of retrieved values into future baseline context.
34
+
35
+ ## Semantic model
36
+
37
+ Each scope may contain six semantic planes:
38
+
39
+ ```text
40
+ global | CWD | session
41
+ ├── artifacts
42
+ ├── contract
43
+ ├── working
44
+ ├── intents
45
+ ├── response (session-owned where applicable)
46
+ └── lazy
47
+ ```
48
+
49
+ `artifacts`, `contract`, `working`, `intents`, and `response` remain hot. `intents` may keep compact active direction while referring to large supporting detail in `lazy`. `lazy` differs only in projection policy:
50
+
51
+ - It is canonical semantic JSON, validated and versioned with its owning scope.
52
+ - It is excluded from the ordinary baseline effective-state body.
53
+ - It becomes model-visible only through bounded baseline navigation hints or explicit `read_state` output.
54
+ - Reading it does not mutate state, freshness, usage metadata, history, or future context.
55
+
56
+ ### Semantic references
57
+
58
+ A reference is semantic content, not a runtime type. The optional `{"$ref":"cwd.lazy.plan"}` object provides the structured state-reference form. Inside any ordinary string or paragraph, a semantic-state reference uses `$` immediately followed by one valid `read_state` path, for example `$effective.lazy.memory[7]`. The prefix separates a deliberate reference from incidental path-like text and provides a deterministic seam if code-based parsing is ever justified. File paths, document sections, URIs, artifact locators, Skill identities, and agent identities retain their native syntax.
59
+
60
+ State Flow preserves all forms exactly as ordinary JSON. It does not scan prose, index targets, validate existence, rewrite relative locators, or infer authority, dependency, hydration, execution, or completion. When a reference matters, the agent resolves it explicitly with `read_state` for semantic paths or the appropriate external read/tool for other resources. A locator supports retrieval but does not replace content required for the current decision.
61
+
62
+ Reference repair is reactive, not a maintenance scan. The agent does not enumerate, audit, or resolve references merely to test them. Only after one requested `read_state` value path is missing does State Flow perform one bounded reverse lookup over current model-patchable semantic planes for exact structured `$ref` and `$path` matches. If found, the tool returns `{value:null, hint:[{type:"dangling-reference", message, paths}]}`. `hint` is explicit top-level metadata rather than state data; its action message asks for reconciliation and its path array contains at most three runtime-verified current owners. The null sentinel is never returned alone for this case. Keys, patch, and multi-path reads keep ordinary all-or-error semantics; no durable match retains the missing-path error and does not prove the agent invented the path. The agent may then reconcile a proven stale owning value while preserving surrounding meaning. This applies equally to `$ref` objects and contextual references in prose. Effective-state absence alone does not identify the owner, and unavailable history, inaccessible external resources, or transient read failure do not prove that a durable reference is broken.
63
+
64
+ Valid lazy values include:
65
+
66
+ ```json
67
+ ["important thought", "next thought"]
68
+ ```
69
+
70
+ ```json
71
+ {
72
+ "decisions": ["keep one publication barrier"],
73
+ "openQuestions": ["large-value storage layout"]
74
+ }
75
+ ```
76
+
77
+ ```json
78
+ 42
79
+ ```
80
+
81
+ State Flow does not inject IDs, provenance, revisions, range descriptors, or truncation fields into those values.
82
+
83
+ ### Effective lazy overlay
84
+
85
+ The explicit `effective.lazy` path recursively overlays `global.lazy → cwd.lazy → session.lazy` using the existing scope precedence and conflict semantics. It is read-only as an effective view and is not inserted into ordinary hot baseline state.
86
+
87
+ Explicit paths such as `global.lazy`, `cwd.lazy`, and `session.lazy` preserve direct ownership access. Deleting a key from an upper scope reveals a lower-scope value exactly as ordinary scope-local deletion does. Hiding an inherited value without changing its owner is not a separate lazy feature.
88
+
89
+ Active obligations, current constraints, unresolved next actions, and facts required for the next correct action remain hot.
90
+
91
+ ## Progressive `read_state`
92
+
93
+ ### Request shape
94
+
95
+ `read_state` accepts either one path or an ordered path list:
96
+
97
+ ```json
98
+ {
99
+ "path": "cwd.lazy.memory[0..10]",
100
+ "projection": "value"
101
+ }
102
+ ```
103
+
104
+ ```json
105
+ {
106
+ "paths": [
107
+ "effective.lazy.rules",
108
+ "cwd.lazy.memory[0..10]",
109
+ "session.working.nextAction"
110
+ ],
111
+ "projection": "value"
112
+ }
113
+ ```
114
+
115
+ `projection` defaults to `value`. A batch uses one projection for every path, evaluates every path against one captured state view, and returns results in request order. Duplicate paths remain duplicate results. If any path is invalid, the whole read fails; there is no mixed partial result.
116
+
117
+ The single `path` form is first-class. The retired top-level `offset` and `scope` inputs are rejected; history and ownership belong in the semantic path itself, such as `cwd[1].lazy.memory`.
118
+
119
+ ### Response shape
120
+
121
+ There are three projections:
122
+
123
+ | Projection | Response shape | Meaning |
124
+ | --- | --- | --- |
125
+ | `value` | `{ "value": ... }` | Exact selected semantic snapshot |
126
+ | `keys` | `{ "meta": ..., "keys": ... }` | Minimal structural facts followed by immediate keys |
127
+ | `patch` | `{ "patch": ... }` | Historical semantic patch at the selected boundary |
128
+
129
+ A single-path request returns one payload. A multi-path request returns positionally aligned arrays under the same projection fields. One missing value path with exact current durable references instead returns `{ "value": null, "hint": [{ "type": "dangling-reference", "message": "Reconcile the verified current values that reference this path.", "paths": ["cwd.working.note"] }] }`; this explicit sentinel is diagnostic metadata, not semantic state.
130
+
131
+ `value` otherwise deliberately mirrors the effective-state snapshot injected at iteration start: it is semantic state without revision, provenance, range, transport, or storage fields. `patch` likewise contains only the selected semantic patch. Only structural discovery earns `meta`, and `keys` remains the final and most valuable field in that response.
132
+
133
+ The response does not repeat the requested path or projection and does not return an internal revision. Runtime owns revision selection, locking, CAS, and publication; the model cannot improve correctness by echoing that machinery.
134
+
135
+ Errors use the normal tool-error channel rather than successful JSON containing an `error` field. The explicit dangling-reference sentinel above is the sole missing-path exception; keys, patch, multi-path, and unmatched value reads still fail.
136
+
137
+ ### Path and range model
138
+
139
+ Every path has an explicit root and addresses:
140
+
141
+ - `effective` for the current composed overlay or an indexed historical effective root.
142
+ - `global`, `cwd`, and `session` for explicit current or historical scopes.
143
+ - `lazy` beneath `effective` or an explicit scope.
144
+ - Existing retained temporal selectors using accepted-transition semantics.
145
+ - Object members and array indices.
146
+ - Canonical half-open array ranges `[start:end]`, selecting indices `start <= i < end`; `[start..end]` is an accepted fallback spelling.
147
+
148
+ Examples:
149
+
150
+ ```text
151
+ effective.lazy
152
+ effective.working.nextAction
153
+ cwd.lazy.memory
154
+ cwd.lazy.memory[4]
155
+ cwd.lazy.memory[10:20]
156
+ session[3].lazy.investigation
157
+ ```
158
+
159
+ Indices are zero-based. Negative indices, open-ended ranges, steps, predicates, wildcards, unions, and cross-array expressions are rejected in the first version.
160
+
161
+ A range must fit entirely within the current array. If an array has length 10, `[0:10]` and `[10:10]` are valid, while `[0:15]` and `[11:11]` fail. The fallback `..` spelling has identical semantics. A successful result always contains exactly the requested range. State Flow never returns a shorter successful range with truncation metadata.
162
+
163
+ The implementation must reuse or compatibly extend existing member escaping rather than inventing a second object-path language.
164
+
165
+ ## Projections
166
+
167
+ ### `value`
168
+
169
+ `value` returns the exact selected scalar, object, array, item, or range:
170
+
171
+ ```json
172
+ {
173
+ "path": "cwd.lazy.memory[0..3]"
174
+ }
175
+ ```
176
+
177
+ ```json
178
+ {
179
+ "value": [
180
+ "first thought",
181
+ "second thought",
182
+ "third thought"
183
+ ]
184
+ }
185
+ ```
186
+
187
+ A whole-value request returns the whole value. State Flow imposes no semantic element-count limit, pagination, cursor, or silent truncation. Host, model-context, and transport ceilings remain external operational constraints and surface as ordinary failures rather than partial semantic success.
188
+
189
+ A multi-path value response is positional:
190
+
191
+ ```json
192
+ {
193
+ "value": [
194
+ {"ranges": "Ranges are half-open."},
195
+ ["first thought", "second thought"],
196
+ "Implement progressive reads."
197
+ ]
198
+ }
199
+ ```
200
+
201
+ ### `keys`
202
+
203
+ `keys` combines the minimum structural facts needed to navigate with the complete immediate named keys and child kinds:
204
+
205
+ ```json
206
+ {
207
+ "path": "effective.lazy",
208
+ "projection": "keys"
209
+ }
210
+ ```
211
+
212
+ ```json
213
+ {
214
+ "meta": {
215
+ "type": "object",
216
+ "size": 3,
217
+ "sources": ["global", "cwd"]
218
+ },
219
+ "keys": {
220
+ "memory": "array",
221
+ "rules": "object",
222
+ "soul": "array"
223
+ }
224
+ }
225
+ ```
226
+
227
+ For an explicitly scoped object, redundant ownership is omitted:
228
+
229
+ ```json
230
+ {
231
+ "meta": {
232
+ "type": "object",
233
+ "size": 2
234
+ },
235
+ "keys": {
236
+ "ranges": "string",
237
+ "publication": "object"
238
+ }
239
+ }
240
+ ```
241
+
242
+ Arrays and scalars have no named child keys. Their `keys` result stays structurally uniform while `meta` supplies the only useful navigation fact:
243
+
244
+ ```json
245
+ {
246
+ "meta": {
247
+ "type": "array",
248
+ "length": 10000
249
+ },
250
+ "keys": []
251
+ }
252
+ ```
253
+
254
+ ```json
255
+ {
256
+ "meta": {
257
+ "type": "string",
258
+ "length": 18420
259
+ },
260
+ "keys": []
261
+ }
262
+ ```
263
+
264
+ ```json
265
+ {
266
+ "meta": {
267
+ "type": "number"
268
+ },
269
+ "keys": []
270
+ }
271
+ ```
272
+
273
+ Progressive discovery comes from selecting a deeper path, not from key pagination or enumerating every array index. State Flow does not add `limit`, `cursor`, or `truncated` fields.
274
+
275
+ The read-level `meta` object is intentionally narrow and unrelated to persisted scope `meta.json` except for the generic word “metadata.” Its closed initial schema contains only:
276
+
277
+ - `type` always.
278
+ - `size` for objects, meaning immediate named-key count.
279
+ - `length` for arrays and strings.
280
+ - `sources` only when an effective view actually combines or resolves scope ownership.
281
+
282
+ It never exposes temporal boundaries, runtime identity, revisions, publication state, provenance registries, timestamps, encoded sizes, cache/index details, diagnostics, or arbitrary copied fields from `meta.json`. Adding a metadata field requires evidence that it changes the agent's next read decision; diagnostic convenience alone is insufficient.
283
+
284
+ A multi-path `keys` response keeps both arrays positional and places `keys` last:
285
+
286
+ ```json
287
+ {
288
+ "meta": [
289
+ {"type": "array", "length": 10000},
290
+ {"type": "object", "size": 2}
291
+ ],
292
+ "keys": [
293
+ [],
294
+ {"ranges": "string", "publication": "object"}
295
+ ]
296
+ }
297
+ ```
298
+
299
+ ### `patch`
300
+
301
+ `patch` explains change rather than materialized state:
302
+
303
+ ```json
304
+ {
305
+ "path": "cwd[3].lazy.memory",
306
+ "projection": "patch"
307
+ }
308
+ ```
309
+
310
+ An indexed change:
311
+
312
+ ```json
313
+ {
314
+ "patch": {
315
+ "[1]": "corrected thought"
316
+ }
317
+ }
318
+ ```
319
+
320
+ A whole-array replacement:
321
+
322
+ ```json
323
+ {
324
+ "patch": [
325
+ "new first thought",
326
+ "new second thought"
327
+ ]
328
+ }
329
+ ```
330
+
331
+ No change to the selected path at that boundary:
332
+
333
+ ```json
334
+ {
335
+ "patch": {}
336
+ }
337
+ ```
338
+
339
+ Deletion of the selected object key:
340
+
341
+ ```json
342
+ {
343
+ "patch": null
344
+ }
345
+ ```
346
+
347
+ This is unambiguous because empty supplied semantic patches are invalid no-ops, while `null` is patch deletion syntax and cannot be retained semantic state. History before the active origin or outside the retained hot window fails explicitly.
348
+
349
+ ## Baseline lazy hint
350
+
351
+ Baseline inference receives ordinary hot effective state plus a fixed-shape lazy availability hint. The hint contains navigation only, not lazy bodies, a catalog, pagination state, or per-value metadata.
352
+
353
+ It may identify:
354
+
355
+ - Whether effective lazy state exists.
356
+ - Its immediate top-level keys and kinds.
357
+ - The exact `read_state` path for deeper inspection.
358
+
359
+ The hint is emitted as `lazy_navigation` with `available` and the exact root `path`. For an object root it includes the complete immediate `keys` → child-kind map only when there are at most 32 keys and its canonical JSON is at most 1,024 characters. Otherwise it omits `keys` entirely rather than presenting a partial catalog. This keeps the hint bounded while `read_state` itself returns every explicitly requested value or key set; omission from the hint never makes lazy state unreachable.
360
+
361
+ ## Activation and promotion
362
+
363
+ A lazy read enriches only the current tool-result trajectory. It does not:
364
+
365
+ - Enter ordinary effective baseline state.
366
+ - Persist in later baseline inference automatically.
367
+ - Become authoritative merely because it was retrieved.
368
+ - Update semantic freshness, usage counters, or history.
369
+
370
+ When a retrieved fact becomes necessary for future correctness, the agent promotes a distilled consequence through an ordinary hot `patch_state` mutation:
371
+
372
+ - Durable requirement or decision → `contract`.
373
+ - Current fact, uncertainty, or continuation → `working`.
374
+ - Source-addressed reusable compilation → `artifacts`.
375
+ - Historical support with no current consequence → remain under `lazy`.
376
+
377
+ ## `patch_state` and arrays
378
+
379
+ `patch_state` remains the sole semantic mutation and publication barrier. There is no `edits` array and no operation vocabulary such as `replace`, `insert`, `remove`, or `move`.
380
+
381
+ Existing recursive semantics continue:
382
+
383
+ - An object recursively patches an object.
384
+ - A scalar replaces the selected scalar/value.
385
+ - An array replaces the selected array as a whole.
386
+ - `null` deletes an object key and remains invalid as retained semantic state.
387
+
388
+ Array index selectors extend recursive addressing:
389
+
390
+ ```json
391
+ {
392
+ "cwd": {
393
+ "lazy": {
394
+ "memory": {
395
+ "[1]": "corrected second thought",
396
+ "[4]": "corrected fifth thought"
397
+ }
398
+ }
399
+ },
400
+ "final": true
401
+ }
402
+ ```
403
+
404
+ Normative index behavior:
405
+
406
+ - `"[N]"` addresses an existing zero-based element of the retained array.
407
+ - Every addressed index must exist against the one captured publication basis.
408
+ - If any index is invalid, the entire `patch_state` call fails and publishes nothing.
409
+ - An indexed scalar or array value is replaced.
410
+ - An indexed object receives the ordinary recursive object patch; the materialized element is the resulting replacement value at that index.
411
+ - Multiple indexed and object changes in one call share one validation and one lock/CAS publication cohort.
412
+ - Index syntax is reserved and distinct from an ordinary object key such as `"1"`.
413
+
414
+ Nested addressing remains ordinary patch structure:
415
+
416
+ ```json
417
+ {
418
+ "cwd": {
419
+ "lazy": {
420
+ "groups": {
421
+ "[0]": {
422
+ "notes": {
423
+ "[1]": "corrected note"
424
+ }
425
+ }
426
+ }
427
+ }
428
+ },
429
+ "final": true
430
+ }
431
+ ```
432
+
433
+ Local insertion, removal with shifting, movement, predicates, and ID addressing are intentionally absent. A caller that needs structural array changes reads the array, constructs the desired ordinary JSON value, and replaces the array. A richer mutation language is considered only if measured real workloads prove whole-array replacement inadequate.
434
+
435
+ ## Publication and storage
436
+
437
+ Lazy mutations inherit existing guarantees:
438
+
439
+ - One accepted transition identity across all changed scopes and planes.
440
+ - One lock/CAS publication cohort.
441
+ - Atomic hot-plus-lazy multi-scope changes.
442
+ - Scope-local deletion and effective revelation semantics.
443
+ - Exact revision selection on restore and branch navigation.
444
+ - Read-only discovery with no commit, timestamp update, or transition.
445
+
446
+ The first implementation keeps lazy trees co-located in the existing scope semantic files. A local Git-backed probe with incompressible 1 KiB, 100 KiB, and 1 MiB lazy payloads observed 0.33–0.42 s publication, 0.24–0.30 s cold restoration, and approximately linear loose-store growth; the 1 MiB case occupied about 2.2 MiB including the worktree and loose Git history. This does not justify sharding before real workload evidence. A future path-sharded or content-addressed optimization must expose one logical State Flow revision, preserve symlink and ownership safety, and keep normalized semantic JSON authoritative while indexes and caches remain rebuildable projections.
447
+
448
+ ## Failure semantics
449
+
450
+ - A nonexistent path, wrong target kind, malformed selector, or out-of-bounds index/range is a tool error.
451
+ - One invalid member of a path batch fails the entire read before returning partial success.
452
+ - One invalid indexed patch fails the entire mutation before publication.
453
+ - A malformed lazy subtree fails closed at the smallest affected path and reports that path.
454
+ - Missing or corrupt optional indexes cannot make canonical lazy JSON disappear.
455
+ - Read failures create no semantic transition and do not affect ordinary hot state.
456
+ - Mechanical index rebuilds create no semantic transition.
457
+
458
+ ## Normative invariants
459
+
460
+ 1. **Ordinary JSON**: Lazy values contain domain semantics, never mandatory State Flow record wrappers.
461
+ 2. **Semantic snapshots**: `value` contains only the selected state snapshot and `patch` only the selected semantic patch; `keys` alone adds closed structural `meta` before `keys`.
462
+ 3. **Exact success**: A successful read returns everything requested; it never truncates or paginates silently.
463
+ 4. **Runtime-owned concurrency**: Revisions, locks, and CAS remain internal unless explicitly needed for diagnostics.
464
+ 5. **Hot-state safety**: Anything required for the next correct action remains hot.
465
+ 6. **Retention/activation independence**: Growing lazy state does not hydrate its body into baseline context.
466
+ 7. **One read protocol**: Current values, effective lazy values, structure, metadata, and retained patches share one address model.
467
+ 8. **No activation by side effect**: Reads cannot change future inference context.
468
+ 9. **Explicit frontier crossing**: Only a visible hot-state patch promotes a lazy consequence.
469
+ 10. **Patch remains patch**: Array indices extend recursive addressing without introducing an edit-command language.
470
+ 11. **Index safety**: Array indices are interpreted only against one captured basis under lock/CAS.
471
+ 12. **Failure isolation**: Lazy corruption or unavailable indexes do not damage valid hot state.
472
+
473
+ ## Validation contract
474
+
475
+ Before release, implementation evidence must prove:
476
+
477
+ - Lazy bodies do not enter ordinary baseline effective state.
478
+ - Baseline lazy navigation remains bounded as lazy body size grows.
479
+ - Single and ordered multi-path reads preserve exact request order and one captured state view.
480
+ - A failing path produces no partial batch result.
481
+ - Every projection returns exactly its matching top-level key.
482
+ - `value` returns complete selected values and exact valid ranges without product pagination or truncation.
483
+ - Out-of-bounds indices and ranges fail, including batch and boundary cases.
484
+ - `keys` returns minimal closed-schema `meta` followed by complete immediate named-key structure without descendant values or array-index enumeration.
485
+ - Read-level `meta` cannot leak or copy persisted `meta.json`, runtime revision, temporal, publication, provenance, cache, or diagnostic fields.
486
+ - `patch` selects the same causal boundary as existing historical reads and distinguishes no-change from deletion.
487
+ - `effective.lazy` follows global → CWD → session overlay while explicit scope paths preserve ownership.
488
+ - Reads create no semantic transition, Git commit, publication, freshness update, or future activation.
489
+ - Whole-array replacement and indexed scalar, array, object, nested, multi-index, and stale-basis patches remain atomic.
490
+ - Restore, fork, file-only, and Git-backed paths select lazy state from the same owning State Flow revision.
491
+ - Corrupt lazy data or optional indexes do not damage ordinary hot State Flow.
492
+ - Legacy stores and legacy `read_state` inputs either migrate deterministically or fail actionably.
493
+
494
+ ## Remaining evolution decisions
495
+
496
+ - Exact member escaping beyond the current strict grammar for names containing separators or brackets.
497
+ - A measured real-workload threshold that would justify replacing the initial co-located semantic layout.
498
+ - Cold Git-history access beyond retained hot history.
499
+
500
+ These decisions cannot introduce mandatory record objects, default metadata envelopes, pagination, typed queries, search, ranking, or a second mutation language without a new design decision.
501
+
502
+ ## Next minor release sequence
503
+
504
+ 1. Extend the existing path parser with canonical escaping, ordered batches, strict indices, and half-open ranges.
505
+ 2. Implement semantic-snapshot `value`, structural `meta` + `keys`, and semantic `patch` reads over current hot state first.
506
+ 3. Add indexed recursive array patching through the existing lock/CAS barrier.
507
+ 4. Add `lazy` to scope validation, persistence, history, restore, and explicit scoped reads.
508
+ 5. Add the read-only `effective.lazy` overlay and bounded baseline navigation hint.
509
+ 6. Add migration, corruption, stale-basis, restore, fork, file-only, Git-backed, and concurrency coverage.
510
+ 7. Measure repository growth, publication latency, restoration latency, and package/store size before selecting any sharded layout.
511
+ 8. Update runtime protocol and user documentation, run full validation, and release through the repository's guarded minor-release flow.
512
+
513
+ The stopping rule is conceptual economy: ordinary JSON, one effective lazy overlay, pure state and patch snapshots, one narrow structural `meta` + `keys` projection, recursive patches with indexed array addressing, and one mutation/publication barrier.
@@ -6,11 +6,11 @@ For the concept and installation, start with the [README](../README.md). This gu
6
6
 
7
7
  `/state-flow-start` initializes any missing storage and enables the current Pi branch. No remote is required. Starting mid-conversation retains Pi's active context for one complete bootstrap run, during which the agent must compile future-relevant information into state.
8
8
 
9
- - **New session:** Ordinary Pi unless `autoStart` is enabled. An enabled new session has its own empty session layer and inherits global/CWD state, never another session's private continuation.
9
+ - **New session:** Passive durable memory is available by default without starting an episode. `autoStart` promotes genuinely new sessions into active State Flow; an active new session has its own empty session layer and inherits global/CWD state, never another session's private continuation.
10
10
  - **Resume:** Restores the selected session's stored enablement, state, and lineage. Agent-level `autoStart` does not override a resumed branch.
11
11
  - **Tree navigation:** Restores the selected checkpoint and recorded state revision without checking out or resetting the shared store.
12
12
  - **Abort inference:** Stops generation while already accepted patches remain durable for continued work and corrected direction in the same session. It does not roll back memory or require immediate remote replication.
13
- - **Stop:** Disables semantic tools and updates immediately on the selected branch; ordinary prompt composition resumes with the next user run. It preserves state and does not create a semantic transition or change automatic-start policy for future new sessions.
13
+ - **Stop:** Ends active episode semantics and returns to the configured passive bootstrap/tool combination. It preserves state, creates no semantic transition, and does not change passive or automatic-start policy.
14
14
  - **Continue after Stop:** The same physical session retains a frozen state handoff, any interrupted current request and tool trajectory (including late results), and post-stop conversation. Completed earlier conversation stays excluded, while other extensions' custom context survives. Reload/resume/tree preserve this projection; new/forked physical sessions do not inherit it. Active restart uses it for one bootstrap run.
15
15
  - **Completed-history compaction:** After an accepted run settles without queued input, State Flow asks Pi for a native compaction boundary only when public context usage reaches 24,000 tokens. No extra model summary is requested; Pi keeps the complete latest user iteration—from its request through tools and final answer—in active history and retains the complete append-only JSONL/tree. On resume, native `buildContextEntries()` and TUI rendering omit the older completed prefix. Unknown or smaller usage skips the request, and custom Pi retention settings may still decline it benignly. Foreign custom context in the removed prefix, bootstrap/fallback/abort/error, Stop and pending input prevent State Flow-owned shortening; ordinary manual/threshold/overflow compaction remains native and may preserve unfinished work not yet patched into memory.
16
16
 
@@ -20,7 +20,7 @@ State Flow does not undo tool effects. After interruption or returning to an old
20
20
 
21
21
  Native fork replacement copies the source session checkpoint, retained patch tail and matching provenance into the new session's own storage. Global/CWD streams and provenance stay current and unchanged. An earlier fork selection copies that point's private state, not the parent's later private work. Parent data/history remain intact; selected enablement is retained, so a stopped source does not become enabled automatically.
22
22
 
23
- The child starts at step zero and a new temporal origin. Its copied tail is preserved, but pre-origin records are not seven past aligned `state[n]` boundaries. The child's own transitions build its hot window; owned checkpoints support normal reload/resume. Parent Stop projection is not inherited, including after child reload.
23
+ The child starts at step zero and a new temporal origin. Its copied tail is preserved, but pre-origin records are not seven past aligned causal boundaries addressable through `effective[n]` or scoped paths. The child's own transitions build its hot window; owned checkpoints support normal reload/resume. Parent Stop projection is not inherited, including after child reload.
24
24
 
25
25
  Initial copying requires a native fork start event, a regular canonical direct-parent session file, matching CWD/identity, a readable temporal source and an unused child namespace. Missing/unsafe evidence or CAS conflicts leave the copy unavailable rather than importing unrelated or newer private state. Explicit Start can retry an unaccepted copy in the same loaded fork after the cause is corrected.
26
26
 
@@ -28,27 +28,30 @@ Selecting a copied parent checkpoint through the child's `/tree` does not make i
28
28
 
29
29
  ## Configuration
30
30
 
31
- Optional `state-flow.json` beneath Pi's agent directory, normally `~/.pi/agent/state-flow.json`:
31
+ Optional global `config.json` at the root of the State Flow repository, normally `~/.pi/agent/state-flow/config.json`:
32
32
 
33
33
  ```json
34
34
  {
35
- "directory": "~/.pi/agent/state-flow",
36
35
  "autoStart": false,
36
+ "passiveBootstrap": true,
37
+ "passiveTools": true,
37
38
  "logging": false,
38
39
  "showSuccessfulPatches": true,
39
40
  "remotePublication": "turn-end"
40
41
  }
41
42
  ```
42
43
 
43
- - `directory`: State store. The default is `state-flow/` beneath the agent directory. Absolute paths, `~`/`~/`, and relative paths are accepted; relative paths resolve from the configuration directory, not project CWD.
44
+ The canonical store is `state-flow/` beneath the agent directory. Keeping configuration inside that repository removes the separate agent-level `state-flow.json`; SDK embeddings may still provide an explicit repository override.
44
45
  - `autoStart`: Defaults to `false`. When `true`, genuinely new sessions use the same initialization as explicit Start, including fresh CWDs.
46
+ - `passiveBootstrap`: Defaults to `true`. Projects existing effective durable memory into ordinary model context without creating scopes, migrating storage, publishing, or starting an episode.
47
+ - `passiveTools`: Defaults to `true`. Exposes `read_state` and `patch_state` outside active episodes. Reads remain side-effect free; the first explicit patch may initialize or migrate storage but does not enable continuation, terminal barriers, or compaction.
45
48
  - `logging`: Defaults to `false`. When enabled, records rejected patches and unresolved terminal/fallback diagnostics locally at `tmp/state-flow/logs.jsonl` beneath the agent directory.
46
49
  - `showSuccessfulPatches`: Defaults to `true`. In interactive Pi, successful `patch_state` rows show only the applied pretty-printed JSON arguments, with blank lines between adjacent memory sections; set it to `false` to keep only the compact summary. Rejected calls still use ordinary error rendering and private validation details are never added.
47
50
  - `remotePublication`: New-runtime policy: `turn-end` queues the newest accepted commit for asynchronous push; `off` keeps commits local; `transition` retains synchronous compatibility behavior. Existing branches keep their persisted policy.
48
51
 
49
52
  Settings are read once at extension load. After editing, use `/reload` or restart Pi. A missing file uses defaults without creating a configuration file; malformed JSON, unknown keys, or invalid values fail loading rather than silently selecting another store.
50
53
 
51
- `PI_CODING_AGENT_DIR` changes the agent-directory default. Configuration remains in that directory even when `directory` selects another state store. This override does not move data or redirect Knowledge discovery, whose default remains `knowledge/` beneath the agent directory. SDK overrides are documented under [embedding](architecture.md#embedding).
54
+ `PI_CODING_AGENT_DIR` changes both the default State Flow repository and its global configuration location. It does not redirect Knowledge discovery, whose default remains `knowledge/` beneath the agent directory. SDK repository overrides are documented under [embedding](architecture.md#embedding); an overridden repository owns its own root `config.json`.
52
55
 
53
56
  ### Diagnostic logging and privacy
54
57
 
@@ -75,11 +78,11 @@ The terminal indicator is `state-flow #N`. When `pi-telegram` is available, one
75
78
  Use a dedicated directory. State storage and Knowledge Markdown have separate responsibilities:
76
79
 
77
80
  ```text
78
- <agentDir>/state-flow/ accepted state and runtime metadata
81
+ <agentDir>/state-flow/ global config, accepted state, and runtime metadata
79
82
  <agentDir>/knowledge/ optional Markdown sources for compilation
80
83
  ```
81
84
 
82
- Each scope materializes an anchored semantic-only `checkpoint.json` plus semantic-only lines in `patches.jsonl`. Scope `meta.json` holds their temporal boundaries, CWD ownership where applicable, and runtime-owned artifact evidence; the session also has `config.json` and branch runtime metadata. CWD/session directories mirror Pi's native naming while validating canonical identities separately. See the [storage contract](architecture.md#storage-and-identity) for the exact layout.
85
+ Each scope materializes an anchored semantic-only `checkpoint.json` plus semantic-only lines in `patches.jsonl`. Scope `meta.json` holds temporal boundaries, CWD ownership where applicable, and runtime-owned artifact evidence. The session additionally uses `config.json` for behavior and `runtime.json` for branch/run recovery metadata; a full prompt is retained there only while its run is unfinished. CWD/session directories mirror Pi's native naming while validating canonical identities separately. See the [storage contract](architecture.md#storage-and-identity) for the exact layout.
83
86
 
84
87
  ### Missing, partial, and malformed storage
85
88
 
@@ -141,4 +144,4 @@ The agent should use sufficient materialized knowledge before rereading files. R
141
144
 
142
145
  Knowledge discovery finds regular lowercase `*.md` beneath its configured root, hashes opaque bytes, and skips symlinks. Only confirmed missing Markdown paths within an available root are pruned; external/non-Markdown artifacts and state under a missing whole root are preserved. An unavailable root makes freshness unknown in status. Successful reads of stale ordinary candidates require same-path global compilation; Skill reads require CWD compilation. The runtime owns provenance: model patches cannot write or delete individual freshness fields, including legacy spellings. Existing legacy entries remain readable and semantically editable. Missing freshness evidence means unknown-but-usable, not proof that a source was acquired.
143
146
 
144
- The optional `state-flow-memory` Skill handles explicit bounded curation, required feature/release/project phase-boundary reconciliation, and external promotion. Ordinary handoffs clean only touched and obviously stale visible branches; the Skill supplies the fuller scoped migration procedure when a phase boundary or explicit request earns it. It is not a background maintenance loop. Promotion must verify the destination before removing the only accepted source copy. Artifact/compiler details and model-tool contracts belong in the [architecture](architecture.md#artifact-routing).
147
+ The packaged `state-flow-guide` Skill answers concrete operational questions about reads, patches, inheritance, acquisition, finalization, and recovery without initiating cleanup. The separate `state-flow-memory` Skill handles explicit bounded curation, feature/release/project phase-boundary reconciliation, and external promotion. Ordinary handoffs clean only touched and obviously stale visible branches; neither Skill is a background maintenance loop. Promotion must verify the destination before removing the only accepted source copy. Artifact/compiler details and model-tool contracts belong in the [architecture](architecture.md#artifact-routing).