npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

the-campfire

v0.4.2

Published

Campfire — collaborative web platform for AI coding agents. Run Claude Code, Codex, Goose, Aider, and more from one browser UI with real-time collaboration, permission voting, and automation.

Readme


Table of Contents


Quick Start

There are four ways to run Campfire: from npm, from source, with Docker, or as a native macOS app.

Option 1: npm (fastest)

If you just want to run Campfire without cloning the repo:

# Install Bun if you don't have it
curl -fsSL https://bun.sh/install | bash

# Run Campfire (downloads and starts automatically)
bunx the-campfire

Open http://localhost:4567. That's it.

To run on a different port:

bunx the-campfire --port 8080

Option 2: Run from source (native)

Clone the repository and run directly with Bun:

# 1. Clone the repo
git clone https://github.com/stretchcloud/campfire.git
cd campfire

# 2. Install dependencies
cd web
bun install

# 3. Build and start
bun run build
bun run start

Open http://localhost:4567. That's it.

Contributing? Use bun run dev for hot reload during frontend development. See the Development section for details.

Option 3: Docker

Pull the pre-built image from the GitHub Container Registry (no clone, no build):

docker run -d \
  --name campfire \
  -p 4567:4567 \
  -v campfire-data:/home/campfire/.campfire \
  --restart unless-stopped \
  ghcr.io/stretchcloud/campfire:latest

Open http://localhost:4567. Pin a specific version by tag instead of latest, e.g. ghcr.io/stretchcloud/campfire:0.2.1.

Or build and run from source with Docker Compose (no Bun installation needed):

# 1. Clone the repo
git clone https://github.com/stretchcloud/campfire.git
cd campfire

# 2. Build and start the container
docker compose up

# Or build and run in the background
docker compose up -d

Open http://localhost:4567.

To build the Docker image manually without Compose:

# Build the image
docker build -t campfire:latest .

# Run the container
docker run -d \
  --name campfire \
  -p 4567:4567 \
  -v campfire-data:/home/campfire/.campfire \
  --restart unless-stopped \
  campfire:latest

To stop and remove:

# Docker Compose
docker compose down

# Or manual
docker stop campfire && docker rm campfire

See Docker Deployment for advanced configuration (mounting agent CLIs, reverse proxy, environment variables).

Option 4: macOS Desktop App (Apple Silicon)

A native desktop app for Macs with Apple Silicon. It bundles the full Campfire server and the Bun runtime — no Bun install needed, every feature included.

  1. Download Campfire-<version>-arm64.dmg from the latest release
  2. Drag Campfire into Applications
  3. First launch: right-click the app → Open (the build is not notarized with Apple; if macOS still refuses, run xattr -cr /Applications/Campfire.app once)

The app stores its data in the same ~/.campfire directory as the CLI, so sessions, recordings, and settings are shared. If a Campfire server is already running on port 4567 (for example the the-campfire background service), the app attaches to it instead of starting a second one. Agent CLIs (claude, codex, …) still need to be installed on your machine.

To build the DMG from source:

make dmg    # stages the backend, then packages desktop/dist/Campfire-<version>-arm64.dmg

Requirements

For native (npm or source):

  • Bun >= 1.0
  • At least one agent CLI installed and on your PATH:
    • Claude Codenpm install -g @anthropic-ai/claude-code
    • Codexnpm install -g @openai/codex
    • Goosebrew install goose or see docs
    • Aiderpip install aider-chat
    • OpenHands — see docs
    • OpenClawopenclaw binary on PATH, set OPENCLAW_GATEWAY_TOKEN and OPENCLAW_GATEWAY_URL
    • OpenCodeopencode binary on PATH

For Docker:


Features

Multi-Agent Sessions

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.

Supported backends:

| Backend | Protocol | How it connects | |---------|----------|-----------------| | Claude Code | NDJSON over WebSocket | Spawned with --sdk-url flag | | Codex | JSON-RPC over stdio | Spawned as codex app-server | | Goose | JSON-RPC 2.0 (ACP) over stdio | Spawned as goose acp --with-builtin developer --with-builtin memory | | Aider | stdout parsing over stdio | Spawned as aider --no-pretty --yes --no-auto-commits | | OpenHands | JSON-RPC 2.0 (ACP) over stdio | Spawned as openhands acp | | OpenClaw | JSON-RPC 2.0 (ACP) over stdio | Spawned as openclaw acp; requires OPENCLAW_GATEWAY_TOKEN + OPENCLAW_GATEWAY_URL | | OpenCode | JSON-RPC 2.0 (ACP) over stdio | Spawned as opencode acp; model set via OPENCODE_MODEL |

Creating a session:

  1. Click New Session in the sidebar
  2. Choose a backend (Claude Code, Codex, Goose, Aider, OpenHands, OpenClaw, or OpenCode)
  3. Select a model (backend-specific model lists)
  4. Set the working directory for the session
  5. Optionally choose a permission mode, environment profile, or git branch
  6. Click Create

Session options:

| Option | Description | |--------|-------------| | Backend | Which agent CLI to use | | Model | AI model to run (e.g. claude-sonnet-4-5-20250929, o3, gpt-4.1) | | Permission mode | default, bypassPermissions, oneTouchApprovals, manualApprovals | | Working directory | Folder the agent operates in | | Environment profile | Pre-saved set of environment variables to inject | | Git branch | Check out a specific branch before starting | | Use worktree | Create an isolated git worktree (keeps branches separate) | | Create branch | Create the branch if it doesn't exist | | Docker container | Run the session inside a Docker container (Claude only) | | Internet access | Enable web search for Codex | | Allowed tools | Restrict which tools the agent can use |

Session lifecycle:

  • Running — agent is processing, streaming output
  • Idle — agent is waiting for input
  • Compacting — agent is compacting context (Claude Code)
  • Exited — agent process has stopped

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.

Managing sessions:

  • Rename — click the session name in the sidebar to edit inline
  • Kill — stop the running agent process
  • Relaunch — restart a stopped session (uses --resume for Claude Code)
  • Archive — hide the session from the active list while preserving history
  • Delete — permanently remove the session (also cleans up worktrees and containers)

Real-Time Collaboration

Share any session with teammates using invite links. Multiple people can watch and interact with the same session simultaneously.

How to share a session:

  1. Open a running session
  2. Click the Share button in the top bar
  3. Choose a role for the invited user:
    • Collaborator — can send messages and vote on permissions
    • Spectator — watch-only (cannot send messages or vote)
  4. Copy the generated link and share it

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.

Presence indicators:

Connected users appear as colored avatars in the top bar:

  • Blue — Owner (the person who created the session)
  • Green — Collaborator (can interact)
  • Gray — Spectator (watch-only)

Presence updates are broadcast in real time — you see when someone joins or leaves.

Roles and permissions:

| Capability | Owner | Collaborator | Spectator | |-----------|-------|--------------|-----------| | View session output | Yes | Yes | Yes | | Send messages | Yes | Yes | No | | Approve/deny permissions | Yes | Yes | No | | Vote on tool calls | Yes | Yes | No | | Interrupt the agent | Yes | Yes | No | | Change model or mode | Yes | Yes | No | | Configure MCP servers | Yes | Yes | No |

The first browser to connect to a session becomes the Owner. Subsequent connections default to Collaborator unless they join via a spectator invite link.


Permission Control & Voting

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.

Permission banner displays:

| Tool | What you see | |------|-------------| | Bash | The exact command with $ prefix | | Edit | Side-by-side diff showing old vs new content | | Write | The full file content being written | | Read | The file path being read | | Glob / Grep | The search pattern and path | | AskUserQuestion | Multiple-choice options with a custom text input |

Actions available:

  • Allow — approve this specific tool call
  • Deny — reject this tool call
  • Permission suggestions — apply a broader rule (e.g. "Allow for session", "Allow always", "Trust directory")

Voting (collaborative sessions):

When multiple viewers are connected, permission requests become votes. The voting behavior is configurable:

| Policy | How it works | |--------|-------------| | majority-rules | Action is allowed if more than half vote "allow" (default) | | any-deny-blocks | A single "deny" vote blocks the action | | owner-decides | Only the owner's vote counts |

Configure the voting policy via the UI or API:

# Get current policy
curl http://localhost:4567/api/voting-policy

# Change policy
curl -X PUT http://localhost:4567/api/voting-policy \
  -H "Content-Type: application/json" \
  -d '{"policy": "any-deny-blocks"}'

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.


Session Replay

Scrub through completed sessions at 1x / 2x / 4x / 8x speed. Every tool call, permission decision, and streaming token is preserved in protocol recordings.

How to use replay:

  1. Open a completed session from the sidebar
  2. Click the Recordings section to see available recording files
  3. Click a recording to open the replay player
  4. Use the playback controls to play, pause, and change speed

Replay controls:

  • Play / Pause toggle
  • Speed selector: 1x, 2x, 4x, 8x
  • Progress scrubber for seeking

Recording format:

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:

{"ts": 1771153996875, "dir": "in", "raw": "{\"type\":\"system\",...}", "ch": "cli"}
  • ts — Unix timestamp in milliseconds
  • dir"in" (received by server) or "out" (sent by server)
  • ch"cli" (agent process) or "browser" (frontend)
  • raw — exact original message string, never re-serialized

Recording management:

# List all recordings
curl http://localhost:4567/api/recordings

# Check if a session is being recorded
curl http://localhost:4567/api/sessions/:id/recording/status

# Start/stop recording for a specific session
curl -X POST http://localhost:4567/api/sessions/:id/recording/start
curl -X POST http://localhost:4567/api/sessions/:id/recording/stop

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).


Fork & Branch

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.

How to fork:

  1. From the top bar — click the Fork button to fork at the current point
  2. From any message — hover over a message and click the fork icon to fork from that specific point

What happens when you fork:

  1. The message history is copied up to the selected point
  2. If the session is in a git repository, a new worktree is created for isolation
  3. A new session is launched with the copied history
  4. The forked session shows a "forked from" indicator linking back to the original

Fork options:

curl -X POST http://localhost:4567/api/sessions/:id/fork \
  -H "Content-Type: application/json" \
  -d '{
    "messageIndex": 5,
    "model": "claude-sonnet-4-5-20250929",
    "permissionMode": "bypassPermissions",
    "branch": "experiment/new-approach"
  }'

| Field | Description | |-------|-------------| | messageIndex | Fork after this message (0-indexed). Omit to fork at the end. | | model | Override the model for the forked session | | permissionMode | Override permission mode | | branch | Git branch name for the worktree |


Session Gallery

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.

How to publish:

  1. Navigate to the Gallery page from the sidebar
  2. Click Add to Gallery
  3. Select a completed session
  4. Add a name, description, and tags
  5. Click Publish

Browsing the gallery:

The gallery supports filtering and sorting:

| Filter | Example | |--------|---------| | Backend | Show only Claude Code sessions | | Cost range | Sessions between $0.01 and $1.00 | | Tags | Filter by migration, refactor, bugfix, etc. | | Featured only | Show only featured entries |

| Sort by | Description | |---------|-------------| | Votes | Most upvoted first | | Recent | Newest first | | Cost | Cheapest or most expensive first | | Duration | Shortest or longest first |

Voting and featuring:

  • Click the up/down arrows on any gallery card to vote (anonymous, IP-deduplicated)
  • Admins can toggle the Featured star to highlight exceptional sessions

Gallery entry metadata:

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.

Public share links:

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.

ClawHub export:

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.

Moltbook posting:

Entries can also be posted as "molts" to Moltbook, a social network for AI agents (POST /api/gallery/:id/post-moltbook; configure the agent account in Settings).

# List gallery entries with filters
curl "http://localhost:4567/api/gallery?backend=claude&sortBy=votes&featured=true"

# Publish a session
curl -X POST http://localhost:4567/api/gallery \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "abc-123",
    "name": "Migrated auth to OAuth2",
    "description": "Full migration from session-based auth to OAuth2 with PKCE",
    "tags": ["migration", "auth", "oauth"]
  }'

# Vote on an entry
curl -X POST http://localhost:4567/api/gallery/:id/vote \
  -H "Content-Type: application/json" \
  -d '{"direction": 1}'

# Toggle featured status
curl -X POST http://localhost:4567/api/gallery/:id/feature

Prompt Library

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.

How to create a prompt:

  1. Navigate to the Prompts page from the sidebar
  2. Click + New Prompt
  3. Enter a name and the prompt text
  4. Choose scope: Global (available everywhere) or Project (scoped to a path prefix)
  5. Click Save

Inserting prompts in the composer:

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.

The full content of the selected prompt replaces the @query in your message, so you can mix prompt snippets with your own text.

CWD-scoped loading:

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.

REST API:

# List prompts (optionally filtered by cwd)
curl "http://localhost:4567/api/prompts?cwd=/home/user/my-project"

# Create a prompt
curl -X POST http://localhost:4567/api/prompts \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Code review checklist",
    "content": "Please review for: 1) correctness, 2) edge cases, 3) performance, 4) test coverage",
    "scope": "global"
  }'

# Update a prompt
curl -X PUT http://localhost:4567/api/prompts/:id \
  -H "Content-Type: application/json" \
  -d '{"name": "Updated name", "content": "Updated content"}'

# Delete a prompt
curl -X DELETE http://localhost:4567/api/prompts/:id

Prompts are stored at ~/.campfire/prompts.json.


Linear Integration

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.

Setup:

  1. Navigate to IntegrationsLinear from the sidebar
  2. Create a personal API key at linear.app/settings/api
  3. Paste your key and click Connect

What it enables:

  • Browse and search Linear issues when creating a new session
  • Auto-generate a recommended git branch name from the issue (e.g. feat/eng-123-add-auth)
  • Link issues to sessions — track which issue each session is working on
  • Map Linear teams/projects to git repositories for automatic filtering
  • Auto-transition issues to "In Progress" when a linked session starts

Project-repo mapping:

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.

Issue-session workflow:

  1. Open the New Session page in a git repo with a linked Linear team
  2. The Linear Issues section appears automatically
  3. Search for an issue by title or identifier
  4. Select an issue — a branch name is auto-generated (e.g. feat/ENG-123-add-oauth-flow)
  5. The worktree toggle activates with the generated branch name
  6. Create the session — the issue is linked and transitions to "In Progress"

REST API:

# Check connection status
curl http://localhost:4567/api/linear/connection
# → {"connected": true, "viewer": {"name": "...", "email": "..."}, "teams": [...]}

# Search issues (cached, deduplicated)
curl "http://localhost:4567/api/linear/issues?query=auth&limit=10"

# List teams
curl http://localhost:4567/api/linear/teams

# Get workflow states for a team
curl http://localhost:4567/api/linear/team/:teamId/states

# Project-repo mapping
curl http://localhost:4567/api/linear/project-mapping?repoRoot=/path/to/repo
curl -X POST http://localhost:4567/api/linear/project-mapping \
  -H "Content-Type: application/json" \
  -d '{"repoRoot": "/path/to/repo", "teamId": "...", "teamKey": "ENG", "teamName": "Engineering"}'
curl -X DELETE http://localhost:4567/api/linear/project-mapping \
  -H "Content-Type: application/json" \
  -d '{"repoRoot": "/path/to/repo"}'

# Link an issue to a session
curl -X POST http://localhost:4567/api/linear/session/:sessionId/link-issue \
  -H "Content-Type: application/json" \
  -d '{"issueId": "...", "identifier": "ENG-123", "title": "Add OAuth", "url": "...", "state": "Todo", "teamKey": "ENG"}'

# Get linked issue for a session
curl http://localhost:4567/api/linear/session/:sessionId/issue

# Transition an issue's state
curl -X POST http://localhost:4567/api/linear/issues/:issueId/transition \
  -H "Content-Type: application/json" \
  -d '{"stateId": "..."}'

Caching:

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.

Data storage:

| File | Contents | |------|----------| | ~/.campfire/settings.json | Linear API key (never exposed via GET) | | ~/.campfire/linear-projects.json | Repo → team/project mappings | | ~/.campfire/linear-session-issues.json | Session → issue links |


Webhooks

Receive HTTP POST notifications when events happen in your sessions. Configure webhooks with event filters, HMAC-SHA256 signing, and automatic retries.

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.

How to set up a webhook:

  1. Navigate to the Webhooks page from the sidebar
  2. Click Create Webhook
  3. Enter the destination URL
  4. Select which events to subscribe to
  5. Optionally add a signing secret and session filters
  6. Click Create

Available events:

| Event | When it fires | |-------|---------------| | session.created | A new session starts | | session.completed | A session finishes successfully | | session.failed | A session exits with an error | | permission.requested | An agent requests permission for a tool call | | permission.resolved | A permission request is approved or denied | | turn.completed | An agent completes a turn (each back-and-forth) | | cost.threshold | Session cost crosses a threshold |

Payload format:

{
  "event": "session.completed",
  "timestamp": 1771153996875,
  "sessionId": "abc-123",
  "data": {
    "backendType": "claude",
    "model": "claude-sonnet-4-5-20250929",
    "totalCostUsd": 0.42,
    "numTurns": 12,
    "durationMs": 180000
  }
}

HMAC-SHA256 signing:

If you provide a secret, every delivery includes an X-Campfire-Signature header:

X-Campfire-Signature: sha256=<hex-encoded-hmac>

Verify the signature on your server by computing HMAC-SHA256(secret, request_body) and comparing.

Retry behavior:

Failed deliveries are retried 3 times with exponential backoff: 1s, 5s, 15s. Delivery stats (total, failed, last delivery time) are tracked per webhook.

Session filters:

Narrow a webhook to specific sessions by backend type or working directory:

{
  "sessionFilter": {
    "backendType": "claude",
    "cwd": "/home/user/my-project"
  }
}

Slack integration:

Webhook payloads include Slack-compatible formatting. Point a webhook at a Slack incoming webhook URL and events will render as formatted messages.

Testing:

Click the Test button on any webhook to send a test payload and verify your endpoint is receiving events correctly.

# Create a webhook
curl -X POST http://localhost:4567/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Slack Alerts",
    "url": "https://hooks.slack.com/services/...",
    "events": ["session.completed", "session.failed", "cost.threshold"],
    "secret": "my-signing-secret",
    "enabled": true
  }'

# Test delivery
curl -X POST http://localhost:4567/api/webhooks/:id/test

# Toggle enable/disable
curl -X POST http://localhost:4567/api/webhooks/:id/toggle

Scheduled Tasks (Cron)

Run autonomous agent sessions on a schedule — daily test suites, nightly code reviews, weekly dependency updates, or one-shot migration scripts.

How to create a scheduled task:

  1. Navigate to the Scheduled page from the sidebar
  2. Click Create Job
  3. Fill in the form:
    • Name — human-readable label (e.g. "Nightly Test Suite")
    • Prompt — the instruction to send to the agent
    • Schedule — cron expression (0 2 * * *) or ISO datetime for one-shot
    • Backend — which agent to use
    • Model — which model to run
    • Working directory — where to run
    • Permission mode — typically bypassPermissions for autonomous execution
    • Environment profile — optional API keys and variables
  4. Click Create

Cron expression examples:

| Expression | Meaning | |-----------|---------| | 0 2 * * * | Every day at 2:00 AM | | 0 9 * * 1 | Every Monday at 9:00 AM | | */30 * * * * | Every 30 minutes | | 0 0 1 * * | First day of every month at midnight |

One-shot tasks:

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.

Execution tracking:

Each execution creates a session and tracks:

  • Start time and completion time
  • Success or failure status
  • Cost incurred
  • Link to the session for full replay

Jobs auto-disable after repeated consecutive failures to prevent runaway costs.

Managing jobs:

# List all jobs
curl http://localhost:4567/api/cron/jobs

# Create a recurring job
curl -X POST http://localhost:4567/api/cron/jobs \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nightly Tests",
    "prompt": "Run the full test suite and fix any failures",
    "schedule": "0 2 * * *",
    "recurring": true,
    "backendType": "claude",
    "model": "claude-sonnet-4-5-20250929",
    "cwd": "/home/user/my-project",
    "permissionMode": "bypassPermissions"
  }'

# Manually trigger a job
curl -X POST http://localhost:4567/api/cron/jobs/:id/run

# Enable/disable
curl -X POST http://localhost:4567/api/cron/jobs/:id/toggle

# View execution history
curl http://localhost:4567/api/cron/jobs/:id/executions

Adapter Registry

Install community agent adapters from npm to add new backends to Campfire. Adapters are npm packages with a campfireAdapter field in their package.json.

Related: you can also run 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.

Installing an adapter:

# Via CLI
the-campfire install-adapter @campfire/example-adapter

# Via API
curl -X POST http://localhost:4567/api/adapters/install \
  -H "Content-Type: application/json" \
  -d '{"npmPackage": "@campfire/example-adapter"}'

Once installed, the adapter appears as a new backend option when creating sessions.

Managing adapters in the UI:

  1. Navigate to the Adapters page from the sidebar
  2. View installed adapters with their metadata (name, version, protocol, models)
  3. Install new adapters by entering the npm package name
  4. Uninstall adapters with the remove button

Adapter metadata:

Each adapter's package.json must include:

{
  "campfireAdapter": {
    "name": "my-agent",
    "displayName": "My Agent",
    "binaryName": "my-agent-cli",
    "protocol": "stdio",
    "models": [
      { "value": "model-v1", "label": "Model V1" }
    ],
    "modes": [
      { "value": "default", "label": "Default" }
    ]
  }
}

Writing your own adapter:

See 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.

# List installed adapters
curl http://localhost:4567/api/adapters

# Uninstall
curl -X DELETE http://localhost:4567/api/adapters/my-agent

Cost Dashboard

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.

What's tracked:

  • Total cost in USD per session
  • Number of turns (back-and-forth exchanges)
  • Context usage percentage (how much of the context window is used)
  • Lines added and removed
  • Session duration

Shareable cost cards:

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.

Cost information in the UI:

  • Top bar — live cost ticker during active sessions
  • Task panel — detailed stats (cost, turns, context %, lines changed, duration)
  • Gallery cards — cost displayed on each published session

Environment Profiles

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.

How to use:

  1. Navigate to the Environments page from the sidebar
  2. Click Create Profile
  3. Enter a name (e.g. "Production", "Staging")
  4. Add key-value pairs for your environment variables
  5. Click Save

When creating a session, select an environment profile from the dropdown. All variables from that profile are injected into the agent's environment.

Profile structure:

{
  "name": "Production",
  "slug": "production",
  "variables": {
    "ANTHROPIC_API_KEY": "sk-ant-...",
    "DATABASE_URL": "postgres://prod-host/db",
    "REDIS_URL": "redis://prod-redis:6379"
  }
}

Profiles are stored as individual JSON files in ~/.campfire/envs/.

# List profiles
curl http://localhost:4567/api/envs

# Create a profile
curl -X POST http://localhost:4567/api/envs \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Staging",
    "variables": {
      "API_KEY": "sk-staging-...",
      "DEBUG": "true"
    }
  }'

# Update a profile
curl -X PUT http://localhost:4567/api/envs/staging \
  -H "Content-Type: application/json" \
  -d '{"variables": {"API_KEY": "sk-new-key", "DEBUG": "false"}}'

# Delete a profile
curl -X DELETE http://localhost:4567/api/envs/staging

Git Integration

Campfire tracks git state for every session and provides tools for branch and worktree management.

What's tracked per session:

  • Current branch name
  • Ahead/behind counts relative to the remote
  • Whether the session is in a worktree
  • Total lines added and removed (from tool calls)
  • Repository root path

This information is displayed in the sidebar next to each session and updated in real time.

Worktrees:

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.

When creating a session with "Use worktree" enabled:

  1. A new worktree is created for the selected branch
  2. The session runs in the worktree directory
  3. A CLAUDE.md file is injected with guardrails (e.g. "Stay on this branch")
  4. When the session is deleted, the worktree is cleaned up if there are no uncommitted changes

GitHub PR status:

If the gh CLI is installed and authenticated, Campfire polls for PR metadata on the session's branch:

  • PR title, number, state (open/closed/merged)
  • Draft status
  • Review decision (approved/changes requested/pending)
  • CI check status (passing/failing/pending)
  • Review thread counts (resolved/unresolved)

PR status is displayed in the task panel and updates automatically.

# Get repository info
curl "http://localhost:4567/api/git/repo-info?path=/home/user/project"

# List branches
curl "http://localhost:4567/api/git/branches?repoRoot=/home/user/project"

# Create a worktree
curl -X POST http://localhost:4567/api/git/worktree \
  -H "Content-Type: application/json" \
  -d '{
    "repoRoot": "/home/user/project",
    "branch": "feature/new-feature",
    "createBranch": true
  }'

# Fetch and pull
curl -X POST http://localhost:4567/api/git/fetch \
  -H "Content-Type: application/json" \
  -d '{"repoRoot": "/home/user/project"}'

Embedded Terminal

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.

How to use:

  1. Click Terminal in the sidebar footer
  2. A terminal spawns in the configured working directory
  3. Type commands as you would in any terminal
  4. The terminal supports full ANSI colors, cursor movement, and resize

The terminal connects via WebSocket (/ws/terminal/:id) and supports all standard terminal operations.

# Spawn a terminal
curl -X POST http://localhost:4567/api/terminal/spawn \
  -H "Content-Type: application/json" \
  -d '{"cwd": "/home/user/project", "cols": 120, "rows": 40}'

# Kill the terminal
curl -X POST http://localhost:4567/api/terminal/kill

Protocol Recording

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.

Configuration:

| Variable | Default | Description | |----------|---------|-------------| | CAMPFIRE_RECORD | 1 | Set to 0 or false to disable | | CAMPFIRE_RECORDINGS_DIR | ~/.campfire/recordings | Output directory | | CAMPFIRE_RECORDINGS_MAX_LINES | 100000 | Auto-rotation threshold |

File format:

File naming: {sessionId}_{backendType}_{ISO-timestamp}_{randomSuffix}.jsonl

{"ts":1771153996875,"dir":"in","raw":"{\"type\":\"system\",\"subtype\":\"init\",...}","ch":"cli"}
{"ts":1771153996900,"dir":"out","raw":"{\"type\":\"session_init\",...}","ch":"browser"}

Recordings are useful for debugging protocol issues, building replay-based tests, and understanding how agents communicate.


Docker Containers

Optionally sandbox sessions inside Docker containers for isolation. When enabled, the agent runs inside a container with the working directory mounted at /workspace.

How it works:

  1. When creating a session, click the Container toggle in the toolbar
  2. Choose a Docker image (default: campfire-dev:latest) in the text field that appears
  3. Click Create — a progress overlay appears showing each step
  4. The session runs inside the container with authentication automatically seeded

Creation progress overlay:

When launching a container session, a step-by-step progress modal appears:

| Step | What happens | |------|-------------| | Checking image | Verifies if the Docker image exists locally | | Pulling image | Downloads the image if not found (with progress bar showing layer download %) | | Creating container | Creates and starts the Docker container with mounted volumes | | Seeding authentication | Copies ~/.claude/ (for Claude Code) or ~/.codex/ (for Codex) into the container | | Launching agent | Starts the agent process inside the container |

If any step fails, the overlay shows an error with Retry and Cancel buttons.

Authentication seeding:

Campfire automatically copies authentication credentials into containers so agents can authenticate without manual setup:

  • Claude Code sessions: ~/.claude/ is copied to /root/.claude/ inside the container
  • Codex sessions: ~/.codex/ is copied to /root/.codex/ inside the container

Image pull management:

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.

Git info inside containers:

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.

SSE creation endpoint:

Container session creation uses Server-Sent Events (SSE) for real-time progress reporting:

# Create a container session with progress (returns text/event-stream)
curl -N -X POST http://localhost:4567/api/sessions/create-with-progress \
  -H "Content-Type: application/json" \
  -d '{
    "backend": "claude",
    "model": "claude-sonnet-4-5-20250929",
    "cwd": "/home/user/project",
    "container": {"image": "campfire-dev:latest"}
  }'
# event: step
# data: {"step":"checking_image","message":"Checking image campfire-dev:latest..."}
# event: step
# data: {"step":"pulling_image","message":"Pulling campfire-dev:latest...","percent":45}
# event: done
# data: {"sessionId":"abc-123","session":{...}}

Requirements:

  • Docker must be installed and running on the host
  • The Docker socket must be accessible to the Campfire process
# Check Docker availability
curl http://localhost:4567/api/containers/status
# → {"available": true, "version": "24.0.7"}

# List available images
curl http://localhost:4567/api/containers/images

PWA & Mobile

Campfire is a Progressive Web App (PWA) — installable on mobile devices with push notifications for permission requests.

To install on mobile:

  1. Open Campfire in your mobile browser
  2. Tap "Add to Home Screen" (or the browser's install prompt)
  3. The app launches in standalone mode with its own window

Push notifications:

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.

Touch optimization:

Permission buttons are enlarged on mobile (min-height: 36px) for easy tap targets. Tool blocks default to collapsed on small screens.


Auto-Naming

Sessions automatically receive descriptive names after their first turn completes. This uses OpenRouter to generate a short title based on the user's first message.

Setup:

  1. Go to Settings in the sidebar
  2. Enter your OpenRouter API key
  3. Optionally choose a model (default: openrouter/free)

Auto-naming only runs if:

  • An OpenRouter API key is configured
  • The session doesn't already have a manual name
  • A first turn has completed

Manual renames always take precedence. You can rename any session by clicking its name in the sidebar.


Collective Intelligence

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.

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.

Four layers:

| Layer | What it does | |-------|-------------| | Semantic Memory | Stores observations, decisions, and patterns from each session in a local LanceDB database, scoped by namespace (global / repo / session / agent). Memories decay over time unless reused, and relevant ones are auto-recalled into a session's next prompt. See Semantic Memory below. | | 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. | | 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. | | 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. |

How it works end-to-end:

  1. When an agent produces output, the CI layer extracts observations, decisions, and patterns and stores them as MemoryFragment records in the right namespace (with vector embeddings if an embedding provider is configured). Thinking-block content is scrubbed before anything is stored.
  2. When a user sends a message, the CI layer recalls the most relevant memories from the repo, agent, and global namespaces (under a 250 ms budget so chat is never blocked) and prepends them to the message. The recalled items are shown to the user as a collapsible "recalled context" chip on that message.
  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.
  4. Episodic fragments are consolidated into distilled ConsolidatedKnowledge — triggered on turn boundaries, idle, session end, or manually — via a JUDGE → DISTILL → CONSOLIDATE pipeline (see below).

Embedding providers:

Vector search requires an embedding provider. Configure one in Settings:

| Provider | Model | Dimensions | Notes | |----------|-------|-----------|-------| | openai | text-embedding-3-small (default) | 1536 | Requires OpenAI API key | | ollama | nomic-embed-text (default) | 768 | Requires local Ollama instance | | none | — | — | Fragments stored without embeddings; metadata-only search |

Without an embedding provider, memory still works — recall falls back to a recency- and confidence-ranked scan over the relevant namespaces (so recent repo decisions still surface, just without semantic similarity).

How Semantic Memory works:

  • Namespaces — every memory lives in a scope: global (cross-repo conventions), repo:<hash> (one repository), session:<id> (one session's episodic notes), and agent:<backend> (backend-specific quirks). Recall for a session draws from repo, agent, and global scopes with per-namespace depth limits.
  • Decay & reinforcement — memories lose weight over time on a per-namespace half-life; being recalled reinforces a memory and extends its life (capped, so nothing becomes immortal). Low-weight, consolidated memories are eventually evicted. You can pin a memory so it never decays.
  • Consolidation (JUDGE → DISTILL → CONSOLIDATE) — raw fragments are filtered and clustered locally, then distilled into durable knowledge by an LLM (via your configured OpenRouter key). If no key is set, it falls back to a simple concatenation, badged as such in the UI — consolidation is never blocked on configuration.
  • UI — the Memory panel shows per-namespace counts and decayed-weight bars with pin/unpin controls; Settings → Memory exposes per-namespace decay half-lives, reinforce multipliers, and recall depths.

Storage:

All CI data is stored locally under ~/.campfire/memory/ — no external service required. Schema is versioned via meta.json and migrated automatically from earlier versions.

| Table | Purpose | |-------|---------| | fragments_v2 | Episodic memory fragments (namespace-scoped, with embeddings when available) | | consolidated_v2 | Distilled knowledge synthesized from fragments |

Capability data is stored as JSON in ~/.campfire/capabilities/ and learning history is appended to ~/.campfire/capability-learning.jsonl.

Quick setup:

# 1. Configure an embedding provider in Settings (optional but recommended)
#    OpenAI: enter your API key, set provider = "openai"
#    Ollama: ensure ollama is running, set provider = "ollama"

# 2. Start multiple sessions — CI activates automatically

# 3. Query shared memory via the REST API
curl "http://localhost:4567/api/sessions/:id/memory/query?q=authentication+pattern&limit=5"

# 4. Route a task to the best agent
curl -X POST http://localhost:4567/api/sessions/route-task \
  -H "Content-Type: application/json" \
  -d '{"taskDescription": "Refactor the TypeScript authentication module"}'

REST API summary:

| Group | Endpoints | |-------|-----------| | Memory | GET/POST /sessions/:id/memory, GET /sessions/:id/memory/query, GET /sessions/:id/memory/overview, POST /sessions/:id/memory/consolidate, POST /memory/pin, GET /memory/global | | Deliberation | GET /sessions/:id/deliberations, GET /sessions/:id/deliberations/:proposalId, POST .../respond, POST .../resolve | | Capabilities | POST /sessions/route-task, GET /capabilities, GET /capabilities/history, POST /capabilities/feedback | | Shared Context | GET /sessions/:id/context/stream, GET /sessions/:id/context/consensus, GET /sessions/:id/context/thread/:fragmentId |

Architecture details are documented in CLAUDE.md. The full semantic-memory design (namespaces, decay, retrieval scoring, and the consolidation pipeline) is written up in docs/design/semantic-memory-v2.md.


Copy Output Button

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).

Voice Input

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:

  • Real-time interim text display while speaking
  • Auto-restart on silence for continuous dictation
  • Pulsing red indicator when active
  • Transcript is appended to the composer textarea so you can edit before sending

Note: Requires a browser that supports the Web Speech API (Chrome, Edge, Safari).

Workspace File Tree

A collapsible file tree in the right-side TaskPanel showing the session's working directory. Features include:

  • Lazy-loading — subdirectories load on expand, keeping the initial render fast
  • File preview — click a file to see its contents inline (up to 10KB)
  • Hidden files toggle — show/hide dotfiles and system directories
  • Refresh — re-scan the directory tree on demand

Powered by the GET /api/fs/list-entries endpoint which filters out .git, node_modules, and __pycache__ by default.

Mermaid Diagram Rendering

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.

  • Toggle between diagram and source code views
  • Error handling with automatic fallback to source display
  • Lazy-loaded via React.lazy() to avoid impacting initial bundle size

Orchestrator Pipelines

A multi-stage automation engine for chaining sequential AI sessions into workflows. Access it at #/orchestrator in the sidebar.

How it works:

  1. Create a pipeline — define a name, working directory, and a series of stages
  2. Each stage has a prompt, backend (Claude/Codex), and model selection
  3. Run the pipeline — stages execute sequentially, each creating a real agent session
  4. Context passing — output from one stage feeds into the next via {{previous_output}}
  5. Monitor — real-time status timeline with per-stage duration and cost tracking

Example use cases:

  • Analyze → Review → Write Tests → Create PR
  • Scaffold → Implement → Lint → Deploy
  • Research → Plan → Execute → Verify

REST API:

| Method | Endpoint | Purpose | |--------|----------|---------| | GET | /api/orchestrator/pipelines | List all pipelines | | POST | /api/orchestrator/pipelines | Create a new pipeline | | PUT | /api/orchestrator/pipelines/:id | Update a pipeline | | DELETE | /api/orchestrator/pipelines/:id | Delete a pipeline | | POST | /api/orchestrator/pipelines/:id/run | Execute a pipeline | | GET | /api/orchestrator/runs | List all runs | | GET | /api/orchestrator/runs/:id | Get run status and details | | POST | /api/orchestrator/runs/:id/cancel | Cancel a running pipeline |

Pipeline and run data is persisted to ~/.campfire/orchestrator/.

Multi-Agent Orchestration

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.

Agent-to-agent delegation:

  • Lead Claude Code and Codex sessions can receive an internal campfire_agents MCP server.
  • The MCP server exposes ask_codex, ask_goose, ask_aider, ask_openhands, and ask_claude tools, excluding the lead session's own backend.
  • 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.
  • Sub-agent progress is streamed back to the parent session through sub_agent_update events and appears in the session activity UI.
  • Set CAMPFIRE_ENABLE_AGENT_MCP=0 to disable automatic agent MCP injection.

Agent races:

Open Agent Races at #/races from the sidebar to run the same prompt across multiple backends in parallel.

  1. Choose a repository root and task prompt.
  2. Select at least two backends. The UI currently offers Claude, Codex, Goose, Aider, and OpenHands; the REST API also accepts OpenClaw and OpenCode.
  3. Campfire creates one git worktree and branch per backend, launches a session in each worktree, and sends the same prompt to every agent.
  4. The comparison view shows status, wall-clock time, cost, changed file count, line changes, output summary, and a loadable diff for each entry.
  5. Click Merge on the winning entry to merge its race branch into the repository root and clean up the other race worktrees.

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.

Race results are saved to ~/.campfire/races/ so completed comparisons remain available after a server restart.

Environment detection:

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.

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).

REST API:

| Method | Endpoint | Purpose | |--------|----------|---------| | POST | /api/races | Start a race with { prompt, repoRoot, backends, baseBranch?, modelByBackend?, cascade? } | | GET | /api/races | List saved races | | GET | /api/races/:id | Get race status and entries | | GET | /api/races/:id/entries/:entryId/diff | Load a race entry's git diff | | POST | /api/races/:id/pick | Merge the winning entry by sessionId | | POST | /api/races/:id/cancel | Cancel a running race and clean up worktrees | | DELETE | /api/races/:id | Delete a saved race record |

Message Queue

When the agent is busy processing a request (status "running"), new messages are queued instead of being dropped. Features include:

  • Queue indicator — a badge shows the number of queued messages with a clear button
  • Auto-send — queued messages are sent one at a time when the agent becomes idle
  • System notification — a "Queued: ..." message appears in the chat timeline so you know the message was captured
  • Works seamlessly with all backends (Claude Code, Codex, Goose, Aider, OpenHands, OpenClaw, OpenCode)

Kanban Task Board

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).

Three columns:

  • To Do — pending tasks
  • In Progress — tasks the agent is actively working on (with animated pulse indicator)
  • Done — completed tasks

Task cards show:

  • Subject and description
  • Owner (agent name)
  • Active form (what the agent is currently doing)
  • Blocked status with warning badge
  • Task ID for reference

A progress bar at the top shows overall completion percentage.


Authentication

Token-based authentication to protect your Campfire instance. When enabled, all API routes and WebSocket connections require a valid session token.

Setup:

# Set a password via environment variable
CAMPFIRE_PASSWORD=your-secret bunx the-campfire

# Or configure through the UI on first visit

Features:

  • Password-based login with salted scrypt hashing (legacy unsalted SHA-256 hashes are migrated automatically on the next successful login)
  • 7-day rotating session tokens stored in ~/.campfire/auth.json
  • Auth middleware protects all /api/* routes
  • WebSocket connections validated on upgrade
  • Environment variable override for headless/CI deployments

API endpoints:

  • GET /api/auth/status — Check if auth is enabled and user is logged in
  • POST /api/auth/login — Authenticate with password
  • POST /api/auth/logout — Invalidate session token
  • POST /api/auth/setup — Initial password setup
  • POST /api/auth/disable — Remove authentication

Thinking Effort (Codex)

Control the reasoning effort level for Codex o-series models. This maps to Codex's reasoningEffort parameter on thread/start and thread/resume calls.

Three levels:

  • Low — Faster responses, less deliberation
  • Medium — Balanced (default)
  • High — Maximum reasoning depth

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.


Skills & Plugins Management

Browse and manage Claude Code plugins and skills from a dedicated UI page at #/skills (accessible via the sparkle icon in the sidebar).

Features:

  • Lists all installed plugins from ~/.claude/plugins/installed_plugins.json
  • Expandable cards showing each plugin's skills, commands, install path, version, and author
  • View SKILL.md content for any skill by clicking its name
  • Enable/disable plugins in Campfire without uninstalling them (stored in ~/.campfire/skills-config.json)
  • Blocked plugin detection from ~/.claude/plugins/blocklist.json

API endpoints:

  • GET /api/skills — List all plugins with enriched status
  • GET /api/skills/:id — Get a single plugin's details
  • GET /api/skills/:id/skill/:name — Read a skill's SKILL.md content
  • GET /api/skills/:id/command/:name — Read a command's content
  • POST /api/skills/:id/toggle — Enable/disable a plugin in Campfire

Drag & Drop Upload

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.

Supported: Any image format (PNG, JPG, GIF, WebP, etc.). Images are converted to base64 and sent as attachments with your message.


Session Folders

Organize sessions into named, color-coded folders in the sidebar.

Features:

  • Create folders with a name and optional color
  • Move sessions into folders via context menu
  • Collapse/expand folders (state persists in localStorage)
  • Remove sessions from folders
  • Delete empty folders

Storage: Folder data persists in ~/.campfire/session-folders.json.

API endpoints:

  • GET /api/folders — List all folders
  • POST /api/folders — Create a folder
  • PATCH /api/folders/:id — Update folder name/color
  • DELETE /api/folders/:id — Delete a folder
  • POST /api/folders/:folderId/sessions/:sessionId — Add session to folder
  • DELETE /api/folders/sessions/:sessionId — Remove session from folder

Permission Mode Selector

A dropdown in the Composer lets you switch between Claude Code permission modes in real-time, without restarting the session.

Four modes: | Mode | Behavior | |------|----------| | Agent (auto-approve) | Uses --dangerously-skip-permissions — all tool calls approved automatically | | Accept Edits | File edits approved automatically, other tools require approval | | Ask Every Time | Every tool call requires explicit approval | | Plan | Planning mode only — no code execution |

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.


Session Pulse (Background Activity)

A floating widget in the bottom-right corner of the chat view that provides real-time awareness of background activity. Two tabs:

Activity tab — shows what's happening in the current session:

  • Background agents spawned with run_in_background (Claude Code)
  • Active tool calls with elapsed timers (all backends)
  • Task progress from TodoWrite/TaskCreate

Sessions tab — shows other sessions running in the background:

  • Which sessions are running or compacting
  • Pending permission counts with warning badges
  • Click any row to jump to that session

Auto-hides when all activity completes. Appears automatically when agents or sessions are active.

Agent System

Persistent agent profiles with automated triggers. Navigate to Config > Agents (#/agents).

Creating an agent:

  1. Click Create Agent
  2. Fill in: name, description, backend (all 7 supported), model, permission mode, working directory
  3. Write a prompt template — use {{input}} as a placeholder for trigger input
  4. Select an environment profile (important for Codex — provides OPENAI_API_KEY)
  5. Optionally enable triggers: webhook or cron schedule

Running an agent:

  • Click the play button on any agent card
  • If the prompt contains {{input}}, a modal asks for the input value
  • The agent creates a new session, injects the resolved prompt, and runs autonomously
  • Agent sessions are named with the agent's icon (e.g., 🔬 Analyser)

Triggers: | Trigger | How it works | |---------|-------------| | Manual | Click the play button | | Webhook | POST /api/agents/{id}/webhook with { "input": "..." } | | Schedule | Cron expression (e.g., 0 8 * * * for daily at 8am) |

Safety: Auto-disables after 5 consecutive failures. Overlap prevention skips execution if previous run is still alive.

Import/Export: Agents can be exported as JSON and imported on another Campfire instance.

Provider Settings

Configure AI provider authentication tokens. Navigate to Settings > Providers.

Three token types, auto-injected into sessions for matching backends:

| Token | Environment Variable | Used By | |-------|---------------------|---------| | Claude Code OAuth | CLAUDE_CODE_OAUTH_TOKEN | Claude sessions | | OpenAI API Key | OPENAI_API_KEY | Codex sessions | | Anthropic API Key | ANTHROPIC_API_KEY | All sessions (Goose, Aider, etc.) |

Precedence: Environment profiles override global provider tokens. If your env profile sets OPENAI_API_KEY, the global setting is skipped for that session.

Auth detection: GET /api/settings/auth-status checks for existing authentication:

  • ~/.claude/.credentials.json (Claude subscription login)
  • `~/.