Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,8 @@ jobs:

- name: Build
run: cd web && bun run build

# Desktop shell helpers are pure Node/Bun modules — no Electron install
# needed to test them.
- name: Desktop tests
run: cd desktop && bun test test/
31 changes: 31 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,34 @@ jobs:
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true

# macOS desktop app (Apple Silicon DMG). Runs on the free macos-14 arm64
# runner and attaches the DMG to the release created above — GitHub Releases
# is the distribution channel, so shipping the desktop app costs nothing.
build-dmg:
name: Build macOS app (arm64 DMG)
runs-on: macos-14
needs: [github-release]
steps:
- uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Stage backend + Bun runtime
run: ./desktop/scripts/stage.sh

- name: Desktop tests
run: cd desktop && bun test test/

- name: Install Electron toolchain
run: cd desktop && bun install

- name: Build DMG
run: cd desktop && bun run dist

- name: Attach DMG to release
uses: softprops/action-gh-release@v2
with:
files: desktop/dist/*.dmg
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

> Campfire began as a fork of [the-companion](https://github.com/The-Vibe-Company/companion) and diverged into a separate product. Pre-fork history (versions up to 0.42.0) lives in the upstream repository; Campfire's own releases start at 0.1.0.

## 0.4.0 (2026-07-07)

### Features

* **desktop:** native macOS app (Apple Silicon) distributed as a DMG on GitHub Releases. An Electron shell boots the full Campfire server — every backend and feature included — as a bundled Bun sidecar, so no Bun install is required. Attaches to an already-running Campfire on port 4567 (service installs, `bunx the-campfire`) instead of double-spawning against `~/.campfire`; otherwise picks the first free port. Native menu, window-state persistence, external links open in the default browser, sidecar logs at `~/.campfire/logs/desktop-server.log`, crash dialog with relaunch. Build locally with `make dmg`; CI builds the DMG on the free macos-14 runner and attaches it to each release
* **agents:** the orchestration MCP server is now spawned via the absolute path of the running Bun executable instead of a PATH lookup, so multi-agent tools work in the desktop app (where Bun ships inside the bundle) and on machines without a global Bun install

## 0.3.2 (2026-07-07)

### Documentation
Expand Down
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ cd web && bun run typecheck
# Production build + serve
cd web && bun run build && bun run start

# macOS desktop app (Electron shell, Apple Silicon DMG)
make dmg # stage backend + package desktop/dist/Campfire-<version>-arm64.dmg
cd desktop && bun test # desktop helper tests (no Electron needed)

# Landing page (campfire.sh) — idempotent: starts if down, no-op if up
# IMPORTANT: Always use this script to run the landing page. Never cd into landing/ and run bun/vite manually.
./scripts/landing-start.sh # start
Expand Down Expand Up @@ -536,6 +540,9 @@ campfire/
│ ├── bin/cli.ts # CLI entry point (bunx the-campfire)
│ ├── dist/ # Built frontend assets
│ └── package.json # Published as "the-campfire"
├── desktop/ # macOS Electron app (arm64 DMG). Thin shell: spawns the
│ # bundled Bun server sidecar (vendor/ staged by scripts/stage.sh)
│ # and loads the web UI. See desktop/README.md.
├── landing/ # Marketing site (separate Vite app)
├── scripts/ # Utility scripts (landing-start.sh)
├── CLAUDE.md # This file (project instructions)
Expand Down
18 changes: 17 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
.PHONY: dev build start
.PHONY: dev build start desktop-stage desktop dmg

dev:
cd web && bun run dev

build:
cd web && bun run build

start:
cd web && bun run start

# ── macOS desktop app (Electron shell around the Bun server) ────────────────
desktop-stage:
./desktop/scripts/stage.sh

desktop: desktop-stage
cd desktop && bun install && bun run start

dmg: desktop-stage
cd desktop && bun install && bun run dist
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@

## Quick Start

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

### Option 1: npm (fastest)

Expand Down Expand Up @@ -187,6 +187,22 @@ docker stop campfire && docker rm campfire

See [Docker Deployment](#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](https://github.com/stretchcloud/campfire/releases/latest)
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:

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

### Requirements

**For native (npm or source):**
Expand Down
3 changes: 3 additions & 0 deletions desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
vendor/
dist/
70 changes: 70 additions & 0 deletions desktop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Campfire Desktop (macOS, Apple Silicon)

A native Electron shell around the Campfire server. The app is deliberately
thin: the main process boots the **same Bun + Hono backend** the npm/Docker
distributions run (bundled under `Contents/Resources/backend` together with a
Bun runtime at `Contents/Resources/bun/bun`), then points a `BrowserWindow` at
`http://127.0.0.1:<port>`. Every feature — all agent backends, collaboration,
replay, gallery, webhooks, cron, semantic memory — is served by that sidecar,
so the desktop and web builds can never diverge.

## Behavior

- **Reuse-first**: if a Campfire server already answers on port 4567 (the
`the-campfire` background service, `bunx the-campfire`, or the dev server),
the app attaches to it instead of spawning a second server against the same
`~/.campfire` state. Otherwise it spawns the bundled sidecar on the first
free port from 4567 upward.
- **Shared state**: sessions, recordings, settings, and memory live in
`~/.campfire`, shared with the CLI/web flavors.
- **Sidecar logs**: `~/.campfire/logs/desktop-server.log`.
- **Lifecycle**: closing the window keeps the app (and server) alive per macOS
convention; Cmd+Q stops the sidecar. Agent CLI processes persist and are
resumed on the next launch, same as a server restart.
- **Links**: anything not on the local server origin opens in the default
browser.

## Build

```bash
# From the repo root
make dmg # stage + package desktop/dist/Campfire-<version>-arm64.dmg

# Or step by step
./desktop/scripts/stage.sh # build frontend, stage backend + node_modules + bun into desktop/vendor/
cd desktop
bun install
bun run smoke # boots the app headless: spawns sidecar, loads UI, exits 0/1
bun run dist # electron-builder → dist/Campfire-<version>-arm64.dmg
```

`bun test test/` runs the unit tests for the boot-time networking helpers
(free-port scan, Campfire probe, readiness wait). They need no Electron
install.

## Signing ("cheap" distribution)

Builds are **ad-hoc signed** (`scripts/after-pack.js`) — valid signature, no
Apple Developer account, $0. Downloaded copies carry the quarantine attribute,
so the first launch needs right-click → **Open**, or:

```bash
xattr -cr /Applications/Campfire.app
```

To move to real signing + notarization later: set `mac.identity` in
`electron-builder.yml`, add notarize options, and delete the codesign calls in
`scripts/after-pack.js` (keep the node_modules copy step — electron-builder
drops `node_modules` from `extraResources` by default, and without the copied
modules the app only works on machines where Bun can auto-install at runtime).

## Gotchas learned the hard way

- `extraResources` silently excludes `node_modules`; a bundle missing them
*appears* to work on dev machines because Bun auto-installs into its global
cache at runtime. `scripts/after-pack.js` copies them explicitly and CI
would fail the packaging step if staging was skipped.
- `codesign` rejects bundles containing symlinks whose targets it can't seal —
`node_modules/.bin` shims are removed during packaging.
- The first GUI launch takes ~20 s while Gatekeeper scans the bundle; later
launches are ~3 s.
Binary file added desktop/build/icon-src.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktop/build/icon.icns
Binary file not shown.
Loading
Loading