@plurnk/plurnk-contracts 1.7.0 → 1.9.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 (104) hide show
  1. package/SPEC.md +227 -63
  2. package/dist/conformance/agui-v1.json +541 -0
  3. package/dist/plurnk.gemma.gbnf +26 -22
  4. package/dist/plurnk.qwen.gbnf +26 -22
  5. package/dist/schema/A2aAgentDefinition.json +44 -0
  6. package/dist/schema/AcpPlan.json +63 -0
  7. package/dist/schema/AguiClientConformance.json +74 -0
  8. package/dist/schema/AguiConformanceKit.json +111 -0
  9. package/dist/schema/AguiDiscovery.json +70 -0
  10. package/dist/schema/ClientDisplayCapabilities.json +1 -1
  11. package/dist/schema/ClientInteractionProjection.json +2 -2
  12. package/dist/schema/ClientInteractionRequest.json +1 -1
  13. package/dist/schema/ClientInteractionResolution.json +1 -1
  14. package/dist/schema/ClientStatement.json +16 -11
  15. package/dist/schema/EntryReadResult.json +2 -2
  16. package/dist/schema/FunctionalityCandidate.json +33 -0
  17. package/dist/schema/FunctionalityDefinitionState.json +33 -0
  18. package/dist/schema/FunctionalityDiscoverQuery.json +16 -0
  19. package/dist/schema/FunctionalityDiscoverResult.json +15 -0
  20. package/dist/schema/FunctionalityListResult.json +15 -0
  21. package/dist/schema/FunctionalityMutationResult.json +16 -0
  22. package/dist/schema/LineMarker.json +1 -1
  23. package/dist/schema/LoopFlags.json +1 -1
  24. package/dist/schema/MatcherBody.json +1 -1
  25. package/dist/schema/McpConfigurationOverlay.json +25 -0
  26. package/dist/schema/McpServerDefinition.json +3 -2
  27. package/dist/schema/McpServerOptions.json +36 -0
  28. package/dist/schema/ModelCatalogPage.json +122 -0
  29. package/dist/schema/ModelCatalogQuery.json +32 -0
  30. package/dist/schema/ModelReadiness.json +47 -0
  31. package/dist/schema/ModelRoute.json +23 -0
  32. package/dist/schema/Notice.json +1 -1
  33. package/dist/schema/OperationResult.json +3 -3
  34. package/dist/schema/ParsedPath.json +1 -1
  35. package/dist/schema/Plan.json +52 -0
  36. package/dist/schema/PlurnkStatement.json +57 -40
  37. package/dist/schema/Position.json +1 -1
  38. package/dist/schema/ProblemDetails.json +1 -1
  39. package/dist/schema/ProposalDisposition.json +1 -1
  40. package/dist/schema/ProposalProjection.json +5 -6
  41. package/dist/schema/ProviderAccounting.json +3 -3
  42. package/dist/schema/ProviderCost.json +1 -1
  43. package/dist/schema/ProviderRequestAccounting.json +3 -3
  44. package/dist/schema/ProviderUsage.json +1 -1
  45. package/dist/schema/RangeExtent.json +1 -1
  46. package/dist/schema/ReasoningPolicy.json +7 -0
  47. package/dist/schema/ResourceSelection.json +3 -3
  48. package/dist/schema/SendBody.json +1 -1
  49. package/dist/schema/SkillDefinition.json +26 -0
  50. package/dist/schema/TextLineMarker.json +1 -1
  51. package/dist/schema/TextRegion.json +1 -1
  52. package/dist/src/AcpPlanValue.d.ts +7 -0
  53. package/dist/src/AcpPlanValue.d.ts.map +1 -0
  54. package/dist/src/AcpPlanValue.js +32 -0
  55. package/dist/src/AcpPlanValue.js.map +1 -0
  56. package/dist/src/AguiConformance.d.ts +11 -0
  57. package/dist/src/AguiConformance.d.ts.map +1 -0
  58. package/dist/src/AguiConformance.js +16 -0
  59. package/dist/src/AguiConformance.js.map +1 -0
  60. package/dist/src/ApplicationPort.d.ts +271 -0
  61. package/dist/src/ApplicationPort.d.ts.map +1 -0
  62. package/dist/src/ApplicationPort.js +2 -0
  63. package/dist/src/ApplicationPort.js.map +1 -0
  64. package/dist/src/AstBuilder.d.ts.map +1 -1
  65. package/dist/src/AstBuilder.js +44 -22
  66. package/dist/src/AstBuilder.js.map +1 -1
  67. package/dist/src/PlanValue.d.ts +10 -0
  68. package/dist/src/PlanValue.d.ts.map +1 -0
  69. package/dist/src/PlanValue.js +58 -0
  70. package/dist/src/PlanValue.js.map +1 -0
  71. package/dist/src/PlurnkErrorStrategy.d.ts.map +1 -1
  72. package/dist/src/PlurnkErrorStrategy.js +33 -19
  73. package/dist/src/PlurnkErrorStrategy.js.map +1 -1
  74. package/dist/src/PlurnkParser.js +3 -3
  75. package/dist/src/PlurnkParser.js.map +1 -1
  76. package/dist/src/Problems.js +1 -1
  77. package/dist/src/Validator.d.ts +68 -1
  78. package/dist/src/Validator.d.ts.map +1 -1
  79. package/dist/src/Validator.js +373 -0
  80. package/dist/src/Validator.js.map +1 -1
  81. package/dist/src/generated/plurnkLexer.d.ts +30 -28
  82. package/dist/src/generated/plurnkLexer.d.ts.map +1 -1
  83. package/dist/src/generated/plurnkLexer.js +398 -381
  84. package/dist/src/generated/plurnkLexer.js.map +1 -1
  85. package/dist/src/generated/plurnkParser.d.ts +56 -39
  86. package/dist/src/generated/plurnkParser.d.ts.map +1 -1
  87. package/dist/src/generated/plurnkParser.js +644 -450
  88. package/dist/src/generated/plurnkParser.js.map +1 -1
  89. package/dist/src/generated/plurnkParserVisitor.d.ts +7 -7
  90. package/dist/src/generated/plurnkParserVisitor.d.ts.map +1 -1
  91. package/dist/src/generated/plurnkParserVisitor.js +6 -6
  92. package/dist/src/generated/plurnkParserVisitor.js.map +1 -1
  93. package/dist/src/index.d.ts +7 -2
  94. package/dist/src/index.d.ts.map +1 -1
  95. package/dist/src/index.js +5 -2
  96. package/dist/src/index.js.map +1 -1
  97. package/dist/src/types.d.ts +2 -1
  98. package/dist/src/types.d.ts.map +1 -1
  99. package/dist/src/types.generated.d.ts +430 -21
  100. package/dist/src/types.generated.d.ts.map +1 -1
  101. package/dist/src/types.js +4 -0
  102. package/dist/src/types.js.map +1 -1
  103. package/package.json +7 -3
  104. package/plurnk.md +67 -78
package/SPEC.md CHANGED
@@ -10,10 +10,17 @@ is the single code API for those contracts.
10
10
  | ------------------------------------------------------------------------------- | --------------------------------------------------- |
11
11
  | Parser, AST, validators, Problems, results, Notices, text regions and extents | `@plurnk/plurnk-contracts` |
12
12
  | Effective loop policy and its default | `LoopFlags`, `DEFAULT_LOOP_FLAGS` |
13
+ | Durable reasoning intent | `ReasoningPolicy`, `REASONING_POLICIES` |
14
+ | Model route and catalog discovery | `ModelRoute`, `ModelCatalogQuery`, `ModelCatalogPage`, `ModelReadiness` |
13
15
  | Stopped-world client contract | `ProposalDisposition`, `ProposalProjection` |
14
16
  | Client-owned interaction contract | `ClientInteractionRequest`, `ClientInteractionProjection`, `ClientInteractionResolution` |
15
17
  | Client capability presentation | `ClientDisplayCapabilities` |
16
- | Workspace MCP server attachment | `McpServerDefinition` |
18
+ | Exterior adapter application calls | `ApplicationPort` |
19
+ | Workspace MCP configuration | `McpServerDefinition`, `McpServerOptions`, `McpConfigurationOverlay` |
20
+ | Worker Agent Skills definition | `SkillDefinition` |
21
+ | Worker outbound A2A agent definition | `A2aAgentDefinition` |
22
+ | Worker Functionality lifecycle projections (family-neutral) | `FunctionalityCandidate`, `FunctionalityDiscoverQuery`, `FunctionalityDiscoverResult`, `FunctionalityDefinitionState`, `FunctionalityListResult`, `FunctionalityMutationResult` |
23
+ | AG-UI discovery, client accounting, and shared conformance specimens | `AguiDiscovery`, `AguiClientConformance`, `AguiConformanceKit` |
17
24
  | JSON Schemas | `@plurnk/plurnk-contracts/schema/*.json` |
18
25
  | Generated JSON result rendering | `renderJsonResult` |
19
26
  | Local-model rails | `@plurnk/plurnk-contracts/plurnk.{gemma,qwen}.gbnf` |
@@ -23,6 +30,45 @@ is the single code API for those contracts.
23
30
  generated from the schemas; ANTLR is authoritative for accepted model-language
24
31
  syntax; GBNF remains the bounded generation aid described in §1.2.
25
32
 
33
+ §agui-discovery-contract `AguiDiscovery` is the complete installed AG-UI+
34
+ surface at one instant. `schemaVersion` identifies its discovery shape;
35
+ `actions` maps each unique public name to exactly one `scope`, `inputSchema`,
36
+ and `outputSchema`; `notifications` maps each unique event-family name to one
37
+ `payloadSchema`; and `display` carries {§client-display-capabilities} without
38
+ another presentation mechanism. The AG-UI owner supplies the built-in registry;
39
+ an extension contributes the same schema-bearing action descriptor through its
40
+ core module registration rather than creating a second action type.
41
+
42
+ §agui-action-schema-enforcement The JSON Schema values in
43
+ {§agui-discovery-contract} are executable boundary contracts, not prose or
44
+ hints. The AG-UI boundary rejects an action input before dispatch when it does
45
+ not satisfy the advertised `inputSchema`, rejects an owner's successful output
46
+ when it does not satisfy `outputSchema`, and validates a known notification
47
+ before projecting it to AG-UI. Schemas are discovery values owned by their
48
+ registrants; validation must not annotate or otherwise mutate them.
49
+
50
+ §agui-client-conformance `AguiClientConformance` is a language-neutral JSON
51
+ document accounting for every action and notification in one
52
+ {§agui-discovery-contract}. Each name is classified as `native` (dedicated
53
+ client behavior), `generic` (lossless protocol support without dedicated UI),
54
+ or `unsupported` with an explicit reason, and cites nonempty verification
55
+ evidence. Each disposition declares the exact verification dimensions its
56
+ evidence covers; native behavior includes admission and presentation, every
57
+ action includes projection plus success and failure, and every notification
58
+ includes framing plus projection. Validation requires exact action and
59
+ notification key equality with the installed discovery surface; adding or
60
+ removing a public capability therefore breaks every stale client matrix
61
+ visibly. The contracts-owned report procedure resolves every cited evidence
62
+ path and emits one record per member with its posture and verified dimensions;
63
+ a stale or fictional citation fails the report.
64
+
65
+ §agui-conformance-kit `AguiConformanceKit` is the one versioned,
66
+ language-neutral corpus of raw SSE boundary specimens and AG-UI lifecycle
67
+ sequences used by every client transport. Its JSON resource is test input, not
68
+ a third protocol implementation: each client feeds the same chunks and events
69
+ through its production parser and projection seam, then verifies the declared
70
+ outcome. Specimen names are unique within their transport or lifecycle family.
71
+
26
72
  §json-result-rendering `renderJsonResult` is the one presentation serializer
27
73
  for generated JSON operation results. A top-level array remains one valid,
28
74
  compact JSON value but places each item on its own physical line by adding only
@@ -63,7 +109,7 @@ flowchart LR
63
109
  | Shared wire data | `schema/*.json` | Defines runtime-neutral data shapes projected into generated TypeScript |
64
110
  | Stateful behavior | consuming runtime | Resolves addresses, permissions, selection arithmetic, effects, and lifecycle |
65
111
 
66
- ANTLR owns statement structure, suffix matching, slot multiplicity, accepted
112
+ ANTLR owns statement structure, delimiter matching, slot multiplicity, accepted
67
113
  slot permutations, scope-number syntax, and interstatement text recognition.
68
114
  AstBuilder owns URL decomposition and deterministic matcher validation through
69
115
  WHATWG `URL`, ECMAScript `RegExp`, XPath 1.0, and RFC 9535 JSONPath parsers.
@@ -81,7 +127,7 @@ The schemas own the runtime-neutral shapes; core owns their stateful values.
81
127
  | ------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
82
128
  | `LoopFlags` | Complete effective `mode`, `auto`, `noWeb`, `noInteraction`, and `noProposals` | Validate/expand persisted partial policy before use |
83
129
  | `ProposalDisposition` | Client authority, or the loop's exact automatic accept/reject | Compute precedence from effective loop policy, proposal kind, and stale-target truth |
84
- | `ProposalProjection` | Identity, review target/body/attrs, effective flags, stale signal, disposition | Derive one validated projection for live delivery and durable reconnect discovery |
130
+ | `ProposalProjection` | Identity, `{ scheme, authority, pathname }` review target, body/attrs, effective flags, stale signal, disposition | Derive one validated projection for live delivery and durable reconnect discovery |
85
131
  | `ProviderUsage` | Conventional input/output totals with cache and reasoning details | Preserve observed quantities without replacing absence with zero |
86
132
  | `ProviderCost` | Exact charged, estimated, or unknown monetary evidence | Normalize one monetary disposition for each physical provider request |
87
133
  | `ProviderRequestAccounting` | Usage and cost evidence for one physical provider request | Preserve request order across retries, failover, success, and failure |
@@ -89,6 +135,20 @@ The schemas own the runtime-neutral shapes; core owns their stateful values.
89
135
 
90
136
  `DEFAULT_LOOP_FLAGS` is the contracts-owned effective default value. A consumer may persist a partial object as an implementation detail, but it never exposes or acts on that partial representation as though it were the complete contract.
91
137
 
138
+ §reasoning-policy-wire `ReasoningPolicy` is exactly `off | adaptive | low |
139
+ medium | high`. The schema owns this shared wire vocabulary. Providers own the
140
+ supported subset and native projection for a selected route; core owns the
141
+ durable worker value.
142
+
143
+ §model-catalog-wire `ModelRoute` is one exact client-visible provider/model
144
+ identity with optional alias provenance. Provider credentials, endpoints, and
145
+ tuning never enter this wire shape. Catalog discovery uses a
146
+ closed bounded query and page: entries carry exact selectors, display facts,
147
+ physical limits, capabilities, and local `ModelReadiness`. A readiness cause
148
+ contains alternative environment-variable sets—every name within a set is
149
+ required and any set may satisfy the cause. It carries names only, never values,
150
+ and asserts neither credential validity nor endpoint reachability.
151
+
92
152
  ### §client-interaction-wire Client-owned interaction wire
93
153
 
94
154
  The closed client-interaction schemas describe one operation asking its client
@@ -203,14 +263,14 @@ response roots plus the parser/AstBuilder result.
203
263
 
204
264
  §rail-heading-boundaries On the GBNF rail, PLAN and every operation use lane `0`.
205
265
  Every reserved PLAN or operation heading stem is structural, regardless of the
206
- suffix a model attempts next, so a non-`0` pseudo-heading cannot be swallowed as
266
+ delimiter a model attempts next, so a non-`0` pseudo-heading cannot be swallowed as
207
267
  literal body text. Rail bodies therefore cannot quote reserved headings from any
208
- lane. This makes both the canonical suffix and section boundary structurally
268
+ lane. This makes both the canonical delimiter and section boundary structurally
209
269
  available during constrained generation; ANTLR remains the wider language and
210
270
  accepts intentional alternate-lane literals during ingestion.
211
271
 
212
272
  §gbnf-curation-shaping The rail admits OPEN/FOLD curation terms, a canonical
213
- `log:` target, and a matcher independently. It accepts any ordered mixture of
273
+ `log:` target, an optional log-body line scope, and a matcher independently. It accepts any ordered mixture of
214
274
  unsigned, `+`, and `-` terms without proving that the combination selects a log
215
275
  item; ANTLR and AstBuilder own that condition, while runtime owns wider ingested
216
276
  target resolution.
@@ -218,32 +278,35 @@ target resolution.
218
278
  ## §canonical-statement 2. Canonical statement form
219
279
 
220
280
  ```text
221
- # PLANsuffix
281
+ # PLANdelimiter
222
282
  body
223
283
 
224
- ## OPsuffix [signal]? (path)? <scope>?
284
+ ## OPdelimiter [signal]? (path)? <scope>? <!-- annotation -->?
225
285
  body?
226
286
  ```
227
287
 
228
288
  §section-boundary A statement is one Markdown section. PLAN alone uses a level-one
229
289
  heading; every other operation uses a level-two heading. Its body is the
230
290
  character-perfect section content before the next structural heading or EOF.
231
- Canonical adjacent sections have one blank separator line. That final separator
232
- line is syntax and is not body content; any additional preceding blank lines
233
- remain body content. The tolerant ingester also admits a structural heading on
234
- the immediately following line.
291
+ Canonical adjacent sections place the next structural heading on the immediately
292
+ following line. The tolerant ingester also admits one empty separator line; that
293
+ separator is syntax rather than body content, while any additional preceding
294
+ blank lines remain body content.
235
295
 
236
- §empty-section An empty section has no body lines between its heading and the
237
- section separator (or EOF) and normalizes to a null body.
296
+ §empty-section An empty section has no body lines between its heading and the next
297
+ structural heading, tolerated separator, or EOF. Optional operation bodies normalize
298
+ to null; PLAN admission normalizes its required semantic body to `[]`
299
+ under {§plan-value}.
238
300
 
239
301
  | Element | Canonical contract |
240
302
  |--------------|---------------------------------------------------------------------------|
241
303
  | `# PLAN` | Required level-one turn anchor |
242
304
  | `## OP` | Level-two protocol operation |
243
- | `suffix` | Heading lane, joined directly to PLAN or OP |
305
+ | `delimiter` | Heading lane, joined directly to PLAN or OP |
244
306
  | `[signal]` | Optional operation-specific signal, preceded by one space |
245
307
  | `(path)` | Optional target slot, preceded by one space |
246
308
  | `<scope>` | Optional numeric scope, preceded by one space |
309
+ | `<!-- … -->` | Optional trailing operation annotation, preceded by one space |
247
310
  | line ending | Ends the single-line heading |
248
311
  | `body` | Zero or more characters of operation-specific, character-perfect content |
249
312
  | blank line | Canonical section separator; excluded from the preceding body |
@@ -251,21 +314,31 @@ section separator (or EOF) and normalizes to a null body.
251
314
  The following constraints are structural:
252
315
 
253
316
  - §lane-match PLAN establishes one lane for the turn. A heading is structural
254
- only when its suffix character-matches that lane; a different suffix remains
317
+ only when its delimiter character-matches that lane; a different delimiter remains
255
318
  ordinary body text.
256
319
  - PLAN is the only H1 operation and every non-PLAN operation is H2.
257
320
  - A header occupies one physical line.
258
321
  - Each admitted signal, target, and scope slot appears at most once.
259
- - OPEN, FOLD, BARE, WORK, FORK, and KILL do not admit a scope slot.
260
- - An ingested suffix is `[A-Za-z0-9_]*`; canonical teaching and the GBNF use `0`.
322
+ - An annotation follows every present modifier and appears at most once.
323
+ - BARE, WORK, FORK, and KILL do not admit a scope slot.
324
+ - An ingested delimiter is `[A-Za-z0-9_]*`; canonical teaching and the GBNF use `0`.
261
325
 
262
326
  §slot-order Canonical producers and the GBNF rail emit signal, then target, then
263
- scope, with one ASCII space before every present slot. Slot delimiters make
327
+ scope, then annotation, with one ASCII space before every present slot. Slot delimiters make
264
328
  their boundaries unambiguous, so the tolerant ANTLR ingester accepts zero or
265
329
  more horizontal whitespace characters before each slot and any permutation of
266
330
  the slots admitted by that operation, at most once each. Accepted spacing and
267
331
  permutation are not second canonical spellings.
268
332
 
333
+ §operation-annotation A heading may end with one single-line Markdown HTML
334
+ comment. AstBuilder strips the delimiters and surrounding horizontal whitespace
335
+ into the statement's fixed `annotation: string | null` field. The annotation is
336
+ durable, model- and client-facing descriptive text but semantically inert: it
337
+ does not alter operation identity, signal, target, scope, dispatch, effect,
338
+ authorization, status, or body. An empty comment normalizes to the empty string.
339
+ Text containing a newline or lacking the closing `-->` is not an annotation;
340
+ `<!--` elsewhere remains ordinary body text.
341
+
269
342
  The ingester also accepts several bounded noncanonical forms so it can explain
270
343
  or safely execute understandable input:
271
344
 
@@ -283,10 +356,11 @@ or safely execute understandable input:
283
356
  | Element | Accepted shape or role |
284
357
  |-------------|--------------------------------------------------------------------|
285
358
  | `OP` | `FIND READ EDIT COPY MOVE OPEN FOLD SEND EXEC BARE WORK FORK KILL PLAN` |
286
- | `suffix` | `[A-Za-z0-9_]*`, adjacent to PLAN or OP |
359
+ | `delimiter` | `[A-Za-z0-9_]*`, adjacent to PLAN or OP |
287
360
  | `[signal]` | Operation-specific tags, identifier, branch, or integer |
288
361
  | `(path)` | Local path or scheme URL target; detailed in §5 |
289
362
  | `<scope>` | One or more signed integers or decimals; detailed in §7 |
363
+ | annotation | Optional trailing `<!-- … -->` descriptive text |
290
364
  | `body` | Opaque section text before the next same-lane heading or EOF |
291
365
 
292
366
  ## §op-shapes 4. Per-operation semantics
@@ -296,14 +370,14 @@ governed by {§canonical-statement}; runtime conditions remain explicit below.
296
370
 
297
371
  | OP | `[signal]` | `(path)` | `<scope>` | `body` |
298
372
  |------|-------------------------------|----------------------------------------------|---------------------------------|--------------------------------|
299
- | PLAN | none | none | none | required intended goals |
373
+ | PLAN | none | none | none | required Plurnk Plan JSON array |
300
374
  | FIND | optional add log tags | required target or glob | optional result range | optional matcher |
301
375
  | READ | optional add log tags | required target | optional text region | empty |
302
376
  | EDIT | optional add log tags | required file or entry | required for an existing target | literal text |
303
377
  | COPY | optional add log tags | required source | optional source region | required destination selection |
304
378
  | MOVE | optional add log tags | required source | optional source region | required destination selection |
305
- | FOLD | optional filter/change tags | optional log selection | none | optional matcher |
306
- | OPEN | optional filter/change tags | optional log selection | none | optional matcher |
379
+ | FOLD | optional filter/change tags | optional log selection | optional log-body line scope | optional matcher |
380
+ | OPEN | optional filter/change tags | optional log selection | optional log-body line scope | optional matcher |
307
381
  | EXEC | optional executor | optional local working path | optional timeout, poll | optional executor input |
308
382
  | BARE | optional add log tags | none | none | required prompt |
309
383
  | WORK | optional Git branch | required fresh `worker://name` | none | required prompt |
@@ -317,10 +391,33 @@ Directed SEND and KILL delegate any present code to the addressed target's
317
391
  operation contract; a live process may interpret a KILL code as a Unix signal,
318
392
  but that interpretation does not define KILL generally.
319
393
 
320
- §plan-intended-goals **PLAN records working-state deltas.** Its concise body adds
321
- new material conclusions or unresolved questions and the current turn's priorities;
322
- it does not restate settled context. PLAN is public, durable log content—not provider
323
- reasoning. Dispatch records it and has no other runtime effect.
394
+ §plan-value **PLAN carries one complete Plurnk Plan.** Its entries are the
395
+ model's current working-memory inventory: durable findings are `memory`, finished
396
+ actions are `completed`, open inquiries are `pending`, and active priorities are
397
+ `in_progress`. Admission parses the JSON body — one JSON array document in any whitespace layout, including the {§json-result-rendering} spread the log projects — and supplies the neutral `medium`
398
+ priority to each entry that omits it, and validates the canonical bare array:
399
+ every entry has string `content`, `priority` in
400
+ `high | medium | low`, and `status` in
401
+ `pending | in_progress | completed | memory`. A nonempty plain-text,
402
+ malformed-JSON, or otherwise invalid body becomes one `medium`, `in_progress`
403
+ entry whose content is the exact authored body; admission performs no partial
404
+ repair or list inference. An empty body becomes the planless `[]`
405
+ value. Each PLAN completely replaces the current Plan; it never expresses a
406
+ delta. The exact `turnOps` source remains forensic program evidence, while the
407
+ normalized array is the sole semantic value used by AST, persistence, durable
408
+ log bodies, and model-packet materialization. PLAN is public log content—not
409
+ provider reasoning—and Plurnk initially mints no `_meta` values. Dispatch records
410
+ the canonical value and has no other runtime effect.
411
+
412
+ §plan-acp-projection **Only an ACP-facing boundary projects the model-native
413
+ Plan.** It constructs ACP's `{ "entries": [...] }` Plan object from the internal
414
+ array, maps each `memory` entry to ACP `completed`, and prefixes its content with
415
+ exact "Memory: " framing without duplicating an existing prefix. Every other
416
+ entry field remains unchanged, and the internal value is not mutated.
417
+ The projected value validates against the separately owned ACP Plan schema pinned
418
+ to ACP v1
419
+ [`schema-v1.21.0`](https://github.com/agentclientprotocol/agent-client-protocol/tree/schema-v1.21.0)
420
+ commit `272bf799f35a258c6a4107a0410ed361e83683d3`.
324
421
 
325
422
  §log-tag-signal FIND, READ, EDIT, COPY, MOVE, and BARE canonically express additions
326
423
  as `+tag`. Because those operations have no tag-selection semantics, ANTLR also
@@ -329,11 +426,13 @@ strips any `+`; the signal neither filters nor modifies resources. OPEN and
329
426
  FOLD treat every unsigned `tag` as an ALL-tags selector, then add each `+tag`
330
427
  and remove each `-tag` from the selected log items. Signed terms never select,
331
428
  so either a target, matcher, or unsigned tag is required. Adding and removing
332
- the same tag conflicts. Neither curation operation exposes a positional scope.
429
+ the same tag conflicts. An optional OPEN/FOLD line scope changes visibility
430
+ inside every selected canonical log body; it does not participate in row selection.
333
431
 
334
432
  The `<scope>` slot is optional where admitted and its domain is OP-specific. FIND
335
433
  scopes ordered results. EXEC and SEND scope timing. READ, EDIT, COPY, and
336
- MOVE use one universal text algebra independent of mimetype:
434
+ MOVE use one universal text algebra independent of mimetype; OPEN/FOLD admit
435
+ only its one- and two-line forms for canonical log-body visibility:
337
436
 
338
437
  | Arity | Surface meaning | Endpoint rule |
339
438
  |---------------|---------------------------------------------------------------------|------------------------------------------------------|
@@ -401,7 +500,7 @@ Mutation semantics:
401
500
  | WORK | Spawn acknowledgement; the deliverable arrives through the log |
402
501
  | FORK | Spawn acknowledgement; the inherited worker's deliverable arrives through the log |
403
502
  | KILL | Status of deletion or termination |
404
- | PLAN | Status of durable intended-goals logging |
503
+ | PLAN | Status of durable complete-Plan logging |
405
504
 
406
505
  §find-result-unit For FIND, authored target shape fixes the paginated result
407
506
  unit. An exact target with a matcher pages flat match locations; a glob or
@@ -548,6 +647,7 @@ The operation column names the canonical AST operation after
548
647
  | EDIT | 0/1/2/4 text coordinates | Text replacement, deletion, prepend, or append |
549
648
  | COPY/MOVE source | 0/1/2/4 text coordinates | Region copied or moved from the selected source |
550
649
  | COPY/MOVE destination | 0/1/2/4 text coordinates after target | Region replaced or insertion point at the destination |
650
+ | OPEN / FOLD | 0/1/2 body-relative line coordinates | Whole log body when absent; one physical line or inclusive range when present |
551
651
  | EXEC | `timeout[,poll]` | Spawn lifetime bound and poll cadence in seconds |
552
652
  | Terminal SEND `[202]` | `timeout[,poll]` | Bounded or indefinite wait and optional poll cadence |
553
653
 
@@ -556,13 +656,15 @@ whole line, two integers are an inclusive whole-line range, and four integers
556
656
  are an exact start-inclusive/end-exclusive region. Mutation scopes additionally
557
657
  admit `0` as prepend and `-1` as append. A leading decimal on semantic FIND
558
658
  is a similarity threshold; any remaining integers select result positions. READ
559
- does not admit decimal scope components.
659
+ does not admit decimal scope components. OPEN/FOLD intersect a valid body-relative line
660
+ scope with each selected body; an absent line is a successful no-op for that
661
+ body, while unsupported arity is a runtime failure.
560
662
 
561
663
  §text-line-anchor-syntax A text coordinate admits a case-sensitive line anchor
562
664
  spelled `@` followed by exactly five Base62 characters (`0-9A-Za-z`) wherever
563
665
  its `L`, `SL`, or `EL` position denotes a line. Columns, prepend `0`, and append
564
- `-1` remain numeric. Exact READ, EDIT, COPY/MOVE source and destination, and
565
- client LOOK preserve these positions in `TextLineMarker`; core resolves them
666
+ `-1` remain numeric. Exact READ, EDIT, COPY/MOVE source and destination,
667
+ OPEN/FOLD, and client LOOK preserve these positions in `TextLineMarker`; core resolves them
566
668
  against the addressed current text before operation-specific numeric scope
567
669
  semantics run. A matcher-bearing or path-glob READ normalizes to FIND, whose
568
670
  result positions remain numeric and reject anchors. Numeric text scopes remain
@@ -577,27 +679,27 @@ shapes for runtime validation. An anchor-bearing text scope uses commas; ANTLR
577
679
  tolerates one space after each comma.
578
680
 
579
681
  Apart from the unadvertised three-coordinate text-scope tolerance in
580
- {§text-scope-semantics}, the runtime rejects invalid arity, out-of-range or
682
+ {§text-scope-semantics} and OPEN/FOLD's per-body empty intersection, the runtime rejects invalid arity, out-of-range or
581
683
  inverted positions, and decimal text coordinates rather than rounding or
582
684
  reinterpreting them. FIND owns a deterministic result order so the same
583
685
  inclusive range selects the same positions from unchanged state. The parser
584
686
  does not enforce either condition.
585
687
 
586
- ## §suffix-discipline 8. Suffix Discipline
688
+ ## §delimiter-discipline 8. Delimiter Discipline
587
689
 
588
- The suffix is a turn-wide heading lane. A heading carrying the active lane
690
+ The delimiter is a turn-wide heading lane. A heading carrying the active lane
589
691
  is structural; an otherwise valid PLURNK heading carrying another lane is body
590
692
  text. The lane therefore makes literal or nested PLURNK unambiguous.
591
693
 
592
- Suffix rules:
694
+ Delimiter rules:
593
695
 
594
- - `suffix` is `[A-Za-z0-9_]*`, concatenated to PLAN or OP with no separator.
696
+ - `delimiter` is `[A-Za-z0-9_]*`, concatenated to PLAN or OP with no separator.
595
697
  - The H1 PLAN establishes the lane; every real H2 operation heading in that
596
- turn has the exact same suffix.
597
- - An empty suffix is accepted only by ANTLR ingestion. Canonical teaching and
698
+ turn has the exact same delimiter.
699
+ - An empty delimiter is accepted only by ANTLR ingestion. Canonical teaching and
598
700
  the generated rail use `0` on PLAN and every operation.
599
- - A body may contain any heading whose suffix differs from the active lane.
600
- - To carry a nested turn written with lane `0`, choose another suffix for the
701
+ - A body may contain any heading whose delimiter differs from the active lane.
702
+ - To carry a nested turn written with lane `0`, choose another delimiter for the
601
703
  outer turn and repeat it on every outer heading.
602
704
  - The GBNF deliberately emits only lane `0`. It cannot emit body content that
603
705
  contains a same-lane structural heading; unconstrained producers use another
@@ -607,11 +709,11 @@ Example — a lane-0 turn stored inside a lane-2 EDIT body:
607
709
 
608
710
  ```plurnk
609
711
  # PLAN2
610
- Store the quoted turn.
712
+ [{"content":"Store the quoted turn.","status":"in_progress"}]
611
713
 
612
714
  ## EDIT2 (worker:///quoted.plurnk)
613
715
  # PLAN0
614
- Answer from memory.
716
+ [{"content":"Answer from memory.","status":"in_progress"}]
615
717
 
616
718
  ## SEND0 [200]
617
719
  Paris.
@@ -633,23 +735,22 @@ transfers directly:
633
735
  |-------|-----------------------------------------------------------------|-------------------------------|
634
736
  | `1xx` | Continue after submitted operations | `102 Processing` |
635
737
  | `2xx` | Conclude successfully or wait on live obligations | `200 OK`, `202 Accepted` |
636
- | `3xx` | Ask the interactive user a stop-the-world multiple choice | `300 Multiple Choices` |
637
738
  | `4xx` | Abandon the loop after a model-side inability | `499` |
638
739
  | `5xx` | Runtime or infrastructure failure; never a model terminal claim | none |
639
740
 
640
741
  ### §waitpid-dispositions The terminal contract (waitpid)
641
742
 
642
743
  The model signals one intention per turn — **continue (102)**, **done
643
- (200)**, **wait (202)**, or **give up (499)**, plus the operator-facing
644
- **question (300)** and the engine verifies the claim against the
645
- loop's live obligations (spawned children, open streams, pending
646
- retrievals); the grammar polices *shape* only. The shape rules ARE
647
- structural:
744
+ (200)**, **wait (202)**, or **give up (499)** and the engine verifies
745
+ the claim against the loop's live obligations (spawned children, open
746
+ streams, pending retrievals); the grammar polices *shape* only. Asking
747
+ the human is the native `question` EXEC tool ({§question-tool}), not a
748
+ disposition. The shape rules ARE structural:
648
749
 
649
- - §send-mid-reservation The five disposition codes `{102, 200, 202, 300, 499}` lex as a
750
+ - §send-mid-reservation The four disposition codes `{102, 200, 202, 499}` lex as a
650
751
  distinct `DISPOSITION` token, making a disposition-coded SEND
651
752
  **structurally terminal**: a statement after it is a parse error
652
- (the mid-termination rule), and the GBNF reserves the five from
753
+ (the mid-termination rule), and the GBNF reserves the four from
653
754
  mid-position SENDs (`status-mid` is their complement over `DDD`).
654
755
  This keeps the grammar's last-SEND model and the dispatcher's
655
756
  first-disposition model coincident.
@@ -700,6 +801,7 @@ stateDiagram-v2
700
801
  TARGET --> TARGET: balanced literals / target escapes
701
802
  TARGET --> SLOTS: target close at depth zero
702
803
  SLOTS --> SLOTS: scope token
804
+ SLOTS --> SLOTS: trailing annotation
703
805
  SLOTS --> BODY: heading line end
704
806
  BODY --> DEFAULT: same-lane heading boundary
705
807
  BODY --> [*]: end of input
@@ -707,13 +809,14 @@ stateDiagram-v2
707
809
 
708
810
  The first H1 PLAN establishes the turn lane. DEFAULT recognizes only an H1
709
811
  PLAN or H2 minted operation carrying that exact lane. SLOTS admits
710
- operation-appropriate signal, target, and scope openers in any order; the parser
711
- grammar enforces at-most-once multiplicity. Signal submodes select tags, integer,
812
+ operation-appropriate signal, target, and scope openers in any order, followed
813
+ by an optional annotation; the parser grammar enforces at-most-once multiplicity.
814
+ Signal submodes select tags, integer,
712
815
  or identifier tokens by operation family. TARGET preserves balanced inner
713
816
  parentheses and recognized target escapes. BODY emits opaque text until a
714
817
  same-lane heading boundary or EOF.
715
818
 
716
- A differently suffixed heading stays BODY text. Multi-turn logs are plain
819
+ A differently delimited heading stays BODY text. Multi-turn logs are plain
717
820
  sequences of independently lane-anchored PLAN turns. Complete native reasoning
718
821
  enclosures before PLAN remain one TEXT token so an operation drafted inside
719
822
  provider reasoning cannot become the turn anchor.
@@ -728,13 +831,15 @@ possible. EOF is a valid body boundary. An unfinished signal or target produces
728
831
  | Location | Canonical generation | Tolerant ANTLR ingestion |
729
832
  |-----------------------------|---------------------------------------|-----------------------------------------------------------|
730
833
  | Heading marker | `# PLAN0` or `## OP0` at column zero | The initial PLAN may directly follow leading TEXT; subsequent headings retain exact depth and column |
731
- | Between OP and suffix | Adjacent | Must remain adjacent |
834
+ | Between OP and delimiter | Adjacent | Must remain adjacent |
732
835
  | Before each header slot | One ASCII space | Zero or more horizontal whitespace characters |
733
836
  | Inside signal | Adjacent values | Horizontal whitespace is ignored; newline is invalid |
734
837
  | Inside target | Path alias plus target escapes | Balanced literals tolerated; newline is invalid |
735
838
  | Inside scope | Comma-separated numbers | Dash separator and one post-comma space are also accepted |
839
+ | Before annotation | One ASCII space | Zero or more horizontal whitespace characters |
840
+ | Inside annotation | One-line prose padded by one space | Any single-line text through the first closing `-->` |
736
841
  | Inside body | Character-perfect | Character-perfect |
737
- | Between canonical sections | One empty separator line | A directly following structural heading is also admitted |
842
+ | Between canonical sections | No empty separator line | One empty separator line is also admitted |
738
843
  | Before the first PLAN | Nothing | Whitespace or TEXT may surface as preamble items without requiring a separator before PLAN |
739
844
 
740
845
  PLURNK never escape-decodes body text: `\n` reaches the owning operation as
@@ -746,7 +851,8 @@ content emit an actual newline.
746
851
  break, and returns it as ordered text items without assigning semantics. Once
747
852
  a heading begins, all nonstructural text belongs to that section body.
748
853
  `parseStatements` and `parseClient` admit H2 statements;
749
- `parseLog` admits consecutive H1 PLAN turns. PLURNK defines no comment syntax.
854
+ `parseLog` admits consecutive H1 PLAN turns. PLURNK defines no general comment
855
+ syntax; only the trailing heading position gives `<!-- … -->` annotation meaning.
750
856
 
751
857
  ## §public-api 12. Public API
752
858
 
@@ -867,7 +973,7 @@ enforces both the schema and the relational endpoint invariants.
867
973
  ### §entry-read-result 13.3 Client entry reads
868
974
 
869
975
  `EntryReadResult` is the exact transport-neutral projection of one entry. It
870
- does not expose workspace IDs, storage owner IDs, split scheme/pathname fields,
976
+ does not expose workspace IDs, storage owner IDs, split persistence-coordinate fields,
871
977
  scope, or other persistence columns.
872
978
 
873
979
  | Outcome | Exact shape |
@@ -967,19 +1073,77 @@ model-language syntax or model packet teaching.
967
1073
 
968
1074
  ### §mcp-server-definition 13.8 MCP server definitions
969
1075
 
970
- `McpServerDefinition` is the transport-neutral, client/daemon-shared definition
971
- of one workspace MCP server. It is a closed `stdio`/`http` union. The schema
1076
+ `McpServerDefinition` is the transport-neutral normalized definition of one
1077
+ workspace MCP server. It is a closed `stdio`/`http` union. The schema
972
1078
  owns transport-specific fields, enabled/read tool sets, supported HTTP
973
1079
  authorization choices, and symbolic credential references; it carries no
974
1080
  workspace identifier, connection state, discovered catalog, or secret value.
975
- `Validator.assertMcpServerDefinition` is the admission boundary used by every
976
- client interface and the MCP host before persistence or connection work.
1081
+ `Validator.assertMcpServerDefinition` is the MCP host's admission boundary
1082
+ before persistence or connection work.
1083
+
1084
+ §mcp-server-options `McpServerOptions` is the closed client/daemon-shared
1085
+ supplement accepted when adding an MCP server by alias and target. It reuses
1086
+ only `McpServerDefinition` option fields and cannot repeat identity, target, or
1087
+ transport. The target determines the transport; normalization through
1088
+ `McpServerDefinition` rejects options belonging to the other transport.
977
1089
 
978
1090
  Interactive OAuth always requires a callback URL. Its structurally exclusive
979
1091
  identity modes are an HTTPS Client ID Metadata Document URL, a pre-registered
980
1092
  client ID plus symbolic secret, or neither for server-advertised Dynamic Client
981
1093
  Registration fallback. A definition cannot combine those identity modes.
982
1094
 
1095
+ §mcp-configuration-overlay `McpConfigurationOverlay` is the bounded raw
1096
+ configuration projection a client may carry to MCP list and enable actions. It
1097
+ contains only string-valued `PLURNK_MCP_*` server declaration variables;
1098
+ service-owned connection/request timeouts and default enabledness are excluded.
1099
+ The client does not interpret this map. The MCP host composes it over the
1100
+ lower normalized definition through the same parser that admits service
1101
+ environment declarations, then validates the resulting
1102
+ `McpServerDefinition`. Carrying the overlay does not connect, persist, or
1103
+ expand credentials by itself.
1104
+
1105
+ `SkillDefinition` is the one definition the Worker `skills` Functionality
1106
+ family accepts and persists: the standard Agent Skills `name` (the directory
1107
+ name), the universal root `scope` (`project` or `global`), and — for a
1108
+ Worker-installed skill — the standard installer package `source` that
1109
+ provides it. `Validator.assertSkillDefinition` is the family's admission
1110
+ boundary; the filesystem under the scope's root, never the definition, is the
1111
+ truth about installation.
1112
+
1113
+ `A2aAgentDefinition` is the one definition the Worker `a2a` Functionality
1114
+ family accepts and persists: the local alias `name` (the `a2a://<name>`
1115
+ authority), the remote `url` whose standard Agent Card remains the protocol
1116
+ authority, and optional local `cardPath`, `headers`, and bearer
1117
+ `authorization` whose token is a symbolic `${NAME}` reference.
1118
+ `Validator.assertA2aAgentDefinition` is the family's admission boundary.
1119
+
1120
+ ### §application-port 13.9 Exterior application port
1121
+
1122
+ `ApplicationPort` is the single transport-neutral TypeScript contract through
1123
+ which an exterior adapter drives and observes the Plurnk application. Core
1124
+ implements it; AG-UI, A2A, and other interface modules consume it. The port
1125
+ contains typed application calls and a scoped event subscription, not wire
1126
+ route names, protocol framing, persistence access, or adapter-specific methods.
1127
+ An exterior adapter owns its own protocol validation, identity binding, and
1128
+ projection while reusing the same workspace, worker, loop, operation, proposal,
1129
+ interaction, and event owners through this port.
1130
+
1131
+ `runLoop.source` is trusted causal provenance supplied by an adapter, distinct
1132
+ from user-authored prompt content. An adapter may expose no public means to set
1133
+ it; Core validates and records it through the same prompt admission path.
1134
+
1135
+ §application-worker-observation Worker observation exposes durable identity,
1136
+ origin, and immediate parent identity. `readWorker` resolves exactly one id or
1137
+ name and returns `null` when absent. `listWorkers` filters collections by origin
1138
+ or lineage position; an omitted parent filter means every position and an
1139
+ explicit `null` means roots. Singular and plural cardinalities are distinct
1140
+ contracts. Observation is not a client binding or permission grant.
1141
+
1142
+ §application-loop-observation Loop observation exposes the durable scheduler
1143
+ state and exact terminal `OperationResult` for one owned Worker. Exterior
1144
+ adapters consume this projection instead of reconstructing lifecycle from
1145
+ events or persistence; events remain the live notification edge.
1146
+
983
1147
  ## 14. Parse diagnostics
984
1148
 
985
1149
  §parse-diagnostics `PlurnkParseError` is a JSON-serializable Error subclass.