Self-organizing AI task system. Decomposes complex requests into focused, isolated agent sessions that run in parallel.
Telegram Bot ──writes──▶ SQLite ◀──reads── Daemon Manager
▲ ▲ │
│ │ fork / kill
│ │ ▼
└──reads events────────┴──read/write── Daemon (1 per project)
│
┌─────┼─────┐
agent agent agent
Three independent processes, one SQLite database:
| Process | What it does |
|---|---|
| Telegram Bot | Stateless relay. Writes commands to DB, reads events back. |
| Daemon Manager | Always-on. Scans DB, spawns daemon processes, health checks. |
| Daemon | One per project. Decomposes tasks, runs agents, sends results to Telegram. |
If the bot dies, daemons keep working. If the manager dies, running daemons keep working. Everything reconnects through SQLite.
- Node.js 20+
- An Anthropic API key
- A Telegram bot token (see Setting up Telegram below)
- Your Telegram username (see Setting up Telegram below)
git clone <repo> && cd overwatch
npm install
npm run buildCopy the example env file and fill in your values:
cp .env.example .envEdit .env:
ANTHROPIC_API_KEY=sk-ant-...
OW_TELEGRAM_TOKEN=123456:ABC-DEF...
OW_ALLOWED_USERS=yourusername # your Telegram username (without @) — REQUIRED for securityThe bot rejects all messages if OW_ALLOWED_USERS is empty.
source .env
npm startThat's it. This launches the daemon manager, Telegram bot, and TUI dashboard in a single process. Open Telegram and message your bot.
If a component crashes, it auto-restarts after 3 seconds. Ctrl+C stops everything.
For headless servers (no terminal UI):
npm run start:headless| Command | Description |
|---|---|
| Natural language message | Manager interprets intent and decides whether to start or control daemons |
/status |
List all daemons with task progress and cost |
/kill <name> |
Stop a daemon and all its agents |
/killall |
Stop all daemons |
When an agent asks a question, the daemon posts it as a Telegram message. Reply directly to that message and your response is routed back to the correct task automatically.
You: /start api Build a REST API with JWT auth and user CRUD
Bot: Started project "api" (daemon: 01J...)
Bot: [2 minutes later]
Project "api" completed.
Result:
## Auth System
Created JWT middleware in src/middleware/auth.ts...
## User CRUD
Added routes in src/routes/users.ts...
## Integration Tests
All 12 tests passing...
Overwatch automatically downloads the Anthropic Skills library on first run. During task decomposition, the system selects relevant skills (e.g. frontend-design, webapp-testing, pdf) and injects them into each agent's workspace. No setup required — it just works.
Skills are stored in ~/.overwatch/skill-library/. To use a custom skill library, set OW_SKILL_LIBRARY_DIR to a directory containing a skills/ folder with skill subdirectories.
See SECURITY.md for important information about external skill execution.
Overwatch maintains a capability registry in SQLite. Skills are synced as capabilities and applied at runtime with capability policies (tools, MCP allowlist, model/time/turn limits, rate limit, and optional budget cap).
Cron triggers are processed by the manager and enqueue root tasks when due. Trigger definitions live in the cron_triggers table (UTC 5-field cron).
Built-in capabilities include long-context-analysis, which uses an RLM-style recursive analysis path for very large local logs/docs/transcripts.
- You send a natural language request to Telegram (e.g. "start an api project and build JWT auth")
- Bot writes a daemon record + root task to SQLite
- Manager detects the new daemon, forks a process
- Daemon decomposes the prompt into subtasks via Claude (e.g., "Auth System", "User CRUD", "Tests")
- Independent subtasks run in parallel, each in a fresh agent session
- When all subtasks complete, results are aggregated and sent back to Telegram
- Daemon goes idle. Manager leaves it alone until new work arrives.
- Open Telegram and search for @BotFather
- Send
/newbotto create a new bot - Follow the prompts to set a name and username for your bot
- BotFather will reply with your bot token (looks like
123456:ABC-DEF...) — copy it intoOW_TELEGRAM_TOKENin your.env
Your Telegram username is the @handle shown in your profile (e.g. @johndoe). Add it to OW_ALLOWED_USERS in your .env without the @ prefix. Multiple usernames can be comma-separated.
All config is via environment variables. See .env.example for the full list.
| Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
— | Required. Anthropic API key. |
OW_TELEGRAM_TOKEN |
— | Required. Telegram bot token from @BotFather. See Setting up Telegram. |
OW_ALLOWED_USERS |
"" |
Comma-separated Telegram usernames (without @). Empty = reject all. See Setting up Telegram. |
OW_MODEL |
sonnet |
Claude model for agents. |
OW_MAX_AGENTS |
5 |
Max concurrent agents per daemon. |
OW_AGENT_TIMEOUT_MS |
600000 |
Per-agent timeout (10 min). |
OW_BUDGET_CAP_USD |
0 |
Per-daemon spend cap. 0 = unlimited. |
OW_DB_PATH |
.overwatch/orch.db |
SQLite database path. |
OW_SKILL_LIBRARY_DIR |
~/.overwatch/skill-library/ |
Directory containing external skills. Auto-downloaded on first run. |
OW_LOG_LEVEL |
info |
debug, info, warn, or error. |
Run everything without building (uses tsx):
npm run devOr run individual components:
npm run dev:manager
npm run dev:telegram
npm run dev:tuiRun a single daemon directly (bypasses manager):
npm run dev:daemon -- --name test --prompt "list files in the current directory"Build the project first:
npm run buildThen set up systemd services:
sudo bash scripts/setup.sh
sudo systemctl enable --now overwatch-manager
sudo systemctl enable --now overwatch-telegramDaemons are spawned automatically by the manager. To manually start one via systemd:
sudo systemctl start overwatch-daemon@myprojectsrc/
├── launch.ts # Single entry point — spawns all components
├── daemon/ # Standalone process per project
│ ├── index.ts # Entry point (parses args, sets up TG messaging)
│ ├── scheduler.ts # Event loop: decompose → spawn → promote → aggregate
│ ├── agent-pool.ts # Concurrent SDK query() calls with timeout
│ ├── decomposer.ts # LLM-powered task decomposition
│ ├── hooks.ts # SDK hooks (file tracking, session capture)
│ ├── budget.ts # Per-daemon cost tracking
│ └── lifecycle.ts # Signal handlers, PID file
├── manager/ # Always-on process that spawns daemons
│ └── index.ts # Scans SQLite, forks daemons, health checks
├── telegram/ # Stateless Telegram bot
│ ├── index.ts # Grammy bot setup, auth middleware
│ ├── commands.ts # Command handlers (all DB-only)
│ └── router.ts # Writes daemon/task records to DB
├── db/ # SQLite layer
│ ├── index.ts # Connection, WAL mode, transactions
│ ├── schema.ts # Tables, indexes, migrations
│ └── queries.ts # Typed query functions
├── shared/ # Cross-process utilities
│ ├── types.ts # TypeScript interfaces
│ ├── config.ts # Validated env var config
│ └── logger.ts # Structured logging (console + file)
├── skills/ # Role-based agent instructions
│ ├── index.ts # Skill injection (role + library skills)
│ ├── library.ts # Skill library scanner + auto-downloader
│ └── */SKILL.md # Per-role system prompts
├── mcp/ # MCP server configuration
│ ├── defaults.ts # Built-in server configs per role
│ └── registry.ts # Merges DB + defaults with validation
└── tui/ # Terminal dashboard (React + Ink)
├── index.ts # Main app
├── tree-view.ts # Task tree renderer
└── log-view.ts # Event log