@plurnk/plurnk-contracts 1.6.1 → 1.8.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 (51) hide show
  1. package/SPEC.md +133 -48
  2. package/dist/plurnk.gemma.gbnf +26 -22
  3. package/dist/plurnk.qwen.gbnf +26 -22
  4. package/dist/schema/ClientInteractionProjection.json +16 -0
  5. package/dist/schema/ClientInteractionRequest.json +15 -0
  6. package/dist/schema/ClientInteractionResolution.json +25 -0
  7. package/dist/schema/ClientStatement.json +9 -4
  8. package/dist/schema/McpConfigurationOverlay.json +25 -0
  9. package/dist/schema/McpServerDefinition.json +155 -0
  10. package/dist/schema/McpServerOptions.json +36 -0
  11. package/dist/schema/ModelCatalogPage.json +122 -0
  12. package/dist/schema/ModelCatalogQuery.json +32 -0
  13. package/dist/schema/ModelReadiness.json +47 -0
  14. package/dist/schema/ModelRoute.json +23 -0
  15. package/dist/schema/PlurnkStatement.json +48 -31
  16. package/dist/schema/ReasoningPolicy.json +7 -0
  17. package/dist/src/AstBuilder.d.ts.map +1 -1
  18. package/dist/src/AstBuilder.js +42 -21
  19. package/dist/src/AstBuilder.js.map +1 -1
  20. package/dist/src/PlurnkErrorStrategy.js +16 -16
  21. package/dist/src/PlurnkErrorStrategy.js.map +1 -1
  22. package/dist/src/PlurnkParser.js +3 -3
  23. package/dist/src/PlurnkParser.js.map +1 -1
  24. package/dist/src/Validator.d.ts +45 -1
  25. package/dist/src/Validator.d.ts.map +1 -1
  26. package/dist/src/Validator.js +193 -0
  27. package/dist/src/Validator.js.map +1 -1
  28. package/dist/src/generated/plurnkLexer.d.ts +30 -28
  29. package/dist/src/generated/plurnkLexer.d.ts.map +1 -1
  30. package/dist/src/generated/plurnkLexer.js +398 -381
  31. package/dist/src/generated/plurnkLexer.js.map +1 -1
  32. package/dist/src/generated/plurnkParser.d.ts +56 -39
  33. package/dist/src/generated/plurnkParser.d.ts.map +1 -1
  34. package/dist/src/generated/plurnkParser.js +644 -450
  35. package/dist/src/generated/plurnkParser.js.map +1 -1
  36. package/dist/src/generated/plurnkParserVisitor.d.ts +7 -7
  37. package/dist/src/generated/plurnkParserVisitor.d.ts.map +1 -1
  38. package/dist/src/generated/plurnkParserVisitor.js +6 -6
  39. package/dist/src/generated/plurnkParserVisitor.js.map +1 -1
  40. package/dist/src/index.d.ts +2 -2
  41. package/dist/src/index.d.ts.map +1 -1
  42. package/dist/src/index.js +2 -2
  43. package/dist/src/index.js.map +1 -1
  44. package/dist/src/types.d.ts +2 -1
  45. package/dist/src/types.d.ts.map +1 -1
  46. package/dist/src/types.generated.d.ts +214 -19
  47. package/dist/src/types.generated.d.ts.map +1 -1
  48. package/dist/src/types.js +4 -0
  49. package/dist/src/types.js.map +1 -1
  50. package/package.json +2 -3
  51. package/plurnk.md +91 -110
package/SPEC.md CHANGED
@@ -10,8 +10,12 @@ 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` |
16
+ | Client-owned interaction contract | `ClientInteractionRequest`, `ClientInteractionProjection`, `ClientInteractionResolution` |
14
17
  | Client capability presentation | `ClientDisplayCapabilities` |
18
+ | Workspace MCP configuration | `McpServerDefinition`, `McpServerOptions`, `McpConfigurationOverlay` |
15
19
  | JSON Schemas | `@plurnk/plurnk-contracts/schema/*.json` |
16
20
  | Generated JSON result rendering | `renderJsonResult` |
17
21
  | Local-model rails | `@plurnk/plurnk-contracts/plurnk.{gemma,qwen}.gbnf` |
@@ -61,7 +65,7 @@ flowchart LR
61
65
  | Shared wire data | `schema/*.json` | Defines runtime-neutral data shapes projected into generated TypeScript |
62
66
  | Stateful behavior | consuming runtime | Resolves addresses, permissions, selection arithmetic, effects, and lifecycle |
63
67
 
64
- ANTLR owns statement structure, suffix matching, slot multiplicity, accepted
68
+ ANTLR owns statement structure, delimiter matching, slot multiplicity, accepted
65
69
  slot permutations, scope-number syntax, and interstatement text recognition.
66
70
  AstBuilder owns URL decomposition and deterministic matcher validation through
67
71
  WHATWG `URL`, ECMAScript `RegExp`, XPath 1.0, and RFC 9535 JSONPath parsers.
@@ -87,6 +91,35 @@ The schemas own the runtime-neutral shapes; core owns their stateful values.
87
91
 
88
92
  `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.
89
93
 
94
+ §reasoning-policy-wire `ReasoningPolicy` is exactly `off | adaptive | low |
95
+ medium | high`. The schema owns this shared wire vocabulary. Providers own the
96
+ supported subset and native projection for a selected route; core owns the
97
+ durable worker value.
98
+
99
+ §model-catalog-wire `ModelRoute` is one exact client-visible provider/model
100
+ identity with optional alias provenance. Provider credentials, endpoints, and
101
+ tuning never enter this wire shape. Catalog discovery uses a
102
+ closed bounded query and page: entries carry exact selectors, display facts,
103
+ physical limits, capabilities, and local `ModelReadiness`. A readiness cause
104
+ contains alternative environment-variable sets—every name within a set is
105
+ required and any set may satisfy the cause. It carries names only, never values,
106
+ and asserts neither credential validity nor endpoint reachability.
107
+
108
+ ### §client-interaction-wire Client-owned interaction wire
109
+
110
+ The closed client-interaction schemas describe one operation asking its client
111
+ for structured input without transferring private protocol continuation state.
112
+
113
+ | Contract | Shape invariant |
114
+ |---|---|
115
+ | `ClientInteractionRequest` | Non-empty `toolName`, object `arguments`, optional non-empty `message`, and object `responseSchema` |
116
+ | `ClientInteractionProjection` | Positive interaction, worker, loop, and turn identities plus the exact request; workspace scope remains the containing transport envelope |
117
+ | `ClientInteractionResolution` | Exactly `{ status: "resolved", payload? }` or `{ status: "cancelled" }` |
118
+
119
+ Opaque upstream request identities, retry state, credentials, and callbacks are
120
+ not members of these schemas. The operation owner retains and interprets those
121
+ facts; core and client interfaces carry only this standard interaction.
122
+
90
123
  §provider-usage `ProviderUsage` records only known non-negative safe-integer
91
124
  quantities. `inputTokens` includes every input category; cache reads and cache
92
125
  writes are details within it. `outputTokens` includes reasoning; text and
@@ -186,14 +219,14 @@ response roots plus the parser/AstBuilder result.
186
219
 
187
220
  §rail-heading-boundaries On the GBNF rail, PLAN and every operation use lane `0`.
188
221
  Every reserved PLAN or operation heading stem is structural, regardless of the
189
- suffix a model attempts next, so a non-`0` pseudo-heading cannot be swallowed as
222
+ delimiter a model attempts next, so a non-`0` pseudo-heading cannot be swallowed as
190
223
  literal body text. Rail bodies therefore cannot quote reserved headings from any
191
- lane. This makes both the canonical suffix and section boundary structurally
224
+ lane. This makes both the canonical delimiter and section boundary structurally
192
225
  available during constrained generation; ANTLR remains the wider language and
193
226
  accepts intentional alternate-lane literals during ingestion.
194
227
 
195
228
  §gbnf-curation-shaping The rail admits OPEN/FOLD curation terms, a canonical
196
- `log:` target, and a matcher independently. It accepts any ordered mixture of
229
+ `log:` target, an optional log-body line scope, and a matcher independently. It accepts any ordered mixture of
197
230
  unsigned, `+`, and `-` terms without proving that the combination selects a log
198
231
  item; ANTLR and AstBuilder own that condition, while runtime owns wider ingested
199
232
  target resolution.
@@ -201,32 +234,33 @@ target resolution.
201
234
  ## §canonical-statement 2. Canonical statement form
202
235
 
203
236
  ```text
204
- # PLANsuffix
237
+ # PLANdelimiter
205
238
  body
206
239
 
207
- ## OPsuffix [signal]? (path)? <scope>?
240
+ ## OPdelimiter [signal]? (path)? <scope>? <!-- annotation -->?
208
241
  body?
209
242
  ```
210
243
 
211
244
  §section-boundary A statement is one Markdown section. PLAN alone uses a level-one
212
245
  heading; every other operation uses a level-two heading. Its body is the
213
246
  character-perfect section content before the next structural heading or EOF.
214
- Canonical adjacent sections have one blank separator line. That final separator
215
- line is syntax and is not body content; any additional preceding blank lines
216
- remain body content. The tolerant ingester also admits a structural heading on
217
- the immediately following line.
247
+ Canonical adjacent sections place the next structural heading on the immediately
248
+ following line. The tolerant ingester also admits one empty separator line; that
249
+ separator is syntax rather than body content, while any additional preceding
250
+ blank lines remain body content.
218
251
 
219
- §empty-section An empty section has no body lines between its heading and the
220
- section separator (or EOF) and normalizes to a null body.
252
+ §empty-section An empty section has no body lines between its heading and the next
253
+ structural heading, tolerated separator, or EOF and normalizes to a null body.
221
254
 
222
255
  | Element | Canonical contract |
223
256
  |--------------|---------------------------------------------------------------------------|
224
257
  | `# PLAN` | Required level-one turn anchor |
225
258
  | `## OP` | Level-two protocol operation |
226
- | `suffix` | Heading lane, joined directly to PLAN or OP |
259
+ | `delimiter` | Heading lane, joined directly to PLAN or OP |
227
260
  | `[signal]` | Optional operation-specific signal, preceded by one space |
228
261
  | `(path)` | Optional target slot, preceded by one space |
229
262
  | `<scope>` | Optional numeric scope, preceded by one space |
263
+ | `<!-- … -->` | Optional trailing operation annotation, preceded by one space |
230
264
  | line ending | Ends the single-line heading |
231
265
  | `body` | Zero or more characters of operation-specific, character-perfect content |
232
266
  | blank line | Canonical section separator; excluded from the preceding body |
@@ -234,21 +268,31 @@ section separator (or EOF) and normalizes to a null body.
234
268
  The following constraints are structural:
235
269
 
236
270
  - §lane-match PLAN establishes one lane for the turn. A heading is structural
237
- only when its suffix character-matches that lane; a different suffix remains
271
+ only when its delimiter character-matches that lane; a different delimiter remains
238
272
  ordinary body text.
239
273
  - PLAN is the only H1 operation and every non-PLAN operation is H2.
240
274
  - A header occupies one physical line.
241
275
  - Each admitted signal, target, and scope slot appears at most once.
242
- - OPEN, FOLD, BARE, WORK, FORK, and KILL do not admit a scope slot.
243
- - An ingested suffix is `[A-Za-z0-9_]*`; canonical teaching and the GBNF use `0`.
276
+ - An annotation follows every present modifier and appears at most once.
277
+ - BARE, WORK, FORK, and KILL do not admit a scope slot.
278
+ - An ingested delimiter is `[A-Za-z0-9_]*`; canonical teaching and the GBNF use `0`.
244
279
 
245
280
  §slot-order Canonical producers and the GBNF rail emit signal, then target, then
246
- scope, with one ASCII space before every present slot. Slot delimiters make
281
+ scope, then annotation, with one ASCII space before every present slot. Slot delimiters make
247
282
  their boundaries unambiguous, so the tolerant ANTLR ingester accepts zero or
248
283
  more horizontal whitespace characters before each slot and any permutation of
249
284
  the slots admitted by that operation, at most once each. Accepted spacing and
250
285
  permutation are not second canonical spellings.
251
286
 
287
+ §operation-annotation A heading may end with one single-line Markdown HTML
288
+ comment. AstBuilder strips the delimiters and surrounding horizontal whitespace
289
+ into the statement's fixed `annotation: string | null` field. The annotation is
290
+ durable, model- and client-facing descriptive text but semantically inert: it
291
+ does not alter operation identity, signal, target, scope, dispatch, effect,
292
+ authorization, status, or body. An empty comment normalizes to the empty string.
293
+ Text containing a newline or lacking the closing `-->` is not an annotation;
294
+ `<!--` elsewhere remains ordinary body text.
295
+
252
296
  The ingester also accepts several bounded noncanonical forms so it can explain
253
297
  or safely execute understandable input:
254
298
 
@@ -266,10 +310,11 @@ or safely execute understandable input:
266
310
  | Element | Accepted shape or role |
267
311
  |-------------|--------------------------------------------------------------------|
268
312
  | `OP` | `FIND READ EDIT COPY MOVE OPEN FOLD SEND EXEC BARE WORK FORK KILL PLAN` |
269
- | `suffix` | `[A-Za-z0-9_]*`, adjacent to PLAN or OP |
313
+ | `delimiter` | `[A-Za-z0-9_]*`, adjacent to PLAN or OP |
270
314
  | `[signal]` | Operation-specific tags, identifier, branch, or integer |
271
315
  | `(path)` | Local path or scheme URL target; detailed in §5 |
272
316
  | `<scope>` | One or more signed integers or decimals; detailed in §7 |
317
+ | annotation | Optional trailing `<!-- … -->` descriptive text |
273
318
  | `body` | Opaque section text before the next same-lane heading or EOF |
274
319
 
275
320
  ## §op-shapes 4. Per-operation semantics
@@ -285,8 +330,8 @@ governed by {§canonical-statement}; runtime conditions remain explicit below.
285
330
  | EDIT | optional add log tags | required file or entry | required for an existing target | literal text |
286
331
  | COPY | optional add log tags | required source | optional source region | required destination selection |
287
332
  | MOVE | optional add log tags | required source | optional source region | required destination selection |
288
- | FOLD | optional filter/change tags | optional log selection | none | optional matcher |
289
- | OPEN | optional filter/change tags | optional log selection | none | optional matcher |
333
+ | FOLD | optional filter/change tags | optional log selection | optional log-body line scope | optional matcher |
334
+ | OPEN | optional filter/change tags | optional log selection | optional log-body line scope | optional matcher |
290
335
  | EXEC | optional executor | optional local working path | optional timeout, poll | optional executor input |
291
336
  | BARE | optional add log tags | none | none | required prompt |
292
337
  | WORK | optional Git branch | required fresh `worker://name` | none | required prompt |
@@ -312,11 +357,13 @@ strips any `+`; the signal neither filters nor modifies resources. OPEN and
312
357
  FOLD treat every unsigned `tag` as an ALL-tags selector, then add each `+tag`
313
358
  and remove each `-tag` from the selected log items. Signed terms never select,
314
359
  so either a target, matcher, or unsigned tag is required. Adding and removing
315
- the same tag conflicts. Neither curation operation exposes a positional scope.
360
+ the same tag conflicts. An optional OPEN/FOLD line scope changes visibility
361
+ inside every selected canonical log body; it does not participate in row selection.
316
362
 
317
363
  The `<scope>` slot is optional where admitted and its domain is OP-specific. FIND
318
364
  scopes ordered results. EXEC and SEND scope timing. READ, EDIT, COPY, and
319
- MOVE use one universal text algebra independent of mimetype:
365
+ MOVE use one universal text algebra independent of mimetype; OPEN/FOLD admit
366
+ only its one- and two-line forms for canonical log-body visibility:
320
367
 
321
368
  | Arity | Surface meaning | Endpoint rule |
322
369
  |---------------|---------------------------------------------------------------------|------------------------------------------------------|
@@ -531,6 +578,7 @@ The operation column names the canonical AST operation after
531
578
  | EDIT | 0/1/2/4 text coordinates | Text replacement, deletion, prepend, or append |
532
579
  | COPY/MOVE source | 0/1/2/4 text coordinates | Region copied or moved from the selected source |
533
580
  | COPY/MOVE destination | 0/1/2/4 text coordinates after target | Region replaced or insertion point at the destination |
581
+ | OPEN / FOLD | 0/1/2 body-relative line coordinates | Whole log body when absent; one physical line or inclusive range when present |
534
582
  | EXEC | `timeout[,poll]` | Spawn lifetime bound and poll cadence in seconds |
535
583
  | Terminal SEND `[202]` | `timeout[,poll]` | Bounded or indefinite wait and optional poll cadence |
536
584
 
@@ -539,13 +587,15 @@ whole line, two integers are an inclusive whole-line range, and four integers
539
587
  are an exact start-inclusive/end-exclusive region. Mutation scopes additionally
540
588
  admit `0` as prepend and `-1` as append. A leading decimal on semantic FIND
541
589
  is a similarity threshold; any remaining integers select result positions. READ
542
- does not admit decimal scope components.
590
+ does not admit decimal scope components. OPEN/FOLD intersect a valid body-relative line
591
+ scope with each selected body; an absent line is a successful no-op for that
592
+ body, while unsupported arity is a runtime failure.
543
593
 
544
594
  §text-line-anchor-syntax A text coordinate admits a case-sensitive line anchor
545
595
  spelled `@` followed by exactly five Base62 characters (`0-9A-Za-z`) wherever
546
596
  its `L`, `SL`, or `EL` position denotes a line. Columns, prepend `0`, and append
547
- `-1` remain numeric. Exact READ, EDIT, COPY/MOVE source and destination, and
548
- client LOOK preserve these positions in `TextLineMarker`; core resolves them
597
+ `-1` remain numeric. Exact READ, EDIT, COPY/MOVE source and destination,
598
+ OPEN/FOLD, and client LOOK preserve these positions in `TextLineMarker`; core resolves them
549
599
  against the addressed current text before operation-specific numeric scope
550
600
  semantics run. A matcher-bearing or path-glob READ normalizes to FIND, whose
551
601
  result positions remain numeric and reject anchors. Numeric text scopes remain
@@ -560,27 +610,27 @@ shapes for runtime validation. An anchor-bearing text scope uses commas; ANTLR
560
610
  tolerates one space after each comma.
561
611
 
562
612
  Apart from the unadvertised three-coordinate text-scope tolerance in
563
- {§text-scope-semantics}, the runtime rejects invalid arity, out-of-range or
613
+ {§text-scope-semantics} and OPEN/FOLD's per-body empty intersection, the runtime rejects invalid arity, out-of-range or
564
614
  inverted positions, and decimal text coordinates rather than rounding or
565
615
  reinterpreting them. FIND owns a deterministic result order so the same
566
616
  inclusive range selects the same positions from unchanged state. The parser
567
617
  does not enforce either condition.
568
618
 
569
- ## §suffix-discipline 8. Suffix Discipline
619
+ ## §delimiter-discipline 8. Delimiter Discipline
570
620
 
571
- The suffix is a turn-wide heading lane. A heading carrying the active lane
621
+ The delimiter is a turn-wide heading lane. A heading carrying the active lane
572
622
  is structural; an otherwise valid PLURNK heading carrying another lane is body
573
623
  text. The lane therefore makes literal or nested PLURNK unambiguous.
574
624
 
575
- Suffix rules:
625
+ Delimiter rules:
576
626
 
577
- - `suffix` is `[A-Za-z0-9_]*`, concatenated to PLAN or OP with no separator.
627
+ - `delimiter` is `[A-Za-z0-9_]*`, concatenated to PLAN or OP with no separator.
578
628
  - The H1 PLAN establishes the lane; every real H2 operation heading in that
579
- turn has the exact same suffix.
580
- - An empty suffix is accepted only by ANTLR ingestion. Canonical teaching and
629
+ turn has the exact same delimiter.
630
+ - An empty delimiter is accepted only by ANTLR ingestion. Canonical teaching and
581
631
  the generated rail use `0` on PLAN and every operation.
582
- - A body may contain any heading whose suffix differs from the active lane.
583
- - To carry a nested turn written with lane `0`, choose another suffix for the
632
+ - A body may contain any heading whose delimiter differs from the active lane.
633
+ - To carry a nested turn written with lane `0`, choose another delimiter for the
584
634
  outer turn and repeat it on every outer heading.
585
635
  - The GBNF deliberately emits only lane `0`. It cannot emit body content that
586
636
  contains a same-lane structural heading; unconstrained producers use another
@@ -616,23 +666,22 @@ transfers directly:
616
666
  |-------|-----------------------------------------------------------------|-------------------------------|
617
667
  | `1xx` | Continue after submitted operations | `102 Processing` |
618
668
  | `2xx` | Conclude successfully or wait on live obligations | `200 OK`, `202 Accepted` |
619
- | `3xx` | Ask the interactive user a stop-the-world multiple choice | `300 Multiple Choices` |
620
669
  | `4xx` | Abandon the loop after a model-side inability | `499` |
621
670
  | `5xx` | Runtime or infrastructure failure; never a model terminal claim | none |
622
671
 
623
672
  ### §waitpid-dispositions The terminal contract (waitpid)
624
673
 
625
674
  The model signals one intention per turn — **continue (102)**, **done
626
- (200)**, **wait (202)**, or **give up (499)**, plus the operator-facing
627
- **question (300)** and the engine verifies the claim against the
628
- loop's live obligations (spawned children, open streams, pending
629
- retrievals); the grammar polices *shape* only. The shape rules ARE
630
- structural:
675
+ (200)**, **wait (202)**, or **give up (499)** and the engine verifies
676
+ the claim against the loop's live obligations (spawned children, open
677
+ streams, pending retrievals); the grammar polices *shape* only. Asking
678
+ the human is the native `question` EXEC tool ({§question-tool}), not a
679
+ disposition. The shape rules ARE structural:
631
680
 
632
- - §send-mid-reservation The five disposition codes `{102, 200, 202, 300, 499}` lex as a
681
+ - §send-mid-reservation The four disposition codes `{102, 200, 202, 499}` lex as a
633
682
  distinct `DISPOSITION` token, making a disposition-coded SEND
634
683
  **structurally terminal**: a statement after it is a parse error
635
- (the mid-termination rule), and the GBNF reserves the five from
684
+ (the mid-termination rule), and the GBNF reserves the four from
636
685
  mid-position SENDs (`status-mid` is their complement over `DDD`).
637
686
  This keeps the grammar's last-SEND model and the dispatcher's
638
687
  first-disposition model coincident.
@@ -683,6 +732,7 @@ stateDiagram-v2
683
732
  TARGET --> TARGET: balanced literals / target escapes
684
733
  TARGET --> SLOTS: target close at depth zero
685
734
  SLOTS --> SLOTS: scope token
735
+ SLOTS --> SLOTS: trailing annotation
686
736
  SLOTS --> BODY: heading line end
687
737
  BODY --> DEFAULT: same-lane heading boundary
688
738
  BODY --> [*]: end of input
@@ -690,13 +740,14 @@ stateDiagram-v2
690
740
 
691
741
  The first H1 PLAN establishes the turn lane. DEFAULT recognizes only an H1
692
742
  PLAN or H2 minted operation carrying that exact lane. SLOTS admits
693
- operation-appropriate signal, target, and scope openers in any order; the parser
694
- grammar enforces at-most-once multiplicity. Signal submodes select tags, integer,
743
+ operation-appropriate signal, target, and scope openers in any order, followed
744
+ by an optional annotation; the parser grammar enforces at-most-once multiplicity.
745
+ Signal submodes select tags, integer,
695
746
  or identifier tokens by operation family. TARGET preserves balanced inner
696
747
  parentheses and recognized target escapes. BODY emits opaque text until a
697
748
  same-lane heading boundary or EOF.
698
749
 
699
- A differently suffixed heading stays BODY text. Multi-turn logs are plain
750
+ A differently delimited heading stays BODY text. Multi-turn logs are plain
700
751
  sequences of independently lane-anchored PLAN turns. Complete native reasoning
701
752
  enclosures before PLAN remain one TEXT token so an operation drafted inside
702
753
  provider reasoning cannot become the turn anchor.
@@ -711,13 +762,15 @@ possible. EOF is a valid body boundary. An unfinished signal or target produces
711
762
  | Location | Canonical generation | Tolerant ANTLR ingestion |
712
763
  |-----------------------------|---------------------------------------|-----------------------------------------------------------|
713
764
  | Heading marker | `# PLAN0` or `## OP0` at column zero | The initial PLAN may directly follow leading TEXT; subsequent headings retain exact depth and column |
714
- | Between OP and suffix | Adjacent | Must remain adjacent |
765
+ | Between OP and delimiter | Adjacent | Must remain adjacent |
715
766
  | Before each header slot | One ASCII space | Zero or more horizontal whitespace characters |
716
767
  | Inside signal | Adjacent values | Horizontal whitespace is ignored; newline is invalid |
717
768
  | Inside target | Path alias plus target escapes | Balanced literals tolerated; newline is invalid |
718
769
  | Inside scope | Comma-separated numbers | Dash separator and one post-comma space are also accepted |
770
+ | Before annotation | One ASCII space | Zero or more horizontal whitespace characters |
771
+ | Inside annotation | One-line prose padded by one space | Any single-line text through the first closing `-->` |
719
772
  | Inside body | Character-perfect | Character-perfect |
720
- | Between canonical sections | One empty separator line | A directly following structural heading is also admitted |
773
+ | Between canonical sections | No empty separator line | One empty separator line is also admitted |
721
774
  | Before the first PLAN | Nothing | Whitespace or TEXT may surface as preamble items without requiring a separator before PLAN |
722
775
 
723
776
  PLURNK never escape-decodes body text: `\n` reaches the owning operation as
@@ -729,7 +782,8 @@ content emit an actual newline.
729
782
  break, and returns it as ordered text items without assigning semantics. Once
730
783
  a heading begins, all nonstructural text belongs to that section body.
731
784
  `parseStatements` and `parseClient` admit H2 statements;
732
- `parseLog` admits consecutive H1 PLAN turns. PLURNK defines no comment syntax.
785
+ `parseLog` admits consecutive H1 PLAN turns. PLURNK defines no general comment
786
+ syntax; only the trailing heading position gives `<!-- … -->` annotation meaning.
733
787
 
734
788
  ## §public-api 12. Public API
735
789
 
@@ -948,6 +1002,37 @@ and identity fallback when `glyph` is absent. Empty framework sentinels are
948
1002
  normalized to absence at composition. Display metadata is client state, never
949
1003
  model-language syntax or model packet teaching.
950
1004
 
1005
+ ### §mcp-server-definition 13.8 MCP server definitions
1006
+
1007
+ `McpServerDefinition` is the transport-neutral normalized definition of one
1008
+ workspace MCP server. It is a closed `stdio`/`http` union. The schema
1009
+ owns transport-specific fields, enabled/read tool sets, supported HTTP
1010
+ authorization choices, and symbolic credential references; it carries no
1011
+ workspace identifier, connection state, discovered catalog, or secret value.
1012
+ `Validator.assertMcpServerDefinition` is the MCP host's admission boundary
1013
+ before persistence or connection work.
1014
+
1015
+ §mcp-server-options `McpServerOptions` is the closed client/daemon-shared
1016
+ supplement accepted when adding an MCP server by alias and target. It reuses
1017
+ only `McpServerDefinition` option fields and cannot repeat identity, target, or
1018
+ transport. The target determines the transport; normalization through
1019
+ `McpServerDefinition` rejects options belonging to the other transport.
1020
+
1021
+ Interactive OAuth always requires a callback URL. Its structurally exclusive
1022
+ identity modes are an HTTPS Client ID Metadata Document URL, a pre-registered
1023
+ client ID plus symbolic secret, or neither for server-advertised Dynamic Client
1024
+ Registration fallback. A definition cannot combine those identity modes.
1025
+
1026
+ §mcp-configuration-overlay `McpConfigurationOverlay` is the bounded raw
1027
+ configuration projection a client may carry to MCP list and enable actions. It
1028
+ contains only string-valued `PLURNK_MCP_*` server declaration variables;
1029
+ service-owned connection/request timeouts and default enabledness are excluded.
1030
+ The client does not interpret this map. The MCP host composes it over the
1031
+ lower normalized definition through the same parser that admits service
1032
+ environment declarations, then validates the resulting
1033
+ `McpServerDefinition`. Carrying the overlay does not connect, persist, or
1034
+ expand credentials by itself.
1035
+
951
1036
  ## 14. Parse diagnostics
952
1037
 
953
1038
  §parse-diagnostics `PlurnkParseError` is a JSON-serializable Error subclass.
@@ -45,29 +45,32 @@ section-body-b40 ::= ("#" section-body-b1 | [ PLANFDRETCOYMVSXBWK] section-body-
45
45
  section-body-b41 ::= ("#" section-body-b1 | [ PANFIDRETCOYMVSXBWK] section-body-b0 | "L" section-body-b42 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F# PLANFIDRETCOYMVSXBWK] section-body-b0)?
46
46
  section-body-b42 ::= ("#" section-body-b1 | [ PANFIDRETCOYMVSXBWK] section-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F# PLANFIDRETCOYMVSXBWK] section-body-b0)?
47
47
  section-body-ne ::= "#" section-body-b1 | [ PLANFIDRETCOYMVSXBWK] section-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F# PLANFIDRETCOYMVSXBWK] section-body-b0
48
+ annotation-body-b0 ::= ("-" annotation-body-b1 | ">" annotation-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0)?
49
+ annotation-body-b1 ::= ("-" annotation-body-b2 | ">" annotation-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0)?
50
+ annotation-body-b2 ::= ("-" annotation-body-b2 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0)?
51
+ annotation-body-ne ::= "-" annotation-body-b1 | ">" annotation-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0
48
52
  pattern-body-ne ::= [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r:#] [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r]*
49
53
  log-selection ::= (curation-tags-slot log-target-slot? | log-target-slot)?
50
- plan ::= "# PLAN0" "\n" section-body-ne "\n\n"
51
- find ::= "## FIND0" add-tags-slot? target-slot line-slot? "\n\n" | "## FIND0" add-tags-slot? target-slot line-slot? "\n" pattern-body-ne "\n\n"
52
- read ::= "## READ0" add-tags-slot? target-slot text-line-slot? "\n\n" | "## READ0" add-tags-slot? target-slot text-line-slot? "\n" pattern-body-ne "\n\n"
53
- edit ::= "## EDIT0" add-tags-slot? target-slot text-line-slot? "\n\n" | "## EDIT0" add-tags-slot? target-slot text-line-slot? "\n" section-body-ne "\n\n"
54
- copy ::= "## COPY0" add-tags-slot? target-slot text-line-slot? "\n" section-body-ne "\n\n"
55
- move ::= "## MOVE0" add-tags-slot? target-slot text-line-slot? "\n" section-body-ne "\n\n"
56
- open ::= "## OPEN0" log-selection "\n\n" | "## OPEN0" log-selection "\n" pattern-body-ne "\n\n"
57
- fold ::= "## FOLD0" log-selection "\n\n" | "## FOLD0" log-selection "\n" pattern-body-ne "\n\n"
58
- exec ::= "## EXEC0" exec-slot? target-slot? line-slot? "\n\n" | "## EXEC0" exec-slot? target-slot? line-slot? "\n" section-body-ne "\n\n"
59
- bare ::= "## BARE0" add-tags-slot? "\n" section-body-ne "\n\n"
60
- work ::= "## WORK0" branch-slot? target-slot "\n" section-body-ne "\n\n"
61
- fork ::= "## FORK0" branch-slot? target-slot "\n" section-body-ne "\n\n"
62
- kill ::= "## KILL0" kill-slot? target-slot "\n\n"
63
- send-mid ::= "## SEND0" status-mid-slot target-slot? "\n\n" | "## SEND0" status-mid-slot target-slot? "\n" section-body-ne "\n\n" | "## SEND0" target-slot? "\n\n" | "## SEND0" target-slot? "\n" section-body-ne "\n\n"
64
- send-102 ::= "## SEND0 [102]" target-slot? "\n" section-body-ne
65
- send-200 ::= "## SEND0 [200]" target-slot? "\n" section-body-ne
66
- send-202 ::= "## SEND0 [202]" target-slot? park-slot? "\n" section-body-ne
67
- send-300 ::= "## SEND0 [300]" target-slot? "\n" section-body-ne
68
- send-499 ::= "## SEND0 [499]" target-slot? "\n" section-body-ne
69
- send-final-any ::= send-102 | send-200 | send-202 | send-300 | send-499
70
- send-final-first ::= send-200 | send-202 | send-300 | send-499
54
+ plan ::= "# PLAN0" annotation-slot? "\n" section-body-ne "\n"
55
+ find ::= "## FIND0" add-tags-slot? target-slot line-slot? annotation-slot? "\n" | "## FIND0" add-tags-slot? target-slot line-slot? annotation-slot? "\n" pattern-body-ne "\n"
56
+ read ::= "## READ0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" | "## READ0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" pattern-body-ne "\n"
57
+ edit ::= "## EDIT0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" | "## EDIT0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" section-body-ne "\n"
58
+ copy ::= "## COPY0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" section-body-ne "\n"
59
+ move ::= "## MOVE0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" section-body-ne "\n"
60
+ open ::= "## OPEN0" log-selection text-line-slot? annotation-slot? "\n" | "## OPEN0" log-selection text-line-slot? annotation-slot? "\n" pattern-body-ne "\n"
61
+ fold ::= "## FOLD0" log-selection text-line-slot? annotation-slot? "\n" | "## FOLD0" log-selection text-line-slot? annotation-slot? "\n" pattern-body-ne "\n"
62
+ exec ::= "## EXEC0" exec-slot? target-slot? line-slot? annotation-slot? "\n" | "## EXEC0" exec-slot? target-slot? line-slot? annotation-slot? "\n" section-body-ne "\n"
63
+ bare ::= "## BARE0" add-tags-slot? annotation-slot? "\n" section-body-ne "\n"
64
+ work ::= "## WORK0" branch-slot? target-slot annotation-slot? "\n" section-body-ne "\n"
65
+ fork ::= "## FORK0" branch-slot? target-slot annotation-slot? "\n" section-body-ne "\n"
66
+ kill ::= "## KILL0" kill-slot? target-slot annotation-slot? "\n"
67
+ send-mid ::= "## SEND0" status-mid-slot target-slot? annotation-slot? "\n" | "## SEND0" status-mid-slot target-slot? annotation-slot? "\n" section-body-ne "\n" | "## SEND0" target-slot? annotation-slot? "\n" | "## SEND0" target-slot? annotation-slot? "\n" section-body-ne "\n"
68
+ send-102 ::= "## SEND0 [102]" target-slot? annotation-slot? "\n" section-body-ne
69
+ send-200 ::= "## SEND0 [200]" target-slot? annotation-slot? "\n" section-body-ne
70
+ send-202 ::= "## SEND0 [202]" target-slot? park-slot? annotation-slot? "\n" section-body-ne
71
+ send-499 ::= "## SEND0 [499]" target-slot? annotation-slot? "\n" section-body-ne
72
+ send-final-any ::= send-102 | send-200 | send-202 | send-499
73
+ send-final-first ::= send-200 | send-202 | send-499
71
74
  op-statement ::= find | read | edit | copy | move | open | fold | exec | bare | work | fork | kill
72
75
  tail-0 ::= send-mid tail-1 | op-statement tail-1 | send-final-first
73
76
  tail-1 ::= send-mid tail-2 | op-statement tail-2 | send-final-any
@@ -126,10 +129,11 @@ branch-slot ::= " " branch
126
129
  kill-slot ::= " " kill-sig
127
130
  status-mid-slot ::= " [" status-mid "]"
128
131
  park-slot ::= " " park
132
+ annotation-slot ::= " <!-- " annotation-body-ne " -->"
129
133
  status-mid ::= [05-9] [0-9] [0-9] | "1" status-mid-1 | "2" status-mid-2 | "3" status-mid-3 | "4" status-mid-4
130
134
  status-mid-1 ::= "0" [0-13-9] | [1-9] [0-9]
131
135
  status-mid-2 ::= "0" [13-9] | [1-9] [0-9]
132
- status-mid-3 ::= "0" [1-9] | [1-9] [0-9]
136
+ status-mid-3 ::= "0" [0-9] | [1-9] [0-9]
133
137
  status-mid-4 ::= "9" [0-8] | [0-8] [0-9]
134
138
  add-tags ::= "[" add-tag add-tag-rest* "]"
135
139
  curation-tags ::= "[" curation-term curation-term-rest* "]"
@@ -45,29 +45,32 @@ section-body-b40 ::= ("#" section-body-b1 | [ PLANFDRETCOYMVSXBWK] section-body-
45
45
  section-body-b41 ::= ("#" section-body-b1 | [ PANFIDRETCOYMVSXBWK] section-body-b0 | "L" section-body-b42 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F# PLANFIDRETCOYMVSXBWK] section-body-b0)?
46
46
  section-body-b42 ::= ("#" section-body-b1 | [ PANFIDRETCOYMVSXBWK] section-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F# PLANFIDRETCOYMVSXBWK] section-body-b0)?
47
47
  section-body-ne ::= "#" section-body-b1 | [ PLANFIDRETCOYMVSXBWK] section-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F# PLANFIDRETCOYMVSXBWK] section-body-b0
48
+ annotation-body-b0 ::= ("-" annotation-body-b1 | ">" annotation-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0)?
49
+ annotation-body-b1 ::= ("-" annotation-body-b2 | ">" annotation-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0)?
50
+ annotation-body-b2 ::= ("-" annotation-body-b2 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0)?
51
+ annotation-body-ne ::= "-" annotation-body-b1 | ">" annotation-body-b0 | [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r>-] annotation-body-b0
48
52
  pattern-body-ne ::= [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r:#] [^\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\n\r]*
49
53
  log-selection ::= (curation-tags-slot log-target-slot? | log-target-slot)?
50
- plan ::= "# PLAN0" "\n" section-body-ne "\n\n"
51
- find ::= "## FIND0" add-tags-slot? target-slot line-slot? "\n\n" | "## FIND0" add-tags-slot? target-slot line-slot? "\n" pattern-body-ne "\n\n"
52
- read ::= "## READ0" add-tags-slot? target-slot text-line-slot? "\n\n" | "## READ0" add-tags-slot? target-slot text-line-slot? "\n" pattern-body-ne "\n\n"
53
- edit ::= "## EDIT0" add-tags-slot? target-slot text-line-slot? "\n\n" | "## EDIT0" add-tags-slot? target-slot text-line-slot? "\n" section-body-ne "\n\n"
54
- copy ::= "## COPY0" add-tags-slot? target-slot text-line-slot? "\n" section-body-ne "\n\n"
55
- move ::= "## MOVE0" add-tags-slot? target-slot text-line-slot? "\n" section-body-ne "\n\n"
56
- open ::= "## OPEN0" log-selection "\n\n" | "## OPEN0" log-selection "\n" pattern-body-ne "\n\n"
57
- fold ::= "## FOLD0" log-selection "\n\n" | "## FOLD0" log-selection "\n" pattern-body-ne "\n\n"
58
- exec ::= "## EXEC0" exec-slot? target-slot? line-slot? "\n\n" | "## EXEC0" exec-slot? target-slot? line-slot? "\n" section-body-ne "\n\n"
59
- bare ::= "## BARE0" add-tags-slot? "\n" section-body-ne "\n\n"
60
- work ::= "## WORK0" branch-slot? target-slot "\n" section-body-ne "\n\n"
61
- fork ::= "## FORK0" branch-slot? target-slot "\n" section-body-ne "\n\n"
62
- kill ::= "## KILL0" kill-slot? target-slot "\n\n"
63
- send-mid ::= "## SEND0" status-mid-slot target-slot? "\n\n" | "## SEND0" status-mid-slot target-slot? "\n" section-body-ne "\n\n" | "## SEND0" target-slot? "\n\n" | "## SEND0" target-slot? "\n" section-body-ne "\n\n"
64
- send-102 ::= "## SEND0 [102]" target-slot? "\n" section-body-ne
65
- send-200 ::= "## SEND0 [200]" target-slot? "\n" section-body-ne
66
- send-202 ::= "## SEND0 [202]" target-slot? park-slot? "\n" section-body-ne
67
- send-300 ::= "## SEND0 [300]" target-slot? "\n" section-body-ne
68
- send-499 ::= "## SEND0 [499]" target-slot? "\n" section-body-ne
69
- send-final-any ::= send-102 | send-200 | send-202 | send-300 | send-499
70
- send-final-first ::= send-200 | send-202 | send-300 | send-499
54
+ plan ::= "# PLAN0" annotation-slot? "\n" section-body-ne "\n"
55
+ find ::= "## FIND0" add-tags-slot? target-slot line-slot? annotation-slot? "\n" | "## FIND0" add-tags-slot? target-slot line-slot? annotation-slot? "\n" pattern-body-ne "\n"
56
+ read ::= "## READ0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" | "## READ0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" pattern-body-ne "\n"
57
+ edit ::= "## EDIT0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" | "## EDIT0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" section-body-ne "\n"
58
+ copy ::= "## COPY0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" section-body-ne "\n"
59
+ move ::= "## MOVE0" add-tags-slot? target-slot text-line-slot? annotation-slot? "\n" section-body-ne "\n"
60
+ open ::= "## OPEN0" log-selection text-line-slot? annotation-slot? "\n" | "## OPEN0" log-selection text-line-slot? annotation-slot? "\n" pattern-body-ne "\n"
61
+ fold ::= "## FOLD0" log-selection text-line-slot? annotation-slot? "\n" | "## FOLD0" log-selection text-line-slot? annotation-slot? "\n" pattern-body-ne "\n"
62
+ exec ::= "## EXEC0" exec-slot? target-slot? line-slot? annotation-slot? "\n" | "## EXEC0" exec-slot? target-slot? line-slot? annotation-slot? "\n" section-body-ne "\n"
63
+ bare ::= "## BARE0" add-tags-slot? annotation-slot? "\n" section-body-ne "\n"
64
+ work ::= "## WORK0" branch-slot? target-slot annotation-slot? "\n" section-body-ne "\n"
65
+ fork ::= "## FORK0" branch-slot? target-slot annotation-slot? "\n" section-body-ne "\n"
66
+ kill ::= "## KILL0" kill-slot? target-slot annotation-slot? "\n"
67
+ send-mid ::= "## SEND0" status-mid-slot target-slot? annotation-slot? "\n" | "## SEND0" status-mid-slot target-slot? annotation-slot? "\n" section-body-ne "\n" | "## SEND0" target-slot? annotation-slot? "\n" | "## SEND0" target-slot? annotation-slot? "\n" section-body-ne "\n"
68
+ send-102 ::= "## SEND0 [102]" target-slot? annotation-slot? "\n" section-body-ne
69
+ send-200 ::= "## SEND0 [200]" target-slot? annotation-slot? "\n" section-body-ne
70
+ send-202 ::= "## SEND0 [202]" target-slot? park-slot? annotation-slot? "\n" section-body-ne
71
+ send-499 ::= "## SEND0 [499]" target-slot? annotation-slot? "\n" section-body-ne
72
+ send-final-any ::= send-102 | send-200 | send-202 | send-499
73
+ send-final-first ::= send-200 | send-202 | send-499
71
74
  op-statement ::= find | read | edit | copy | move | open | fold | exec | bare | work | fork | kill
72
75
  tail-0 ::= send-mid tail-1 | op-statement tail-1 | send-final-first
73
76
  tail-1 ::= send-mid tail-2 | op-statement tail-2 | send-final-any
@@ -115,10 +118,11 @@ branch-slot ::= " " branch
115
118
  kill-slot ::= " " kill-sig
116
119
  status-mid-slot ::= " [" status-mid "]"
117
120
  park-slot ::= " " park
121
+ annotation-slot ::= " <!-- " annotation-body-ne " -->"
118
122
  status-mid ::= [05-9] [0-9] [0-9] | "1" status-mid-1 | "2" status-mid-2 | "3" status-mid-3 | "4" status-mid-4
119
123
  status-mid-1 ::= "0" [0-13-9] | [1-9] [0-9]
120
124
  status-mid-2 ::= "0" [13-9] | [1-9] [0-9]
121
- status-mid-3 ::= "0" [1-9] | [1-9] [0-9]
125
+ status-mid-3 ::= "0" [0-9] | [1-9] [0-9]
122
126
  status-mid-4 ::= "9" [0-8] | [0-8] [0-9]
123
127
  add-tags ::= "[" add-tag add-tag-rest* "]"
124
128
  curation-tags ::= "[" curation-term curation-term-rest* "]"
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.plurnk.dev/v0/ClientInteractionProjection.json",
4
+ "title": "ClientInteractionProjection",
5
+ "description": "The runtime-neutral client-interface projection of one pending client interaction. Live delivery and reconnect discovery expose this same shape.",
6
+ "type": "object",
7
+ "required": ["interactionId", "workerId", "loopId", "turnId", "request"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "interactionId": { "type": "integer", "minimum": 1 },
11
+ "workerId": { "type": "integer", "minimum": 1 },
12
+ "loopId": { "type": "integer", "minimum": 1 },
13
+ "turnId": { "type": "integer", "minimum": 1 },
14
+ "request": { "$ref": "https://schemas.plurnk.dev/v0/ClientInteractionRequest.json" }
15
+ }
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.plurnk.dev/v0/ClientInteractionRequest.json",
4
+ "title": "ClientInteractionRequest",
5
+ "description": "A runtime-neutral request for one client-owned interaction. The owner supplies the standard tool presentation and response contract; protocol-private continuation state is excluded.",
6
+ "type": "object",
7
+ "required": ["toolName", "arguments", "responseSchema"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "toolName": { "type": "string", "minLength": 1 },
11
+ "arguments": { "type": "object", "additionalProperties": true },
12
+ "message": { "type": "string", "minLength": 1 },
13
+ "responseSchema": { "type": "object", "additionalProperties": true }
14
+ }
15
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.plurnk.dev/v0/ClientInteractionResolution.json",
4
+ "title": "ClientInteractionResolution",
5
+ "description": "The client response that settles one pending interaction. A cancelled interaction carries no fabricated payload.",
6
+ "oneOf": [
7
+ {
8
+ "type": "object",
9
+ "required": ["status"],
10
+ "additionalProperties": false,
11
+ "properties": {
12
+ "status": { "const": "resolved" },
13
+ "payload": true
14
+ }
15
+ },
16
+ {
17
+ "type": "object",
18
+ "required": ["status"],
19
+ "additionalProperties": false,
20
+ "properties": {
21
+ "status": { "const": "cancelled" }
22
+ }
23
+ }
24
+ ]
25
+ }