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
package/AGENTS.md ADDED
@@ -0,0 +1,362 @@
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** with session resumption across 6 agent types
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 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 version bump, tag rule, dist-tag choice and why there is no provenance
117
+ attestation are in [docs/releasing.md](docs/releasing.md).
118
+
119
+ ## CLI Commands
120
+
121
+ | Command | Purpose |
122
+ |---------|---------|
123
+ | `daemon` | Manage daemon lifecycle (start, stop, restart, status, logs) |
124
+ | `spawn` | Spawn new agent sessions (`--attach`, `--model`, `--role`, `-- <args>`) |
125
+ | `attach` | Attach to a tmux session |
126
+ | `list` | List narratives grouped by brane (`--brane`, `--archived`, `--limit`) — reads `GET /api/narratives` + `GET /api/branes` |
127
+ | `fold` | Register directories as spawn points (`--brane` to associate with a brane) — delegates to `POST /api/folds` |
128
+ | `meld` | Generate QR code for mobile access (defaults to `brane.organelle.dev`, `--local` for direct); 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 |
129
+ | `mcp` | MCP stdio server (used internally by agent sessions) |
130
+ | `revive` | Restart dead agent sessions (`--prompt`, `--no-prompt`, `--agent`) — delegates to `POST /api/revive/:nid` |
131
+ | `config` | Get/set brane configuration (git-config style: `--list`, `--unset`) |
132
+ | `certify` | Force-refresh TLS certificates (daemon auto-provisions and renews on its own; this is a manual escape hatch) |
133
+ | `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 |
134
+ | `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 |
135
+ | `cost` | Cost ledger maintenance (`backfill [--dry-run] [--all]`, `reprice [--dry-run] [--all]`) — delegates to `POST /api/cost/backfill` and `POST /api/cost/reprice` |
136
+ | `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) |
137
+ | `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) |
138
+
139
+ ## Database
140
+
141
+ Single SQLite database at `~/.brane/brane.db` (WAL mode). Key tables:
142
+
143
+ | Table | Purpose |
144
+ |-------|---------|
145
+ | `meta` | Instance ID, daemon port/pid/version/tls/http_port/socket, config |
146
+ | `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) |
147
+ | `folds` | Registered spawn directories (path, brane_id, created_at) |
148
+ | `narratives` | Agent sessions (id, brane_id, agent_type, role, status, fold_path, title, summary, archived, agent_session_id) |
149
+ | `events` | Append-only event log: (narrative_id, seq, time, type, content, content_type, source, re, payloads, meta) |
150
+ | `memory_chunks` | Event chunks for embeddings |
151
+ | `memory_vec` | Vector embeddings for semantic search (sqlite-vec) |
152
+ | `memory_fts` | FTS5 full-text search table |
153
+ | `memory_cursors` | Per-narrative indexing cursors |
154
+ | `memory_stats` | Indexing statistics |
155
+ | `usage_ledger` | Durable per-message / per-session cost rows — see [Cost Ledger](docs/cost-ledger.md) |
156
+ | `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) |
157
+ | `absorb_files` | (brane, provider, session) → (size, mtime) at its last absorb, so an unchanged file is skipped on a stat |
158
+
159
+ Event types: `narration` (agent), `human_signal` (operator), `agent_signal` (cross-agent).
160
+
161
+ ## Agent Adapters
162
+
163
+ Brane supports multiple agent types with session resumption. Each agent has an adapter in `src/agents.ts`:
164
+
165
+ | Agent | Resume Method | Notes |
166
+ |-------|--------------|-------|
167
+ | `claude` | `--resume <session_id>` | Discovers session from `~/.claude/projects/` |
168
+ | `goose` | `-r` | Resumes by session name |
169
+ | `gemini` | (none) | Uses `-i` for prompt injection |
170
+ | `codex` | `resume <session_id>` | Subcommand-based resumption |
171
+ | `amp` | (none) | Uses thread references `@T-<id>` in prompt |
172
+ | `copilot` | `--session-id <session_id>` | Daemon-pinned UUID resumes the exact local session |
173
+
174
+ 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:
175
+ - **Claude**: `.mcp.json` in fold directory
176
+ - **Goose**: `--with-extension` argument with env passthrough
177
+ - **Gemini**: `.gemini/settings.json` project-level config
178
+ - **Codex**: `~/.codex/config.toml` with env references
179
+ - **Copilot**: Per-session `.brane-copilot-mcp-<nid>.json`
180
+
181
+ ## Security Model
182
+
183
+ See `SECURITY.md` for full details. Key features:
184
+
185
+ - **TCP-level IP filtering** — only allows localhost, Tailscale IPs, RFC 1918 private ranges, and CGNAT
186
+ - **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.
187
+ - **Atomic daemon startup** — `BEGIN EXCLUSIVE` SQLite transaction prevents race conditions
188
+ - **Version checking** — daemon stores version for CLI compatibility detection
189
+ - **Payload security** — path traversal protection, 50MB size limits, immutable cached URLs
190
+ - **Origin checking** — WebSocket upgrade validates Origin header
191
+
192
+ ## Rules for Every Change
193
+
194
+ The full reasoning for each is in the linked doc; these are the parts that
195
+ bite outside their own subsystem.
196
+
197
+ - **The CLI is a daemon client.** A command that touches narratives, folds,
198
+ sessions, or the memory index calls a daemon route (adding one if needed)
199
+ and keeps only terminal-shaped work for itself. It never opens the database
200
+ itself. Every client calls `warnIfVersionMismatch()` first. See [The CLI is
201
+ a daemon client](docs/daemon-api.md#the-cli-is-a-daemon-client).
202
+ - **A new daemon route is closed to agents** until it is listed in
203
+ `AGENT_ROUTES` (`src/daemon/agent-scope.ts`). If agents' CLI or bridge
204
+ needs it, add it there; operator acts stay off the list. See [Agent
205
+ tokens](docs/token-rotation.md#agent-tokens).
206
+ - **No test opens the operator's database.** `openDatabase()` throws under
207
+ `node --test`; code the suite drives takes a `db`, and tests build one with
208
+ `createTestDb()`. A test that reads *source* (not `dist/`) must `skip` when
209
+ the source is absent, or `brane doctor` goes red on every install. See
210
+ [Doctor](docs/doctor.md).
211
+ - **MCP tool errors use `sendToolError()`**, not `sendToolResult({ error })`;
212
+ the bridge maps it to `isError: true`. Tool logic lives in the daemon, never
213
+ in the bridge. See [MCP Architecture](docs/mcp.md).
214
+ - **Bodiless app requests send no headers.** The token rides in `?token=`, so
215
+ a GET needs no CORS preflight; `src/test/api-request.test.ts` enforces it.
216
+ Breaking this is invisible on a fast network. See [The Request
217
+ Layer](docs/request-layer.md).
218
+ - **A `src/shared/` module with a bare npm import needs a metro alias** in
219
+ `expo/metro.config.js`, as `katex` has. See [Math Rendering](docs/math.md).
220
+ - **One parse, never a second scanner.** Warnings, mentions and diagram
221
+ diagnostics reuse the renderer's own parse; a parallel regex eventually
222
+ disagrees with what the operator sees. Regexes on the `narrate` path must
223
+ be linear-time. See [Rendering Warnings](docs/rendering-warnings.md),
224
+ [Mentions](docs/mentions.md), [Diagrams](docs/diagrams.md).
225
+
226
+ - **Every conversational append goes through `announceEvent()`**, which
227
+ records mentions and *then* wakes listeners. A new append site in
228
+ `server.ts` that open-codes the two in the other order leaves a mention
229
+ delivered and never settled. See [Mentions](docs/mentions.md).
230
+ - **`expo/public/index.html` is the HTML template that ships**; keep
231
+ `expo/app/+html.tsx` in step with it, but a `<head>` change made only there
232
+ never reaches a browser. See [Math Rendering](docs/math.md) and [Link
233
+ Previews](docs/link-previews.md).
234
+
235
+ ## Further Reading
236
+
237
+ Relative links into [`docs/`](docs/). Each is the full write-up for its area,
238
+ including the "less obvious than it looks" decisions and the tests that pin
239
+ them. The paths in parentheses are the code each one goes with: about to
240
+ change one of those, read its doc first.
241
+
242
+ **Daemon and CLI**
243
+
244
+ - [Daemon](docs/daemon-api.md) (`src/daemon/server.ts` routes,
245
+ `src/daemon/client.ts`, `src/commands/`): every HTTP and WebSocket endpoint;
246
+ the Spawn, Revive, Run and Folds APIs; why the CLI is a daemon client; who
247
+ may register which folds.
248
+ - [MCP and the LIVE Loop](docs/mcp.md) (`src/mcp/`, `src/daemon/awaiting.ts`,
249
+ MCP handlers in `server.ts`): the stdio↔WebSocket bridge, listen wakeup and
250
+ cancellation, `narrate({ wait: true })`, the LIVE loop tools, narrative
251
+ metadata.
252
+ - [Token Rotation](docs/token-rotation.md) (`src/daemon/token-ring.ts`,
253
+ `src/db/tokens.ts`, `src/daemon/token-routes.ts`, `src/commands/token.ts`):
254
+ tokens stored as hashes only, a token per melded device and per agent session, the Devices list
255
+ and per-device revoke, `brane token rotate`, why the swap happens on first
256
+ use of the new token, and why this machine holds no token (`.daemon_token`
257
+ is retired).
258
+ - [Passkeys](docs/passkeys.md) (not built yet; `src/presence.ts`,
259
+ `src/db/tokens.ts`): the design, the spike and real-device results, what
260
+ the browser and daemon sides must do, open questions, build order.
261
+ - [Presence Check](docs/presence.md) (`src/presence.ts`,
262
+ `src/daemon/presence-gate.ts`): confirming the operator is at
263
+ the machine with the OS's own prompt (macOS, Windows Hello from Windows or
264
+ WSL, polkit); the gate it puts on meld, a device's sign-out and rotation
265
+ from the shell, and why agents are refused them.
266
+ - [Session Affinity](docs/session-affinity.md) (`src/session-affinity.ts`):
267
+ the `X-Session-Affinity` header for claude sessions on Fireworks.
268
+ - [Doctor](docs/doctor.md) (`src/commands/doctor.ts`, `src/test/`): `brane
269
+ doctor`, and the shipped-test-suite rules.
270
+ - [Releasing](docs/releasing.md) (`.github/workflows/release.yml`,
271
+ `package.json` version): the npm release workflow.
272
+
273
+ **Data**
274
+
275
+ - [Multi-Brane](docs/multi-brane.md) (`brane_id` resolution, `src/folds.ts`):
276
+ home and foreign branes, brane_id resolution.
277
+ - [Absorb](docs/absorb.md) (`src/absorb/`): importing history (ChatGPT,
278
+ organelle, local Claude Code stores), per-message idempotence, `--rebuild`.
279
+ - [Memory and Search Ranking](docs/memory-search.md) (`src/memory/`):
280
+ embeddings, FTS5, and why hybrid search fuses ranks rather than scores.
281
+ - [Cost Ledger](docs/cost-ledger.md) (`src/cost/`, `usage_ledger`, adapters'
282
+ usage readers): `usage_ledger`, credit assignment across forks, backfill,
283
+ re-pricing.
284
+ - [Mentions](docs/mentions.md) (`src/mentions-scan.ts`, `src/db/mentions.ts`,
285
+ `src/shared/markdown-mentions.ts`): `@nid` addressing, the mentions ledger,
286
+ and the record-before-wake ordering.
287
+
288
+ **Web app**
289
+
290
+ - [Web App (Expo)](docs/web-app.md) (`expo/`): what the app offers, view by
291
+ view.
292
+ - [Terminal Mirroring](docs/terminal-mirroring.md)
293
+ (`expo/components/TerminalPane.tsx`, the capture loop in `server.ts`):
294
+ capture-pane mirroring, the resync heartbeat, the stranded rAF, the cursor,
295
+ paste and copy, block glyphs.
296
+ - [Files View](docs/files-view.md) (`src/files/`, `expo/lib/hexDoc.ts`,
297
+ `expo/lib/hexFind.ts`): `GET /api/files`, every format the Files view shows
298
+ (archives as folders, hex as the floor), searching the bytes.
299
+ - [The Request Layer](docs/request-layer.md) (`expo/lib/api.ts`,
300
+ `src/shared/api-request.ts`): CORS preflights, timeouts and retries at
301
+ satellite RTT.
302
+ - [View URLs](docs/view-urls.md) (`src/shared/view-url.ts`,
303
+ `expo/app/_layout.tsx`): what the query string and fragment carry, Isolate
304
+ and Meld links.
305
+ - [The Selection Store](docs/selection-store.md)
306
+ (`src/shared/message-selection.ts`, `expo/lib/selection.ts`): the chat's
307
+ message selection outside React state.
308
+ - [Export Scope](docs/export-scope.md) (`src/export.ts`,
309
+ `src/shared/export-selection.ts`): exporting a selection or its complement,
310
+ and what an excerpt discloses.
311
+ - [Link Previews](docs/link-previews.md) (`expo/public/index.html`,
312
+ `expo/scripts/og-membrane/`): the `og:*` card and its image.
313
+
314
+ **Markdown rendering**
315
+
316
+ - [Diagram Rendering](docs/diagrams.md) (`src/diagram/`): mermaid fences drawn
317
+ on the daemon, the dialect census, labels, self-loops.
318
+ - [Math Rendering](docs/math.md) (`src/shared/markdown-math.ts`,
319
+ `src/math.ts`): KaTeX in the app and the export, every delimiter a model
320
+ writes.
321
+ - [Rendering Warnings](docs/rendering-warnings.md)
322
+ (`src/markdown-diagnostics.ts`): what `narrate`'s `warnings` report and
323
+ `strict: true`.
324
+ - [Wiki: Local and Shared](docs/wiki.md) (`src/memory/wiki.ts`,
325
+ `src/shared/wiki-links.ts`): `wiki/` vs `wiki/shared/`, who sees what, the
326
+ install fold.
327
+
328
+ Also: `DESIGN.md` (original architecture), `SECURITY.md` (security model),
329
+ `CONTRIBUTING.md` (contribution policy), and `protocols/` (agent protocols,
330
+ read at runtime).
331
+
332
+ ## Key Patterns
333
+
334
+ - **Port stability**: daemon restart captures port before SIGTERM, reuses it
335
+ - **Scroll preservation**: chat/terminal tabs use absolute positioning with zIndex stacking
336
+ - **Terminal resize**: ResizeObserver measures monospace character dimensions, sends cols/rows to tmux
337
+ - **Multitouch keyboard**: refs for synchronous state, React state for visual rendering only
338
+ - **Event cursor**: monotonic `seq` per narrative, `after`/`before`/`tail` parameters on narrate/listen (supports multi-narrative object format)
339
+ - **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)
340
+ - **Atomic daemon claim**: SQLite `BEGIN EXCLUSIVE` transaction ensures singleton daemon
341
+ - **IP filtering**: TCP-level socket filtering before HTTP processing
342
+ - **Version tracking**: daemon and CLI version compatibility checks
343
+ - **Metadata broadcasts**: control WebSocket pushes summary/status changes in real-time
344
+ - **Portable paths**: stored as `~/relative` format, converted via `toPortablePath()`/`fromPortablePath()`
345
+ - **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
346
+ - **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
347
+ - **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
348
+ - **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
349
+ - **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)
350
+ - **`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
351
+ - **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
352
+ - **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`
353
+ - **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
354
+ - **Stale PID cleanup**: daemon info queries verify PID liveness, clean up dead entries
355
+ - **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
356
+
357
+ ## Important Warnings
358
+
359
+ - **Never restart the organelle Nucleus daemon** — it maintains WebSocket connections to mobile devices
360
+ - The brane daemon is separate and safe to restart
361
+ - Database has no back-compat concerns yet — schema can change freely
362
+ - `~/.brane/` directory should be portable (paths stored as ~/relative)
package/CHANGELOG.md ADDED
@@ -0,0 +1,33 @@
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.0 - 2026-10-11
10
+
11
+ The first release of this codebase. What ships:
12
+
13
+ - The `brane` CLI and userspace daemon: register directories as folds,
14
+ spawn agents in them (Claude Code, Codex, Gemini, Goose, Crush, Copilot,
15
+ or any command) under tmux, and keep every session's narrative in one
16
+ SQLite database, every message with a stable `nid:seq` address.
17
+ - The LIVE loop: an MCP server injected into each agent session
18
+ (`narrate`, `listen`, `whoami`, wiki and memory search), and the
19
+ protocols agents read at runtime, in `protocols/`.
20
+ - The web app the daemon serves to any browser on your tailnet: chat,
21
+ terminal mirroring, files, export, markdown with math and diagrams, and
22
+ meld by QR code. Per-device and per-agent tokens, a presence prompt for
23
+ new devices, and `brane token rotate`.
24
+ - Memory: local embeddings on `onnxruntime-node` fused with FTS5, across
25
+ narratives and absorbed history (ChatGPT, organelle, local Claude Code
26
+ stores).
27
+ - `brane doctor`, which runs the shipped test suite against the install.
28
+ - Node 20 or newer. AGPL-3.0-or-later.
29
+
30
+ ## 0.1.1
31
+
32
+ An unrelated earlier package that held the name on npm (2022). Not an
33
+ ancestor of this code.
@@ -0,0 +1,91 @@
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
+ ## How changes land
10
+
11
+ - `main` takes pull requests only. The `protect-main-branch` ruleset
12
+ (2026-09-02) requires a PR, forbids force-pushes and deletions, and has
13
+ no bypass actors.
14
+ - Work happens on a branch, usually in a worktree, and arrives as a PR
15
+ with CI green.
16
+ - A human merges. Agents open PRs; they do not approve or merge them, not
17
+ even their own.
18
+
19
+ ## Working from a clone
20
+
21
+ ```sh
22
+ npm install
23
+ npm link # once: `brane` now resolves to this checkout
24
+ npm run build # Compile TypeScript + build the Expo web bundle
25
+ ```
26
+
27
+ `npm link` points your global `brane` at `<repo>/dist/cli.js`, so every
28
+ later `npm run build` is picked up without reinstalling; after a
29
+ server-side change, `brane daemon restart` puts the daemon on it. To go
30
+ back to a published release, `npm unlink -g brane` and then
31
+ `npm install -g brane`.
32
+
33
+ ## Disclosure: say when an agent helped
34
+
35
+ Every commit an agent wrote or substantially shaped carries a trailer naming
36
+ the agent and the model version:
37
+
38
+ ```
39
+ Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
40
+ ```
41
+
42
+ This is the form Claude Code emits and the form the history already uses on
43
+ most commits since 2026-02-28. The kernel-style
44
+ `Assisted-by: <tool>:<model>` trailer is equally acceptable for contributors
45
+ whose tools emit it. The trailer is a disclosure, not an attribution of
46
+ authorship: it records that a model was involved so a reader can tell, the
47
+ same way `Assisted-by:` does in the Linux kernel, Fedora, and LLVM. An
48
+ agent never removes or rewrites a trailer. The human who signs off on a
49
+ commit may rewrite it, trailer included, and by doing so takes sole
50
+ responsibility for its contents; that is what signing off means.
51
+
52
+ ## Sign-off: humans only
53
+
54
+ Responsibility for a change belongs to a person. Concretely:
55
+
56
+ - **An agent never adds `Signed-off-by:`.** The Developer Certificate of
57
+ Origin is a legal certification that the signer has the right to submit
58
+ the work under the project's license. A model cannot hold copyright,
59
+ enter an agreement, or take responsibility, so it cannot certify
60
+ anything, and an agent must not write a sign-off on a human's behalf.
61
+ - **Outside contributors sign off.** Add
62
+ `Signed-off-by: Your Name <you@example.com>` to each commit
63
+ (`git commit -s`), certifying the
64
+ [Developer Certificate of Origin 1.1](https://developercertificate.org/).
65
+ Brane asks for a DCO sign-off rather than a contributor license
66
+ agreement.
67
+ - **The maintainer's own changes are signed off by the merge.** Brane's
68
+ history predates this file and does not carry `Signed-off-by` on every
69
+ commit. For changes the maintainer lands, reviewing and merging the PR
70
+ is the accountability step, so agents committing in the maintainer's
71
+ checkout do not add a sign-off for the maintainer.
72
+ - **Understand what you submit.** Whoever signs off or merges is expected
73
+ to have read the change, be able to explain it, and stand behind its
74
+ correctness and licensing. "The agent wrote it" is a disclosure, not a
75
+ defense.
76
+
77
+ ## Licensing
78
+
79
+ Brane is AGPL-3.0-or-later (see `LICENSE`). Every contribution is accepted
80
+ under that license. Do not submit code you are not entitled to license
81
+ that way, including code whose origin you cannot account for.
82
+
83
+ ## Security
84
+
85
+ Do not open a public issue for a vulnerability. See `SECURITY.md`.
86
+
87
+ ## For agents
88
+
89
+ The same rules, phrased as instructions, are in `AGENTS.md` under
90
+ "Commits, Sign-off, and Accountability". Brane's own agents read that file
91
+ at startup.