botctl is a process manager for autonomous AI bots. Each bot is defined by a single BOT.md file — YAML config and a markdown prompt. The harness runs each bot in a loop: execute, log, sleep, repeat. No servers, no infrastructure, just a Go binary.
Bots persist across runs with session memory. You can send messages, resume sessions, and monitor everything from a TUI, web dashboard, or CLI.
macOS / Linux
Windows (PowerShell)
Go
Pre-built binaries for macOS, Linux, and Windows are on the releases page.
Each bot lives at ~/.botctl/bots/{name}/ and is defined by a BOT.md file. YAML frontmatter sets the config, the markdown body is the bot's prompt.
The markdown body becomes the bot's system prompt. Claude sees it every run along with workspace path, skills, and turn limit. Edit the file and changes take effect on the next run — no restart needed.
| Field | Type | Description |
|---|---|---|
| name | string | Display name for the bot (required) |
| id | string | Stable database key — survives folder renames. Defaults to folder name. |
| interval_seconds | int | Seconds between runs. Default: 60 |
| max_turns | int | Turn limit per run. 0 = unlimited. When hit, the session is saved for resume. |
| workspace | string | local (per-bot) or shared (global). Default: local |
| skills_dir | string | Relative path to skill directories |
| log_dir | string | Custom log directory. Default: logs/ |
| log_retention | int | Number of run logs to keep before pruning. Default: 30 |
| env | map | Environment variables. Supports ${VAR} references to system env. |
Skills are directories containing a SKILL.md file with YAML frontmatter (name and description) and a markdown body. The harness parses frontmatter from all discovered skills and lists them by name and description in the system prompt. Claude loads full skill content on-demand via the Skill tool.
Skills are discovered from three locations (first occurrence of a name wins):
~/.agents/skills/— cross-agent shared skills~/.botctl/skills/— botctl-wide shared skills- Bot's
skills_dir— per-bot skills
Skills are re-discovered every run, so you can add, edit, or remove them without restarting the bot.
Managing Skills
The botctl skills commands let you search, install, view, and remove skills from the CLI.
By default, skills install to ~/.botctl/skills/ (shared across all bots). Use flags to change the destination:
| Flag | Destination |
|---|---|
--bot <name> | Bot's skills_dir (per-bot only) |
--global | ~/.agents/skills/ (cross-agent, shared with other tools) |
| (default) | ~/.botctl/skills/ (all botctl bots) |
- Local (
workspace: local) —~/.botctl/bots/{name}/workspace/— private to this bot - Shared (
workspace: shared) —~/.botctl/workspace/— shared across all bots that opt in
Claude's working directory is set to the workspace. All file operations happen there by default.
The env field in BOT.md sets environment variables for the bot process. Values support ${VAR} references that resolve against system environment variables.
Set MM_HOME to override the default ~/.botctl directory.
| Command | Description |
|---|---|
| botctl | Open the TUI dashboard (--web-ui for web, --port to set port) |
| botctl create [name] | Create a new bot via Claude (-d description, -i interval, -m max turns) |
| botctl start [name] | Start a bot (-d detach, -m message, --once single run) |
| botctl stop [name] | Stop a bot (no args = stop all) |
| botctl pause <name> | Pause a running or sleeping bot |
| botctl play <name> | Resume a paused bot |
| botctl list | List all bots with status |
| botctl status | Detailed status of all bots |
| botctl logs [name] | View logs (-n lines, -f follow) |
| botctl delete <name> | Delete a bot and its data (-y skip confirmation) |
| botctl skills list | List discovered skills (--bot to filter by bot) |
| botctl skills search <query> | Search skills.sh for community skills (-n limit) |
| botctl skills add <owner/repo> | Install skills from a GitHub repo (--skill, --bot, --global) |
| botctl skills view <name> | View a skill's SKILL.md and list its files |
| botctl skills remove <name> | Remove an installed skill |
| botctl update | Self-update to the latest release |
| botctl --version | Show version and commit hash |
Run botctl with no arguments to open the terminal dashboard. Two-pane layout: bot list on the left, streaming logs on the right.
Keybindings
Tip: To select text in the TUI, hold Option (macOS) or Shift (other terminals) while clicking and dragging.
Browser-based dashboard with the same capabilities as the TUI. Real-time log streaming via Server-Sent Events (SSE). Accessible from any device on your network.
API Endpoints
| Endpoint | Description |
|---|---|
| GET /api/bots | List all bots with status and stats |
| POST /api/bots/{name}/start | Start a bot |
| POST /api/bots/{name}/stop | Stop a bot |
| POST /api/bots/{name}/message | Send a message to a running bot |
| GET /api/bots/{name}/logs | Get log entries |
| GET /api/bots/{name}/logs/stream | SSE stream of log entries |
The harness is the background process that executes each bot. It runs a continuous loop:
- Reload
BOT.mdconfig from disk - Check the pending message queue
- Execute Claude with the bot's prompt, tools, and workspace
- Record stats (cost, turns, session ID) to the database
- Write structured log entries
- Sleep for
interval_seconds(woken early by messages or resume signals)
Config is reloaded every iteration, so changes to BOT.md take effect on the next run without restarting the harness.
When a run hits max_turns, the session ID is saved in the database. You can resume from exactly where Claude left off:
- Press
rin the TUI — opens an input pre-filled with the currentmax_turns. Edit the number and press enter. - The harness detects the resume signal, applies the new turn limit, and calls Claude with the saved session ID.
Messages sent to a running bot (via m in the TUI or botctl start --message) wake the harness early via SIGUSR1.
SQLite at ~/.botctl/data/botctl.db with WAL mode. Stores:
| Table | Description |
|---|---|
| runs | Execution history — duration, cost, turns, session ID, log file |
| pids | Active process tracking (bot name, PID, started_at) |
| messages | Raw Claude API response JSON per run |
| pending_messages | Message queue for operator-to-bot communication |
| log_entries | Structured log records (bot_id, run_id, kind, heading, body) |