Self-hosted AI coding agent platform — chat with any LLM, run coding agents in Docker that open real GitHub PRs, and orchestrate multi-role agent pipelines. One Next.js app, SQLite, and your choice of cloud or local LLM.
Just want to try it? demo.ghostbot.dev — no sign-up, no risk. Agent-job launches + secret saves are disabled, the database resets every 24h.
Just want to use it? See docs/GETTING_STARTED.md — the plain-language guide for people who aren't developers.
Want to self-host? Read on.
- Chat with any LLM — Anthropic, OpenAI, Google, or your own self-hosted Ollama (Qwen 2.5 Coder, Llama, Mistral, etc.)
- First-run setup wizard at
/setup— walks the owner through LLM, Docker, GitHub, and notification configuration in minutes - Real-time cross-device sync — Laptop and phone stay in lock-step via Server-Sent Events
- Markdown chat with code-block copy buttons, tables, syntax highlighting, LaTeX-safe rendering
- Image paste + vision — Clipboard screenshots auto-resized and sent to vision-capable models
- Voice-to-text input — Browser SpeechRecognition API, no transcription API cost, no server round-trip
- Self-learning memory (RAG) — Every chat is auto-summarised + embedded; future chats retrieve relevant past context
- Project Connect — Attach a local project folder to any chat. Browse the tree, click-to-attach files, launch agents directly.
CLAUDE.mdis auto-injected into the system prompt - Coding agents in Docker — Aider (default), OpenCode, Codex, Gemini CLI. Fire from chat → clone repo → edit → PR
- Side-by-side diff viewer for agent-job output (unified + side-by-side toggle, word-level intra-line highlighting)
- Cluster pipelines — Chain multi-role agents (planner → reviewer → coder → tester) with one-click templates
- GitHub PR triggers — Comment
/ghostbot fix thison a PR, the bot picks it up and pushes a fix - Telegram + Slack alerts — Get pinged when agent jobs finish
- Autonomous Builder — LLM-planned multi-step builds with progress tracking, retries, and SSE updates
- AI Scanner — Daily self-reflecting cron distills recent sessions into insights + self-improvement suggestions
- AIOS / Skills — Per-user business context and voice injected into every prompt; reusable
/skill-nameprompt templates - Multi-user — Admin invites via one-time links, each user has isolated chat + memory, ownership enforced at DB layer
- PWA install — Add-to-Home-Screen on mobile; standalone window, offline shell cache
- Demo mode — Set
DEMO_MODE=truefor a sandboxed public instance (agent jobs + secret saves disabled); see docs/DEMO.md - Admin backup — One-click JSON export of the whole DB before risky migrations
- VS Code extension — Embed the live GhostBot UI inside your editor (see vscode-extension/PUBLISHING.md for Marketplace publish)
Browser ─┬─ Next.js App Router (chat, admin, clusters, docs, /setup wizard)
├─ Server Actions for every admin + owner action
└─ /stream/sync + /stream/chat (SSE)
Server ──┬─ src/lib/ai direct Ollama client + LangChain fallback
├─ src/lib/memory embeddings + cosine search + summarize
├─ src/lib/agent-jobs db / launch / notify (Telegram + Slack)
├─ src/lib/cluster templates + run-now chain executor
├─ src/lib/sync pub/sub bus + per-user SSE handlers
├─ src/lib/db schema + runtime auto-migrations
└─ src/lib/tools docker, github, telegram, slack
Host ───┬─ ghostbot Docker container (Dokploy-managed)
├─ ghostbot:coding-agent-aider (default)
├─ ghostbot:coding-agent-opencode
├─ ghostbot:coding-agent-codex
├─ ghostbot:coding-agent-gemini
└─ Ollama on a separate VPS (Qwen 2.5 Coder, etc.)
One Next.js app. One SQLite file. Docker socket for agents. No microservices, no message queues.
git clone https://github.com/flndrnai/ghostbot.git
cd ghostbot
cp .env.example .env
echo "AUTH_SECRET=$(openssl rand -base64 32)" >> .env
docker compose up -dOpen http://localhost:3000. The first visit creates the owner account and auto-redirects you to /setup — a 5-step wizard that gets your LLM, Docker, GitHub, and notifications configured in one place.
Requires Node.js ≥ 20.10 (for ES2025 import attributes).
git clone https://github.com/flndrnai/ghostbot.git
cd ghostbot/src
npm install
export AUTH_SECRET="$(openssl rand -base64 32)"
npm run devRun tests:
cd src && npm testDeploy src/Dockerfile via Dokploy with these environment variables:
AUTH_SECRET=<openssl rand -base64 32>
AUTH_TRUST_HOST=true
NODE_ENV=production
DATABASE_PATH=/app/data/db/ghostbot.sqliteMounts:
| Type | Source | Mount path | Purpose |
|---|---|---|---|
| Volume | ghostbot-data |
/app/data |
Persists SQLite + memory across redeploys |
| Bind | /var/run/docker.sock |
/var/run/docker.sock |
Required to launch agent containers |
⚠️ Docker socket bind-mount grants host-root-equivalent privilege to the app container. Only enable it if you trust every admin on the instance. For multi-tenant deployments, put the socket behind tecnativa/docker-socket-proxy with a restrictive allowlist. See Security below.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Server Actions) |
| Frontend | React 19, Tailwind CSS v4, motion (animated icons), react-markdown, Sora font |
| Backend | Node.js 20.10+ (targets 22 in production) |
| Database | SQLite + Drizzle ORM (WAL mode) + runtime auto-migrations |
| Auth | NextAuth v5 (credentials, JWT sessions) |
| Encryption | AES-256-GCM (secrets via PBKDF2 from AUTH_SECRET), bcrypt (passwords) |
| LLM — chat path | Direct fetch to Ollama /api/chat (no LangChain for reliability) |
| LLM — cloud path | LangChain ChatAnthropic / ChatOpenAI / ChatGoogleGenerativeAI |
| Embeddings | Ollama nomic-embed-text (768 dims), in-JS cosine search |
| Sync | Server-Sent Events with in-process pub/sub keyed by userId |
| Containers | Docker Unix socket API (never docker exec from Node) |
| i18n | Plain src/locales/<lang>.json + tiny t() helper (no library) |
| Tests | Vitest |
| Role | Hex | Usage |
|---|---|---|
| Background | #050509 |
App background |
| Dark surface | #111827 |
Cards, sidebar |
| Gold accent | #D4AF37 |
Buttons, links, active states |
| Primary | #F5D97A |
Highlights, hover states |
| Foreground | #E5E2DA |
Text, borders |
Dark-first. The sidebar-footer theme toggle lives only in the user nav dropdown (no duplicates).
ghostbot/
├── docker-compose.yml # Production: docker compose up -d
├── docker-compose.dev.yml # Dev override with hot reload
├── .env.example # Env variable template
├── docker/ # Coding-agent images
│ ├── build.sh # Build all agent images locally
│ ├── agents/
│ └── coding-agent/
├── src/ # Next.js app (npm workspace)
│ ├── app/
│ │ ├── (public)/ # Public landing page
│ │ ├── setup/ # Owner-only first-run wizard
│ │ ├── chat/[chatId]/
│ │ ├── clusters/ # list + templates
│ │ ├── cluster/[id]/ # detail + roles
│ │ ├── projects/ # project connect
│ │ ├── builder/[planId]/ # autonomous builder progress
│ │ ├── admin/ # 16 admin pages
│ │ ├── docs/ # in-app guide
│ │ ├── invite/[token]/ # public invite acceptance
│ │ ├── login/
│ │ ├── api/ # REST + webhooks (GitHub, Telegram)
│ │ └── stream/ # SSE endpoints
│ ├── components/ # Shared components (SetupBanner, etc.)
│ ├── lib/
│ │ ├── ai/ # Ollama client, model factory, chat stream
│ │ ├── memory/ # embeddings, store, summarize, session logs
│ │ ├── agent-jobs/ # launch, db, notify
│ │ ├── cluster/ # actions, templates, runtime
│ │ ├── builder/ # autonomous multi-step builder
│ │ ├── scanner/ # daily self-reflecting cron
│ │ ├── chat/ # actions + components
│ │ ├── auth/ # NextAuth config + edge config
│ │ ├── admin/ # server actions for every admin page + wizard
│ │ ├── db/ # schema + runtime auto-migrations
│ │ ├── sync/ # SSE bus
│ │ ├── tools/ # docker, github, telegram, slack
│ │ ├── icons/ # animated lucide wrappers
│ │ ├── i18n.js # minimal t() helper
│ │ └── projects/ # project-folder + file-system API
│ ├── locales/ # en.json, nl.json, fr.json
│ ├── proxy.js # Auth + owner-only /setup gating + rate limiting (Next 16 successor to middleware.js)
│ ├── server.js # Custom server entry
│ └── Dockerfile # Production image
├── docs/
│ ├── OLLAMA_QWEN_SETUP.md # Full Ollama + Qwen setup
│ └── superpowers/ # Design specs + implementation plans
├── vscode-extension/ # VS Code extension (webview)
└── README.md
18+ tables, auto-migrated at runtime via runAutoMigrations in src/lib/db/index.js — no drizzle-kit generate step required, just add columns to schema.js and addColumnIfMissing.
| Table | Purpose |
|---|---|
users |
Accounts with role (admin/user) and owner (exactly one per install) |
invitations |
One-time signup tokens for multi-user |
chats, messages |
Chat sessions + messages (with optional base64 image attachments) |
chat_summaries |
Auto-generated 2–3 sentence recaps + embeddings |
knowledge_entries |
Manual + auto knowledge with embeddings |
agent_jobs |
Coding agent runs (status, output, PR URL) |
clusters + cluster_roles |
Multi-role agent pipelines |
projects |
Connected project folders |
skills |
Reusable /slug prompt templates |
builder_plans, builder_steps |
Autonomous builder state |
token_usage |
Per-request token accounting |
settings |
Encrypted config (AES-256-GCM via PBKDF2 from AUTH_SECRET) |
notifications, subscriptions, code_workspaces |
Notifs, channels, interactive sessions |
Works with any Ollama model — not just the ones listed. ollama pull <model> on your Ollama machine and it appears in Admin → Ollama. Browse ollama.com/library for options.
Full walkthrough (cost comparison, KVM8 migration checklist): docs/OLLAMA_QWEN_SETUP.md.
| Hardware | Suggested model | Notes |
|---|---|---|
| 16 GB VPS (Hostinger KVM4) | qwen2.5-coder:7b |
Stable for chat, fast |
| 16 GB VPS | qwen2.5-coder:14b |
Tight but works |
| 24 GB+ VPS (KVM8) | qwen2.5-coder:32b |
Strong tool-calling, real agent reliability |
| Every box | nomic-embed-text |
Required for memory (~274 MB) |
| Feature | Requires | Why |
|---|---|---|
| Web chat | nothing | Works on localhost |
| Self-hosted LLM | VPS + Ollama | Zero per-token cost |
| Cloud LLM | API key | If you don't run your own |
| Memory / RAG | ollama pull nomic-embed-text |
Semantic search + auto-summarize |
| Docker agents | docker.sock mounted | Launch coding-agent containers |
| GitHub integration | Fine-grained PAT (Contents + PRs + Issues rw) | Branches, commits, PRs |
/ghostbot PR trigger |
GitHub webhook + secret | Comment /ghostbot fix this on a PR |
| Telegram notifications | Public HTTPS URL + bot token | Telegram needs a public webhook target |
| Slack notifications | Slack app + bot token + chat:write + channel ID |
Posts to the configured channel |
| Multi-user | nothing extra | Admin → Users → Invite |
| VS Code extension | Build .vsix locally |
Embed live GhostBot in your editor |
GhostBot is designed to run inside your own perimeter — a personal VPS, a home server, or a small-team deployment. It is not hardened for public multi-tenant hosting.
- Password hashing with bcrypt
- Secrets at rest encrypted with AES-256-GCM, key derived via PBKDF2 from
AUTH_SECRET - JWT sessions (NextAuth v5) with role + owner claims
- Owner-only gating on
/setup(src/proxy.js+ server component + action-layerrequireOwner()) - Admin-only gating on
/admin/** - Path-traversal defense on the Project Connect file API (absolute-path resolve + prefix check +
realpathSyncsymlink check) - Drizzle ORM parameterizes every query (no string-concat SQL)
- GitHub webhook signatures verified with
crypto.timingSafeEqualwhen both secret and header are present - Rate limiting on sensitive routes via in-process sliding window (
src/lib/rate-limit.js)
If you plan to expose GhostBot to the public internet or onboard untrusted users, you must address these before going live:
- Docker socket — the app container has root-equivalent access to the host via
/var/run/docker.sock. Put it behind tecnativa/docker-socket-proxy and allowlist onlycontainers/create,containers/start,containers/{id}/logs, andcontainers/{id}DELETE. - Agent container limits — coding-agent containers are launched without enforced
Memory,NanoCpus, orPidsLimitsettings. A hostile or buggy agent can exhaust host resources. Apply limits in src/lib/tools/docker.jsrunContainer. - Webhook endpoints — every webhook receiver (
/api/github/webhook,/api/telegram/webhook,/api/webhook/*,/api/clusters/[id]/roles/[id]/webhook) must fail closed when no secret is configured. Audit the signature-verification branches before exposure. - Multi-user isolation — server actions operating on user-scoped resources (clusters, skills, memory, chats) must verify ownership (
resource.userId === session.user.id), not just that a session exists. - Command-template inputs — if you wire up
type: 'command'triggers, never let untrusted HTTP input reach the command string. Pass placeholders as env vars intoexecFile, not intoexec. - Rate limiting — extend
enforceRateLimit()to every/api/**route, not just the currently-covered subset. Trust only thex-forwarded-forchain your reverse proxy sets.
GhostBot assumes:
- The
AUTH_SECRETis kept secret (it's the root of all encryption) - Admins are trusted. Invited
user-role accounts have read-only-ish access to their own data but should not be treated as adversarial - The Ollama endpoint is on a private network or behind HTTPS with a credential on the ingress
- The Docker host is single-tenant to the admin(s)
Please do not open a public GitHub issue for security reports. Email the maintainer at the address listed on the repo's GitHub profile, or open a private advisory via GitHub's security tab. We'll acknowledge within 72 hours.
- All core logic lives under
src/lib/— never duplicate in templates - Server actions colocated with their feature (
src/lib/admin/,src/lib/chat/, etc.) - API routes (
src/app/api/) are for external callers + webhook receivers; everything browser-side uses server actions - SSE endpoints under
src/app/stream/ - Docker only via
src/lib/tools/docker.jsover the Unix socket — never shell out todockerCLI - Date/time formatting through
src/lib/date-format.js(24h,dd/mm/yyyy) - No i18n libraries — strings come from
src/locales/<lang>.jsonviat()in src/lib/i18n.js
GhostBot is designed for single-server, single-owner or small-team deployments. See docs/SCALING.md for:
- what a single instance handles comfortably (and where the ceiling actually is)
- signals that you're approaching the ceiling
- the three-step horizontal scaling migration path (Redis pub/sub → Postgres/Turso → multi-Ollama)
- what GhostBot explicitly does NOT try to do (multi-region active-active, serverless, multi-pod K8s)
Design specs + implementation plans live in docs/superpowers/.
Shipped:
- ✅ Phase 1 — public landing page, docker-compose, repo polish
- ✅ Phase 2.1 — first-run setup wizard at
/setup - ✅ Phase 2.2 — expanded in-app
/docs(Getting Started, Project Connect, Clusters, Troubleshooting) - ✅ Phase 2.3 — Docker mount & security docs section
- ✅ Phase 3.1 — CI/CD (GitHub Actions: lint/build on PR, release on tag → GHCR)
- ✅ Phase 3.2 — agent container resource limits (Memory/NanoCpus/PidsLimit/timeout) + docker-socket-proxy
- ✅ Phase 3.3 — monitoring + live log streaming (already shipped pre-Phase-3)
- ✅ Phase 3.4 — PWA (manifest.json + service worker)
- ✅ Phase 4.1 — voice-to-text input + diff2html side-by-side viewer
- ✅ Phase 4.2 — single-server ceiling documented in docs/SCALING.md
- ✅ Phase 4.3 — DEMO_MODE + live demo at demo.ghostbot.dev
- ✅ 10-finding security audit patched (command injection, webhook fail-open, ownership gates; see commit history)
- ✅
ENCRYPTION_KEYsplit fromAUTH_SECRET; extended rate limiting to every/api/*route - ✅
src/proxy.js(Next.js 16 convention) replaces the oldmiddleware.js
Deferred (need dedicated design/work):
- ⏳ Monaco as in-browser file editor for Project Connect (save/publish/revert flow needs its own design)
- ⏳ In-browser terminal beyond the existing workspace-shell surface
- ⏳ Additional coding-agent images (Claude Code, Cline, Cursor-agent, etc.)
- ⏳ Light-mode per-component polish
- ⏳ VS Code Marketplace publish (extension packaging + guide done; see vscode-extension/PUBLISHING.md — you run
vsce publish)
MIT — see LICENSE.
Built by flndrn · Live at ghostbot.dev