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.
- package/AGENTS.md +362 -0
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTING.md +91 -0
- package/DESIGN.md +402 -0
- package/Dockerfile +61 -0
- package/LICENSE +656 -17
- package/README.md +174 -2
- package/SECURITY.md +205 -0
- package/dist/absorb/brane-id.js +11 -0
- package/dist/absorb/chatgpt.js +161 -0
- package/dist/absorb/claude-code.js +504 -0
- package/dist/absorb/index.js +543 -0
- package/dist/absorb/organelle.js +345 -0
- package/dist/absorb/run.js +520 -0
- package/dist/absorb/sources.js +168 -0
- package/dist/absorb/types.js +3 -0
- package/dist/agent-env.js +45 -0
- package/dist/agents.js +1168 -0
- package/dist/claude-live-session.js +124 -0
- package/dist/cli.js +50 -0
- package/dist/codex-tool-log.js +144 -0
- package/dist/commands/absorb.js +291 -0
- package/dist/commands/attach.js +31 -0
- package/dist/commands/certify.js +62 -0
- package/dist/commands/config.js +116 -0
- package/dist/commands/cost.js +126 -0
- package/dist/commands/daemon.js +350 -0
- package/dist/commands/doctor.js +262 -0
- package/dist/commands/fold.js +95 -0
- package/dist/commands/list.js +89 -0
- package/dist/commands/mcp.js +84 -0
- package/dist/commands/meld.js +332 -0
- package/dist/commands/memory.js +215 -0
- package/dist/commands/revive.js +74 -0
- package/dist/commands/run.js +85 -0
- package/dist/commands/spawn.js +1094 -0
- package/dist/commands/token.js +153 -0
- package/dist/copilot-tool-log.js +145 -0
- package/dist/cost/pricing.js +116 -0
- package/dist/cost/reprice.js +136 -0
- package/dist/crush-tool-log.js +293 -0
- package/dist/daemon/agent-scope.js +116 -0
- package/dist/daemon/awaiting.js +54 -0
- package/dist/daemon/cert-manager.js +349 -0
- package/dist/daemon/client.js +262 -0
- package/dist/daemon/gated-routes.js +112 -0
- package/dist/daemon/keep-awake.js +103 -0
- package/dist/daemon/local-socket.js +145 -0
- package/dist/daemon/presence-gate.js +206 -0
- package/dist/daemon/server.js +6349 -0
- package/dist/daemon/signal-source.js +35 -0
- package/dist/daemon/tailscale-rebind.js +58 -0
- package/dist/daemon/token-ring.js +263 -0
- package/dist/daemon/token-routes.js +190 -0
- package/dist/db/events.js +152 -0
- package/dist/db/mentions.js +179 -0
- package/dist/db/schema.js +633 -0
- package/dist/db/tokens.js +583 -0
- package/dist/db/tool-uses.js +647 -0
- package/dist/diagram/index.js +85 -0
- package/dist/diagram/label.js +455 -0
- package/dist/diagram/layout.js +476 -0
- package/dist/diagram/links.js +50 -0
- package/dist/diagram/metrics.js +152 -0
- package/dist/diagram/parse.js +487 -0
- package/dist/diagram/svg.js +389 -0
- package/dist/diagram/types.js +9 -0
- package/dist/export.js +629 -0
- package/dist/files/archive-types.js +2 -0
- package/dist/files/archive.js +182 -0
- package/dist/files/browse.js +327 -0
- package/dist/files/bytes.js +162 -0
- package/dist/files/codecs.js +33 -0
- package/dist/files/find.js +212 -0
- package/dist/files/tar.js +223 -0
- package/dist/files/zip.js +209 -0
- package/dist/folds.js +72 -0
- package/dist/grammars/ebnf.js +92 -0
- package/dist/highlight.js +250 -0
- package/dist/ids.js +24 -0
- package/dist/markdown-diagnostics.js +233 -0
- package/dist/math.js +168 -0
- package/dist/mcp/server.js +886 -0
- package/dist/memory/embedder.js +145 -0
- package/dist/memory/embedding-worker.js +71 -0
- package/dist/memory/embeddings.js +91 -0
- package/dist/memory/index.js +232 -0
- package/dist/memory/storage.js +587 -0
- package/dist/memory/wiki.js +688 -0
- package/dist/memory/wordpiece.js +247 -0
- package/dist/mentions-scan.js +40 -0
- package/dist/presence.js +259 -0
- package/dist/session-affinity.js +185 -0
- package/dist/shared/api-request.js +124 -0
- package/dist/shared/block-glyphs.js +114 -0
- package/dist/shared/diagram-css.js +17 -0
- package/dist/shared/export-selection.js +101 -0
- package/dist/shared/find-in-text.js +110 -0
- package/dist/shared/glow-hues.js +225 -0
- package/dist/shared/hex-dump.js +62 -0
- package/dist/shared/hex-pages.js +52 -0
- package/dist/shared/hit-drum.js +79 -0
- package/dist/shared/known-nids.js +58 -0
- package/dist/shared/list-scroll-keys.js +56 -0
- package/dist/shared/markdown-lists.js +72 -0
- package/dist/shared/markdown-math.js +485 -0
- package/dist/shared/markdown-mentions.js +79 -0
- package/dist/shared/markdown-nids.js +41 -0
- package/dist/shared/markdown-protocols.js +53 -0
- package/dist/shared/markdown-refs.js +123 -0
- package/dist/shared/membrane-invasion.js +342 -0
- package/dist/shared/membrane-motion.js +83 -0
- package/dist/shared/membrane-palette.js +253 -0
- package/dist/shared/membrane-terrain.js +212 -0
- package/dist/shared/message-selection.js +123 -0
- package/dist/shared/mo-glyph.js +57 -0
- package/dist/shared/narrative-format.js +237 -0
- package/dist/shared/narrative-menu.js +82 -0
- package/dist/shared/narrative-sort.js +47 -0
- package/dist/shared/narrative-status.js +52 -0
- package/dist/shared/no-pan.js +85 -0
- package/dist/shared/pane-layout.js +50 -0
- package/dist/shared/payload-inline.js +83 -0
- package/dist/shared/speaker-color.js +61 -0
- package/dist/shared/token-rotation.js +14 -0
- package/dist/shared/view-url.js +197 -0
- package/dist/shared/wiki-links.js +70 -0
- package/dist/shared/wiki-window.js +4 -0
- package/dist/tailscale.js +55 -0
- package/dist/test/absorb-claude.test.js +892 -0
- package/dist/test/agent-scope.test.js +193 -0
- package/dist/test/agents.test.js +55 -0
- package/dist/test/api-request.test.js +122 -0
- package/dist/test/awaiting-glow.test.js +54 -0
- package/dist/test/awaiting.test.js +122 -0
- package/dist/test/bind-token.test.js +88 -0
- package/dist/test/block-glyphs.test.js +68 -0
- package/dist/test/cert-manager.test.js +262 -0
- package/dist/test/claude-live-session.test.js +110 -0
- package/dist/test/codex-tool-log.test.js +568 -0
- package/dist/test/config.test.js +71 -0
- package/dist/test/copilot-tool-log.test.js +93 -0
- package/dist/test/cors-preflight.test.js +49 -0
- package/dist/test/cost-linger.test.js +31 -0
- package/dist/test/cost-pricing.test.js +72 -0
- package/dist/test/cost-reprice.test.js +139 -0
- package/dist/test/cost-sessions.test.js +301 -0
- package/dist/test/crush-tool-log.test.js +289 -0
- package/dist/test/daemon-client.test.js +109 -0
- package/dist/test/daemon-socket.test.js +293 -0
- package/dist/test/diagram-arrows.test.js +205 -0
- package/dist/test/diagram-export.test.js +210 -0
- package/dist/test/diagram-labels.test.js +313 -0
- package/dist/test/diagram-parse.test.js +191 -0
- package/dist/test/diagram-render.test.js +175 -0
- package/dist/test/diagram-review.test.js +288 -0
- package/dist/test/diagram-self-loop-labels.test.js +303 -0
- package/dist/test/embedder.test.js +84 -0
- package/dist/test/events.test.js +123 -0
- package/dist/test/export-selection.test.js +102 -0
- package/dist/test/export.test.js +505 -0
- package/dist/test/files-browse.test.js +393 -0
- package/dist/test/files-find.test.js +272 -0
- package/dist/test/find-in-text.test.js +86 -0
- package/dist/test/first-paint-viewport.test.js +59 -0
- package/dist/test/fixtures/embedding-golden.js +23 -0
- package/dist/test/fixtures/wordpiece-golden.js +167 -0
- package/dist/test/glow-hues.test.js +202 -0
- package/dist/test/harness-cost.test.js +423 -0
- package/dist/test/helpers.js +21 -0
- package/dist/test/hex-pages.test.js +68 -0
- package/dist/test/highlight.test.js +69 -0
- package/dist/test/hit-drum.test.js +71 -0
- package/dist/test/hook-config.test.js +262 -0
- package/dist/test/json-gzip.test.js +70 -0
- package/dist/test/key-routing.test.js +58 -0
- package/dist/test/known-nids.test.js +106 -0
- package/dist/test/link-preview.test.js +67 -0
- package/dist/test/list-scroll-keys.test.js +66 -0
- package/dist/test/listen-own-words.test.js +147 -0
- package/dist/test/listen-timeout.test.js +33 -0
- package/dist/test/markdown-diagnostics.test.js +121 -0
- package/dist/test/markdown-lists.test.js +182 -0
- package/dist/test/markdown-math.test.js +256 -0
- package/dist/test/markdown-nids.test.js +146 -0
- package/dist/test/markdown-protocols.test.js +139 -0
- package/dist/test/mcp-bridge-cancel.test.js +98 -0
- package/dist/test/mcp-bridge-reconnect.test.js +121 -0
- package/dist/test/mcp-narrative.test.js +193 -0
- package/dist/test/mcp.test.js +548 -0
- package/dist/test/meld.test.js +85 -0
- package/dist/test/membrane-invasion.test.js +482 -0
- package/dist/test/membrane-motion.test.js +101 -0
- package/dist/test/membrane-palette.test.js +166 -0
- package/dist/test/membrane-terrain.test.js +170 -0
- package/dist/test/memory-log.test.js +202 -0
- package/dist/test/mentions-e2e.test.js +261 -0
- package/dist/test/mentions-ledger.test.js +265 -0
- package/dist/test/mentions-listen.test.js +265 -0
- package/dist/test/mentions.test.js +238 -0
- package/dist/test/message-selection.test.js +114 -0
- package/dist/test/mo-glyph.test.js +22 -0
- package/dist/test/model-resolution.test.js +166 -0
- package/dist/test/narrate-validate.test.js +77 -0
- package/dist/test/narrate-wait.test.js +160 -0
- package/dist/test/narrative-format.test.js +219 -0
- package/dist/test/narrative-menu.test.js +137 -0
- package/dist/test/narrative-sort.test.js +75 -0
- package/dist/test/no-pan.test.js +60 -0
- package/dist/test/pane-layout.test.js +153 -0
- package/dist/test/paths.test.js +37 -0
- package/dist/test/payload-inline.test.js +91 -0
- package/dist/test/precache-fonts.test.js +72 -0
- package/dist/test/presence-gate.test.js +440 -0
- package/dist/test/presence.test.js +160 -0
- package/dist/test/read-events.test.js +220 -0
- package/dist/test/remote-meld.test.js +115 -0
- package/dist/test/revive-cli.test.js +93 -0
- package/dist/test/search-floor.test.js +206 -0
- package/dist/test/search-fusion.test.js +168 -0
- package/dist/test/search.test.js +205 -0
- package/dist/test/security.test.js +48 -0
- package/dist/test/selection-wiring.test.js +61 -0
- package/dist/test/session-affinity.test.js +295 -0
- package/dist/test/signal-source.test.js +32 -0
- package/dist/test/socket-account.test.js +268 -0
- package/dist/test/spawn-toml.test.js +72 -0
- package/dist/test/speaker-color.test.js +90 -0
- package/dist/test/tailscale-rebind.test.js +79 -0
- package/dist/test/terminal-cursor.test.js +61 -0
- package/dist/test/terminal-resync.test.js +23 -0
- package/dist/test/thin-cli.test.js +382 -0
- package/dist/test/token-bootstrap.test.js +272 -0
- package/dist/test/token-devices.test.js +587 -0
- package/dist/test/token-lapse.test.js +94 -0
- package/dist/test/token-ring.test.js +188 -0
- package/dist/test/token-rotate-cli.test.js +58 -0
- package/dist/test/token-routes.test.js +95 -0
- package/dist/test/tool-uses.test.js +1006 -0
- package/dist/test/usage-ledger.test.js +126 -0
- package/dist/test/view-url.test.js +581 -0
- package/dist/test/wiki-links.test.js +57 -0
- package/dist/test/wiki-sources.test.js +85 -0
- package/dist/test/wiki-window.test.js +31 -0
- package/dist/test/wiki.test.js +399 -0
- package/dist/test/wordpiece.test.js +68 -0
- package/dist/tls.js +148 -0
- package/dist/tmux.js +202 -0
- package/dist/user-agent.js +46 -0
- package/docker-entrypoint.sh +141 -0
- package/docs/README.md +3 -0
- package/docs/absorb.md +231 -0
- package/docs/cost-ledger.md +125 -0
- package/docs/daemon-api.md +189 -0
- package/docs/diagrams.md +163 -0
- package/docs/doctor.md +36 -0
- package/docs/export-scope.md +69 -0
- package/docs/files-view.md +133 -0
- package/docs/link-previews.md +38 -0
- package/docs/math.md +32 -0
- package/docs/mcp.md +69 -0
- package/docs/memory-search.md +75 -0
- package/docs/mentions.md +101 -0
- package/docs/multi-brane.md +14 -0
- package/docs/passkeys.md +165 -0
- package/docs/presence.md +202 -0
- package/docs/releasing.md +53 -0
- package/docs/rendering-warnings.md +22 -0
- package/docs/request-layer.md +72 -0
- package/docs/selection-store.md +50 -0
- package/docs/session-affinity.md +61 -0
- package/docs/terminal-mirroring.md +211 -0
- package/docs/token-rotation.md +413 -0
- package/docs/view-urls.md +114 -0
- package/docs/web-app.md +23 -0
- package/docs/wiki.md +43 -0
- package/expo/dist/_expo/static/js/web/entry-e56efc1291dca7258ea00b8108b033a4.js +1097 -0
- package/expo/dist/apple-touch-icon.png +0 -0
- package/expo/dist/favicon.svg +3 -0
- package/expo/dist/index.html +177 -0
- package/expo/dist/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/expo/dist/katex/katex.min.css +1 -0
- package/expo/dist/manifest.json +16 -0
- package/expo/dist/metadata.json +1 -0
- package/expo/dist/og/membrane.v1.png +0 -0
- package/expo/dist/pdf.min.mjs +28 -0
- package/expo/dist/pdf.worker.min.mjs +28 -0
- package/expo/dist/sw.js +154 -0
- package/package.json +81 -23
- package/protocols/LIVE_loop.md +407 -0
- package/protocols/bebrief.md +41 -0
- package/protocols/digest.md +231 -0
- package/protocols/fly.md +266 -0
- package/protocols/idle.md +81 -0
- package/protocols/keeper.md +829 -0
- package/protocols/markdown.md +80 -0
- package/protocols/memory.md +419 -0
- package/protocols/mentions.md +93 -0
- package/protocols/payloads.md +53 -0
- package/protocols/prelude.md +91 -0
- package/protocols/ramify.md +105 -0
- package/protocols/review.md +356 -0
- package/protocols/rrr.md +232 -0
- package/protocols/scribe.md +429 -0
- package/protocols/summarize.md +203 -0
- package/protocols/twin.md +174 -0
- package/protocols/wiki.md +438 -0
- package/protocols/worker.md +38 -0
- package/wiki/shared/append-only-event-log.md +148 -0
- package/wiki/shared/index.md +48 -0
- package/wiki/shared/owning-your-narratives.md +161 -0
- package/wiki/shared/premature-ontologies.md +435 -0
- package/wiki/shared/sedimentary-superintelligence.md +128 -0
- package/wiki/shared/sequestering-the-narrative.md +143 -0
- package/wiki/shared/why-wikis-work.md +216 -0
- package/.npmignore +0 -2
- package/.travis.yml +0 -5
- package/index.js +0 -8
- 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.
|
package/CONTRIBUTING.md
ADDED
|
@@ -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.
|