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