From 24229ebd8e51a9606f28e65f2924ebc965d55a6c Mon Sep 17 00:00:00 2001 From: opencode Date: Sun, 13 Sep 2026 04:37:09 -0400 Subject: [PATCH 1/2] docs: rewrite README to v2 quality bar, J1 branding, real screenshot Co-Authored-By: opencode --- README.md | 220 ++++++++++-------------------------------------------- 1 file changed, 38 insertions(+), 182 deletions(-) diff --git a/README.md b/README.md index d2cdf80..0d6f9e9 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,18 @@ -
- -![CommandDesk banner](docs/assets/banner.svg) - # CommandDesk -**A self-hosted AI helpdesk agent** — multi-platform ticketing, email-to-ticket, knowledge-base answers, and live cost tracking, running on local LLMs. - -Stars -Last commit -License -Python -FastAPI -llama.cpp +> Self-hosted AI helpdesk agent that ingests email, chat, WhatsApp, and tickets into one queue, answers from your knowledge base with a local LLM, and tracks the per-ticket AI cost in real time. -
+[![License](https://img.shields.io/github/license/OneByJorah/CommandDesk?style=for-the-badge&color=FFB300&labelColor=0a0a09)](https://github.com/OneByJorah/CommandDesk) +[![Top Language](https://img.shields.io/github/languages/top/OneByJorah/CommandDesk?style=for-the-badge&color=FFB300&labelColor=0a0a09)](https://github.com/OneByJorah/CommandDesk) +[![Stars](https://img.shields.io/github/stars/OneByJorah/CommandDesk?style=for-the-badge&color=FFB300&labelColor=0a0a09)](https://github.com/OneByJorah/CommandDesk/stargazers) +[![Last Commit](https://img.shields.io/github/last-commit/OneByJorah/CommandDesk?style=for-the-badge&color=FFB300&labelColor=0a0a09)](https://github.com/OneByJorah/CommandDesk/commits) +[![CI](https://img.shields.io/github/actions/workflow/status/OneByJorah/CommandDesk/ci.yml?style=for-the-badge&color=FFB300&labelColor=0a0a09&label=ci)](https://github.com/OneByJorah/CommandDesk/actions/workflows/ci.yml) -![CommandDesk screenshot](docs/assets/screenshot.png) +![CommandDesk admin dashboard](dashboard-realistic.png) ## What This Is -Helpdesk AI is usually a paid SaaS add-on, and your ticket data leaves the building. CommandDesk runs the whole pipeline locally: it ingests email and chat into a unified queue, answers from your own knowledge base with a local LLM, and tracks the AI cost of every ticket. Humans can take over at any point, and n8n workflows handle routing, escalation, and surveys. +Helpdesk AI is usually a paid SaaS add-on that ships your ticket data off-premises. CommandDesk runs the whole pipeline locally: it ingests email and chat into a unified queue, answers from your own knowledge base using a local llama.cpp model (or the OpenAI API), and tracks the AI cost of every ticket. Humans can take over any conversation at any point, and n8n workflows handle routing, escalation, and satisfaction surveys. ## Quick Start @@ -31,187 +24,50 @@ docker compose up -d ``` | Service | URL | -|---------|-----| -| **Dashboard** | http://localhost/dashboard/ (nginx reverse proxy) | -| **Widget preview** | http://localhost:8484 | -| **Agent API** | http://localhost:8080 | -| **WhatsApp webhook** | http://localhost:9090 | - -### Local development - -```bash -pip install -r requirements.txt -uvicorn scripts.agent_server:app --reload --port 8080 -``` +|---|---| +| Dashboard (nginx) | http://localhost/dashboard/ | +| Widget preview | http://localhost:8484 | +| Agent API | http://localhost:8080 | +| WhatsApp webhook | http://localhost:9090 | ## Features -- **Multi-platform queue** — email, web widget, WhatsApp, osTicket, Freshdesk, and Zammad in one place. -- **AI responses** — local llama.cpp or OpenAI GPT, with context-aware replies. -- **Knowledge base** — ChromaDB vector search over your documentation. -- **Email-to-ticket** — IMAP ingestion creates tickets automatically. -- **SLA management** — define SLAs with automatic escalation on breach. -- **Cost tracking** — per-ticket, per-agent, and per-session AI usage costs in real time. -- **Rate limiting** — per-session limits with automatic blocking and audit logging. -- **Workflow automation** — n8n handles routing, escalation, satisfaction surveys, and daily digests. -- **Admin dashboard** — live queue, performance metrics, audit logs, and service health. +- Multi-platform queue: email, web widget, WhatsApp, osTicket, Freshdesk, and Zammad. +- AI responses via local llama.cpp or OpenAI GPT with context-aware replies. +- ChromaDB vector-search knowledge base over your own documentation. +- IMAP email-to-ticket ingestion. +- SLA definitions with automatic escalation on breach. +- Real-time AI cost tracking per ticket, per agent, per session. +- Per-session rate limiting with audit logging. +- n8n workflow automation for routing, escalation, surveys, and daily digests. +- Admin dashboard with live queue, metrics, audit log, and service health. ## Architecture ``` - ┌──────────────────────────────────────────────────┐ - │ User │ - │ (WhatsApp / Web Widget / Email / API / Portal) │ - └──────────────────────┬───────────────────────────┘ - │ - ┌────────────────────┴────────────────────┐ - │ Helpdesk Agent │ - │ (agent_server.py · FastAPI) │ - │ Session Mgmt · Rate Limiting · Routing │ - └──────┬──────────┬──────────┬─────────────┘ - │ │ │ - ┌────────────┴─┐ ┌─────┴─────┐ └──────────────┐ - │ LLM Core │ │ Context │ Ticket Platforms│ - │ llama.cpp / │ │ ChromaDB ·│ osTicket · FD │ - │ OpenAI API │ │ SearXNG │ Zammad · Email │ - └──────────────┘ └───────────┘ └────────────────┘ - │ - ┌──────────────────────────┐ ┌──────┴──────┐ - │ Admin Dashboard │ │ n8n Workflows│ - │ PostgreSQL · Redis · Logs│ │ Escalation │ - │ Costs · Metrics · Audit │ │ Surveys │ - └──────────────────────────┘ └─────────────┘ + User (WhatsApp / Web Widget / Email / API / Portal) + │ + Helpdesk Agent (FastAPI :8080) + Session Mgmt · Rate Limiting · Routing + │ │ │ + ┌──────┴───┐ ┌───┴──────┐ ┌─────┴────────────┐ + │ LLM Core │ │ Context │ │ Ticket Platforms │ + │llama.cpp │ │ChromaDB │ │osTicket·Freshdesk│ + │ / OpenAI │ │· SearXNG │ │· Zammad · Email │ + └──────────┘ └──────────┘ └──────────────────┘ + │ │ + Admin Dashboard n8n Workflows + PostgreSQL·Redis Escalation·Surveys ``` -## API Endpoints - -**Helpdesk agent** (port 8080): - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/health` | GET | Agent health check | -| `/chat` | POST | Send a user message, get an AI response | -| `/session/{session_id}` | GET | Session usage info | - -**WhatsApp webhook** (port 9090): - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/webhook/whatsapp` | GET | Webhook verification challenge | -| `/webhook/whatsapp` | POST | Receive WhatsApp messages | -| `/admin/takeover/{phone}` | POST | Human takes over a conversation | -| `/admin/resume/{phone}` | POST | Re-enable the bot | -| `/admin/queue` | GET | View the human support queue | - -## Ticket Statuses - -| Status | Description | -|--------|-------------| -| `open` | New ticket awaiting response | -| `in_progress` | Being handled by an agent | -| `waiting` | Awaiting customer response | -| `resolved` | Issue resolved | -| `closed` | Ticket archived | - -## Configuration - -Core variables (see [.env.example](.env.example) for the full list): - -| Variable | Default | Description | -|----------|---------|-------------| -| `LLM_API_BASE` | `http://llama:8081/v1` | LLM OpenAI-compatible endpoint | -| `LLM_MODEL` | `qwen2.5-7b-instruct` | Model name sent to the LLM | -| `LLAMA_MODEL_PATH` | `/models/qwen2.5-7b-instruct-q4_k_m.gguf` | Local GGUF model path | -| `REDIS_URL` | `redis://redis:6379/0` | Redis for sessions & rate limiting | -| `POSTGRES_URL` | `postgresql://helpdesk:helpdesk@postgres:5432/helpdesk` | PostgreSQL persistence | -| `CHROMA_URL` | `http://chroma:8000` | ChromaDB vector store | -| `SEARX_URL` | `http://searxng:8080` | SearXNG metasearch | -| `RATE_LIMIT_PER_SESSION` | `50` | Max messages per session window | -| `RATE_LIMIT_WINDOW` | `3600` | Rate-limit window (seconds) | -| `MAX_MESSAGE_LENGTH` | `4000` | Max message characters | -| `IMAP_HOST` / `IMAP_USER` / `IMAP_PASSWORD` | — | Email-to-ticket ingestion | -| `TICKET_PLATFORM` | `osticket` | Default ticket backend | -| `OSTICKET_URL` / `OSTICKET_API_KEY` | — | osTicket API | -| `FRESHDESK_URL` / `FRESHDESK_API_KEY` | — | Freshdesk API | -| `WHATSAPP_TOKEN` / `WHATSAPP_PHONE_NUMBER_ID` | — | WhatsApp Business API | - -> [!WARNING] -> `HERMES_API_KEY`, `ADMIN_API_KEY`, `DB_PASSWORD`, and the platform API keys are secrets. Keep them in `.env` (never committed). - -## Compose Overlays - -The base `docker-compose.yml` brings up the core stack; add overlays for extra services in `compose/`: - -| Overlay | Adds | -|---------|------| -| `docker-compose.mail.yml` | Mail handling | -| `docker-compose.knowledge.yml` | Knowledge-base indexing | -| `docker-compose.monitoring.yml` | Monitoring | -| `docker-compose.automation.yml` | n8n automation | -| `docker-compose.selfhosted.yml` | Self-hosted extras | -| `docker-compose.storage.yml` | Object/file storage | -| `docker-compose.wiki.yml` / `.git.yml` / `.ci.yml` / `.plus.yml` | Wiki, git, CI, extras | - -## Web UI - -| File | Purpose | -|------|---------| -| `index.html` | Landing page with features, architecture, and quick start | -| `admin/admin-dashboard.html` | Real-time admin dashboard: metrics, queue, service health, costs, audit log | -| `tools-ui/index.html` | Embeddable WhatsApp-style widget preview with a configuration panel | - -## Project Structure +## Stack -``` -CommandDesk/ -├── admin/admin-dashboard.html # Real-time ops dashboard -├── compose/ # Docker Compose overlays -├── config/ # Agent & service configuration -├── scripts/ # Backend agents & utilities -│ ├── agent_server.py # Core helpdesk agent (FastAPI) -│ ├── email_fetcher.py # Email ingestion (IMAP) -│ ├── session_manager.py # Session lifecycle -│ ├── rate_limiter.py # Rate limiting engine -│ ├── health_monitor.py # Service health checks -│ ├── analytics.py # Cost & usage analytics -│ └── whatsapp_webhook.py # WhatsApp integration -├── skills/ # AI skill definitions -├── ticket_platforms/ # osTicket, Freshdesk, Zammad, email adapters -├── tools-ui/ # Embeddable web widget -├── workflows/ # n8n workflow JSONs -├── docker-compose.yml # Production deployment -├── Dockerfile # Helpdesk agent image -└── .env.example -``` - -## Use Cases - -1. **Small-team helpdesk** — automate first-line responses without a SaaS bill. -2. **Privacy-sensitive support** — keep tickets and customer data on-premises. -3. **AI cost visibility** — track exactly what each automated ticket costs in tokens. - -## Tech Stack - -Python 3.10+ · FastAPI · llama.cpp / OpenAI · ChromaDB · PostgreSQL · Redis · SearXNG · n8n · Docker Compose · HTML/CSS - -## Screenshots - -| View | | -|---|---| -| ![admin dashboard](docs/screenshots/admin-dashboard.png) | ![ai assistant](docs/screenshots/ai-assistant.png) | -| ![costs](docs/screenshots/costs.png) | ![widget preview](docs/screenshots/widget-preview.png) | -| ![landing](docs/screenshots/landing.png) | ![mobile](docs/screenshots/main.mobile.png) | +Python 3.10+ · FastAPI · llama.cpp / OpenAI · ChromaDB · PostgreSQL · Redis · SearXNG · n8n · Docker Compose · HTML/CSS. ## Contributing -Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). [Open an issue](https://github.com/OneByJorah/CommandDesk/issues). +See [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). [Open an issue](https://github.com/OneByJorah/CommandDesk/issues). ## License MIT — see [LICENSE](LICENSE). - -## Connect - -- [jorahone.com](https://jorahone.com) -- [GitHub Org](https://github.com/OneByJorah) -- [info@jorahone.com](mailto:info@jorahone.com) From 92484425e1b8c1b8577920e54b2212cc1198e996 Mon Sep 17 00:00:00 2001 From: opencode Date: Sun, 13 Sep 2026 08:30:05 -0400 Subject: [PATCH 2/2] fix: indent whatsapp-webhook/health-monitor/tools-ui under services; valid default IP Three services were defined at top level instead of under services:, which invalidated the compose file. Also replaced placeholders with 127.0.0.1 so config validates and the stack binds loopback by default. Co-Authored-By: opencode --- docker-compose.yml | 168 ++++++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2181660..177001a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: image: ghcr.io/ggerganov/llama.cpp:server container_name: helpdesk-llama ports: - - ":8081:8081" + - "127.0.0.1:8081:8081" volumes: - ./models:/models:ro environment: @@ -17,7 +17,7 @@ services: - LLAMA_ARG_CTX_SIZE=65536 - LLAMA_ARG_N_BATCH=512 - LLAMA_ARG_THREADS=6 - - LLAMA_ARG_HOST= + - LLAMA_ARG_HOST=127.0.0.1 - LLAMA_ARG_N_GL=0 deploy: resources: @@ -25,7 +25,7 @@ services: memory: 7G restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-f", "http://:8081/health"] + test: ["CMD", "curl", "-f", "http://127.0.0.1:8081/health"] interval: 30s timeout: 10s retries: 5 @@ -42,7 +42,7 @@ services: dockerfile: Dockerfile container_name: helpdesk-agent ports: - - ":8080:8080" + - "127.0.0.1:8080:8080" volumes: - ./config:/app/config:ro - ./ticket_platforms:/app/ticket_platforms:ro @@ -90,7 +90,7 @@ services: dockerfile: Dockerfile container_name: helpdesk-admin-agent ports: - - ":8082:8082" + - "127.0.0.1:8082:8082" volumes: - ./config:/app/config:ro - ./ticket_platforms:/app/ticket_platforms:ro @@ -132,11 +132,11 @@ services: image: chromadb/chroma:0.5.23 container_name: helpdesk-chroma ports: - - ":8000:8000" + - "127.0.0.1:8000:8000" volumes: - chroma-data:/chroma/chroma environment: - - CHROMA_SERVER_HOST= + - CHROMA_SERVER_HOST=127.0.0.1 - CHROMA_SERVER_PORT=8000 - PERSIST_DIRECTORY=/chroma/chroma - ALLOW_RESET=true @@ -147,7 +147,7 @@ services: memory: 2G restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-sf", "http://:8000/api/v1/heartbeat"] + test: ["CMD", "curl", "-sf", "http://127.0.0.1:8000/api/v1/heartbeat"] interval: 30s timeout: 10s retries: 3 @@ -161,20 +161,20 @@ services: image: searxng/searxng:latest container_name: helpdesk-searxng ports: - - ":8888:8080" + - "127.0.0.1:8888:8080" volumes: - searxng-data:/etc/searxng - ./config/searxng-settings.yml:/etc/searxng/settings.yml:ro environment: - SEARXNG_BASE_URL=http://localhost:8888/ - - SEARXNG_BIND_ADDRESS= + - SEARXNG_BIND_ADDRESS=127.0.0.1 deploy: resources: limits: memory: 1G restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-sf", "http://:8888/search?q=test&format=json"] + test: ["CMD", "curl", "-sf", "http://127.0.0.1:8888/search?q=test&format=json"] interval: 60s timeout: 10s retries: 3 @@ -188,7 +188,7 @@ services: image: n8nio/n8n:latest container_name: helpdesk-n8n ports: - - ":5678:5678" + - "127.0.0.1:5678:5678" volumes: - n8n-data:/home/node/.n8n - ./workflows:/home/node/.n8n/workflows:ro @@ -207,7 +207,7 @@ services: memory: 1G restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-sf", "http://:5678/healthz"] + test: ["CMD", "curl", "-sf", "http://127.0.0.1:5678/healthz"] interval: 30s timeout: 10s retries: 3 @@ -221,7 +221,7 @@ services: image: postgres:16-alpine container_name: helpdesk-postgres ports: - - ":5432:5432" + - "127.0.0.1:5432:5432" volumes: - postgres-data:/var/lib/postgresql/data - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro @@ -250,7 +250,7 @@ services: image: redis:7-alpine container_name: helpdesk-redis ports: - - ":6379:6379" + - "127.0.0.1:6379:6379" volumes: - redis-data:/data command: > @@ -339,82 +339,82 @@ services: # ═══════════════════════════════════════════════════ # WhatsApp Webhook Receiver # ═══════════════════════════════════════════════════ -whatsapp-webhook: - build: - context: . - dockerfile: Dockerfile.whatsapp - container_name: helpdesk-whatsapp - ports: - - ":9090:9090" - - ":8383:8383" - volumes: - - ./config:/app/config:ro - - ./scripts:/app/scripts:ro - environment: - - WHATSAPP_TOKEN=${WHATSAPP_TOKEN} - - WHATSAPP_PHONE_NUMBER_ID=${WHATSAPP_PHONE_NUMBER_ID} - - WHATSAPP_WEBHOOK_SECRET=${WHATSAPP_WEBHOOK_SECRET:-change_me} - - ADMIN_PHONE_NUMBER=${ADMIN_PHONE_NUMBER} - - HELPDESK_AGENT_URL=http://helpdesk-agent:8080 - - REDIS_URL=redis://:${REDIS_PASSWORD:-redis_pass}@redis:6379/0 - - WHATSAPP_RATE_LIMIT_PER_MINUTE=${WHATSAPP_RATE_LIMIT_PER_MINUTE:-10} - depends_on: - helpdesk-agent: - condition: service_started - redis: - condition: service_healthy - deploy: - resources: - limits: - memory: 500M - restart: unless-stopped - networks: - - helpdesk-net + whatsapp-webhook: + build: + context: . + dockerfile: Dockerfile.whatsapp + container_name: helpdesk-whatsapp + ports: + - "127.0.0.1:9090:9090" + - "127.0.0.1:8383:8383" + volumes: + - ./config:/app/config:ro + - ./scripts:/app/scripts:ro + environment: + - WHATSAPP_TOKEN=${WHATSAPP_TOKEN} + - WHATSAPP_PHONE_NUMBER_ID=${WHATSAPP_PHONE_NUMBER_ID} + - WHATSAPP_WEBHOOK_SECRET=${WHATSAPP_WEBHOOK_SECRET:-change_me} + - ADMIN_PHONE_NUMBER=${ADMIN_PHONE_NUMBER} + - HELPDESK_AGENT_URL=http://helpdesk-agent:8080 + - REDIS_URL=redis://:${REDIS_PASSWORD:-redis_pass}@redis:6379/0 + - WHATSAPP_RATE_LIMIT_PER_MINUTE=${WHATSAPP_RATE_LIMIT_PER_MINUTE:-10} + depends_on: + helpdesk-agent: + condition: service_started + redis: + condition: service_healthy + deploy: + resources: + limits: + memory: 500M + restart: unless-stopped + networks: + - helpdesk-net # ═══════════════════════════════════════════════════ # Health Monitor # ═══════════════════════════════════════════════════ -health-monitor: - build: - context: . - dockerfile: Dockerfile - container_name: helpdesk-health - volumes: - - ./scripts:/app/scripts:ro - - ./config:/app/config:ro - environment: - - REDIS_URL=redis://:${REDIS_PASSWORD:-redis_pass}@redis:6379/0 - depends_on: - redis: - condition: service_healthy - deploy: - resources: - limits: - memory: 200M - restart: unless-stopped - networks: - - helpdesk-net + health-monitor: + build: + context: . + dockerfile: Dockerfile + container_name: helpdesk-health + volumes: + - ./scripts:/app/scripts:ro + - ./config:/app/config:ro + environment: + - REDIS_URL=redis://:${REDIS_PASSWORD:-redis_pass}@redis:6379/0 + depends_on: + redis: + condition: service_healthy + deploy: + resources: + limits: + memory: 200M + restart: unless-stopped + networks: + - helpdesk-net # ═══════════════════════════════════════════════════ # Tools UI (Widget + Admin Panel) # ═══════════════════════════════════════════════════ -tools-ui: - build: - context: tools-ui - dockerfile: Dockerfile - container_name: helpdesk-tools-ui - ports: - - ":8484:8484" - depends_on: - - helpdesk-agent - - admin-agent - deploy: - resources: - limits: - memory: 200M - restart: unless-stopped - networks: - - helpdesk-net + tools-ui: + build: + context: tools-ui + dockerfile: Dockerfile + container_name: helpdesk-tools-ui + ports: + - "127.0.0.1:8484:8484" + depends_on: + - helpdesk-agent + - admin-agent + deploy: + resources: + limits: + memory: 200M + restart: unless-stopped + networks: + - helpdesk-net # ═══════════════════════════════════════════════════ # Networks @@ -424,7 +424,7 @@ networks: driver: bridge ipam: config: - - subnet: /16 + - subnet: 127.0.0.1/16 # ═══════════════════════════════════════════════════ # Volumes