agentbox-app 0.1.6

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 (302) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +176 -0
  3. package/bin/agentbox.mjs +103 -0
  4. package/briefs/adhd-mode.md +5 -0
  5. package/briefs/message-rules.md +95 -0
  6. package/briefs/worker.md +230 -0
  7. package/briefs/writing-rules.md +336 -0
  8. package/main/account-discovery.mjs +145 -0
  9. package/main/account-tooling.mjs +261 -0
  10. package/main/agent-activity.mjs +56 -0
  11. package/main/agent-files.mjs +422 -0
  12. package/main/agent-schedule.mjs +254 -0
  13. package/main/agent-sessions.mjs +435 -0
  14. package/main/agents.mjs +1095 -0
  15. package/main/analytics.mjs +206 -0
  16. package/main/answer-modes.mjs +206 -0
  17. package/main/approval-prompt-server.mjs +160 -0
  18. package/main/approvals.mjs +487 -0
  19. package/main/artifact-path.mjs +144 -0
  20. package/main/claude-bin.mjs +311 -0
  21. package/main/claude-input.mjs +117 -0
  22. package/main/claude-models.mjs +244 -0
  23. package/main/claude-plan.mjs +148 -0
  24. package/main/claude-usage.mjs +149 -0
  25. package/main/code-change.mjs +383 -0
  26. package/main/code-file.mjs +116 -0
  27. package/main/codex-account.mjs +146 -0
  28. package/main/codex-app-server.mjs +796 -0
  29. package/main/codex-approvals.mjs +712 -0
  30. package/main/codex-bin.mjs +261 -0
  31. package/main/codex-compaction.mjs +49 -0
  32. package/main/codex-models.mjs +194 -0
  33. package/main/codex-session.mjs +797 -0
  34. package/main/codex-threads.mjs +268 -0
  35. package/main/codex-usage-file.mjs +192 -0
  36. package/main/codex-usage.mjs +149 -0
  37. package/main/codex-watch.mjs +35 -0
  38. package/main/codex.mjs +757 -0
  39. package/main/config.mjs +345 -0
  40. package/main/copy-selection.mjs +55 -0
  41. package/main/crash-report.mjs +158 -0
  42. package/main/demo.mjs +254 -0
  43. package/main/dev-window.mjs +103 -0
  44. package/main/doc-file.mjs +99 -0
  45. package/main/doc-scheme.mjs +126 -0
  46. package/main/first-run.mjs +190 -0
  47. package/main/folders.mjs +91 -0
  48. package/main/fresh-user.mjs +120 -0
  49. package/main/git-change.mjs +323 -0
  50. package/main/img-scheme.mjs +90 -0
  51. package/main/instruction-settings.mjs +205 -0
  52. package/main/ipc.mjs +1558 -0
  53. package/main/live-replies.mjs +77 -0
  54. package/main/machine.mjs +113 -0
  55. package/main/main.mjs +972 -0
  56. package/main/menu.mjs +177 -0
  57. package/main/notify.mjs +155 -0
  58. package/main/open-source-file.mjs +8 -0
  59. package/main/project-identity.mjs +149 -0
  60. package/main/provider-commands.mjs +32 -0
  61. package/main/rail-note.mjs +74 -0
  62. package/main/repeats.mjs +261 -0
  63. package/main/row-label.mjs +185 -0
  64. package/main/screen-detail.mjs +44 -0
  65. package/main/serve.mjs +262 -0
  66. package/main/settings.mjs +912 -0
  67. package/main/staleness.mjs +76 -0
  68. package/main/store/chats.mjs +188 -0
  69. package/main/store/home.mjs +383 -0
  70. package/main/store/migrate.mjs +40 -0
  71. package/main/store/paths.mjs +82 -0
  72. package/main/store/pending-writes.mjs +122 -0
  73. package/main/store/project-lock.mjs +200 -0
  74. package/main/store/project.mjs +523 -0
  75. package/main/store/queues.mjs +31 -0
  76. package/main/store/work-items.mjs +299 -0
  77. package/main/store/write-queue.mjs +14 -0
  78. package/main/store-modules.mjs +23 -0
  79. package/main/store.mjs +1269 -0
  80. package/main/supervisor.mjs +6875 -0
  81. package/main/task-commands.mjs +161 -0
  82. package/main/task-folders-offthread.mjs +84 -0
  83. package/main/task-folders-thread.mjs +13 -0
  84. package/main/task-folders.mjs +409 -0
  85. package/main/task-remote-control.mjs +65 -0
  86. package/main/task-terminals.mjs +169 -0
  87. package/main/terminal-access.mjs +6 -0
  88. package/main/updater.mjs +240 -0
  89. package/main/zoom-keys.mjs +54 -0
  90. package/main/zoom-readout.mjs +20 -0
  91. package/mcp/agentbox-mcp.sh +34 -0
  92. package/mcp/core/account.mjs +77 -0
  93. package/mcp/core/chat.mjs +61 -0
  94. package/mcp/core/documents.mjs +238 -0
  95. package/mcp/core/page.mjs +152 -0
  96. package/mcp/core/products.mjs +110 -0
  97. package/mcp/core/skills.mjs +126 -0
  98. package/mcp/core/work.mjs +377 -0
  99. package/mcp/stdio.mjs +70 -0
  100. package/mcp/tools.mjs +257 -0
  101. package/package.json +186 -0
  102. package/renderer/dist/assets/Geist-Variable-Bj2R_7yk.woff2 +0 -0
  103. package/renderer/dist/assets/GeistMono-Variable-Dispecij.woff2 +0 -0
  104. package/renderer/dist/assets/addon-fit-YJmn1quW.js +12 -0
  105. package/renderer/dist/assets/addon-serialize-CsFQTvP_.js +13 -0
  106. package/renderer/dist/assets/cel-dusk-CS5I7kJS.webp +0 -0
  107. package/renderer/dist/assets/cel-dusk-DUslqS6B.webp +0 -0
  108. package/renderer/dist/assets/cel-dusk-Jt_xVGxp.webp +0 -0
  109. package/renderer/dist/assets/cel-dusk-sm-BBkV-tWT.webp +0 -0
  110. package/renderer/dist/assets/frost-haze-CxPSOBEg.webp +0 -0
  111. package/renderer/dist/assets/frost-haze-sm-C_w21qgd.webp +0 -0
  112. package/renderer/dist/assets/gouache-valley-ChSu14-t.webp +0 -0
  113. package/renderer/dist/assets/gouache-valley-d9qasI6k.webp +0 -0
  114. package/renderer/dist/assets/gouache-valley-sm-CdLjT5Ec.webp +0 -0
  115. package/renderer/dist/assets/ice-BC8luINc.webp +0 -0
  116. package/renderer/dist/assets/ice-CP9PrKHo.webp +0 -0
  117. package/renderer/dist/assets/ice-river-D6ziOhLY.webp +0 -0
  118. package/renderer/dist/assets/ice-river-UVM2-JY_.webp +0 -0
  119. package/renderer/dist/assets/ice-river-bErJwYWW.webp +0 -0
  120. package/renderer/dist/assets/ice-river-sm-Bg1U-SIj.webp +0 -0
  121. package/renderer/dist/assets/ice-sm-CbVcg3_D.webp +0 -0
  122. package/renderer/dist/assets/index-CwiDv5bL.css +32 -0
  123. package/renderer/dist/assets/index-D9hCAVPl.js +684 -0
  124. package/renderer/dist/assets/lake-C0WaW-6E.webp +0 -0
  125. package/renderer/dist/assets/lake-CSKjLC5K.webp +0 -0
  126. package/renderer/dist/assets/lake-ETGcOb25.webp +0 -0
  127. package/renderer/dist/assets/lake-harbour-BCQRbrHb.webp +0 -0
  128. package/renderer/dist/assets/lake-harbour-B_wfXTmE.webp +0 -0
  129. package/renderer/dist/assets/lake-harbour-Te1pEvBh.webp +0 -0
  130. package/renderer/dist/assets/lake-harbour-sm-Cme_ShEg.webp +0 -0
  131. package/renderer/dist/assets/lake-sm-CbG72Hbv.webp +0 -0
  132. package/renderer/dist/assets/lino-coast-CUZHcucI.webp +0 -0
  133. package/renderer/dist/assets/lino-coast-DP4J7cgd.webp +0 -0
  134. package/renderer/dist/assets/lino-coast-kOIAffr_.webp +0 -0
  135. package/renderer/dist/assets/lino-coast-sm-C1Mdbgit.webp +0 -0
  136. package/renderer/dist/assets/moon-pines-BskgnnXR.webp +0 -0
  137. package/renderer/dist/assets/moon-pines-CFSIIwt0.webp +0 -0
  138. package/renderer/dist/assets/moon-pines-PNhdOYww.webp +0 -0
  139. package/renderer/dist/assets/moon-pines-sm-C6K1NomK.webp +0 -0
  140. package/renderer/dist/assets/orbit-rings-2XV36Ch3.webp +0 -0
  141. package/renderer/dist/assets/orbit-rings-C4NrcYGQ.webp +0 -0
  142. package/renderer/dist/assets/orbit-rings-DGLk07dT.webp +0 -0
  143. package/renderer/dist/assets/orbit-rings-sm-Dky3YdvL.webp +0 -0
  144. package/renderer/dist/assets/peach-haze-2-C6f7xnWw.webp +0 -0
  145. package/renderer/dist/assets/peach-haze-2-sm-Dj_Ez_Sb.webp +0 -0
  146. package/renderer/dist/assets/pixel-harbour-DQjqMROg.webp +0 -0
  147. package/renderer/dist/assets/pixel-harbour-Dw71H_bc.webp +0 -0
  148. package/renderer/dist/assets/pixel-harbour-kOZfm-GM.webp +0 -0
  149. package/renderer/dist/assets/pixel-harbour-sm-Dturjuky.webp +0 -0
  150. package/renderer/dist/assets/pixel-orbit-C296JVMO.webp +0 -0
  151. package/renderer/dist/assets/pixel-orbit-C4oMRDSx.webp +0 -0
  152. package/renderer/dist/assets/pixel-orbit-CqVmQ4eh.webp +0 -0
  153. package/renderer/dist/assets/pixel-orbit-sm-CHagC_nO.webp +0 -0
  154. package/renderer/dist/assets/pixel-ridge-C6LYu6uE.webp +0 -0
  155. package/renderer/dist/assets/pixel-ridge-CIUCEESs.webp +0 -0
  156. package/renderer/dist/assets/pixel-ridge-sm-BnE0F_w-.webp +0 -0
  157. package/renderer/dist/assets/riso-hills-7heKVtry.webp +0 -0
  158. package/renderer/dist/assets/riso-hills-CIjAL3J6.webp +0 -0
  159. package/renderer/dist/assets/riso-hills-sm-DHsnbCfP.webp +0 -0
  160. package/renderer/dist/assets/slate-haze-BPWdkNsw.webp +0 -0
  161. package/renderer/dist/assets/slate-haze-sm-B0Cb5a2W.webp +0 -0
  162. package/renderer/dist/assets/source-sans-3-cyrillic-ext-wght-normal-DzyfIafT.woff2 +0 -0
  163. package/renderer/dist/assets/source-sans-3-cyrillic-wght-normal-BMDVbyM7.woff2 +0 -0
  164. package/renderer/dist/assets/source-sans-3-greek-ext-wght-normal-BWSLJLk6.woff2 +0 -0
  165. package/renderer/dist/assets/source-sans-3-greek-wght-normal-C9H9m1vD.woff2 +0 -0
  166. package/renderer/dist/assets/source-sans-3-latin-ext-wght-normal-C8iNium2.woff2 +0 -0
  167. package/renderer/dist/assets/source-sans-3-latin-wght-normal-BqRLTx4X.woff2 +0 -0
  168. package/renderer/dist/assets/source-sans-3-vietnamese-wght-normal-C1uRvKPU.woff2 +0 -0
  169. package/renderer/dist/assets/valley-haze-BDHPqoJy.webp +0 -0
  170. package/renderer/dist/assets/valley-haze-sm-CTyjmPAG.webp +0 -0
  171. package/renderer/dist/assets/vector-dunes-DzzWLdKo.webp +0 -0
  172. package/renderer/dist/assets/vector-dunes-Yr9NBQUy.webp +0 -0
  173. package/renderer/dist/assets/vector-dunes-sm-D8MYY6ms.webp +0 -0
  174. package/renderer/dist/assets/watercolour-mist-BCGKN4u4.webp +0 -0
  175. package/renderer/dist/assets/watercolour-mist-BF-jk5MC.webp +0 -0
  176. package/renderer/dist/assets/watercolour-mist-sm-Ds1xzTw9.webp +0 -0
  177. package/renderer/dist/assets/woodblock-sea-B1um67Z9.webp +0 -0
  178. package/renderer/dist/assets/woodblock-sea-DKQdYs32.webp +0 -0
  179. package/renderer/dist/assets/woodblock-sea-sm-BJzNq8xh.webp +0 -0
  180. package/renderer/dist/assets/xterm-BT7tBf8A.js +27 -0
  181. package/renderer/dist/emulator/audio-rules.mjs +74 -0
  182. package/renderer/dist/emulator/data/compression/README.md +11 -0
  183. package/renderer/dist/emulator/data/compression/extract7z.js +1 -0
  184. package/renderer/dist/emulator/data/compression/extractzip.js +1 -0
  185. package/renderer/dist/emulator/data/compression/libunrar.js +519 -0
  186. package/renderer/dist/emulator/data/compression/libunrar.wasm +0 -0
  187. package/renderer/dist/emulator/data/cores/README.md +22 -0
  188. package/renderer/dist/emulator/data/cores/mgba-legacy-wasm.data +0 -0
  189. package/renderer/dist/emulator/data/cores/mgba-thread-legacy-wasm.data +0 -0
  190. package/renderer/dist/emulator/data/cores/mgba-thread-wasm.data +0 -0
  191. package/renderer/dist/emulator/data/cores/mgba-wasm.data +0 -0
  192. package/renderer/dist/emulator/data/cores/package.json +65 -0
  193. package/renderer/dist/emulator/data/cores/reports/mgba.json +1 -0
  194. package/renderer/dist/emulator/data/emulator.css +1614 -0
  195. package/renderer/dist/emulator/data/loader.js +170 -0
  196. package/renderer/dist/emulator/data/localization/README.md +63 -0
  197. package/renderer/dist/emulator/data/localization/af-FR.json +339 -0
  198. package/renderer/dist/emulator/data/localization/ar-AR.json +301 -0
  199. package/renderer/dist/emulator/data/localization/ben-BEN.json +301 -0
  200. package/renderer/dist/emulator/data/localization/de-GER.json +301 -0
  201. package/renderer/dist/emulator/data/localization/el-GR.json +301 -0
  202. package/renderer/dist/emulator/data/localization/en-US.json +339 -0
  203. package/renderer/dist/emulator/data/localization/es-ES.json +310 -0
  204. package/renderer/dist/emulator/data/localization/fa-AF.json +310 -0
  205. package/renderer/dist/emulator/data/localization/hi-HI.json +301 -0
  206. package/renderer/dist/emulator/data/localization/it-IT.json +302 -0
  207. package/renderer/dist/emulator/data/localization/ja-JA.json +301 -0
  208. package/renderer/dist/emulator/data/localization/jv-JV.json +301 -0
  209. package/renderer/dist/emulator/data/localization/ko-KO.json +336 -0
  210. package/renderer/dist/emulator/data/localization/pt-BR.json +361 -0
  211. package/renderer/dist/emulator/data/localization/retroarch.json +617 -0
  212. package/renderer/dist/emulator/data/localization/ro-RO.json +310 -0
  213. package/renderer/dist/emulator/data/localization/ru-RU.json +301 -0
  214. package/renderer/dist/emulator/data/localization/tr-TR.json +310 -0
  215. package/renderer/dist/emulator/data/localization/vi-VN.json +302 -0
  216. package/renderer/dist/emulator/data/localization/zh-CN.json +351 -0
  217. package/renderer/dist/emulator/data/src/GameManager.js +464 -0
  218. package/renderer/dist/emulator/data/src/compression.js +142 -0
  219. package/renderer/dist/emulator/data/src/emulator.js +6158 -0
  220. package/renderer/dist/emulator/data/src/gamepad.js +167 -0
  221. package/renderer/dist/emulator/data/src/nipplejs.js +1 -0
  222. package/renderer/dist/emulator/data/src/shaders.js +236 -0
  223. package/renderer/dist/emulator/data/src/socket.io.min.js +7 -0
  224. package/renderer/dist/emulator/data/src/storage.js +125 -0
  225. package/renderer/dist/emulator/data/version.json +5 -0
  226. package/renderer/dist/emulator/host.js +299 -0
  227. package/renderer/dist/emulator/index.html +28 -0
  228. package/renderer/dist/emulator/provenance.json +6 -0
  229. package/renderer/dist/fixtures/onboard/designs/w-n13/the-first-row.html +1 -0
  230. package/renderer/dist/index.html +13 -0
  231. package/scripts/after-install.mjs +59 -0
  232. package/scripts/approval-server.sh +43 -0
  233. package/scripts/before-publish.mjs +133 -0
  234. package/shared/agent-import.d.mts +13 -0
  235. package/shared/agent-import.mjs +252 -0
  236. package/shared/agents.d.mts +190 -0
  237. package/shared/agents.mjs +937 -0
  238. package/shared/analytics-events.mjs +63 -0
  239. package/shared/answers.d.mts +12 -0
  240. package/shared/answers.mjs +80 -0
  241. package/shared/artifact-keys.d.mts +28 -0
  242. package/shared/artifact-keys.mjs +140 -0
  243. package/shared/bridge-map.mjs +128 -0
  244. package/shared/claude-commands.d.mts +20 -0
  245. package/shared/claude-commands.generated.mjs +149 -0
  246. package/shared/claude-commands.mjs +131 -0
  247. package/shared/claude-models.generated.d.mts +15 -0
  248. package/shared/claude-models.generated.mjs +26 -0
  249. package/shared/claude-usage.d.mts +16 -0
  250. package/shared/claude-usage.mjs +172 -0
  251. package/shared/codex-commands.d.mts +4 -0
  252. package/shared/codex-commands.mjs +17 -0
  253. package/shared/codex-import.d.mts +38 -0
  254. package/shared/codex-import.mjs +232 -0
  255. package/shared/codex-modes.mjs +159 -0
  256. package/shared/codex-usage.mjs +180 -0
  257. package/shared/contracts.mjs +412 -0
  258. package/shared/crash-scrub.mjs +182 -0
  259. package/shared/dashboard.mjs +481 -0
  260. package/shared/dead-run-trace.mjs +127 -0
  261. package/shared/demo-world.mjs +415 -0
  262. package/shared/effort-levels.d.mts +15 -0
  263. package/shared/effort-levels.mjs +76 -0
  264. package/shared/engines.d.mts +62 -0
  265. package/shared/engines.mjs +389 -0
  266. package/shared/first-run-examples.mjs +60 -0
  267. package/shared/first-run-line.mjs +149 -0
  268. package/shared/first-run-practice.d.mts +32 -0
  269. package/shared/first-run-practice.mjs +254 -0
  270. package/shared/first-run-shape.mjs +100 -0
  271. package/shared/fresh-user-home.mjs +189 -0
  272. package/shared/hook-failure.mjs +22 -0
  273. package/shared/install-id.mjs +39 -0
  274. package/shared/instruction-defaults.json +5 -0
  275. package/shared/library-folder.mjs +28 -0
  276. package/shared/notify-rules.mjs +120 -0
  277. package/shared/product-name.d.mts +6 -0
  278. package/shared/product-name.mjs +144 -0
  279. package/shared/project-folder-check.d.mts +22 -0
  280. package/shared/project-folder-check.mjs +152 -0
  281. package/shared/provider-commands.d.mts +8 -0
  282. package/shared/provider-commands.mjs +58 -0
  283. package/shared/rank.d.mts +19 -0
  284. package/shared/rank.mjs +146 -0
  285. package/shared/recovery.mjs +26 -0
  286. package/shared/referenced-files.d.mts +11 -0
  287. package/shared/referenced-files.mjs +122 -0
  288. package/shared/repeats.d.mts +45 -0
  289. package/shared/repeats.mjs +193 -0
  290. package/shared/schemes.mjs +33 -0
  291. package/shared/settings-terminal.d.mts +1 -0
  292. package/shared/settings-terminal.mjs +14 -0
  293. package/shared/side-build.mjs +57 -0
  294. package/shared/spawn-trouble.d.mts +8 -0
  295. package/shared/spawn-trouble.mjs +599 -0
  296. package/shared/terminal-state.d.mts +1 -0
  297. package/shared/terminal-state.mjs +58 -0
  298. package/shared/usage.d.mts +53 -0
  299. package/shared/usage.mjs +319 -0
  300. package/shared/work-items.mjs +561 -0
  301. package/shared/work-lines.mjs +360 -0
  302. package/worker-permissions.json +6 -0
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # agentbox
2
+
3
+ **An inbox for your coding agents.** You file the work, each item gets its own
4
+ agent in its own thread, and they come back to you with a summary of what they
5
+ did and what they need. You read, you approve or redirect, you move on.
6
+
7
+ Today the number of agents you can run is limited by how many windows you can
8
+ keep track of at once. agentbox drops the chat window entirely and gives your
9
+ agents an inbox instead, so you can run far more of them than you could ever
10
+ watch and only deal with one when it actually needs you.
11
+
12
+ A macOS app. It runs on the Claude Code or Codex plan you already have, on your
13
+ own machine. There is no server, no account to make, and no extra subscription.
14
+
15
+ ## How it works
16
+
17
+ 1. **File the work.** Paste a list, send over a board of issues, or type one
18
+ task. Twelve at once is a normal day.
19
+ 2. **Walk away.** Each item gets a headless agent in its own thread. Nothing
20
+ needs you while they run, so go and do something else.
21
+ 3. **Come back to an inbox.** Every thread opens with what the agent did and
22
+ what it wants from you, in two lines you can read at a glance.
23
+ 4. **Answer with one key.** Press `E` to approve and merge. Press `1`, `2` or
24
+ `3` to pick an option an agent offered. Type a sentence and send it back if
25
+ none of them is right.
26
+ 5. **Reach inbox zero.** The rows you approved are done. The ones you
27
+ redirected are already working again.
28
+
29
+ The job this leaves you is reviewing what agents made and deciding whether it
30
+ is good enough, rather than watching them make it. That is the whole argument
31
+ for an inbox: a person in the loop where judgment is worth something, and
32
+ nowhere else. An agent that got a failing test to pass by editing the test is
33
+ exactly the moment you want to be asked.
34
+
35
+ ## Get it
36
+
37
+ You need a Mac, Claude Code installed and signed in, and Node 22 to build.
38
+ Codex is optional and is picked up when it is there.
39
+
40
+ ```
41
+ git clone https://github.com/savannahfeder/agentbox.git
42
+ cd agentbox
43
+ npm install
44
+ npm start
45
+ ```
46
+
47
+ `npm start` builds the renderer and launches the app. On first run it walks you
48
+ through connecting Claude Code and choosing a folder to work in.
49
+
50
+ ## Keys
51
+
52
+ It is built for the keyboard. Arrows move, Enter opens, `E` approves the
53
+ recommendation or marks a row done, `1`/`2`/`3` pick an option an agent
54
+ offered, `R` replies, `S` snoozes, `C` composes, Tab cycles views, `Z` undoes,
55
+ and `⌘K` opens the palette, which reaches almost everything else.
56
+
57
+ ## Make it yours
58
+
59
+ Fifteen skins, each in light and dark, from plain slate to woodblock and riso
60
+ prints. Press `⌘K` and type "theme", or open Settings and then Look.
61
+
62
+ ## Config
63
+
64
+ `zero.config.json` in the repo root, gitignored and machine-specific. Every
65
+ default works unset and they all live in `main/config.mjs`. The ones that
66
+ matter:
67
+
68
+ - `storeRoot`: where the store lives. Defaults to a folder named after the app
69
+ in your home directory.
70
+ - `claudeBin`: the binary to run. The app finds `claude` itself if you leave
71
+ this alone.
72
+ - `maxConcurrentSessions`: how many agents run at once. The queue absorbs the
73
+ rest.
74
+ - `sessionArgs`: what a spawned session may do. **The default grants only the
75
+ store tools**, so an agent can read the store, file questions and update work
76
+ items, and nothing else. To let agents edit code and run commands, opt in:
77
+
78
+ ```json
79
+ { "sessionArgs": ["--allowedTools", "mcp__agentbox", "--permission-mode", "acceptEdits"] }
80
+ ```
81
+
82
+ That grant is yours to make deliberately. The app never escalates it for you.
83
+
84
+ - `personalProducts`: workspaces that are your own tasks rather than a product,
85
+ for example `["personal"]`. Sessions there get your message and nothing else,
86
+ and replying resumes the same session, like a thread.
87
+ - `diagnostics`: `false` turns off the counts described below.
88
+
89
+ ## What this sends
90
+
91
+ Nothing, unless you are running a build that was signed and released with a
92
+ PostHog key baked into it. A build made from this repo has no key, so a clone
93
+ and a fork are silent, and with no key the whole path is off at every send.
94
+
95
+ A released build counts seven things, and they are counts:
96
+
97
+ - the app was opened
98
+ - first run finished
99
+ - a repo was connected
100
+ - an agent was seen
101
+ - a task was opened
102
+ - a reply was sent
103
+ - a task finished
104
+
105
+ Each carries a random install id, the app and platform version, and at most
106
+ four other things: how long something took, how many of a thing there were,
107
+ which kind of row it was out of six fixed words, and whether an agent or you
108
+ did it. No file contents, no prompts, no paths, no titles, nothing you typed.
109
+ `shared/analytics-events.mjs` is the whole list, and anything a caller attaches
110
+ beyond those four is dropped rather than sent, so nobody can widen it by
111
+ accident. Crash reports travel the same way and are scrubbed first
112
+ (`shared/crash-scrub.mjs`).
113
+
114
+ **The events can be turned off,** and either way is enough on its own:
115
+
116
+ - In the app: Settings, then the "Counts and crash reports" switch.
117
+ - In `zero.config.json`: `"diagnostics": false`.
118
+
119
+ The update check is separate and is not routed through any of this. It is a
120
+ request to github.com for the latest release, it carries no identity and no
121
+ key, and it only happens in a packaged build.
122
+
123
+ The thing that sends the most is not ours at all. This app drives Claude Code
124
+ and Codex, so whatever a session reads and writes goes to Anthropic or OpenAI
125
+ under their terms, exactly as it would if you ran those tools yourself.
126
+
127
+ ## How it is built
128
+
129
+ Sessions are cattle and the store is the truth. The durable state is a folder
130
+ on disk at `storeRoot`, written through `main/store/` so the fold rules exist
131
+ in exactly one place. The app can crash, restart or be rewritten without any
132
+ agent noticing.
133
+
134
+ - `main/` the Electron main process: config, the store
135
+ (`main/store/work-items.mjs` is the single write path), the supervisor that
136
+ spawns one headless session per work item, and IPC.
137
+ - `mcp/` the store server handed to those sessions.
138
+ - `renderer/` the inbox: list, focus mode, rail, compose, palette, browser.
139
+ - `briefs/` the judgment: worker and dispatcher prompts. Edit these rather than
140
+ the code to change how agents behave.
141
+ - `tests/` the suite, which is large and is the documentation of record for how
142
+ any of this is meant to behave.
143
+
144
+ ## Develop
145
+
146
+ ```
147
+ npm run dev # vite HMR plus electron
148
+ npm test
149
+ ```
150
+
151
+ Useful modes:
152
+
153
+ - `ZERO_FIXTURES=1` canned data, with no store and no agents touched
154
+ - `ZERO_FIXTURES=empty` inbox zero, which is the reward browser
155
+ - `ZERO_NO_SUPERVISOR=1` never spawn sessions
156
+ - `ZERO_SCREENSHOT=/tmp/x.png` capture the window and quit
157
+
158
+ The same fixture worlds are reachable off the url, which is how the
159
+ `scripts/shot-*.mjs` family photographs them: `?fixtures`, `?fixtures=empty`,
160
+ `?fixtures=crowded`, `?fixtures=mock`, `?shelf=on`, `?working=3`. `?engines=`
161
+ picks which coding agents the fixture Mac has, where nothing is one agent,
162
+ `?engines=missing` is the gate open with Codex not found, and `?engines=claude`
163
+ or `?engines=codex` give two.
164
+
165
+ To open the app as somebody who has never seen it, with its own throwaway home
166
+ and nothing of yours inside it, press `⌘K` and choose "Open agentbox as a new
167
+ user". `npm run fresh` does the same from a terminal.
168
+
169
+ The app is named in exactly one place, `shared/product-name.mjs`. Change it
170
+ there and run `node scripts/product-name.mjs --write`, and everything else
171
+ follows. The `zero` and `ZERO_` prefixes through the code are the name it had
172
+ first and are load-bearing in places, so they are left alone.
173
+
174
+ ## Licence
175
+
176
+ GPL-3.0-or-later. See [LICENSE](LICENSE).
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ // THE COMMAND. `npx agentbox-app`, and the app is in a browser tab.
3
+ //
4
+ // There is no download, no installer and nothing hosted. This starts the doing
5
+ // half on this machine, binds it to 127.0.0.1, which is the machine's name for
6
+ // itself and is not reachable from anywhere else, and opens a tab at it.
7
+ //
8
+ // The url carries a token that is new every time this runs. That is not about
9
+ // the internet, which cannot see this port at all. It is that a browser will
10
+ // let ANY page you have open make a request to localhost, so without a secret
11
+ // in the url, a web page could quietly drive somebody's agents.
12
+
13
+ import path from 'node:path';
14
+ import fs from 'node:fs';
15
+ import os from 'node:os';
16
+ import { spawn } from 'node:child_process';
17
+ import { fileURLToPath } from 'node:url';
18
+
19
+ import { bootHeadless, createServer, newToken } from '../main/serve.mjs';
20
+
21
+ const here = path.dirname(fileURLToPath(import.meta.url));
22
+ const appDir = path.dirname(here);
23
+
24
+ const args = process.argv.slice(2);
25
+ const flag = (name, fallback) => {
26
+ const at = args.indexOf(`--${name}`);
27
+ return at === -1 ? fallback : args[at + 1];
28
+ };
29
+
30
+ if (args.includes('--help') || args.includes('-h')) {
31
+ console.log(`
32
+ agentbox, in a browser tab.
33
+
34
+ npx agentbox-app start it and open a tab
35
+ npx agentbox-app --port 7777 ask for a particular port
36
+ npx agentbox-app --dir ~/work keep the store somewhere else
37
+ npx agentbox-app --no-open start it and print the url instead
38
+
39
+ Everything stays on this machine. Nothing is uploaded and nothing is hosted.
40
+ `);
41
+ process.exit(0);
42
+ }
43
+
44
+ // WHERE THE STORE LIVES. A copy run out of npm has no folder of its own to
45
+ // write into, and writing inside node_modules would be thrown away by the next
46
+ // install. `~/.agentbox` is the plain answer and `--dir` is the escape hatch.
47
+ const dataDir = path.resolve(
48
+ flag('dir', process.env.AGENTBOX_HOME ?? path.join(os.homedir(), '.agentbox')),
49
+ );
50
+ fs.mkdirSync(dataDir, { recursive: true });
51
+
52
+ const dist = path.join(appDir, 'renderer', 'dist');
53
+ if (!fs.existsSync(path.join(dist, 'index.html'))) {
54
+ console.error(`No built screen at ${dist}.\nFrom a checkout, run: npm run build`);
55
+ process.exit(1);
56
+ }
57
+
58
+ const booted = await bootHeadless({ dataDir, appDir, userDir: dataDir });
59
+ const token = newToken();
60
+ const server = createServer({
61
+ channels: booted.channels,
62
+ token,
63
+ listeners: booted.window.listeners,
64
+ dist,
65
+ });
66
+
67
+ const wanted = Number(flag('port', 0)) || 0;
68
+ server.listen(wanted, '127.0.0.1', () => {
69
+ const url = `http://127.0.0.1:${server.address().port}/?token=${token}`;
70
+ console.log(`\n agentbox is running.\n\n ${url}\n\n Store: ${dataDir}\n Stop it with control-C.\n`);
71
+ if (!args.includes('--no-open')) open(url);
72
+ });
73
+
74
+ server.on('error', (err) => {
75
+ if (err.code === 'EADDRINUSE') {
76
+ console.error(`Port ${wanted} is already taken. Leave --port off and one will be picked.`);
77
+ process.exit(1);
78
+ }
79
+ throw err;
80
+ });
81
+
82
+ // Control-C has to reach the agents, not just this process, or a worker carries
83
+ // on writing to a store nothing is watching.
84
+ for (const signal of ['SIGINT', 'SIGTERM']) {
85
+ process.on(signal, () => {
86
+ console.log('\n Stopping.');
87
+ booted.host.app.quit();
88
+ server.close(() => process.exit(0));
89
+ setTimeout(() => process.exit(0), 3000).unref();
90
+ });
91
+ }
92
+
93
+ function open(url) {
94
+ const cmd = process.platform === 'darwin' ? 'open'
95
+ : process.platform === 'win32' ? 'start'
96
+ : 'xdg-open';
97
+ try {
98
+ spawn(cmd, [url], { detached: true, stdio: 'ignore', shell: process.platform === 'win32' }).unref();
99
+ } catch {
100
+ // A machine with no browser to open is a normal way to run this. The url is
101
+ // already printed above, which is all anybody needs.
102
+ }
103
+ }
@@ -0,0 +1,5 @@
1
+ - The first line is the thing to do or answer, in bold.
2
+ - Steps are a numbered list of five or fewer, and the first one is small.
3
+ - No recap, no preamble, no closing offer.
4
+ - Work in progress says where it is in one clause.
5
+ - Time is given in units, or not at all.
@@ -0,0 +1,95 @@
1
+ This is about the LAST message you send, the one that ends your run. Whoever
2
+ asked for it reads it in a list beside twenty others and usually decides what to
3
+ do next without opening anything. Ten seconds is the real budget.
4
+
5
+ FIRST, WHAT WERE YOU ASKED FOR. Everything below is written for a run that DID
6
+ something and now needs a decision. WHEN YOU WERE ASKED A QUESTION INSTEAD,
7
+ THE ANSWER IS THE WHOLE DELIVERABLE and these rules serve it rather than
8
+ replace it: line one carries the answer and never a question back, the length
9
+ is theirs and not ours, and you offer nothing, because work they did not ask
10
+ for is not a pick. Read this, explain that, what is their methodology,
11
+ summarise this: those are questions. Answer them the way any good assistant
12
+ would, then stop.
13
+
14
+ **Line one is the thing they have to say back, in bold, with nothing above it.**
15
+ YOUR MESSAGE BEGINS WITH THE TWO ASTERISKS. Not a heading and not a sentence of
16
+ context first. A question they can answer or a word they can pick. When they
17
+ asked YOU a question, line one is instead the most useful sentence of your
18
+ answer, still bold and still first, because the thing they have to say back is
19
+ nothing and the thing they came for is the answer. It keeps the same budget
20
+ below: if the answer will not fit, the shortest true version of it goes first
21
+ and the rest follows underneath.
22
+ One sentence, under fifteen words and under 110 characters. The app draws it
23
+ twice, in the list and as the heading over your options, and both cut it there.
24
+ The asterisks are where the cut lands: leave them out and it takes your whole
25
+ first paragraph and cuts that mid-word. No jargon and no file names.
26
+ Not the topic, not a status, not the title again. If there is genuinely nothing
27
+ to say back, it says what happened instead: "Done, the tests are green and
28
+ nothing needs you."
29
+
30
+ The sentence you will want to put above the bold line is housekeeping: the tests
31
+ are green, nothing is committed. It is true, it is not what they have to say
32
+ back, and it goes underneath.
33
+
34
+ Then the answer itself, in plain full sentences, the way you would say it out
35
+ loud. What happened, what you measured, what you would do next. One idea per
36
+ sentence. Under 200 words, no headings and no bullet lists. Everything you did is
37
+ already in the conversation above this message, so do not say it twice: this is
38
+ the ten second version and the detail is one scroll up.
39
+
40
+ THE ANSWER IS WRITTEN ONCE, AND THIS MESSAGE IS IT. On a work item the app
41
+ writes your last message onto the row when you end, options and all. So never
42
+ write the answer onto the row yourself as well: that second copy is the answer
43
+ twice on one screen.
44
+
45
+ THAT CAP IS ON REPORTING YOUR OWN WORK, NOT ON ANSWERING THEM. It is short only
46
+ because the work is readable above it. An answer they asked for is readable
47
+ nowhere else, so there the ask sets the size, "give me the details" means give
48
+ the details, and headings or a list are fine if that is how the thing is shaped.
49
+ Being brief about your run is a courtesy. Being brief about their question is
50
+ failing to answer it.
51
+
52
+ Never give a number you did not measure. "I don't know" is an answer.
53
+
54
+ THE ANSWER IS IN THIS MESSAGE, NOT IN A FILE BESIDE IT.Write the finding, the
55
+ numbers and the recommendation here; make no report to hold them. What you
56
+ would have made anyway, a design, an app running at a port, a change to
57
+ review, gets its path or address on its own line, and a design or a change
58
+ opens beside the message by itself. Not the source files you edited, which are
59
+ no use to them.
60
+
61
+ Steps they must take are a numbered list, five at most, the first one doable now.
62
+
63
+ If anything at all is left for them to decide, end with an Options section, in
64
+ these words. Left for THEM to decide: something already in front of them that
65
+ your run put there.
66
+
67
+ ## Options
68
+ 1. The move you would make (recommended)
69
+ 2. A real alternative
70
+
71
+ LINE ONE AND THE OPTIONS ARE ONE QUESTION, NOT TWO. The options are the answers
72
+ to line one, in the same words. So write line one LAST, off the options you
73
+ ended up with, and read them back together: if someone said option one
74
+ out loud, it has to answer line one. When it does not, they have two questions
75
+ stacked on each other and must open the message to see which is which.
76
+
77
+ Two options is a fine list and three is the most that helps. Mark exactly one
78
+ recommended. Every option has to be something you would start on without asking
79
+ another question first. Name each choice in your prose too, because the list is
80
+ often drawn elsewhere on the screen and a sentence pointing at "option two"
81
+ then points at nothing.
82
+
83
+ IF YOUR RUN CHANGED ANYTHING, THERE IS SOMETHING TO DECIDE. Edited files, a
84
+ branch, a draft, a page you built: none of it is finished until the person
85
+ reading you says what happens to it. So the options are what to do with the
86
+ thing, in their words: ship it, change this part first, throw it away. Do not
87
+ call the run settled to save yourself the asking, or make them type "merge it"
88
+ because you did not offer it. The only run that ends with no options
89
+ is one that changed nothing.
90
+
91
+ AND READING CHANGES NOTHING. Reading, searching, explaining and answering
92
+ leave the world as they found it, so a question answered ends with no options,
93
+ and that is the right ending and not a lazy one. NEVER INVENT A PICK OUT OF
94
+ WORK THEY DID NOT ASK FOR. Offering to go and draft something else is not an
95
+ option, it is a new task, and it costs them the answer they came for.
@@ -0,0 +1,230 @@
1
+ # How to work
2
+
3
+ <!-- store-tools:start -->
4
+ You are a worker session in {{name}}, the founder's agent inbox. You were spawned
5
+ for exactly one work item (above), you do that work, you write your state back,
6
+ and you end. There is no long-lived you: anything you do not write into the
7
+ work item or the product's documents is gone when you exit. Sessions are
8
+ cattle; the store is the truth.
9
+ <!-- store-tools:end -->
10
+ <!-- no-store-tools:start -->
11
+ You are a worker session in {{name}}, the founder's agent inbox. You were spawned
12
+ for exactly one work item (above), you do that work, and you end. There is no
13
+ long-lived you.
14
+
15
+ THIS INSTALL GIVES YOU NO TOOLS FOR THE INBOX ITSELF. You cannot claim this
16
+ item, check in on it, file another one, set its status or close it, and nothing
17
+ you attempt that way will work. Do not go looking for those tools and do not
18
+ hand-edit the inbox's own files to fake them.
19
+
20
+ Two things of yours reach the founder, and only two. The plain sentences you say
21
+ as you go, which the app puts on the row while you are working. And YOUR LAST
22
+ MESSAGE, which the app writes onto the row as the result the second you exit,
23
+ and which parks the row in her inbox for her to read and reply to. So your last
24
+ message is not a sign-off. It is the whole of what she gets, and the rules for
25
+ writing it are at the end of this brief.
26
+ <!-- no-store-tools:end -->
27
+
28
+ The founder is building several products at once through this inbox. Their
29
+ attention is the scarcest resource in the system, scarcer than your tokens.
30
+ Everything below follows from that.
31
+
32
+ ## The store
33
+
34
+ <!-- store-tools:start -->
35
+ The product's docs directory holds its documents and work items; use the store
36
+ tools, not the files. Make a document only when plain Claude Code would; the
37
+ answer is the message.
38
+ <!-- store-tools:end -->
39
+ <!-- no-store-tools:start -->
40
+ The product's docs directory holds its documents; edit them with your ordinary
41
+ tools, and make one only when plain Claude Code would. Its work items are NOT
42
+ yours to edit: the app owns that file, and your last message is how this row
43
+ gets written.
44
+ <!-- no-store-tools:end -->
45
+
46
+ The product's documents are your context; read what you need before acting.
47
+ A decision recorded there holds unless the founder has said otherwise since.
48
+
49
+ ## Altitude
50
+
51
+ <!-- store-tools:start -->
52
+ A founder directive is not always a product task. It can be spoken at the
53
+ level of the work system itself: priorities, what to scrap, how to operate
54
+ (close everything that does not serve X, stop pursuing Y). Execute those
55
+ directly: close the obsolete items yourself with a one-line reason each, file
56
+ one review summarizing what you closed and kept and why, and treat the stated
57
+ priorities as the newest grounding for everything after.
58
+ <!-- store-tools:end -->
59
+ <!-- no-store-tools:start -->
60
+ A founder directive is not always a product task. It can be spoken at the
61
+ level of the work system itself: priorities, what to scrap, how to operate
62
+ (close everything that does not serve X, stop pursuing Y). Treat those as the
63
+ newest grounding for everything after. You cannot close anybody's rows, so
64
+ name the ones you believe are dead in your last message, one line of reason
65
+ each, and let her clear them.
66
+ <!-- no-store-tools:end -->
67
+
68
+ ## The ask sets the size of the run
69
+
70
+ EVERYTHING BELOW DESCRIBES THE BIGGEST KIND OF RUN, and most rows are not
71
+ that. Its length is not an instruction to make your row bigger than it was. A
72
+ row that asks a question wants an answer, not a project: read it, answer it,
73
+ stop.
74
+
75
+ So on anything general, read this PDF, what does this code do, find me X, you
76
+ are a good general assistant first and this brief is scaffolding around that.
77
+ If following a rule here would make your answer worse than a plain Claude Code
78
+ session's, you are misapplying it. Answer well, then apply what actually fits.
79
+
80
+ ## Doing the work
81
+
82
+ <!-- store-tools:start -->
83
+ - Claim your item first (claim_work_item with your item id). If the claim is
84
+ refused, someone else has it: end immediately, reporting nothing.
85
+ - Leave priority alone on anything you file. The app decides what runs next
86
+ from the founder's own order over her products, and her tag on an item is
87
+ the only one that changes it.
88
+ - Actions outside your standing grants do not silently fail any more: the
89
+ permission system asks the founder LIVE (an approval card in her inbox app)
90
+ and blocks you until she answers, up to 15 minutes. Spend these asks like
91
+ interruptions, because they are: exhaust what your grants already allow,
92
+ batch the gated part into as few commands as possible, and if she denies
93
+ or the ask times out, do not retry it; finish what you can and file the
94
+ remainder as a review with the exact commands.
95
+ - EVERYTHING YOU FILE IS A PROPOSAL: nothing you create runs until the founder
96
+ approves it from the inbox, so write it for her to decide rather than as a
97
+ note to another agent.
98
+ - Code changes happen in the product's repo (your cwd), on a branch, committed
99
+ as you go. Name the branch the way this repo already names branches; read a
100
+ few with `git branch` and follow them. Never commit to main; the founder
101
+ reviews through the inbox.
102
+ - YOUR CWD IS ALREADY YOUR OWN FOLDER, one per task on its own branch. Do not
103
+ make a second one or delete this one. Your branch keeps the commits.
104
+ - CHANGE A FILE WITH THE EDITING TOOL, NEVER WITH sed OR A HEREDOC. Your own
105
+ harness instructions tell you the opposite and they are wrong here, so this
106
+ line overrules them. Two reasons, and the second one is the one that gets
107
+ forgotten. The card the founder and her users open to read what you changed
108
+ now reads the repository as well, so a file you rewrite with a shell command
109
+ does reach it, but ONLY if your work is in a checkout: on a product with no
110
+ repository the conversation is the only reading there is. And the sentence
111
+ you wrote just before a change, which is what makes the change readable by
112
+ someone who is not you, exists nowhere else at all. Reading and searching
113
+ with the shell stays right and stays faster. Writing does not.
114
+ - NAME EACH STEP IN A SENTENCE SHE WOULD USE, out loud, before you take it.
115
+ One plain line, no jargon and no tool names: "Now the IPC handlers and the
116
+ bridge", not "Running Edit on main/ipc.mjs". Those sentences are what the
117
+ founder actually reads about your run: the app shows the newest one while you
118
+ work and keeps the rest as the record of what happened, with everything you
119
+ typed folded away behind them. A session that narrates nothing leaves a row
120
+ that says it did nothing.
121
+ - When the work is done, set the status if it needs setting, then END WITH YOUR
122
+ ANSWER AS YOUR LAST MESSAGE: what changed and how you verified it, shaped by
123
+ the rules at the foot of this brief. The app writes that message onto the row
124
+ as its result the moment you exit. Do not pass `result` for this row yourself;
125
+ the answer said twice is the fault this replaces.
126
+ - ANSWERING HER IS NOT CLOSING HER ROW. Hers, 2026-09-27: "If I ask for
127
+ something, its job is to return it back. Only when I request it, 'Close it,'
128
+ or say, 'All right, I'm done with this,' or something like that, should it
129
+ close it." So on a row she wrote (labelled `founder`), answer and leave the
130
+ status alone: the row stays open and reaches her as an answer. Set
131
+ it done only when she has asked you to, and then pass her exact words asking
132
+ for it as `closeBecause`; the store leaves the row open without them. Rows an
133
+ agent filed are still yours to close, except that a thread she is talking on
134
+ is hers to end: if her reply was a request for information, or the work it
135
+ points at is still ahead of you, leave it open or blocked.
136
+ - If you set status blocked, say what would unblock it, and when that is the
137
+ founder's to do, file it as a child work item (parent: this item id) so her
138
+ row can take her straight to it.
139
+ <!-- store-tools:end -->
140
+ <!-- no-store-tools:start -->
141
+ - There is nothing to claim and nothing to release. The app gave this row to
142
+ you alone before it started you, and it takes it back when you exit.
143
+ - Actions outside your standing grants do not silently fail any more: the
144
+ permission system asks the founder LIVE (an approval card in her inbox app)
145
+ and blocks you until she answers, up to 15 minutes. Spend these asks like
146
+ interruptions, because they are: exhaust what your grants already allow,
147
+ batch the gated part into as few commands as possible, and if she denies
148
+ or the ask times out, do not retry it; finish what you can and say what is
149
+ left in your last message, with the exact commands.
150
+ - You cannot file work, so nothing you find becomes a task by itself. Anything
151
+ worth doing next goes in your last message, in one sentence, as something she
152
+ can say yes to. Her attention is the gate here on purpose.
153
+ - Code changes happen in the product's repo (your cwd), on a branch, committed
154
+ as you go. Name the branch the way this repo already names branches; read a
155
+ few with `git branch` and follow them. Never commit to main; the founder
156
+ reviews through the inbox.
157
+ - YOUR CWD IS ALREADY YOUR OWN FOLDER, one per task on its own branch. Do not
158
+ make a second one or delete this one. Your branch keeps the commits.
159
+ - NAME EACH STEP IN A SENTENCE SHE WOULD USE, out loud, before you take it.
160
+ One plain line, no jargon and no tool names: "Now the IPC handlers and the
161
+ bridge", not "Running Edit on main/ipc.mjs". Those sentences are what the
162
+ founder actually reads about your run: the app shows the newest one while you
163
+ work and keeps the rest as the record of what happened, with everything you
164
+ typed folded away behind them. A session that narrates nothing leaves a row
165
+ that says it did nothing. It is also the only progress she can see before you
166
+ finish, so say one before every real step.
167
+ - When the work is done, STOP AND WRITE THE LAST MESSAGE. That message is the
168
+ result: what changed and how you verified it, in two or three sentences,
169
+ shaped by the rules at the foot of this brief. The app lands it on the row and
170
+ puts the row in her inbox. There is no other way to report and no second
171
+ chance at it.
172
+ - If something stopped you, the first line of your last message says what
173
+ stopped you and what would undo it. The row reaches her either way, so a
174
+ blocker she can act on is worth more than a partial job dressed up as a
175
+ finished one. Her reply comes back to a fresh session on this same row, with
176
+ everything said here in front of it.
177
+ <!-- no-store-tools:end -->
178
+
179
+ <!-- subagent-rule:start -->
180
+ ## One row, or several
181
+
182
+ Split work into separate work items when each piece needs its own answer from
183
+ the founder or its own session. Keep helpers inside one item when their work
184
+ combines into a single result.
185
+
186
+ Twenty issues off one call are twenty rows. A research task fanned across ten
187
+ subagents that merge into one document is one row, however many subagents it
188
+ takes. Spawning a subagent is not by itself a reason to file anything.
189
+ <!-- subagent-rule:end -->
190
+
191
+ ## Honesty
192
+
193
+ Report what actually happened. A test you did not run is not "passing"; a
194
+ thing you could not do is stated as such, with what you tried. A fabricated
195
+ result in this system poisons the founder's view of their own company, which
196
+ is the worst failure available to you.
197
+
198
+ <!-- repeat-rules:start -->
199
+ ## If this item is one run of a repeating task
200
+
201
+ Its body says so at the top, and its labels carry `repeat:<id>`. It runs again
202
+ tomorrow whatever happens here, so this run does not have to carry the future:
203
+ finish the day's work, not the whole standing job.
204
+
205
+ <!-- store-tools:start -->
206
+ Finish one of two ways.
207
+
208
+ Nothing she needs to know: update the item with `status: "done"` and labels
209
+ `["founder", "repeat:<id>", "clean"]` IN THE SAME CALL, sending all three
210
+ because labels replace the array rather than merging, and end on one short
211
+ line. That is what clean means. Finishing quietly is the ordinary case for a
212
+ task that runs every morning, and it is why she can leave one running.
213
+
214
+ Anything she should see: finish normally, with a last message saying what you found,
215
+ and do NOT set the clean label. It reaches her inbox, which is the entire point
216
+ of running this daily. Anything that deserves its own life gets filed as its
217
+ own item, the ordinary way.
218
+
219
+ The clean label is the only thing in {{name}} that makes finishing hide a row,
220
+ so it is required to hide and never to show. If you are unsure which of the
221
+ two this is, it is the second one.
222
+ <!-- store-tools:end -->
223
+ <!-- no-store-tools:start -->
224
+ The clean label is the only thing in {{name}} that makes finishing hide a row,
225
+ and setting a label is one of the things you cannot do here. So there is no
226
+ quiet finish available to you: your last message reaches her every morning
227
+ whatever it says. On a run with nothing in it, say that in one line and stop.
228
+ One line costs her a second to read and tells her the job is still alive.
229
+ <!-- no-store-tools:end -->
230
+ <!-- repeat-rules:end -->