factoryhub 0.1.0 → 0.1.1

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 (87) hide show
  1. package/README.md +9 -3
  2. package/factories/index.json +231 -0
  3. package/factories/newsletter-note/README.md +11 -0
  4. package/factories/newsletter-note/agents/reviewer/agent.md +10 -0
  5. package/factories/newsletter-note/agents/writer/agent.md +11 -0
  6. package/factories/newsletter-note/factory.yaml +12 -0
  7. package/factories/newsletter-note/flow.yaml +45 -0
  8. package/factories/newsletter-note/mindburn.tests.yaml +80 -0
  9. package/factories/release-desk/README.md +13 -0
  10. package/factories/release-desk/agents/editor/agent.md +10 -0
  11. package/factories/release-desk/agents/reviewer/agent.md +10 -0
  12. package/factories/release-desk/factory.yaml +13 -0
  13. package/factories/release-desk/flow.yaml +67 -0
  14. package/factories/release-desk/mindburn.tests.yaml +163 -0
  15. package/factories/short-video-cut/README.md +11 -0
  16. package/factories/short-video-cut/agents/reviewer/agent.md +10 -0
  17. package/factories/short-video-cut/agents/writer/agent.md +11 -0
  18. package/factories/short-video-cut/factory.yaml +13 -0
  19. package/factories/short-video-cut/flow.yaml +46 -0
  20. package/factories/short-video-cut/mindburn.tests.yaml +80 -0
  21. package/factories/video-facts/README.md +11 -0
  22. package/factories/video-facts/agents/analyst/agent.md +10 -0
  23. package/factories/video-facts/agents/reviewer/agent.md +10 -0
  24. package/factories/video-facts/factory.yaml +13 -0
  25. package/factories/video-facts/flow.yaml +39 -0
  26. package/factories/video-facts/mindburn.tests.yaml +34 -0
  27. package/factories/video-to-posts/README.md +35 -0
  28. package/factories/video-to-posts/agents/analyst/agent.md +10 -0
  29. package/factories/video-to-posts/agents/reviewer/agent.md +10 -0
  30. package/factories/video-to-posts/agents/writer/agent.md +11 -0
  31. package/factories/video-to-posts/factory.yaml +12 -0
  32. package/factories/video-to-posts/flow.yaml +62 -0
  33. package/factories/video-to-posts/mindburn.tests.yaml +34 -0
  34. package/factories/week-of-posts/README.md +11 -0
  35. package/factories/week-of-posts/agents/reviewer/agent.md +10 -0
  36. package/factories/week-of-posts/agents/writer/agent.md +11 -0
  37. package/factories/week-of-posts/factory.yaml +12 -0
  38. package/factories/week-of-posts/flow.yaml +46 -0
  39. package/factories/week-of-posts/mindburn.tests.yaml +80 -0
  40. package/package.json +15 -2
  41. package/packages/cli/package.json +1 -1
  42. package/packages/cli/src/commands/export.mjs +0 -1
  43. package/packages/cli/src/commands/get.mjs +0 -1
  44. package/packages/cli/src/commands/inspect.mjs +0 -1
  45. package/packages/cli/src/commands/list.mjs +1 -6
  46. package/packages/cli/src/commands/login.mjs +161 -0
  47. package/packages/cli/src/commands/logout.mjs +43 -0
  48. package/packages/cli/src/commands/mcp.mjs +0 -1
  49. package/packages/cli/src/commands/new.mjs +0 -1
  50. package/packages/cli/src/commands/pack.mjs +0 -1
  51. package/packages/cli/src/commands/publish.mjs +62 -0
  52. package/packages/cli/src/commands/pull.mjs +59 -0
  53. package/packages/cli/src/commands/push.mjs +115 -0
  54. package/packages/cli/src/commands/resume.mjs +0 -1
  55. package/packages/cli/src/commands/run.mjs +182 -20
  56. package/packages/cli/src/commands/runs.mjs +52 -0
  57. package/packages/cli/src/commands/search.mjs +0 -1
  58. package/packages/cli/src/commands/validate.mjs +1 -3
  59. package/packages/cli/src/commands/whoami.mjs +34 -0
  60. package/packages/cli/src/hosted.mjs +159 -0
  61. package/packages/cli/src/main.mjs +80 -14
  62. package/packages/cli/src/tool-sources.mjs +272 -0
  63. package/packages/cli/src/util.mjs +37 -0
  64. package/packages/engine/lib/credentials.mjs +121 -0
  65. package/packages/engine/lib/hosted.mjs +119 -0
  66. package/packages/engine/lib/hub.mjs +376 -24
  67. package/packages/engine/lib/nango.mjs +157 -0
  68. package/packages/engine/lib/node.mjs +161 -33
  69. package/packages/engine/lib/providers.mjs +8 -3
  70. package/packages/engine/lib/run.mjs +70 -9
  71. package/packages/engine/lib/text.mjs +5 -0
  72. package/packages/engine/package.json +8 -2
  73. package/packages/engine/src/factory-engine.mjs +415 -68
  74. package/packages/engine/src/flow-sources.mjs +135 -0
  75. package/packages/engine/src/mcp-client.mjs +429 -0
  76. package/packages/engine/src/run.mjs +81 -5
  77. package/packages/engine/src/tool-sources.mjs +566 -0
  78. package/packages/mcp/package.json +1 -1
  79. package/packages/mcp/src/server.mjs +47 -17
  80. package/packages/sdk/package.json +28 -0
  81. package/packages/sdk/src/index.d.ts +163 -0
  82. package/packages/sdk/src/index.mjs +266 -0
  83. package/spec/README.md +7 -1
  84. package/spec/factory-format.md +264 -19
  85. package/spec/schema/factory.yaml.json +815 -0
  86. package/spec/schema/flow.schema.json +24 -2
  87. package/spec/skill-export.md +3 -0
package/README.md CHANGED
@@ -109,8 +109,8 @@ the start. More in the [quickstart](docs/quickstart.md).
109
109
 
110
110
  | Part | What it does |
111
111
  |---|---|
112
- | [`spec/`](spec) | The factory format v1alpha1: a readable [specification](spec/factory-format.md), JSON Schemas for `factory.yaml` and `flow.yaml`, conformance fixtures that test the schemas against the engine, the [skill export](spec/skill-export.md) mapping, and an [RFC process](spec/rfcs/README.md). |
113
- | [`packages/engine`](packages/engine) | The engine with no dependencies: parses a factory, runs its flow on Anthropic or any OpenAI-compatible model, writes and verifies receipts. The factoryhub site runs the same engine code. |
112
+ | [`spec/`](spec) | The factory format v1alpha1: a readable [specification](spec/factory-format.md), JSON Schemas for `factory.yaml`, `flow.yaml` and the [single-file form](docs/single-file-factory.md), conformance fixtures that test the schemas against the engine, the [skill export](spec/skill-export.md) mapping, and an [RFC process](spec/rfcs/README.md). |
113
+ | [`packages/engine`](packages/engine) | The engine with no dependencies: parses a factory, runs its flow on Anthropic or any OpenAI-compatible model, writes and verifies receipts. The factoryhub site runs a copy of this engine. |
114
114
  | [`packages/cli`](packages/cli) | `factoryhub`: `list`, `inspect`, `validate`, `run`, `resume`, `new`, `pack`, `export --as skill`, `search`, `get`. [Reference](docs/cli.md). |
115
115
  | [`packages/mcp`](packages/mcp) | A local stdio MCP server: list, read, validate, export and run factories from any MCP client. Runs stop at every decision and resume with the person's answer. [Reference](docs/mcp.md). |
116
116
  | [`factories/`](factories) | The house factories, each checked by `npm run validate` and the CI workflow, with a generated [`index.json`](factories/index.json). |
@@ -129,8 +129,14 @@ the start. More in the [quickstart](docs/quickstart.md).
129
129
  | [`inbox-triage`](factories/inbox-triage) | Sorts a batch of customer messages by urgency and type, drafts a reply to each in your tone, and lists what needs a human decision. | 2 of 3 | 4 | no | none |
130
130
  | [`launch-kit`](factories/launch-kit) | Turns a product description into a launch kit with positioning, a landing page draft, a launch email, three follow-ups and posts for social channels, all in one voice. | 2 of 5 | 6 | yes | web_fetch |
131
131
  | [`meeting-to-actions`](factories/meeting-to-actions) | Turns rough meeting notes or a transcript into decisions, owned actions with dates, open questions and a follow-up message ready to send. | 1 of 2 | 3 | no | none |
132
+ | [`newsletter-note`](factories/newsletter-note) | Writes a short newsletter note, under 120 words, that tells your readers what your new video, podcast or talk is about and points them to it, using only the facts sheet. | 1 of 3 | 2 | no | none |
132
133
  | [`outreach-pack`](factories/outreach-pack) | Turns checked market research and launch materials into an outreach pack. | 2 of 3 | 3 | no | none |
133
134
  | [`prospect-brief`](factories/prospect-brief) | Researches one company you want to sell to and writes a one-page brief plus a first email and follow-up that mention real, checkable facts about them. | 2 of 3 | 7 | yes | web_fetch, web_search |
135
+ | [`release-desk`](factories/release-desk) | Puts the posts, the short-video script and the newsletter note written from one video into a single release packet: the week at a glance, every piece checked against the others and the facts sheet, and every claim listed with the words it rests on, for you to approve once. | 1 of 4 | 3 | yes | none |
136
+ | [`short-video-cut`](factories/short-video-cut) | Writes a 30-second script for TikTok, Reels or Shorts and a cut list from the facts sheet of one video, podcast or talk: a hook, three beats and a closing line, each clip with the timestamp and the exact words where it starts and ends. | 1 of 3 | 2 | no | none |
137
+ | [`video-facts`](factories/video-facts) | Reads the transcript of one video, podcast or talk and writes a facts sheet: every number, result, claim and quote the speaker states, in their own words, with each hedge kept and a timestamp or the first words for each. | 1 of 1 | 2 | no | none |
138
+ | [`video-to-posts`](factories/video-to-posts) | Turns the transcript of one video, podcast or talk into a week of posts for X, LinkedIn, a short video and a newsletter, using only what the speaker said. | 1 of 2 | 4 | yes | none |
139
+ | [`week-of-posts`](factories/week-of-posts) | Writes an X thread, two single posts and a LinkedIn post from the facts sheet of one video, podcast or talk, in the speaker's voice, saying nothing the facts sheet does not say. | 1 of 3 | 2 | no | none |
134
140
 
135
141
  <!-- factories:end -->
136
142
 
@@ -148,7 +154,7 @@ exercised. CI has not run yet, so nothing is marked "tested in CI".
148
154
  |---|---|---|
149
155
  | Claude Code | [plugin](integrations/claude-code-plugin) with the skill and the MCP server | tested locally |
150
156
  | Gemini CLI | [MCP entry](integrations/mcp-clients/gemini.settings.json) | tested locally |
151
- | Codex | [MCP entry](integrations/mcp-clients/codex.config.toml) | documented only |
157
+ | Codex | [MCP entry](integrations/mcp-clients/codex.config.toml) | tested locally (ran a factory to its approval step) |
152
158
  | Cursor | [MCP entry](integrations/mcp-clients/cursor.mcp.json) | documented only |
153
159
  | VS Code | [MCP entry](integrations/mcp-clients/vscode.mcp.json) | documented only |
154
160
  | Claude Desktop | [MCP entry](integrations/mcp-clients/claude-desktop.json) | documented only |
@@ -267,6 +267,46 @@
267
267
  ],
268
268
  "tools": []
269
269
  },
270
+ {
271
+ "id": "newsletter-note",
272
+ "title": "Newsletter note from the facts",
273
+ "description": "Writes a short newsletter note, under 120 words, that tells your readers what your new video, podcast or talk is about and points them to it, using only the facts sheet. Use after \"Facts from a video\", or with your own list of what you said, when you want to send your list a note in your voice.",
274
+ "version": "1.0.0",
275
+ "license": "MIT",
276
+ "author": "Mindburn Labs",
277
+ "tags": [
278
+ "social",
279
+ "marketing"
280
+ ],
281
+ "time": "about 1 minute",
282
+ "path": "factories/newsletter-note",
283
+ "sha256": "533ee09b58d3f53f4683bf3313c0382eb904bf4939e8fa1bbe747cd2f3677ff5",
284
+ "runnable": true,
285
+ "inputs": [
286
+ {
287
+ "key": "facts",
288
+ "type": "longtext",
289
+ "required": true
290
+ },
291
+ {
292
+ "key": "transcript",
293
+ "type": "longtext",
294
+ "required": false
295
+ },
296
+ {
297
+ "key": "about_you",
298
+ "type": "text",
299
+ "required": false
300
+ }
301
+ ],
302
+ "steps": 2,
303
+ "decision": false,
304
+ "agents": [
305
+ "reviewer",
306
+ "writer"
307
+ ],
308
+ "tools": []
309
+ },
270
310
  {
271
311
  "id": "outreach-pack",
272
312
  "title": "Outreach pack",
@@ -351,6 +391,197 @@
351
391
  "web_fetch",
352
392
  "web_search"
353
393
  ]
394
+ },
395
+ {
396
+ "id": "release-desk",
397
+ "title": "Release desk",
398
+ "description": "Puts the posts, the short-video script and the newsletter note written from one video into a single release packet: the week at a glance, every piece checked against the others and the facts sheet, and every claim listed with the words it rests on, for you to approve once. Use when the pieces are written and you want to read them side by side before any goes out.",
399
+ "version": "1.0.0",
400
+ "license": "MIT",
401
+ "author": "Mindburn Labs",
402
+ "tags": [
403
+ "social",
404
+ "marketing"
405
+ ],
406
+ "time": "about 2 minutes, then your approval",
407
+ "path": "factories/release-desk",
408
+ "sha256": "13c086430906e2f1ff11afeddbd4e2449b704a3e441b17c8b7daf53555d8c02e",
409
+ "runnable": true,
410
+ "inputs": [
411
+ {
412
+ "key": "facts",
413
+ "type": "longtext",
414
+ "required": true
415
+ },
416
+ {
417
+ "key": "posts",
418
+ "type": "longtext",
419
+ "required": false
420
+ },
421
+ {
422
+ "key": "short_video",
423
+ "type": "longtext",
424
+ "required": false
425
+ },
426
+ {
427
+ "key": "newsletter",
428
+ "type": "longtext",
429
+ "required": false
430
+ }
431
+ ],
432
+ "steps": 3,
433
+ "decision": true,
434
+ "agents": [
435
+ "editor",
436
+ "reviewer"
437
+ ],
438
+ "tools": []
439
+ },
440
+ {
441
+ "id": "short-video-cut",
442
+ "title": "Short-video script and cut list from the facts",
443
+ "description": "Writes a 30-second script for TikTok, Reels or Shorts and a cut list from the facts sheet of one video, podcast or talk: a hook, three beats and a closing line, each clip with the timestamp and the exact words where it starts and ends. Use after \"Facts from a video\", or with your own list of what you said, when you want a short cut that says only what you said.",
444
+ "version": "1.0.0",
445
+ "license": "MIT",
446
+ "author": "Mindburn Labs",
447
+ "tags": [
448
+ "social",
449
+ "marketing"
450
+ ],
451
+ "time": "about 2 minutes",
452
+ "path": "factories/short-video-cut",
453
+ "sha256": "67ebc881b8a7e28b1f4a2e4cfa7fdf78096ccb54ed77058854f1ab7e7ad0b3c2",
454
+ "runnable": true,
455
+ "inputs": [
456
+ {
457
+ "key": "facts",
458
+ "type": "longtext",
459
+ "required": true
460
+ },
461
+ {
462
+ "key": "transcript",
463
+ "type": "longtext",
464
+ "required": false
465
+ },
466
+ {
467
+ "key": "about_you",
468
+ "type": "text",
469
+ "required": false
470
+ }
471
+ ],
472
+ "steps": 2,
473
+ "decision": false,
474
+ "agents": [
475
+ "reviewer",
476
+ "writer"
477
+ ],
478
+ "tools": []
479
+ },
480
+ {
481
+ "id": "video-facts",
482
+ "title": "Facts from a video",
483
+ "description": "Reads the transcript of one video, podcast or talk and writes a facts sheet: every number, result, claim and quote the speaker states, in their own words, with each hedge kept and a timestamp or the first words for each. Use before you write posts, clips or a newsletter from a video, so every line can be checked against what was actually said.",
484
+ "version": "1.0.0",
485
+ "license": "MIT",
486
+ "author": "Mindburn Labs",
487
+ "tags": [
488
+ "social",
489
+ "marketing"
490
+ ],
491
+ "time": "about 2 minutes",
492
+ "path": "factories/video-facts",
493
+ "sha256": "59f85f0120282f88089d12567e7b918fe07f142fc649e0cd5fc0b1dad60bf818",
494
+ "runnable": true,
495
+ "inputs": [
496
+ {
497
+ "key": "transcript",
498
+ "type": "longtext",
499
+ "required": true
500
+ }
501
+ ],
502
+ "steps": 2,
503
+ "decision": false,
504
+ "agents": [
505
+ "analyst",
506
+ "reviewer"
507
+ ],
508
+ "tools": []
509
+ },
510
+ {
511
+ "id": "video-to-posts",
512
+ "title": "One video, a week of posts",
513
+ "description": "Turns the transcript of one video, podcast or talk into a week of posts for X, LinkedIn, a short video and a newsletter, using only what the speaker said. Use after you put out a video on YouTube or TikTok, or a podcast episode, and want posts that say nothing you did not say.",
514
+ "version": "1.0.0",
515
+ "license": "MIT",
516
+ "author": "Mindburn Labs",
517
+ "tags": [
518
+ "social",
519
+ "marketing"
520
+ ],
521
+ "time": "about 3 minutes",
522
+ "path": "factories/video-to-posts",
523
+ "sha256": "b85b36c4ac3520d3256be897c17f18e5396dddacc75369582a4c795196336a3f",
524
+ "runnable": true,
525
+ "inputs": [
526
+ {
527
+ "key": "transcript",
528
+ "type": "longtext",
529
+ "required": true
530
+ },
531
+ {
532
+ "key": "about_you",
533
+ "type": "text",
534
+ "required": false
535
+ }
536
+ ],
537
+ "steps": 4,
538
+ "decision": true,
539
+ "agents": [
540
+ "analyst",
541
+ "reviewer",
542
+ "writer"
543
+ ],
544
+ "tools": []
545
+ },
546
+ {
547
+ "id": "week-of-posts",
548
+ "title": "X and LinkedIn posts from the facts",
549
+ "description": "Writes an X thread, two single posts and a LinkedIn post from the facts sheet of one video, podcast or talk, in the speaker's voice, saying nothing the facts sheet does not say. Use after \"Facts from a video\", or with your own list of what you said, when you want posts you can put your name to.",
550
+ "version": "1.0.0",
551
+ "license": "MIT",
552
+ "author": "Mindburn Labs",
553
+ "tags": [
554
+ "social",
555
+ "marketing"
556
+ ],
557
+ "time": "about 2 minutes",
558
+ "path": "factories/week-of-posts",
559
+ "sha256": "935bbb60f363d53382e106d929d6fadc2dda267c233070a2b468f243d830ecb0",
560
+ "runnable": true,
561
+ "inputs": [
562
+ {
563
+ "key": "facts",
564
+ "type": "longtext",
565
+ "required": true
566
+ },
567
+ {
568
+ "key": "transcript",
569
+ "type": "longtext",
570
+ "required": false
571
+ },
572
+ {
573
+ "key": "about_you",
574
+ "type": "text",
575
+ "required": false
576
+ }
577
+ ],
578
+ "steps": 2,
579
+ "decision": false,
580
+ "agents": [
581
+ "reviewer",
582
+ "writer"
583
+ ],
584
+ "tools": []
354
585
  }
355
586
  ]
356
587
  }
@@ -0,0 +1,11 @@
1
+ # Newsletter note from the facts
2
+
3
+ Paste the facts sheet of a video, podcast or talk, and the transcript if you have it. You get a note under 120 words for your newsletter that says what the video is about and points readers to it, with "[ADD: link to the video]" where the link goes. A checker holds every sentence against the facts sheet and sends back anything stronger than what you said.
4
+
5
+ The facts sheet can come from "Facts from a video", or you can write your own: one fact a line, each with its timestamp or the first words of the line. "Release desk" puts the note together with the other pieces for one approval.
6
+
7
+ ## Try it on the example
8
+
9
+ The example is invented: Maya, her flat and her video do not exist. Its facts sheet is the one "Facts from a video" should write from her transcript. On the factory page, "Fill in the example" pastes it for you.
10
+
11
+ The example is in `mindburn.tests.yaml`. With the downloaded folder, `node run.mjs --test` runs it and checks that the note leaves the link for you and makes none of the easy roundings. Passing checks are a repeatable regression signal, not proof that every facts sheet will be handled correctly.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Checks work against stated criteria and sends weak work back.
3
+ agentType: REVIEW
4
+ ---
5
+
6
+ You are the reviewer. You hold one piece of work against the criteria you are given and decide whether it passes.
7
+
8
+ - You judge only what is on the page and only against the stated criteria.
9
+ - You fail work for a clear, specific breach you can point to. You never fail it for taste, or for something nobody asked for.
10
+ - When you send work back, each reason is one concrete sentence the author can act on.
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: Writes the finished words the person will use or send.
3
+ agentType: CUSTOM
4
+ ---
5
+
6
+ You are the writer. You write the finished thing the person will use: the brief, the message, the page, the report.
7
+
8
+ - Plain words, short sentences, the reader's own vocabulary. No filler and no hype.
9
+ - You keep to the sections, word limits and order the step asks for.
10
+ - You add no fact that is not in the inputs or earlier results. Where a real asset or decision is missing, you mark the gap clearly instead of inventing it.
11
+ - What you write should be usable as it stands.
@@ -0,0 +1,12 @@
1
+ schemaVersion: v1alpha1
2
+ name: newsletter-note
3
+ description: |
4
+ Writes a short newsletter note, under 120 words, that tells your readers
5
+ what your new video, podcast or talk is about and points them to it, using
6
+ only the facts sheet. Use after "Facts from a video", or with your own list
7
+ of what you said, when you want to send your list a note in your voice.
8
+ repositories: []
9
+ agentDefaults:
10
+ harness:
11
+ type: claude
12
+ model: sonnet
@@ -0,0 +1,45 @@
1
+ flow: mindburn.flow/v1
2
+ title: Newsletter note from the facts
3
+ author: Mindburn Labs
4
+ version: "1.0.0"
5
+ license: MIT
6
+ tags: [social, marketing]
7
+ time: about 1 minute
8
+ inputs:
9
+ facts:
10
+ type: longtext
11
+ help: "The facts sheet from \"Facts from a video\", or your own list of what you said: one fact a line, each with its timestamp or the first words of the line."
12
+ transcript:
13
+ type: longtext
14
+ optional: true
15
+ help: "The transcript the facts came from. With it, the note can use your exact wording."
16
+ about_you:
17
+ type: text
18
+ optional: true
19
+ help: "Who you are and who reads your newsletter, for example \"I make short videos about building small apps; most of my readers are students\". It sets the voice, not the facts."
20
+ steps:
21
+ note:
22
+ title: Write the newsletter note
23
+ agent: writer
24
+ kind: deliver
25
+ task: |
26
+ Write a note for the speaker's newsletter that tells readers what the video is about and points them to it, in the speaker's voice and, wherever you can, in the speaker's own words as the facts sheet quotes them. Use about_you only for the voice and the audience, never as a source of facts. Sections, in this order:
27
+
28
+ 1. **Newsletter note**: under 120 words, with "[ADD: link to the video]" where the link goes.
29
+ 2. **Facts used**: every factual claim the note makes, each with the facts-sheet ID if the sheet has IDs, its timestamp or first words, and the exact words it rests on.
30
+
31
+ Every fact comes from the facts sheet. If the transcript is given, you may take the speaker's exact wording from it, but only for facts the sheet has. Never round a number, shorten or lengthen a time span, make a result bigger or more certain, drop a qualifier that keeps a claim modest, state an opinion as a fact, work out a figure the sheet does not state, or name a person the sheet does not name. A fact the sheet marks "unclear" is not stated as settled. Write no link, address or date yourself. Add no hype the speaker did not use, and no exclamation marks or emojis unless the sheet quotes them.
32
+ check_note:
33
+ title: Check the note against the facts sheet
34
+ agent: reviewer
35
+ kind: check
36
+ needs: [note]
37
+ checks: note
38
+ task: |
39
+ Compare every sentence of the note with the facts sheet, and with the transcript if it is given. Each number, time span, name, result and quote is on the facts sheet with the same meaning. Send back anything rounded, worked out, made bigger or more certain, a dropped qualifier, an opinion stated as fact, a fact marked "unclear" stated as settled, a quote that is not word for word, and any fact the sheet does not have.
40
+
41
+ Then check the shape: both sections are present and in order, the note is under 120 words, "[ADD: link to the video]" appears in it and no other link or address does, and every factual claim appears under "Facts used". When you send work back, quote the note's words and the source's words side by side so the writer can correct them.
42
+ done:
43
+ - "Every number, time span, name and quote in the note is on the facts sheet, with the same meaning."
44
+ - "The note is under 120 words and marks the link with \"[ADD: link to the video]\" instead of inventing one."
45
+ - "Every factual claim is listed under \"Facts used\" with the words it rests on."
@@ -0,0 +1,80 @@
1
+ version: 1
2
+ cases:
3
+ frying_pan_note:
4
+ name: Writes a short note that leaves the link for the speaker to add
5
+ inputs:
6
+ facts: |
7
+ ## Facts
8
+
9
+ | ID | Where | Fact | Exact words |
10
+ | --- | --- | --- | --- |
11
+ | F1 | [0:00] | The video is the story of how a frying pan made the speaker build an app. | "So this is the story of how a frying pan made me build an app." |
12
+ | F2 | [0:06] | The flat's group chat had 212 messages in one month; the speaker counted them. | "Our flat group chat had 212 messages in one month. I counted." |
13
+ | F3 | [0:06] | Most of those messages were about one frying pan that nobody would wash. | "Most of them were about one frying pan that nobody would wash." |
14
+ | F4 | [0:18] | Five people live in the flat. | "There are five of us in the flat." |
15
+ | F5 | [0:18] | Everyone thought they did the most dishes, and everyone was wrong, the speaker included. | "Everyone thought they did the most dishes. Everyone was wrong, including me." |
16
+ | F6 | [0:31] | The speaker is not a programmer: one coding course at school, most of it forgotten. | "I'm not a programmer. I did one coding course at school and forgot most of it." |
17
+ | F7 | [0:31] | The speaker had been using an AI coding assistant for small things. | "But I'd been using an AI coding assistant for small things" |
18
+ | F8 | [0:47] | The app took two weekends, maybe three counting the weekend spent on the logo. | "It took me two weekends. Maybe three, if you count the weekend I spent on the logo." |
19
+ | F9 | [0:55] | The speaker's first lesson: a whole Saturday went on a logo, and nobody has ever mentioned it. | "I spent a whole Saturday on a logo, and not one person has ever mentioned the logo. Not one." |
20
+ | F10 | [1:06] | When something needs washing, you tap one button, and the app messages the one person who has done the fewest dishes this week. | "When something needs washing, you tap one button. The app looks at who has done the fewest dishes this week and sends that one person a message." |
21
+ | F11 | [1:06] | The app has no points, no leaderboard and no badges. | "No points, no leaderboard, no badges." |
22
+ | F12 | [1:27] | Points came first and made it worse: one flatmate washed single teaspoons to collect points. | "I tried points first. Points made it worse. One flatmate started washing single teaspoons to collect points." |
23
+ | F13 | [1:38] | The speaker's opinion, called a hot take: most chore apps fail because they turn chores into a game. | "So here's my hot take: most chore apps fail because they turn chores into a game." |
24
+ | F14 | [1:38] | Nobody in the flat wanted a game; they wanted the arguing to stop. | "Nobody in my flat wanted a game. We wanted the arguing to stop." |
25
+ | F15 | [1:50] | The group chat went from 212 messages to 9 messages last month, and three of those were about pizza. | "The group chat went from 212 messages to, I checked last night, 9 messages last month. And three of those were about pizza." |
26
+ | F16 | [2:04] | After a friend posted about it, people from other flats started asking for it. | "Then a friend posted about it, and people from other flats started asking for it." |
27
+ | F17 | [2:04] | 38 people signed up in the first week, mostly friends of friends. | "38 people signed up in the first week. Mostly friends of friends, to be fair." |
28
+ | F18 | [2:04] | 11 of them used it again the next day. | "11 of them used it again the next day, which for an app about dishes I'll take." |
29
+ | F19 | [2:22] | Running it costs three pounds a month, after a correction. | "It costs me about four, no, three pounds a month to run. Three." |
30
+ | F20 | [2:28] | What the speaker would do differently: skip the logo, and ask the flatmates what annoyed them before writing a single line. They guessed fairness; it was the frying pan. | "What I'd do differently: skip the logo, and ask my flatmates what annoyed them before writing a single line. I guessed it was fairness. It was the frying pan." |
31
+ | F21 | [2:42] | The speaker's advice: start with the one message the app sends, and write that message first. | "If you build something like this, start with the one message the app sends. Write that message first. Everything else is decoration." |
32
+ | F22 | [2:51] | The pan is clean, for now. | "The pan is clean. For now." |
33
+
34
+ ## Quotes worth using
35
+
36
+ - [0:06] "Our flat group chat had 212 messages in one month. I counted." (F2)
37
+ - [0:55] "not one person has ever mentioned the logo. Not one." (F9)
38
+ - [1:06] "No points, no leaderboard, no badges." (F11)
39
+ - [1:27] "One flatmate started washing single teaspoons to collect points." (F12)
40
+ - [1:38] "We wanted the arguing to stop." (F14)
41
+ - [2:28] "I guessed it was fairness. It was the frying pan." (F20)
42
+ - [2:42] "Write that message first. Everything else is decoration." (F21)
43
+ - [2:51] "The pan is clean. For now." (F22)
44
+
45
+ ## Corrections and unclear
46
+
47
+ - [2:22] The running cost: the speaker says "about four, no, three pounds a month", then "Three." The corrected figure, three pounds a month, is the fact (F19).
48
+ - [0:47] and [0:55] The time on the logo is said two ways: "the weekend I spent on the logo" and "a whole Saturday on a logo". Unclear: quote each where it is said, and do not state how long the logo took.
49
+
50
+ ## Names
51
+
52
+ No one other than the speaker is named.
53
+ transcript: |
54
+ [0:00] So this is the story of how a frying pan made me build an app.
55
+ [0:06] Our flat group chat had 212 messages in one month. I counted. Most of them were about one frying pan that nobody would wash.
56
+ [0:18] There are five of us in the flat. Everyone thought they did the most dishes. Everyone was wrong, including me.
57
+ [0:31] I'm not a programmer. I did one coding course at school and forgot most of it. But I'd been using an AI coding assistant for small things, and I thought, okay, how hard can a dishes app be?
58
+ [0:47] It took me two weekends. Maybe three, if you count the weekend I spent on the logo.
59
+ [0:55] And that's my first lesson. I spent a whole Saturday on a logo, and not one person has ever mentioned the logo. Not one.
60
+ [1:06] Here's how it works, and honestly the trick is how little it does. When something needs washing, you tap one button. The app looks at who has done the fewest dishes this week and sends that one person a message. That's it. No points, no leaderboard, no badges.
61
+ [1:27] I tried points first. Points made it worse. One flatmate started washing single teaspoons to collect points.
62
+ [1:38] So here's my hot take: most chore apps fail because they turn chores into a game. Nobody in my flat wanted a game. We wanted the arguing to stop.
63
+ [1:50] Did it work? The group chat went from 212 messages to, I checked last night, 9 messages last month. And three of those were about pizza.
64
+ [2:04] Then a friend posted about it, and people from other flats started asking for it. 38 people signed up in the first week. Mostly friends of friends, to be fair. 11 of them used it again the next day, which for an app about dishes I'll take.
65
+ [2:22] It costs me about four, no, three pounds a month to run. Three.
66
+ [2:28] What I'd do differently: skip the logo, and ask my flatmates what annoyed them before writing a single line. I guessed it was fairness. It was the frying pan. It's always one frying pan.
67
+ [2:42] If you build something like this, start with the one message the app sends. Write that message first. Everything else is decoration.
68
+ [2:51] Anyway. The pan is clean. For now.
69
+ # Invented sample: Maya, her flat and this video do not exist. The
70
+ # disclosure stays out of the inputs so it does not leak into the result;
71
+ # the README carries it.
72
+ about_you: "I'm Maya. I make short videos about building small apps; most of my viewers are students and first-time builders."
73
+ # The facts sheet is the reference result of "Facts from a video" on the
74
+ # same transcript. Contains: the placeholder for the link, never an invented
75
+ # one. Excludes: the roundings the transcript invites and claims she never made.
76
+ expect:
77
+ contains: ["[ADD: link to the video]", "Facts used", "frying pan"]
78
+ excludes: ["went viral", "in one weekend", "in a weekend", "40 people", "nearly 40", "almost 40", "never coded", "£4", "four pounds a month", "96%", "29%"]
79
+ min_length: 400
80
+ max_length: 4000
@@ -0,0 +1,13 @@
1
+ # Release desk
2
+
3
+ Paste the facts sheet and the pieces written from one video: the X and LinkedIn posts, the short-video script and the newsletter note. Leave out any piece you do not have. You get one release packet: the week at a glance, each piece as written, and under "Before you post" every claim once with the words it rests on, every name to ask about and every placeholder still to fill.
4
+
5
+ A checker reads the pieces together. A number that reads one way in a post and another way in the newsletter, a claim the facts sheet does not have, or a line changed without saying so goes back to the desk. Where a piece contradicts the facts sheet, the desk brings that line back to it and lists the change, without repeating the wrong words. Then you approve once: these go out under your name. Nothing is posted for you: you copy what you approve.
6
+
7
+ The pieces can come from "X and LinkedIn posts from the facts", "Short-video script and cut list from the facts" and "Newsletter note from the facts", which all write from the sheet "Facts from a video" makes, or you can paste pieces you wrote yourself.
8
+
9
+ ## Try it on the example
10
+
11
+ The example is invented: Maya, her flat and her video do not exist. Its facts sheet and pieces are written from her transcript, except that two pieces round a figure up, as a person writing by hand might: the short video says the app costs four pounds a month, and the newsletter says nearly 40 people signed up. The packet has to bring both back to the facts sheet. On the factory page, "Fill in the example" pastes it for you.
12
+
13
+ The example is in `mindburn.tests.yaml`. With the downloaded folder, `node run.mjs --test --yes` runs it, approves the packet for you and checks that both roundings are gone. Passing checks are a repeatable regression signal, not proof that every set of pieces will be handled correctly.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Puts checked pieces together into one packet without rewriting them.
3
+ agentType: CUSTOM
4
+ ---
5
+
6
+ You are the editor at the release desk. You take pieces that were written and checked separately and put them together, so one person can read them side by side and approve them once.
7
+
8
+ - You keep each piece as it was written. You change a line only where it contradicts the source or another piece, and then only to say what the source says.
9
+ - You list every change you make, so the person can see it.
10
+ - You add nothing: no new facts, posts, names, links or hashtags.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Checks work against stated criteria and sends weak work back.
3
+ agentType: REVIEW
4
+ ---
5
+
6
+ You are the reviewer. You hold one piece of work against the criteria you are given and decide whether it passes.
7
+
8
+ - You judge only what is on the page and only against the stated criteria.
9
+ - You fail work for a clear, specific breach you can point to. You never fail it for taste, or for something nobody asked for.
10
+ - When you send work back, each reason is one concrete sentence the author can act on.
@@ -0,0 +1,13 @@
1
+ schemaVersion: v1alpha1
2
+ name: release-desk
3
+ description: |
4
+ Puts the posts, the short-video script and the newsletter note written from
5
+ one video into a single release packet: the week at a glance, every piece
6
+ checked against the others and the facts sheet, and every claim listed with
7
+ the words it rests on, for you to approve once. Use when the pieces are
8
+ written and you want to read them side by side before any goes out.
9
+ repositories: []
10
+ agentDefaults:
11
+ harness:
12
+ type: claude
13
+ model: sonnet
@@ -0,0 +1,67 @@
1
+ flow: mindburn.flow/v1
2
+ title: Release desk
3
+ author: Mindburn Labs
4
+ version: "1.0.0"
5
+ license: MIT
6
+ tags: [social, marketing]
7
+ time: about 2 minutes, then your approval
8
+ inputs:
9
+ facts:
10
+ type: longtext
11
+ help: "The facts sheet the pieces were written from, such as the one \"Facts from a video\" writes."
12
+ posts:
13
+ type: longtext
14
+ optional: true
15
+ help: "The X posts and the LinkedIn post, as written. Leave it empty if you have none."
16
+ short_video:
17
+ type: longtext
18
+ optional: true
19
+ help: "The short-video script and its cut list, as written. Leave it empty if you have none."
20
+ newsletter:
21
+ type: longtext
22
+ optional: true
23
+ help: "The newsletter note, as written. Leave it empty if you have none."
24
+ steps:
25
+ packet:
26
+ title: Assemble the release packet
27
+ agent: editor
28
+ kind: deliver
29
+ task: |
30
+ Put the pieces you were given into one release packet that the speaker can approve once and copy from. Sections, in this order:
31
+
32
+ 1. **The week at a glance**: a table with columns Day, Channel, Piece, First line. One row for each post, script and note, on days 1 to 7, no piece on two days. First line is the piece's first line as written.
33
+ 2. **X**: the thread and the single posts.
34
+ 3. **LinkedIn**: the post.
35
+ 4. **Short video**: the script and the cut list.
36
+ 5. **Newsletter**: the note.
37
+ 6. **Before you post**: every factual claim across all the pieces, once each, with the facts-sheet ID if the sheet has IDs, its timestamp or first words, and the exact words it rests on; every person or company the pieces name other than the speaker, so they can be asked; every "[ADD: ...]" still to fill; anything the facts sheet marks "unclear" that a piece touches; and the pieces that were not given.
38
+ 7. **Changes at the desk**: each change you made, or "None."
39
+
40
+ Copy each piece as written, without its own list of facts used: those claims go into "Before you post". If a piece was not given, keep its heading and write "Not given." under it. Change a line only where it contradicts the facts sheet or another piece, and then only to say what the facts sheet says, in the piece's own voice. List each change under "Changes at the desk" by piece and line, with the fact it now rests on. Describe the fix without repeating the wrong words, so nothing wrong can be copied from the packet. Add no posts, facts, names, links or hashtags.
41
+ check_packet:
42
+ title: Check the pieces against each other and the facts
43
+ agent: reviewer
44
+ kind: check
45
+ needs: [packet]
46
+ checks: packet
47
+ task: |
48
+ Check the packet as a whole against the facts sheet and the pieces as given.
49
+
50
+ - No contradictions: every number, time span, name and result reads the same way in every piece, with the same qualifiers.
51
+ - Every claim traceable: each factual claim in the packet is on the facts sheet with the same meaning, and is listed under "Before you post" with the words it rests on.
52
+ - Nothing invented: no fact, figure, name, quote, link or hashtag appears that the facts sheet or the pieces as given do not have, and no "[ADD: ...]" is filled in.
53
+ - Copied faithfully: every line not listed under "Changes at the desk" is word for word as given; every listed change only brings a line back to the facts sheet; the wrong words are not repeated anywhere in the packet.
54
+ - Shape: all seven sections are present and in order, the week at a glance has each piece once and on one day, and a piece that was not given says "Not given." and is named under "Before you post".
55
+
56
+ Send back any breach. When you do, quote the packet's words and the source's words side by side so the editor can correct them.
57
+ approve_packet:
58
+ title: Approve the release packet
59
+ kind: approve
60
+ needs: [check_packet]
61
+ shows: packet
62
+ task: |
63
+ These go out under your name. Approve the packet, or say what to change: a piece to drop, a line that does not sound like you, a fact that is wrong. Nothing is posted for you: you copy what you approve.
64
+ done:
65
+ - "No number, time span, name or result reads differently in two pieces."
66
+ - "Every factual claim in the packet is on the facts sheet and listed under \"Before you post\" with the words it rests on."
67
+ - "Nothing appears that the facts sheet and the pieces as given do not have, and every change at the desk is listed."