basecamp/once-campfire
Super simple group chat, without a subscription
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 4w ago
- ✓16 active contributors
- ✓Distributed ownership (top contributor 42% of recent commits)
Show 3 more →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/basecamp/once-campfire)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/basecamp/once-campfire on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: basecamp/once-campfire
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/basecamp/once-campfire shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 4w ago
- 16 active contributors
- Distributed ownership (top contributor 42% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live basecamp/once-campfire
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/basecamp/once-campfire.
What it runs against: a local clone of basecamp/once-campfire — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in basecamp/once-campfire | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | Last commit ≤ 56 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of basecamp/once-campfire. If you don't
# have one yet, run these first:
#
# git clone https://github.com/basecamp/once-campfire.git
# cd once-campfire
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of basecamp/once-campfire and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "basecamp/once-campfire(\\.git)?\\b" \\
&& ok "origin remote is basecamp/once-campfire" \\
|| miss "origin remote is not basecamp/once-campfire (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 56 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~26d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/basecamp/once-campfire"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Campfire is a self-hosted, subscription-free web-based group chat application built with Rails that supports multiple rooms with access controls, direct messages, file attachments, Web Push notifications, @mentions, and a bot API. It's a complete alternative to services like Slack or Basecamp's own Campfire, deployable as a single Docker container with built-in SSL, caching, and background job processing. Classic Rails monolith: app/ contains models/controllers/views, app/assets/ holds SVG icons and static assets, config/ has environment setup, db/ holds migrations. Background jobs are likely handled via Sidekiq or similar (Procfile suggests background worker support). Docker Compose is not present, so deployment is single-container with volume mounting to /rails/storage for persistence.
👥Who it's for
Organizations, teams, and developers who want to self-host their own chat infrastructure without recurring subscription costs. Specifically valuable for users who need fine-grained access controls, on-premise deployment, or bot integration capabilities within a Rails ecosystem.
🌱Maturity & risk
Production-ready. The codebase shows 264k lines of Ruby with organized structure (app/, config/, db/ patterns), includes Docker support with Let's Encrypt SSL automation, has GitHub Actions CI/CD workflows, and appears actively maintained by Basecamp. The presence of dependabot.yml and publish-image.yml workflows indicates ongoing dependency management and container image releases.
Low risk for a self-hosted deployment: single Rails monolith (no microservice complexity), explicit Docker support minimizes environment drift, but dependency auditing is critical since Gemfile.lock isn't visible in the file list. Unknown commit recency makes it hard to assess if security patches are current—inspect the last commit timestamp before deploying to production.
Active areas of work
Unable to determine from file list alone—no recent commit hashes, PR descriptions, or CHANGELOG are visible. Check GitHub's activity tab and releases page. The presence of .github/workflows/ci.yml and publish-image.yml suggests active CI/CD and container image publication.
🚀Get running
git clone https://github.com/basecamp/once-campfire.git && cd once-campfire && bin/setup && bin/rails server. The app will start on localhost:3000 (default Rails). First run prompts admin account creation; no subscription setup required.
Daily commands: bin/rails server starts the dev server (port 3000). For full-stack local: bin/setup configures DB, loads seeds, installs JS deps. To mimic Docker locally: docker build -t campfire . && docker run -p 80:80 -v campfire:/rails/storage campfire (requires SECRET_KEY_BASE, VAPID keys as env vars).
🗺️Map of the codebase
- Dockerfile: Defines production build: installs Ruby, deps, compiles assets, configures SSL/Puma/Sidekiq in single image—critical for deployment.
- Procfile: Specifies process types for Puma web server, background job worker, and asset serving—used by Docker and Heroku-like platforms.
- app/models/: Contains core domain logic: Message, Room, User, Notification models; start here to understand data flow and associations.
- .github/workflows/ci.yml: Rails test suite and linting (RuboCop) runs on every push—shows testing patterns and required code quality standards.
- config/routes.rb: Rails routing table; defines all API endpoints, web routes, and ActionCable endpoints—essential map of app functionality.
- app/channels/: ActionCable WebSocket channels handle real-time message delivery and notifications—core to live chat UX.
🛠️How to make changes
Models: app/models/ (likely Message, Room, User, Notification classes). Views: app/views/ organized by controller (rooms/, messages/, etc.). Real-time: ActionCable channels in app/channels/. API endpoints: check app/controllers/api/ for bot integration routes. Styling: CSS in app/assets/stylesheets/ (not fully listed but likely present). Icons: app/assets/images/ has SVGs for UI elements.
🪤Traps & gotchas
SECRET_KEY_BASE must be set before first run (Rails default will fail in production). VAPID_PUBLIC_KEY/VAPID_PRIVATE_KEY are required for Web Push notifications; without them, notification features silently fail—run script/admin/create-vapid-key to generate. SSL_DOMAIN or DISABLE_SSL must be set in Docker (no default HTTP/HTTPS fallback). Database persistence: migrations auto-run in Docker but must be seeded with first admin account via UI. .pumaenv file suggests Puma config is in play; check for any custom worker/thread counts that might not suit your deployment size.
💡Concepts to learn
- ActionCable (WebSocket over Rails) — Campfire uses ActionCable for real-time message delivery and live notifications; understanding subscription/broadcasting patterns is essential to modify chat features.
- Web Push API & VAPID — Campfire implements browser notifications via Web Push with VAPID authentication; you need to understand keypair generation and ServiceWorker integration to modify notification behavior.
- Docker multi-stage builds & volume mounting — Campfire's single-container deployment relies on Docker-specific patterns (storage at /rails/storage, SSL certificate management); critical for production deployment and local development parity.
- ActiveRecord associations & scopes — Campfire's data model (rooms, messages, users, access controls) depends on Rails associations and query scopes; you'll modify these constantly when adding features.
- Sprockets asset pipeline & SVG inlining — Campfire uses Sprockets to bundle CSS/JS and inlines SVG icons from app/assets/images/; modifying UI icons or stylesheet loading requires understanding asset compilation.
- Let's Encrypt certificate automation (certbot) — Docker deployment auto-configures SSL via SSL_DOMAIN env var; understanding how Puma integrates with certbot renewal is critical for long-running instances.
- Rails background jobs (Sidekiq/ActiveJob) — Procfile specifies a separate worker process; notifications, file processing, and bot integrations likely run async. Understanding job enqueueing and failure handling is essential.
🔗Related repos
matrix-org/synapse— Open-source communication server like Campfire but protocol-based (Matrix) instead of monolithic app; useful for federated chat.rocket/rocket.chat— Self-hosted chat alternative with more features (video, advanced bots, plugins); shows how Campfire competes in the self-hosted space.basecamp/trix— Basecamp's rich-text editor library; likely used in Campfire for message composition and may need updates when Campfire evolves rich-text features.rails/rails— Campfire is built entirely on Rails; understanding Rails internals (ActionCable, migrations, asset pipeline) is prerequisite knowledge.basecamp/basecamp— Basecamp's main product repo; Campfire is spun out as a lightweight alternative, so design patterns and shared dependencies may exist.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for WebSocket/ActionCable message handling
The file structure shows a Rails app with real-time chat features (notifications, @mentions, direct messages), but there's no visible test/ directory in the file listing. Real-time messaging is critical infrastructure—testing ActionCable channels, message broadcasting, and room access controls would prevent regressions in core chat functionality.
- [ ] Create test/channels/ directory with tests for message broadcasting channels
- [ ] Add tests for room access control and permission checks in ActionCable
- [ ] Test @mention notification triggers and WebSocket delivery
- [ ] Test direct message channel isolation between users
- [ ] Add integration tests verifying message ordering and delivery guarantees
Document VAPID key generation and Web Push setup in CONTRIBUTING.md
The README mentions generating VAPID keypairs via /scr (incomplete) but doesn't complete the command or document the process. Contributors trying to set up local development with push notifications will hit a wall. This is a concrete missing section that blocks a specific feature.
- [ ] Complete and verify the VAPID keypair generation command in documentation
- [ ] Add step-by-step instructions to CONTRIBUTING.md for enabling Web Push locally
- [ ] Document where to set VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY in .env.erb
- [ ] Include testing instructions for verifying Web Push notifications work
- [ ] Add troubleshooting section for common VAPID setup issues
Add GitHub Actions workflow for testing Docker image builds
The repo has publish-image.yml for publishing, but no workflow that validates the Dockerfile and Dockerfile-export build correctly on PRs. This prevents contributors from catching Docker build failures before they're merged. Also ensures the single-machine deployment claim is testable.
- [ ] Create .github/workflows/docker-build-test.yml
- [ ] Add job to build Dockerfile and verify it completes without errors
- [ ] Add job to build Dockerfile-export and verify export functionality
- [ ] Test that resulting image can start (docker run health check)
- [ ] Verify storage volume mounting works as documented in README
- [ ] Trigger on: pull_request targeting app/, Dockerfile, and Gemfile changes
🌿Good first issues
- Add support for user profile avatars: currently only default-avatar.svg and default-bot-avatar.svg exist in app/assets/images/. Implement avatar upload in User model, add migration to store avatar_url, and update views to render per-user avatars instead of defaults.
- Implement message search indexing: 'Search' is listed as a feature but no full-text search implementation is visible. Add PostgreSQL full-text search to Message model or integrate Elasticsearch, then create a /search endpoint and UI component.
- Add rate limiting to bot API endpoints: bot integrations (mentioned in README) likely need protection against abuse. Implement token bucket rate limiting in app/controllers/api/ using a Redis counter or gem like Rack::Attack.
⭐Top contributors
Click to expand
Top contributors
- @monorkin — 42 commits
- @dhh — 20 commits
- @kevinmcconnell — 7 commits
- @jzimdars — 6 commits
- @jeremy — 5 commits
📝Recent commits
Click to expand
Recent commits
ba11a0a— Merge pull request #192 from ESH13/fix-negative-limit-direct-placeholders (monorkin)8c7f49e— Fix crash when user has 20+ direct conversations (ESH13)3fada3d— ci: harden GitHub Actions workflows (#185) (flavorjones)dde94b0— Delete server-side session on logout (rosa)1852adb— Fix 1Password account ID (was user UUID) (#156) (jeremy)e983e3f— Block IPv6 SSRF bypass via ipv4_compat addresses (#153) (jeremy)53e36a1— Latest Brakeman (jeremy)a05292f— Switch 1Password account to 37signals.1password.com (#154) (jeremy)71ffeee— Merge pull request #147 from basecamp/fix-sgid-decoding (monorkin)77bcad6— Try to decode SGIDs in multiple ways (monorkin)
🔒Security observations
The Campfire application shows moderate security maturity with a Docker-based deployment approach and some security-conscious design (SSL support, VAPID for push notifications). However, there are notable gaps: security headers are not configured, SSL is optional rather than enforced, file upload handling lacks visible validation, and API/bot authentication details are missing. The most critical concern is potential hardcoded secrets in environment files. Additionally, the incomplete documentation on key generation and the absence of comprehensive input validation for features like @mentions, search, and message handling represent XSS and injection risks. Immediate priorities should be enforcing HTTPS, implementing security headers, completing documentation, and ensuring proper API authentication.
- High · Potential Hardcoded Secrets in Environment Configuration —
.env.erb. The presence of .env.erb file suggests environment-based configuration. If secrets like database passwords, API keys, or VAPID keys are hardcoded in configuration files or source control, this poses a significant security risk. Fix: Ensure .env files are in .gitignore, use proper secret management (e.g., Docker secrets, environment variables, or a secrets manager), and never commit sensitive credentials to version control. - Medium · Incomplete README Security Instructions —
README.md. The README mentions VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY generation but the instructions are truncated ('/scr' is incomplete). This could lead to improper key generation or handling, weakening Web Push notification security. Fix: Complete the documentation with full instructions for generating and securely storing VAPID keypairs. Ensure users understand not to hardcode these values. - High · Missing Security Headers Configuration —
Rails Configuration (not visible in provided files). No visible configuration for security headers (Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security) in the provided file structure. This increases vulnerability to XSS, clickjacking, and MIME-sniffing attacks. Fix: Implement security headers via Rails middleware or web server configuration. Add CSP, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, and HSTS headers. - Medium · SSL Configuration Optional and HTTP Fallback —
Dockerfile, README.md. The application supports both SSL (via DISABLE_SSL flag) and plain HTTP. Without enforcing SSL, sensitive data (authentication tokens, messages, files) could be transmitted unencrypted. Fix: Default to SSL enforcement. If DISABLE_SSL is used, document it clearly as development-only. Use HSTS headers to force HTTPS in production. - Medium · File Upload Handling Not Visible —
app/assets/images/attachment.svg (suggests file upload feature). The application supports file attachments with previews, but no validation logic is visible in the provided file structure. This could lead to file upload vulnerabilities (malicious file execution, XXE, path traversal). Fix: Implement strict file upload validation: whitelist file types, scan for malware, store uploads outside webroot, validate MIME types server-side, and implement size limits. - Medium · API Bot Integration Security —
README.md (API feature mentioned). The README mentions bot integrations via API, but no API authentication/authorization details are provided. This could allow unauthorized bot registration or command injection. Fix: Implement API token-based authentication, rate limiting per bot, input validation for all API endpoints, and audit logging for bot actions. - Low · Build Dependencies Not Pinned —
Dockerfile (build stage). The Dockerfile uses 'apt-get install' without pinning specific versions for build tools (build-essential, git, pkg-config). This could introduce supply chain risks. Fix: Pin specific versions of all installed packages to ensure reproducible, predictable builds and reduce exposure to compromised or malicious package versions. - Low · Ruby Version Not Explicitly Validated —
Dockerfile, .ruby-version. While .ruby-version file exists, there's no runtime validation that the container is running the correct Ruby version, potentially allowing version mismatches. Fix: Add a health check or startup validation in the Rails app to verify Ruby version matches requirements.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.