markform 0.1.3 → 0.1.5
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.
- package/README.md +110 -70
- package/dist/ai-sdk.d.mts +2 -2
- package/dist/ai-sdk.mjs +5 -5
- package/dist/{apply-00UmzDKL.mjs → apply-BCCiJzQr.mjs} +371 -26
- package/dist/bin.mjs +6 -6
- package/dist/{cli-D--Lel-e.mjs → cli-D469amuk.mjs} +386 -96
- package/dist/cli.mjs +6 -6
- package/dist/{coreTypes-BXhhz9Iq.d.mts → coreTypes-9XZSNOv6.d.mts} +1878 -325
- package/dist/{coreTypes-Dful87E0.mjs → coreTypes-pyctKRgc.mjs} +79 -5
- package/dist/index.d.mts +142 -5
- package/dist/index.mjs +5 -5
- package/dist/session-B_stoXQn.mjs +4 -0
- package/dist/{session-Bqnwi9wp.mjs → session-uF0e6m6k.mjs} +9 -5
- package/dist/{shared-N_s1M-_K.mjs → shared-BqPnYXrn.mjs} +82 -1
- package/dist/shared-CZsyShck.mjs +3 -0
- package/dist/{src-Dm8jZ5dl.mjs → src-Df0XX7UB.mjs} +818 -125
- package/docs/markform-apis.md +194 -0
- package/{DOCS.md → docs/markform-reference.md} +130 -69
- package/{SPEC.md → docs/markform-spec.md} +359 -108
- package/examples/earnings-analysis/earnings-analysis.form.md +88 -800
- package/examples/earnings-analysis/earnings-analysis.valid.ts +16 -148
- package/examples/movie-research/movie-research-basic.form.md +41 -37
- package/examples/movie-research/movie-research-deep.form.md +110 -98
- package/examples/movie-research/movie-research-minimal.form.md +29 -15
- package/examples/simple/simple-mock-filled.form.md +105 -41
- package/examples/simple/simple-skipped-filled.form.md +103 -41
- package/examples/simple/simple-with-skips.session.yaml +93 -25
- package/examples/simple/simple.form.md +86 -32
- package/examples/simple/simple.session.yaml +98 -25
- package/examples/startup-deep-research/startup-deep-research.form.md +130 -103
- package/examples/startup-research/startup-research-mock-filled.form.md +55 -55
- package/examples/startup-research/startup-research.form.md +36 -36
- package/package.json +18 -19
- package/dist/session-DdAtY2Ni.mjs +0 -4
- package/dist/shared-D7gf27Tr.mjs +0 -3
- package/examples/celebrity-deep-research/celebrity-deep-research.form.md +0 -912
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Markform APIs
|
|
2
|
+
|
|
3
|
+
Markform provides TypeScript APIs for parsing, validating, and manipulating forms
|
|
4
|
+
programmatically.
|
|
5
|
+
|
|
6
|
+
## CLI
|
|
7
|
+
|
|
8
|
+
The `markform` CLI is self-documenting:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
markform --help # List all commands
|
|
12
|
+
markform <command> --help # Help for specific command
|
|
13
|
+
markform docs # Form syntax quick reference
|
|
14
|
+
markform spec # Full specification
|
|
15
|
+
markform apis # This document
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Form syntax:** See [markform-reference.md](markform-reference.md) for the quick
|
|
19
|
+
reference on form syntax, field kinds, and attributes.
|
|
20
|
+
|
|
21
|
+
## Project Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install markform
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Core Engine API
|
|
28
|
+
|
|
29
|
+
Import from the main package:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import {
|
|
33
|
+
parseForm,
|
|
34
|
+
serialize,
|
|
35
|
+
validate,
|
|
36
|
+
inspect,
|
|
37
|
+
applyPatches,
|
|
38
|
+
} from 'markform';
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### parseForm(content: string): ParsedForm
|
|
42
|
+
|
|
43
|
+
Parse a `.form.md` file into a structured form object.
|
|
44
|
+
|
|
45
|
+
### serialize(form: ParsedForm, options?: SerializeOptions): string
|
|
46
|
+
|
|
47
|
+
Convert a parsed form back to Markdown.
|
|
48
|
+
|
|
49
|
+
### validate(form: ParsedForm, options?: ValidateOptions): ValidateResult
|
|
50
|
+
|
|
51
|
+
Validate form syntax and constraints.
|
|
52
|
+
|
|
53
|
+
### inspect(form: ParsedForm, options?: InspectOptions): InspectResult
|
|
54
|
+
|
|
55
|
+
Get form state including structure, progress, and validation issues.
|
|
56
|
+
|
|
57
|
+
### applyPatches(form: ParsedForm, patches: Patch[]): ApplyResult
|
|
58
|
+
|
|
59
|
+
Apply value changes to a form.
|
|
60
|
+
Modifies the form in place.
|
|
61
|
+
|
|
62
|
+
## Vercel AI SDK Integration
|
|
63
|
+
|
|
64
|
+
Import from the ai-sdk subpath:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import {
|
|
68
|
+
createMarkformTools,
|
|
69
|
+
MarkformSessionStore
|
|
70
|
+
} from 'markform/ai-sdk';
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### MarkformSessionStore
|
|
74
|
+
|
|
75
|
+
Session store for managing form state during AI interactions.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
const store = new MarkformSessionStore(parsedForm);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### createMarkformTools(options): MarkformToolSet
|
|
82
|
+
|
|
83
|
+
Create AI SDK compatible tools for agent-driven form filling.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { generateText } from 'ai';
|
|
87
|
+
|
|
88
|
+
const tools = createMarkformTools({ sessionStore: store });
|
|
89
|
+
const { text } = await generateText({
|
|
90
|
+
model: yourModel,
|
|
91
|
+
tools,
|
|
92
|
+
prompt: 'Fill out this form...',
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Available tools:**
|
|
97
|
+
|
|
98
|
+
| Tool | Description |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| `markform_inspect` | Get form state, structure, progress, issues |
|
|
101
|
+
| `markform_apply` | Apply patches to update field values |
|
|
102
|
+
| `markform_export` | Export schema and values as JSON |
|
|
103
|
+
| `markform_get_markdown` | Get canonical Markdown representation |
|
|
104
|
+
|
|
105
|
+
See [vercelAiSdkTools.ts](../packages/markform/src/integrations/vercelAiSdkTools.ts) for
|
|
106
|
+
full details.
|
|
107
|
+
|
|
108
|
+
### Patch Operations
|
|
109
|
+
|
|
110
|
+
Use `markform_apply` with an array of patches.
|
|
111
|
+
Each patch has an `op` and `fieldId`.
|
|
112
|
+
|
|
113
|
+
| Operation | Fields | Value Format |
|
|
114
|
+
| --- | --- | --- |
|
|
115
|
+
| `set_string` | string | `{ "op": "set_string", "fieldId": "name", "value": "Alice" }` |
|
|
116
|
+
| `set_number` | number | `{ "op": "set_number", "fieldId": "age", "value": 25 }` |
|
|
117
|
+
| `set_string_list` | string_list | `{ "op": "set_string_list", "fieldId": "tags", "items": ["a", "b"] }` |
|
|
118
|
+
| `set_single_select` | single_select | `{ "op": "set_single_select", "fieldId": "rating", "selected": "high" }` |
|
|
119
|
+
| `set_multi_select` | multi_select | `{ "op": "set_multi_select", "fieldId": "cats", "selected": ["a", "b"] }` |
|
|
120
|
+
| `set_checkboxes` | checkboxes | `{ "op": "set_checkboxes", "fieldId": "tasks", "values": {"item1": "done"} }` |
|
|
121
|
+
| `set_url` | url | `{ "op": "set_url", "fieldId": "website", "value": "https://..." }` |
|
|
122
|
+
| `set_url_list` | url_list | `{ "op": "set_url_list", "fieldId": "sources", "items": ["https://..."] }` |
|
|
123
|
+
| `set_date` | date | `{ "op": "set_date", "fieldId": "deadline", "value": "2024-06-15" }` |
|
|
124
|
+
| `set_year` | year | `{ "op": "set_year", "fieldId": "founded", "value": 2015 }` |
|
|
125
|
+
| `clear_field` | any | `{ "op": "clear_field", "fieldId": "name" }` |
|
|
126
|
+
| `skip_field` | optional | `{ "op": "skip_field", "fieldId": "notes", "reason": "Not applicable" }` |
|
|
127
|
+
| `abort_field` | any | `{ "op": "abort_field", "fieldId": "data", "reason": "Unable to find" }` |
|
|
128
|
+
|
|
129
|
+
### Checkbox Values
|
|
130
|
+
|
|
131
|
+
For `set_checkboxes`, values depend on the checkbox mode:
|
|
132
|
+
|
|
133
|
+
- **multi** (default): `todo`, `done`, `incomplete`, `active`, `na`
|
|
134
|
+
|
|
135
|
+
- **simple**: `todo`, `done`
|
|
136
|
+
|
|
137
|
+
- **explicit**: `unfilled`, `yes`, `no`
|
|
138
|
+
|
|
139
|
+
## Form Harness API
|
|
140
|
+
|
|
141
|
+
The harness manages step-by-step form filling sessions.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { FormHarness, createHarness, fillForm } from 'markform';
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### fillForm(options: FillOptions): Promise<FillResult>
|
|
148
|
+
|
|
149
|
+
High-level API for filling a form with an AI model.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const result = await fillForm({
|
|
153
|
+
form: parsedForm,
|
|
154
|
+
model: 'anthropic/claude-sonnet-4-5',
|
|
155
|
+
roles: ['agent'],
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### createHarness(form, config?): FormHarness
|
|
160
|
+
|
|
161
|
+
Create a harness for manual control over the fill loop.
|
|
162
|
+
|
|
163
|
+
See [harness.ts](../packages/markform/src/harness/harness.ts) for full details.
|
|
164
|
+
|
|
165
|
+
## Research API
|
|
166
|
+
|
|
167
|
+
For research-type forms that run extended data gathering sessions.
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { runResearch, isResearchForm } from 'markform';
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### runResearch(options: ResearchOptions): Promise<ResearchResult>
|
|
174
|
+
|
|
175
|
+
Run a research session on a research-type form.
|
|
176
|
+
|
|
177
|
+
See [runResearch.ts](../packages/markform/src/research/runResearch.ts) for full details.
|
|
178
|
+
|
|
179
|
+
## Type Exports
|
|
180
|
+
|
|
181
|
+
All Zod schemas and TypeScript types are exported from the main package:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import type {
|
|
185
|
+
ParsedForm,
|
|
186
|
+
Field,
|
|
187
|
+
FieldValue,
|
|
188
|
+
Patch,
|
|
189
|
+
InspectResult,
|
|
190
|
+
// ... many more
|
|
191
|
+
} from 'markform';
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
See [src/index.ts](../packages/markform/src/index.ts) for the complete list of exports.
|
|
@@ -7,8 +7,8 @@ Files combine YAML frontmatter with [Markdoc](https://markdoc.dev/) tags to defi
|
|
|
7
7
|
typed, validated fields.
|
|
8
8
|
|
|
9
9
|
**More info:** [Project README](https://github.com/jlevy/markform) |
|
|
10
|
-
[Full Specification](
|
|
11
|
-
|
|
10
|
+
[Full Specification](markform-spec.md) (`markform spec`) |
|
|
11
|
+
[API Documentation](markform-apis.md) (`markform apis`)
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
@@ -39,11 +39,11 @@ markform:
|
|
|
39
39
|
|
|
40
40
|
{% form id="form_id" title="Form Title" %}
|
|
41
41
|
|
|
42
|
-
{%
|
|
42
|
+
{% group id="group_id" title="Group Title" %}
|
|
43
43
|
|
|
44
44
|
<!-- fields go here -->
|
|
45
45
|
|
|
46
|
-
{% /
|
|
46
|
+
{% /group %}
|
|
47
47
|
|
|
48
48
|
{% /form %}
|
|
49
49
|
```
|
|
@@ -53,20 +53,24 @@ markform:
|
|
|
53
53
|
Use `.form.md` for Markform files.
|
|
54
54
|
They are Markdoc syntax, which is a superset of Markdown.
|
|
55
55
|
|
|
56
|
-
## Field
|
|
56
|
+
## Field Kinds
|
|
57
|
+
|
|
58
|
+
Markform uses the term **field kind** to refer to the type of a field (e.g., `string`,
|
|
59
|
+
`number`, `checkboxes`). The term **data type** refers to the underlying value
|
|
60
|
+
representation. See the Type System section in SPEC.md for full details.
|
|
57
61
|
|
|
58
62
|
### String Field
|
|
59
63
|
|
|
60
64
|
Single-line or multi-line text.
|
|
61
65
|
|
|
62
66
|
````markdown
|
|
63
|
-
{%
|
|
67
|
+
{% field kind="string" id="name" label="Name" required=true minLength=2 maxLength=100 %}{% /field %}
|
|
64
68
|
|
|
65
|
-
{%
|
|
69
|
+
{% field kind="string" id="bio" label="Biography" pattern="^[A-Z].*" %}
|
|
66
70
|
```value
|
|
67
71
|
Existing value here
|
|
68
72
|
````
|
|
69
|
-
{% /
|
|
73
|
+
{% /field %}
|
|
70
74
|
````
|
|
71
75
|
|
|
72
76
|
| Attribute | Type | Description |
|
|
@@ -80,13 +84,13 @@ Existing value here
|
|
|
80
84
|
Numeric values with optional constraints.
|
|
81
85
|
|
|
82
86
|
```markdown
|
|
83
|
-
{%
|
|
87
|
+
{% field kind="number" id="age" label="Age" required=true min=0 max=150 integer=true %}{% /field %}
|
|
84
88
|
|
|
85
|
-
{%
|
|
89
|
+
{% field kind="number" id="price" label="Price" min=0.01 max=999999.99 %}
|
|
86
90
|
```value
|
|
87
91
|
49.99
|
|
88
92
|
````
|
|
89
|
-
{% /
|
|
93
|
+
{% /field %}
|
|
90
94
|
````
|
|
91
95
|
|
|
92
96
|
| Attribute | Type | Description |
|
|
@@ -100,15 +104,15 @@ Numeric values with optional constraints.
|
|
|
100
104
|
Array of strings, one per line.
|
|
101
105
|
|
|
102
106
|
```markdown
|
|
103
|
-
{%
|
|
107
|
+
{% field kind="string_list" id="tags" label="Tags" required=true minItems=1 maxItems=10 uniqueItems=true %}{% /field %}
|
|
104
108
|
|
|
105
|
-
{%
|
|
109
|
+
{% field kind="string_list" id="features" label="Key Features" minItems=3 itemMinLength=10 %}
|
|
106
110
|
```value
|
|
107
111
|
Feature one description
|
|
108
112
|
Feature two description
|
|
109
113
|
Feature three description
|
|
110
114
|
````
|
|
111
|
-
{% /
|
|
115
|
+
{% /field %}
|
|
112
116
|
````
|
|
113
117
|
|
|
114
118
|
| Attribute | Type | Description |
|
|
@@ -124,11 +128,11 @@ Feature three description
|
|
|
124
128
|
Choose exactly one option.
|
|
125
129
|
|
|
126
130
|
```markdown
|
|
127
|
-
{%
|
|
131
|
+
{% field kind="single_select" id="rating" label="Rating" required=true %}
|
|
128
132
|
- [ ] Low {% #low %}
|
|
129
133
|
- [ ] Medium {% #medium %}
|
|
130
134
|
- [x] High {% #high %}
|
|
131
|
-
{% /
|
|
135
|
+
{% /field %}
|
|
132
136
|
````
|
|
133
137
|
|
|
134
138
|
Options use `[ ]` (unselected) or `[x]` (selected).
|
|
@@ -139,12 +143,12 @@ Each option needs `{% #id %}`.
|
|
|
139
143
|
Choose multiple options.
|
|
140
144
|
|
|
141
145
|
```markdown
|
|
142
|
-
{%
|
|
146
|
+
{% field kind="multi_select" id="categories" label="Categories" required=true minSelections=1 maxSelections=3 %}
|
|
143
147
|
- [x] Frontend {% #frontend %}
|
|
144
148
|
- [x] Backend {% #backend %}
|
|
145
149
|
- [ ] Database {% #database %}
|
|
146
150
|
- [ ] DevOps {% #devops %}
|
|
147
|
-
{% /
|
|
151
|
+
{% /field %}
|
|
148
152
|
```
|
|
149
153
|
|
|
150
154
|
| Attribute | Type | Description |
|
|
@@ -159,13 +163,13 @@ Stateful checklists with three modes.
|
|
|
159
163
|
**Multi Mode** (default) - 5 states for workflow tracking:
|
|
160
164
|
|
|
161
165
|
```markdown
|
|
162
|
-
{% checkboxes id="tasks" label="Tasks" required=true checkboxMode="multi" %}
|
|
166
|
+
{% field kind="checkboxes" id="tasks" label="Tasks" required=true checkboxMode="multi" %}
|
|
163
167
|
- [ ] Research {% #research %}
|
|
164
168
|
- [x] Design {% #design %}
|
|
165
169
|
- [/] Implementation {% #impl %}
|
|
166
170
|
- [*] Testing {% #test %}
|
|
167
171
|
- [-] N/A item {% #na %}
|
|
168
|
-
{% /
|
|
172
|
+
{% /field %}
|
|
169
173
|
```
|
|
170
174
|
|
|
171
175
|
| Token | State | Meaning |
|
|
@@ -179,20 +183,20 @@ Stateful checklists with three modes.
|
|
|
179
183
|
**Simple Mode** - 2 states (GFM compatible):
|
|
180
184
|
|
|
181
185
|
```markdown
|
|
182
|
-
{% checkboxes id="agreements" label="Agreements" checkboxMode="simple" required=true %}
|
|
186
|
+
{% field kind="checkboxes" id="agreements" label="Agreements" checkboxMode="simple" required=true %}
|
|
183
187
|
- [x] I agree to terms {% #terms %}
|
|
184
188
|
- [ ] Subscribe to newsletter {% #news %}
|
|
185
|
-
{% /
|
|
189
|
+
{% /field %}
|
|
186
190
|
```
|
|
187
191
|
|
|
188
192
|
**Explicit Mode** - Requires yes/no for each:
|
|
189
193
|
|
|
190
194
|
```markdown
|
|
191
|
-
{% checkboxes id="confirmations" label="Confirmations" checkboxMode="explicit" required=true %}
|
|
195
|
+
{% field kind="checkboxes" id="confirmations" label="Confirmations" checkboxMode="explicit" required=true %}
|
|
192
196
|
- [y] Backup completed {% #backup %}
|
|
193
197
|
- [n] Stakeholders notified {% #notify %}
|
|
194
198
|
- [ ] Deployment ready {% #deploy %}
|
|
195
|
-
{% /
|
|
199
|
+
{% /field %}
|
|
196
200
|
```
|
|
197
201
|
|
|
198
202
|
| Token | Value | Meaning |
|
|
@@ -206,13 +210,13 @@ Stateful checklists with three modes.
|
|
|
206
210
|
Single URL with format validation.
|
|
207
211
|
|
|
208
212
|
````markdown
|
|
209
|
-
{%
|
|
213
|
+
{% field kind="url" id="website" label="Website" required=true %}{% /field %}
|
|
210
214
|
|
|
211
|
-
{%
|
|
215
|
+
{% field kind="url" id="repo" label="Repository" %}
|
|
212
216
|
```value
|
|
213
217
|
https://github.com/example/repo
|
|
214
218
|
````
|
|
215
|
-
{% /
|
|
219
|
+
{% /field %}
|
|
216
220
|
````
|
|
217
221
|
|
|
218
222
|
### URL List
|
|
@@ -220,14 +224,52 @@ https://github.com/example/repo
|
|
|
220
224
|
Array of URLs.
|
|
221
225
|
|
|
222
226
|
```markdown
|
|
223
|
-
{%
|
|
227
|
+
{% field kind="url_list" id="sources" label="Sources" required=true minItems=1 maxItems=10 uniqueItems=true %}
|
|
224
228
|
```value
|
|
225
229
|
https://example.com/source1
|
|
226
230
|
https://example.com/source2
|
|
227
231
|
````
|
|
228
|
-
{% /
|
|
232
|
+
{% /field %}
|
|
233
|
+
`````
|
|
234
|
+
|
|
235
|
+
### Date Field
|
|
236
|
+
|
|
237
|
+
Date value in ISO 8601 format (YYYY-MM-DD).
|
|
238
|
+
|
|
239
|
+
````markdown
|
|
240
|
+
{% field kind="date" id="deadline" label="Deadline" required=true %}{% /field %}
|
|
241
|
+
|
|
242
|
+
{% field kind="date" id="start_date" label="Start Date" min="2020-01-01" max="2030-12-31" %}
|
|
243
|
+
```value
|
|
244
|
+
2024-06-15
|
|
245
|
+
`````
|
|
246
|
+
{% /field %}
|
|
247
|
+
`````
|
|
248
|
+
|
|
249
|
+
| Attribute | Type | Description |
|
|
250
|
+
|-----------|------|-------------|
|
|
251
|
+
| `min` | string | Minimum date (ISO 8601: YYYY-MM-DD) |
|
|
252
|
+
| `max` | string | Maximum date (ISO 8601: YYYY-MM-DD) |
|
|
253
|
+
|
|
254
|
+
### Year Field
|
|
255
|
+
|
|
256
|
+
Integer year with optional constraints.
|
|
257
|
+
|
|
258
|
+
````markdown
|
|
259
|
+
{% field kind="year" id="release_year" label="Release Year" required=true min=1888 max=2030 %}{% /field %}
|
|
260
|
+
|
|
261
|
+
{% field kind="year" id="founded" label="Year Founded" %}
|
|
262
|
+
```value
|
|
263
|
+
2015
|
|
264
|
+
`````
|
|
265
|
+
{% /field %}
|
|
229
266
|
````
|
|
230
267
|
|
|
268
|
+
| Attribute | Type | Description |
|
|
269
|
+
|-----------|------|-------------|
|
|
270
|
+
| `min` | number | Minimum year (inclusive) |
|
|
271
|
+
| `max` | number | Maximum year (inclusive) |
|
|
272
|
+
|
|
231
273
|
## Common Attributes
|
|
232
274
|
|
|
233
275
|
All fields support these attributes:
|
|
@@ -240,6 +282,20 @@ All fields support these attributes:
|
|
|
240
282
|
| `role` | string | - | Target actor (`user`, `agent`) |
|
|
241
283
|
| `priority` | string | medium | `high`, `medium`, `low` |
|
|
242
284
|
|
|
285
|
+
**Text-entry fields only** (string, number, string-list, url, url-list):
|
|
286
|
+
|
|
287
|
+
| Attribute | Type | Description |
|
|
288
|
+
|-----------|------|-------------|
|
|
289
|
+
| `placeholder` | string | Hint text shown in empty fields |
|
|
290
|
+
| `examples` | string[] | Example values (helps LLMs understand expected format) |
|
|
291
|
+
|
|
292
|
+
```markdown
|
|
293
|
+
{% field kind="string" id="name" label="Name" placeholder="Enter your name" examples=["John Doe", "Jane Smith"] %}{% /field %}
|
|
294
|
+
{% field kind="number" id="revenue" label="Revenue" placeholder="1000000" examples=["500000", "1000000"] %}{% /field %}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Note: `placeholder` and `examples` are NOT valid on chooser fields (single-select, multi-select, checkboxes).
|
|
298
|
+
|
|
243
299
|
## Documentation Blocks
|
|
244
300
|
|
|
245
301
|
Add context to fields, groups, or the form.
|
|
@@ -283,8 +339,8 @@ roles:
|
|
|
283
339
|
```
|
|
284
340
|
|
|
285
341
|
```markdown
|
|
286
|
-
{%
|
|
287
|
-
{%
|
|
342
|
+
{% field kind="string" id="query" label="Search Query" role="user" %}{% /field %}
|
|
343
|
+
{% field kind="string" id="summary" label="AI Summary" role="agent" %}{% /field %}
|
|
288
344
|
```
|
|
289
345
|
|
|
290
346
|
## Value Encoding
|
|
@@ -292,17 +348,17 @@ roles:
|
|
|
292
348
|
Values use fenced code blocks with language `value`:
|
|
293
349
|
|
|
294
350
|
````markdown
|
|
295
|
-
{%
|
|
351
|
+
{% field kind="string" id="name" label="Name" %}
|
|
296
352
|
```value
|
|
297
353
|
John Smith
|
|
298
354
|
````
|
|
299
|
-
{% /
|
|
355
|
+
{% /field %}
|
|
300
356
|
````
|
|
301
357
|
|
|
302
358
|
Empty fields omit the value block entirely:
|
|
303
359
|
|
|
304
360
|
```markdown
|
|
305
|
-
{%
|
|
361
|
+
{% field kind="string" id="name" label="Name" %}{% /field %}
|
|
306
362
|
````
|
|
307
363
|
|
|
308
364
|
## Complete Example
|
|
@@ -343,124 +399,124 @@ A focused research form for gathering ratings and key statistics for any film.
|
|
|
343
399
|
Pulls from IMDB, Rotten Tomatoes, and Metacritic.
|
|
344
400
|
{% /description %}
|
|
345
401
|
|
|
346
|
-
{%
|
|
402
|
+
{% group id="movie_input" title="Movie Identification" %}
|
|
347
403
|
|
|
348
|
-
{%
|
|
404
|
+
{% field kind="string" id="movie" label="Movie" role="user" required=true minLength=1 maxLength=300 %}{% /field %}
|
|
349
405
|
|
|
350
406
|
{% instructions ref="movie" %}
|
|
351
407
|
Enter the movie title (add any details to help identify, like "Barbie 2023" or "the Batman movie with Robert Pattinson")
|
|
352
408
|
{% /instructions %}
|
|
353
409
|
|
|
354
|
-
{% /
|
|
410
|
+
{% /group %}
|
|
355
411
|
|
|
356
|
-
{%
|
|
412
|
+
{% group id="title_identification" title="Title Identification" %}
|
|
357
413
|
|
|
358
|
-
{%
|
|
414
|
+
{% field kind="string" id="full_title" label="Full Title" role="agent" required=true %}{% /field %}
|
|
359
415
|
|
|
360
416
|
{% instructions ref="full_title" %}
|
|
361
417
|
Look up what film the user had in mind and fill in the official title including subtitle if any (e.g., "The Lord of the Rings: The Fellowship of the Ring").
|
|
362
418
|
{% /instructions %}
|
|
363
419
|
|
|
364
|
-
{% /
|
|
420
|
+
{% /group %}
|
|
365
421
|
|
|
366
|
-
{%
|
|
422
|
+
{% group id="sources" title="Sources" %}
|
|
367
423
|
|
|
368
|
-
{%
|
|
424
|
+
{% field kind="url" id="imdb_url" label="IMDB URL" role="agent" required=true %}{% /field %}
|
|
369
425
|
|
|
370
426
|
{% instructions ref="imdb_url" %}
|
|
371
427
|
Direct link to the movie's IMDB page (e.g., https://www.imdb.com/title/tt0111161/).
|
|
372
428
|
{% /instructions %}
|
|
373
429
|
|
|
374
|
-
{%
|
|
430
|
+
{% field kind="url" id="rt_url" label="Rotten Tomatoes URL" role="agent" %}{% /field %}
|
|
375
431
|
|
|
376
432
|
{% instructions ref="rt_url" %}
|
|
377
433
|
Direct link to the movie's Rotten Tomatoes page.
|
|
378
434
|
{% /instructions %}
|
|
379
435
|
|
|
380
|
-
{%
|
|
436
|
+
{% field kind="url" id="metacritic_url" label="Metacritic URL" role="agent" %}{% /field %}
|
|
381
437
|
|
|
382
438
|
{% instructions ref="metacritic_url" %}
|
|
383
439
|
Direct link to the movie's Metacritic page.
|
|
384
440
|
{% /instructions %}
|
|
385
441
|
|
|
386
|
-
{% /
|
|
442
|
+
{% /group %}
|
|
387
443
|
|
|
388
|
-
{%
|
|
444
|
+
{% group id="basic_details" title="Basic Details" %}
|
|
389
445
|
|
|
390
|
-
{%
|
|
446
|
+
{% field kind="number" id="year" label="Release Year" role="agent" required=true min=1888 max=2030 %}{% /field %}
|
|
391
447
|
|
|
392
|
-
{%
|
|
448
|
+
{% field kind="string_list" id="directors" label="Director(s)" role="agent" required=true %}{% /field %}
|
|
393
449
|
|
|
394
450
|
{% instructions ref="directors" %}
|
|
395
451
|
One director per line. Most films have one; some have two or more co-directors.
|
|
396
452
|
{% /instructions %}
|
|
397
453
|
|
|
398
|
-
{%
|
|
454
|
+
{% field kind="number" id="runtime_minutes" label="Runtime (minutes)" role="agent" min=1 max=1000 %}{% /field %}
|
|
399
455
|
|
|
400
|
-
{%
|
|
456
|
+
{% field kind="single_select" id="mpaa_rating" label="MPAA Rating" role="agent" %}
|
|
401
457
|
- [ ] G {% #g %}
|
|
402
458
|
- [ ] PG {% #pg %}
|
|
403
459
|
- [ ] PG-13 {% #pg_13 %}
|
|
404
460
|
- [ ] R {% #r %}
|
|
405
461
|
- [ ] NC-17 {% #nc_17 %}
|
|
406
462
|
- [ ] NR/Unrated {% #nr %}
|
|
407
|
-
{% /
|
|
463
|
+
{% /field %}
|
|
408
464
|
|
|
409
|
-
{% /
|
|
465
|
+
{% /group %}
|
|
410
466
|
|
|
411
|
-
{%
|
|
467
|
+
{% group id="imdb_ratings" title="IMDB Ratings" %}
|
|
412
468
|
|
|
413
|
-
{%
|
|
469
|
+
{% field kind="number" id="imdb_rating" label="IMDB Rating" role="agent" min=1.0 max=10.0 %}{% /field %}
|
|
414
470
|
|
|
415
471
|
{% instructions ref="imdb_rating" %}
|
|
416
472
|
IMDB user rating (1.0-10.0 scale).
|
|
417
473
|
{% /instructions %}
|
|
418
474
|
|
|
419
|
-
{%
|
|
475
|
+
{% field kind="number" id="imdb_votes" label="IMDB Vote Count" role="agent" min=0 %}{% /field %}
|
|
420
476
|
|
|
421
477
|
{% instructions ref="imdb_votes" %}
|
|
422
478
|
Number of IMDB user votes (e.g., 2800000 for a popular film).
|
|
423
479
|
{% /instructions %}
|
|
424
480
|
|
|
425
|
-
{% /
|
|
481
|
+
{% /group %}
|
|
426
482
|
|
|
427
|
-
{%
|
|
483
|
+
{% group id="rotten_tomatoes_ratings" title="Rotten Tomatoes Ratings" %}
|
|
428
484
|
|
|
429
|
-
{%
|
|
485
|
+
{% field kind="number" id="rt_critics_score" label="Tomatometer (Critics)" role="agent" min=0 max=100 %}{% /field %}
|
|
430
486
|
|
|
431
487
|
{% instructions ref="rt_critics_score" %}
|
|
432
488
|
Tomatometer percentage (0-100).
|
|
433
489
|
{% /instructions %}
|
|
434
490
|
|
|
435
|
-
{%
|
|
491
|
+
{% field kind="number" id="rt_critics_count" label="Critics Review Count" role="agent" min=0 %}{% /field %}
|
|
436
492
|
|
|
437
|
-
{%
|
|
493
|
+
{% field kind="number" id="rt_audience_score" label="Audience Score" role="agent" min=0 max=100 %}{% /field %}
|
|
438
494
|
|
|
439
495
|
{% instructions ref="rt_audience_score" %}
|
|
440
496
|
Audience Score percentage (0-100).
|
|
441
497
|
{% /instructions %}
|
|
442
498
|
|
|
443
|
-
{% /
|
|
499
|
+
{% /group %}
|
|
444
500
|
|
|
445
|
-
{%
|
|
501
|
+
{% group id="metacritic_ratings" title="Metacritic Ratings" %}
|
|
446
502
|
|
|
447
|
-
{%
|
|
503
|
+
{% field kind="number" id="metacritic_score" label="Metacritic Score" role="agent" min=0 max=100 %}{% /field %}
|
|
448
504
|
|
|
449
505
|
{% instructions ref="metacritic_score" %}
|
|
450
506
|
Metascore (0-100 scale). Leave empty if not available.
|
|
451
507
|
{% /instructions %}
|
|
452
508
|
|
|
453
|
-
{% /
|
|
509
|
+
{% /group %}
|
|
454
510
|
|
|
455
|
-
{%
|
|
511
|
+
{% group id="summary" title="Summary" %}
|
|
456
512
|
|
|
457
|
-
{%
|
|
513
|
+
{% field kind="string" id="logline" label="One-Line Summary" role="agent" maxLength=300 %}{% /field %}
|
|
458
514
|
|
|
459
515
|
{% instructions ref="logline" %}
|
|
460
516
|
Brief plot summary in 1-2 sentences, no spoilers.
|
|
461
517
|
{% /instructions %}
|
|
462
518
|
|
|
463
|
-
{%
|
|
519
|
+
{% field kind="string_list" id="notable_awards" label="Notable Awards" role="agent" %}{% /field %}
|
|
464
520
|
|
|
465
521
|
{% instructions ref="notable_awards" %}
|
|
466
522
|
Major awards won. One per line.
|
|
@@ -468,7 +524,7 @@ Format: Award | Category | Year
|
|
|
468
524
|
Example: "Oscar | Best Picture | 1995"
|
|
469
525
|
{% /instructions %}
|
|
470
526
|
|
|
471
|
-
{% /
|
|
527
|
+
{% /group %}
|
|
472
528
|
|
|
473
529
|
{% /form %}
|
|
474
530
|
```
|
|
@@ -539,8 +595,13 @@ markform fill template.form.md --mock --mock-source filled.form.md
|
|
|
539
595
|
|
|
540
596
|
3. **Set constraints**: Use `min`, `max`, `minLength`, `pattern` to validate
|
|
541
597
|
|
|
542
|
-
4. **Group logically**: Related fields in the same `
|
|
598
|
+
4. **Group logically**: Related fields in the same `group`
|
|
543
599
|
|
|
544
600
|
5. **Assign roles**: Separate user input from agent research
|
|
545
601
|
|
|
546
602
|
6. **Document thoroughly**: Use `{% instructions %}` for complex fields
|
|
603
|
+
|
|
604
|
+
## Programmatic API
|
|
605
|
+
|
|
606
|
+
For TypeScript and AI SDK integration, run `markform apis` or see
|
|
607
|
+
[markform-apis.md](markform-apis.md).
|