the-campfire 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2388 -0
  3. package/dist/assets/{MermaidDiagram-D_MwUXi3.js → MermaidDiagram-Cas1Ngze.js} +2 -2
  4. package/dist/assets/{_basePickBy-DsMRBmhy.js → _basePickBy-D1h3RRT9.js} +1 -1
  5. package/dist/assets/{_baseUniq-CZ0BR5Mx.js → _baseUniq-Z9p6uaM9.js} +1 -1
  6. package/dist/assets/{arc-D6Y0ooDg.js → arc-DJLNkmre.js} +1 -1
  7. package/dist/assets/{architectureDiagram-VXUJARFQ-3T5ZoEn1.js → architectureDiagram-VXUJARFQ-CBHHYg8R.js} +1 -1
  8. package/dist/assets/{blockDiagram-VD42YOAC-CvOCnB8f.js → blockDiagram-VD42YOAC-DMtvAHPO.js} +1 -1
  9. package/dist/assets/{c4Diagram-YG6GDRKO-DPXJvInm.js → c4Diagram-YG6GDRKO-G9Zj2LWB.js} +1 -1
  10. package/dist/assets/channel-CcCVj0rn.js +1 -0
  11. package/dist/assets/{chunk-4BX2VUAB-DPHGuPB4.js → chunk-4BX2VUAB-s3svQOtk.js} +1 -1
  12. package/dist/assets/{chunk-55IACEB6-BbI83gIK.js → chunk-55IACEB6-C6fhtS_L.js} +1 -1
  13. package/dist/assets/{chunk-B4BG7PRW-DGvVY1Y_.js → chunk-B4BG7PRW-CpePj3eQ.js} +1 -1
  14. package/dist/assets/{chunk-DI55MBZ5-2YN0FhPB.js → chunk-DI55MBZ5-Dq9AChBD.js} +1 -1
  15. package/dist/assets/{chunk-FMBD7UC4-Ctqs0bWj.js → chunk-FMBD7UC4-DSOMddvX.js} +1 -1
  16. package/dist/assets/{chunk-QN33PNHL-CfvfTLi4.js → chunk-QN33PNHL-ZrdWE4nY.js} +1 -1
  17. package/dist/assets/{chunk-QZHKN3VN-C-dG1NiD.js → chunk-QZHKN3VN-BqLE4kwR.js} +1 -1
  18. package/dist/assets/{chunk-TZMSLE5B-Bh07YiOi.js → chunk-TZMSLE5B-DY7GliuX.js} +1 -1
  19. package/dist/assets/classDiagram-2ON5EDUG-8I6xWkSV.js +1 -0
  20. package/dist/assets/classDiagram-v2-WZHVMYZB-8I6xWkSV.js +1 -0
  21. package/dist/assets/clone-zAvPgvOP.js +1 -0
  22. package/dist/assets/{cose-bilkent-S5V4N54A-CTC2n8Hd.js → cose-bilkent-S5V4N54A-DmRYvz2l.js} +1 -1
  23. package/dist/assets/{dagre-6UL2VRFP-CAgGZKYt.js → dagre-6UL2VRFP-D4IfaYgb.js} +1 -1
  24. package/dist/assets/{diagram-PSM6KHXK-DymwxXvC.js → diagram-PSM6KHXK-ClfgeCpw.js} +1 -1
  25. package/dist/assets/{diagram-QEK2KX5R-CAEL5_ej.js → diagram-QEK2KX5R-BaBfarh-.js} +1 -1
  26. package/dist/assets/{diagram-S2PKOQOG-B6onWI1I.js → diagram-S2PKOQOG-DT1eYmOM.js} +1 -1
  27. package/dist/assets/{erDiagram-Q2GNP2WA-DP-dbxgu.js → erDiagram-Q2GNP2WA-C5ZVoHhn.js} +1 -1
  28. package/dist/assets/{flowDiagram-NV44I4VS-OMmA9Rvb.js → flowDiagram-NV44I4VS-C9MYAakn.js} +1 -1
  29. package/dist/assets/{ganttDiagram-JELNMOA3-B2oAHD8b.js → ganttDiagram-JELNMOA3-HHt6rJj9.js} +1 -1
  30. package/dist/assets/{gitGraphDiagram-V2S2FVAM-CAZO9ISt.js → gitGraphDiagram-V2S2FVAM-CfA3qwoT.js} +1 -1
  31. package/dist/assets/{graph-CeeDmBlM.js → graph-BLJloKEi.js} +1 -1
  32. package/dist/assets/index-CvOAfVHK.css +32 -0
  33. package/dist/assets/{index-CAGJQXdJ.js → index-CxNtY8EJ.js} +82 -82
  34. package/dist/assets/{infoDiagram-HS3SLOUP-m0CP23H-.js → infoDiagram-HS3SLOUP-ASXl-hwl.js} +1 -1
  35. package/dist/assets/{journeyDiagram-XKPGCS4Q-C9WvzT-H.js → journeyDiagram-XKPGCS4Q-B-wDjjzW.js} +1 -1
  36. package/dist/assets/{kanban-definition-3W4ZIXB7-KIEeugzr.js → kanban-definition-3W4ZIXB7-BNWLVKm2.js} +1 -1
  37. package/dist/assets/{layout-P-20nhx7.js → layout-cpBTqNBI.js} +1 -1
  38. package/dist/assets/{linear-CMM5aRIM.js → linear-DAonGknK.js} +1 -1
  39. package/dist/assets/{mermaid.core-Z9YQUdi5.js → mermaid.core-BdetWGOO.js} +4 -4
  40. package/dist/assets/{mindmap-definition-VGOIOE7T-B-NyLDuB.js → mindmap-definition-VGOIOE7T-CJOEqJKm.js} +1 -1
  41. package/dist/assets/{pieDiagram-ADFJNKIX-Dp8zgF7X.js → pieDiagram-ADFJNKIX-Dnc1ekZC.js} +1 -1
  42. package/dist/assets/{quadrantDiagram-AYHSOK5B-Cs07PJ50.js → quadrantDiagram-AYHSOK5B-Dr56Xspi.js} +1 -1
  43. package/dist/assets/{requirementDiagram-UZGBJVZJ-CWMm228C.js → requirementDiagram-UZGBJVZJ-z-G-ThCz.js} +1 -1
  44. package/dist/assets/{sankeyDiagram-TZEHDZUN-Cf7zGgTA.js → sankeyDiagram-TZEHDZUN-D_4p6Me1.js} +1 -1
  45. package/dist/assets/{sequenceDiagram-WL72ISMW-TzZvjAhX.js → sequenceDiagram-WL72ISMW-DD1K4OoS.js} +1 -1
  46. package/dist/assets/{stateDiagram-FKZM4ZOC-CH45r52Y.js → stateDiagram-FKZM4ZOC-ENIvCriI.js} +1 -1
  47. package/dist/assets/stateDiagram-v2-4FDKWEC3-BgJoZY9E.js +1 -0
  48. package/dist/assets/{timeline-definition-IT6M3QCI-CLaDCX_H.js → timeline-definition-IT6M3QCI-V8I1MBPc.js} +1 -1
  49. package/dist/assets/{treemap-GDKQZRPO-BNNAKE7E.js → treemap-GDKQZRPO-1lnlvkR3.js} +1 -1
  50. package/dist/assets/{xychartDiagram-PRI3JC2R-BG_0_QvU.js → xychartDiagram-PRI3JC2R-CrSrN3UV.js} +1 -1
  51. package/dist/index.html +2 -2
  52. package/package.json +2 -2
  53. package/server/collective-intelligence.ts +125 -43
  54. package/server/embedding.ts +12 -3
  55. package/server/memory-consolidation.ts +703 -0
  56. package/server/memory-migration.ts +468 -0
  57. package/server/routes/ci-routes.ts +68 -10
  58. package/server/routes/settings-routes.ts +10 -2
  59. package/server/semantic-memory.ts +1127 -187
  60. package/server/session-types.ts +15 -0
  61. package/server/settings-manager.ts +122 -3
  62. package/server/ws-bridge.ts +207 -26
  63. package/dist/assets/channel-D6cof2B8.js +0 -1
  64. package/dist/assets/classDiagram-2ON5EDUG-BG_dxrC_.js +0 -1
  65. package/dist/assets/classDiagram-v2-WZHVMYZB-BG_dxrC_.js +0 -1
  66. package/dist/assets/clone-vuZ4vhTG.js +0 -1
  67. package/dist/assets/index-Byjg9zgI.css +0 -32
  68. package/dist/assets/stateDiagram-v2-4FDKWEC3-DaPUshfK.js +0 -1
package/README.md ADDED
@@ -0,0 +1,2388 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/stretchcloud/campfire/main/.github/og-image.png" alt="Campfire — Seven agents. One Campfire." width="100%" />
3
+ </p>
4
+
5
+ <h1 align="center">Campfire</h1>
6
+ <p align="center"><strong>The collaborative web platform for AI coding agents.</strong></p>
7
+ <p align="center">A collaborative web platform for AI coding agents. Run Claude Code, Codex, Goose, Aider, OpenHands, OpenClaw, and OpenCode sessions side by side — with real-time collaboration, multi-agent orchestration, permission voting, session replay, scheduled tasks, and 30+ integrations.</p>
8
+
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/the-campfire"><img src="https://img.shields.io/npm/v/the-campfire" alt="npm version" /></a>
11
+ <a href="https://www.npmjs.com/package/the-campfire"><img src="https://img.shields.io/npm/dt/the-campfire" alt="npm downloads" /></a>
12
+ <a href="https://github.com/stretchcloud/campfire/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/stretchcloud/campfire/ci.yml?branch=main&label=CI" alt="CI status" /></a>
13
+ <a href="https://github.com/stretchcloud/campfire/stargazers"><img src="https://img.shields.io/github/stars/stretchcloud/campfire" alt="GitHub stars" /></a>
14
+ <a href="https://github.com/stretchcloud/campfire/pkgs/container/campfire"><img src="https://img.shields.io/badge/ghcr.io-campfire-2496ED?logo=docker&logoColor=white" alt="ghcr.io image" /></a>
15
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/stretchcloud/campfire" alt="MIT License" /></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://the-campfire.dev"><strong>the-campfire.dev</strong></a>
20
+ </p>
21
+
22
+ ---
23
+
24
+ ## Table of Contents
25
+
26
+ - [Quick Start](#quick-start)
27
+ - [Features](#features)
28
+ - [Multi-Agent Sessions](#multi-agent-sessions)
29
+ - [Real-Time Collaboration](#real-time-collaboration)
30
+ - [Permission Control & Voting](#permission-control--voting)
31
+ - [Session Replay](#session-replay)
32
+ - [Fork & Branch](#fork--branch)
33
+ - [Session Gallery](#session-gallery)
34
+ - [Prompt Library](#prompt-library)
35
+ - [Linear Integration](#linear-integration)
36
+ - [Webhooks](#webhooks)
37
+ - [Scheduled Tasks (Cron)](#scheduled-tasks-cron)
38
+ - [Adapter Registry](#adapter-registry)
39
+ - [Cost Dashboard](#cost-dashboard)
40
+ - [Environment Profiles](#environment-profiles)
41
+ - [Git Integration](#git-integration)
42
+ - [Embedded Terminal](#embedded-terminal)
43
+ - [Protocol Recording](#protocol-recording)
44
+ - [Docker Containers](#docker-containers)
45
+ - [PWA & Mobile](#pwa--mobile)
46
+ - [Auto-Naming](#auto-naming)
47
+ - [Collective Intelligence](#collective-intelligence)
48
+ - [Copy Output Button](#copy-output-button)
49
+ - [Voice Input](#voice-input)
50
+ - [Workspace File Tree](#workspace-file-tree)
51
+ - [Mermaid Diagram Rendering](#mermaid-diagram-rendering)
52
+ - [Orchestrator Pipelines](#orchestrator-pipelines)
53
+ - [Multi-Agent Orchestration](#multi-agent-orchestration)
54
+ - [Message Queue](#message-queue)
55
+ - [Kanban Task Board](#kanban-task-board)
56
+ - [Authentication](#authentication)
57
+ - [Thinking Effort (Codex)](#thinking-effort-codex)
58
+ - [Skills & Plugins Management](#skills--plugins-management)
59
+ - [Drag & Drop Upload](#drag--drop-upload)
60
+ - [Session Folders](#session-folders)
61
+ - [Permission Mode Selector](#permission-mode-selector)
62
+ - [Session Pulse (Background Activity)](#session-pulse-background-activity)
63
+ - [Agent System](#agent-system)
64
+ - [Provider Settings](#provider-settings)
65
+ - [Model & Provider Switcher](#model--provider-switcher)
66
+ - [Session Launch Progress](#session-launch-progress)
67
+ - [Onboarding Wizard](#onboarding-wizard)
68
+ - [Monaco Code Editor](#monaco-code-editor)
69
+ - [Files Panel](#files-panel)
70
+ - [Recording Hub](#recording-hub)
71
+ - [Protocol Monitor](#protocol-monitor)
72
+ - [Commands Discovery](#commands-discovery)
73
+ - [Proactive Keepalive](#proactive-keepalive)
74
+ - [Security Headers & Rate Limiting](#security-headers--rate-limiting)
75
+ - [WebSocket Authentication](#websocket-authentication)
76
+ - [Architecture](#architecture)
77
+ - [Docker Deployment](#docker-deployment)
78
+ - [CLI Reference](#cli-reference)
79
+ - [REST API Reference](#rest-api-reference)
80
+ - [WebSocket Protocol](#websocket-protocol)
81
+ - [Development](#development)
82
+ - [License](#license)
83
+
84
+ ---
85
+
86
+ ## Quick Start
87
+
88
+ There are three ways to run Campfire: from npm, from source, or with Docker.
89
+
90
+ ### Option 1: npm (fastest)
91
+
92
+ If you just want to run Campfire without cloning the repo:
93
+
94
+ ```bash
95
+ # Install Bun if you don't have it
96
+ curl -fsSL https://bun.sh/install | bash
97
+
98
+ # Run Campfire (downloads and starts automatically)
99
+ bunx the-campfire
100
+ ```
101
+
102
+ Open [http://localhost:4567](http://localhost:4567). That's it.
103
+
104
+ To run on a different port:
105
+
106
+ ```bash
107
+ bunx the-campfire --port 8080
108
+ ```
109
+
110
+ ### Option 2: Run from source (native)
111
+
112
+ Clone the repository and run directly with Bun:
113
+
114
+ ```bash
115
+ # 1. Clone the repo
116
+ git clone https://github.com/stretchcloud/campfire.git
117
+ cd campfire
118
+
119
+ # 2. Install dependencies
120
+ cd web
121
+ bun install
122
+
123
+ # 3. Build and start
124
+ bun run build
125
+ bun run start
126
+ ```
127
+
128
+ Open [http://localhost:4567](http://localhost:4567). That's it.
129
+
130
+ > **Contributing?** Use `bun run dev` for hot reload during frontend development. See the [Development](#development) section for details.
131
+
132
+ ### Option 3: Docker
133
+
134
+ Pull the pre-built image from the GitHub Container Registry (no clone, no build):
135
+
136
+ ```bash
137
+ docker run -d \
138
+ --name campfire \
139
+ -p 4567:4567 \
140
+ -v campfire-data:/home/campfire/.campfire \
141
+ --restart unless-stopped \
142
+ ghcr.io/stretchcloud/campfire:latest
143
+ ```
144
+
145
+ Open [http://localhost:4567](http://localhost:4567). Pin a specific version by tag instead of `latest`, e.g. `ghcr.io/stretchcloud/campfire:0.2.1`.
146
+
147
+ Or build and run from source with Docker Compose (no Bun installation needed):
148
+
149
+ ```bash
150
+ # 1. Clone the repo
151
+ git clone https://github.com/stretchcloud/campfire.git
152
+ cd campfire
153
+
154
+ # 2. Build and start the container
155
+ docker compose up
156
+
157
+ # Or build and run in the background
158
+ docker compose up -d
159
+ ```
160
+
161
+ Open [http://localhost:4567](http://localhost:4567).
162
+
163
+ To build the Docker image manually without Compose:
164
+
165
+ ```bash
166
+ # Build the image
167
+ docker build -t campfire:latest .
168
+
169
+ # Run the container
170
+ docker run -d \
171
+ --name campfire \
172
+ -p 4567:4567 \
173
+ -v campfire-data:/home/campfire/.campfire \
174
+ --restart unless-stopped \
175
+ campfire:latest
176
+ ```
177
+
178
+ To stop and remove:
179
+
180
+ ```bash
181
+ # Docker Compose
182
+ docker compose down
183
+
184
+ # Or manual
185
+ docker stop campfire && docker rm campfire
186
+ ```
187
+
188
+ See [Docker Deployment](#docker-deployment) for advanced configuration (mounting agent CLIs, reverse proxy, environment variables).
189
+
190
+ ### Requirements
191
+
192
+ **For native (npm or source):**
193
+ - [Bun](https://bun.sh) >= 1.0
194
+ - At least one agent CLI installed and on your `PATH`:
195
+ - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) — `npm install -g @anthropic-ai/claude-code`
196
+ - [Codex](https://github.com/openai/codex) — `npm install -g @openai/codex`
197
+ - [Goose](https://github.com/block/goose) — `brew install goose` or see [docs](https://github.com/block/goose)
198
+ - [Aider](https://aider.chat) — `pip install aider-chat`
199
+ - [OpenHands](https://github.com/All-Hands-AI/OpenHands) — see [docs](https://github.com/All-Hands-AI/OpenHands)
200
+ - [OpenClaw](https://github.com/anomalyco/openclaw) — `openclaw` binary on `PATH`, set `OPENCLAW_GATEWAY_TOKEN` and `OPENCLAW_GATEWAY_URL`
201
+ - [OpenCode](https://github.com/anomalyco/opencode) — `opencode` binary on `PATH`
202
+
203
+ **For Docker:**
204
+ - [Docker](https://docs.docker.com/get-docker/) >= 20.0
205
+ - Agent CLIs are **not** included in the Docker image — see [Running with Agent CLIs](#running-with-agent-CLIs) for how to mount or install them
206
+
207
+ ---
208
+
209
+ ## Features
210
+
211
+ ### Multi-Agent Sessions
212
+
213
+ Run parallel sessions across seven agent backends from a single browser tab. Each session streams output, tool calls, and results in a unified timeline. The frontend is completely backend-agnostic — it renders the same UI regardless of which agent is running.
214
+
215
+ **Supported backends:**
216
+
217
+ | Backend | Protocol | How it connects |
218
+ |---------|----------|-----------------|
219
+ | Claude Code | NDJSON over WebSocket | Spawned with `--sdk-url` flag |
220
+ | Codex | JSON-RPC over stdio | Spawned as `codex app-server` |
221
+ | Goose | JSON-RPC 2.0 (ACP) over stdio | Spawned as `goose acp --with-builtin developer --with-builtin memory` |
222
+ | Aider | stdout parsing over stdio | Spawned as `aider --no-pretty --yes --no-auto-commits` |
223
+ | OpenHands | JSON-RPC 2.0 (ACP) over stdio | Spawned as `openhands acp` |
224
+ | OpenClaw | JSON-RPC 2.0 (ACP) over stdio | Spawned as `openclaw acp`; requires `OPENCLAW_GATEWAY_TOKEN` + `OPENCLAW_GATEWAY_URL` |
225
+ | OpenCode | JSON-RPC 2.0 (ACP) over stdio | Spawned as `opencode acp`; model set via `OPENCODE_MODEL` |
226
+
227
+ **Creating a session:**
228
+
229
+ 1. Click **New Session** in the sidebar
230
+ 2. Choose a backend (Claude Code, Codex, Goose, Aider, OpenHands, OpenClaw, or OpenCode)
231
+ 3. Select a model (backend-specific model lists)
232
+ 4. Set the working directory for the session
233
+ 5. Optionally choose a permission mode, environment profile, or git branch
234
+ 6. Click **Create**
235
+
236
+ **Session options:**
237
+
238
+ | Option | Description |
239
+ |--------|-------------|
240
+ | Backend | Which agent CLI to use |
241
+ | Model | AI model to run (e.g. `claude-sonnet-4-5-20250929`, `o3`, `gpt-4.1`) |
242
+ | Permission mode | `default`, `bypassPermissions`, `oneTouchApprovals`, `manualApprovals` |
243
+ | Working directory | Folder the agent operates in |
244
+ | Environment profile | Pre-saved set of environment variables to inject |
245
+ | Git branch | Check out a specific branch before starting |
246
+ | Use worktree | Create an isolated git worktree (keeps branches separate) |
247
+ | Create branch | Create the branch if it doesn't exist |
248
+ | Docker container | Run the session inside a Docker container (Claude only) |
249
+ | Internet access | Enable web search for Codex |
250
+ | Allowed tools | Restrict which tools the agent can use |
251
+
252
+ **Session lifecycle:**
253
+
254
+ - **Running** — agent is processing, streaming output
255
+ - **Idle** — agent is waiting for input
256
+ - **Compacting** — agent is compacting context (Claude Code)
257
+ - **Exited** — agent process has stopped
258
+
259
+ Sessions persist to disk and survive server restarts. When the server restarts, running CLI processes are detected by PID and given a grace period to reconnect. If they don't, they're killed and relaunched with `--resume`.
260
+
261
+ **Managing sessions:**
262
+
263
+ - **Rename** — click the session name in the sidebar to edit inline
264
+ - **Kill** — stop the running agent process
265
+ - **Relaunch** — restart a stopped session (uses `--resume` for Claude Code)
266
+ - **Archive** — hide the session from the active list while preserving history
267
+ - **Delete** — permanently remove the session (also cleans up worktrees and containers)
268
+
269
+ ---
270
+
271
+ ### Real-Time Collaboration
272
+
273
+ Share any session with teammates using invite links. Multiple people can watch and interact with the same session simultaneously.
274
+
275
+ **How to share a session:**
276
+
277
+ 1. Open a running session
278
+ 2. Click the **Share** button in the top bar
279
+ 3. Choose a role for the invited user:
280
+ - **Collaborator** — can send messages and vote on permissions
281
+ - **Spectator** — watch-only (cannot send messages or vote)
282
+ 4. Copy the generated link and share it
283
+
284
+ The invite link looks like `http://localhost:4567/#/join/<token>`. When someone opens it, they join the session with the assigned role. **Invite links expire after 24 hours** — they are bearer credentials that bypass password auth, so generate a fresh one when you need to re-share.
285
+
286
+ **Presence indicators:**
287
+
288
+ Connected users appear as colored avatars in the top bar:
289
+ - **Blue** — Owner (the person who created the session)
290
+ - **Green** — Collaborator (can interact)
291
+ - **Gray** — Spectator (watch-only)
292
+
293
+ Presence updates are broadcast in real time — you see when someone joins or leaves.
294
+
295
+ **Roles and permissions:**
296
+
297
+ | Capability | Owner | Collaborator | Spectator |
298
+ |-----------|-------|--------------|-----------|
299
+ | View session output | Yes | Yes | Yes |
300
+ | Send messages | Yes | Yes | No |
301
+ | Approve/deny permissions | Yes | Yes | No |
302
+ | Vote on tool calls | Yes | Yes | No |
303
+ | Interrupt the agent | Yes | Yes | No |
304
+ | Change model or mode | Yes | Yes | No |
305
+ | Configure MCP servers | Yes | Yes | No |
306
+
307
+ The first browser to connect to a session becomes the **Owner**. Subsequent connections default to **Collaborator** unless they join via a spectator invite link.
308
+
309
+ ---
310
+
311
+ ### Permission Control & Voting
312
+
313
+ Every risky tool call (file writes, bash commands, etc.) surfaces a permission banner at the top of the chat. The banner shows what the agent wants to do and lets you approve, deny, or apply a permission rule.
314
+
315
+ **Permission banner displays:**
316
+
317
+ | Tool | What you see |
318
+ |------|-------------|
319
+ | Bash | The exact command with `$` prefix |
320
+ | Edit | Side-by-side diff showing old vs new content |
321
+ | Write | The full file content being written |
322
+ | Read | The file path being read |
323
+ | Glob / Grep | The search pattern and path |
324
+ | AskUserQuestion | Multiple-choice options with a custom text input |
325
+
326
+ **Actions available:**
327
+
328
+ - **Allow** — approve this specific tool call
329
+ - **Deny** — reject this tool call
330
+ - **Permission suggestions** — apply a broader rule (e.g. "Allow for session", "Allow always", "Trust directory")
331
+
332
+ **Voting (collaborative sessions):**
333
+
334
+ When multiple viewers are connected, permission requests become votes. The voting behavior is configurable:
335
+
336
+ | Policy | How it works |
337
+ |--------|-------------|
338
+ | `majority-rules` | Action is allowed if more than half vote "allow" (default) |
339
+ | `any-deny-blocks` | A single "deny" vote blocks the action |
340
+ | `owner-decides` | Only the owner's vote counts |
341
+
342
+ Configure the voting policy via the UI or API:
343
+
344
+ ```bash
345
+ # Get current policy
346
+ curl http://localhost:4567/api/voting-policy
347
+
348
+ # Change policy
349
+ curl -X PUT http://localhost:4567/api/voting-policy \
350
+ -H "Content-Type: application/json" \
351
+ -d '{"policy": "any-deny-blocks"}'
352
+ ```
353
+
354
+ Votes have a **30-second deadline**. If the deadline passes, the vote resolves based on collected votes. The UI shows a countdown timer, current vote tally, and voter avatars.
355
+
356
+ ---
357
+
358
+ ### Session Replay
359
+
360
+ Scrub through completed sessions at 1x / 2x / 4x / 8x speed. Every tool call, permission decision, and streaming token is preserved in protocol recordings.
361
+
362
+ **How to use replay:**
363
+
364
+ 1. Open a completed session from the sidebar
365
+ 2. Click the **Recordings** section to see available recording files
366
+ 3. Click a recording to open the replay player
367
+ 4. Use the playback controls to play, pause, and change speed
368
+
369
+ **Replay controls:**
370
+ - Play / Pause toggle
371
+ - Speed selector: 1x, 2x, 4x, 8x
372
+ - Progress scrubber for seeking
373
+
374
+ **Recording format:**
375
+
376
+ Recordings are stored as JSONL (newline-delimited JSON) files in `~/.campfire/recordings/`. Each line captures the exact raw message as it was sent or received:
377
+
378
+ ```json
379
+ {"ts": 1771153996875, "dir": "in", "raw": "{\"type\":\"system\",...}", "ch": "cli"}
380
+ ```
381
+
382
+ - `ts` — Unix timestamp in milliseconds
383
+ - `dir` — `"in"` (received by server) or `"out"` (sent by server)
384
+ - `ch` — `"cli"` (agent process) or `"browser"` (frontend)
385
+ - `raw` — exact original message string, never re-serialized
386
+
387
+ **Recording management:**
388
+
389
+ ```bash
390
+ # List all recordings
391
+ curl http://localhost:4567/api/recordings
392
+
393
+ # Check if a session is being recorded
394
+ curl http://localhost:4567/api/sessions/:id/recording/status
395
+
396
+ # Start/stop recording for a specific session
397
+ curl -X POST http://localhost:4567/api/sessions/:id/recording/start
398
+ curl -X POST http://localhost:4567/api/sessions/:id/recording/stop
399
+ ```
400
+
401
+ Recording is enabled by default. Disable globally with `CAMPFIRE_RECORD=0`. Files auto-rotate when total lines exceed 100,000 (configurable with `CAMPFIRE_RECORDINGS_MAX_LINES`).
402
+
403
+ ---
404
+
405
+ ### Fork & Branch
406
+
407
+ Fork any session at any point in its conversation to explore a different path. Forks create a new session with the message history up to the fork point, optionally on a new git worktree.
408
+
409
+ **How to fork:**
410
+
411
+ 1. **From the top bar** — click the **Fork** button to fork at the current point
412
+ 2. **From any message** — hover over a message and click the fork icon to fork from that specific point
413
+
414
+ **What happens when you fork:**
415
+
416
+ 1. The message history is copied up to the selected point
417
+ 2. If the session is in a git repository, a new worktree is created for isolation
418
+ 3. A new session is launched with the copied history
419
+ 4. The forked session shows a "forked from" indicator linking back to the original
420
+
421
+ **Fork options:**
422
+
423
+ ```bash
424
+ curl -X POST http://localhost:4567/api/sessions/:id/fork \
425
+ -H "Content-Type: application/json" \
426
+ -d '{
427
+ "messageIndex": 5,
428
+ "model": "claude-sonnet-4-5-20250929",
429
+ "permissionMode": "bypassPermissions",
430
+ "branch": "experiment/new-approach"
431
+ }'
432
+ ```
433
+
434
+ | Field | Description |
435
+ |-------|-------------|
436
+ | `messageIndex` | Fork after this message (0-indexed). Omit to fork at the end. |
437
+ | `model` | Override the model for the forked session |
438
+ | `permissionMode` | Override permission mode |
439
+ | `branch` | Git branch name for the worktree |
440
+
441
+ ---
442
+
443
+ ### Session Gallery
444
+
445
+ Publish your best sessions to a gallery that anyone on your Campfire instance can browse. Gallery entries include session metadata, cost, duration, and a direct link to replay.
446
+
447
+ **How to publish:**
448
+
449
+ 1. Navigate to the **Gallery** page from the sidebar
450
+ 2. Click **Add to Gallery**
451
+ 3. Select a completed session
452
+ 4. Add a name, description, and tags
453
+ 5. Click **Publish**
454
+
455
+ **Browsing the gallery:**
456
+
457
+ The gallery supports filtering and sorting:
458
+
459
+ | Filter | Example |
460
+ |--------|---------|
461
+ | Backend | Show only Claude Code sessions |
462
+ | Cost range | Sessions between $0.01 and $1.00 |
463
+ | Tags | Filter by `migration`, `refactor`, `bugfix`, etc. |
464
+ | Featured only | Show only featured entries |
465
+
466
+ | Sort by | Description |
467
+ |---------|-------------|
468
+ | Votes | Most upvoted first |
469
+ | Recent | Newest first |
470
+ | Cost | Cheapest or most expensive first |
471
+ | Duration | Shortest or longest first |
472
+
473
+ **Voting and featuring:**
474
+
475
+ - Click the up/down arrows on any gallery card to vote (anonymous, IP-deduplicated)
476
+ - Admins can toggle the **Featured** star to highlight exceptional sessions
477
+
478
+ **Gallery entry metadata:**
479
+
480
+ Each entry captures a snapshot of the session at publish time: backend type, model, total cost, duration, lines added/removed, and number of turns. Click **View Replay** on any card to watch the session.
481
+
482
+ **Public share links:**
483
+
484
+ Generate a tokenized public replay link for any gallery entry (`POST /api/gallery/:id/public-link`). Anyone with the link can watch the session replay at `#/public-replay/<token>` — no login required, no app chrome, read-only.
485
+
486
+ **ClawHub export:**
487
+
488
+ Gallery entries can be exported as ClawHub-compatible skills (`SKILL.md` with stats and a replay link) and published via the `clawhub` CLI. Browse and install shared skills from the **ClawHub** page (`#/clawhub`) in the sidebar.
489
+
490
+ **Moltbook posting:**
491
+
492
+ Entries can also be posted as "molts" to [Moltbook](https://moltbook.com), a social network for AI agents (`POST /api/gallery/:id/post-moltbook`; configure the agent account in Settings).
493
+
494
+ ```bash
495
+ # List gallery entries with filters
496
+ curl "http://localhost:4567/api/gallery?backend=claude&sortBy=votes&featured=true"
497
+
498
+ # Publish a session
499
+ curl -X POST http://localhost:4567/api/gallery \
500
+ -H "Content-Type: application/json" \
501
+ -d '{
502
+ "sessionId": "abc-123",
503
+ "name": "Migrated auth to OAuth2",
504
+ "description": "Full migration from session-based auth to OAuth2 with PKCE",
505
+ "tags": ["migration", "auth", "oauth"]
506
+ }'
507
+
508
+ # Vote on an entry
509
+ curl -X POST http://localhost:4567/api/gallery/:id/vote \
510
+ -H "Content-Type: application/json" \
511
+ -d '{"direction": 1}'
512
+
513
+ # Toggle featured status
514
+ curl -X POST http://localhost:4567/api/gallery/:id/feature
515
+ ```
516
+
517
+ ---
518
+
519
+ ### Prompt Library
520
+
521
+ Save reusable prompt snippets and insert them into any message with `@` in the composer. Prompts can be scoped globally or to a specific project directory.
522
+
523
+ **How to create a prompt:**
524
+
525
+ 1. Navigate to the **Prompts** page from the sidebar
526
+ 2. Click **+ New Prompt**
527
+ 3. Enter a name and the prompt text
528
+ 4. Choose scope: **Global** (available everywhere) or **Project** (scoped to a path prefix)
529
+ 5. Click **Save**
530
+
531
+ **Inserting prompts in the composer:**
532
+
533
+ Type `@` in the message box to open the prompt picker. Start typing to filter by name or content. Use Arrow keys to navigate, Tab or Enter to insert.
534
+
535
+ The full content of the selected prompt replaces the `@query` in your message, so you can mix prompt snippets with your own text.
536
+
537
+ **CWD-scoped loading:**
538
+
539
+ The prompt picker automatically filters prompts based on the current session's working directory. When you switch sessions with different working directories, the prompt list refreshes to show only prompts relevant to that project. Global prompts are always available regardless of the working directory.
540
+
541
+ **REST API:**
542
+
543
+ ```bash
544
+ # List prompts (optionally filtered by cwd)
545
+ curl "http://localhost:4567/api/prompts?cwd=/home/user/my-project"
546
+
547
+ # Create a prompt
548
+ curl -X POST http://localhost:4567/api/prompts \
549
+ -H "Content-Type: application/json" \
550
+ -d '{
551
+ "name": "Code review checklist",
552
+ "content": "Please review for: 1) correctness, 2) edge cases, 3) performance, 4) test coverage",
553
+ "scope": "global"
554
+ }'
555
+
556
+ # Update a prompt
557
+ curl -X PUT http://localhost:4567/api/prompts/:id \
558
+ -H "Content-Type: application/json" \
559
+ -d '{"name": "Updated name", "content": "Updated content"}'
560
+
561
+ # Delete a prompt
562
+ curl -X DELETE http://localhost:4567/api/prompts/:id
563
+ ```
564
+
565
+ Prompts are stored at `~/.campfire/prompts.json`.
566
+
567
+ ---
568
+
569
+ ### Linear Integration
570
+
571
+ Connect your Linear workspace to manage issues end-to-end: browse and search issues, link them to sessions, auto-generate branch names, map projects to repositories, and auto-transition issue state when work begins.
572
+
573
+ **Setup:**
574
+
575
+ 1. Navigate to **Integrations** → **Linear** from the sidebar
576
+ 2. Create a personal API key at `linear.app/settings/api`
577
+ 3. Paste your key and click **Connect**
578
+
579
+ **What it enables:**
580
+
581
+ - Browse and search Linear issues when creating a new session
582
+ - Auto-generate a recommended git branch name from the issue (e.g. `feat/eng-123-add-auth`)
583
+ - Link issues to sessions — track which issue each session is working on
584
+ - Map Linear teams/projects to git repositories for automatic filtering
585
+ - Auto-transition issues to "In Progress" when a linked session starts
586
+
587
+ **Project-repo mapping:**
588
+
589
+ When you first use Linear in a git repository, Campfire prompts you to link the repo to a Linear team. Once linked, issue searches are automatically filtered to that team. Mappings are stored in `~/.campfire/linear-projects.json`.
590
+
591
+ **Issue-session workflow:**
592
+
593
+ 1. Open the **New Session** page in a git repo with a linked Linear team
594
+ 2. The **Linear Issues** section appears automatically
595
+ 3. Search for an issue by title or identifier
596
+ 4. Select an issue — a branch name is auto-generated (e.g. `feat/ENG-123-add-oauth-flow`)
597
+ 5. The worktree toggle activates with the generated branch name
598
+ 6. Create the session — the issue is linked and transitions to "In Progress"
599
+
600
+ **REST API:**
601
+
602
+ ```bash
603
+ # Check connection status
604
+ curl http://localhost:4567/api/linear/connection
605
+ # → {"connected": true, "viewer": {"name": "...", "email": "..."}, "teams": [...]}
606
+
607
+ # Search issues (cached, deduplicated)
608
+ curl "http://localhost:4567/api/linear/issues?query=auth&limit=10"
609
+
610
+ # List teams
611
+ curl http://localhost:4567/api/linear/teams
612
+
613
+ # Get workflow states for a team
614
+ curl http://localhost:4567/api/linear/team/:teamId/states
615
+
616
+ # Project-repo mapping
617
+ curl http://localhost:4567/api/linear/project-mapping?repoRoot=/path/to/repo
618
+ curl -X POST http://localhost:4567/api/linear/project-mapping \
619
+ -H "Content-Type: application/json" \
620
+ -d '{"repoRoot": "/path/to/repo", "teamId": "...", "teamKey": "ENG", "teamName": "Engineering"}'
621
+ curl -X DELETE http://localhost:4567/api/linear/project-mapping \
622
+ -H "Content-Type: application/json" \
623
+ -d '{"repoRoot": "/path/to/repo"}'
624
+
625
+ # Link an issue to a session
626
+ curl -X POST http://localhost:4567/api/linear/session/:sessionId/link-issue \
627
+ -H "Content-Type: application/json" \
628
+ -d '{"issueId": "...", "identifier": "ENG-123", "title": "Add OAuth", "url": "...", "state": "Todo", "teamKey": "ENG"}'
629
+
630
+ # Get linked issue for a session
631
+ curl http://localhost:4567/api/linear/session/:sessionId/issue
632
+
633
+ # Transition an issue's state
634
+ curl -X POST http://localhost:4567/api/linear/issues/:issueId/transition \
635
+ -H "Content-Type: application/json" \
636
+ -d '{"stateId": "..."}'
637
+ ```
638
+
639
+ **Caching:**
640
+
641
+ Linear API responses are cached with a 60-second TTL to reduce API calls. Concurrent identical requests are deduplicated — only one GraphQL call is made, and all callers receive the same result.
642
+
643
+ **Data storage:**
644
+
645
+ | File | Contents |
646
+ |------|----------|
647
+ | `~/.campfire/settings.json` | Linear API key (never exposed via GET) |
648
+ | `~/.campfire/linear-projects.json` | Repo → team/project mappings |
649
+ | `~/.campfire/linear-session-issues.json` | Session → issue links |
650
+
651
+ ---
652
+
653
+ ### Webhooks
654
+
655
+ Receive HTTP POST notifications when events happen in your sessions. Configure webhooks with event filters, HMAC-SHA256 signing, and automatic retries.
656
+
657
+ **Inbound (OpenClaw):** Campfire also accepts inbound calls — `POST /api/webhooks/openclaw` (token-guarded) spawns an OpenClaw session from an external trigger, and `POST /api/openclaw/inbound` delivers agent messages from the OpenClaw channel plugin into an existing session.
658
+
659
+ **How to set up a webhook:**
660
+
661
+ 1. Navigate to the **Webhooks** page from the sidebar
662
+ 2. Click **Create Webhook**
663
+ 3. Enter the destination URL
664
+ 4. Select which events to subscribe to
665
+ 5. Optionally add a signing secret and session filters
666
+ 6. Click **Create**
667
+
668
+ **Available events:**
669
+
670
+ | Event | When it fires |
671
+ |-------|---------------|
672
+ | `session.created` | A new session starts |
673
+ | `session.completed` | A session finishes successfully |
674
+ | `session.failed` | A session exits with an error |
675
+ | `permission.requested` | An agent requests permission for a tool call |
676
+ | `permission.resolved` | A permission request is approved or denied |
677
+ | `turn.completed` | An agent completes a turn (each back-and-forth) |
678
+ | `cost.threshold` | Session cost crosses a threshold |
679
+
680
+ **Payload format:**
681
+
682
+ ```json
683
+ {
684
+ "event": "session.completed",
685
+ "timestamp": 1771153996875,
686
+ "sessionId": "abc-123",
687
+ "data": {
688
+ "backendType": "claude",
689
+ "model": "claude-sonnet-4-5-20250929",
690
+ "totalCostUsd": 0.42,
691
+ "numTurns": 12,
692
+ "durationMs": 180000
693
+ }
694
+ }
695
+ ```
696
+
697
+ **HMAC-SHA256 signing:**
698
+
699
+ If you provide a `secret`, every delivery includes an `X-Campfire-Signature` header:
700
+
701
+ ```
702
+ X-Campfire-Signature: sha256=<hex-encoded-hmac>
703
+ ```
704
+
705
+ Verify the signature on your server by computing `HMAC-SHA256(secret, request_body)` and comparing.
706
+
707
+ **Retry behavior:**
708
+
709
+ Failed deliveries are retried 3 times with exponential backoff: 1s, 5s, 15s. Delivery stats (total, failed, last delivery time) are tracked per webhook.
710
+
711
+ **Session filters:**
712
+
713
+ Narrow a webhook to specific sessions by backend type or working directory:
714
+
715
+ ```json
716
+ {
717
+ "sessionFilter": {
718
+ "backendType": "claude",
719
+ "cwd": "/home/user/my-project"
720
+ }
721
+ }
722
+ ```
723
+
724
+ **Slack integration:**
725
+
726
+ Webhook payloads include Slack-compatible formatting. Point a webhook at a Slack incoming webhook URL and events will render as formatted messages.
727
+
728
+ **Testing:**
729
+
730
+ Click the **Test** button on any webhook to send a test payload and verify your endpoint is receiving events correctly.
731
+
732
+ ```bash
733
+ # Create a webhook
734
+ curl -X POST http://localhost:4567/api/webhooks \
735
+ -H "Content-Type: application/json" \
736
+ -d '{
737
+ "name": "Slack Alerts",
738
+ "url": "https://hooks.slack.com/services/...",
739
+ "events": ["session.completed", "session.failed", "cost.threshold"],
740
+ "secret": "my-signing-secret",
741
+ "enabled": true
742
+ }'
743
+
744
+ # Test delivery
745
+ curl -X POST http://localhost:4567/api/webhooks/:id/test
746
+
747
+ # Toggle enable/disable
748
+ curl -X POST http://localhost:4567/api/webhooks/:id/toggle
749
+ ```
750
+
751
+ ---
752
+
753
+ ### Scheduled Tasks (Cron)
754
+
755
+ Run autonomous agent sessions on a schedule — daily test suites, nightly code reviews, weekly dependency updates, or one-shot migration scripts.
756
+
757
+ **How to create a scheduled task:**
758
+
759
+ 1. Navigate to the **Scheduled** page from the sidebar
760
+ 2. Click **Create Job**
761
+ 3. Fill in the form:
762
+ - **Name** — human-readable label (e.g. "Nightly Test Suite")
763
+ - **Prompt** — the instruction to send to the agent
764
+ - **Schedule** — cron expression (`0 2 * * *`) or ISO datetime for one-shot
765
+ - **Backend** — which agent to use
766
+ - **Model** — which model to run
767
+ - **Working directory** — where to run
768
+ - **Permission mode** — typically `bypassPermissions` for autonomous execution
769
+ - **Environment profile** — optional API keys and variables
770
+ 4. Click **Create**
771
+
772
+ **Cron expression examples:**
773
+
774
+ | Expression | Meaning |
775
+ |-----------|---------|
776
+ | `0 2 * * *` | Every day at 2:00 AM |
777
+ | `0 9 * * 1` | Every Monday at 9:00 AM |
778
+ | `*/30 * * * *` | Every 30 minutes |
779
+ | `0 0 1 * *` | First day of every month at midnight |
780
+
781
+ **One-shot tasks:**
782
+
783
+ Set `recurring: false` and provide an ISO datetime as the schedule (e.g. `2025-12-31T23:59:00Z`). The job runs once at that time and auto-disables.
784
+
785
+ **Execution tracking:**
786
+
787
+ Each execution creates a session and tracks:
788
+ - Start time and completion time
789
+ - Success or failure status
790
+ - Cost incurred
791
+ - Link to the session for full replay
792
+
793
+ Jobs auto-disable after repeated consecutive failures to prevent runaway costs.
794
+
795
+ **Managing jobs:**
796
+
797
+ ```bash
798
+ # List all jobs
799
+ curl http://localhost:4567/api/cron/jobs
800
+
801
+ # Create a recurring job
802
+ curl -X POST http://localhost:4567/api/cron/jobs \
803
+ -H "Content-Type: application/json" \
804
+ -d '{
805
+ "name": "Nightly Tests",
806
+ "prompt": "Run the full test suite and fix any failures",
807
+ "schedule": "0 2 * * *",
808
+ "recurring": true,
809
+ "backendType": "claude",
810
+ "model": "claude-sonnet-4-5-20250929",
811
+ "cwd": "/home/user/my-project",
812
+ "permissionMode": "bypassPermissions"
813
+ }'
814
+
815
+ # Manually trigger a job
816
+ curl -X POST http://localhost:4567/api/cron/jobs/:id/run
817
+
818
+ # Enable/disable
819
+ curl -X POST http://localhost:4567/api/cron/jobs/:id/toggle
820
+
821
+ # View execution history
822
+ curl http://localhost:4567/api/cron/jobs/:id/executions
823
+ ```
824
+
825
+ ---
826
+
827
+ ### Adapter Registry
828
+
829
+ Install community agent adapters from npm to add new backends to Campfire. Adapters are npm packages with a `campfireAdapter` field in their `package.json`.
830
+
831
+ > **Related:** you can also run [MetaHarness](https://github.com/ruvnet/metaharness)-generated agent harnesses inside Campfire sessions — their MCP servers attach at runtime and their tool calls go through Campfire's permission-voting UI. See [docs/integrations/metaharness.md](docs/integrations/metaharness.md).
832
+
833
+ **Installing an adapter:**
834
+
835
+ ```bash
836
+ # Via CLI
837
+ the-campfire install-adapter @campfire/example-adapter
838
+
839
+ # Via API
840
+ curl -X POST http://localhost:4567/api/adapters/install \
841
+ -H "Content-Type: application/json" \
842
+ -d '{"npmPackage": "@campfire/example-adapter"}'
843
+ ```
844
+
845
+ Once installed, the adapter appears as a new backend option when creating sessions.
846
+
847
+ **Managing adapters in the UI:**
848
+
849
+ 1. Navigate to the **Adapters** page from the sidebar
850
+ 2. View installed adapters with their metadata (name, version, protocol, models)
851
+ 3. Install new adapters by entering the npm package name
852
+ 4. Uninstall adapters with the remove button
853
+
854
+ **Adapter metadata:**
855
+
856
+ Each adapter's `package.json` must include:
857
+
858
+ ```json
859
+ {
860
+ "campfireAdapter": {
861
+ "name": "my-agent",
862
+ "displayName": "My Agent",
863
+ "binaryName": "my-agent-cli",
864
+ "protocol": "stdio",
865
+ "models": [
866
+ { "value": "model-v1", "label": "Model V1" }
867
+ ],
868
+ "modes": [
869
+ { "value": "default", "label": "Default" }
870
+ ]
871
+ }
872
+ }
873
+ ```
874
+
875
+ **Writing your own adapter:**
876
+
877
+ See [`web/server/ADAPTERS.md`](web/server/ADAPTERS.md) for a step-by-step guide. Adapters implement the `AgentAdapter` interface with methods for sending/receiving messages, session metadata, and disconnection handling.
878
+
879
+ ```bash
880
+ # List installed adapters
881
+ curl http://localhost:4567/api/adapters
882
+
883
+ # Uninstall
884
+ curl -X DELETE http://localhost:4567/api/adapters/my-agent
885
+ ```
886
+
887
+ ---
888
+
889
+ ### Cost Dashboard
890
+
891
+ Every session tracks API costs in real time. The cost is displayed in the top bar during a session and in the session details panel.
892
+
893
+ **What's tracked:**
894
+
895
+ - Total cost in USD per session
896
+ - Number of turns (back-and-forth exchanges)
897
+ - Context usage percentage (how much of the context window is used)
898
+ - Lines added and removed
899
+ - Session duration
900
+
901
+ **Shareable cost cards:**
902
+
903
+ When a session completes, a cost card is generated as a downloadable PNG image containing the session name, cost, duration, turns, model, and backend type — with Campfire branding. Share these cards to show off your results.
904
+
905
+ **Cost information in the UI:**
906
+
907
+ - **Top bar** — live cost ticker during active sessions
908
+ - **Task panel** — detailed stats (cost, turns, context %, lines changed, duration)
909
+ - **Gallery cards** — cost displayed on each published session
910
+
911
+ ---
912
+
913
+ ### Environment Profiles
914
+
915
+ Save named sets of environment variables and inject them into agent sessions. This is useful for managing API keys, database URLs, and other secrets across different projects.
916
+
917
+ **How to use:**
918
+
919
+ 1. Navigate to the **Environments** page from the sidebar
920
+ 2. Click **Create Profile**
921
+ 3. Enter a name (e.g. "Production", "Staging")
922
+ 4. Add key-value pairs for your environment variables
923
+ 5. Click **Save**
924
+
925
+ When creating a session, select an environment profile from the dropdown. All variables from that profile are injected into the agent's environment.
926
+
927
+ **Profile structure:**
928
+
929
+ ```json
930
+ {
931
+ "name": "Production",
932
+ "slug": "production",
933
+ "variables": {
934
+ "ANTHROPIC_API_KEY": "sk-ant-...",
935
+ "DATABASE_URL": "postgres://prod-host/db",
936
+ "REDIS_URL": "redis://prod-redis:6379"
937
+ }
938
+ }
939
+ ```
940
+
941
+ Profiles are stored as individual JSON files in `~/.campfire/envs/`.
942
+
943
+ ```bash
944
+ # List profiles
945
+ curl http://localhost:4567/api/envs
946
+
947
+ # Create a profile
948
+ curl -X POST http://localhost:4567/api/envs \
949
+ -H "Content-Type: application/json" \
950
+ -d '{
951
+ "name": "Staging",
952
+ "variables": {
953
+ "API_KEY": "sk-staging-...",
954
+ "DEBUG": "true"
955
+ }
956
+ }'
957
+
958
+ # Update a profile
959
+ curl -X PUT http://localhost:4567/api/envs/staging \
960
+ -H "Content-Type: application/json" \
961
+ -d '{"variables": {"API_KEY": "sk-new-key", "DEBUG": "false"}}'
962
+
963
+ # Delete a profile
964
+ curl -X DELETE http://localhost:4567/api/envs/staging
965
+ ```
966
+
967
+ ---
968
+
969
+ ### Git Integration
970
+
971
+ Campfire tracks git state for every session and provides tools for branch and worktree management.
972
+
973
+ **What's tracked per session:**
974
+
975
+ - Current branch name
976
+ - Ahead/behind counts relative to the remote
977
+ - Whether the session is in a worktree
978
+ - Total lines added and removed (from tool calls)
979
+ - Repository root path
980
+
981
+ This information is displayed in the sidebar next to each session and updated in real time.
982
+
983
+ **Worktrees:**
984
+
985
+ Worktrees let you run multiple sessions on different branches without switching branches in your main repo. Each worktree is a separate checkout of your repository.
986
+
987
+ When creating a session with "Use worktree" enabled:
988
+ 1. A new worktree is created for the selected branch
989
+ 2. The session runs in the worktree directory
990
+ 3. A `CLAUDE.md` file is injected with guardrails (e.g. "Stay on this branch")
991
+ 4. When the session is deleted, the worktree is cleaned up if there are no uncommitted changes
992
+
993
+ **GitHub PR status:**
994
+
995
+ If the `gh` CLI is installed and authenticated, Campfire polls for PR metadata on the session's branch:
996
+
997
+ - PR title, number, state (open/closed/merged)
998
+ - Draft status
999
+ - Review decision (approved/changes requested/pending)
1000
+ - CI check status (passing/failing/pending)
1001
+ - Review thread counts (resolved/unresolved)
1002
+
1003
+ PR status is displayed in the task panel and updates automatically.
1004
+
1005
+ ```bash
1006
+ # Get repository info
1007
+ curl "http://localhost:4567/api/git/repo-info?path=/home/user/project"
1008
+
1009
+ # List branches
1010
+ curl "http://localhost:4567/api/git/branches?repoRoot=/home/user/project"
1011
+
1012
+ # Create a worktree
1013
+ curl -X POST http://localhost:4567/api/git/worktree \
1014
+ -H "Content-Type: application/json" \
1015
+ -d '{
1016
+ "repoRoot": "/home/user/project",
1017
+ "branch": "feature/new-feature",
1018
+ "createBranch": true
1019
+ }'
1020
+
1021
+ # Fetch and pull
1022
+ curl -X POST http://localhost:4567/api/git/fetch \
1023
+ -H "Content-Type: application/json" \
1024
+ -d '{"repoRoot": "/home/user/project"}'
1025
+ ```
1026
+
1027
+ ---
1028
+
1029
+ ### Embedded Terminal
1030
+
1031
+ A full PTY terminal is available alongside your sessions. Use it for git operations, running tests, or any other command-line tasks without leaving Campfire.
1032
+
1033
+ **How to use:**
1034
+
1035
+ 1. Click **Terminal** in the sidebar footer
1036
+ 2. A terminal spawns in the configured working directory
1037
+ 3. Type commands as you would in any terminal
1038
+ 4. The terminal supports full ANSI colors, cursor movement, and resize
1039
+
1040
+ The terminal connects via WebSocket (`/ws/terminal/:id`) and supports all standard terminal operations.
1041
+
1042
+ ```bash
1043
+ # Spawn a terminal
1044
+ curl -X POST http://localhost:4567/api/terminal/spawn \
1045
+ -H "Content-Type: application/json" \
1046
+ -d '{"cwd": "/home/user/project", "cols": 120, "rows": 40}'
1047
+
1048
+ # Kill the terminal
1049
+ curl -X POST http://localhost:4567/api/terminal/kill
1050
+ ```
1051
+
1052
+ ---
1053
+
1054
+ ### Protocol Recording
1055
+
1056
+ The server automatically records all raw protocol messages to JSONL files. This captures the exact bytes exchanged between the agent CLI and the server, and between the server and browser clients.
1057
+
1058
+ **Configuration:**
1059
+
1060
+ | Variable | Default | Description |
1061
+ |----------|---------|-------------|
1062
+ | `CAMPFIRE_RECORD` | `1` | Set to `0` or `false` to disable |
1063
+ | `CAMPFIRE_RECORDINGS_DIR` | `~/.campfire/recordings` | Output directory |
1064
+ | `CAMPFIRE_RECORDINGS_MAX_LINES` | `100000` | Auto-rotation threshold |
1065
+
1066
+ **File format:**
1067
+
1068
+ File naming: `{sessionId}_{backendType}_{ISO-timestamp}_{randomSuffix}.jsonl`
1069
+
1070
+ ```jsonl
1071
+ {"ts":1771153996875,"dir":"in","raw":"{\"type\":\"system\",\"subtype\":\"init\",...}","ch":"cli"}
1072
+ {"ts":1771153996900,"dir":"out","raw":"{\"type\":\"session_init\",...}","ch":"browser"}
1073
+ ```
1074
+
1075
+ Recordings are useful for debugging protocol issues, building replay-based tests, and understanding how agents communicate.
1076
+
1077
+ ---
1078
+
1079
+ ### Docker Containers
1080
+
1081
+ Optionally sandbox sessions inside Docker containers for isolation. When enabled, the agent runs inside a container with the working directory mounted at `/workspace`.
1082
+
1083
+ **How it works:**
1084
+
1085
+ 1. When creating a session, click the **Container** toggle in the toolbar
1086
+ 2. Choose a Docker image (default: `campfire-dev:latest`) in the text field that appears
1087
+ 3. Click **Create** — a progress overlay appears showing each step
1088
+ 4. The session runs inside the container with authentication automatically seeded
1089
+
1090
+ **Creation progress overlay:**
1091
+
1092
+ When launching a container session, a step-by-step progress modal appears:
1093
+
1094
+ | Step | What happens |
1095
+ |------|-------------|
1096
+ | Checking image | Verifies if the Docker image exists locally |
1097
+ | Pulling image | Downloads the image if not found (with progress bar showing layer download %) |
1098
+ | Creating container | Creates and starts the Docker container with mounted volumes |
1099
+ | Seeding authentication | Copies `~/.claude/` (for Claude Code) or `~/.codex/` (for Codex) into the container |
1100
+ | Launching agent | Starts the agent process inside the container |
1101
+
1102
+ If any step fails, the overlay shows an error with **Retry** and **Cancel** buttons.
1103
+
1104
+ **Authentication seeding:**
1105
+
1106
+ Campfire automatically copies authentication credentials into containers so agents can authenticate without manual setup:
1107
+
1108
+ - **Claude Code sessions**: `~/.claude/` is copied to `/root/.claude/` inside the container
1109
+ - **Codex sessions**: `~/.codex/` is copied to `/root/.codex/` inside the container
1110
+
1111
+ **Image pull management:**
1112
+
1113
+ Images are checked locally before pulling. Recently pulled images are cached for 30 minutes to skip redundant checks. During a pull, the progress overlay shows per-layer download progress with a percentage bar.
1114
+
1115
+ **Git info inside containers:**
1116
+
1117
+ Campfire resolves git information (branch, ahead/behind, worktree status) from inside the container via `docker exec`, so sidebar session metadata stays accurate even for containerized sessions.
1118
+
1119
+ **SSE creation endpoint:**
1120
+
1121
+ Container session creation uses Server-Sent Events (SSE) for real-time progress reporting:
1122
+
1123
+ ```bash
1124
+ # Create a container session with progress (returns text/event-stream)
1125
+ curl -N -X POST http://localhost:4567/api/sessions/create-with-progress \
1126
+ -H "Content-Type: application/json" \
1127
+ -d '{
1128
+ "backend": "claude",
1129
+ "model": "claude-sonnet-4-5-20250929",
1130
+ "cwd": "/home/user/project",
1131
+ "container": {"image": "campfire-dev:latest"}
1132
+ }'
1133
+ # event: step
1134
+ # data: {"step":"checking_image","message":"Checking image campfire-dev:latest..."}
1135
+ # event: step
1136
+ # data: {"step":"pulling_image","message":"Pulling campfire-dev:latest...","percent":45}
1137
+ # event: done
1138
+ # data: {"sessionId":"abc-123","session":{...}}
1139
+ ```
1140
+
1141
+ **Requirements:**
1142
+
1143
+ - Docker must be installed and running on the host
1144
+ - The Docker socket must be accessible to the Campfire process
1145
+
1146
+ ```bash
1147
+ # Check Docker availability
1148
+ curl http://localhost:4567/api/containers/status
1149
+ # → {"available": true, "version": "24.0.7"}
1150
+
1151
+ # List available images
1152
+ curl http://localhost:4567/api/containers/images
1153
+ ```
1154
+
1155
+ ---
1156
+
1157
+ ### PWA & Mobile
1158
+
1159
+ Campfire is a Progressive Web App (PWA) — installable on mobile devices with push notifications for permission requests.
1160
+
1161
+ **To install on mobile:**
1162
+
1163
+ 1. Open Campfire in your mobile browser
1164
+ 2. Tap "Add to Home Screen" (or the browser's install prompt)
1165
+ 3. The app launches in standalone mode with its own window
1166
+
1167
+ **Push notifications:**
1168
+
1169
+ When a permission request arrives and you're not actively viewing the tab, a push notification appears with the tool name and action buttons to allow or deny directly from the notification.
1170
+
1171
+ **Touch optimization:**
1172
+
1173
+ Permission buttons are enlarged on mobile (`min-height: 36px`) for easy tap targets. Tool blocks default to collapsed on small screens.
1174
+
1175
+ ---
1176
+
1177
+ ### Auto-Naming
1178
+
1179
+ Sessions automatically receive descriptive names after their first turn completes. This uses [OpenRouter](https://openrouter.ai/) to generate a short title based on the user's first message.
1180
+
1181
+ **Setup:**
1182
+
1183
+ 1. Go to **Settings** in the sidebar
1184
+ 2. Enter your OpenRouter API key
1185
+ 3. Optionally choose a model (default: `openrouter/free`)
1186
+
1187
+ Auto-naming only runs if:
1188
+ - An OpenRouter API key is configured
1189
+ - The session doesn't already have a manual name
1190
+ - A first turn has completed
1191
+
1192
+ Manual renames always take precedence. You can rename any session by clicking its name in the sidebar.
1193
+
1194
+ ---
1195
+
1196
+ ### Collective Intelligence
1197
+
1198
+ When multiple agent sessions are running simultaneously, Campfire's Collective Intelligence layer lets them share knowledge, coordinate decisions, and route tasks to the best-suited agent — without changing how agents communicate with each other.
1199
+
1200
+ It operates as a non-blocking observer: no agent message is ever delayed by it, and no existing behavior changes if the feature is unused.
1201
+
1202
+ **Four layers:**
1203
+
1204
+ | Layer | What it does |
1205
+ |-------|-------------|
1206
+ | **Semantic Memory** | Stores observations, decisions, and patterns from each agent session as vector embeddings in a local LanceDB database. Any session can query this shared knowledge base for relevant context before starting a task. |
1207
+ | **Deliberation Engine** | Proposes structured decisions across sessions (e.g. "which approach should we use?"). Connected viewers and agents can respond; the engine aggregates votes with role-weighted majority and resolves to `approved`, `rejected`, or `synthesized`. |
1208
+ | **Capability Discovery** | Each session self-reports its strengths, available tools, and context usage. When routing a task, the engine scores all connected sessions and picks the best fit. Confidence probes can be sent to agents in real time to verify self-reported capabilities. |
1209
+ | **Shared Context Stream** | A live think-aloud stream where agents can inject thoughts and observations. The engine detects semantic links (agrees, disagrees, builds on, contradicts) between fragments and tracks consensus scores across the session group. |
1210
+
1211
+ **How it works end-to-end:**
1212
+
1213
+ 1. When an agent produces output, the CI layer silently extracts observations and stores them as `MemoryFragment` records (with vector embeddings if an embedding provider is configured).
1214
+ 2. When a user sends a message, the CI layer queries the memory store for relevant context and prepends it to the message — giving agents access to knowledge from past sessions.
1215
+ 3. Browser clients can send `memory_query`, `memory_store`, `deliberation_respond`, `route_task`, and `inject_thought` messages over WebSocket. The server handles them and broadcasts results back to all connected viewers.
1216
+ 4. Sessions consolidate their episodic memories into distilled `ConsolidatedKnowledge` entries when they end.
1217
+
1218
+ **Embedding providers:**
1219
+
1220
+ Vector search requires an embedding provider. Configure one in **Settings**:
1221
+
1222
+ | Provider | Model | Dimensions | Notes |
1223
+ |----------|-------|-----------|-------|
1224
+ | `openai` | `text-embedding-3-small` (default) | 1536 | Requires OpenAI API key |
1225
+ | `ollama` | `nomic-embed-text` (default) | 768 | Requires local Ollama instance |
1226
+ | `none` | — | — | Fragments stored without embeddings; metadata-only search |
1227
+
1228
+ Without an embedding provider, memory still works — queries fall back to a full scan filtered by session, repo root, tags, and type.
1229
+
1230
+ **Storage:**
1231
+
1232
+ All CI data is stored locally under `~/.campfire/memory/lancedb/` — no external service required.
1233
+
1234
+ | Table | Purpose |
1235
+ |-------|---------|
1236
+ | `fragments.lance` | Episodic memory fragments with embeddings |
1237
+ | `consolidated.lance` | Distilled knowledge synthesized from sessions |
1238
+
1239
+ Capability data is stored as JSON in `~/.campfire/capabilities/` and learning history is appended to `~/.campfire/capability-learning.jsonl`.
1240
+
1241
+ **Quick setup:**
1242
+
1243
+ ```bash
1244
+ # 1. Configure an embedding provider in Settings (optional but recommended)
1245
+ # OpenAI: enter your API key, set provider = "openai"
1246
+ # Ollama: ensure ollama is running, set provider = "ollama"
1247
+
1248
+ # 2. Start multiple sessions — CI activates automatically
1249
+
1250
+ # 3. Query shared memory via the REST API
1251
+ curl "http://localhost:4567/api/sessions/:id/memory/query?q=authentication+pattern&limit=5"
1252
+
1253
+ # 4. Route a task to the best agent
1254
+ curl -X POST http://localhost:4567/api/sessions/route-task \
1255
+ -H "Content-Type: application/json" \
1256
+ -d '{"taskDescription": "Refactor the TypeScript authentication module"}'
1257
+ ```
1258
+
1259
+ **REST API summary:**
1260
+
1261
+ | Group | Endpoints |
1262
+ |-------|-----------|
1263
+ | Memory | `GET/POST /sessions/:id/memory`, `GET /sessions/:id/memory/query`, `POST /sessions/:id/memory/consolidate`, `GET /memory/global` |
1264
+ | Deliberation | `GET /sessions/:id/deliberations`, `GET /sessions/:id/deliberations/:proposalId`, `POST .../respond`, `POST .../resolve` |
1265
+ | Capabilities | `POST /sessions/route-task`, `GET /capabilities`, `GET /capabilities/history`, `POST /capabilities/feedback` |
1266
+ | Shared Context | `GET /sessions/:id/context/stream`, `GET /sessions/:id/context/consensus`, `GET /sessions/:id/context/thread/:fragmentId` |
1267
+
1268
+ Architecture details are documented in [`CLAUDE.md`](CLAUDE.md). A design study for the next iteration of the memory layer lives at [`docs/design/semantic-memory-v2.md`](docs/design/semantic-memory-v2.md).
1269
+
1270
+ ---
1271
+
1272
+ ### Copy Output Button
1273
+
1274
+ Hover over any user or assistant message to reveal a copy button. Copies the full text content to your clipboard with a checkmark confirmation animation. Uses the Clipboard API with a textarea fallback for insecure contexts (e.g. HTTP without TLS).
1275
+
1276
+ ### Voice Input
1277
+
1278
+ Dictate messages using the Web Speech API. Click the microphone button in the composer or press **Ctrl+Shift+M** (Cmd+Shift+M on macOS) to toggle voice input. Features include:
1279
+
1280
+ - Real-time interim text display while speaking
1281
+ - Auto-restart on silence for continuous dictation
1282
+ - Pulsing red indicator when active
1283
+ - Transcript is appended to the composer textarea so you can edit before sending
1284
+
1285
+ > **Note:** Requires a browser that supports the Web Speech API (Chrome, Edge, Safari).
1286
+
1287
+ ### Workspace File Tree
1288
+
1289
+ A collapsible file tree in the right-side TaskPanel showing the session's working directory. Features include:
1290
+
1291
+ - **Lazy-loading** — subdirectories load on expand, keeping the initial render fast
1292
+ - **File preview** — click a file to see its contents inline (up to 10KB)
1293
+ - **Hidden files toggle** — show/hide dotfiles and system directories
1294
+ - **Refresh** — re-scan the directory tree on demand
1295
+
1296
+ Powered by the `GET /api/fs/list-entries` endpoint which filters out `.git`, `node_modules`, and `__pycache__` by default.
1297
+
1298
+ ### Mermaid Diagram Rendering
1299
+
1300
+ When an assistant returns a fenced code block with the `mermaid` language tag, Campfire renders it as an interactive SVG diagram instead of raw text. Supports all Mermaid diagram types: flowcharts, sequence diagrams, class diagrams, state diagrams, ER diagrams, Gantt charts, and more.
1301
+
1302
+ - Toggle between **diagram** and **source code** views
1303
+ - Error handling with automatic fallback to source display
1304
+ - Lazy-loaded via `React.lazy()` to avoid impacting initial bundle size
1305
+
1306
+ ### Orchestrator Pipelines
1307
+
1308
+ A multi-stage automation engine for chaining sequential AI sessions into workflows. Access it at `#/orchestrator` in the sidebar.
1309
+
1310
+ **How it works:**
1311
+
1312
+ 1. **Create a pipeline** — define a name, working directory, and a series of stages
1313
+ 2. **Each stage** has a prompt, backend (Claude/Codex), and model selection
1314
+ 3. **Run the pipeline** — stages execute sequentially, each creating a real agent session
1315
+ 4. **Context passing** — output from one stage feeds into the next via `{{previous_output}}`
1316
+ 5. **Monitor** — real-time status timeline with per-stage duration and cost tracking
1317
+
1318
+ **Example use cases:**
1319
+ - Analyze → Review → Write Tests → Create PR
1320
+ - Scaffold → Implement → Lint → Deploy
1321
+ - Research → Plan → Execute → Verify
1322
+
1323
+ **REST API:**
1324
+
1325
+ | Method | Endpoint | Purpose |
1326
+ |--------|----------|---------|
1327
+ | `GET` | `/api/orchestrator/pipelines` | List all pipelines |
1328
+ | `POST` | `/api/orchestrator/pipelines` | Create a new pipeline |
1329
+ | `PUT` | `/api/orchestrator/pipelines/:id` | Update a pipeline |
1330
+ | `DELETE` | `/api/orchestrator/pipelines/:id` | Delete a pipeline |
1331
+ | `POST` | `/api/orchestrator/pipelines/:id/run` | Execute a pipeline |
1332
+ | `GET` | `/api/orchestrator/runs` | List all runs |
1333
+ | `GET` | `/api/orchestrator/runs/:id` | Get run status and details |
1334
+ | `POST` | `/api/orchestrator/runs/:id/cancel` | Cancel a running pipeline |
1335
+
1336
+ Pipeline and run data is persisted to `~/.campfire/orchestrator/`.
1337
+
1338
+ ### Multi-Agent Orchestration
1339
+
1340
+ Campfire can now coordinate agents as a group instead of only running independent sessions. The orchestration layer lets lead agents delegate one-turn subtasks to other backends, runs parallel "agent races" in isolated worktrees, and detects project environment integrations before a session starts.
1341
+
1342
+ **Agent-to-agent delegation:**
1343
+
1344
+ - Lead Claude Code and Codex sessions can receive an internal `campfire_agents` MCP server.
1345
+ - The MCP server exposes `ask_codex`, `ask_goose`, `ask_aider`, `ask_openhands`, and `ask_claude` tools, excluding the lead session's own backend.
1346
+ - Each `ask_*` tool launches a temporary sub-session in the same working directory, injects the subtask prompt, waits for the result, collects changed files and cost, then returns the result to the lead agent.
1347
+ - Sub-agent progress is streamed back to the parent session through `sub_agent_update` events and appears in the session activity UI.
1348
+ - Set `CAMPFIRE_ENABLE_AGENT_MCP=0` to disable automatic agent MCP injection.
1349
+
1350
+ **Agent races:**
1351
+
1352
+ Open **Agent Races** at `#/races` from the sidebar to run the same prompt across multiple backends in parallel.
1353
+
1354
+ 1. Choose a repository root and task prompt.
1355
+ 2. Select at least two backends. The UI currently offers Claude, Codex, Goose, Aider, and OpenHands; the REST API also accepts OpenClaw and OpenCode.
1356
+ 3. Campfire creates one git worktree and branch per backend, launches a session in each worktree, and sends the same prompt to every agent.
1357
+ 4. The comparison view shows status, wall-clock time, cost, changed file count, line changes, output summary, and a loadable diff for each entry.
1358
+ 5. Click **Merge** on the winning entry to merge its race branch into the repository root and clean up the other race worktrees.
1359
+
1360
+ **Cost cascade mode:** check **"Cost cascade — run backends in order, stop at first success"** to run the selected backends *sequentially* in the order you listed them (put the cheapest first) instead of in parallel. The race stops at the first entry that completes with a non-empty change set; failures, timeouts, and empty patches escalate to the next backend, and never-started entries are marked `skipped`. Pass `cascade: true` in the REST payload for the same behavior.
1361
+
1362
+ Race results are saved to `~/.campfire/races/` so completed comparisons remain available after a server restart.
1363
+
1364
+ **Environment detection:**
1365
+
1366
+ Every launched session scans its working directory for project signals such as Supabase, Stripe, Vercel/Next.js, Prisma, Docker, Fly.io, GitHub Actions, and database configuration. Detected rules appear in the TaskPanel environment card with required environment variables marked as configured or missing. For Claude and Codex sessions, detected MCP servers are injected automatically unless `CAMPFIRE_AUTO_INJECT_ENV_MCP=0` is set.
1367
+
1368
+ **MCP injection policy:** auto-injected servers are governed by a default-deny policy (`web/server/mcp-policy.ts`) — only servers that exactly match Campfire's curated environment-rules catalog and pass a static scan (shell metacharacters, inline-eval flags, plaintext `http://` URLs to non-local hosts) are admitted; everything else is blocked and logged. Servers you add explicitly through the MCP panel are never blocked, but the same scan runs in warn-only mode for visibility. Set `CAMPFIRE_MCP_AUTO_INJECT_POLICY=permissive` to restore scan-free auto-injection (findings are still logged).
1369
+
1370
+ **REST API:**
1371
+
1372
+ | Method | Endpoint | Purpose |
1373
+ |--------|----------|---------|
1374
+ | `POST` | `/api/races` | Start a race with `{ prompt, repoRoot, backends, baseBranch?, modelByBackend?, cascade? }` |
1375
+ | `GET` | `/api/races` | List saved races |
1376
+ | `GET` | `/api/races/:id` | Get race status and entries |
1377
+ | `GET` | `/api/races/:id/entries/:entryId/diff` | Load a race entry's git diff |
1378
+ | `POST` | `/api/races/:id/pick` | Merge the winning entry by `sessionId` |
1379
+ | `POST` | `/api/races/:id/cancel` | Cancel a running race and clean up worktrees |
1380
+ | `DELETE` | `/api/races/:id` | Delete a saved race record |
1381
+
1382
+ ### Message Queue
1383
+
1384
+ When the agent is busy processing a request (status "running"), new messages are queued instead of being dropped. Features include:
1385
+
1386
+ - **Queue indicator** — a badge shows the number of queued messages with a clear button
1387
+ - **Auto-send** — queued messages are sent one at a time when the agent becomes idle
1388
+ - **System notification** — a "Queued: ..." message appears in the chat timeline so you know the message was captured
1389
+ - Works seamlessly with all backends (Claude Code, Codex, Goose, Aider, OpenHands, OpenClaw, OpenCode)
1390
+
1391
+ ### Kanban Task Board
1392
+
1393
+ A full-page Kanban board at `#/kanban` (also accessible via the sidebar or the "board" button in the TaskPanel) that visualizes tasks extracted from agent tool calls (`TaskCreate`, `TaskUpdate`, `TodoWrite`).
1394
+
1395
+ **Three columns:**
1396
+ - **To Do** — pending tasks
1397
+ - **In Progress** — tasks the agent is actively working on (with animated pulse indicator)
1398
+ - **Done** — completed tasks
1399
+
1400
+ **Task cards show:**
1401
+ - Subject and description
1402
+ - Owner (agent name)
1403
+ - Active form (what the agent is currently doing)
1404
+ - Blocked status with warning badge
1405
+ - Task ID for reference
1406
+
1407
+ A progress bar at the top shows overall completion percentage.
1408
+
1409
+ ---
1410
+
1411
+ ### Authentication
1412
+
1413
+ Token-based authentication to protect your Campfire instance. When enabled, all API routes and WebSocket connections require a valid session token.
1414
+
1415
+ **Setup:**
1416
+
1417
+ ```bash
1418
+ # Set a password via environment variable
1419
+ CAMPFIRE_PASSWORD=your-secret bunx the-campfire
1420
+
1421
+ # Or configure through the UI on first visit
1422
+ ```
1423
+
1424
+ **Features:**
1425
+ - Password-based login with salted scrypt hashing (legacy unsalted SHA-256 hashes are migrated automatically on the next successful login)
1426
+ - 7-day rotating session tokens stored in `~/.campfire/auth.json`
1427
+ - Auth middleware protects all `/api/*` routes
1428
+ - WebSocket connections validated on upgrade
1429
+ - Environment variable override for headless/CI deployments
1430
+
1431
+ **API endpoints:**
1432
+ - `GET /api/auth/status` — Check if auth is enabled and user is logged in
1433
+ - `POST /api/auth/login` — Authenticate with password
1434
+ - `POST /api/auth/logout` — Invalidate session token
1435
+ - `POST /api/auth/setup` — Initial password setup
1436
+ - `POST /api/auth/disable` — Remove authentication
1437
+
1438
+ ---
1439
+
1440
+ ### Thinking Effort (Codex)
1441
+
1442
+ Control the reasoning effort level for Codex o-series models. This maps to Codex's `reasoningEffort` parameter on `thread/start` and `thread/resume` calls.
1443
+
1444
+ **Three levels:**
1445
+ - **Low** — Faster responses, less deliberation
1446
+ - **Medium** — Balanced (default)
1447
+ - **High** — Maximum reasoning depth
1448
+
1449
+ **Usage:** When creating a new session with the Codex backend, a segmented control appears on the Home page. Your selection persists in localStorage across page reloads.
1450
+
1451
+ ---
1452
+
1453
+ ### Skills & Plugins Management
1454
+
1455
+ Browse and manage Claude Code plugins and skills from a dedicated UI page at `#/skills` (accessible via the sparkle icon in the sidebar).
1456
+
1457
+ **Features:**
1458
+ - Lists all installed plugins from `~/.claude/plugins/installed_plugins.json`
1459
+ - Expandable cards showing each plugin's skills, commands, install path, version, and author
1460
+ - View SKILL.md content for any skill by clicking its name
1461
+ - Enable/disable plugins in Campfire without uninstalling them (stored in `~/.campfire/skills-config.json`)
1462
+ - Blocked plugin detection from `~/.claude/plugins/blocklist.json`
1463
+
1464
+ **API endpoints:**
1465
+ - `GET /api/skills` — List all plugins with enriched status
1466
+ - `GET /api/skills/:id` — Get a single plugin's details
1467
+ - `GET /api/skills/:id/skill/:name` — Read a skill's SKILL.md content
1468
+ - `GET /api/skills/:id/command/:name` — Read a command's content
1469
+ - `POST /api/skills/:id/toggle` — Enable/disable a plugin in Campfire
1470
+
1471
+ ---
1472
+
1473
+ ### Drag & Drop Upload
1474
+
1475
+ Drag image files directly onto the Composer to attach them to your message. A visual overlay with a dashed border appears when dragging over the input area, confirming the drop target.
1476
+
1477
+ **Supported:** Any image format (PNG, JPG, GIF, WebP, etc.). Images are converted to base64 and sent as attachments with your message.
1478
+
1479
+ ---
1480
+
1481
+ ### Session Folders
1482
+
1483
+ Organize sessions into named, color-coded folders in the sidebar.
1484
+
1485
+ **Features:**
1486
+ - Create folders with a name and optional color
1487
+ - Move sessions into folders via context menu
1488
+ - Collapse/expand folders (state persists in localStorage)
1489
+ - Remove sessions from folders
1490
+ - Delete empty folders
1491
+
1492
+ **Storage:** Folder data persists in `~/.campfire/session-folders.json`.
1493
+
1494
+ **API endpoints:**
1495
+ - `GET /api/folders` — List all folders
1496
+ - `POST /api/folders` — Create a folder
1497
+ - `PATCH /api/folders/:id` — Update folder name/color
1498
+ - `DELETE /api/folders/:id` — Delete a folder
1499
+ - `POST /api/folders/:folderId/sessions/:sessionId` — Add session to folder
1500
+ - `DELETE /api/folders/sessions/:sessionId` — Remove session from folder
1501
+
1502
+ ---
1503
+
1504
+ ### Permission Mode Selector
1505
+
1506
+ A dropdown in the Composer lets you switch between Claude Code permission modes in real-time, without restarting the session.
1507
+
1508
+ **Four modes:**
1509
+ | Mode | Behavior |
1510
+ |------|----------|
1511
+ | **Agent (auto-approve)** | Uses `--dangerously-skip-permissions` — all tool calls approved automatically |
1512
+ | **Accept Edits** | File edits approved automatically, other tools require approval |
1513
+ | **Ask Every Time** | Every tool call requires explicit approval |
1514
+ | **Plan** | Planning mode only — no code execution |
1515
+
1516
+ Switching sends a `set_permission_mode` control message to the CLI. The current mode is displayed as a badge on the mode button. Use `Shift+Tab` in the Composer as a keyboard shortcut to toggle between Plan and your previous mode.
1517
+
1518
+ ---
1519
+
1520
+ ### Session Pulse (Background Activity)
1521
+
1522
+ A floating widget in the bottom-right corner of the chat view that provides real-time awareness of background activity. Two tabs:
1523
+
1524
+ **Activity tab** — shows what's happening in the current session:
1525
+ - Background agents spawned with `run_in_background` (Claude Code)
1526
+ - Active tool calls with elapsed timers (all backends)
1527
+ - Task progress from TodoWrite/TaskCreate
1528
+
1529
+ **Sessions tab** — shows other sessions running in the background:
1530
+ - Which sessions are running or compacting
1531
+ - Pending permission counts with warning badges
1532
+ - Click any row to jump to that session
1533
+
1534
+ Auto-hides when all activity completes. Appears automatically when agents or sessions are active.
1535
+
1536
+ ### Agent System
1537
+
1538
+ Persistent agent profiles with automated triggers. Navigate to **Config > Agents** (`#/agents`).
1539
+
1540
+ **Creating an agent:**
1541
+ 1. Click **Create Agent**
1542
+ 2. Fill in: name, description, backend (all 7 supported), model, permission mode, working directory
1543
+ 3. Write a prompt template — use `{{input}}` as a placeholder for trigger input
1544
+ 4. Select an environment profile (important for Codex — provides `OPENAI_API_KEY`)
1545
+ 5. Optionally enable triggers: webhook or cron schedule
1546
+
1547
+ **Running an agent:**
1548
+ - Click the play button on any agent card
1549
+ - If the prompt contains `{{input}}`, a modal asks for the input value
1550
+ - The agent creates a new session, injects the resolved prompt, and runs autonomously
1551
+ - Agent sessions are named with the agent's icon (e.g., `🔬 Analyser`)
1552
+
1553
+ **Triggers:**
1554
+ | Trigger | How it works |
1555
+ |---------|-------------|
1556
+ | Manual | Click the play button |
1557
+ | Webhook | `POST /api/agents/{id}/webhook` with `{ "input": "..." }` |
1558
+ | Schedule | Cron expression (e.g., `0 8 * * *` for daily at 8am) |
1559
+
1560
+ **Safety:** Auto-disables after 5 consecutive failures. Overlap prevention skips execution if previous run is still alive.
1561
+
1562
+ **Import/Export:** Agents can be exported as JSON and imported on another Campfire instance.
1563
+
1564
+ ### Provider Settings
1565
+
1566
+ Configure AI provider authentication tokens. Navigate to **Settings > Providers**.
1567
+
1568
+ Three token types, auto-injected into sessions for matching backends:
1569
+
1570
+ | Token | Environment Variable | Used By |
1571
+ |-------|---------------------|---------|
1572
+ | Claude Code OAuth | `CLAUDE_CODE_OAUTH_TOKEN` | Claude sessions |
1573
+ | OpenAI API Key | `OPENAI_API_KEY` | Codex sessions |
1574
+ | Anthropic API Key | `ANTHROPIC_API_KEY` | All sessions (Goose, Aider, etc.) |
1575
+
1576
+ **Precedence:** Environment profiles override global provider tokens. If your env profile sets `OPENAI_API_KEY`, the global setting is skipped for that session.
1577
+
1578
+ **Auth detection:** `GET /api/settings/auth-status` checks for existing authentication:
1579
+ - `~/.claude/.credentials.json` (Claude subscription login)
1580
+ - `~/.codex/auth.json` (ChatGPT plan login)
1581
+ - Environment variables and stored tokens
1582
+
1583
+ ### Model & Provider Switcher
1584
+
1585
+ Two compact dropdowns in the TopBar for switching models and providers mid-session:
1586
+
1587
+ **Model Switcher** — click the model name (e.g., `◕ Sonnet`) to see all available models for the current backend. Selecting a different model sends a `set_model` WebSocket message. Works for all backends.
1588
+
1589
+ **Provider Switcher** — click the backend name (e.g., `✨ Claude`) to see all 7 backends with availability status. Selecting a different provider creates a new session with the same working directory (since backends can't be swapped mid-session).
1590
+
1591
+ ### Session Launch Progress
1592
+
1593
+ A non-blocking floating toast (bottom-left) that shows real-time progress when any session is being created:
1594
+
1595
+ - **Standard sessions:** Spawning process → Waiting for connection → Ready
1596
+ - **Auto-detects** new sessions by monitoring the `sdkSessions` store
1597
+ - **Auto-dismisses** after 2 seconds once all steps complete
1598
+ - Works globally — triggers from HomePage, ProviderSwitcher, Agent execution, or Cron jobs
1599
+
1600
+ ### Onboarding Wizard
1601
+
1602
+ A 5-step first-run experience shown on first launch. Navigate through:
1603
+
1604
+ 1. **Welcome** — explains what Campfire is
1605
+ 2. **Providers** — dual-path auth for Claude (subscription via `claude auth login` OR API key) and Codex (ChatGPT login via `codex login` OR API key). Auto-detects existing auth.
1606
+ 3. **Workspace** — pick a default working directory
1607
+ 4. **Tour** — key features overview
1608
+ 5. **Launch** — sends user to create their first session
1609
+
1610
+ Skip at any point. Tracked via `onboardingCompleted` in `~/.campfire/settings.json`. Reset with:
1611
+ ```bash
1612
+ curl -X PUT http://localhost:4567/api/settings -H 'Content-Type: application/json' -d '{"onboardingCompleted": false}'
1613
+ ```
1614
+
1615
+ ### Monaco Code Editor
1616
+
1617
+ VS Code's editor engine integrated into Campfire for code editing. Lazy-loaded — only downloaded when an editor opens.
1618
+
1619
+ **Where it's used:**
1620
+ - **CLAUDE.md Editor** — edit project instructions with Markdown syntax highlighting
1621
+ - **Diff Panel "Edit" mode** — click Diff > Edit to modify any file the agent changed
1622
+ - **Files Panel** — full file browser with editing (see below)
1623
+ - **Agent prompt editor** — write agent prompts with line numbers
1624
+ - **Cron prompt editor** — same for scheduled tasks
1625
+
1626
+ **Features:** IntelliSense (TS/JS/CSS/JSON), minimap, find/replace (Ctrl+H), multi-cursor, code folding, bracket pair colorization, command palette (Ctrl+Shift+P), custom Campfire themes (light + dark).
1627
+
1628
+ ### Files Panel
1629
+
1630
+ A full workspace file browser with Monaco editor. Click the **Files** tab in the TopBar (next to Log and Diff).
1631
+
1632
+ **Features:**
1633
+ - **Lazy-loaded directory tree** — expands on click, shows folders and files
1634
+ - **File search** — filter by filename
1635
+ - **Syntax-highlighted editing** — open any file in Monaco with auto-detected language (40+ extensions)
1636
+ - **Save/Cancel** — save edits to disk or discard changes
1637
+ - **Changed file indicators** — files modified by the agent show a warning dot
1638
+ - **Image preview** — renders PNG/JPG/SVG inline
1639
+ - **Show/hide dotfiles** — toggle hidden files visibility
1640
+ - **Responsive** — sidebar collapses on mobile
1641
+
1642
+ ### Recording Hub
1643
+
1644
+ Browse, validate, and diagnose session recordings. Navigate to **Data > Recordings** (`#/hub`).
1645
+
1646
+ **Getting started:**
1647
+ 1. Click **Index Recordings** to import all existing auto-recordings
1648
+ 2. Browse recordings with backend filter pills, playable/metadata filter, and sort options
1649
+
1650
+ **Per-recording analysis** (click the details icon):
1651
+ - **Protocol Validation** — checks message format compatibility across all 7 backends
1652
+ - **Health Report** — duration, message rate, disconnections, data gaps, permission response times, anomaly patterns
1653
+
1654
+ **Filter/Sort options:**
1655
+ - By backend: Claude, Codex, Goose, etc.
1656
+ - By type: Playable (has chat content), Metadata only
1657
+ - By sort: Newest, Oldest, Longest duration, Most messages
1658
+
1659
+ ### Protocol Monitor
1660
+
1661
+ Real-time WebSocket message flow dashboard. Navigate to **Tools > Monitor** (`#/monitor`).
1662
+
1663
+ **Metrics (auto-refreshes every 3 seconds):**
1664
+ - Total messages, messages/minute, active sessions, errors
1665
+ - Backend breakdown with per-backend message/error counts
1666
+ - Message type distribution (5-minute rolling window)
1667
+ - Per-session stats with name, backend, rate, last activity
1668
+
1669
+ **Protocol drift alerts** — visual warnings when unexpected message formats are detected, with deduplication.
1670
+
1671
+ ### Commands Discovery
1672
+
1673
+ Browse all available slash commands and skills. Navigate to **Config > Commands** (`#/commands`).
1674
+
1675
+ **Dynamic command list** — fetched from the CLI itself (not hardcoded). If no sessions are connected, Campfire spins up a temporary session to discover available commands, caches the result, and kills the session.
1676
+
1677
+ **Three sections:**
1678
+ - **Built-in Commands** — all CLI slash commands (e.g., `/help`, `/compact`, `/cost`, `/memory`)
1679
+ - **Custom Commands** — `.md` files from `~/.claude/commands/` and `{cwd}/.claude/commands/`
1680
+ - **Skills** — directories with `SKILL.md` from `~/.claude/skills/`
1681
+
1682
+ Custom commands and skills show expandable content preview and source badges (user vs project).
1683
+
1684
+ **Slash autocomplete on HomePage** — type `/` in the new session textarea to see the autocomplete dropdown with all available commands.
1685
+
1686
+ ### Proactive Keepalive
1687
+
1688
+ Auto-relaunches crashed CLI sessions with exponential backoff. Ensures autonomous sessions (agents, cron jobs) stay alive even without a browser connected.
1689
+
1690
+ | Setting | Default | Environment Variable |
1691
+ |---------|---------|---------------------|
1692
+ | Base delay | 3 seconds | `CAMPFIRE_KEEPALIVE_DELAY_MS` |
1693
+ | Max attempts | 3 | `CAMPFIRE_KEEPALIVE_MAX_ATTEMPTS` |
1694
+
1695
+ **Backoff schedule:** 3s → 6s → 12s. Resets on successful relaunch.
1696
+
1697
+ **Excluded from relaunch:** Intentional kills (user clicked kill/delete), archived sessions, clean exits (exit code 0).
1698
+
1699
+ **WebSocket config:** Bun's built-in ping timeout is disabled (`idleTimeout: 0, sendPings: false`) to prevent idle CLI connections from being killed with code 1006.
1700
+
1701
+ ### Security Headers & Rate Limiting
1702
+
1703
+ **Security headers** applied to all responses:
1704
+
1705
+ | Header | Value |
1706
+ |--------|-------|
1707
+ | `X-Content-Type-Options` | `nosniff` |
1708
+ | `X-Frame-Options` | `SAMEORIGIN` |
1709
+ | `Referrer-Policy` | `strict-origin-when-cross-origin` |
1710
+ | `X-XSS-Protection` | `1; mode=block` |
1711
+ | `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` |
1712
+ | `Strict-Transport-Security` | `max-age=31536000; includeSubDomains` (HTTPS only) |
1713
+
1714
+ **Rate limiting** on `/api/*` endpoints:
1715
+
1716
+ | Setting | Default | Environment Variable |
1717
+ |---------|---------|---------------------|
1718
+ | Window | 60 seconds | `CAMPFIRE_RATE_LIMIT_WINDOW_MS` |
1719
+ | Max requests | 120 per window | `CAMPFIRE_RATE_LIMIT_MAX` |
1720
+
1721
+ Rate limit headers included in every API response: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`. Returns `429 Too Many Requests` with `Retry-After` header when exceeded.
1722
+
1723
+ ### WebSocket Authentication
1724
+
1725
+ When authentication is enabled, all WebSocket upgrade endpoints are protected — not just the REST API. This prevents unauthorized users from connecting directly to WebSocket endpoints and bypassing the login.
1726
+
1727
+ **Protected endpoints:**
1728
+
1729
+ | Endpoint | What it does | Auth behavior |
1730
+ |----------|-------------|---------------|
1731
+ | `/ws/cli/:sessionId` | Agent CLI connection | Allowed from localhost without token (CLI is spawned locally). Requires token from remote connections. |
1732
+ | `/ws/browser/:sessionId` | Browser session connection | Requires auth token. Valid invite tokens bypass auth (for collaboration). |
1733
+ | `/ws/terminal/:terminalId` | Embedded terminal PTY | Requires auth token. |
1734
+
1735
+ **How tokens are passed:**
1736
+ - Query parameter: `?auth_token=<session_token>` (auto-appended by the frontend)
1737
+ - HTTP header: `Authorization: Bearer <session_token>`
1738
+
1739
+ **When auth is disabled (default):** All WebSocket connections work without tokens — zero friction for local development.
1740
+
1741
+ **Enabling auth:**
1742
+
1743
+ ```bash
1744
+ # Option 1: Set password via environment variable
1745
+ CAMPFIRE_PASSWORD=mypassword bunx the-campfire
1746
+
1747
+ # Option 2: Set password via API
1748
+ curl -X POST http://localhost:4567/api/auth/setup \
1749
+ -H 'Content-Type: application/json' \
1750
+ -d '{"password": "mypassword"}'
1751
+ ```
1752
+
1753
+ **Login flow:**
1754
+
1755
+ ```bash
1756
+ # Get a session token
1757
+ curl -X POST http://localhost:4567/api/auth/login \
1758
+ -H 'Content-Type: application/json' \
1759
+ -d '{"password": "mypassword"}'
1760
+ # Returns: { "token": "abc123..." }
1761
+ ```
1762
+
1763
+ The frontend stores this token in `localStorage` and automatically includes it in all API requests (via `Authorization` header) and WebSocket connections (via `?auth_token=` query parameter).
1764
+
1765
+ **Collaboration:** Invite tokens (generated via the Share menu) still work when auth is enabled. A valid invite token grants the specified role (collaborator/spectator) without requiring a session auth token. Invite tokens expire 24 hours after creation.
1766
+
1767
+ ---
1768
+
1769
+ ## Architecture
1770
+
1771
+ ```
1772
+ Browser (React 19)
1773
+ <-> WebSocket <-> Campfire Server (Bun + Hono)
1774
+ |-- /ws/browser/:id (browser connections)
1775
+ |-- /ws/cli/:id (agent CLI connections)
1776
+ \-- /ws/terminal/:id (embedded PTY)
1777
+ |
1778
+ Claude Code CLI (NDJSON over WebSocket)
1779
+ Codex CLI (JSON-RPC over stdio)
1780
+ Goose CLI (JSON-RPC over stdio)
1781
+ Aider CLI (stdout parsing)
1782
+ OpenHands CLI (JSON-RPC over stdio)
1783
+ OpenClaw CLI (JSON-RPC over stdio)
1784
+ OpenCode CLI (JSON-RPC over stdio)
1785
+ ```
1786
+
1787
+ The server bridges the undocumented `--sdk-url` WebSocket protocol from Claude Code (and equivalent protocols from other agents) to a normalized browser message format. The frontend is completely backend-agnostic — it renders the same UI regardless of which agent is running.
1788
+
1789
+ ### Key Components
1790
+
1791
+ | Layer | Technology | Description |
1792
+ |-------|-----------|-------------|
1793
+ | **Runtime** | [Bun](https://bun.sh) | JavaScript/TypeScript runtime and package manager |
1794
+ | **Backend** | [Hono](https://hono.dev) | Lightweight web framework with WebSocket support |
1795
+ | **Frontend** | [React 19](https://react.dev) | UI with streaming, tool blocks, permission banners |
1796
+ | **State** | [Zustand](https://zustand.docs.pmnd.rs) | Session-scoped state keyed by session ID |
1797
+ | **Styling** | [Tailwind CSS 4](https://tailwindcss.com) | Utility-first CSS |
1798
+ | **Build** | [Vite 6](https://vite.dev) | Frontend bundler with HMR |
1799
+ | **Testing** | [Vitest](https://vitest.dev) | 900+ tests across backend and frontend |
1800
+ | **Scheduling** | [Croner](https://github.com/Hexagon/croner) | Cron expression parser for scheduled sessions |
1801
+ | **Vector DB** | [LanceDB](https://lancedb.github.io/lancedb/) | Embedded TypeScript-native vector database for CI semantic memory |
1802
+
1803
+ ### Data Persistence
1804
+
1805
+ All state is file-based — no database required:
1806
+
1807
+ | Data | Location | Format |
1808
+ |------|----------|--------|
1809
+ | Sessions | `~/.campfire/sessions/` | JSON per session |
1810
+ | Recordings | `~/.campfire/recordings/` | JSONL per session |
1811
+ | Environments | `~/.campfire/envs/` | JSON per profile |
1812
+ | Cron jobs | `~/.campfire/cron/` | JSON per job |
1813
+ | Gallery entries | `~/.campfire/gallery/` | JSON per entry |
1814
+ | Agent races | `~/.campfire/races/` | JSON per race |
1815
+ | Webhooks | `~/.campfire/webhooks/` | JSON per webhook |
1816
+ | Adapters | `~/.campfire/adapters/` | npm packages |
1817
+ | Settings | `~/.campfire/settings.json` | Single JSON file |
1818
+ | Prompts | `~/.campfire/prompts.json` | Single JSON array |
1819
+ | Session names | `~/.campfire/session-names.json` | Single JSON file |
1820
+ | Linear project mappings | `~/.campfire/linear-projects.json` | Single JSON file |
1821
+ | Linear session issues | `~/.campfire/linear-session-issues.json` | Single JSON file |
1822
+ | **CI Memory** | `~/.campfire/memory/lancedb/` | LanceDB vector tables |
1823
+ | **CI Capabilities** | `~/.campfire/capabilities/` | JSON per session |
1824
+ | **CI Learning log** | `~/.campfire/capability-learning.jsonl` | JSONL append-only |
1825
+
1826
+ ---
1827
+
1828
+ ## Docker Deployment
1829
+
1830
+ ### Building the Image
1831
+
1832
+ The included `Dockerfile` uses a multi-stage build:
1833
+ 1. **Builder stage** — installs all dependencies and builds the frontend with Vite
1834
+ 2. **Production stage** — copies only production dependencies, server code, and built frontend (~100MB final image)
1835
+
1836
+ ```bash
1837
+ # Build the image
1838
+ docker build -t campfire:latest .
1839
+
1840
+ # Verify it works
1841
+ docker run --rm -p 4567:4567 campfire:latest
1842
+ ```
1843
+
1844
+ ### Using Docker Compose
1845
+
1846
+ The included `docker-compose.yml` is the easiest way to run with persistent data:
1847
+
1848
+ ```bash
1849
+ # Start (builds if needed)
1850
+ docker compose up
1851
+
1852
+ # Start in background
1853
+ docker compose up -d
1854
+
1855
+ # Rebuild after code changes
1856
+ docker compose up --build
1857
+
1858
+ # Stop
1859
+ docker compose down
1860
+
1861
+ # Stop and remove volumes (deletes all data)
1862
+ docker compose down -v
1863
+ ```
1864
+
1865
+ Open [http://localhost:4567](http://localhost:4567).
1866
+
1867
+ ### docker-compose.yml
1868
+
1869
+ The included `docker-compose.yml` provides a ready-to-run configuration:
1870
+
1871
+ ```yaml
1872
+ services:
1873
+ campfire:
1874
+ build: .
1875
+ ports:
1876
+ - "4567:4567"
1877
+ volumes:
1878
+ - campfire-data:/home/campfire/.campfire
1879
+ environment:
1880
+ - NODE_ENV=production
1881
+ - PORT=4567
1882
+ restart: unless-stopped
1883
+
1884
+ volumes:
1885
+ campfire-data:
1886
+ campfire-data:
1887
+ ```
1888
+
1889
+ ### Environment Variables
1890
+
1891
+ | Variable | Default | Description |
1892
+ |----------|---------|-------------|
1893
+ | `PORT` | `4567` | Server port |
1894
+ | `NODE_ENV` | `production` | Environment mode |
1895
+ | `CAMPFIRE_RECORD` | `1` | Enable protocol recording (`0` to disable) |
1896
+ | `CAMPFIRE_RECORDINGS_DIR` | `~/.campfire/recordings` | Recording output directory |
1897
+ | `CAMPFIRE_RECORDINGS_MAX_LINES` | `100000` | Auto-rotation threshold |
1898
+ | `CAMPFIRE_SESSION_DIR` | `~/.campfire/sessions` | Override session persistence directory |
1899
+
1900
+ ### Volumes
1901
+
1902
+ | Path | Purpose |
1903
+ |------|---------|
1904
+ | `/home/campfire/.campfire` | All persistent data (sessions, settings, envs, agents, recordings, webhooks, gallery) |
1905
+
1906
+ ### Running with Agent CLIs
1907
+
1908
+ The Docker image includes Bun but **not** the agent CLIs themselves. To use agents inside Docker, mount your host binaries or extend the image:
1909
+
1910
+ **Option 1: Mount host binaries (simplest)**
1911
+
1912
+ ```yaml
1913
+ services:
1914
+ campfire:
1915
+ build: .
1916
+ ports:
1917
+ - "4567:4567"
1918
+ volumes:
1919
+ - campfire-data:/home/campfire/.campfire
1920
+ # Mount agent CLIs from host
1921
+ - /usr/local/bin/claude:/usr/local/bin/claude:ro
1922
+ - /usr/local/bin/codex:/usr/local/bin/codex:ro
1923
+ # Mount authentication
1924
+ # Writable — Claude Code updates its own config at runtime. Prefer
1925
+ # copying a snapshot (docker cp) if you don't want the container
1926
+ # touching your host ~/.claude.
1927
+ - ~/.claude:/home/campfire/.claude
1928
+ environment:
1929
+ - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
1930
+ ```
1931
+
1932
+ **Option 2: Extend the Dockerfile**
1933
+
1934
+ ```dockerfile
1935
+ FROM campfire:latest
1936
+
1937
+ # Install Claude Code
1938
+ RUN bun install -g @anthropic-ai/claude-code
1939
+
1940
+ # Install Codex
1941
+ RUN bun install -g @openai/codex
1942
+
1943
+ # OpenClaw and OpenCode ship as standalone binaries — copy from host or download separately
1944
+ # COPY --from=host /usr/local/bin/openclaw /usr/local/bin/openclaw
1945
+ # COPY --from=host /usr/local/bin/opencode /usr/local/bin/opencode
1946
+ ```
1947
+
1948
+ **Option 3: Network mode (connect to host CLIs)**
1949
+
1950
+ ```yaml
1951
+ services:
1952
+ campfire:
1953
+ build: .
1954
+ network_mode: host
1955
+ volumes:
1956
+ - campfire-data:/home/campfire/.campfire
1957
+ ```
1958
+
1959
+ This lets Campfire spawn agent processes on the host directly.
1960
+
1961
+ ### Production Deployment
1962
+
1963
+ For production deployments behind a reverse proxy:
1964
+
1965
+ ```nginx
1966
+ # nginx.conf
1967
+ server {
1968
+ listen 80;
1969
+ server_name campfire.example.com;
1970
+
1971
+ location / {
1972
+ proxy_pass http://localhost:4567;
1973
+ proxy_http_version 1.1;
1974
+ proxy_set_header Upgrade $http_upgrade;
1975
+ proxy_set_header Connection "upgrade";
1976
+ proxy_set_header Host $host;
1977
+ proxy_set_header X-Real-IP $remote_addr;
1978
+ proxy_read_timeout 86400; # WebSocket keep-alive
1979
+ }
1980
+ }
1981
+ ```
1982
+
1983
+ ### Health Check
1984
+
1985
+ The Docker image includes a health check:
1986
+
1987
+ ```bash
1988
+ curl -f http://localhost:4567/api/sessions || exit 1
1989
+ ```
1990
+
1991
+ ---
1992
+
1993
+ ## CLI Reference
1994
+
1995
+ ```
1996
+ the-campfire [command] [options]
1997
+
1998
+ Commands:
1999
+ (none) Start server in foreground (default)
2000
+ serve Start server in foreground
2001
+ start Start as background service
2002
+ install Install as system service (launchd/systemd)
2003
+ stop Stop background service
2004
+ restart Restart background service
2005
+ uninstall Remove system service
2006
+ status Show service status
2007
+ logs Tail service log files
2008
+ install-adapter <package> Install a community adapter from npm
2009
+ uninstall-adapter <name> Remove an installed adapter
2010
+ help Show help
2011
+
2012
+ Options:
2013
+ --port <n> Override default port (default: 4567)
2014
+ ```
2015
+
2016
+ ### Examples
2017
+
2018
+ ```bash
2019
+ # Start on a custom port
2020
+ the-campfire --port 8080
2021
+
2022
+ # Install as a background service
2023
+ the-campfire install
2024
+ the-campfire start
2025
+ the-campfire status
2026
+
2027
+ # Manage adapters
2028
+ the-campfire install-adapter @campfire/my-agent
2029
+ the-campfire uninstall-adapter my-agent
2030
+ ```
2031
+
2032
+ ---
2033
+
2034
+ ## REST API Reference
2035
+
2036
+ All endpoints are under `/api`.
2037
+
2038
+ ### Sessions
2039
+
2040
+ | Method | Path | Description |
2041
+ |--------|------|-------------|
2042
+ | `POST` | `/api/sessions/create` | Create a new session |
2043
+ | `GET` | `/api/sessions` | List all sessions |
2044
+ | `GET` | `/api/sessions/:id` | Get session details |
2045
+ | `PATCH` | `/api/sessions/:id/name` | Rename a session |
2046
+ | `DELETE` | `/api/sessions/:id` | Delete a session |
2047
+ | `POST` | `/api/sessions/:id/kill` | Kill a running session |
2048
+ | `POST` | `/api/sessions/:id/relaunch` | Relaunch a stopped session |
2049
+ | `POST` | `/api/sessions/:id/archive` | Archive a session |
2050
+ | `POST` | `/api/sessions/:id/unarchive` | Unarchive a session |
2051
+ | `POST` | `/api/sessions/:id/fork` | Fork a session at a specific point |
2052
+ | `POST` | `/api/sessions/:id/invite` | Create a shareable invite link |
2053
+ | `GET` | `/api/sessions/join/:token` | Resolve an invite token |
2054
+ | `POST` | `/api/sessions/create-with-progress` | Create a container session with SSE progress (returns `text/event-stream`) |
2055
+
2056
+ ### Agents (autonomous profiles)
2057
+
2058
+ | Method | Path | Description |
2059
+ |--------|------|-------------|
2060
+ | `GET` | `/api/agents` | List agent profiles |
2061
+ | `GET` | `/api/agents/:id` | Get a profile |
2062
+ | `POST` | `/api/agents` | Create a profile |
2063
+ | `PUT` | `/api/agents/:id` | Update a profile |
2064
+ | `DELETE` | `/api/agents/:id` | Delete a profile |
2065
+ | `POST` | `/api/agents/:id/toggle` | Enable/disable a profile |
2066
+ | `POST` | `/api/agents/:id/run` | Trigger a manual run |
2067
+ | `POST` | `/api/agents/:id/webhook` | Trigger via webhook (requires webhook trigger enabled) |
2068
+ | `GET` | `/api/agents/:id/executions` | Execution history |
2069
+ | `GET` | `/api/agents/:id/export` | Export a portable profile |
2070
+ | `POST` | `/api/agents/import` | Import a profile (created disabled) |
2071
+
2072
+ ### Agent Races
2073
+
2074
+ | Method | Path | Description |
2075
+ |--------|------|-------------|
2076
+ | `POST` | `/api/races` | Start a race across two or more agent backends |
2077
+ | `GET` | `/api/races` | List saved race results |
2078
+ | `GET` | `/api/races/:id` | Get race status and entries |
2079
+ | `GET` | `/api/races/:id/entries/:entryId/diff` | Load the git diff for one race entry |
2080
+ | `POST` | `/api/races/:id/pick` | Merge the selected winner by `sessionId` |
2081
+ | `POST` | `/api/races/:id/cancel` | Cancel a running race |
2082
+ | `DELETE` | `/api/races/:id` | Delete a saved race record |
2083
+
2084
+ ### Authentication
2085
+
2086
+ | Method | Path | Description |
2087
+ |--------|------|-------------|
2088
+ | `GET` | `/api/auth/status` | Check if auth is enabled and user is logged in |
2089
+ | `POST` | `/api/auth/login` | Authenticate with password |
2090
+ | `POST` | `/api/auth/logout` | Invalidate session token |
2091
+ | `POST` | `/api/auth/setup` | Initial password setup |
2092
+ | `POST` | `/api/auth/disable` | Remove authentication |
2093
+
2094
+ ### Skills & Plugins
2095
+
2096
+ | Method | Path | Description |
2097
+ |--------|------|-------------|
2098
+ | `GET` | `/api/skills` | List all plugins with status |
2099
+ | `GET` | `/api/skills/:id` | Get a single plugin |
2100
+ | `GET` | `/api/skills/:id/skill/:name` | Read a skill's SKILL.md content |
2101
+ | `GET` | `/api/skills/:id/command/:name` | Read a command's content |
2102
+ | `POST` | `/api/skills/:id/toggle` | Enable/disable a plugin in Campfire |
2103
+
2104
+ ### Session Folders
2105
+
2106
+ | Method | Path | Description |
2107
+ |--------|------|-------------|
2108
+ | `GET` | `/api/folders` | List all folders |
2109
+ | `POST` | `/api/folders` | Create a folder (`{"name": "...", "color": "..."}`) |
2110
+ | `PATCH` | `/api/folders/:id` | Update folder name/color |
2111
+ | `DELETE` | `/api/folders/:id` | Delete a folder |
2112
+ | `POST` | `/api/folders/:folderId/sessions/:sessionId` | Add session to folder |
2113
+ | `DELETE` | `/api/folders/sessions/:sessionId` | Remove session from folder |
2114
+
2115
+ ### Session Recording
2116
+
2117
+ | Method | Path | Description |
2118
+ |--------|------|-------------|
2119
+ | `GET` | `/api/recordings` | List all recording files |
2120
+ | `GET` | `/api/recordings/:filename` | Load a recording for replay |
2121
+ | `GET` | `/api/sessions/:id/recording/status` | Check recording status |
2122
+ | `POST` | `/api/sessions/:id/recording/start` | Start recording a session |
2123
+ | `POST` | `/api/sessions/:id/recording/stop` | Stop recording a session |
2124
+ | `GET` | `/api/sessions/:id/history` | Get session message history |
2125
+
2126
+ ### Gallery
2127
+
2128
+ | Method | Path | Description |
2129
+ |--------|------|-------------|
2130
+ | `GET` | `/api/gallery` | List entries (filters: `backend`, `minCost`, `maxCost`, `tags`, `featured`, `sortBy`, `sortOrder`) |
2131
+ | `GET` | `/api/gallery/:id` | Get a single entry |
2132
+ | `POST` | `/api/gallery` | Publish a session to the gallery |
2133
+ | `PUT` | `/api/gallery/:id` | Update an entry |
2134
+ | `DELETE` | `/api/gallery/:id` | Delete an entry |
2135
+ | `POST` | `/api/gallery/:id/vote` | Vote on an entry (`{"direction": 1}` or `{"direction": -1}`) |
2136
+ | `POST` | `/api/gallery/:id/feature` | Toggle featured status |
2137
+ | `POST` | `/api/gallery/:id/public-link` | Create a tokenized public replay link |
2138
+ | `GET` | `/api/public-replay/:token` | Resolve a public replay (unauthenticated) |
2139
+ | `GET` | `/api/gallery/:id/skill-preview` | Preview the ClawHub SKILL.md export |
2140
+ | `POST` | `/api/gallery/:id/export-clawhub` | Publish the entry to ClawHub |
2141
+ | `GET` | `/api/clawhub/search` | Search ClawHub skills |
2142
+ | `GET` | `/api/clawhub/status` | Check clawhub CLI availability |
2143
+ | `POST` | `/api/clawhub/install` | Install a ClawHub skill |
2144
+ | `GET` | `/api/moltbook/status` | Check Moltbook agent registration |
2145
+ | `POST` | `/api/gallery/:id/post-moltbook` | Post the entry to Moltbook |
2146
+
2147
+ ### Webhooks
2148
+
2149
+ | Method | Path | Description |
2150
+ |--------|------|-------------|
2151
+ | `GET` | `/api/webhooks` | List all webhooks |
2152
+ | `GET` | `/api/webhooks/:id` | Get a single webhook |
2153
+ | `POST` | `/api/webhooks` | Create a webhook |
2154
+ | `PUT` | `/api/webhooks/:id` | Update a webhook |
2155
+ | `DELETE` | `/api/webhooks/:id` | Delete a webhook |
2156
+ | `POST` | `/api/webhooks/:id/toggle` | Enable/disable a webhook |
2157
+ | `POST` | `/api/webhooks/:id/test` | Send a test event |
2158
+ | `POST` | `/api/webhooks/openclaw` | Inbound: spawn an OpenClaw session (token-guarded) |
2159
+ | `POST` | `/api/openclaw/inbound` | Inbound: deliver an OpenClaw channel message to a session |
2160
+
2161
+ ### Adapters
2162
+
2163
+ | Method | Path | Description |
2164
+ |--------|------|-------------|
2165
+ | `GET` | `/api/adapters` | List installed adapters |
2166
+ | `POST` | `/api/adapters/install` | Install an adapter from npm (`{"npmPackage": "..."}`) |
2167
+ | `DELETE` | `/api/adapters/:name` | Uninstall an adapter |
2168
+
2169
+ ### Backends & Models
2170
+
2171
+ | Method | Path | Description |
2172
+ |--------|------|-------------|
2173
+ | `GET` | `/api/backends` | List available agent backends (with availability status) |
2174
+ | `GET` | `/api/backends/:id/models` | Get available models for a backend |
2175
+
2176
+ ### Cron Jobs
2177
+
2178
+ | Method | Path | Description |
2179
+ |--------|------|-------------|
2180
+ | `GET` | `/api/cron/jobs` | List all jobs (with computed `nextRunAt`) |
2181
+ | `GET` | `/api/cron/jobs/:id` | Get a single job |
2182
+ | `POST` | `/api/cron/jobs` | Create a new job |
2183
+ | `PUT` | `/api/cron/jobs/:id` | Update a job |
2184
+ | `DELETE` | `/api/cron/jobs/:id` | Delete a job |
2185
+ | `POST` | `/api/cron/jobs/:id/toggle` | Enable/disable a job |
2186
+ | `POST` | `/api/cron/jobs/:id/run` | Manually trigger a job |
2187
+ | `GET` | `/api/cron/jobs/:id/executions` | Get execution history |
2188
+
2189
+ ### Environments
2190
+
2191
+ | Method | Path | Description |
2192
+ |--------|------|-------------|
2193
+ | `GET` | `/api/envs` | List all environment profiles |
2194
+ | `GET` | `/api/envs/:slug` | Get a single profile |
2195
+ | `POST` | `/api/envs` | Create a profile (`{"name": "...", "variables": {...}}`) |
2196
+ | `PUT` | `/api/envs/:slug` | Update a profile |
2197
+ | `DELETE` | `/api/envs/:slug` | Delete a profile |
2198
+
2199
+ ### Collaboration
2200
+
2201
+ | Method | Path | Description |
2202
+ |--------|------|-------------|
2203
+ | `GET` | `/api/voting-policy` | Get current voting policy |
2204
+ | `PUT` | `/api/voting-policy` | Set voting policy (`majority-rules`, `any-deny-blocks`, `owner-decides`) |
2205
+
2206
+ ### Git
2207
+
2208
+ | Method | Path | Description |
2209
+ |--------|------|-------------|
2210
+ | `GET` | `/api/git/repo-info` | Get repo info (root, branch, default branch) |
2211
+ | `GET` | `/api/git/branches` | List branches (with ahead/behind counts) |
2212
+ | `GET` | `/api/git/worktrees` | List worktrees |
2213
+ | `POST` | `/api/git/worktree` | Create a worktree |
2214
+ | `DELETE` | `/api/git/worktree` | Remove a worktree |
2215
+ | `POST` | `/api/git/fetch` | Git fetch |
2216
+ | `POST` | `/api/git/pull` | Git pull (returns ahead/behind counts) |
2217
+ | `GET` | `/api/git/pr-status` | Get GitHub PR status for a branch |
2218
+
2219
+ ### Filesystem
2220
+
2221
+ | Method | Path | Description |
2222
+ |--------|------|-------------|
2223
+ | `GET` | `/api/fs/list` | List directories in a path |
2224
+ | `GET` | `/api/fs/home` | Get home directory and current working directory |
2225
+ | `GET` | `/api/fs/tree` | Get recursive directory tree |
2226
+ | `GET` | `/api/fs/read` | Read a file (max 2MB) |
2227
+ | `PUT` | `/api/fs/write` | Write a file |
2228
+ | `GET` | `/api/fs/diff` | Git diff for a single file |
2229
+ | `GET` | `/api/fs/claude-md` | Find CLAUDE.md files |
2230
+ | `PUT` | `/api/fs/claude-md` | Create or update CLAUDE.md |
2231
+
2232
+ ### Collective Intelligence
2233
+
2234
+ | Method | Path | Description |
2235
+ |--------|------|-------------|
2236
+ | `GET` | `/api/sessions/:id/memory` | List memory fragments for a session |
2237
+ | `POST` | `/api/sessions/:id/memory` | Store a new memory fragment |
2238
+ | `GET` | `/api/sessions/:id/memory/query` | Semantic search (`?q=...&limit=10`) |
2239
+ | `POST` | `/api/sessions/:id/memory/consolidate` | Consolidate session memory into knowledge |
2240
+ | `GET` | `/api/memory/global` | Query all memory across sessions (`?q=...`) |
2241
+ | `GET` | `/api/sessions/:id/deliberations` | List active deliberation proposals |
2242
+ | `GET` | `/api/sessions/:id/deliberations/:proposalId` | Get a deliberation proposal |
2243
+ | `POST` | `/api/sessions/:id/deliberations/:proposalId/respond` | Respond to a proposal |
2244
+ | `POST` | `/api/sessions/:id/deliberations/:proposalId/resolve` | Force-resolve a proposal |
2245
+ | `POST` | `/api/sessions/route-task` | Route a task to the best-suited session |
2246
+ | `GET` | `/api/capabilities` | List all registered agent capabilities |
2247
+ | `GET` | `/api/capabilities/history` | Get task execution history |
2248
+ | `POST` | `/api/capabilities/feedback` | Submit outcome feedback for a task |
2249
+ | `GET` | `/api/sessions/:id/context/stream` | Get shared context thread for a session |
2250
+ | `GET` | `/api/sessions/:id/context/consensus` | Get consensus state for a session |
2251
+ | `GET` | `/api/sessions/:id/context/thread/:fragmentId` | Get semantic thread from a fragment |
2252
+
2253
+ ### Prompt Library
2254
+
2255
+ | Method | Path | Description |
2256
+ |--------|------|-------------|
2257
+ | `GET` | `/api/prompts` | List prompts (optional `?cwd=` to filter by project path) |
2258
+ | `POST` | `/api/prompts` | Create a prompt (`{"name", "content", "scope", "projectPath?"}`) |
2259
+ | `PUT` | `/api/prompts/:id` | Update a prompt |
2260
+ | `DELETE` | `/api/prompts/:id` | Delete a prompt |
2261
+
2262
+ ### Linear Integration
2263
+
2264
+ | Method | Path | Description |
2265
+ |--------|------|-------------|
2266
+ | `GET` | `/api/linear/connection` | Check connection status and list teams |
2267
+ | `GET` | `/api/linear/issues` | Search issues (`?query=&limit=`) |
2268
+ | `GET` | `/api/linear/teams` | List all Linear teams |
2269
+ | `GET` | `/api/linear/team/:id/states` | Get workflow states for a team |
2270
+ | `GET` | `/api/linear/projects` | List all Linear projects |
2271
+ | `GET` | `/api/linear/project-mapping` | Get project-repo mapping (`?repoRoot=`) |
2272
+ | `POST` | `/api/linear/project-mapping` | Create or update a project-repo mapping |
2273
+ | `DELETE` | `/api/linear/project-mapping` | Remove a project-repo mapping |
2274
+ | `POST` | `/api/linear/session/:id/link-issue` | Link a Linear issue to a session |
2275
+ | `GET` | `/api/linear/session/:id/issue` | Get the linked issue for a session |
2276
+ | `POST` | `/api/linear/issues/:id/transition` | Transition an issue to a new state |
2277
+
2278
+ ### Settings & System
2279
+
2280
+ | Method | Path | Description |
2281
+ |--------|------|-------------|
2282
+ | `GET` | `/api/settings` | Get application settings |
2283
+ | `PUT` | `/api/settings` | Update settings (OpenRouter key/model, Linear API key, embedding provider) |
2284
+ | `GET` | `/api/containers/status` | Check Docker availability |
2285
+ | `GET` | `/api/containers/images` | List Docker images |
2286
+ | `GET` | `/api/usage-limits` | Get account usage limits |
2287
+ | `GET` | `/api/sessions/:id/usage-limits` | Get session-specific usage limits |
2288
+ | `GET` | `/api/update-check` | Check for updates |
2289
+ | `POST` | `/api/update-check` | Force update check |
2290
+ | `POST` | `/api/update` | Install update and restart (service mode only) |
2291
+ | `GET` | `/api/terminal` | Get terminal status |
2292
+ | `POST` | `/api/terminal/spawn` | Spawn embedded terminal |
2293
+ | `POST` | `/api/terminal/kill` | Kill embedded terminal |
2294
+
2295
+ ---
2296
+
2297
+ ## WebSocket Protocol
2298
+
2299
+ ### Browser Connection
2300
+
2301
+ Connect to `ws://localhost:4567/ws/browser/:sessionId` to receive real-time session events.
2302
+
2303
+ **Messages from server:**
2304
+
2305
+ ```json
2306
+ {"type": "session_init", "session": {"session_id": "...", "model": "...", "cwd": "...", ...}}
2307
+ {"type": "assistant", "message": {"id": "msg_01...", "content": [{"type": "text", "text": "..."}]}}
2308
+ {"type": "stream_event", "event": {"type": "content_block_delta", ...}}
2309
+ {"type": "result", "data": {"total_cost_usd": 0.42, "num_turns": 5, ...}}
2310
+ {"type": "permission_request", "request": {"tool_name": "Bash", "input": {"command": "rm -rf /"}, ...}}
2311
+ {"type": "permission_cancelled", "request_id": "pr_01..."}
2312
+ {"type": "tool_progress", "tool_use_id": "tu_01...", "tool_name": "Bash", "elapsed_time_seconds": 5}
2313
+ {"type": "status_change", "status": "running"}
2314
+ {"type": "cli_connected"}
2315
+ {"type": "cli_disconnected"}
2316
+ {"type": "presence_update", "viewers": [{"id": "abc", "name": "Viewer 1", "role": "owner"}]}
2317
+ {"type": "role_assigned", "role": "owner", "viewerId": "abc"}
2318
+ {"type": "vote_update", "request_id": "...", "votes": {"allow": 2, "deny": 0}, "total": 3, "deadline": 1771154026}
2319
+ {"type": "vote_resolved", "request_id": "...", "allowed": true, "policy": "majority-rules"}
2320
+ {"type": "session_name_update", "name": "Fix auth bug"}
2321
+ {"type": "pr_status_update", "pr": {...}, "available": true}
2322
+ {"type": "mcp_status", "servers": [...]}
2323
+ {"type": "message_history", "messages": [...]}
2324
+ {"type": "event_replay", "events": [{"seq": 1, "message": {...}}]}
2325
+ ```
2326
+
2327
+ **Messages from browser:**
2328
+
2329
+ ```json
2330
+ {"type": "user_message", "content": "Fix the bug in auth.ts", "client_msg_id": "..."}
2331
+ {"type": "permission_response", "request_id": "pr_01...", "behavior": "allow"}
2332
+ {"type": "interrupt", "client_msg_id": "..."}
2333
+ {"type": "set_model", "model": "claude-sonnet-4-5-20250929", "client_msg_id": "..."}
2334
+ {"type": "set_permission_mode", "mode": "bypassPermissions", "client_msg_id": "..."}
2335
+ {"type": "session_subscribe", "last_seq": 42}
2336
+ {"type": "session_ack", "last_seq": 50}
2337
+ {"type": "mcp_get_status", "client_msg_id": "..."}
2338
+ {"type": "mcp_toggle", "serverName": "filesystem", "enabled": true}
2339
+ {"type": "mcp_set_servers", "servers": {"my-server": {"type": "stdio", "command": "node", "args": ["server.js"]}}}
2340
+ ```
2341
+
2342
+ **Collective Intelligence messages (browser → server):**
2343
+
2344
+ ```json
2345
+ {"type": "memory_query", "query": "authentication pattern", "limit": 5}
2346
+ {"type": "memory_store", "content": "...", "memoryType": "observation", "tags": ["auth"]}
2347
+ {"type": "deliberation_respond", "proposalId": "...", "stance": "approve", "reasoning": "..."}
2348
+ {"type": "deliberation_resolve", "proposalId": "..."}
2349
+ {"type": "capability_probe_response", "probeId": "...", "confidence": 0.9, "reasoning": "..."}
2350
+ {"type": "route_task", "taskDescription": "Refactor auth module", "availableSessions": ["s1", "s2"]}
2351
+ {"type": "inject_thought", "content": "...", "thoughtType": "observation", "parentId": "..."}
2352
+ ```
2353
+
2354
+ **Collective Intelligence messages (server → browser):**
2355
+
2356
+ ```json
2357
+ {"type": "memory_stored", "fragment": {"id": "...", "content": "...", "tags": ["auth"], ...}}
2358
+ {"type": "memory_query_result", "query": "auth pattern", "results": [...]}
2359
+ {"type": "memory_consolidated", "tag": "auth", "knowledge": {"summary": "...", ...}}
2360
+ {"type": "deliberation_proposal", "proposal": {"id": "...", "question": "...", ...}}
2361
+ {"type": "deliberation_resolved", "resolution": {"proposalId": "...", "outcome": "approved", ...}}
2362
+ {"type": "capability_probe", "probeId": "...", "taskDescription": "...", "instruction": "..."}
2363
+ {"type": "route_result", "result": {"sessionId": "...", "confidence": 0.85, "reasoning": "...", ...}}
2364
+ {"type": "shared_thought", "fragment": {"id": "...", "content": "...", "semanticLinks": [...], ...}}
2365
+ {"type": "consensus_update", "state": {"consensusScore": 0.8, "isControversial": false, ...}}
2366
+ ```
2367
+
2368
+ **Reconnection:**
2369
+
2370
+ The browser tracks a sequence number (`seq`) for each message. On reconnect, it sends `session_subscribe` with the last received `seq`. The server replies with `event_replay` containing all events since that point, so the browser catches up without missing anything.
2371
+
2372
+ Protocol details are documented in [`CLAUDE.md`](CLAUDE.md).
2373
+
2374
+ ---
2375
+
2376
+ ## Development
2377
+
2378
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, dev mode, project structure, testing, and how to write adapters.
2379
+
2380
+ ---
2381
+
2382
+ ## Security
2383
+
2384
+ Found a vulnerability? Please report it privately — see [SECURITY.md](SECURITY.md). The same document covers hardening notes for self-hosters (auth, invite-link semantics, MCP injection policy).
2385
+
2386
+ ## License
2387
+
2388
+ MIT