markform 0.1.16 → 0.1.18

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 (35) hide show
  1. package/LICENSE +369 -0
  2. package/README.md +154 -214
  3. package/dist/ai-sdk.d.mts +1 -1
  4. package/dist/ai-sdk.mjs +2 -2
  5. package/dist/{apply-CXsI5N9x.mjs → apply-BYgtU64w.mjs} +203 -16
  6. package/dist/apply-BYgtU64w.mjs.map +1 -0
  7. package/dist/bin.mjs +1 -1
  8. package/dist/{cli-BsFessUW.mjs → cli-D9w0Bp4J.mjs} +199 -13
  9. package/dist/cli-D9w0Bp4J.mjs.map +1 -0
  10. package/dist/cli.mjs +1 -1
  11. package/dist/{coreTypes-DE6Giau5.d.mts → coreTypes-BMEs8h_2.d.mts} +165 -2
  12. package/dist/{coreTypes-DiCddBKu.mjs → coreTypes-SDB3KRRJ.mjs} +9 -4
  13. package/dist/coreTypes-SDB3KRRJ.mjs.map +1 -0
  14. package/dist/index.d.mts +266 -2
  15. package/dist/index.mjs +5 -5
  16. package/dist/{session-B7aR6hno.mjs → session-CW9AQw6i.mjs} +1 -1
  17. package/dist/{session-XDrocA3j.mjs → session-Ci4B0Pna.mjs} +2 -2
  18. package/dist/{session-XDrocA3j.mjs.map → session-Ci4B0Pna.mjs.map} +1 -1
  19. package/dist/{src-Dv3IZSQU.mjs → src-DDxi-2ne.mjs} +966 -32
  20. package/dist/src-DDxi-2ne.mjs.map +1 -0
  21. package/docs/markform-apis.md +110 -0
  22. package/docs/markform-reference.md +58 -0
  23. package/docs/markform-spec.md +204 -9
  24. package/examples/movie-research/movie-deep-research-mock-filled.form.md +1 -1
  25. package/examples/movie-research/movie-deep-research.form.md +1 -1
  26. package/examples/parallel/parallel-research.form.md +57 -0
  27. package/examples/plan-document/plan-document-markdoc.form.md +35 -0
  28. package/examples/plan-document/plan-document-progress.form.md +47 -0
  29. package/examples/plan-document/plan-document.form.md +47 -0
  30. package/examples/startup-deep-research/startup-deep-research.form.md +1 -1
  31. package/package.json +2 -2
  32. package/dist/apply-CXsI5N9x.mjs.map +0 -1
  33. package/dist/cli-BsFessUW.mjs.map +0 -1
  34. package/dist/coreTypes-DiCddBKu.mjs.map +0 -1
  35. package/dist/src-Dv3IZSQU.mjs.map +0 -1
@@ -202,10 +202,41 @@ const result = await fillForm({
202
202
  | `maxStepsPerTurn` | `number` | `20` | Maximum AI SDK steps (tool call rounds) per turn |
203
203
  | `targetRoles` | `string[]` | `['agent']` | Roles to fill |
204
204
  | `fillMode` | `FillMode` | `'continue'` | `'continue'` or `'overwrite'` |
205
+ | `enableParallel` | `boolean` | `false` | Enable parallel execution for forms with `parallel` batches |
206
+ | `maxParallelAgents` | `number` | `4` | Max concurrent agents for parallel batches |
205
207
  | `callbacks` | `FillCallbacks` | `undefined` | Progress callbacks |
206
208
  | `signal` | `AbortSignal` | `undefined` | Cancellation signal |
207
209
  | `additionalTools` | `Record<string, Tool>` | `undefined` | Custom tools for agent |
208
210
 
211
+ ### Parallel Execution
212
+
213
+ When a form uses `parallel` attributes on groups, you can enable concurrent execution:
214
+
215
+ ```typescript
216
+ const result = await fillForm({
217
+ form: formMarkdown,
218
+ model: 'anthropic/claude-sonnet-4-5',
219
+ enableWebSearch: true,
220
+ captureWireFormat: false,
221
+ enableParallel: true,
222
+ maxParallelAgents: 4,
223
+ callbacks: {
224
+ onOrderLevelStart: ({ order }) => console.log(`Order ${order} starting`),
225
+ onBatchStart: ({ batchId }) => console.log(`Batch ${batchId} starting`),
226
+ onBatchComplete: ({ batchId, patchesApplied }) =>
227
+ console.log(`Batch ${batchId}: ${patchesApplied} patches`),
228
+ },
229
+ });
230
+ ```
231
+
232
+ **Behavior:**
233
+ - `enableParallel: false` (default): All fields filled serially, `parallel` attributes
234
+ ignored. The `order` attribute still controls issue filtering.
235
+ - `enableParallel: true`: Batch items run concurrently (up to `maxParallelAgents`).
236
+ Each agent runs a multi-turn loop with rejection feedback, same as the serial path.
237
+ - If the form has no `parallel` batches, falls back to serial automatically.
238
+ - `FillResult` shape is identical regardless of serial or parallel execution.
239
+
209
240
  ### FillStatus
210
241
 
211
242
  The `status` field in `FillResult` indicates success or failure:
@@ -355,6 +386,85 @@ Run a research session on a research-type form.
355
386
 
356
387
  See [runResearch.ts](../packages/markform/src/research/runResearch.ts) for full details.
357
388
 
389
+ ## Markdown Utilities
390
+
391
+ Utilities for working with markdown content, particularly for plan documents with
392
+ implicit checkboxes.
393
+
394
+ ```typescript
395
+ import {
396
+ findAllHeadings,
397
+ findEnclosingHeadings,
398
+ findAllCheckboxes,
399
+ injectCheckboxIds,
400
+ injectHeaderIds,
401
+ } from 'markform';
402
+ ```
403
+
404
+ ### findAllHeadings(markdown: string): HeadingInfo[]
405
+
406
+ Find all headings in a markdown document, returned in document order.
407
+
408
+ ```typescript
409
+ interface HeadingInfo {
410
+ level: number; // 1-6 for h1-h6
411
+ title: string; // Heading text (without # prefix)
412
+ line: number; // Line number (1-indexed)
413
+ position: SourceRange;
414
+ }
415
+ ```
416
+
417
+ ### findEnclosingHeadings(markdown: string, line: number): HeadingInfo[]
418
+
419
+ Find all headings that enclose a given line position. Returns headings from innermost
420
+ (most specific) to outermost (least specific).
421
+
422
+ A heading "encloses" a line if the heading appears before the line and no heading of
423
+ equal or higher level appears between them.
424
+
425
+ ### findAllCheckboxes(markdown: string): CheckboxInfo[]
426
+
427
+ Find all checkboxes in a markdown document with their enclosing heading context.
428
+
429
+ ```typescript
430
+ interface CheckboxInfo {
431
+ id?: string; // Existing ID from annotation
432
+ label: string; // Checkbox label text
433
+ state: CheckboxValue; // Current state (todo, done, etc.)
434
+ position: SourceRange; // Source position
435
+ enclosingHeadings: HeadingInfo[]; // Innermost first
436
+ }
437
+ ```
438
+
439
+ ### injectCheckboxIds(markdown: string, options): InjectIdsResult
440
+
441
+ Inject ID annotations into checkboxes that lack them.
442
+
443
+ ```typescript
444
+ interface InjectCheckboxIdsOptions {
445
+ generator: (info: CheckboxInfo, index: number) => string;
446
+ onlyMissing?: boolean; // Default: true
447
+ }
448
+
449
+ interface InjectIdsResult {
450
+ markdown: string; // Modified markdown
451
+ injectedCount: number; // Number of IDs added
452
+ injectedIds: Map<string, string>; // label -> generated ID
453
+ }
454
+ ```
455
+
456
+ ### injectHeaderIds(markdown: string, options): InjectIdsResult
457
+
458
+ Inject ID annotations into markdown headings.
459
+
460
+ ```typescript
461
+ interface InjectHeaderIdsOptions {
462
+ generator: (info: HeadingInfo, index: number) => string;
463
+ onlyMissing?: boolean; // Default: true
464
+ levels?: number[]; // Default: [1, 2, 3, 4, 5, 6]
465
+ }
466
+ ```
467
+
358
468
  ## Type Exports
359
469
 
360
470
  All Zod schemas and TypeScript types are exported from the main package:
@@ -256,6 +256,37 @@ Stateful checklists with three modes.
256
256
  | `[y]` | yes | Explicit yes |
257
257
  | `[n]` | no | Explicit no |
258
258
 
259
+ ### Implicit Checkboxes (Plan Documents)
260
+
261
+ Forms designed as task lists can omit explicit field wrappers. When a form has a
262
+ `{% form %}` tag but no `{% field %}` tags, checkboxes are automatically wrapped in
263
+ an implicit checkboxes field.
264
+
265
+ ```markdown
266
+ ---
267
+ markform:
268
+ spec: MF/0.1
269
+ ---
270
+ {% form id="plan" title="Project Plan" %}
271
+
272
+ ## Phase 1: Research
273
+ - [ ] Literature review {% #lit_review %}
274
+ - [ ] Competitive analysis {% #comp %}
275
+
276
+ ## Phase 2: Design
277
+ - [x] Architecture doc {% #arch %}
278
+ - [/] API design {% #api %}
279
+
280
+ {% /form %}
281
+ ```
282
+
283
+ **Requirements:**
284
+ - Each checkbox MUST have an ID annotation (`{% #id %}` or `<!-- #id -->`)
285
+ - IDs must be unique (same rules as explicit checkboxes fields)
286
+ - The implicit field uses ID `checkboxes` (reserved)
287
+ - Always uses `checkboxMode="multi"` (5-state)
288
+ - Mixing explicit fields with checkboxes outside fields is an error
289
+
259
290
  ### URL Field
260
291
 
261
292
  Single URL with format validation.
@@ -385,6 +416,8 @@ All fields support these attributes:
385
416
  | `required` | boolean | false | Must be filled for completion |
386
417
  | `role` | string | - | Target actor (`user`, `agent`) |
387
418
  | `priority` | string | medium | `high`, `medium`, `low` |
419
+ | `order` | number | `0` | Fill order. Lower values filled first. Different order levels are filled in separate turns. |
420
+ | `parallel` | string | - | Parallel batch identifier. Items with the same value may execute concurrently. Top-level only. |
388
421
 
389
422
  **Text-entry fields only** (string, number, string-list, url, url-list):
390
423
 
@@ -401,6 +434,31 @@ All fields support these attributes:
401
434
  Note: `placeholder` and `examples` are NOT valid on chooser fields (single-select,
402
435
  multi-select, checkboxes).
403
436
 
437
+ ## Harness Configuration
438
+
439
+ Optional harness hints can be set in YAML frontmatter under `markform.harness`.
440
+ All keys must be `snake_case` and all values must be numbers.
441
+ These are suggestions — a harness may ignore or override them via API options.
442
+
443
+ | Key | Type | Description |
444
+ | --- | --- | --- |
445
+ | `max_turns` | number | Maximum turns before stopping |
446
+ | `max_patches_per_turn` | number | Maximum patches per turn |
447
+ | `max_issues_per_turn` | number | Maximum issues surfaced per turn |
448
+ | `max_parallel_agents` | number | Maximum concurrent agents for parallel execution |
449
+
450
+ ```yaml
451
+ markform:
452
+ spec: MF/0.1
453
+ harness:
454
+ max_turns: 50
455
+ max_issues_per_turn: 5
456
+ max_patches_per_turn: 10
457
+ max_parallel_agents: 4
458
+ ```
459
+
460
+ Unrecognized keys or non-numeric values cause parse errors.
461
+
404
462
  ## Documentation Blocks
405
463
 
406
464
  Add context to fields, groups, or the form.
@@ -144,6 +144,30 @@ markform:
144
144
  When omitted, tools may infer from field roles or require explicit selection.
145
145
  This is a hint for tooling, not enforced by the engine.
146
146
 
147
+ - `harness` (*optional*): A map of harness configuration hints that suggest execution
148
+ parameters to harness implementations. These are suggestions — a harness MAY ignore
149
+ them or override them via API options.
150
+
151
+ Supported keys (all values must be numbers, all keys must be `snake_case`):
152
+
153
+ | Key | Description |
154
+ | --- | --- |
155
+ | `max_turns` | Suggested maximum turns before stopping |
156
+ | `max_patches_per_turn` | Suggested maximum patches per turn |
157
+ | `max_issues_per_turn` | Suggested maximum issues surfaced per turn |
158
+ | `max_parallel_agents` | Suggested maximum concurrent agents for parallel execution |
159
+
160
+ Unrecognized keys or non-numeric values are parse errors.
161
+
162
+ Example:
163
+ ```yaml
164
+ markform:
165
+ spec: MF/0.1
166
+ harness:
167
+ max_turns: 50
168
+ max_parallel_agents: 4
169
+ ```
170
+
147
171
  **Behavioral rules (*required*):**
148
172
 
149
173
  - *required:* `form_summary`, `form_progress`, and `form_state` are derived,
@@ -255,6 +279,8 @@ Example: `pattern="^[A-Z]{1,5}$"` for a ticker symbol.
255
279
  | `label` | string | Required. Human-readable field name |
256
280
  | `required` | boolean | Whether field must be filled for form completion |
257
281
  | `role` | string | Target actor (e.g., `"user"`, `"agent"`). See role-filtered completion |
282
+ | `parallel` | string | Parallel batch identifier. Top-level fields/groups only. See [Parallel Execution Hints](#parallel-execution-hints) |
283
+ | `order` | number | Fill order (default: `0`). Lower values filled first. See [Fill Order](#fill-order) |
258
284
 
259
285
  The `role` attribute enables multi-actor workflows where different fields are assigned
260
286
  to different actors.
@@ -270,6 +296,11 @@ These attributes are only valid on text-entry field kinds.
270
296
  Using them on chooser fields (single-select, multi-select, checkboxes) will result in a
271
297
  parse error.
272
298
 
299
+ **Nesting constraints:**
300
+ - Field tags MUST NOT be nested inside other field tags
301
+ - Nested field tags produce a parse error:
302
+ `Field tags cannot be nested. Found 'inner_id' inside 'outer_id'`
303
+
273
304
  **Example with placeholder and examples:**
274
305
  ```md
275
306
  {% field kind="string" id="company_name" label="Company name" placeholder="Enter company name" examples=["ACME Corp", "Globex Inc"] %}{% /field %}
@@ -636,6 +667,60 @@ In this example, `risk_factors.currency` is unfilled (`[ ]`) and will fail valid
636
667
  because `checkboxMode="explicit"` requires all options to have explicit `[y]` or `[n]`
637
668
  answers.
638
669
 
670
+ ##### Implicit Checkboxes (Plan Documents)
671
+
672
+ Forms designed as task lists or plans can omit explicit field wrappers. When a form
673
+ contains:
674
+ - A `{% form %}` wrapper (or `<!-- form ... -->`)
675
+ - No explicit `{% field %}` tags
676
+ - Standard markdown checkboxes with ID annotations
677
+
678
+ The parser automatically creates an implicit checkboxes field:
679
+
680
+ | Property | Value |
681
+ | --- | --- |
682
+ | ID | `checkboxes` (reserved) |
683
+ | Label | `Checkboxes` |
684
+ | Mode | `multi` (always) |
685
+ | Options | All checkboxes in document order |
686
+ | Implicit | `true` |
687
+
688
+ **Example:**
689
+ ```md
690
+ ---
691
+ markform:
692
+ spec: MF/0.1
693
+ ---
694
+ {% form id="plan" title="Project Plan" %}
695
+
696
+ ## Phase 1: Research
697
+ - [ ] Literature review {% #lit_review %}
698
+ - [ ] Competitive analysis {% #comp %}
699
+
700
+ ## Phase 2: Design
701
+ - [x] Architecture doc {% #arch %}
702
+ - [/] API design {% #api %}
703
+
704
+ {% /form %}
705
+ ```
706
+
707
+ The above form parses to a schema with a single implicit checkboxes field containing
708
+ four options: `lit_review`, `comp`, `arch`, and `api`.
709
+
710
+ **Requirements:**
711
+ - Standard option ID rules apply (see [Identifiers](#identifiers)):
712
+ - Each checkbox MUST have an ID annotation (`{% #id %}` or `<!-- #id -->`)
713
+ - IDs MUST be unique within the implicit field
714
+ - Recommended: use `snake_case` slugified from label
715
+ - ID `checkboxes` is reserved and MUST NOT be used for explicit fields
716
+ - Nested checkboxes (indented list items) are collected as separate options
717
+
718
+ **Error conditions:**
719
+ - Checkbox without ID annotation: Parse error (same as explicit checkboxes fields)
720
+ - Duplicate checkbox ID: Parse error (same as explicit checkboxes fields)
721
+ - Mixed mode (explicit fields AND checkboxes outside fields): Parse error
722
+ - Explicit field with ID `checkboxes`: Parse error (reserved ID)
723
+
639
724
  ##### String-List Fields
640
725
 
641
726
  String-list fields represent open-ended arrays of user-provided strings.
@@ -974,17 +1059,24 @@ Markform files may contain content outside of Markform tags. This content is han
974
1059
 
975
1060
  | Content Type | Policy |
976
1061
  |--------------|--------|
977
- | HTML comments (`
1062
+ | Markdown content (headings, paragraphs, lists, etc.) | Preserved; structure must be equivalent after round-trip |
1063
+ | HTML comments (`<!-- ... -->`) | Preserved verbatim on round-trip |
1064
+ | Arbitrary Markdoc tags (non-Markform) | Parse warning, ignored (not preserved) |
978
1065
 
979
- <!-- ... -->
1066
+ **Content preservation semantics (*required*):**
1067
+
1068
+ - *required:* All markdown content outside of Markform tags MUST be preserved on
1069
+ canonical serialization
1070
+
1071
+ - *required:* The markdown structure MUST be equivalent after round-trip (same headings,
1072
+ paragraphs, lists, code blocks, etc.)
980
1073
 
981
- `) | Allowed, preserved verbatim on round-trip |
982
- | Markdown headings/text between groups | Allowed, but NOT preserved on canonical serialize |
983
- | Arbitrary Markdoc tags (non-Markform) | Parse warning, ignored |
1074
+ - *recommended:* Visual appearance SHOULD be preserved (same rendering output)
984
1075
 
985
- **MF/0.1 scope:** Only HTML comments are guaranteed to be preserved. Do not rely on
986
- non-Markform content surviving serialization. Future versions may support full
987
- content preservation via raw slicing.
1076
+ - Superficial adjustments are permitted: line wrapping, whitespace normalization,
1077
+ stylistic conventions for Markform tag formatting (attribute ordering, spacing)
1078
+
1079
+ - The semantic content and document structure must remain intact
988
1080
 
989
1081
  #### Serialization Strategy
990
1082
 
@@ -993,7 +1085,9 @@ requirements beyond what it provides—see [Formatting][markdoc-format]):
993
1085
 
994
1086
  **MF/0.1 content restrictions for canonical serialization (*required*):**
995
1087
 
996
- To ensure deterministic round-tripping without building a full markdown serializer:
1088
+ The following restrictions apply to content *within* Markform elements to ensure
1089
+ deterministic parsing and validation. General markdown content outside of Markform
1090
+ tags is preserved via raw slicing (retaining the original text):
997
1091
 
998
1092
  | Content type | Restriction |
999
1093
  |--------------|-------------|
@@ -1191,6 +1285,59 @@ On GitHub, all `<!-- ... -->` comments are hidden, leaving only the visible cont
1191
1285
  **Constraint:** Values containing the literal string `-->` require escaping or should
1192
1286
  use the tag syntax to avoid prematurely closing the comment.
1193
1287
 
1288
+ ##### Parallel Execution Hints
1289
+
1290
+ Top-level fields and groups MAY include a `parallel` attribute to indicate that they
1291
+ can be filled concurrently with other items sharing the same value.
1292
+
1293
+ ```markdown
1294
+ <!-- field kind="string" id="a" label="A" parallel="batch_1" --><!-- /field -->
1295
+ <!-- field kind="string" id="b" label="B" parallel="batch_1" --><!-- /field -->
1296
+ ```
1297
+
1298
+ **Rules:**
1299
+ - `parallel` value is an arbitrary string identifier (recommended: `snake_case`)
1300
+ - Items with the same `parallel` value form a *parallel batch*
1301
+ - Items without `parallel` remain in loose-serial mode (single agent, no enforced
1302
+ ordering) — identical to current behavior
1303
+ - `parallel` MUST NOT appear on fields inside groups (parse error) — only on
1304
+ top-level fields and groups
1305
+ - All items in a parallel batch MUST have the same effective `role` (parse error)
1306
+ - `parallel` is a hint — a harness MAY ignore it and fill everything in
1307
+ loose-serial mode
1308
+
1309
+ **Execution model:**
1310
+ ```
1311
+ Without parallel: All items filled by one agent in loose-serial mode (current behavior).
1312
+
1313
+ With parallel: Items are partitioned into two pools:
1314
+ 1. Loose-serial pool: items without `parallel`, filled by primary agent
1315
+ 2. Parallel batches: items with `parallel`, each item filled by a separate agent
1316
+ All agents (primary + parallel) run concurrently. No barriers between them.
1317
+ ```
1318
+
1319
+ ##### Fill Order
1320
+
1321
+ Fields and groups MAY include an `order` attribute (numeric) that controls the
1322
+ sequence in which the harness presents fields to the agent.
1323
+
1324
+ ```markdown
1325
+ <!-- field kind="string" id="details" label="Details" --><!-- /field -->
1326
+ <!-- field kind="string" id="summary" label="Summary" order=99 --><!-- /field -->
1327
+ ```
1328
+
1329
+ **Rules:**
1330
+ - `order` is a number (integer or float). Default: `0`.
1331
+ - Lower `order` values are filled first. Fields at the same order level are
1332
+ filled in loose-serial order (agent chooses).
1333
+ - The harness MUST NOT surface issues for `order=N` fields until all fields at
1334
+ `order<N` are complete (answered, skipped, or aborted).
1335
+ - Fields at different order levels are always filled in separate agent turns.
1336
+ - A field inside a group with `order` MUST NOT specify a different `order`
1337
+ (parse error). Use separate groups for different order levels.
1338
+ - `order` composes with `parallel`: all items in a parallel batch MUST have the
1339
+ same effective `order` value (parse error otherwise).
1340
+
1194
1341
  * * *
1195
1342
 
1196
1343
  ## Layer 2: Form Data Model
@@ -1374,6 +1521,8 @@ interface FieldGroup {
1374
1521
  // Note: `required` on groups is not supported in MF/0.1 (ignored with warning)
1375
1522
  validate?: ValidatorRef[]; // validator references (string IDs or parameterized objects)
1376
1523
  children: Field[]; // MF/0.1/0.2: fields only; nested groups deferred (future)
1524
+ parallel?: string; // Parallel batch identifier
1525
+ order?: number; // Fill order (default: 0). Applies to all child fields.
1377
1526
  }
1378
1527
 
1379
1528
  type FieldPriorityLevel = 'high' | 'medium' | 'low';
@@ -1384,6 +1533,8 @@ interface FieldBase {
1384
1533
  required: boolean; // explicit: parser defaults to false if not specified
1385
1534
  priority: FieldPriorityLevel; // explicit: parser defaults to 'medium' if not specified
1386
1535
  validate?: ValidatorRef[]; // validator references (string IDs or parameterized objects)
1536
+ parallel?: string; // Parallel batch identifier (top-level only)
1537
+ order?: number; // Fill order (default: 0). Lower = filled first.
1387
1538
  }
1388
1539
 
1389
1540
  // NOTE: `required` and `priority` are explicit (not optional) in the data model.
@@ -1420,7 +1571,9 @@ interface Option {
1420
1571
  id: Id;
1421
1572
  label: string;
1422
1573
  }
1574
+ ```
1423
1575
 
1576
+ ```typescript
1424
1577
  type CheckboxMode = 'multi' | 'simple' | 'explicit';
1425
1578
 
1426
1579
  interface CheckboxesField extends FieldBase {
@@ -1966,6 +2119,16 @@ YAML keys use snake_case for readability and consistency with common YAML conven
1966
2119
  | `tag` | `DocumentationBlock` | `DocumentationTag` values | Identifies doc block type |
1967
2120
  | `nodeType` | `IdIndexEntry` | `'form' \| 'group' \| 'field'` | Identifies structural element type |
1968
2121
 
2122
+ **Special IDs:**
2123
+
2124
+ These IDs have special meaning but can also be used explicitly. When used explicitly, uniqueness
2125
+ is still enforced (only one field or group with each ID).
2126
+
2127
+ | Special ID | Purpose | Explicit Use |
2128
+ | --- | --- | --- |
2129
+ | `default` | Implicit group for ungrouped fields | When explicit, ungrouped fields merge into it |
2130
+ | `checkboxes` | Implicit checkboxes field for plan documents | When explicit, used instead of implicit creation |
2131
+
1969
2132
  ##### Field Kind Mappings
1970
2133
 
1971
2134
  **`string-field`** — Single string value
@@ -2584,6 +2747,38 @@ isRetryableError(error) // LLM error with retryable=true
2584
2747
  `ParseError` is exported as an alias for `MarkformParseError` for backward compatibility.
2585
2748
  Use `MarkformParseError` in new code.
2586
2749
 
2750
+ #### Execution Plan
2751
+
2752
+ An **execution plan** partitions top-level form items into a loose-serial pool and
2753
+ zero or more parallel batches:
2754
+
2755
+ ```typescript
2756
+ interface ExecutionPlan {
2757
+ /** Items without `parallel` — filled by primary agent in loose-serial mode */
2758
+ looseSerial: Array<{ itemId: Id; itemType: 'field' | 'group' }>;
2759
+
2760
+ /** Parallel batches — each item filled by a separate concurrent agent */
2761
+ parallelBatches: Array<{
2762
+ batchId: string;
2763
+ items: Array<{ itemId: Id; itemType: 'field' | 'group' }>;
2764
+ }>;
2765
+ }
2766
+ ```
2767
+
2768
+ **Computation:** Walk top-level items (fields and groups) in document order:
2769
+ - If item has no `parallel`: add to the loose-serial pool
2770
+ - If item has `parallel`: add to the batch with that ID (create batch if new)
2771
+
2772
+ **Execution:** The primary agent fills loose-serial items. For each parallel batch,
2773
+ one agent per item is spawned. All agents (primary + batch agents) run concurrently.
2774
+ When all complete, patches are merged and validation runs.
2775
+
2776
+ **Order-based filtering:** The harness partitions items by their effective `order`
2777
+ value (default `0`). Issues for fields at `order=N` are only surfaced after all fields
2778
+ at `order<N` are complete (answered, skipped, or aborted). This ensures fields at
2779
+ different order levels are always filled in separate agent turns, so higher-order fields
2780
+ see completed lower-order field values in the form markdown.
2781
+
2587
2782
  * * *
2588
2783
 
2589
2784
  ## Layer 4: Tool API & Interfaces
@@ -35,7 +35,7 @@ markform:
35
35
  - Skip fields if data unavailable (older films may lack some metrics)
36
36
  - For box office, use millions (e.g., 100.5 for $100.5M)
37
37
  - Add notes for any missing, confusing, or unclear information
38
- harness_config:
38
+ harness:
39
39
  max_issues_per_turn: 5
40
40
  max_patches_per_turn: 15
41
41
  ---
@@ -35,7 +35,7 @@ markform:
35
35
  - Skip fields if data unavailable (older films may lack some metrics)
36
36
  - For box office, use millions (e.g., 100.5 for $100.5M)
37
37
  - Add notes for any missing, confusing, or unclear information
38
- harness_config:
38
+ harness:
39
39
  max_issues_per_turn: 5
40
40
  max_patches_per_turn: 15
41
41
  ---
@@ -0,0 +1,57 @@
1
+ ---
2
+ markform:
3
+ spec: MF/0.1
4
+ title: Company Research (Parallel)
5
+ description: "Demonstrates parallel and order attributes for concurrent form filling."
6
+ roles:
7
+ - agent
8
+ role_instructions:
9
+ agent: "Research the company and fill in all fields."
10
+ harness:
11
+ max_turns: 10
12
+ max_parallel_agents: 4
13
+ ---
14
+ {% form id="company_research" title="Company Research (Parallel)" %}
15
+
16
+ {% description ref="company_research" %}
17
+ A company research form that uses `parallel` for concurrent deep research
18
+ and `order` to sequence synthesis after data gathering.
19
+ {% /description %}
20
+
21
+ {% group id="overview" order=0 %}
22
+
23
+ {% field kind="string" id="company_name" label="Company Name" role="agent" required=true %}{% /field %}
24
+
25
+ {% field kind="string" id="company_overview" label="Company Overview" role="agent" %}{% /field %}
26
+
27
+ {% /group %}
28
+
29
+ {% group id="financials" parallel="deep_research" order=0 %}
30
+
31
+ {% field kind="string" id="revenue" label="Annual Revenue" role="agent" %}{% /field %}
32
+
33
+ {% field kind="string" id="margins" label="Margin Analysis" role="agent" %}{% /field %}
34
+
35
+ {% /group %}
36
+
37
+ {% group id="team" parallel="deep_research" order=0 %}
38
+
39
+ {% field kind="string" id="leadership" label="Team & Leadership" role="agent" %}{% /field %}
40
+
41
+ {% /group %}
42
+
43
+ {% group id="market" parallel="deep_research" order=0 %}
44
+
45
+ {% field kind="string" id="tam" label="TAM" role="agent" %}{% /field %}
46
+
47
+ {% field kind="string" id="competitors" label="Competitors" role="agent" %}{% /field %}
48
+
49
+ {% /group %}
50
+
51
+ {% group id="synthesis" order=10 %}
52
+
53
+ {% field kind="string" id="overall" label="Overall Assessment" role="agent" required=true %}{% /field %}
54
+
55
+ {% /group %}
56
+
57
+ {% /form %}
@@ -0,0 +1,35 @@
1
+ ---
2
+ markform:
3
+ spec: MF/0.1
4
+ title: Sprint Tasks
5
+ description: "Plan document example using Markdoc syntax instead of HTML comments."
6
+ roles:
7
+ - user
8
+ role_instructions:
9
+ user: "Update task status as you complete work."
10
+ ---
11
+ {% form id="sprint_tasks" title="Sprint Tasks" %}
12
+
13
+ {% description ref="sprint_tasks" %}
14
+ A sprint task list using Markdoc tag syntax. Both Markdoc (`{% %}`) and
15
+ HTML comment (`<!-- -->`) syntaxes are equivalent in Markform.
16
+ {% /description %}
17
+
18
+ ## Backend
19
+
20
+ - [ ] Implement user authentication {% #auth %}
21
+ - [ ] Add rate limiting {% #rate_limit %}
22
+ - [ ] Set up database migrations {% #db_migrations %}
23
+
24
+ ## Frontend
25
+
26
+ - [ ] Create login page {% #login_page %}
27
+ - [ ] Add form validation {% #form_validation %}
28
+ - [ ] Implement dark mode {% #dark_mode %}
29
+
30
+ ## DevOps
31
+
32
+ - [ ] Configure CI/CD pipeline {% #cicd %}
33
+ - [ ] Set up monitoring {% #monitoring %}
34
+
35
+ {% /form %}
@@ -0,0 +1,47 @@
1
+ ---
2
+ markform:
3
+ spec: MF/0.1
4
+ title: Project Plan
5
+ description: "Example plan document using implicit checkboxes - no explicit field wrappers needed."
6
+ roles:
7
+ - user
8
+ - agent
9
+ role_instructions:
10
+ user: "Review the plan and update task status as work progresses."
11
+ agent: "Track task completion and update checkbox states."
12
+ ---
13
+ <!-- form id="project_plan" title="Project Plan" -->
14
+
15
+ <!-- description ref="project_plan" -->
16
+ A project plan demonstrating Markform's implicit checkboxes feature.
17
+ When a form has no explicit field tags, checkboxes are automatically
18
+ collected into an implicit `checkboxes` field.
19
+ <!-- /description -->
20
+
21
+ ## Phase 1: Research
22
+
23
+ - [x] Review existing documentation <!-- #review_docs -->
24
+ - [x] Analyze competitor solutions <!-- #competitor_analysis -->
25
+ - [x] Interview stakeholders <!-- #stakeholder_interviews -->
26
+
27
+ ## Phase 2: Design
28
+
29
+ - [x] Create architecture document <!-- #arch_doc -->
30
+ - [x] Design API specification <!-- #api_spec -->
31
+ - [/] Review design with team <!-- #design_review -->
32
+
33
+ ## Phase 3: Implementation
34
+
35
+ - [*] Set up development environment <!-- #dev_setup -->
36
+ - [ ] Implement core functionality <!-- #core_impl -->
37
+ - [ ] Add unit tests <!-- #unit_tests -->
38
+ - [ ] Add integration tests <!-- #integration_tests -->
39
+
40
+ ## Phase 4: Release
41
+
42
+ - [ ] Write user documentation <!-- #user_docs -->
43
+ - [ ] Perform security audit <!-- #security_audit -->
44
+ - [-] Deploy to staging <!-- #staging_deploy -->
45
+ - [ ] Deploy to production <!-- #prod_deploy -->
46
+
47
+ <!-- /form -->