@foldrun/core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +239 -0
  3. package/dist/index.d.ts +32 -0
  4. package/dist/index.js +43 -0
  5. package/dist/src/agent-tools.d.ts +31 -0
  6. package/dist/src/agent-tools.js +99 -0
  7. package/dist/src/agents-md.d.ts +9 -0
  8. package/dist/src/agents-md.js +83 -0
  9. package/dist/src/api-tools.d.ts +38 -0
  10. package/dist/src/api-tools.js +313 -0
  11. package/dist/src/approvals.d.ts +39 -0
  12. package/dist/src/approvals.js +103 -0
  13. package/dist/src/arrange.d.ts +8 -0
  14. package/dist/src/arrange.js +40 -0
  15. package/dist/src/catalog.d.ts +108 -0
  16. package/dist/src/catalog.js +255 -0
  17. package/dist/src/completions.d.ts +61 -0
  18. package/dist/src/completions.js +578 -0
  19. package/dist/src/confine.d.ts +31 -0
  20. package/dist/src/confine.js +298 -0
  21. package/dist/src/container.d.ts +30 -0
  22. package/dist/src/container.js +172 -0
  23. package/dist/src/context-tools.d.ts +81 -0
  24. package/dist/src/context-tools.js +347 -0
  25. package/dist/src/deploy.d.ts +100 -0
  26. package/dist/src/deploy.js +377 -0
  27. package/dist/src/egress.d.ts +75 -0
  28. package/dist/src/egress.js +133 -0
  29. package/dist/src/evals.d.ts +150 -0
  30. package/dist/src/evals.js +651 -0
  31. package/dist/src/flow-lint.d.ts +16 -0
  32. package/dist/src/flow-lint.js +177 -0
  33. package/dist/src/git-hook.d.ts +1 -0
  34. package/dist/src/git-hook.js +70 -0
  35. package/dist/src/git.d.ts +37 -0
  36. package/dist/src/git.js +101 -0
  37. package/dist/src/gitrepo.d.ts +95 -0
  38. package/dist/src/gitrepo.js +355 -0
  39. package/dist/src/history.d.ts +82 -0
  40. package/dist/src/history.js +259 -0
  41. package/dist/src/kinds.d.ts +95 -0
  42. package/dist/src/kinds.js +421 -0
  43. package/dist/src/library.d.ts +94 -0
  44. package/dist/src/library.js +341 -0
  45. package/dist/src/linkable.d.ts +20 -0
  46. package/dist/src/linkable.js +113 -0
  47. package/dist/src/model-probe.d.ts +21 -0
  48. package/dist/src/model-probe.js +81 -0
  49. package/dist/src/notify.d.ts +61 -0
  50. package/dist/src/notify.js +252 -0
  51. package/dist/src/oauth-presets.d.ts +13 -0
  52. package/dist/src/oauth-presets.js +39 -0
  53. package/dist/src/okf.d.ts +220 -0
  54. package/dist/src/okf.js +656 -0
  55. package/dist/src/openapi.d.ts +66 -0
  56. package/dist/src/openapi.js +342 -0
  57. package/dist/src/paths.d.ts +33 -0
  58. package/dist/src/paths.js +78 -0
  59. package/dist/src/platform.d.ts +32 -0
  60. package/dist/src/platform.js +48 -0
  61. package/dist/src/providers.d.ts +47 -0
  62. package/dist/src/providers.js +114 -0
  63. package/dist/src/refs.d.ts +20 -0
  64. package/dist/src/refs.js +78 -0
  65. package/dist/src/run-container.d.ts +227 -0
  66. package/dist/src/run-container.js +760 -0
  67. package/dist/src/runner.d.ts +241 -0
  68. package/dist/src/runner.js +3215 -0
  69. package/dist/src/runtime.d.ts +41 -0
  70. package/dist/src/runtime.js +357 -0
  71. package/dist/src/script-tools.d.ts +62 -0
  72. package/dist/src/script-tools.js +296 -0
  73. package/dist/src/secret-files.d.ts +12 -0
  74. package/dist/src/secret-files.js +92 -0
  75. package/dist/src/secrets.d.ts +147 -0
  76. package/dist/src/secrets.js +626 -0
  77. package/dist/src/starter.d.ts +21 -0
  78. package/dist/src/starter.js +399 -0
  79. package/dist/src/step-exec.d.ts +136 -0
  80. package/dist/src/step-exec.js +391 -0
  81. package/dist/src/storage.d.ts +123 -0
  82. package/dist/src/storage.js +640 -0
  83. package/dist/src/store.d.ts +1052 -0
  84. package/dist/src/store.js +2378 -0
  85. package/dist/src/tar.d.ts +30 -0
  86. package/dist/src/tar.js +111 -0
  87. package/dist/src/tool-names.d.ts +39 -0
  88. package/dist/src/tool-names.js +79 -0
  89. package/dist/src/tool-programs.d.ts +18 -0
  90. package/dist/src/tool-programs.js +52 -0
  91. package/dist/src/tool-test.d.ts +19 -0
  92. package/dist/src/tool-test.js +335 -0
  93. package/dist/src/translator.d.ts +159 -0
  94. package/dist/src/translator.js +986 -0
  95. package/dist/src/triggers.d.ts +60 -0
  96. package/dist/src/triggers.js +270 -0
  97. package/dist/src/webhook.d.ts +47 -0
  98. package/dist/src/webhook.js +148 -0
  99. package/index.ts +44 -0
  100. package/package.json +64 -0
  101. package/src/agent-tools.ts +138 -0
  102. package/src/agents-md.ts +81 -0
  103. package/src/api-tools.ts +389 -0
  104. package/src/approvals.ts +129 -0
  105. package/src/arrange.ts +42 -0
  106. package/src/catalog.ts +321 -0
  107. package/src/completions.ts +652 -0
  108. package/src/confine.ts +350 -0
  109. package/src/container.ts +220 -0
  110. package/src/context-tools.ts +435 -0
  111. package/src/deploy.ts +458 -0
  112. package/src/egress.ts +176 -0
  113. package/src/evals.ts +812 -0
  114. package/src/flow-lint.ts +215 -0
  115. package/src/git-hook.ts +73 -0
  116. package/src/git.ts +117 -0
  117. package/src/gitrepo.ts +391 -0
  118. package/src/history.ts +329 -0
  119. package/src/kinds.ts +507 -0
  120. package/src/library.ts +419 -0
  121. package/src/linkable.ts +123 -0
  122. package/src/model-probe.ts +112 -0
  123. package/src/notify.ts +281 -0
  124. package/src/oauth-presets.ts +54 -0
  125. package/src/okf.ts +768 -0
  126. package/src/openapi.ts +383 -0
  127. package/src/paths.ts +79 -0
  128. package/src/platform.ts +87 -0
  129. package/src/providers.ts +147 -0
  130. package/src/refs.ts +83 -0
  131. package/src/run-container.ts +883 -0
  132. package/src/runner.ts +3446 -0
  133. package/src/runtime.ts +404 -0
  134. package/src/script-tools.ts +383 -0
  135. package/src/secret-files.ts +101 -0
  136. package/src/secrets.ts +799 -0
  137. package/src/starter.ts +415 -0
  138. package/src/step-exec.ts +498 -0
  139. package/src/storage.ts +771 -0
  140. package/src/store.ts +2985 -0
  141. package/src/tar.ts +124 -0
  142. package/src/tool-names.ts +91 -0
  143. package/src/tool-programs.ts +65 -0
  144. package/src/tool-test.ts +401 -0
  145. package/src/translator.ts +1029 -0
  146. package/src/triggers.ts +287 -0
  147. package/src/webhook.ts +183 -0
  148. package/templates/blog-desk/AGENTS.md +13 -0
  149. package/templates/blog-desk/agents/researcher/agent.md +11 -0
  150. package/templates/blog-desk/agents/writer/agent.md +8 -0
  151. package/templates/blog-desk/evals/writer-quality.md +10 -0
  152. package/templates/blog-desk/flows/publish.md +10 -0
  153. package/templates/blog-desk/knowledge/house-style.md +9 -0
  154. package/templates/blog-desk/knowledge/index.md +9 -0
  155. package/templates/hello/AGENTS.md +18 -0
  156. package/templates/hello/agents/curator/agent.md +32 -0
  157. package/templates/hello/agents/notetaker/agent.md +24 -0
  158. package/templates/hello/evals/house-style.md +16 -0
  159. package/templates/hello/flows/memory-review.md +7 -0
  160. package/templates/hello/flows/note.md +7 -0
  161. package/templates/hello/knowledge/house-style.md +15 -0
  162. package/templates/hello/knowledge/index.md +9 -0
  163. package/templates/hello/skills/plain-english/SKILL.md +11 -0
  164. package/templates/hello/state/publishing.md +7 -0
  165. package/templates/hello/tools/wordcount/run.py +13 -0
  166. package/templates/hello/tools/wordcount/tool.md +22 -0
package/src/starter.ts ADDED
@@ -0,0 +1,415 @@
1
+ // The starter workspace, defined once.
2
+ //
3
+ // Two things used to build one: `foldrun init` had its own copy and the
4
+ // dashboard's "new workspace" button had another. They drifted exactly as you
5
+ // would expect — different flow names, one with evals and knowledge and one
6
+ // without — and when structural documents moved from `type:` to `kind:`, one
7
+ // copy was migrated and the other silently kept writing the old spelling.
8
+ //
9
+ // This is the same failure the consistency tests exist to catch: a list in two
10
+ // places, one updated, nothing erroring. So there is one definition here and
11
+ // both callers read it.
12
+ //
13
+ // Not to be confused with KINDS[kind].template(), which makes *one* document
14
+ // of a kind with a placeholder name — that is what the New button uses inside
15
+ // an existing workspace. This is the set of files a brand-new workspace starts
16
+ // with, and they reference each other on purpose: the flow names the agents,
17
+ // the eval names the writer, so `foldrun check` passes and `foldrun run
18
+ // publish` works before anything has been edited.
19
+
20
+ /** One authored file, relative to the workspace root. */
21
+ export interface StarterFile {
22
+ path: string;
23
+ content: string;
24
+ }
25
+
26
+ /**
27
+ * The account root's own files — one scope up from any workspace.
28
+ *
29
+ * The account AGENTS.md was readable from the day `workspaceFrontmatter` and
30
+ * `sharedInstructions` learned to look for it, and nothing ever wrote one. So
31
+ * the outer half of "nearest-wins" existed only for people who had read the
32
+ * spec closely enough to know the file could exist at all, which is the same
33
+ * failure as prose that reached no model: a feature nobody is told about.
34
+ *
35
+ * Deliberately near-empty. This file's frontmatter governs *every* workspace
36
+ * under it, so the scaffold ships the shape and a commented example rather
37
+ * than a live `provider:` — a starter that silently routed every future
38
+ * workspace somewhere would be worse than no starter.
39
+ */
40
+ export function accountFiles(account: string): StarterFile[] {
41
+ return [
42
+ {
43
+ path: "AGENTS.md",
44
+ content: `---
45
+ foldrun_version: "0.1"
46
+ # Config here applies to every workspace under this account, and a workspace
47
+ # that declares the same key replaces it *whole* — base_url and token never
48
+ # merge across scopes, so a provider block belongs entirely at one level.
49
+ #
50
+ # provider:
51
+ # base_url: https://openrouter.ai/api
52
+ # token: \${OPENROUTER_API_KEY}
53
+ # models: # what this gateway calls each tier
54
+ # fast: google/gemini-2.5-flash
55
+ # max: anthropic/claude-opus-4.1
56
+ # headers: # anything else the gateway wants
57
+ # X-Title: foldrun
58
+ #
59
+ # The token is sent as a bearer credential. A gateway that wants it as a key
60
+ # header asks for that by name: headers: { x-api-key: \${THE_SECRET} }.
61
+ ---
62
+
63
+ # ${account}
64
+
65
+ Context every agent in every workspace here shares.
66
+
67
+ Unlike the frontmatter above, this prose **accumulates**: a workspace's
68
+ AGENTS.md is added to it, not swapped for it, so a rule written here cannot be
69
+ dropped further down.
70
+ `,
71
+ },
72
+ ];
73
+ }
74
+
75
+ export function starterFiles(workspace: string): StarterFile[] {
76
+ return [
77
+ {
78
+ // AGENTS.md, not project.md — the file was renamed to the Linux
79
+ // Foundation standard and this scaffold was missed once already, so
80
+ // every workspace made from the dashboard started with a file nothing
81
+ // reads.
82
+ path: "AGENTS.md",
83
+ content: `---
84
+ name: ${workspace}
85
+ description: A starter workspace — edit the agents, then run the flow.
86
+ foldrun_version: "0.1"
87
+ ---
88
+
89
+ # ${workspace}
90
+
91
+ Context every agent here shares. Prices, rules, anything they should all know.
92
+ `,
93
+ },
94
+
95
+ {
96
+ // A workspace is meant to be a git repository — that is the whole pitch,
97
+ // that you can diff and review what an agent is. So it has to arrive
98
+ // knowing which of its own files must never be committed. The decisive
99
+ // one is `.foldrun/.secret-key`: the CLI writes the key that decrypts
100
+ // every secret *inside the workspace*, and without this file the first
101
+ // `git add -A` after setting a secret commits it.
102
+ path: ".gitignore",
103
+ content: `# The key that decrypts every secret in this workspace, plus the
104
+ # local run store. Never commit these.
105
+ .foldrun/
106
+
107
+ # Written by runs, not by you.
108
+ runs/
109
+ outputs/
110
+
111
+ .env
112
+ .env.local
113
+ .DS_Store
114
+ `,
115
+ },
116
+
117
+ {
118
+ path: "agents/researcher/agent.md",
119
+ content: `---
120
+ name: researcher
121
+ description: Finds one thing worth writing about, and says why.
122
+ model: fast
123
+ effort: high
124
+ tools:
125
+ - web
126
+ - read
127
+ ---
128
+
129
+ Pick exactly one topic, in a short paragraph, and say who it helps and why now.
130
+ Do not write the article.
131
+ `,
132
+ },
133
+
134
+ {
135
+ path: "agents/writer/agent.md",
136
+ content: `---
137
+ name: writer
138
+ description: Turns a brief into a short draft.
139
+ tools:
140
+ - files
141
+ ---
142
+
143
+ Write a short draft from the brief you were given. Save it to outputs/draft.md.
144
+ `,
145
+ },
146
+
147
+ {
148
+ path: "flows/publish.md",
149
+ content: `---
150
+ name: publish
151
+ trigger: manual
152
+ ---
153
+
154
+ Read the numbers, not the order of the lines.
155
+ Same number = at the same time. Different number = one after the other.
156
+
157
+ 1. [[researcher]] — find one topic worth writing about
158
+ 2. [[writer]] — draft it
159
+ `,
160
+ },
161
+
162
+ {
163
+ // knowledge/ is an OKF bundle, so this one declares itself in `type:`.
164
+ path: "knowledge/house-style.md",
165
+ content: `---
166
+ type: Reference
167
+ title: How we write
168
+ description: How we write. Agents read this; they never rewrite it.
169
+ status: stable
170
+ ---
171
+
172
+ - Short sentences. One idea each.
173
+ - Say the number, not "significant growth".
174
+ `,
175
+ },
176
+
177
+ {
178
+ // The other half of OKF, and the half the starter never showed. Same
179
+ // format as knowledge/, different write permission: an agent may add
180
+ // here, and when it does the runtime stamps `generated:` so a fact it
181
+ // worked out never looks like one you gave it.
182
+ path: "memory/what-worked.md",
183
+ content: `---
184
+ type: Fact
185
+ title: What worked last time
186
+ description: Something learned from a run. Agents add files here themselves.
187
+ status: stable
188
+ # generated: is stamped automatically when an agent writes a memory.
189
+ # Add verified: with a \`human:\` actor once you have checked one yourself —
190
+ # that is what moves it from unverified to human-reviewed in the index.
191
+ ---
192
+
193
+ Short drafts got edited less than long ones. Prefer four paragraphs to eight.
194
+ `,
195
+ },
196
+
197
+ {
198
+ // For the CODING TOOL the author is using, not for the platform — this is
199
+ // the one file here that foldrun itself never reads. Claude Code and its
200
+ // peers look for AGENTS.md/CLAUDE.md at the root of whatever they open,
201
+ // and without one they infer conventions from the tree, which for a
202
+ // workspace of loosely-structured markdown means guessing frontmatter
203
+ // fields that do not exist and putting agents in the wrong place.
204
+ //
205
+ // The platform already imports .claude/agents/*.md as agents, so a
206
+ // subagent authored in Claude Code deploys as a foldrun agent with no
207
+ // conversion. That path is much more useful when the tool knows it
208
+ // exists, which is most of what this file is for.
209
+ path: "CLAUDE.md",
210
+ content: `# Working on this foldrun workspace
211
+
212
+ This is a foldrun workspace: agents, flows and knowledge as markdown. There is
213
+ no build — the files ARE the program — so the loop is edit, check, run, deploy.
214
+
215
+ ## The loop
216
+
217
+ \`\`\`sh
218
+ foldrun check # validate everything, offline, no model calls
219
+ foldrun run <flow> # run it locally against real models
220
+ foldrun eval # run the evals
221
+ foldrun deploy --url <server> --token $FOLDRUN_TOKEN
222
+ \`\`\`
223
+
224
+ \`check\` is cheap and catches a broken flow before a schedule fires it at 3am.
225
+ Run it after edits, the way you would run a typecheck.
226
+
227
+ ## Where things go
228
+
229
+ | Path | What |
230
+ |---|---|
231
+ | \`AGENTS.md\` | shared context every agent in this workspace sees |
232
+ | \`agents/<name>/agent.md\` | one role: its persona, model, tools |
233
+ | \`flows/<name>.md\` | steps, in order, naming the agents that run them |
234
+ | \`knowledge/\` | reference material agents read |
235
+ | \`memory/\` | what past runs learned — agents write here themselves |
236
+ | \`evals/\` | tests for agents, same idea as unit tests |
237
+ | \`skills/\` | a procedure an agent can follow, named in \`skills:\` |
238
+ | \`tools/\` | a folder tool: its definition and its code together |
239
+ | \`scripts/\` | code the agents call, referenced by \`scripts:\` |
240
+ | \`state/\` | what runs accumulate. Yours to read, never deployed over |
241
+ | \`.claude/agents/<name>.md\` | a Claude Code subagent — deploys AS an agent |
242
+
243
+ \`knowledge/\` is what you tell the agents; \`memory/\` is what they worked out.
244
+ Regenerated every run means a file; accumulated across runs means \`state/\`.
245
+
246
+ That last row is worth knowing: a subagent you write in Claude Code is imported
247
+ as \`agents/<name>/agent.md\` at deploy, no conversion. Write it either way.
248
+
249
+ ## What a deploy does NOT touch
250
+
251
+ \`runs/\`, \`state/\`, \`secrets.json\`, and any memory an agent wrote that your
252
+ push does not mention. Those belong to the platform, not to git — a deploy that
253
+ reverted what an agent learned would make every run a little dumber.
254
+
255
+ Secrets never go in these files. \`foldrun secrets\` puts them in the vault, and
256
+ agents reference them by name.
257
+
258
+ ## Talking to a deployed workspace
259
+
260
+ The CLI is local except for \`deploy\`. To inspect or drive a workspace running
261
+ on a server, use the HTTP API — every route takes the same API key
262
+ (\`Authorization: Bearer $FOLDRUN_TOKEN\`, from Settings → API keys) or a browser
263
+ session, and refuses without one.
264
+
265
+ \`\`\`sh
266
+ export FOLDRUN_TOKEN=... FOLDRUN_URL=https://your-server WS=my-workspace
267
+ api() { p=$1; shift; curl -sS -H "authorization: Bearer $FOLDRUN_TOKEN" "$FOLDRUN_URL/api/$p" "$@"; }
268
+
269
+ api workspaces/$WS/runs # recent runs, newest first
270
+ api workspaces/$WS/runs/<id> # the full trail of one
271
+ api workspaces/$WS/runs/<id>/stream # follow a live one (SSE)
272
+ api workspaces/$WS/flows/<flow>/run -X POST # start one
273
+ \`\`\`
274
+
275
+ All of it, \`/api/workspaces/<workspace>\` unless noted:
276
+
277
+ | Route | Methods | For |
278
+ |---|---|---|
279
+ | \`/\` | GET DELETE PATCH | the workspace itself |
280
+ | \`/deploy\` | POST | what \`foldrun deploy\` calls |
281
+ | \`/source\` | GET PUT PATCH DELETE | read and write single files |
282
+ | \`/runs\` | GET | list runs |
283
+ | \`/runs/<id>\` | GET DELETE | one run, every step |
284
+ | \`/runs/<id>/stream\` | GET | live events, server-sent |
285
+ | \`/runs/<id>/stop\` | POST | kill it — destroys the sandbox too |
286
+ | \`/runs/<id>/rerun\` | POST | again, or from a chosen step |
287
+ | \`/runs/<id>/approve\` | POST | release a run waiting on a human |
288
+ | \`/flows\` · \`/flows/<f>\` | GET POST · POST DELETE PATCH | list, create, edit |
289
+ | \`/flows/<f>/run\` | POST | start a flow |
290
+ | \`/agents\` · \`/agents/<a>/run\` | GET POST · POST | list agents, run one |
291
+ | \`/evals\` · \`/evals/<e>/run\` | GET POST · POST | list evals, run one |
292
+ | \`/tools/<t>/test\` | POST | exercise one tool alone |
293
+ | \`/storage\` · \`/storage/download\` · \`/storage/upload-url\` | GET POST PUT DELETE · GET · POST | workspace files |
294
+ | \`/assets\` | POST | upload an asset |
295
+ | \`/hooks/<f>/rotate\` | POST | new webhook token for a flow |
296
+ | \`/vocabulary\` | GET | what this workspace's documents may say |
297
+
298
+ Account-level, outside \`/workspaces\`: \`/api/secrets\`, \`/api/keys\`, \`/api/schedule\`,
299
+ \`/api/approvals\`, \`/api/usage\`, \`/api/library/<kind>\`, \`/api/team\`, \`/api/billing\`,
300
+ \`/api/healthz\` (open) and \`/api/metrics\` (Prometheus).
301
+
302
+ Debugging a failed run is usually: \`runs\` to find it, \`runs/<id>\` to read which
303
+ step failed and what it cost, fix the markdown, \`deploy\`, then \`rerun\`.
304
+
305
+ Every route, with request and response shapes, is in \`docs/api.md\` in the
306
+ foldrun repository — including secrets, keys, billing, OAuth, webhooks and the
307
+ git push endpoint.
308
+
309
+ ## Writing a flow
310
+
311
+ A numbered list of steps. The number is the GROUP: same number means those
312
+ steps run in parallel, and the flow waits for all of them before the next.
313
+
314
+ \`\`\`markdown
315
+ ---
316
+ trigger: manual # manual | schedule | webhook
317
+ schedule: "0 9 * * 1" # cron, when trigger: schedule
318
+ timezone: Australia/Sydney
319
+ model: default # a default for every step here
320
+ effort: low
321
+ overlap: skip # skip | queue — what a second run does while one is live
322
+ ---
323
+
324
+ 1. [[researcher]] — Find three sources on {{topic}}.
325
+ 2. [[writer]] — Draft from what the researcher found.
326
+ model: max
327
+ verify: the draft cites every source
328
+ 3?. [[editor]] — Tighten it.
329
+ 4!. [[publisher]] — Publish it.
330
+ \`\`\`
331
+
332
+ \`3?.\` is optional — it may be skipped. \`4!.\` needs a human to approve before it
333
+ runs. \`[[flow:other-flow]]\` in place of an agent runs another flow as a step.
334
+
335
+ Indented under a step, any of:
336
+
337
+ | | |
338
+ |---|---|
339
+ | \`approve: true\` | stop for a human (\`!\` is shorthand for this) |
340
+ | \`when: <condition>\` | run only if it holds |
341
+ | \`case: <value>\` / \`else: true\` | branch on the previous step's result |
342
+ | \`retry: 2\` | re-run on failure, up to 5 |
343
+ | \`timeout: 900\` | seconds before the step is cut off |
344
+ | \`verify: <claim>\` | the step fails unless this is true of its output |
345
+ | \`model:\` / \`effort:\` | override the flow's default for this step |
346
+ | \`loop: 3\` / \`until: <condition>\` | repeat until it holds, at most 5 |
347
+ | \`each: lines\` | run once per line of the previous result |
348
+ | \`each: rows of <path>\` | run once per CSV row |
349
+ | \`max: 10\` | cap how many iterations \`each:\` produces |
350
+ | \`on-fail: [[agent]]\` | who handles it when this step fails |
351
+ | \`wait: 30m\` | pause before running — \`90s\`, \`30m\`, \`4h\`, \`3d\` |
352
+ | \`wait: event\` | hold until something POSTs the run's event URL; the body reaches the step |
353
+ | \`ask: <question>\` | ask a human, use the answer |
354
+ | \`preview: draft/*.mdx\` | what the approval box shows — paths under \`storage/\`, globs allowed |
355
+ | \`delegate: [[a]], [[b]]\` | hand the step to whichever fits, up to 5 |
356
+ | \`output: json\` | the reply ends with one JSON value; the next step gets it as data, \`each: items\` fans out over it |
357
+ | \`each: items\` | run once per element of the previous step's JSON array |
358
+
359
+ ## Writing an agent
360
+
361
+ Frontmatter then prose. The prose IS the system prompt, so write it to be read
362
+ by a model: what this role is for, what it must not do, what good looks like.
363
+
364
+ \`\`\`markdown
365
+ ---
366
+ name: researcher
367
+ description: Finds and summarises sources.
368
+ model: default # fast | default | max
369
+ effort: low # how hard to think about it
370
+ size: large # small | large | heavy — the sandbox it rents
371
+ tools: [WebSearch, Read, my-folder-tool] # built-ins and your own tools/, one list
372
+ disallowedTools: [Bash] # subtract from what it would otherwise have
373
+ skills: [house-style] # from skills/
374
+ scripts: [summarise.py] # from scripts/, each becomes a callable tool
375
+ apis: [{ name: crm }] # an HTTP API, as a tool
376
+ mcpServers: {} # an MCP server, as a tool
377
+ agents: [writer] # colleagues this one may consult
378
+ secrets: [CRM_TOKEN] # from the vault — never written in these files
379
+ provider: {} # BYOK: your own model credential
380
+ permissionMode: plan # plan first, act once approved
381
+ runtime: # only if scripts need packages
382
+ packages: [requests]
383
+ ---
384
+
385
+ You research a topic and report what you found...
386
+ \`\`\`
387
+
388
+ Only \`name\` and the prose are required. Every other field widens or narrows
389
+ what the agent can reach, and the default is narrow.
390
+
391
+ \`runtime:\` installs pip/npm packages in the sandbox each agent runs in. Pin
392
+ versions the normal way (\`pandas>=2\`, \`lodash@^4\`). Python and Node are
393
+ supported; anything else should ship as a committed binary.
394
+
395
+ Link documents to each other with \`[[wikilinks]]\` — the name, not the path.
396
+ `,
397
+ },
398
+
399
+ {
400
+ path: "evals/writer-quality.md",
401
+ content: `---
402
+ name: writer-quality
403
+ agent: writer
404
+ model: fast
405
+ effort: low
406
+ ---
407
+
408
+ ## writes something
409
+ task: Write two sentences about rain.
410
+ expect:
411
+ - judge: it is two sentences and mentions rain
412
+ `,
413
+ },
414
+ ];
415
+ }