the-campfire 0.2.0 → 0.2.1

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