brane 0.0.2 → 0.3.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 (338) hide show
  1. package/AGENTS.md +362 -0
  2. package/CHANGELOG.md +33 -0
  3. package/CONTRIBUTING.md +91 -0
  4. package/DESIGN.md +402 -0
  5. package/Dockerfile +61 -0
  6. package/LICENSE +656 -17
  7. package/README.md +174 -2
  8. package/SECURITY.md +205 -0
  9. package/dist/absorb/brane-id.js +11 -0
  10. package/dist/absorb/chatgpt.js +161 -0
  11. package/dist/absorb/claude-code.js +504 -0
  12. package/dist/absorb/index.js +543 -0
  13. package/dist/absorb/organelle.js +345 -0
  14. package/dist/absorb/run.js +520 -0
  15. package/dist/absorb/sources.js +168 -0
  16. package/dist/absorb/types.js +3 -0
  17. package/dist/agent-env.js +45 -0
  18. package/dist/agents.js +1168 -0
  19. package/dist/claude-live-session.js +124 -0
  20. package/dist/cli.js +50 -0
  21. package/dist/codex-tool-log.js +144 -0
  22. package/dist/commands/absorb.js +291 -0
  23. package/dist/commands/attach.js +31 -0
  24. package/dist/commands/certify.js +62 -0
  25. package/dist/commands/config.js +116 -0
  26. package/dist/commands/cost.js +126 -0
  27. package/dist/commands/daemon.js +350 -0
  28. package/dist/commands/doctor.js +262 -0
  29. package/dist/commands/fold.js +95 -0
  30. package/dist/commands/list.js +89 -0
  31. package/dist/commands/mcp.js +84 -0
  32. package/dist/commands/meld.js +332 -0
  33. package/dist/commands/memory.js +215 -0
  34. package/dist/commands/revive.js +74 -0
  35. package/dist/commands/run.js +85 -0
  36. package/dist/commands/spawn.js +1094 -0
  37. package/dist/commands/token.js +153 -0
  38. package/dist/copilot-tool-log.js +145 -0
  39. package/dist/cost/pricing.js +116 -0
  40. package/dist/cost/reprice.js +136 -0
  41. package/dist/crush-tool-log.js +293 -0
  42. package/dist/daemon/agent-scope.js +116 -0
  43. package/dist/daemon/awaiting.js +54 -0
  44. package/dist/daemon/cert-manager.js +349 -0
  45. package/dist/daemon/client.js +262 -0
  46. package/dist/daemon/gated-routes.js +112 -0
  47. package/dist/daemon/keep-awake.js +103 -0
  48. package/dist/daemon/local-socket.js +145 -0
  49. package/dist/daemon/presence-gate.js +206 -0
  50. package/dist/daemon/server.js +6349 -0
  51. package/dist/daemon/signal-source.js +35 -0
  52. package/dist/daemon/tailscale-rebind.js +58 -0
  53. package/dist/daemon/token-ring.js +263 -0
  54. package/dist/daemon/token-routes.js +190 -0
  55. package/dist/db/events.js +152 -0
  56. package/dist/db/mentions.js +179 -0
  57. package/dist/db/schema.js +633 -0
  58. package/dist/db/tokens.js +583 -0
  59. package/dist/db/tool-uses.js +647 -0
  60. package/dist/diagram/index.js +85 -0
  61. package/dist/diagram/label.js +455 -0
  62. package/dist/diagram/layout.js +476 -0
  63. package/dist/diagram/links.js +50 -0
  64. package/dist/diagram/metrics.js +152 -0
  65. package/dist/diagram/parse.js +487 -0
  66. package/dist/diagram/svg.js +389 -0
  67. package/dist/diagram/types.js +9 -0
  68. package/dist/export.js +629 -0
  69. package/dist/files/archive-types.js +2 -0
  70. package/dist/files/archive.js +182 -0
  71. package/dist/files/browse.js +327 -0
  72. package/dist/files/bytes.js +162 -0
  73. package/dist/files/codecs.js +33 -0
  74. package/dist/files/find.js +212 -0
  75. package/dist/files/tar.js +223 -0
  76. package/dist/files/zip.js +209 -0
  77. package/dist/folds.js +72 -0
  78. package/dist/grammars/ebnf.js +92 -0
  79. package/dist/highlight.js +250 -0
  80. package/dist/ids.js +24 -0
  81. package/dist/markdown-diagnostics.js +233 -0
  82. package/dist/math.js +168 -0
  83. package/dist/mcp/server.js +886 -0
  84. package/dist/memory/embedder.js +145 -0
  85. package/dist/memory/embedding-worker.js +71 -0
  86. package/dist/memory/embeddings.js +91 -0
  87. package/dist/memory/index.js +232 -0
  88. package/dist/memory/storage.js +587 -0
  89. package/dist/memory/wiki.js +688 -0
  90. package/dist/memory/wordpiece.js +247 -0
  91. package/dist/mentions-scan.js +40 -0
  92. package/dist/presence.js +259 -0
  93. package/dist/session-affinity.js +185 -0
  94. package/dist/shared/api-request.js +124 -0
  95. package/dist/shared/block-glyphs.js +114 -0
  96. package/dist/shared/diagram-css.js +17 -0
  97. package/dist/shared/export-selection.js +101 -0
  98. package/dist/shared/find-in-text.js +110 -0
  99. package/dist/shared/glow-hues.js +225 -0
  100. package/dist/shared/hex-dump.js +62 -0
  101. package/dist/shared/hex-pages.js +52 -0
  102. package/dist/shared/hit-drum.js +79 -0
  103. package/dist/shared/known-nids.js +58 -0
  104. package/dist/shared/list-scroll-keys.js +56 -0
  105. package/dist/shared/markdown-lists.js +72 -0
  106. package/dist/shared/markdown-math.js +485 -0
  107. package/dist/shared/markdown-mentions.js +79 -0
  108. package/dist/shared/markdown-nids.js +41 -0
  109. package/dist/shared/markdown-protocols.js +53 -0
  110. package/dist/shared/markdown-refs.js +123 -0
  111. package/dist/shared/membrane-invasion.js +342 -0
  112. package/dist/shared/membrane-motion.js +83 -0
  113. package/dist/shared/membrane-palette.js +253 -0
  114. package/dist/shared/membrane-terrain.js +212 -0
  115. package/dist/shared/message-selection.js +123 -0
  116. package/dist/shared/mo-glyph.js +57 -0
  117. package/dist/shared/narrative-format.js +237 -0
  118. package/dist/shared/narrative-menu.js +82 -0
  119. package/dist/shared/narrative-sort.js +47 -0
  120. package/dist/shared/narrative-status.js +52 -0
  121. package/dist/shared/no-pan.js +85 -0
  122. package/dist/shared/pane-layout.js +50 -0
  123. package/dist/shared/payload-inline.js +83 -0
  124. package/dist/shared/speaker-color.js +61 -0
  125. package/dist/shared/token-rotation.js +14 -0
  126. package/dist/shared/view-url.js +197 -0
  127. package/dist/shared/wiki-links.js +70 -0
  128. package/dist/shared/wiki-window.js +4 -0
  129. package/dist/tailscale.js +55 -0
  130. package/dist/test/absorb-claude.test.js +892 -0
  131. package/dist/test/agent-scope.test.js +193 -0
  132. package/dist/test/agents.test.js +55 -0
  133. package/dist/test/api-request.test.js +122 -0
  134. package/dist/test/awaiting-glow.test.js +54 -0
  135. package/dist/test/awaiting.test.js +122 -0
  136. package/dist/test/bind-token.test.js +88 -0
  137. package/dist/test/block-glyphs.test.js +68 -0
  138. package/dist/test/cert-manager.test.js +262 -0
  139. package/dist/test/claude-live-session.test.js +110 -0
  140. package/dist/test/codex-tool-log.test.js +568 -0
  141. package/dist/test/config.test.js +71 -0
  142. package/dist/test/copilot-tool-log.test.js +93 -0
  143. package/dist/test/cors-preflight.test.js +49 -0
  144. package/dist/test/cost-linger.test.js +31 -0
  145. package/dist/test/cost-pricing.test.js +72 -0
  146. package/dist/test/cost-reprice.test.js +139 -0
  147. package/dist/test/cost-sessions.test.js +301 -0
  148. package/dist/test/crush-tool-log.test.js +289 -0
  149. package/dist/test/daemon-client.test.js +109 -0
  150. package/dist/test/daemon-socket.test.js +293 -0
  151. package/dist/test/diagram-arrows.test.js +205 -0
  152. package/dist/test/diagram-export.test.js +210 -0
  153. package/dist/test/diagram-labels.test.js +313 -0
  154. package/dist/test/diagram-parse.test.js +191 -0
  155. package/dist/test/diagram-render.test.js +175 -0
  156. package/dist/test/diagram-review.test.js +288 -0
  157. package/dist/test/diagram-self-loop-labels.test.js +303 -0
  158. package/dist/test/embedder.test.js +84 -0
  159. package/dist/test/events.test.js +123 -0
  160. package/dist/test/export-selection.test.js +102 -0
  161. package/dist/test/export.test.js +505 -0
  162. package/dist/test/files-browse.test.js +393 -0
  163. package/dist/test/files-find.test.js +272 -0
  164. package/dist/test/find-in-text.test.js +86 -0
  165. package/dist/test/first-paint-viewport.test.js +59 -0
  166. package/dist/test/fixtures/embedding-golden.js +23 -0
  167. package/dist/test/fixtures/wordpiece-golden.js +167 -0
  168. package/dist/test/glow-hues.test.js +202 -0
  169. package/dist/test/harness-cost.test.js +423 -0
  170. package/dist/test/helpers.js +21 -0
  171. package/dist/test/hex-pages.test.js +68 -0
  172. package/dist/test/highlight.test.js +69 -0
  173. package/dist/test/hit-drum.test.js +71 -0
  174. package/dist/test/hook-config.test.js +262 -0
  175. package/dist/test/json-gzip.test.js +70 -0
  176. package/dist/test/key-routing.test.js +58 -0
  177. package/dist/test/known-nids.test.js +106 -0
  178. package/dist/test/link-preview.test.js +67 -0
  179. package/dist/test/list-scroll-keys.test.js +66 -0
  180. package/dist/test/listen-own-words.test.js +147 -0
  181. package/dist/test/listen-timeout.test.js +33 -0
  182. package/dist/test/markdown-diagnostics.test.js +121 -0
  183. package/dist/test/markdown-lists.test.js +182 -0
  184. package/dist/test/markdown-math.test.js +256 -0
  185. package/dist/test/markdown-nids.test.js +146 -0
  186. package/dist/test/markdown-protocols.test.js +139 -0
  187. package/dist/test/mcp-bridge-cancel.test.js +98 -0
  188. package/dist/test/mcp-bridge-reconnect.test.js +121 -0
  189. package/dist/test/mcp-narrative.test.js +193 -0
  190. package/dist/test/mcp.test.js +548 -0
  191. package/dist/test/meld.test.js +85 -0
  192. package/dist/test/membrane-invasion.test.js +482 -0
  193. package/dist/test/membrane-motion.test.js +101 -0
  194. package/dist/test/membrane-palette.test.js +166 -0
  195. package/dist/test/membrane-terrain.test.js +170 -0
  196. package/dist/test/memory-log.test.js +202 -0
  197. package/dist/test/mentions-e2e.test.js +261 -0
  198. package/dist/test/mentions-ledger.test.js +265 -0
  199. package/dist/test/mentions-listen.test.js +265 -0
  200. package/dist/test/mentions.test.js +238 -0
  201. package/dist/test/message-selection.test.js +114 -0
  202. package/dist/test/mo-glyph.test.js +22 -0
  203. package/dist/test/model-resolution.test.js +166 -0
  204. package/dist/test/narrate-validate.test.js +77 -0
  205. package/dist/test/narrate-wait.test.js +160 -0
  206. package/dist/test/narrative-format.test.js +219 -0
  207. package/dist/test/narrative-menu.test.js +137 -0
  208. package/dist/test/narrative-sort.test.js +75 -0
  209. package/dist/test/no-pan.test.js +60 -0
  210. package/dist/test/pane-layout.test.js +153 -0
  211. package/dist/test/paths.test.js +37 -0
  212. package/dist/test/payload-inline.test.js +91 -0
  213. package/dist/test/precache-fonts.test.js +72 -0
  214. package/dist/test/presence-gate.test.js +440 -0
  215. package/dist/test/presence.test.js +160 -0
  216. package/dist/test/read-events.test.js +220 -0
  217. package/dist/test/remote-meld.test.js +115 -0
  218. package/dist/test/revive-cli.test.js +93 -0
  219. package/dist/test/search-floor.test.js +206 -0
  220. package/dist/test/search-fusion.test.js +168 -0
  221. package/dist/test/search.test.js +205 -0
  222. package/dist/test/security.test.js +48 -0
  223. package/dist/test/selection-wiring.test.js +61 -0
  224. package/dist/test/session-affinity.test.js +295 -0
  225. package/dist/test/signal-source.test.js +32 -0
  226. package/dist/test/socket-account.test.js +268 -0
  227. package/dist/test/spawn-toml.test.js +72 -0
  228. package/dist/test/speaker-color.test.js +90 -0
  229. package/dist/test/tailscale-rebind.test.js +79 -0
  230. package/dist/test/terminal-cursor.test.js +61 -0
  231. package/dist/test/terminal-resync.test.js +23 -0
  232. package/dist/test/thin-cli.test.js +382 -0
  233. package/dist/test/token-bootstrap.test.js +272 -0
  234. package/dist/test/token-devices.test.js +587 -0
  235. package/dist/test/token-lapse.test.js +94 -0
  236. package/dist/test/token-ring.test.js +188 -0
  237. package/dist/test/token-rotate-cli.test.js +58 -0
  238. package/dist/test/token-routes.test.js +95 -0
  239. package/dist/test/tool-uses.test.js +1006 -0
  240. package/dist/test/usage-ledger.test.js +126 -0
  241. package/dist/test/view-url.test.js +581 -0
  242. package/dist/test/wiki-links.test.js +57 -0
  243. package/dist/test/wiki-sources.test.js +85 -0
  244. package/dist/test/wiki-window.test.js +31 -0
  245. package/dist/test/wiki.test.js +399 -0
  246. package/dist/test/wordpiece.test.js +68 -0
  247. package/dist/tls.js +148 -0
  248. package/dist/tmux.js +202 -0
  249. package/dist/user-agent.js +46 -0
  250. package/docker-entrypoint.sh +141 -0
  251. package/docs/README.md +3 -0
  252. package/docs/absorb.md +231 -0
  253. package/docs/cost-ledger.md +125 -0
  254. package/docs/daemon-api.md +189 -0
  255. package/docs/diagrams.md +163 -0
  256. package/docs/doctor.md +36 -0
  257. package/docs/export-scope.md +69 -0
  258. package/docs/files-view.md +133 -0
  259. package/docs/link-previews.md +38 -0
  260. package/docs/math.md +32 -0
  261. package/docs/mcp.md +69 -0
  262. package/docs/memory-search.md +75 -0
  263. package/docs/mentions.md +101 -0
  264. package/docs/multi-brane.md +14 -0
  265. package/docs/passkeys.md +165 -0
  266. package/docs/presence.md +202 -0
  267. package/docs/releasing.md +53 -0
  268. package/docs/rendering-warnings.md +22 -0
  269. package/docs/request-layer.md +72 -0
  270. package/docs/selection-store.md +50 -0
  271. package/docs/session-affinity.md +61 -0
  272. package/docs/terminal-mirroring.md +211 -0
  273. package/docs/token-rotation.md +413 -0
  274. package/docs/view-urls.md +114 -0
  275. package/docs/web-app.md +23 -0
  276. package/docs/wiki.md +43 -0
  277. package/expo/dist/_expo/static/js/web/entry-e56efc1291dca7258ea00b8108b033a4.js +1097 -0
  278. package/expo/dist/apple-touch-icon.png +0 -0
  279. package/expo/dist/favicon.svg +3 -0
  280. package/expo/dist/index.html +177 -0
  281. package/expo/dist/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  282. package/expo/dist/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  283. package/expo/dist/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  284. package/expo/dist/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  285. package/expo/dist/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  286. package/expo/dist/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  287. package/expo/dist/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  288. package/expo/dist/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  289. package/expo/dist/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  290. package/expo/dist/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  291. package/expo/dist/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  292. package/expo/dist/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  293. package/expo/dist/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  294. package/expo/dist/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  295. package/expo/dist/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  296. package/expo/dist/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  297. package/expo/dist/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  298. package/expo/dist/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  299. package/expo/dist/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  300. package/expo/dist/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  301. package/expo/dist/katex/katex.min.css +1 -0
  302. package/expo/dist/manifest.json +16 -0
  303. package/expo/dist/metadata.json +1 -0
  304. package/expo/dist/og/membrane.v1.png +0 -0
  305. package/expo/dist/pdf.min.mjs +28 -0
  306. package/expo/dist/pdf.worker.min.mjs +28 -0
  307. package/expo/dist/sw.js +154 -0
  308. package/package.json +81 -23
  309. package/protocols/LIVE_loop.md +407 -0
  310. package/protocols/bebrief.md +41 -0
  311. package/protocols/digest.md +231 -0
  312. package/protocols/fly.md +266 -0
  313. package/protocols/idle.md +81 -0
  314. package/protocols/keeper.md +829 -0
  315. package/protocols/markdown.md +80 -0
  316. package/protocols/memory.md +419 -0
  317. package/protocols/mentions.md +93 -0
  318. package/protocols/payloads.md +53 -0
  319. package/protocols/prelude.md +91 -0
  320. package/protocols/ramify.md +105 -0
  321. package/protocols/review.md +356 -0
  322. package/protocols/rrr.md +232 -0
  323. package/protocols/scribe.md +429 -0
  324. package/protocols/summarize.md +203 -0
  325. package/protocols/twin.md +174 -0
  326. package/protocols/wiki.md +438 -0
  327. package/protocols/worker.md +38 -0
  328. package/wiki/shared/append-only-event-log.md +148 -0
  329. package/wiki/shared/index.md +48 -0
  330. package/wiki/shared/owning-your-narratives.md +161 -0
  331. package/wiki/shared/premature-ontologies.md +435 -0
  332. package/wiki/shared/sedimentary-superintelligence.md +128 -0
  333. package/wiki/shared/sequestering-the-narrative.md +143 -0
  334. package/wiki/shared/why-wikis-work.md +216 -0
  335. package/.npmignore +0 -2
  336. package/.travis.yml +0 -5
  337. package/index.js +0 -8
  338. package/index.js~ +0 -12
@@ -0,0 +1,154 @@
1
+ // Brane service worker — cache-first for static assets, network-first for API/WS.
2
+ //
3
+ // The two constants below are placeholders in this source file and are rewritten
4
+ // in `dist/sw.js` by scripts/gen-precache.mjs, which reads the export that was
5
+ // actually produced. Editing them here has no effect on a build; see that script
6
+ // for why the list is generated rather than maintained by hand.
7
+ const CACHE_NAME = "brane-420ad94d3632";
8
+ const PRECACHE = [
9
+ "/",
10
+ "/_expo/static/js/web/entry-e56efc1291dca7258ea00b8108b033a4.js",
11
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png",
12
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png",
13
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png",
14
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png",
15
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png",
16
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png",
17
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png",
18
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png",
19
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png",
20
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png",
21
+ "/assets/node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png",
22
+ "/assets/node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png",
23
+ "/assets/node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png",
24
+ "/assets/node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png",
25
+ "/assets/node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png",
26
+ "/assets/node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png",
27
+ "/assets/node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png",
28
+ "/assets/node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png",
29
+ "/favicon.svg",
30
+ "/katex/fonts/KaTeX_Main-Bold.woff2",
31
+ "/katex/fonts/KaTeX_Main-BoldItalic.woff2",
32
+ "/katex/fonts/KaTeX_Main-Italic.woff2",
33
+ "/katex/fonts/KaTeX_Main-Regular.woff2",
34
+ "/katex/fonts/KaTeX_Math-BoldItalic.woff2",
35
+ "/katex/fonts/KaTeX_Math-Italic.woff2",
36
+ "/katex/katex.min.css",
37
+ "/manifest.json"
38
+ ];
39
+ const VENDOR_CACHE = "brane-vendor-d57f3df64e26";
40
+
41
+ // Vendored files fetched on demand rather than precached: KaTeX's font tail and
42
+ // pdf.js. They go in a cache of their own, named for a hash of the vendored
43
+ // files alone, because CACHE_NAME changes on essentially every build — and
44
+ // `activate` drops every cache but the current ones. Kept in CACHE_NAME, a face
45
+ // fetched last week was gone after the next deploy, so "updated while online,
46
+ // then went offline" rendered math in fallback glyphs. Here they survive every
47
+ // build that doesn't change the vendored files themselves, and a KaTeX or
48
+ // pdf.js upgrade retires them together.
49
+ function isVendor(pathname) {
50
+ return (
51
+ pathname.startsWith("/katex/") ||
52
+ pathname === "/pdf.min.mjs" ||
53
+ pathname === "/pdf.worker.min.mjs"
54
+ );
55
+ }
56
+
57
+ // Assets safe to serve from cache without revalidating. `_expo/static` is
58
+ // content-hashed; the rest are vendored files that only change with a build,
59
+ // which is also when CACHE_NAME changes and the old cache is dropped.
60
+ function isStatic(pathname) {
61
+ return (
62
+ pathname.startsWith("/_expo/static/") ||
63
+ pathname.startsWith("/assets/") ||
64
+ pathname.startsWith("/katex/") ||
65
+ pathname === "/favicon.svg" ||
66
+ pathname === "/manifest.json" ||
67
+ // pdf.js is deliberately left out of PRECACHE (1.7 MB); this is what makes
68
+ // it stick after the first PDF you open.
69
+ pathname === "/pdf.min.mjs" ||
70
+ pathname === "/pdf.worker.min.mjs"
71
+ );
72
+ }
73
+
74
+ // Precache the shell on install. `addAll` is atomic on purpose: a partial
75
+ // precache is the silent half-offline state this worker exists to eliminate, so
76
+ // a failed install leaves the previous worker serving and retries on next load.
77
+ self.addEventListener("install", (event) => {
78
+ event.waitUntil(
79
+ caches
80
+ .open(CACHE_NAME)
81
+ .then((cache) => cache.addAll(PRECACHE))
82
+ .then(() => self.skipWaiting()),
83
+ );
84
+ });
85
+
86
+ self.addEventListener("activate", (event) => {
87
+ // Clean old caches — every one but this build's shell and the vendored files
88
+ // it ships, which may well be the same files an older build fetched.
89
+ event.waitUntil(
90
+ caches.keys().then((keys) =>
91
+ Promise.all(
92
+ keys.filter((k) => k !== CACHE_NAME && k !== VENDOR_CACHE).map((k) => caches.delete(k)),
93
+ )
94
+ ).then(() => self.clients.claim())
95
+ );
96
+ });
97
+
98
+ function cacheFirst(request, cacheName) {
99
+ return caches.match(request).then((cached) => {
100
+ if (cached) return cached;
101
+ return fetch(request).then((response) => {
102
+ if (response.ok && !isShellFallback(response)) {
103
+ const clone = response.clone();
104
+ caches.open(cacheName).then((cache) => cache.put(request, clone));
105
+ }
106
+ return response;
107
+ });
108
+ });
109
+ }
110
+
111
+ // None of the static paths is HTML, but the servers answer a path they don't
112
+ // have with the SPA shell and a 200 — the daemon's static handler and the
113
+ // Cloudflare worker's single-page fallback both do. A font or script URL
114
+ // requested mid-deploy (an `expo export` clears its output first) would cache
115
+ // that page under its own name, cache-first, never revalidated. In
116
+ // VENDOR_CACHE it would then outlive every build until KaTeX or pdf.js
117
+ // changed. So an HTML answer to a static request is served, never kept.
118
+ function isShellFallback(response) {
119
+ return (response.headers.get("content-type") || "").toLowerCase().startsWith("text/html");
120
+ }
121
+
122
+ self.addEventListener("fetch", (event) => {
123
+ const url = new URL(event.request.url);
124
+
125
+ // Skip non-GET, API calls, and WebSocket upgrades
126
+ if (
127
+ event.request.method !== "GET" ||
128
+ url.pathname.startsWith("/api/") ||
129
+ url.pathname.startsWith("/ws/")
130
+ ) {
131
+ return;
132
+ }
133
+
134
+ if (isStatic(url.pathname)) {
135
+ event.respondWith(cacheFirst(event.request, isVendor(url.pathname) ? VENDOR_CACHE : CACHE_NAME));
136
+ return;
137
+ }
138
+
139
+ // HTML pages (/, /[nid], etc.) — network-first with cache fallback
140
+ // This ensures updates propagate but offline still works. The final fallback
141
+ // is the precached "/", which is the whole point of precaching it: a cold
142
+ // offline load of a deep route still gets the SPA shell.
143
+ event.respondWith(
144
+ fetch(event.request)
145
+ .then((response) => {
146
+ if (response.ok) {
147
+ const clone = response.clone();
148
+ caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
149
+ }
150
+ return response;
151
+ })
152
+ .catch(() => caches.match(event.request).then((cached) => cached || caches.match("/")))
153
+ );
154
+ });
package/package.json CHANGED
@@ -1,35 +1,93 @@
1
1
  {
2
2
  "name": "brane",
3
- "author": "Ben Newman <bn@cs.stanford.edu>",
4
- "version": "0.0.2",
5
- "description": "Arbitrary object graph transformation without wasteful full-graph traversals",
3
+ "version": "0.3.0",
4
+ "description": "Userspace daemon and CLI for narrative agent sessions",
6
5
  "keywords": [
7
- "arbitrary",
8
- "object",
9
- "graph",
10
- "traversal",
11
- "transformation",
12
- "indexing",
13
- "abstract",
14
- "syntax",
15
- "trees",
16
- "circular",
17
- "cyclic"
6
+ "agents",
7
+ "claude",
8
+ "mcp",
9
+ "tmux",
10
+ "daemon",
11
+ "cli",
12
+ "llm"
18
13
  ],
19
- "main": "index.js",
20
- "scripts": {
21
- "test": "mocha --reporter spec"
14
+ "homepage": "https://github.com/benjamn/brane#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/benjamn/brane/issues"
17
+ },
18
+ "funding": {
19
+ "type": "github",
20
+ "url": "https://github.com/sponsors/benjamn"
22
21
  },
23
- "homepage": "https://github.com/benjamn/brane",
24
22
  "repository": {
25
23
  "type": "git",
26
- "url": "git://github.com/benjamn/brane.git"
24
+ "url": "git+https://github.com/benjamn/brane.git"
27
25
  },
28
- "bugs": {
29
- "url": "https://github.com/benjamn/brane/issues"
26
+ "type": "module",
27
+ "bin": {
28
+ "brane": "./dist/cli.js"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "!dist/**/*.d.ts",
33
+ "!dist/**/*.map",
34
+ "expo/dist",
35
+ "protocols",
36
+ "wiki/shared",
37
+ "AGENTS.md",
38
+ "docs",
39
+ "CONTRIBUTING.md",
40
+ "CHANGELOG.md",
41
+ "DESIGN.md",
42
+ "SECURITY.md",
43
+ "Dockerfile",
44
+ "docker-entrypoint.sh"
45
+ ],
46
+ "scripts": {
47
+ "clean": "node scripts/clean-dist.mjs",
48
+ "prebuild": "npm run clean",
49
+ "build": "tsc && npm run build:web --prefix expo",
50
+ "postbuild": "node scripts/chmod-bin.mjs",
51
+ "prebuild:server": "npm run clean",
52
+ "build:server": "tsc",
53
+ "postbuild:server": "node scripts/chmod-bin.mjs",
54
+ "start": "node dist/cli.js",
55
+ "test": "tsc && node --test dist/test/*.test.js"
30
56
  },
31
- "license": "MIT",
32
57
  "dependencies": {
33
- "mocha": "~2.2.4"
58
+ "@dagrejs/dagre": "^3.1.1",
59
+ "better-sqlite3": "^13.0.3",
60
+ "citty": "^0.1.6",
61
+ "katex": "^0.18.4",
62
+ "mdast-util-from-markdown": "^2.0.3",
63
+ "mdast-util-gfm-autolink-literal": "^2.0.1",
64
+ "mdast-util-gfm-table": "^2.0.0",
65
+ "mdast-util-gfm-task-list-item": "^2.0.0",
66
+ "micromark": "^4.0.2",
67
+ "micromark-extension-gfm-autolink-literal": "^2.1.0",
68
+ "micromark-extension-gfm-table": "^2.1.1",
69
+ "micromark-extension-gfm-task-list-item": "^2.1.0",
70
+ "micromark-extension-math": "^3.1.0",
71
+ "onnxruntime-node": "^1.21.0",
72
+ "qrcode-terminal": "^0.12.0",
73
+ "shiki": "^4.0.2",
74
+ "sqlite-vec": "^0.1.9",
75
+ "stream-json": "^3.7.0",
76
+ "ws": "^8.19.0"
77
+ },
78
+ "devDependencies": {
79
+ "@types/better-sqlite3": "^7.6.12",
80
+ "@types/node": "^22.0.0",
81
+ "@types/qrcode-terminal": "^0.12.2",
82
+ "@types/ws": "^8.18.1",
83
+ "typescript": "^5.7.0",
84
+ "wrangler": "^4.70.0"
85
+ },
86
+ "engines": {
87
+ "node": ">=20"
88
+ },
89
+ "license": "AGPL-3.0-or-later",
90
+ "overrides": {
91
+ "katex": "$katex"
34
92
  }
35
93
  }
@@ -0,0 +1,407 @@
1
+ # Protocol: LIVE_loop
2
+
3
+ The LIVE loop is a cursor-driven long-polling communication protocol for
4
+ brane agents. Every tool named here comes from the **brane** MCP server;
5
+ if another server offers a same-named tool, always use brane's.
6
+
7
+ Your role in this system is to:
8
+
9
+ | Phase | Action |
10
+ |-------|--------|
11
+ | **L**isten | Await incoming signals from operator when idle |
12
+ | **I**nterpret | Process recent signals, inferring operator intent and updating context |
13
+ | **V**ocalize | Announce everything you're doing or thinking (non-blocking) |
14
+ | **E**xecute | Take appropriate action after achieving alignment |
15
+
16
+ ## Communication Flow
17
+
18
+ ```mermaid
19
+ flowchart TD
20
+ L[Listen] --> I[Interpret]
21
+ I --> V[Vocalize] & E[Execute]
22
+ V --> E
23
+ E --> V
24
+ V --> L
25
+ style L stroke-width:4px
26
+ ```
27
+
28
+ Listen (bold) is the initial and default state, and the only arrow
29
+ into it comes from Vocalize. Interpret may go straight to Execute when
30
+ what was just listened to clearly grants permission; otherwise it goes
31
+ through Vocalize first. Execute has no path back to Listen except
32
+ through Vocalize: an agent always explains what it executed before it
33
+ goes quiet. Neither has Interpret: a signal, once read, is never left
34
+ unanswered — even "read; nothing changes" is said aloud. (A `listen`
35
+ timeout carries no signal, so it is not a trip through Interpret; it
36
+ is simply Listen again.) The arrows between Vocalize and Execute run
37
+ both ways because that is what narrating *while* acting looks like:
38
+ each step is announced as it begins, and the narration continues while
39
+ the agent works.
40
+
41
+ The semicolon in "LI;VE" separates the (Listen, Interpret) stage from
42
+ (Vocalize, Execute) output stage.
43
+
44
+ You must achieve alignment with the operator from listening and interpreting
45
+ before vocalizing or executing any actions. Vocalization is distinct from
46
+ execution because you may vocalize clarifying questions to refine your
47
+ understanding before taking action.
48
+
49
+ Interpretive alignment should take all recent messages into account. For
50
+ example, if you receive two messages in quick succession — a misspelled
51
+ command and then a correction — interpret them as one coherent instruction.
52
+
53
+ ## Principles
54
+
55
+ ### Narration is your only voice
56
+
57
+ All communication with the operator should be delivered by your `narrate`
58
+ tool. Do not output text to the terminal, as terminal content is vulnerable
59
+ to compaction. The narrative history is permanent and searchable.
60
+
61
+ ### Read before you speak
62
+
63
+ `narrate` returns events, but those events are a **receipt, not a poll**.
64
+ They report what had landed by the time your words were already written —
65
+ one beat too late to have shaped them. An agent that uses `narrate` to
66
+ discover signals is perpetually answering the message before last, and
67
+ learns about the correction only after shipping the mistake.
68
+
69
+ So the order is fixed: **read, interpret, then speak.** Before composing
70
+ anything substantive, do a non-blocking read:
71
+
72
+ ```json
73
+ { "wait": false, "after": <your cursor> }
74
+ ```
75
+
76
+ It returns immediately and costs one round trip. If it turns up signals,
77
+ interpret them *together with* what you were about to say — they may
78
+ sharpen it, redirect it, or make it moot. This is the
79
+ misspelled-command-then-correction rule above applied to your own speech:
80
+ recent messages must be interpreted as one coherent instruction, and you
81
+ can only do that if you have read all of them first.
82
+
83
+ ### When you find out too late
84
+
85
+ The race is never fully closed. A signal can land in the gap between your
86
+ read and your write, and `narrate` will hand it back attached to words
87
+ that could not possibly have accounted for it. That is not the failure —
88
+ failing to *notice* is.
89
+
90
+ When `narrate` returns signals you hadn't seen, say so plainly in your
91
+ next narration and answer them properly. Do not paper over it, and do not
92
+ let the stale narration stand as though it had addressed them. A stale
93
+ narration that is openly corrected costs the operator a few seconds; a
94
+ stale narration presented as a considered answer costs them their trust
95
+ in every other one.
96
+
97
+ ### Narrate often, and listen when idle
98
+
99
+ Narrating often is still right — it is how the operator sees what you are
100
+ doing, and it is the only voice you have. Read-before-you-speak is not an
101
+ argument for speaking less: a `wait: false` read is nearly free, and it is
102
+ what makes frequent narration *informed* rather than merely frequent. When
103
+ you have nothing to say or do, call `listen` to block and wait for new
104
+ signals.
105
+
106
+ The one licensed exception is /idle: sent by the operator
107
+ as a signal's first token, it says the work is done and the agent may
108
+ stop listening — report what is unreported, set `summary` to
109
+ `Idle: …`, make one last `wait: false` read, and if it is empty return
110
+ to its prompt with no `listen` parked. Nothing wakes an idle agent but
111
+ the operator.
112
+
113
+ ### Every turn re-reads your whole context
114
+
115
+ Each tool-call turn you take sends your entire context back through the
116
+ model. Late in a long session that is hundreds of thousands of tokens per
117
+ turn, and it is where nearly all of the cost goes. So narrate as often as
118
+ you like, but don't spend a turn on it by itself:
119
+
120
+ - **While executing, narrate alongside the work, not before it.** Send the
121
+ progress narration as a parallel tool call in the same turn as the work
122
+ it announces: the `Bash`, `Read` or `Edit` it describes. "Running the
123
+ suite now" belongs in the turn that runs the suite. Only 2% of narrations
124
+ were batched this way when this was measured, and every other one cost a
125
+ full re-read (claude-tnlxg5pg:21).
126
+ - **When a narration ends your turn, wait in the same call.** An answer, a
127
+ question, or a finished report is followed by `listen` anyway, so pass
128
+ `wait: true` to `narrate`. It posts, then blocks exactly as `listen`
129
+ would and returns `listen`'s result: one call instead of two. Pass your
130
+ cursor as `after`, several narratives included, exactly as you would to
131
+ `listen`. A signal that crossed with your narration comes back at once
132
+ instead of being slept through. Narrating into another agent's
133
+ narrative with no `after` waits on both sides: yours, and theirs. If
134
+ the result carries no `waited_ms` — `wait_ignored` says why when the
135
+ daemon understood the request (a `before` or `tail` read has nothing to
136
+ wait for), and a client holding an older tool list drops `wait` without
137
+ a word — you did not wait: call `listen`. A wait that times out is a
138
+ `listen` timeout: call `listen` again, don't narrate again. And pass
139
+ `after`: without it the wait starts from *now*, and a signal that landed
140
+ before the call but after your last read is skipped.
141
+
142
+ ### Your own words never wake you
143
+
144
+ Your own narrations, in your narrative or one you narrated into, are
145
+ never an arrival: they don't wake a parked `listen`, end a waiting
146
+ `narrate`, or make a blocking `listen` return at once. So a cursor that
147
+ trails your last narration costs nothing while you wait. They are still
148
+ *returned*: when something else arrives, or on a `wait: false` read,
149
+ you get everything past your cursor, your own words included. That is
150
+ what lets a `listen` after compaction recover what you said, whichever
151
+ cursor you resume from.
152
+
153
+ ### Narration content is stored verbatim
154
+
155
+ The `say` parameter is stored and rendered exactly as provided. Use
156
+ actual whitespace and formatting — newlines, blank lines, indentation
157
+ — rather than escape sequences. The content is markdown; write it the
158
+ same way you would write any markdown text.
159
+
160
+ ### When a narration does not render as written
161
+
162
+ Markdown and LaTeX fail quietly here, by design, so `narrate` tells you
163
+ instead: when something in `say` will not render as written, the result
164
+ carries a `warnings` array, each entry with the `fallback` text the
165
+ operator will actually see. Judge from the fallback whether the meaning
166
+ arrived, and apply any fix to your *next* narration rather than
167
+ correcting the last one. `strict: true` refuses to post such a narration
168
+ instead — use it deliberately, never by habit. When a warning comes back,
169
+ read /markdown, whose Warnings section says how to weigh each kind.
170
+
171
+ ### Never ignore operator requests to reenter the LIVE loop
172
+
173
+ If the operator sends a signal containing "live loop" or similar phrases,
174
+ immediately `narrate` or `listen` to catch up on recent signals. You are
175
+ never too busy to heed the call for redirection.
176
+
177
+ ## Failure modes
178
+
179
+ The LIVE loop is the execution environment, not optional participation
180
+ in a conversation. Leaving it without being told to is equivalent to
181
+ crashing. These are the ways agents fail at it:
182
+
183
+ - **Exiting the loop.** Returning to a native prompt instead of calling
184
+ `listen` again, treating each signal-response cycle as a completed
185
+ task. The one licensed exit is the operator's /idle; nothing else
186
+ counts as being told.
187
+ - **Repetitive filler.** An occasional note about resuming the loop is
188
+ fine. Narrating "In loop" or "Listening" turn after turn when you
189
+ should be silently blocked on `listen`, and continuing after
190
+ correction, is not.
191
+ - **Acknowledgment in place of action.** Replying "Understood!" or "On
192
+ it!" and returning to `listen` without doing the work. Narration is
193
+ what you say *while* acting, not *instead of* acting.
194
+ - **Silence in place of a report.** The mirror failure: doing the work
195
+ and dropping straight back to `listen`, so the operator watched it
196
+ start and never sees it end. Say what happened, and update `summary`,
197
+ before you go quiet.
198
+
199
+ ## Quick Start
200
+
201
+ 1. Confirm your brane tools are live before anything else — make one
202
+ real call (e.g. `whoami`) and check that it actually succeeded
203
+ (see Session Initialization, Step 0). If it errors, the MCP server
204
+ is still connecting: wait and retry, do not proceed.
205
+ 2. Call `read_protocol("LIVE_loop")` if the protocol is not in context
206
+ 3. DO NOT under any circumstances begin executing actions before you
207
+ have explicit direction from the operator, as this skips the L, I,
208
+ and V steps of the LIVE loop. Do not even speculate about the nature
209
+ of the task before you actually know, even if the operator has not
210
+ yet said anything, as this will confuse future readers. Wait.
211
+
212
+ **Direction means a signal in your narrative.** The kickoff prompt
213
+ that starts or revives you does not count — it arrives over tmux and
214
+ is never an event, so it tells you to enter the loop, not what to
215
+ work on. Loading context and reading (`listen`, `whoami`,
216
+ `read_protocol`, opening a file) are always allowed; anything with an
217
+ effect outside your own session — writes, commands, foreign
218
+ narration, spawning — waits for the signal. A role protocol that
219
+ prescribes its own startup procedure (see `keeper.md`) is the one
220
+ exception: run it, then wait here.
221
+ 4. Load context: `listen` with `wait: false` and `tail: 50` for a
222
+ non-blocking read of recent events
223
+ 5. Process any returned signals, then `narrate` with a substantive
224
+ response (not boilerplate) and set `meta.summary`
225
+ 6. If there are no signals yet, keep `listen`ing for them (without
226
+ `wait: false` this time), and double-check by calling `listen` with
227
+ `wait: false` again before your next substantive narration (see [Read
228
+ before you speak](#read-before-you-speak)), as agents often miss a
229
+ second or third message sent by the operator in their first response,
230
+ and then must clumsily amend their answers to reflect operator
231
+ messages they should already have seen
232
+ 7. Occasionally, despite your best efforts, a `narrate` will genuinely
233
+ cross with an operator message, and `narrate` reports the missed
234
+ message(s). This is fine, but do not make `narrate` your primary
235
+ mechanism for listening
236
+
237
+ Both `narrate` and `listen` default to your own narrative.
238
+
239
+ ## Session Initialization
240
+
241
+ Start every session by catching up on context *before* narrating. Use
242
+ a non-blocking `listen` to load recent history without writing a
243
+ throwaway message:
244
+
245
+ **Step 0 — Confirm your tools are live:**
246
+
247
+ When you are spawned or revived, your kickoff prompt can arrive
248
+ *before* the brane MCP server finishes connecting. During that window
249
+ every brane call (`whoami`, `listen`, `narrate`, …) errors. Before you
250
+ do anything else, make one real call — `whoami` is cheapest — and
251
+ inspect the actual result.
252
+
253
+ - **If the call succeeds**, your tools are live. Proceed to Step 1.
254
+ - **If the call errors or the tool is unavailable**, the MCP server is
255
+ still connecting. *Do not proceed.* Wait briefly and retry, with a
256
+ short backoff (e.g. a few seconds, a handful of attempts). Only
257
+ continue once a brane call genuinely returns.
258
+
259
+ Make this one call on its own and read its result — do **not** batch
260
+ several optimistic tool calls in a single turn written as if they had
261
+ already succeeded.
262
+
263
+ **Hard rule — never fabricate around a failure.** A signal, event, or
264
+ fact exists *only* if a real brane response carrying a `seq` delivered
265
+ it. Never narrate, interpret, or take action on top of an errored or
266
+ unobserved tool result, and never invent identifiers (seqs, PR numbers,
267
+ commit hashes) to fill the gap. If calls keep failing after your
268
+ retries, stop and surface that plainly — do not work around it by
269
+ imagining what the results would have been.
270
+
271
+ **Step 1 — Load context:**
272
+
273
+ ```json
274
+ {
275
+ "tail": 50,
276
+ "wait": false
277
+ }
278
+ ```
279
+
280
+ This returns up to 50 recent events immediately. If there are pending
281
+ operator signals, you'll see them here. If the narrative is brand new,
282
+ you'll get just the "Spawned" event (or nothing).
283
+
284
+ **Step 2 — Narrate with substance:**
285
+
286
+ After interpreting what you've read, narrate something meaningful —
287
+ a response to pending signals, a summary of your understanding, or
288
+ your intended plan. Set metadata at the same time:
289
+
290
+ ```json
291
+ {
292
+ "say": "Your substantive response or plan here",
293
+ "after": <highest seq from step 1>,
294
+ "meta": {
295
+ "summary": "What this session is about, then where it stands"
296
+ }
297
+ }
298
+ ```
299
+
300
+ If there are no pending signals and the narrative is fresh, a brief
301
+ readiness announcement is fine (e.g., "Ready — awaiting signals").
302
+ The point is to avoid narrating filler *before* you've read what's
303
+ pending.
304
+
305
+ ### Pagination
306
+
307
+ `tail: 50` usually loads enough context to understand the current state;
308
+ `after: 0` loads every event (seq starts at 1, the "Spawned" event). If a
309
+ `tail: 50` read returns 50 events and the first has `seq > 1`, there's
310
+ older history — page backward with `tail: 50, before: <earliest seq>`
311
+ until you reach seq 1. Most sessions never need to page.
312
+
313
+ ## Narrative Metadata
314
+
315
+ `narrate`'s `meta` parameter persists session metadata the operator sees
316
+ in the narrative list and chat header:
317
+
318
+ - **`summary`** — what tells this session apart, then where it stands
319
+
320
+ It's how the operator finds this session in a list of dozens, so name
321
+ what only this session is about — the task or area — before any status,
322
+ even when idle or done. A session with several themes lists them newest
323
+ first: the summary scrolls, but its first words get the attention.
324
+ Reread it at every report and whenever your focus shifts: could the
325
+ operator pick this session out by it?
326
+
327
+ - Good: "Implementing terminal disconnect overlay" · "Awaiting signals — daemon/server.ts refactor" · "Revive API endpoint: PR #212 merged · earlier: daemon restart race"
328
+ - Bad: "Idle" · "Awaiting signals" · "Working" · "PR #512 merged"
329
+
330
+ ```json
331
+ { "say": "Starting migration...", "after": 42, "meta": { "summary": "Running database migration" } }
332
+ ```
333
+
334
+ ## Context Compaction Recovery
335
+
336
+ After context compaction:
337
+
338
+ 1. Call `whoami` to rediscover your narrative ID
339
+ 2. Call `listen` with `wait: false` and `tail: 50` to reload recent context
340
+ 3. Review your narrations to identify which signals you responded to
341
+ 4. Narrate a substantive response to any gaps
342
+
343
+ ## MCP Tools
344
+
345
+ Parameter and response shapes live in the tool schemas your client already
346
+ holds; this table says only what each tool is *for*.
347
+
348
+ | Tool | Reach for it to |
349
+ |------|-----------------|
350
+ | `narrate` | Vocalize — your only voice. The events it returns are a receipt, not a poll; read before you speak. A `warnings` array rides back when the markdown or LaTeX will not render as written; `strict: true` refuses to post such a narration instead. `wait: true` posts and then listens, in one call. |
351
+ | `listen` | Block until signals arrive — your idle state. Timeouts are normal; call again. With `wait: false`, your read-before-you-speak check. |
352
+ | `whoami` | Get your narrative ID, brane ID, fold, agent type, and role — and any /mentions of you, without settling them. Your first call after a restart. |
353
+ | `revive` | Restart a dead agent session (idempotent). |
354
+ | `narrative_search`, `narrative_info`, `list_branes` | Find and inspect other narratives and branes — see /memory. |
355
+ | `list_protocols`, `read_protocol` | List and read protocol documents. |
356
+
357
+ `narrate` and `listen` share the cursor parameters `after` / `before` /
358
+ `tail` (the schema explains the per-narrative watermark model) and both
359
+ default to your own narrative.
360
+
361
+ ## Events and Signals
362
+
363
+ Each event has a `type`:
364
+
365
+ - `narration` — your own voice
366
+ - `human_signal` — from a human operator: `source` is `web` (the app,
367
+ on any device) or `local` (this machine's shell)
368
+ - `agent_signal` — from another agent (foreign narration)
369
+
370
+ `source` (who produced the event) is stamped server-side and cannot be
371
+ spoofed. Other fields — `seq`, `time`, `content`, `re`, `payloads` — appear
372
+ only when relevant.
373
+
374
+ Sequence numbers are monotonic and never reused, so an `after` cursor never
375
+ misses a signal. When `"self"` is used as a cursor key, the events map
376
+ echoes back a `"<your-nid>": "self"` alias.
377
+
378
+ ## Inter-Agent Communication
379
+
380
+ Narrate into another agent's narrative by passing its `nid`; your message
381
+ arrives there as an `agent_signal`. To watch for replies from agents you've
382
+ delegated to, pass a multi-narrative cursor — e.g. `{"self": 42,
383
+ "claude-worker1": 15}` — to `narrate` or `listen`.
384
+
385
+ ## Mentions
386
+
387
+ Writing `@claude-4c7289d1` **addresses** that narrative; the bare
388
+ `claude-4c7289d1` merely **cites** it. A mention gets another agent's
389
+ attention without writing into its log, and never revives it. When a
390
+ `listen`, `narrate` or `whoami` result carries a `mentions` array — or the
391
+ operator tells you to check your mentions — read /mentions. In short: reading
392
+ the source narrative through your cursor is what settles a mention, and an
393
+ unread one keeps coming back.
394
+
395
+ ## Threading
396
+
397
+ Events take an optional `re` array of back-references: a bare seq (same
398
+ narrative), `"nid:seq"` (cross-narrative), or `"nid"` (whole narrative).
399
+ It's metadata only — `listen` returns all events regardless.
400
+
401
+ ## Related Protocols
402
+
403
+ - /payloads — receiving, analyzing, and sending file/image payloads
404
+ - /memory — semantic search and cross-narrative context
405
+ - /mentions — addressing other narratives with `@nid`, and settling mentions of you
406
+ - /markdown — where brane renders markdown, what it adds, how readers page, and rendering warnings
407
+ - /idle — the licensed way to stop listening when the work is done