markform 0.1.6 → 0.1.8

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 (47) hide show
  1. package/README.md +464 -207
  2. package/dist/ai-sdk.d.mts +1 -2
  3. package/dist/ai-sdk.mjs +3 -2
  4. package/dist/{apply-DMQl-VVd.mjs → apply-BUU2QcJ2.mjs} +130 -23
  5. package/dist/bin.d.mts +0 -1
  6. package/dist/bin.mjs +3 -6
  7. package/dist/{cli-CXjkdym_.mjs → cli-BZh25bvy.mjs} +1380 -632
  8. package/dist/cli.d.mts +0 -1
  9. package/dist/cli.mjs +2 -6
  10. package/dist/coreTypes-BSPJ9H27.d.mts +3253 -0
  11. package/dist/{coreTypes-pyctKRgc.mjs → coreTypes-DJtu8OOp.mjs} +26 -4
  12. package/dist/index.d.mts +112 -5
  13. package/dist/index.mjs +6 -5
  14. package/dist/{session-uF0e6m6k.mjs → session-CmHdAPyg.mjs} +3 -2
  15. package/dist/session-DSTNiHza.mjs +4 -0
  16. package/dist/{shared-u22MtBRo.mjs → shared-C9yW5FLZ.mjs} +2 -1
  17. package/dist/{shared-DRlgu2ZJ.mjs → shared-DQ6y3Ggc.mjs} +3 -1
  18. package/dist/{src-o_5TSoHQ.mjs → src-kUggXhN1.mjs} +519 -98
  19. package/docs/markform-apis.md +30 -1
  20. package/docs/markform-reference.md +65 -6
  21. package/docs/markform-spec.md +2 -2
  22. package/examples/earnings-analysis/earnings-analysis.form.md +1 -0
  23. package/examples/movie-research/movie-research-basic.form.md +1 -0
  24. package/examples/movie-research/movie-research-deep.form.md +16 -56
  25. package/examples/movie-research/movie-research-demo.form.md +60 -0
  26. package/examples/rejection-test/rejection-test-mock-filled.form.md +41 -0
  27. package/examples/rejection-test/rejection-test-mock-filled.report.md +15 -0
  28. package/examples/rejection-test/rejection-test-mock-filled.schema.json +59 -0
  29. package/examples/rejection-test/rejection-test-mock-filled.yml +13 -0
  30. package/examples/rejection-test/rejection-test.form.md +35 -0
  31. package/examples/rejection-test/rejection-test.session.yaml +88 -0
  32. package/examples/simple/simple-mock-filled.report.md +96 -0
  33. package/examples/simple/simple-mock-filled.schema.json +374 -0
  34. package/examples/simple/simple-mock-filled.yml +87 -0
  35. package/examples/simple/simple-skipped-filled.report.md +90 -0
  36. package/examples/simple/simple-skipped-filled.schema.json +374 -0
  37. package/examples/simple/simple-skipped-filled.yml +77 -0
  38. package/examples/simple/simple-with-skips.session.yaml +3 -3
  39. package/examples/simple/simple.form.md +1 -0
  40. package/examples/simple/simple.schema.json +374 -0
  41. package/examples/simple/simple.session.yaml +3 -3
  42. package/examples/startup-deep-research/startup-deep-research.form.md +1 -0
  43. package/examples/startup-research/startup-research.form.md +1 -0
  44. package/package.json +11 -9
  45. package/dist/coreTypes-9XZSNOv6.d.mts +0 -8951
  46. package/dist/session-B_stoXQn.mjs +0 -4
  47. package/examples/movie-research/movie-research-minimal.form.md +0 -68
package/README.md CHANGED
@@ -1,57 +1,77 @@
1
1
  # Markform
2
2
 
3
- **Markform** turns Markdown documents into executable specifications for structured data
4
- collection.
5
- Define fields, validation rules, and instructions in a single `.form.md` file
6
- that is readable by humans, parseable by machines, and fillable by LLM agents.
7
-
8
- The core idea: **a form combines structure, unstructured context, and memory in a simple
9
- text document**. Users can give inputs via UIs or CLI. Agents can fill fields
10
- incrementally via tools or APIs.
11
- Validation catches errors early and humans can review or intervene at any point.
12
- The entire workflow is visible in a token-friendly text file you can read, diff, and
13
- version control.
3
+ **Markform** is a text format for defining structured forms that humans can read,
4
+ machines can parse, and agents can fill via tool calls.
5
+
6
+ Define instructions, fields, and validation rules in a single `.form.md` file.
7
+ Agents fill forms incrementally via patches.
8
+ Fields are validated, so errors are caught early and can be corrected.
9
+ Humans can review or intervene at any point.
10
+
11
+ **Why forms?** For deep research or complex AI tasks, you need more than just prompts or
12
+ flow: you need *structure*, which is precise control over agent output at every stage of
13
+ a workflow. A well-designed form combines instructions, structured data, and validations
14
+ in one place.
14
15
 
15
- Syntax is [Markdoc](https://github.com/markdoc/markdoc), which is Markdown extended with
16
- `{% tag %}` annotations, so LLMs are already quite good at writing Markform docs.
16
+ **How it works:**
17
17
 
18
- ## Why?
18
+ - A Markform document exposes a programmatic interface: users fill fields via CLI or web
19
+ UI, agents fill via tool calls ([Vercel AI SDK](https://github.com/vercel/ai)
20
+ integration included).
19
21
 
20
- Many agent workflow frameworks emphasize *prompts* and the *flow* of information (the
21
- *how*) over the desired *structure* of the results (the *what*). Markform lets you build
22
- agent workflows by structuring and validating *what* you want (the structure of
23
- information, validations, and reviews encoded in a form) instead of *how* to run a
24
- workflow as code (via explicit workflows or just an unstructured swarm of agents).
22
+ - Changes are explicit patch operations (`{ "op": "set_string", "fieldId": "name",
23
+ "value": "Alice" }`) validated against a schema specified in the form.
24
+ The agent sees validation errors and can self-correct.
25
25
 
26
- For centuries, humans have used paper forms to systematize and manage processes.
27
- A well-designed form with instructions, field definitions, and validations is a concise
28
- way to share context: background knowledge, goals, process rules, and memories.
29
- I don’t think AI changes this essential aspect of knowledge work.
30
- It’s time to bring bureaucracy to the agents.
26
+ - The format extends Markdown with a
27
+ [precise specification](https://github.com/jlevy/markform/blob/main/docs/markform-spec.md).
28
+ Export Markform syntax to JSON, YAML, JSON Schema, or plain Markdown reports.
29
+
30
+ Markform syntax is a good source format: token-efficient text you can read, diff, and
31
+ version control.
32
+ It is built with [Markdoc](https://github.com/markdoc/markdoc), which is
33
+ a Markdown extension from Stripe with Jinja-style `{% tag %}` annotations.
31
34
 
32
- There’s one more key benefit to this approach: LLMs are good at writing forms!
33
- Because the syntax is just Markdown with Jinja-style tags, agents can convert an
34
- informal Markdown doc describing a process to a precise Markform process easily.
35
+ ## Why Do Agents Need Forms?
35
36
 
36
- (For more, see [the FAQ](#faq).)
37
+ For centuries, humans have used paper forms and
38
+ [checklists](https://en.wikipedia.org/wiki/The_Checklist_Manifesto) to systematize
39
+ complex processes. A form with instructions, field definitions, and validations is a
40
+ concise way to share context: goals, background knowledge, process rules, and state
41
+ (memory). I don’t think AI changes this essential aspect of knowledge work.
42
+
43
+ Most agent frameworks focus on *prompts* and *flow* (the how) over the *structure* of
44
+ results (the what).
45
+ But for deep research or other multi-step workflows, you need precise
46
+ control over intermediate states and final output.
47
+ You don’t want that structure in a GUI (not token-friendly), in code (hard to update),
48
+ or dependent on model whims (changes unpredictably with model updates).
49
+
50
+ Forms solve this. Forms codify operational excellence.
51
+ They’re easy to read, easy to edit, and enforce standards.
52
+ Because LLMs handle Markdown and Jinja-style tags well, agents can also help create and
53
+ improve the forms themselves—closing the meta-loop.
54
+
55
+ It’s time to bring bureaucracy to the agents!
56
+ See [the FAQ](#faq) for more on the design.
37
57
 
38
58
  ## Quick Start
39
59
 
40
60
  ```bash
41
- # Try filling in one of a few example forms without installing.
42
- # First set OPENAI_API_KEY or ANTHROPIC_API_KEY in environment or .env file
43
- # to try the research examples.
44
- npx markform examples
61
+ # Copy example forms to ./forms/ and run one interactively.
62
+ # Set OPENAI_API_KEY or ANTHROPIC_API_KEY (or put in .env) for research examples
63
+ npx markform@latest examples
45
64
 
46
- # Read the docs
65
+ # Read the docs (tell your agents to run these; they are agent-friendly!)
47
66
  npx markform # CLI help
48
67
  npx markform readme # This file
49
- npx markform docs # Quick start for humans or agents to write Markforms
68
+ npx markform docs # Quick reference for writing Markforms
50
69
  npx markform spec # Read the full spec
51
70
  ```
52
71
 
53
- This lets you walk through a form interactively from the CLI, with the option to have an
54
- agent fill in parts of the form.
72
+ The `markform examples` command copies some sample forms to `./forms` and prompts you to
73
+ fill in a form interactively and then optionally have an agent complete it.
74
+ Pick `movie-research-demo.form.md` for a quick example.
55
75
 
56
76
  ## Installation
57
77
 
@@ -70,56 +90,92 @@ npm install markform
70
90
  ### Form Definition
71
91
 
72
92
  A `.form.md` file is simply a Markdoc file.
73
- It combines YAML frontmatter with Markdoc-tagged content:
93
+ It combines YAML frontmatter with Markdoc-tagged content.
74
94
 
75
- ```markdown
95
+ The text can be any Markdown.
96
+ The tags define things like fields:
97
+
98
+ ```jinja
99
+ {% field kind="string" id="movie" label="Movie" role="user"
100
+ required=true minLength=1 maxLength=300 %}{% /field %}
101
+
102
+ {% field kind="single_select" id="mpaa_rating" role="agent" label="MPAA Rating" %}
103
+ - [ ] G {% #g %}
104
+ - [ ] PG {% #pg %}
105
+ - [ ] PG-13 {% #pg_13 %}
106
+ - [ ] R {% #r %}
107
+ - [ ] NC-17 {% #nc_17 %}
108
+ - [ ] NR/Unrated {% #nr %}
109
+ {% /field %}
110
+ ```
111
+
112
+ Fields have types defined by the attributes.
113
+ Values are filled in incrementally, just like any form.
114
+ Once filled in, values appear directly inside the tags, in Markdown format:
115
+
116
+ ```jinja
117
+ {% field kind="string" id="movie" label="Movie" role="user"
118
+ required=true minLength=1 maxLength=300 %}
119
+ The Shawshank Redemption
120
+ {% /field %}
121
+
122
+ {% field kind="single_select" id="mpaa_rating" role="agent" label="MPAA Rating" %}
123
+ - [ ] G {% #g %}
124
+ - [ ] PG {% #pg %}
125
+ - [ ] PG-13 {% #pg_13 %}
126
+ - [X] R {% #r %}
127
+ - [ ] NC-17 {% #nc_17 %}
128
+ - [ ] NR/Unrated {% #nr %}
129
+ {% /field %}
130
+ ```
131
+
132
+ Note fields can have a `role="user"` to indicate they are filled interactively by the
133
+ user, or a `role="agent"` to indicate an agent should fill them in.
134
+
135
+ There are also tags for user or agent instructions per field or at form level and
136
+ grouping of forms.
137
+
138
+ Checkboxes and tables as values are supported!
139
+ Checkboxes can be single-select or multi-select.
140
+
141
+ Here’s a full example:
142
+
143
+ <details>
144
+
145
+ <summary>Markform for Movie Research Demo (click to expand)</summary>
146
+
147
+ ```jinja
76
148
  ---
77
149
  markform:
78
150
  spec: MF/0.1
79
- title: Movie Research (Minimal)
80
- description: Quick movie lookup with just the essentials (title, year, ratings, summary).
151
+ title: Movie Research Demo
152
+ description: Movie lookup with ratings from IMDB and Rotten Tomatoes.
153
+ run_mode: research
81
154
  roles:
82
155
  - user
83
156
  - agent
84
157
  role_instructions:
85
158
  user: "Enter the movie title."
86
159
  agent: |
87
- Quickly identify the movie and fill in basic info from IMDB.
88
- This is a minimal lookup - just get the core facts.
160
+ Identify the movie with web searches and use imdb.com and rottentomatoes.com to fill in the ratings.
89
161
  ---
90
- {% form id="movie_research_minimal" title="Movie Research (Minimal)" %}
162
+ {% form id="movie_research_demo" %}
163
+ {% group id="movie_input" %}
91
164
 
92
- ## Movie Research Example
93
-
94
- {% group id="movie_input" title="Movie Identification" %}
95
-
96
- What movie do you want to research? \[*This field is filled in by the user (`role="user"`).*\]
165
+ ## What movie do you want to research?
97
166
 
98
167
  {% field kind="string" id="movie" label="Movie" role="user" required=true minLength=1 maxLength=300 %}{% /field %}
99
168
  {% instructions ref="movie" %}Enter the movie title (add year or details for disambiguation).{% /instructions %}
100
169
 
101
170
  {% /group %}
102
171
 
103
- ## About the Movie
104
-
105
172
  {% group id="about_the_movie" title="About the Movie" %}
106
173
 
107
- **Title:**
174
+ ## Movie Ratings
108
175
 
109
- {% field kind="string" id="full_title" label="Full Title" role="agent" required=true %}{% /field %}
110
- {% instructions ref="full_title" %}Official title, including subtitle if any.{% /instructions %}
176
+ Here are the ratings for the movie:
111
177
 
112
- **Release year:**
113
-
114
- {% field kind="number" id="year" label="Release Year" role="agent" required=true min=1888 max=2030 %}{% /field %}
115
-
116
- **IMDB:**
117
-
118
- {% field kind="url" id="imdb_url" label="IMDB URL" role="agent" required=true %}{% /field %}
119
-
120
- **MPAA rating:**
121
-
122
- {% field kind="single_select" id="mpaa_rating" label="MPAA Rating" role="agent" %}
178
+ {% field kind="single_select" id="mpaa_rating" role="agent" label="MPAA Rating" %}
123
179
  - [ ] G {% #g %}
124
180
  - [ ] PG {% #pg %}
125
181
  - [ ] PG-13 {% #pg_13 %}
@@ -128,64 +184,191 @@ What movie do you want to research? \[*This field is filled in by the user (`rol
128
184
  - [ ] NR/Unrated {% #nr %}
129
185
  {% /field %}
130
186
 
131
- **IMDB rating:**
132
-
133
- {% field kind="number" id="imdb_rating" label="IMDB Rating" role="agent" min=1.0 max=10.0 %}{% /field %}
134
- {% instructions ref="imdb_rating" %}IMDB user rating (1.0-10.0 scale).{% /instructions %}
135
-
136
- **Summary:**
187
+ {% field kind="table" id="ratings_table" role="agent"
188
+ label="Ratings" required=true
189
+ columnIds=["source", "score", "votes"] columnTypes=["string", "number", "number"]
190
+ minRows=0 maxRows=3 %}
191
+ | Source | Score | Votes |
192
+ |--------|-------|-------|
193
+ {% /field %}
137
194
 
138
- {% field kind="string" id="logline" label="One-Line Summary" role="agent" maxLength=300 %}{% /field %}
139
- {% instructions ref="logline" %}Brief plot summary in 1-2 sentences, no spoilers.{% /instructions %}
195
+ {% instructions ref="ratings_table" %}
196
+ Fill in scores and vote counts from each source:
197
+ - IMDB: Rating (1.0-10.0 scale), vote count
198
+ - RT Critics: Tomatometer (0-100%), review count
199
+ - RT Audience: Audience Score (0-100%), rating count
200
+ {% /instructions %}
140
201
 
141
202
  {% /group %}
142
-
143
203
  {% /form %}
144
204
  ```
145
205
 
206
+ </details>
207
+
146
208
  ### Form Report Output
147
209
 
148
- Run the `npx markform examples` and select the `Movie Research (Minimal)` example and
149
- view the report:
210
+ Run `npx markform examples` to copy examples, then `npx markform run` and select `Movie
211
+ Research Demo` to fill it.
150
212
 
151
- ```markdown
152
- # Movie Research (Minimal)
213
+ A form can be exported
214
+
215
+ - as the filled form (Markform format, just like the input)
153
216
 
154
- ## Movie Identification
217
+ - as a report (plain Markdown)
155
218
 
219
+ - as values (YAML or JSON)
220
+
221
+ - as a JSON schema (just the structure)
222
+
223
+ The report output (using `gpt-5-mini` to fill it in) looks like:
224
+
225
+ ```markdown
156
226
  Movie:
157
- shawshank redemption
227
+ The Shawshank Redemption
158
228
 
159
229
  ## About the Movie
160
230
 
161
- Full Title:
231
+ MPAA Rating:
232
+ R
233
+
234
+ Ratings:
235
+ | Source | Score | Votes |
236
+ | --- | --- | --- |
237
+ | IMDB | 9.3 | 3100000 |
238
+ | RT Critics | 89 | 146 |
239
+ | RT Audience | 98 | 250000 |
240
+ ```
241
+
242
+ Here is the schema and YAML values for the form above.
243
+
244
+ <details> <summary>Filled Markform (click to expand)</summary>
245
+
246
+ ````jinja
247
+ {% form id="movie_research_demo" %}
248
+
249
+ {% group id="movie_input" %}
250
+
251
+ {% field kind="string" id="movie" role="user" label="Movie" maxLength=300 minLength=1 required=true %}
252
+ ```value
162
253
  The Shawshank Redemption
254
+ ```
255
+ {% /field %}
163
256
 
164
- Release Year:
165
- 1994
257
+ {% instructions ref="movie" %}
258
+ Enter the movie title (add year or details for disambiguation).
259
+ {% /instructions %}
166
260
 
167
- IMDB URL:
168
- https://www.imdb.com/title/tt0111161/
261
+ {% /group %}
169
262
 
170
- MPAA Rating:
171
- R
263
+ {% group id="about_the_movie" title="About the Movie" %}
172
264
 
173
- IMDB Rating:
174
- 9.3
265
+ {% field kind="single_select" id="mpaa_rating" label="MPAA Rating" %}
266
+ - [ ] G {% #g %}
267
+ - [ ] PG {% #pg %}
268
+ - [ ] PG-13 {% #pg_13 %}
269
+ - [x] R {% #r %}
270
+ - [ ] NC-17 {% #nc_17 %}
271
+ - [ ] NR/Unrated {% #nr %}
272
+ {% /field %}
175
273
 
176
- One-Line Summary:
177
- Convicted banker Andy Dufresne is sent to Shawshank State Penitentiary, where he forms an unexpected friendship with inmate Red while holding onto hope and striving to maintain his dignity in a corrupt prison system.
274
+ {% field kind="table" id="ratings_table"
275
+ columnIds=["source", "score", "votes"] columnLabels=["Source", "Score", "Votes"]
276
+ columnTypes=["string", "number", "number"]
277
+ label="Ratings" maxRows=3 minRows=0 required=true %}
278
+ | Source | Score | Votes |
279
+ | --- | --- | --- |
280
+ | IMDB | 9.3 | 3100000 |
281
+ | RT Critics | 89 | 146 |
282
+ | RT Audience | 98 | 250000 |
283
+ {% /field %}
284
+
285
+ {% instructions ref="ratings_table" %}
286
+ Fill in scores and vote counts from each source:IMDB: Rating (1.0-10.0 scale), vote countRT Critics: Tomatometer (0-100%), review countRT Audience: Audience Score (0-100%), rating count
287
+ {% /instructions %}
288
+
289
+ {% /group %}
290
+
291
+ {% /form %}
292
+ ````
293
+
294
+ </details>
295
+
296
+ <details> <summary>YAML Export (click to expand)</summary>
297
+
298
+ ```yaml
299
+ values:
300
+ movie:
301
+ state: answered
302
+ value: The Shawshank Redemption
303
+ mpaa_rating:
304
+ state: answered
305
+ value: r
306
+ ratings_table:
307
+ state: answered
308
+ value:
309
+ - source: IMDB
310
+ score: 9.3
311
+ votes: 3100000
312
+ - source: RT Critics
313
+ score: 89
314
+ votes: 146
315
+ - source: RT Audience
316
+ score: 98
317
+ votes: 250000
318
+ ```
319
+
320
+ </details>
321
+
322
+ <details> <summary>JSON Schema (click to expand)</summary>
323
+
324
+ ```json
325
+ {
326
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
327
+ "$id": "movie_research_demo",
328
+ "type": "object",
329
+ "properties": {
330
+ "movie": {
331
+ "type": "string",
332
+ "title": "Movie",
333
+ "minLength": 1,
334
+ "maxLength": 300
335
+ },
336
+ "mpaa_rating": {
337
+ "type": "string",
338
+ "enum": ["g", "pg", "pg_13", "r", "nc_17", "nr"],
339
+ "title": "MPAA Rating"
340
+ },
341
+ "ratings_table": {
342
+ "type": "array",
343
+ "items": {
344
+ "type": "object",
345
+ "properties": {
346
+ "source": { "title": "Source", "type": "string" },
347
+ "score": { "title": "Score", "type": "number" },
348
+ "votes": { "title": "Votes", "type": "number" }
349
+ }
350
+ },
351
+ "title": "Ratings",
352
+ "minItems": 0,
353
+ "maxItems": 3
354
+ }
355
+ },
356
+ "required": ["movie", "ratings_table"]
357
+ }
178
358
  ```
179
359
 
360
+ </details>
361
+
180
362
  ### More Example Forms
181
363
 
182
364
  The package includes example forms.
183
- View them with `markform examples --list` or try these interactively:
365
+ View them with `markform examples --list`, copy with `markform examples`, and run with
366
+ `markform run`:
184
367
 
185
368
  - [`simple.form.md`](https://github.com/jlevy/markform/blob/main/packages/markform/examples/simple/simple.form.md)
186
369
  \- Basic form demonstrating all field kinds.
187
370
 
188
- - [`movie-research-minimal.form.md`](https://github.com/jlevy/markform/blob/main/packages/markform/examples/movie-research/movie-research-minimal.form.md)
371
+ - [`movie-research-demo.form.md`](https://github.com/jlevy/markform/blob/main/packages/markform/examples/movie-research/movie-research-demo.form.md)
189
372
  \- The quick example above.
190
373
 
191
374
  - [`movie-research-basic.form.md`](https://github.com/jlevy/markform/blob/main/packages/markform/examples/movie-research/movie-research-basic.form.md)
@@ -196,20 +379,103 @@ View them with `markform examples --list` or try these interactively:
196
379
 
197
380
  - [`earnings-analysis.form.md`](https://github.com/jlevy/markform/blob/main/packages/markform/examples/earnings-analysis/earnings-analysis.form.md)
198
381
  \- Financial analysis form.
382
+ ## Architecture
383
+
384
+ This repo has a specification and an implementation.
385
+ The implementation is a TypeScript API with Vercel AI SDK integration, and a CLI
386
+ interface.
387
+
388
+ ```mermaid
389
+ flowchart LR
390
+ subgraph SPEC["<b>MARKFORM SPEC</b>"]
391
+ direction TB
392
+
393
+ subgraph L1["<b>LAYER 1: SYNTAX</b><br/>Markdoc tag syntax and frontmatter (form, group, string-field, checkboxes, etc.)"]
394
+ end
395
+
396
+ subgraph L2["<b>LAYER 2: FORM DATA MODEL</b><br/>Schema definitions for forms, fields, values (in Zod but mappable to JSON Schema or Pydantic)"]
397
+ end
398
+
399
+ subgraph L3["<b>LAYER 3: VALIDATION & FORM FILLING</b><br/>Rules for filling forms via patches, field ids, required field semantics, validation hooks"]
400
+ end
401
+
402
+ subgraph L4["<b>LAYER 4: TOOL API & INTERFACES</b><br/>Abstract API for agents and humans (TypeScript and AI SDK integration)"]
403
+ end
404
+
405
+ L4 --> L3 --> L2 --> L1
406
+ end
407
+
408
+ subgraph IMPL["<b>THIS IMPLEMENTATION</b>"]
409
+ direction TB
410
+
411
+ subgraph CLI["<b>`markform` CLI</b><br/>Command-line interface to all features"]
412
+ end
413
+
414
+ subgraph AGENT["<b>AGENT TOOL INTERFACE</b><br/>Tool API library using AI SDK tools"]
415
+ end
416
+
417
+ subgraph HARNESS["<b>EXECUTION HARNESS</b><br/>Step-by-step form-filling agentic loop"]
418
+ end
419
+
420
+ subgraph ENGINE["<b>CORE TYPESCRIPT APIS</b><br/>Markdoc parser, serializer, patch application, validation (uses jiti for TypeScript rules)"]
421
+ end
422
+
423
+ subgraph TEST["<b>TESTING FRAMEWORK</b><br/>Golden session testing with .session.yaml transcripts"]
424
+ end
425
+
426
+ CLI --> ENGINE
427
+ CLI --> HARNESS
428
+ AGENT --> HARNESS
429
+ AGENT --> ENGINE
430
+ HARNESS --> ENGINE
431
+ ENGINE --> TEST
432
+ end
433
+
434
+ SPEC ~~~ IMPL
435
+
436
+ style SPEC fill:#e8f4f8,stroke:#0077b6
437
+ style L1 fill:#caf0f8,stroke:#0077b6
438
+ style L2 fill:#caf0f8,stroke:#0077b6
439
+ style L3 fill:#caf0f8,stroke:#0077b6
440
+ style L4 fill:#caf0f8,stroke:#0077b6
441
+ style IMPL fill:#fff3e6,stroke:#fb8500
442
+ style ENGINE fill:#ffe8cc,stroke:#fb8500
443
+ style CLI fill:#ffe8cc,stroke:#fb8500
444
+ style AGENT fill:#ffe8cc,stroke:#fb8500
445
+ style HARNESS fill:#ffe8cc,stroke:#fb8500
446
+ style TEST fill:#ffe8cc,stroke:#fb8500
447
+ ```
199
448
 
200
449
  ## CLI Commands
201
450
 
202
- ### Explore Examples
451
+ ### Copy and Run Examples
203
452
 
204
453
  ```bash
205
- # Interactive: select an example, fill it, optionally run agent
454
+ # Copy all bundled examples to ./forms/
206
455
  markform examples
207
456
 
208
457
  # List available examples
209
458
  markform examples --list
210
459
 
211
- # Start with a specific example
212
- markform examples --name political-research
460
+ # Copy a specific example
461
+ markform examples --name movie-research-demo
462
+ ```
463
+
464
+ ### Browse and Run Forms
465
+
466
+ ```bash
467
+ # Browse forms in ./forms/ and run one interactively
468
+ markform run
469
+
470
+ # Run a specific form directly
471
+ markform run forms/movie-research-demo.form.md
472
+ ```
473
+
474
+ ### Check Form Status
475
+
476
+ ```bash
477
+ # Show fill progress with per-role breakdown
478
+ markform status my-form.form.md
213
479
  ```
214
480
 
215
481
  ### Inspect Forms
@@ -251,11 +517,24 @@ markform export my-form.form.md --format=yaml
251
517
  markform dump my-form.form.md
252
518
  ```
253
519
 
520
+ ### Export JSON Schema
521
+
522
+ ```bash
523
+ # Export form structure as JSON Schema (for validation, code generation, etc.)
524
+ markform schema my-form.form.md
525
+
526
+ # Pure JSON Schema without Markform extensions
527
+ markform schema my-form.form.md --pure
528
+
529
+ # Specify JSON Schema draft version
530
+ markform schema my-form.form.md --draft draft-07
531
+ ```
532
+
254
533
  ### Apply Patches
255
534
 
256
535
  ```bash
257
536
  # Apply a JSON patch to update field values
258
- markform apply my-form.form.md --patch '[{"op":"set","fieldId":"name","value":"Alice"}]'
537
+ markform apply my-form.form.md --patch '[{"op":"set_string","fieldId":"name","value":"Alice"}]'
259
538
  ```
260
539
 
261
540
  ### Web Interface
@@ -287,88 +566,25 @@ markform models
287
566
  markform --help
288
567
  ```
289
568
 
290
- ## Supported Providers
291
-
292
- Standard LLMs can be used to fill in forms or create research reports from form
293
- templates. The package currently has support for these models built in, and enables web
294
- search tools for them if possible.
295
-
296
- | Provider | Env Variable | Example Models |
297
- | --- | --- | --- |
298
- | openai | `OPENAI_API_KEY` | gpt-5-mini, gpt-5.1, gpt-5.2 |
299
- | anthropic | `ANTHROPIC_API_KEY` | claude-sonnet-4-5, claude-opus-4-5 |
300
- | google | `GOOGLE_API_KEY` | gemini-2.5-pro, gemini-2.5-flash |
301
- | xai | `XAI_API_KEY` | grok-4, grok-4-fast |
302
- | deepseek | `DEEPSEEK_API_KEY` | deepseek-chat, deepseek-reasoner |
569
+ ## API Key Setup
303
570
 
304
571
  Set the appropriate environment variable for your provider before running `markform
305
- fill`. See
572
+ fill`:
573
+
574
+ | Provider | Env Variable | Native Web Search |
575
+ | --- | --- | :---: |
576
+ | openai | `OPENAI_API_KEY` | ✓ |
577
+ | anthropic | `ANTHROPIC_API_KEY` | ✓ |
578
+ | google | `GOOGLE_API_KEY` | ✓ |
579
+ | xai | `XAI_API_KEY` | ✓ |
580
+ | deepseek | `DEEPSEEK_API_KEY` | ✗ |
581
+
582
+ Run `markform models` to see available models.
583
+ See
306
584
  [`src/settings.ts`](https://github.com/jlevy/markform/blob/main/packages/markform/src/settings.ts)
307
- for the full list of models.
585
+ for defaults.
308
586
 
309
- ## Architecture
310
-
311
- ```mermaid
312
- flowchart LR
313
- subgraph SPEC["<b>MARKFORM SPEC</b>"]
314
- direction TB
315
-
316
- subgraph L1["<b>LAYER 1: SYNTAX</b><br/>Markdoc tag syntax and frontmatter (form, group, string-field, checkboxes, etc.)"]
317
- end
318
-
319
- subgraph L2["<b>LAYER 2: FORM DATA MODEL</b><br/>Schema definitions for forms, fields, values (in Zod but mappable to JSON Schema or Pydantic)"]
320
- end
321
-
322
- subgraph L3["<b>LAYER 3: VALIDATION & FORM FILLING</b><br/>Rules for filling forms via patches, field ids, required field semantics, validation hooks"]
323
- end
324
-
325
- subgraph L4["<b>LAYER 4: TOOL API & INTERFACES</b><br/>Abstract API for agents and humans (TypeScript and AI SDK integration)"]
326
- end
327
-
328
- L4 -->
329
-
330
- L3 --> L2 --> L1
331
- end
332
-
333
- subgraph IMPL["<b>THIS IMPLEMENTATION</b>"]
334
- direction TB
335
-
336
- subgraph ENGINE["<b>ENGINE IMPLEMENTATION</b><br/>Markdoc parser, serializer, patch application, validation (uses jiti for TypeScript rules)"]
337
- end
338
-
339
- subgraph UI["<b>USER INTERFACES</b><br/>CLI commands, web UI (serve), render to HTML"]
340
- end
341
-
342
- subgraph AGENT["<b>AGENT INTERFACES</b><br/>Tool API library, MCP server, AI SDK tools"]
343
- end
344
-
345
- subgraph HARNESS["<b>EXECUTION HARNESS</b><br/>Step-by-step form-filling agentic loop"]
346
- end
347
-
348
- subgraph TEST["<b>TESTING FRAMEWORK</b><br/>Golden session testing with .session.yaml transcripts"]
349
- end
350
-
351
- UI --> ENGINE
352
- AGENT --> HARNESS
353
- AGENT --> ENGINE
354
- HARNESS --> ENGINE
355
- ENGINE --> TEST
356
- end
357
-
358
- SPEC ~~~ IMPL
359
-
360
- style SPEC fill:#e8f4f8,stroke:#0077b6
361
- style L1 fill:#caf0f8,stroke:#0077b6
362
- style L2 fill:#caf0f8,stroke:#0077b6
363
- style L3 fill:#caf0f8,stroke:#0077b6
364
- style L4 fill:#caf0f8,stroke:#0077b6
365
- style IMPL fill:#fff3e6,stroke:#fb8500
366
- style ENGINE fill:#ffe8cc,stroke:#fb8500
367
- style UI fill:#ffe8cc,stroke:#fb8500
368
- style AGENT fill:#ffe8cc,stroke:#fb8500
369
- style HARNESS fill:#ffe8cc,stroke:#fb8500
370
- style TEST fill:#ffe8cc,stroke:#fb8500
371
- ```
587
+ If unsure, try `gpt-5-mini` first as it’s fast and supports web search.
372
588
 
373
589
  ## Programmatic Usage
374
590
 
@@ -401,10 +617,14 @@ import { createMarkformTools, MarkformSessionStore } from "markform/ai-sdk";
401
617
  import { generateText } from "ai";
402
618
  import { anthropic } from "@ai-sdk/anthropic";
403
619
 
620
+ // Parse form and create session store (tracks state across tool calls)
404
621
  const form = parseForm(markdownContent);
405
622
  const store = new MarkformSessionStore(form);
623
+
624
+ // Create tools the agent can call: inspect, apply patches, export
406
625
  const tools = createMarkformTools({ sessionStore: store });
407
626
 
627
+ // Agent fills the form via tool calls until complete or maxSteps reached
408
628
  const result = await generateText({
409
629
  model: anthropic("claude-sonnet-4-5-20250929"),
410
630
  prompt: "Fill out this form with appropriate values...",
@@ -422,11 +642,32 @@ const result = await generateText({
422
642
  | `markform_export` | Export schema and values as JSON |
423
643
  | `markform_get_markdown` | Get canonical Markdown representation |
424
644
 
645
+ ## Other Documentation
646
+
647
+ - **[Quick
648
+ Reference](https://github.com/jlevy/markform/blob/main/docs/markform-reference.md)**
649
+ (or run `markform docs`) — Concise syntax reference (agent-friendly)
650
+
651
+ - **[Markform Spec](https://github.com/jlevy/markform/blob/main/docs/markform-spec.md)**
652
+ (or run `markform spec`) — Complete syntax and semantics
653
+
654
+ - **[API
655
+ Documentation](https://github.com/jlevy/markform/blob/main/docs/markform-apis.md)**
656
+ (or run `markform apis`) — TypeScript and AI SDK APIs
657
+
658
+ - **[Design
659
+ Doc](https://github.com/jlevy/markform/blob/main/docs/project/architecture/current/arch-markform-design.md)**
660
+ — Technical design and roadmap
661
+
662
+ - **[Development](https://github.com/jlevy/markform/blob/main/docs/development.md)** —
663
+ Build, test, and contribute
664
+
425
665
  ## FAQ
426
666
 
427
- ### Can you say more why this is a good idea?
667
+ ### Can you talk more about why forms are cool?
428
668
 
429
- Yes! I’ve come to believe forms are a missing piece of the workflow problem with agents.
669
+ As a matter of fact, I can!
670
+ I’ve come to believe forms are a missing piece of the workflow problem with agents.
430
671
  For deep research or complex multi-step workflows, key pieces need to be *precisely
431
672
  controlled*, *domain-specific*, and *always improving*. You need precise documentation
432
673
  on the key intermediate states and final output from an AI pipeline.
@@ -437,6 +678,27 @@ Forms define these pieces and are easy to edit.
437
678
  All other choices can be left to the agents themselves, with the structure and
438
679
  validations enforced by the form-filling tools the agents use.
439
680
 
681
+ Another cool thing about forms: they get rid of the inefficiencies of conversation chat
682
+ history.
683
+ Often when an agentic loop is built, it just saves the chat history for context.
684
+ But a form is inherently more efficient: the harness itself can be stateless.
685
+ It just shares the partly-filled form with the agent, and it has full context in one
686
+ message. That’s what the agentic loop in this implementation does.
687
+
688
+ Finally, the meta-loop of *creating and improving* forms is easier to automate:
689
+
690
+ - To get started, you can ask a good coding model to convert any unstructured doc
691
+ describing a process to a form.
692
+ The model can also use the CLI or tools to validate and test it.
693
+
694
+ - Any time you have a workflow problem, you can ask an LLM to diagnose it and if
695
+ possible, go back and fix up the form with additional instructions or fields or checks
696
+ that would prevent the problem from happening again.
697
+
698
+ I suspect dynamic form structures like this could make complex deep research more
699
+ powerful. Just as you plan a spec before implementing with a coding agent, you could use
700
+ Markform to encode a research plan before dispatching agents to fill it.
701
+
440
702
  ### Is this mature?
441
703
 
442
704
  No! I just wrote it.
@@ -445,10 +707,24 @@ But it’s been useful for me already.
445
707
 
446
708
  ### Was it Vibe Coded?
447
709
 
448
- It’s all written by LLMs but using a strongly spec-driven process, using rules from
449
- [Speculate](https://github.com/jlevy/speculate).
450
- See [the spec](docs/markform-spec.md) and the architecture docs and specs in
451
- [docs/](docs/).
710
+ This is 100% agent-written code and the planning specs are also 100% agent written,
711
+ using a mix of Opus 4.5, GPT 5.2, GPT-5 Pro, Gemini 3, and occasionally others.
712
+
713
+ But it’s not slop. It is written via a strongly spec-driven process, using rules from my
714
+ [Speculate](https://github.com/jlevy/speculate) repo and Steve Yegge’s
715
+ [beads](https://github.com/steveyegge/beads) for tracking work.
716
+
717
+ See
718
+ [my post](https://github.com/jlevy/speculate/blob/main/about/lessons_in_spec_coding.md)
719
+ for more thoughts on how this works.
720
+ And see [the complete history of
721
+ specs](https://github.com/jlevy/markform/tree/main/docs/project/specs/done) for examples
722
+ of how everything is done with specs.
723
+
724
+ Although I didn’t write much code, there was a *lot* of management, review, and
725
+ iteration on design decisions.
726
+ And yes, this README is written by me.
727
+ :)
452
728
 
453
729
  ### What are the goals of Markform?
454
730
 
@@ -504,13 +780,14 @@ The closest alternatives are:
504
780
  human-friendly UI. But these do not have a human-friendly text format for use by
505
781
  agents as well as humans.
506
782
 
507
- | Approach | Has GUI | Human-readable source format | Agent-editable | APIs and validation rules |
783
+ | Approach | Usable GUI editor | Human-readable source format | Agent-editable | APIs and validation rules |
508
784
  | --- | :---: | :---: | :---: | :---: |
509
- | Plain Markdown | ☑️ existing tools | ✅ | ⚠️ fragile | ❌ |
510
- | JSON with schema | ⚠️ in some apps | ⚠️ um it’s JSON | ✅ | ✅ |
511
- | SaaS tools (Typeform, Docusign, PDF forms) | ✅ | ⚠️ rarely | ⚠️ if they add it | ⚠️ if they add it |
512
- | Excel/Google Sheets | ✅ | .csv (poor) or .xlsx (worse) | ⚠️ with tools | ✅ with some coding |
513
- | **Markform** | ☑️ existing tools | | with this package | ✅ with this package |
785
+ | Plain Markdown | IDEs/editors | ✅ | ⚠️ fragile | ❌ |
786
+ | JSON + JSON Schema | IDEs/editors | ⚠️ no free text | ✅ | ✅ |
787
+ | SaaS tools (Typeform, Docusign, PDF forms) | ✅ | ⚠️ rarely | ⚠️ sometimes | ⚠️ sometimes |
788
+ | HTML/web Forms | ✅ IDEs/editors | ⚠️ HTML+code | ⚠️ coding agent | ✅ |
789
+ | Excel/Google Sheets | app | .csv/.xlsx | ⚠️ with tools | ✅ with some coding |
790
+ | **Markform** | ✅ IDEs/editors | ✅ | ✅ with this package | ✅ with this package |
514
791
 
515
792
  ### What are example use cases?
516
793
 
@@ -552,26 +829,6 @@ settings:
552
829
 
553
830
  Or see [markdoc/language-server](https://github.com/markdoc/language-server).
554
831
 
555
- ## Documentation
556
-
557
- - **[Quick
558
- Reference](https://github.com/jlevy/markform/blob/main/docs/markform-reference.md)**
559
- (or run `markform docs`) - Concise syntax reference (agent-friendly)
560
-
561
- - **[Markform Spec](https://github.com/jlevy/markform/blob/main/docs/markform-spec.md)**
562
- (or run `markform spec`) - Complete syntax and semantics
563
-
564
- - **[API
565
- Documentation](https://github.com/jlevy/markform/blob/main/docs/markform-apis.md)**
566
- (or run `markform apis`) - TypeScript and AI SDK APIs
567
-
568
- - **[Design
569
- Doc](https://github.com/jlevy/markform/blob/main/docs/project/architecture/current/arch-markform-design.md)**
570
- \- Technical design and roadmap
571
-
572
- - **[Development](https://github.com/jlevy/markform/blob/main/docs/development.md)** -
573
- Build, test, and contribute
574
-
575
832
  ## License
576
833
 
577
834
  AGPL-3.0-or-later. [Contact me](https://github.com/jlevy) for additional licensing