brane 0.1.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/AGENTS.md +367 -0
  2. package/CHANGELOG.md +66 -0
  3. package/CONTRIBUTING.md +101 -0
  4. package/DESIGN.md +405 -0
  5. package/Dockerfile +61 -0
  6. package/LICENSE +656 -17
  7. package/README.md +174 -2
  8. package/SECURITY.md +213 -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 +133 -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 +360 -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 +1101 -0
  37. package/dist/commands/token.js +154 -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 +6353 -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 +643 -0
  58. package/dist/db/tokens.js +624 -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/app-origin.js +26 -0
  96. package/dist/shared/block-glyphs.js +114 -0
  97. package/dist/shared/diagram-css.js +17 -0
  98. package/dist/shared/export-selection.js +101 -0
  99. package/dist/shared/find-in-text.js +110 -0
  100. package/dist/shared/glow-hues.js +225 -0
  101. package/dist/shared/hex-dump.js +62 -0
  102. package/dist/shared/hex-pages.js +52 -0
  103. package/dist/shared/hit-drum.js +79 -0
  104. package/dist/shared/known-nids.js +58 -0
  105. package/dist/shared/list-scroll-keys.js +56 -0
  106. package/dist/shared/markdown-lists.js +72 -0
  107. package/dist/shared/markdown-math.js +485 -0
  108. package/dist/shared/markdown-mentions.js +79 -0
  109. package/dist/shared/markdown-nids.js +41 -0
  110. package/dist/shared/markdown-protocols.js +53 -0
  111. package/dist/shared/markdown-refs.js +123 -0
  112. package/dist/shared/membrane-invasion.js +342 -0
  113. package/dist/shared/membrane-motion.js +83 -0
  114. package/dist/shared/membrane-palette.js +253 -0
  115. package/dist/shared/membrane-terrain.js +212 -0
  116. package/dist/shared/message-selection.js +123 -0
  117. package/dist/shared/mo-glyph.js +57 -0
  118. package/dist/shared/narrative-format.js +237 -0
  119. package/dist/shared/narrative-menu.js +84 -0
  120. package/dist/shared/narrative-sort.js +47 -0
  121. package/dist/shared/narrative-status.js +52 -0
  122. package/dist/shared/no-pan.js +85 -0
  123. package/dist/shared/pane-layout.js +50 -0
  124. package/dist/shared/payload-inline.js +83 -0
  125. package/dist/shared/speaker-color.js +61 -0
  126. package/dist/shared/token-rotation.js +14 -0
  127. package/dist/shared/view-url.js +216 -0
  128. package/dist/shared/wiki-links.js +70 -0
  129. package/dist/shared/wiki-window.js +4 -0
  130. package/dist/tailscale.js +55 -0
  131. package/dist/test/absorb-claude.test.js +892 -0
  132. package/dist/test/agent-scope.test.js +193 -0
  133. package/dist/test/agents.test.js +55 -0
  134. package/dist/test/api-request.test.js +122 -0
  135. package/dist/test/app-host-literal.test.js +53 -0
  136. package/dist/test/awaiting-glow.test.js +54 -0
  137. package/dist/test/awaiting.test.js +122 -0
  138. package/dist/test/bind-token.test.js +88 -0
  139. package/dist/test/block-glyphs.test.js +68 -0
  140. package/dist/test/cert-manager.test.js +262 -0
  141. package/dist/test/claude-live-session.test.js +110 -0
  142. package/dist/test/codex-tool-log.test.js +568 -0
  143. package/dist/test/config.test.js +71 -0
  144. package/dist/test/copilot-tool-log.test.js +93 -0
  145. package/dist/test/cors-preflight.test.js +56 -0
  146. package/dist/test/cost-linger.test.js +31 -0
  147. package/dist/test/cost-pricing.test.js +72 -0
  148. package/dist/test/cost-reprice.test.js +139 -0
  149. package/dist/test/cost-sessions.test.js +301 -0
  150. package/dist/test/crush-tool-log.test.js +289 -0
  151. package/dist/test/daemon-client.test.js +109 -0
  152. package/dist/test/daemon-socket.test.js +293 -0
  153. package/dist/test/diagram-arrows.test.js +205 -0
  154. package/dist/test/diagram-export.test.js +210 -0
  155. package/dist/test/diagram-labels.test.js +313 -0
  156. package/dist/test/diagram-parse.test.js +191 -0
  157. package/dist/test/diagram-render.test.js +175 -0
  158. package/dist/test/diagram-review.test.js +288 -0
  159. package/dist/test/diagram-self-loop-labels.test.js +303 -0
  160. package/dist/test/embedder.test.js +84 -0
  161. package/dist/test/events.test.js +123 -0
  162. package/dist/test/export-selection.test.js +102 -0
  163. package/dist/test/export.test.js +505 -0
  164. package/dist/test/files-browse.test.js +393 -0
  165. package/dist/test/files-find.test.js +272 -0
  166. package/dist/test/find-in-text.test.js +86 -0
  167. package/dist/test/first-paint-viewport.test.js +59 -0
  168. package/dist/test/fixtures/embedding-golden.js +23 -0
  169. package/dist/test/fixtures/wordpiece-golden.js +167 -0
  170. package/dist/test/glow-hues.test.js +202 -0
  171. package/dist/test/harness-cost.test.js +423 -0
  172. package/dist/test/helpers.js +21 -0
  173. package/dist/test/hex-pages.test.js +68 -0
  174. package/dist/test/highlight.test.js +69 -0
  175. package/dist/test/hit-drum.test.js +71 -0
  176. package/dist/test/hook-config.test.js +299 -0
  177. package/dist/test/json-gzip.test.js +70 -0
  178. package/dist/test/key-routing.test.js +58 -0
  179. package/dist/test/known-nids.test.js +106 -0
  180. package/dist/test/link-preview.test.js +67 -0
  181. package/dist/test/list-scroll-keys.test.js +66 -0
  182. package/dist/test/listen-own-words.test.js +147 -0
  183. package/dist/test/listen-timeout.test.js +33 -0
  184. package/dist/test/markdown-diagnostics.test.js +121 -0
  185. package/dist/test/markdown-lists.test.js +182 -0
  186. package/dist/test/markdown-math.test.js +256 -0
  187. package/dist/test/markdown-nids.test.js +146 -0
  188. package/dist/test/markdown-protocols.test.js +139 -0
  189. package/dist/test/mcp-bridge-cancel.test.js +98 -0
  190. package/dist/test/mcp-bridge-reconnect.test.js +121 -0
  191. package/dist/test/mcp-narrative.test.js +193 -0
  192. package/dist/test/mcp.test.js +548 -0
  193. package/dist/test/meld.test.js +143 -0
  194. package/dist/test/membrane-invasion.test.js +482 -0
  195. package/dist/test/membrane-motion.test.js +101 -0
  196. package/dist/test/membrane-palette.test.js +166 -0
  197. package/dist/test/membrane-terrain.test.js +170 -0
  198. package/dist/test/memory-log.test.js +202 -0
  199. package/dist/test/mentions-e2e.test.js +261 -0
  200. package/dist/test/mentions-ledger.test.js +265 -0
  201. package/dist/test/mentions-listen.test.js +265 -0
  202. package/dist/test/mentions.test.js +238 -0
  203. package/dist/test/message-selection.test.js +114 -0
  204. package/dist/test/mo-glyph.test.js +22 -0
  205. package/dist/test/model-resolution.test.js +166 -0
  206. package/dist/test/narrate-validate.test.js +77 -0
  207. package/dist/test/narrate-wait.test.js +160 -0
  208. package/dist/test/narrative-format.test.js +219 -0
  209. package/dist/test/narrative-menu.test.js +150 -0
  210. package/dist/test/narrative-sort.test.js +75 -0
  211. package/dist/test/no-pan.test.js +60 -0
  212. package/dist/test/pane-layout.test.js +153 -0
  213. package/dist/test/paths.test.js +37 -0
  214. package/dist/test/payload-inline.test.js +91 -0
  215. package/dist/test/precache-fonts.test.js +72 -0
  216. package/dist/test/presence-gate.test.js +440 -0
  217. package/dist/test/presence.test.js +160 -0
  218. package/dist/test/read-events.test.js +220 -0
  219. package/dist/test/remote-meld.test.js +128 -0
  220. package/dist/test/revive-cli.test.js +93 -0
  221. package/dist/test/search-floor.test.js +206 -0
  222. package/dist/test/search-fusion.test.js +168 -0
  223. package/dist/test/search.test.js +205 -0
  224. package/dist/test/security.test.js +48 -0
  225. package/dist/test/selection-wiring.test.js +61 -0
  226. package/dist/test/session-affinity.test.js +295 -0
  227. package/dist/test/signal-source.test.js +32 -0
  228. package/dist/test/socket-account.test.js +268 -0
  229. package/dist/test/spawn-toml.test.js +72 -0
  230. package/dist/test/speaker-color.test.js +90 -0
  231. package/dist/test/tailscale-rebind.test.js +79 -0
  232. package/dist/test/terminal-cursor.test.js +61 -0
  233. package/dist/test/terminal-resync.test.js +23 -0
  234. package/dist/test/terminal-size.test.js +36 -0
  235. package/dist/test/thin-cli.test.js +382 -0
  236. package/dist/test/token-bootstrap.test.js +272 -0
  237. package/dist/test/token-devices.test.js +646 -0
  238. package/dist/test/token-lapse.test.js +94 -0
  239. package/dist/test/token-ring.test.js +188 -0
  240. package/dist/test/token-rotate-cli.test.js +58 -0
  241. package/dist/test/token-routes.test.js +95 -0
  242. package/dist/test/tool-uses.test.js +1006 -0
  243. package/dist/test/usage-ledger.test.js +126 -0
  244. package/dist/test/view-url.test.js +627 -0
  245. package/dist/test/wiki-links.test.js +57 -0
  246. package/dist/test/wiki-sources.test.js +85 -0
  247. package/dist/test/wiki-window.test.js +31 -0
  248. package/dist/test/wiki.test.js +399 -0
  249. package/dist/test/wordpiece.test.js +68 -0
  250. package/dist/test/wrangler-route.test.js +27 -0
  251. package/dist/tls.js +148 -0
  252. package/dist/tmux.js +213 -0
  253. package/dist/user-agent.js +46 -0
  254. package/docker-entrypoint.sh +154 -0
  255. package/docs/README.md +3 -0
  256. package/docs/absorb.md +231 -0
  257. package/docs/cost-ledger.md +125 -0
  258. package/docs/daemon-api.md +189 -0
  259. package/docs/diagrams.md +163 -0
  260. package/docs/doctor.md +36 -0
  261. package/docs/export-scope.md +69 -0
  262. package/docs/files-view.md +133 -0
  263. package/docs/link-previews.md +38 -0
  264. package/docs/math.md +32 -0
  265. package/docs/mcp.md +69 -0
  266. package/docs/memory-search.md +75 -0
  267. package/docs/mentions.md +101 -0
  268. package/docs/multi-brane.md +14 -0
  269. package/docs/passkeys.md +165 -0
  270. package/docs/presence.md +202 -0
  271. package/docs/releasing.md +104 -0
  272. package/docs/rendering-warnings.md +22 -0
  273. package/docs/request-layer.md +72 -0
  274. package/docs/selection-store.md +50 -0
  275. package/docs/session-affinity.md +61 -0
  276. package/docs/terminal-mirroring.md +243 -0
  277. package/docs/token-rotation.md +431 -0
  278. package/docs/view-urls.md +134 -0
  279. package/docs/web-app.md +23 -0
  280. package/docs/wiki.md +43 -0
  281. package/expo/dist/_expo/static/js/web/entry-e94247f119fdcd3b424a1764233a41d2.js +1099 -0
  282. package/expo/dist/apple-touch-icon.png +0 -0
  283. package/expo/dist/favicon.svg +3 -0
  284. package/expo/dist/index.html +177 -0
  285. package/expo/dist/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  286. package/expo/dist/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  287. package/expo/dist/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  288. package/expo/dist/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  289. package/expo/dist/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  290. package/expo/dist/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  291. package/expo/dist/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  292. package/expo/dist/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  293. package/expo/dist/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  294. package/expo/dist/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  295. package/expo/dist/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  296. package/expo/dist/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  297. package/expo/dist/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  298. package/expo/dist/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  299. package/expo/dist/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  300. package/expo/dist/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  301. package/expo/dist/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  302. package/expo/dist/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  303. package/expo/dist/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  304. package/expo/dist/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  305. package/expo/dist/katex/katex.min.css +1 -0
  306. package/expo/dist/manifest.json +16 -0
  307. package/expo/dist/metadata.json +1 -0
  308. package/expo/dist/og/membrane.v1.png +0 -0
  309. package/expo/dist/pdf.min.mjs +28 -0
  310. package/expo/dist/pdf.worker.min.mjs +28 -0
  311. package/expo/dist/sw.js +154 -0
  312. package/package.json +79 -27
  313. package/protocols/LIVE_loop.md +407 -0
  314. package/protocols/bebrief.md +41 -0
  315. package/protocols/digest.md +231 -0
  316. package/protocols/fly.md +266 -0
  317. package/protocols/idle.md +81 -0
  318. package/protocols/keeper.md +829 -0
  319. package/protocols/markdown.md +80 -0
  320. package/protocols/memory.md +419 -0
  321. package/protocols/mentions.md +93 -0
  322. package/protocols/payloads.md +53 -0
  323. package/protocols/prelude.md +91 -0
  324. package/protocols/ramify.md +105 -0
  325. package/protocols/review.md +356 -0
  326. package/protocols/rrr.md +232 -0
  327. package/protocols/scribe.md +429 -0
  328. package/protocols/summarize.md +203 -0
  329. package/protocols/twin.md +174 -0
  330. package/protocols/wiki.md +438 -0
  331. package/protocols/worker.md +38 -0
  332. package/wiki/shared/append-only-event-log.md +148 -0
  333. package/wiki/shared/index.md +53 -0
  334. package/wiki/shared/owning-your-narratives.md +161 -0
  335. package/wiki/shared/premature-ontologies.md +435 -0
  336. package/wiki/shared/sedimentary-superintelligence.md +128 -0
  337. package/wiki/shared/sequestering-the-narrative.md +143 -0
  338. package/wiki/shared/why-wikis-work.md +216 -0
  339. package/.travis.yml +0 -7
  340. package/lib/brane.cjs.js +0 -12
  341. package/lib/brane.cjs.js.map +0 -1
  342. package/lib/brane.d.ts +0 -11
  343. package/lib/brane.js +0 -6
  344. package/lib/brane.js.map +0 -1
  345. package/lib/tests.d.ts +0 -1
  346. package/lib/tests.js +0 -8
  347. package/lib/tests.js.map +0 -1
  348. package/rollup.config.js +0 -21
  349. package/scripts/test.sh +0 -8
  350. package/src/brane.ts +0 -21
  351. package/src/tests.ts +0 -8
  352. package/tsconfig.json +0 -16
package/AGENTS.md ADDED
@@ -0,0 +1,367 @@
1
+ # Brane — Agent Development Guide
2
+
3
+ This file is loaded into every agent session in this fold, so it stays an
4
+ **index**: the rules that apply to every change, how to build, and a map of
5
+ where everything else is written down. The design write-ups for each
6
+ subsystem live in [`docs/`](docs/); read the one for the area you are about
7
+ to touch (see [Further Reading](#further-reading)) before changing it.
8
+
9
+ **Keep it that way.** A new subsystem's design notes go in a new or existing
10
+ `docs/<topic>.md`, and this file gets one line in [Further
11
+ Reading](#further-reading) pointing at it. A rule belongs here only if it
12
+ applies to changes everywhere in the repo.
13
+
14
+ ## What Is This?
15
+
16
+ Brane is a TypeScript reimagining of the [organelle](https://github.com/benjamn/organelle) system. It provides:
17
+
18
+ - A CLI (`npx brane` or `node dist/cli.js`) built with **citty**
19
+ - A background **daemon** (HTTP + WebSocket) with SQLite persistence
20
+ - An **Expo web app** for mobile control over Tailscale
21
+ - An **MCP server** (stdio↔WebSocket bridge) injected into agent sessions
22
+ - **Terminal mirroring** of tmux sessions with keyboard input
23
+ - The **LIVE loop** protocol for cursor-based agent communication
24
+ - A **semantic memory** system with embeddings and full-text search
25
+ - **Multi-agent support** across 8 agent types, with session resumption where the agent offers it
26
+
27
+ ## Golden Rule
28
+
29
+ **Never delete files, directories, database records, git branches, or any other artifacts without explicit operator approval.** If your task seems to require deletion, stop and ask the operator first. Prefer renaming, archiving, or commenting out over deletion. The cost of keeping something is low; the cost of losing it can be catastrophic.
30
+
31
+ ## Commits, Sign-off, and Accountability
32
+
33
+ `CONTRIBUTING.md` is the policy; this is what it asks of an agent.
34
+
35
+ - **Never add `Signed-off-by:`**, on your own behalf or the operator's. Only a human can certify the Developer Certificate of Origin, and a sign-off written by an agent is a false certification. Responsibility for a change attaches to the human who submits or merges it.
36
+ - **Keep the disclosure trailer.** Commits you write carry `Co-Authored-By: <agent> <model> <noreply@anthropic.com>` (Claude Code adds it). Never strip, rewrite, or backdate one, yours or another agent's.
37
+ - **Never merge, and never approve a PR.** `main` is PR-only; open the PR, report CI, and stop. The human who merges is the one taking responsibility for the change.
38
+ - **Never run `npm publish`** — see [Releasing](docs/releasing.md).
39
+
40
+ ## Repository Layout
41
+
42
+ ```
43
+ brane/
44
+ ├── src/
45
+ │ ├── cli.ts # CLI entry (citty)
46
+ │ ├── agents.ts # Agent adapter interface (claude, goose, gemini, codex, amp, copilot)
47
+ │ ├── commands/ # Subcommands (see CLI Commands below)
48
+ │ ├── daemon/server.ts # HTTP/WS server, terminal streaming, MCP bridge
49
+ │ ├── daemon/client.ts # CLI-side daemon client (find-or-start, JSON API calls)
50
+ │ ├── db/schema.ts # SQLite schema, helpers (better-sqlite3)
51
+ │ ├── db/events.ts # Event append-log operations
52
+ │ ├── memory/ # Semantic search system
53
+ │ │ ├── embeddings.ts # Worker-thread façade over the embedder
54
+ │ │ ├── embedder.ts # ONNX session + mean pool + normalize (onnxruntime-node)
55
+ │ │ ├── wordpiece.ts # BERT WordPiece tokenizer, parity-pinned to transformers.js
56
+ │ │ ├── index.ts # Search orchestration (hybrid vector + FTS5)
57
+ │ │ └── storage.ts # Chunk storage and indexing state
58
+ │ ├── files/ # GET /api/files: browse.ts (the route), zip.ts, tar.ts, archive.ts, bytes.ts
59
+ │ ├── markdown-diagnostics.ts # Rendering warnings returned by narrate
60
+ │ ├── mcp/server.ts # Thin stdio↔WebSocket MCP bridge
61
+ │ └── test/ # Node test suite
62
+ ├── expo/ # React Native web app
63
+ │ ├── app/[nid].tsx # Narrative detail (chat + terminal tabs)
64
+ │ ├── app/_layout.tsx # Root layout, WebSocket control channel
65
+ │ ├── app/index.tsx # Narrative list
66
+ │ ├── components/ # MacroMenu, TerminalPane, TerminalKeyboard
67
+ │ ├── lib/ # api.ts, terminal.ts, connection.ts, registry.ts
68
+ │ └── dist/ # Built web bundle (served by daemon)
69
+ ├── worker/ # Cloudflare Workers deployment (serves the latest release's expo/dist as SPA)
70
+ ├── protocols/
71
+ │ ├── LIVE_loop.md # Core agent communication protocol
72
+ │ ├── digest.md # /digest protocol for activity summaries
73
+ │ └── memory.md # Semantic search protocol
74
+ ├── docs/ # Per-subsystem design notes (see Further Reading)
75
+ ├── dist/ # Compiled TypeScript output
76
+ ├── SECURITY.md # Security model documentation
77
+ ├── DESIGN.md # Architecture documentation
78
+ ├── tsconfig.json # ES2022, NodeNext, strict
79
+ └── package.json # Node 20+, ESM
80
+ ```
81
+
82
+ ## Building
83
+
84
+ ```bash
85
+ # Compile TypeScript (server + CLI)
86
+ npx tsc
87
+
88
+ # Build Expo web bundle
89
+ cd expo && npx expo export --platform web
90
+
91
+ # Run tests
92
+ npx tsc && node --test dist/test/*.test.js
93
+ ```
94
+
95
+ Output goes to `dist/` (server) and `expo/dist/` (web app).
96
+
97
+ `build` and `build:server` sweep `dist/` first (`scripts/clean-dist.mjs`, via
98
+ `prebuild` hooks): `tsc` only ever adds files, so without the sweep a checkout
99
+ accumulates outputs whose source is gone and `npm pack` ships them. Because
100
+ the sweep makes tsc create `dist/cli.js` fresh (mode 0644), `postbuild` hooks
101
+ run `scripts/chmod-bin.mjs` to put the execute bit back on every `bin` target;
102
+ without it an `npm link`ed `brane` vanishes from the shell (`which` skips
103
+ non-executable files) while `node dist/cli.js` keeps working.
104
+
105
+ ### When to rebuild
106
+
107
+ - **Server-side TypeScript changes** (`src/`): `npx tsc` then `brane daemon restart`
108
+ - **Expo app changes** (`expo/`): **`npm run build`** (not just `npx tsc`) then `brane daemon restart`
109
+ - **Protocol/markdown changes** (`protocols/`): **No rebuild needed.** The daemon reads protocol files from disk at runtime via `readFileSync`.
110
+ - **Both server + expo**: `npm run build` (runs tsc + expo export)
111
+
112
+ ### Releasing
113
+
114
+ Publishing to npm is done by `.github/workflows/release.yml`, triggered by a
115
+ published GitHub release, and only by it. **Agents never run `npm publish`.**
116
+ The shared web app ships with it: a release deploys its tarball's
117
+ `expo/dist`, and a merge to `main` deploys nothing (staging is Isolate on a
118
+ daemon running `main`). The version bump, tag rule, dist-tag choice, app
119
+ deploy and rollback, and why 0.3.0 has no provenance attestation are in
120
+ [docs/releasing.md](docs/releasing.md).
121
+
122
+ ## CLI Commands
123
+
124
+ | Command | Purpose |
125
+ |---------|---------|
126
+ | `daemon` | Manage daemon lifecycle (start, stop, restart, status, logs) |
127
+ | `spawn` | Spawn new agent sessions (`--attach`, `--model`, `--role`, `-- <args>`) |
128
+ | `attach` | Attach to a tmux session |
129
+ | `list` | List narratives grouped by brane (`--brane`, `--archived`, `--limit`) — reads `GET /api/narratives` + `GET /api/branes` |
130
+ | `fold` | Register directories as spawn points (`--brane` to associate with a brane) — delegates to `POST /api/folds` |
131
+ | `meld` | Generate QR code for mobile access (points at the `app_domain` config, `brane.organelle.dev` unless set; `--app <host>` for one QR, `--local` for a direct daemon URL); waits for Touch ID at this machine — see [Presence Check](docs/presence.md#the-gate). `--remote --send … --ask …` melds a daemon on another machine (a Fly machine: /fly) with a token minted here, and refuses in an agent's session |
132
+ | `mcp` | MCP stdio server (used internally by agent sessions) |
133
+ | `revive` | Restart dead agent sessions (`--prompt`, `--no-prompt`, `--agent`) — delegates to `POST /api/revive/:nid` |
134
+ | `config` | Get/set brane configuration (git-config style: `--list`, `--unset`) |
135
+ | `certify` | Force-refresh TLS certificates (daemon auto-provisions and renews on its own; this is a manual escape hatch) |
136
+ | `absorb` | Import conversation history: from provider exports (`chatgpt`, `organelle`) or from agent session stores on this machine (`claude`); `survey` lists what the machine has (`--fold`, `--brane`, `--identity`, `--dry-run`, `--since`, `--session`, `--rebuild`) — delegates to `GET /api/absorb/survey` and `POST /api/absorb`, printing its progress stream |
137
+ | `memory` | Semantic search and indexing (`search`, `log`, `index` subcommands) — clients of `POST /api/search`, `GET /api/narratives/recent`, `POST /api/memory/index`. `log --archived` to include absorbed history, which is archived by construction |
138
+ | `cost` | Cost ledger maintenance (`backfill [--dry-run] [--all]`, `reprice [--dry-run] [--all]`) — delegates to `POST /api/cost/backfill` and `POST /api/cost/reprice` |
139
+ | `token` | Daemon bearer tokens (`list`: the Devices list; `revoke <id> [--cascade]`: sign out one device, and with `--cascade` the devices it added; `rotate`: sign out every web client, keep this shell; revoking a device and rotating wait for Touch ID, see [Presence Check](docs/presence.md#the-gate)) — delegates to `GET /api/tokens`, `POST /api/tokens/:id/revoke` and `POST /api/token/rotate`; from the shell, which holds no token, rotate is one request — see [Token Rotation](docs/token-rotation.md) |
140
+ | `doctor` | Check the install: Node vs `engines`, `tmux`, Tailscale, daemon status, which checkout it runs from and whether this shell can reach it over `daemon.sock`, a leftover `.daemon_token`, then the shipped test suite (`dist/test`) against this install — see [Doctor](docs/doctor.md) |
141
+
142
+ ## Database
143
+
144
+ Single SQLite database at `~/.brane/brane.db` (WAL mode). Key tables:
145
+
146
+ | Table | Purpose |
147
+ |-------|---------|
148
+ | `meta` | Instance ID, daemon port/pid/version/tls/http_port/socket, config |
149
+ | `tokens` | Daemon bearer tokens as SHA-256 hashes only (`local`: one row for this machine's CLI, which no token opens; `device` per meld, `agent` per narrative session, handed to it as `BRANE_NARRATIVE_SECRET`), revoked never deleted — see [Token Rotation](docs/token-rotation.md) |
150
+ | `folds` | Registered spawn directories (path, brane_id, created_at) |
151
+ | `narratives` | Agent sessions (id, brane_id, agent_type, role, status, fold_path, title, summary, archived, agent_session_id) |
152
+ | `events` | Append-only event log: (narrative_id, seq, time, type, content, content_type, source, re, payloads, meta) |
153
+ | `memory_chunks` | Event chunks for embeddings |
154
+ | `memory_vec` | Vector embeddings for semantic search (sqlite-vec) |
155
+ | `memory_fts` | FTS5 full-text search table |
156
+ | `memory_cursors` | Per-narrative indexing cursors |
157
+ | `memory_stats` | Indexing statistics |
158
+ | `usage_ledger` | Durable per-message / per-session cost rows — see [Cost Ledger](docs/cost-ledger.md) |
159
+ | `absorb_messages` | (brane, provider, message id) → (narrative, seq): the per-message dedup that makes re-absorbing a session store idempotent — see [Absorb](docs/absorb.md) |
160
+ | `absorb_files` | (brane, provider, session) → (size, mtime) at its last absorb, so an unchanged file is skipped on a stat |
161
+
162
+ Event types: `narration` (agent), `human_signal` (operator), `agent_signal` (cross-agent).
163
+
164
+ ## Agent Adapters
165
+
166
+ Brane supports multiple agent types with session resumption. Each agent has an adapter in `src/agents.ts`:
167
+
168
+ | Agent | Resume Method | Notes |
169
+ |-------|--------------|-------|
170
+ | `claude` | `--resume <session_id>` | Discovers session from `~/.claude/projects/` |
171
+ | `goose` | `-r` | Resumes by session name |
172
+ | `gemini` | (none) | Uses `-i` for prompt injection |
173
+ | `codex` | `resume <session_id>` | Subcommand-based resumption |
174
+ | `amp` | (none) | Uses thread references `@T-<id>` in prompt |
175
+ | `copilot` | `--session-id <session_id>` | Daemon-pinned UUID resumes the exact local session |
176
+ | `cline` | (none) | Each revive starts a fresh session; brane captures its id for cost |
177
+ | `crush` | (none) | Each revive starts a fresh session; brane captures its id for cost |
178
+
179
+ Spawning a session generates agent-specific MCP config. This happens in `doSpawn()`, which always runs in the daemon — `brane spawn` gets it by delegating to `POST /api/spawn`, not by writing these files itself:
180
+ - **Claude**: `.mcp.json` in fold directory
181
+ - **Goose**: `--with-extension` argument with env passthrough
182
+ - **Gemini**: `.gemini/settings.json` project-level config
183
+ - **Codex**: `~/.codex/config.toml` with env references
184
+ - **Copilot**: Per-session `.brane-copilot-mcp-<nid>.json`
185
+
186
+ ## Security Model
187
+
188
+ See `SECURITY.md` for full details. Key features:
189
+
190
+ - **TCP-level IP filtering** — only allows localhost, Tailscale IPs, RFC 1918 private ranges, and CGNAT
191
+ - **TLS auto-provisioning + renewal** — daemon shells out to `tailscale cert` at startup if no valid cert exists, renews when <30d remain, hot-reloads via `setSecureContext` on file change; when TLS is active, an HTTP fallback server (private IPs only) runs on a separate port for local/LAN access. `brane certify` remains as a manual escape hatch.
192
+ - **Atomic daemon startup** — `BEGIN EXCLUSIVE` SQLite transaction prevents race conditions
193
+ - **Version checking** — daemon stores version for CLI compatibility detection
194
+ - **Payload security** — path traversal protection, 50MB size limits, immutable cached URLs
195
+ - **The token is the only credential** — no origin allowlist: CORS answers `*` without credentials, the WebSocket upgrade checks the token and nothing else, and the `Origin` a device runs the app from is recorded on its token for the Devices list (`SECURITY.md`, Authentication)
196
+
197
+ ## Rules for Every Change
198
+
199
+ The full reasoning for each is in the linked doc; these are the parts that
200
+ bite outside their own subsystem.
201
+
202
+ - **The CLI is a daemon client.** A command that touches narratives, folds,
203
+ sessions, or the memory index calls a daemon route (adding one if needed)
204
+ and keeps only terminal-shaped work for itself. It never opens the database
205
+ itself. Every client calls `warnIfVersionMismatch()` first. See [The CLI is
206
+ a daemon client](docs/daemon-api.md#the-cli-is-a-daemon-client).
207
+ - **A new daemon route is closed to agents** until it is listed in
208
+ `AGENT_ROUTES` (`src/daemon/agent-scope.ts`). If agents' CLI or bridge
209
+ needs it, add it there; operator acts stay off the list. See [Agent
210
+ tokens](docs/token-rotation.md#agent-tokens).
211
+ - **No test opens the operator's database.** `openDatabase()` throws under
212
+ `node --test`; code the suite drives takes a `db`, and tests build one with
213
+ `createTestDb()`. A test that reads *source* (not `dist/`) must `skip` when
214
+ the source is absent, or `brane doctor` goes red on every install. See
215
+ [Doctor](docs/doctor.md).
216
+ - **MCP tool errors use `sendToolError()`**, not `sendToolResult({ error })`;
217
+ the bridge maps it to `isError: true`. Tool logic lives in the daemon, never
218
+ in the bridge. See [MCP Architecture](docs/mcp.md).
219
+ - **Bodiless app requests send no headers.** The token rides in `?token=`, so
220
+ a GET needs no CORS preflight; `src/test/api-request.test.ts` enforces it.
221
+ Breaking this is invisible on a fast network. See [The Request
222
+ Layer](docs/request-layer.md).
223
+ - **A `src/shared/` module with a bare npm import needs a metro alias** in
224
+ `expo/metro.config.js`, as `katex` has. See [Math Rendering](docs/math.md).
225
+ - **One parse, never a second scanner.** Warnings, mentions and diagram
226
+ diagnostics reuse the renderer's own parse; a parallel regex eventually
227
+ disagrees with what the operator sees. Regexes on the `narrate` path must
228
+ be linear-time. See [Rendering Warnings](docs/rendering-warnings.md),
229
+ [Mentions](docs/mentions.md), [Diagrams](docs/diagrams.md).
230
+
231
+ - **Every conversational append goes through `announceEvent()`**, which
232
+ records mentions and *then* wakes listeners. A new append site in
233
+ `server.ts` that open-codes the two in the other order leaves a mention
234
+ delivered and never settled. See [Mentions](docs/mentions.md).
235
+ - **`expo/public/index.html` is the HTML template that ships**; keep
236
+ `expo/app/+html.tsx` in step with it, but a `<head>` change made only there
237
+ never reaches a browser. See [Math Rendering](docs/math.md) and [Link
238
+ Previews](docs/link-previews.md).
239
+
240
+ ## Further Reading
241
+
242
+ Relative links into [`docs/`](docs/). Each is the full write-up for its area,
243
+ including the "less obvious than it looks" decisions and the tests that pin
244
+ them. The paths in parentheses are the code each one goes with: about to
245
+ change one of those, read its doc first.
246
+
247
+ **Daemon and CLI**
248
+
249
+ - [Daemon](docs/daemon-api.md) (`src/daemon/server.ts` routes,
250
+ `src/daemon/client.ts`, `src/commands/`): every HTTP and WebSocket endpoint;
251
+ the Spawn, Revive, Run and Folds APIs; why the CLI is a daemon client; who
252
+ may register which folds.
253
+ - [MCP and the LIVE Loop](docs/mcp.md) (`src/mcp/`, `src/daemon/awaiting.ts`,
254
+ MCP handlers in `server.ts`): the stdio↔WebSocket bridge, listen wakeup and
255
+ cancellation, `narrate({ wait: true })`, the LIVE loop tools, narrative
256
+ metadata.
257
+ - [Token Rotation](docs/token-rotation.md) (`src/daemon/token-ring.ts`,
258
+ `src/db/tokens.ts`, `src/daemon/token-routes.ts`, `src/commands/token.ts`):
259
+ tokens stored as hashes only, a token per melded device and per agent session, the Devices list
260
+ and per-device revoke, `brane token rotate`, why the swap happens on first
261
+ use of the new token, and why this machine holds no token (`.daemon_token`
262
+ is retired).
263
+ - [Passkeys](docs/passkeys.md) (not built yet; `src/presence.ts`,
264
+ `src/db/tokens.ts`): the design, the spike and real-device results, what
265
+ the browser and daemon sides must do, open questions, build order.
266
+ - [Presence Check](docs/presence.md) (`src/presence.ts`,
267
+ `src/daemon/presence-gate.ts`): confirming the operator is at
268
+ the machine with the OS's own prompt (macOS, Windows Hello from Windows or
269
+ WSL, polkit); the gate it puts on meld, a device's sign-out and rotation
270
+ from the shell, and why agents are refused them.
271
+ - [Session Affinity](docs/session-affinity.md) (`src/session-affinity.ts`):
272
+ the `X-Session-Affinity` header for claude sessions on Fireworks.
273
+ - [Doctor](docs/doctor.md) (`src/commands/doctor.ts`, `src/test/`): `brane
274
+ doctor`, and the shipped-test-suite rules.
275
+ - [Releasing](docs/releasing.md) (`.github/workflows/release.yml`,
276
+ `package.json` version): the npm release workflow.
277
+
278
+ **Data**
279
+
280
+ - [Multi-Brane](docs/multi-brane.md) (`brane_id` resolution, `src/folds.ts`):
281
+ home and foreign branes, brane_id resolution.
282
+ - [Absorb](docs/absorb.md) (`src/absorb/`): importing history (ChatGPT,
283
+ organelle, local Claude Code stores), per-message idempotence, `--rebuild`.
284
+ - [Memory and Search Ranking](docs/memory-search.md) (`src/memory/`):
285
+ embeddings, FTS5, and why hybrid search fuses ranks rather than scores.
286
+ - [Cost Ledger](docs/cost-ledger.md) (`src/cost/`, `usage_ledger`, adapters'
287
+ usage readers): `usage_ledger`, credit assignment across forks, backfill,
288
+ re-pricing.
289
+ - [Mentions](docs/mentions.md) (`src/mentions-scan.ts`, `src/db/mentions.ts`,
290
+ `src/shared/markdown-mentions.ts`): `@nid` addressing, the mentions ledger,
291
+ and the record-before-wake ordering.
292
+
293
+ **Web app**
294
+
295
+ - [Web App (Expo)](docs/web-app.md) (`expo/`): what the app offers, view by
296
+ view.
297
+ - [Terminal Mirroring](docs/terminal-mirroring.md)
298
+ (`expo/components/TerminalPane.tsx`, the capture loop in `server.ts`):
299
+ capture-pane mirroring, the resync heartbeat, the stranded rAF, the cursor,
300
+ paste and copy, block glyphs.
301
+ - [Files View](docs/files-view.md) (`src/files/`, `expo/lib/hexDoc.ts`,
302
+ `expo/lib/hexFind.ts`): `GET /api/files`, every format the Files view shows
303
+ (archives as folders, hex as the floor), searching the bytes.
304
+ - [The Request Layer](docs/request-layer.md) (`expo/lib/api.ts`,
305
+ `src/shared/api-request.ts`): CORS preflights, timeouts and retries at
306
+ satellite RTT.
307
+ - [View URLs](docs/view-urls.md) (`src/shared/view-url.ts`,
308
+ `expo/app/_layout.tsx`): what the query string and fragment carry, Isolate
309
+ and Meld links.
310
+ - [The Selection Store](docs/selection-store.md)
311
+ (`src/shared/message-selection.ts`, `expo/lib/selection.ts`): the chat's
312
+ message selection outside React state.
313
+ - [Export Scope](docs/export-scope.md) (`src/export.ts`,
314
+ `src/shared/export-selection.ts`): exporting a selection or its complement,
315
+ and what an excerpt discloses.
316
+ - [Link Previews](docs/link-previews.md) (`expo/public/index.html`,
317
+ `expo/scripts/og-membrane/`): the `og:*` card and its image.
318
+
319
+ **Markdown rendering**
320
+
321
+ - [Diagram Rendering](docs/diagrams.md) (`src/diagram/`): mermaid fences drawn
322
+ on the daemon, the dialect census, labels, self-loops.
323
+ - [Math Rendering](docs/math.md) (`src/shared/markdown-math.ts`,
324
+ `src/math.ts`): KaTeX in the app and the export, every delimiter a model
325
+ writes.
326
+ - [Rendering Warnings](docs/rendering-warnings.md)
327
+ (`src/markdown-diagnostics.ts`): what `narrate`'s `warnings` report and
328
+ `strict: true`.
329
+ - [Wiki: Local and Shared](docs/wiki.md) (`src/memory/wiki.ts`,
330
+ `src/shared/wiki-links.ts`): `wiki/` vs `wiki/shared/`, who sees what, the
331
+ install fold.
332
+
333
+ Also: `DESIGN.md` (original architecture), `SECURITY.md` (security model),
334
+ `CONTRIBUTING.md` (contribution policy), and `protocols/` (agent protocols,
335
+ read at runtime).
336
+
337
+ ## Key Patterns
338
+
339
+ - **Port stability**: daemon restart captures port before SIGTERM, reuses it
340
+ - **Scroll preservation**: chat/terminal tabs use absolute positioning with zIndex stacking
341
+ - **Terminal resize**: ResizeObserver measures monospace character dimensions, sends cols/rows to tmux
342
+ - **Multitouch keyboard**: refs for synchronous state, React state for visual rendering only
343
+ - **Event cursor**: monotonic `seq` per narrative, `after`/`before`/`tail` parameters on narrate/listen (supports multi-narrative object format)
344
+ - **Hashed tokens, and none for this machine**: the database holds only token hashes; devices get one minted per meld, agents one per session, and `--token` is adopted as a device token. The shell's CLI and MCP bridges hold no token: they present nothing over `daemon.sock`, the only way in for them, and nothing reads or writes `.daemon_token` — see [No local token](docs/token-rotation.md#no-local-token)
345
+ - **Atomic daemon claim**: SQLite `BEGIN EXCLUSIVE` transaction ensures singleton daemon
346
+ - **IP filtering**: TCP-level socket filtering before HTTP processing
347
+ - **Version tracking**: daemon and CLI version compatibility checks
348
+ - **Metadata broadcasts**: control WebSocket pushes summary/status changes in real-time
349
+ - **Portable paths**: stored as `~/relative` format, converted via `toPortablePath()`/`fromPortablePath()`
350
+ - **The mirror sends text; everything else is explicit**: the pane's cursor is the only thing about a terminal that isn't in its text, so it rides the same tmux round trip as the capture — and gets its own message when it moves and the text doesn't
351
+ - **The chat never scrolls itself**: after landing, only the operator moves the chat. It is a `column-reverse` scroller (`CHAT_SCROLLER_STYLE`, `expo/app/[nid].tsx`), not a virtualized `FlatList`, so scroll position is measured from the bottom: it opens on the latest message without a scroll, an arrival is followed only when the view is already exactly at the bottom, a page of older history lands at the far end and moves nothing, and no row is ever swapped for an estimated spacer mid-scroll. The one scroll the code writes is landing on `?scrollToSeq=` / `?scrollTo=`, plus the ↑/↓ tab button the operator taps. Sending doesn't scroll, and vertical scroll is never disabled, not even under a horizontal pane swipe. Measured in Chromium and WebKit against a sandbox daemon: the message under the viewport moves 0 px on arrival, on send and on each page loaded
352
+ - **A tap should cost what it changed**: the chat's selection lives in a store with per-seq subscriptions, so selecting a message wakes that bubble, the header's count and the composer — not the screen, not `renderItem`, not the other two hundred rows; the same store is what makes two taps in one frame both land
353
+ - **The URL carries the view**: anything that must survive an origin hop (Isolate) or a device hop (Meld) goes in the query string, built through `src/shared/view-url.ts` — `sessionStorage` is origin-scoped and does not travel. The app names no host: "isolated" is `location.host` equal to the connection's host, and the way out is the daemon's `app_domain` from `/api/status`; `src/test/app-host-literal.test.ts` keeps it that way
354
+ - **Back undoes a jump, never a view change**: a different narrative or any `nid:seq` link (even into the narrative you're reading) is a `router.push`; a tab, pin, file or selection change is `router.setParams`, which replaces. Screens behind the top stay mounted, so Back restores them whole, and narrative subscriptions are refcounted because two of them can watch the same narrative — see [View URLs](docs/view-urls.md)
355
+ - **`shared/` is the publication unit**: a fold's `wiki/shared/` is what other folds — and the npm tarball — can see; everything directly under `wiki/` is fold-local, and the install directory is just another fold
356
+ - **One renderer, two targets**: markdown features that must survive export (code highlighting, math) render server-side or through shared code, never through a script the exported file carries
357
+ - **Fail quietly for the reader, loudly for the writer**: renderers fall back rather than show errors; the same decisions are collected and returned to whoever wrote the markdown, as `narrate` warnings — advisory, unless that call asked for `strict`
358
+ - **Ask once, not twice**: a cross-origin request that carries no custom headers needs no CORS preflight, so bodiless API calls authenticate through `?token=` and send none — the extra round trip is invisible on a LAN and fatal at satellite RTT
359
+ - **Stale PID cleanup**: daemon info queries verify PID liveness, clean up dead entries
360
+ - **A blind start is not a verdict**: Tailscale detection at startup is one `tailscale status` with a 3 s timeout, and the extension can be wedged at exactly that moment (it hung for 11 hours on 2026-08-30 while the menu bar said "Connected"). The daemon therefore keeps re-probing — 5 s doubling to a 60 s cap while blind, 60 s steady once seen — and binds HTTPS + HTTP-fallback listeners on tailnet addresses as they appear (`src/daemon/tailscale-rebind.ts` holds the policy, `src/test/tailscale-rebind.test.ts` pins it). `GET /api/status` reports `listening_on`; empty means "this machine only". `--bind` opts out
361
+
362
+ ## Important Warnings
363
+
364
+ - **Never restart the organelle Nucleus daemon** — it maintains WebSocket connections to mobile devices
365
+ - The brane daemon is separate and safe to restart
366
+ - Database has no back-compat concerns yet — schema can change freely
367
+ - `~/.brane/` directory should be portable (paths stored as ~/relative)
package/CHANGELOG.md ADDED
@@ -0,0 +1,66 @@
1
+ # Changelog
2
+
3
+ Notable changes to brane, by published version. Each version's full notes
4
+ are on the [GitHub releases](https://github.com/benjamn/brane/releases)
5
+ page, which is also what triggers its publish (see
6
+ [docs/releasing.md](docs/releasing.md)). This file is the summary that
7
+ travels in the npm tarball.
8
+
9
+ ## 0.3.1 - 2026-10-12
10
+
11
+ - The shared web app ships with the release. It serves the `latest`
12
+ release's own `expo/dist`, and a merge to `main` deploys nothing; a
13
+ daemon running `main` serves its own newer bundle, through Isolate
14
+ ([#600](https://github.com/benjamn/brane/pull/600)).
15
+ - The app knows no host. `brane meld` and `brane spawn --meld` point
16
+ their QR at the `app_domain` config (`--app` / `--meld-app` for one
17
+ QR), `GET /api/status` reports it, and Isolate and the in-app Meld
18
+ work from whichever host serves the app
19
+ ([#598](https://github.com/benjamn/brane/pull/598),
20
+ [#599](https://github.com/benjamn/brane/pull/599)).
21
+ - The token is the only credential. The daemon no longer checks an
22
+ origin allowlist: CORS answers `*` without credentials. The origin
23
+ each device runs the app from is recorded and shown in the Devices
24
+ list and `brane token list`
25
+ ([#593](https://github.com/benjamn/brane/pull/593),
26
+ [#595](https://github.com/benjamn/brane/pull/595)).
27
+ - The spawn dialog's "Other…" agent runs any command on the daemon's
28
+ `PATH`, as `brane spawn <agent>` does, and spawn errors show in the
29
+ dialog ([#596](https://github.com/benjamn/brane/pull/596)).
30
+ - New terminals start at the viewer's size, so launch redraws no longer
31
+ pile up in scrollback, and the 🦾 menu gains "Clear 🧽" to clear a
32
+ pane's scrollback ([#574](https://github.com/benjamn/brane/pull/574)).
33
+ - On a Fly machine the daemon keeps its ports across boots, and a revive
34
+ repoints the fold's hook config at the running daemon
35
+ ([#594](https://github.com/benjamn/brane/pull/594)).
36
+ - Vulnerabilities are reported through GitHub's private vulnerability
37
+ reporting (see `SECURITY.md`). This is the first release published
38
+ from the public repository, so it carries npm provenance; 0.3.0 has
39
+ none ([#597](https://github.com/benjamn/brane/pull/597)).
40
+
41
+ ## 0.3.0 - 2026-10-11
42
+
43
+ The first release of this codebase. What ships:
44
+
45
+ - The `brane` CLI and userspace daemon: register directories as folds,
46
+ spawn agents in them (Claude Code, Codex, Gemini, Goose, Amp, Copilot,
47
+ Cline, Crush, or any command) under tmux, and keep every session's
48
+ narrative in one SQLite database, every message with a stable `nid:seq`
49
+ address.
50
+ - The LIVE loop: an MCP server injected into each agent session
51
+ (`narrate`, `listen`, `whoami`, wiki and memory search), and the
52
+ protocols agents read at runtime, in `protocols/`.
53
+ - The web app the daemon serves to any browser on your tailnet: chat,
54
+ terminal mirroring, files, export, markdown with math and diagrams, and
55
+ meld by QR code. Per-device and per-agent tokens, a presence prompt for
56
+ new devices, and `brane token rotate`.
57
+ - Memory: local embeddings on `onnxruntime-node` fused with FTS5, across
58
+ narratives and absorbed history (ChatGPT, organelle, local Claude Code
59
+ stores).
60
+ - `brane doctor`, which runs the shipped test suite against the install.
61
+ - Node 20 or newer. AGPL-3.0-or-later.
62
+
63
+ ## 0.1.1
64
+
65
+ An unrelated earlier package that held the name on npm (2020). Not an
66
+ ancestor of this code.
@@ -0,0 +1,101 @@
1
+ # Contributing to brane
2
+
3
+ Brane is a single-maintainer project developed with coding agents. Most
4
+ commits on `main` were written by an agent under the operator's direction,
5
+ and every one of them was reviewed, authored, committed, and merged by a
6
+ human. This document says what that means for anyone touching the
7
+ repository, human or agent.
8
+
9
+ ## Issues and pull requests
10
+
11
+ Brane is not a product, and its maintainer makes no support promise.
12
+ Issues are open: bug reports and ideas are welcome there, and may or may
13
+ not get an answer. Pull requests are limited to the maintainer; if you
14
+ have a fix, describe it in an issue. Vulnerabilities go through private
15
+ reporting instead, as `SECURITY.md` describes.
16
+
17
+ ## How changes land
18
+
19
+ - `main` takes pull requests only. The `protect-main-branch` ruleset
20
+ (2026-09-02) requires a PR, forbids force-pushes and deletions, and has
21
+ no bypass actors.
22
+ - Work happens on a branch, usually in a worktree, and arrives as a PR
23
+ with CI green.
24
+ - A human merges. Agents open PRs; they do not approve or merge them, not
25
+ even their own.
26
+
27
+ ## Working from a clone
28
+
29
+ ```sh
30
+ npm install
31
+ npm link # once: `brane` now resolves to this checkout
32
+ npm run build # Compile TypeScript + build the Expo web bundle
33
+ ```
34
+
35
+ `npm link` points your global `brane` at `<repo>/dist/cli.js`, so every
36
+ later `npm run build` is picked up without reinstalling; after a
37
+ server-side change, `brane daemon restart` puts the daemon on it. To go
38
+ back to a published release, `npm unlink -g brane` and then
39
+ `npm install -g brane`.
40
+
41
+ ## Disclosure: say when an agent helped
42
+
43
+ Every commit an agent wrote or substantially shaped carries a trailer naming
44
+ the agent and the model version:
45
+
46
+ ```
47
+ Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
48
+ ```
49
+
50
+ This is the form Claude Code emits and the form the history already uses on
51
+ most commits since 2026-02-28. The kernel-style
52
+ `Assisted-by: <tool>:<model>` trailer is equally acceptable for contributors
53
+ whose tools emit it. The trailer is a disclosure, not an attribution of
54
+ authorship: it records that a model was involved so a reader can tell, the
55
+ same way `Assisted-by:` does in the Linux kernel, Fedora, and LLVM. An
56
+ agent never removes or rewrites a trailer. The human who signs off on a
57
+ commit may rewrite it, trailer included, and by doing so takes sole
58
+ responsibility for its contents; that is what signing off means.
59
+
60
+ ## Sign-off: humans only
61
+
62
+ Responsibility for a change belongs to a person. Concretely:
63
+
64
+ - **An agent never adds `Signed-off-by:`.** The Developer Certificate of
65
+ Origin is a legal certification that the signer has the right to submit
66
+ the work under the project's license. A model cannot hold copyright,
67
+ enter an agreement, or take responsibility, so it cannot certify
68
+ anything, and an agent must not write a sign-off on a human's behalf.
69
+ - **Outside contributors sign off**, should outside pull requests open
70
+ (for now they are maintainer-only; see above). Add
71
+ `Signed-off-by: Your Name <you@example.com>` to each commit
72
+ (`git commit -s`), certifying the
73
+ [Developer Certificate of Origin 1.1](https://developercertificate.org/).
74
+ Brane asks for a DCO sign-off rather than a contributor license
75
+ agreement.
76
+ - **The maintainer's own changes are signed off by the merge.** Brane's
77
+ history predates this file and does not carry `Signed-off-by` on every
78
+ commit. For changes the maintainer lands, reviewing and merging the PR
79
+ is the accountability step, so agents committing in the maintainer's
80
+ checkout do not add a sign-off for the maintainer.
81
+ - **Understand what you submit.** Whoever signs off or merges is expected
82
+ to have read the change, be able to explain it, and stand behind its
83
+ correctness and licensing. "The agent wrote it" is a disclosure, not a
84
+ defense.
85
+
86
+ ## Licensing
87
+
88
+ Brane is AGPL-3.0-or-later (see `LICENSE`). Every contribution is accepted
89
+ under that license. Do not submit code you are not entitled to license
90
+ that way, including code whose origin you cannot account for.
91
+
92
+ ## Security
93
+
94
+ Report a vulnerability privately, as `SECURITY.md` describes, not in an
95
+ issue.
96
+
97
+ ## For agents
98
+
99
+ The same rules, phrased as instructions, are in `AGENTS.md` under
100
+ "Commits, Sign-off, and Accountability". Brane's own agents read that file
101
+ at startup.