Give your AI coding agents a job board. Turn Claude Code, Codex, OpenCode, and any CLI-based AI tool into an autonomous software team — with task routing, memory sharing, and human-in-the-loop approval — all orchestrated from a single dashboard.
![]() |
![]() |
You already have AI coding agents installed. claude, codex, opencode, gemini — they sit in your terminal, waiting for prompts. Agent Control turns them into a coordinated team:
| Without Agent Control | With Agent Control |
|---|---|
| One agent, one prompt, one shot | Multiple agents, continuous loops, task routing |
| No memory between sessions | Memory bridged via GitHub Issues, Linear, Jira |
| Manual model selection per command | Smart routing: expensive models plan, cheap ones code |
| Human copies outputs between tools | Agents hand off tasks to each other via labels |
| "Did it work?" — check logs manually | Real-time dashboard with status, logs, analytics |
It's not a workflow engine. It's a job board for your CLI agents.
┌──────────────────────────────────────────────────────────────┐
│ Dashboard (Expo / React Native) │
│ Web · iOS · Android — Real-time via SSE stream │
│ http://localhost:8081 ← API │
└───────────────────────────┬──────────────────────────────────┘
│ REST + SSE
┌───────────────────────────▼──────────────────────────────────┐
│ API Server (agent-api) │
│ Agent CRUD · Settings · Secrets · Hooks · Git · Skills │
│ Port 8080 │
└───────────────────────────┬──────────────────────────────────┘
│ SQLite + Filesystem
┌───────────────────────────▼──────────────────────────────────┐
│ Runner (agent-ctrl) │
│ Orchestrator · Provider Bridge · Tracker · Memory │
│ · Cron · Hooks · Notifications │
│ ┌───────────┐ ┌──────────┐ ┌───────────┐ ┌────────────┐ │
│ │ Codex │ │ Claude │ │ OpenCode │ │ Gemini / │ │
│ │ Provider │ │ Provider │ │ Provider │ │ Copilot │ │
│ └───────────┘ └──────────┘ └───────────┘ └────────────┘ │
│ │ GitHub/Local Tracker · Cron · Hooks │
└──────────────────────────────────────────────────────────────┘
Two binaries, one database:
| Binary | Role | Runs |
|---|---|---|
agent-api |
REST API + SSE streaming | Continuously (daemon) |
agent-ctrl |
Agent executor per agent | Per-agent (launchd/cron/daemon) |
Everything is backed by a single SQLite database (core/data/agentctrl.db) — zero external dependencies beyond Go's standard library.
cd core
go run ./cmd/api --port 8080
# → Agent Control Office ready addr=0.0.0.0:8080cd frontend
bun install
bun run web
# → Opens http://localhost:8081 in your browsercurl -X POST http://localhost:8080/api/agents \
-H 'Content-Type: application/json' \
-d '{
"id": "backend-dev",
"role": "Backend Developer",
"provider": "cli",
"cli_tool": "opencode",
"model": "haiku",
"enabled": true,
"instruction": "You are a backend developer. Write clean, tested Go code.",
"task_source": {"type": "local", "path": "data/agents/backend-dev/tasks"},
"max_tasks_per_cycle": 1
}'mkdir -p core/data/agents/backend-dev/tasks/todo
cat > core/data/agents/backend-dev/tasks/todo/001-add-healthcheck.md << 'EOF'
---
id: add-healthcheck
title: Add health check endpoint
---
Add a GET /health endpoint to the API that returns {"status": "ok"}.
Include a test. Use the standard library net/http.
EOFcd core && go run ./cmd/runner --agent backend-dev --onceYour agent picks up the task, feeds it to OpenCode via stdin, and reports results back to the dashboard. That's it.
Your issue tracker is the distributed state machine. No separate workflow engine needed.
┌─────────┐ ┌──────────┐ ┌───────────┐ ┌────────┐
│ ai-plan │───▶│ai-backend│───▶│ ai-review │───▶│ ai-qe │
│ Planner │ │ Backend │ │ Reviewer │ │ QA │
└─────────┘ └──────────┘ └───────────┘ └────────┘
│ │
│ GitHub Issue / Linear Ticket │
│ (label = queue position, comments = memory) │
│ │
└──────── needs-human (escalation gate) ◀──────────┘
- Each agent watches for its label on GitHub Issues or local task buckets
- Completing a task → agent removes its label, adds the next one
- Every state transition is an issue comment (full audit trail)
- Human override is a label change away
Agents never call each other. They poll their task source on a schedule and pull work when it's available. This means:
- No message queues to manage — GitHub Issues IS the queue
- Crash recovery is trivial — label stays; agent restarts and picks up where it left off
- No central orchestrator process — each agent is self-contained
- Heterogeneous scheduling — one agent runs on cron, another on interval, another on demand
Any CLI tool that reads stdin and produces output is a provider. The bridge:
- Writes the prompt to a temp file
- Substitutes
{prompt_file}in the command template - Runs the CLI with timeout + signal handling
- Parses stdout for JSON results + extracts run metadata (tokens, model, session ID)
- Detects quota/auth errors and marks them as "blocked" (not "failed")
{
"id": "opencode",
"name": "OpenCode",
"default_command": "cat \"{prompt_file}\" | opencode run --pure --dangerously-skip-permissions"
}Supported CLI tools: Codex, Claude, OpenCode, Gemini, Copilot — add new ones by editing cli_tools.json.
![]() |
![]() |
Different tasks need different models. Route them by label or agent role:
ai-product-owner → sonnet (thinking, planning, research, analysis)
ai-developer → haiku (code generation for backend/mobile/web/…)
ai-review → opus (review needs precision with senior engineer quality)
ai-qe → haiku (test generation is mechanical)
Each agent has its own model configuration. Labels + models = cost-optimized pipelines.
Agents can pause and ask for permission before executing:
- Agent reaches
require_approvalgate → writes toapprovalstable - Dashboard receives notification (SSE + Telegram)
- User reviews task in web/mobile UI → clicks Approve or Reject
- Agent resumes or skips (10-minute timeout)
No Pinecone. No Chroma. No complexity.
- Short-term: Agent state lives in per-agent SQLite (
handoffstable +runstable) - Cross-agent: Task context passes through GitHub Issue comments or local MD files
- Persistent: Control plane stores agent configs, settings, secrets, hooks
Each agent's previous run context is injected into the next prompt as SUPERVISOR_MEMORY_JSON.
- 3D Desk Grid — All agents rendered as interactive terminal cards with real-time status glow
- System Monitor — Live CPU/RAM meters, process list, macOS service health
- Unified Event Log — Real-time log viewer with type filters (pre/post/sub/agent) and search
- SSE Streaming — Agent state changes pushed to the dashboard in real-time (no polling)
- UTC Clock — Synchronized time display across all agents and event log entries
- Full CRUD — Create, edit, duplicate, delete agents from the UI
- Lifecycle Actions — Start, stop, restart, install (launchd/systemd), uninstall, run-once
- Launchd Integration — macOS: generate plist, bootstrap, bootout from the UI
- Cron Scheduling — 5-field cron expressions with visual editor and validation
- Agent Dossier — Deep-dive into any agent: run history, logs, task queue, quick actions
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
- Full-Featured Editor — Edit agent prompts with syntax highlighting
- Variable Preview — See rendered prompts with all
{variables}resolved - Suggestions Pool — Save, browse, and insert prompt templates
- AI Improvement — One-click prompt optimization via OpenRouter (or bring your own LLM)
- Agent Docs — Edit per-agent
AGENTS.mddocumentation from the UI
- Dual Task Sources — Local file buckets (todo/in-progress/done/blocked) or GitHub Issues
- Label-Based Discovery — Agents discover tasks by matching labels in GitHub Issues
- Pipeline Workflows — Chain multiple agents: planner → backend → reviewer → QA
- Approval Gates — Require human approval before task execution (inline Approve/Reject)
- GitHub Integration — Full OAuth flow, repo browsing, clone/sync management
- Lifecycle Hooks — Pre-execution, post-completion, error-failure, watch-monitor hooks
- Dual Types — Shell commands and HTTP webhooks
- Per-Agent Filtering — Hooks scoped to specific agent IDs
- Cycle Gates — Pre-hooks can block cycles (e.g., "don't run during deployment window")
![]() |
![]() |
- Status Dashboard — See which CLI tools are installed and their binary paths
- One-Click Install — Install Codex, Claude, Gemini, OpenCode, Copilot from the UI
- Built-In Reference — Inline documentation with command templates, flags, and examples
- Model Discovery — List available models per CLI tool
![]() |
![]() |
- Run Statistics — Total runs, status distribution, runs per agent
- Token Tracking — Prompt tokens, completion tokens, total tokens per agent
- Cost Estimation — Estimated USD cost based on model pricing (Sonnet, Haiku, GPT-4o-mini, GPT-4o)
- Runtime Inspector — Drill into per-agent SQLite databases, tables, events, lock files
![]() |
![]() |
- Secrets Management — Masked API keys stored in SQLite with reveal/hide
- Environment Variables — Runtime env var editor with key-value pairs
- GitHub OAuth — Full OAuth web flow + mobile deep link support
- Notification Testing — Test Telegram notifications from the UI
- Provider Smoke Testing — Validate CLI provider config with exit code + output display
- Web — Full-featured dashboard with responsive layout
- iOS / Android — Native mobile app via Expo with push notifications
- iOS Widgets — Home screen widgets showing agent counts
- Bilingual — Full English and Turkish localization with in-app toggle
| CLI Tool | Provider | Pipe Prompt? | Model Arg? | Install from UI? | Docs? |
|---|---|---|---|---|---|
| Codex | OpenAI | codex exec --sandbox |
-m {model} |
✅ | ✅ |
| Claude | Anthropic | claude --print |
--model {model} |
✅ | ✅ |
| OpenCode | OpenCode | opencode run --pure |
Built-in | ✅ | ✅ |
| Gemini | gemini |
-m {model} |
✅ | ✅ | |
| Copilot | GitHub | copilot |
-m {model} |
✅ | ✅ |
Add any CLI tool by editing core/data/cli_tools.json — the provider bridge handles the rest.
| Agent Control | LangChain / CrewAI | Manual CLI Usage | |
|---|---|---|---|
| Orchestration | Label-driven (no workflow engine) | Code-defined DAGs & chains | None |
| Setup | 1 binary + SQLite | Python venv + dependencies | Just the CLI |
| Memory | GitHub Issues / SQLite / local files | Vector DBs, LangSmith | Manual copy-paste |
| Multi-Agent | Pull-based, decoupled | Framework-coded collaboration | Sequential manual runs |
| Human-in-the-Loop | Built-in approval cards + notifications | Requires custom code | The human IS the loop |
| Monitoring | Real-time SSE dashboard + Telegram | LangSmith / manual logging | Terminal output only |
| Failure Recovery | Label stays; agent retries on restart | Framework-specific error handling | Re-run manually |
| External Dependencies | 1 (pure Go SQLite) | 20+ Python packages | None |
| Model Routing | Per-agent, per-label, per-task | Per-chain configuration | Manual per-command |
Agent Control sits between "manual CLI usage" (too simple for teams) and "heavy frameworks" (too complex for individual developers). It gives you just enough structure without locking you into a workflow engine.
git clone https://github.com/serifcolakel/agent-control.git
cd agent-control
# Backend
cd core
make build # All platforms (macOS, Linux, Windows)
# Or: make build-darwin # macOS only
# Or: make build-linux # Linux only
# Frontend
cd ../frontend
bun install
bun run web| Component | Minimum |
|---|---|
| Go | 1.25+ |
| Bun | Latest (for frontend) |
| Node.js | 20+ (for Expo) |
| At least one CLI tool | Codex, Claude, OpenCode, Gemini, or Copilot |
Agent Control orchestrates your existing CLI tools — it doesn't replace their setup. Before running agents, make sure each CLI tool is properly configured:
- AGENTS.md — Repository-level instructions that define how the AI should behave in your codebase
- Skills — Loaded capabilities for Project Folder (domain expertise, patterns, testing frameworks, etc.)
- MCP Servers — Model Context Protocol servers with proper access permissions (linear, jira, filesystem, database, API, etc.)
- Extra Tools — Custom CLI tools like
rtk,gh, codebase-memory-mcp, and any other tooling your agents rely on - Authentication — API keys, tokens, and credentials configured for each CLI tool
Agent Control takes this existing setup and automates the workflow loop on top of it. If your CLI tools aren't working standalone, they won't work orchestrated either.
| Platform | Binary |
|---|---|
| macOS ARM64 | core/bin/darwin-arm64/agent-api, agent-ctrl |
| Linux AMD64 | core/bin/linux-amd64/agent-api, agent-ctrl |
| Linux ARM64 | core/bin/linux-arm64/agent-api, agent-ctrl |
| Windows AMD64 | core/bin/windows-amd64/agent-api.exe, agent-ctrl.exe |
Place in core/.env or set in your shell:
| Variable | Purpose |
|---|---|
LINEAR_API_KEY |
Linear integration (MCP-based issue tracking) |
LINEAR_TEAM_NAME |
Linear team name for issue routing |
TELEGRAM_BOT_TOKEN |
Telegram notifications (cycle start, completion, panics) |
TELEGRAM_CHAT_ID |
Telegram chat ID for delivery |
TARGET_REPO_DIR |
Default working directory for agents |
OPENROUTER_API_KEY |
AI-powered prompt improvement |
OPENAI_API_KEY |
Fallback for prompt improvement |
AGENT_PROMPT_OVERRIDE |
Override agent prompt at runtime |
AGENT_SKIP_PERMISSIONS |
Skip confirmations (default: true) |
GITHUB_TOKEN |
GitHub API access for issue-based task sources |
GITHUB_CLIENT_ID |
GitHub OAuth app client ID |
GITHUB_CLIENT_SECRET |
GitHub OAuth app client secret |
Agents can override their configuration at runtime using an inline config block in their prompt:
You are a backend developer. Write Go code.
```agentctrl-config
{
"provider": "cli",
"model": "sonnet",
"max_tasks_per_cycle": 3,
"target_repo_dir": "/path/to/project"
}
```Values from the config block take precedence over stored agent configuration — useful for one-off runs without modifying the database.
| Resource | Endpoint |
|---|---|
| Health | GET /api/health |
| Stream | GET /api/stream (SSE) |
| Agents | GET/POST /api/agents, GET/PUT/DELETE /api/agents/:id |
| Agent Actions | POST /api/agents/:id/action (start, stop, restart, install, uninstall) |
| Agent States | GET /api/agents/states, GET /api/agents/:id/states |
| Tasks | GET /api/agents/:id/tasks, GET /api/agents/:id/task-preview |
| Runs | GET /api/agents/:id/runs |
| Logs | GET /api/agents/:id/logstream (SSE) |
| Prompt | GET/POST /api/agents/:id/prompt, GET /api/agents/:id/preview-prompt |
| Settings | GET/POST /api/settings |
| Secrets | GET/POST /api/secrets |
| Hooks | GET/POST /api/hooks, PUT/DELETE /api/hooks/:id |
| CLI Tools | GET/POST /api/settings/cli-tools, POST /api/cli-install |
| Git | GET/POST/DELETE /api/git/projects, POST /api/git/clone-sync |
| Analytics | GET /api/analytics |
| Pipelines | GET/POST /api/pipelines, POST /api/pipelines/:id/run |
| Approvals | GET /api/approvals, POST /api/approvals/:id |
| Notifications | POST /api/test/notification |
| Auth | GET /auth/github, GET /auth/github/callback, GET /auth/logout |
Full API documentation: see core/internal/controlplane/ and core/cmd/api/router.go.
agent-control/
├── core/ # 🔥 Go backend (1 external dependency)
│ ├── Makefile # Build, test, vet, clean
│ ├── cmd/
│ │ ├── runner/main.go # Agent executor binary (agent-ctrl)
│ │ └── api/main.go, router.go # REST API binary (agent-api)
│ ├── internal/
│ │ ├── orchestrator/ # RunCycle, RunDiscovery, pipeline handoff
│ │ ├── provider/ # CLI bridge (stdin→stdout), Claude, Noop adapters
│ │ ├── tracker/ # Task sources: GitHub Issues, Local files, Noop
│ │ ├── controlplane/ # Agent CRUD, settings, secrets, hooks, approvals
│ │ ├── agentmanager/ # Agent lifecycle (start/stop/install/uninstall)
│ │ ├── strategies/ # Prompt builder, prompt-only mode, validation
│ │ ├── hooks/ # Shell + webhook lifecycle hooks
│ │ ├── memory/ # Per-agent SQLite: runs, handoffs, events, KV store
│ │ ├── config/ # AgentConfig loader from SQLite + registry.json
│ │ ├── models/ # Task, ProviderResult, Event, Hook, MemoryContext
│ │ ├── notifications/ # Telegram Bot API integration
│ │ ├── gitutils/ # Git clone, checkout, commit helpers
│ │ ├── cron/ # 5-field cron parser
│ │ ├── servicemanager/ # macOS launchd plist generation + bootstrap
│ │ ├── sysinfo/ # System monitoring (OS, CPU, RAM, disk)
│ │ ├── session/ # JSON session state files
│ │ ├── lockfile/ # Atomic file lock for single-instance
│ │ └── legacyimport/ # Legacy folder import migration
│ └── data/ # Runtime data (SQLite DBs, CLI tools config)
│ ├── agentctrl.db # Control plane: agents, hooks, settings, secrets
│ ├── cli_tools.json # CLI tool definitions + command templates
│ └── agents/ # Per-agent state DBs + task buckets + logs
├── frontend/ # 📱 React Native (Expo) dashboard
│ ├── src/
│ │ ├── app/ # Expo Router: single-page dashboard
│ │ ├── components/
│ │ │ ├── modals/ # 22 modal screens (CRUD, config, tools, analytics)
│ │ │ ├── panels/ # Side panels (Agent Dossier, desk cards)
│ │ │ ├── desks/ # 3D agent card grid
│ │ │ └── layout/ # Header, navigation
│ │ ├── stores/ # Zustand: agent state, UI state
│ │ ├── services/ # REST API client, SSE stream client
│ │ ├── hooks/ # TanStack Query wrappers
│ │ ├── i18n/ # Bilingual: English + Turkish
│ │ └── constants/ # Theme, typography, colors
│ └── package.json # Expo SDK 57 + React 19 + TanStack Query
├── AGENTS.md # Repository guidelines
└── README.md # You are here
cd core
# Build
make build
# Test
make test && make vet
# Run API with hot-reload
go install github.com/air-verse/air@latest
air -- --port 8080
# Run a single agent cycle
go run ./cmd/runner --agent my-agent --oncecd frontend
bun install
bun run check # Biome format + lint
bun run web # Start web dashboard| Issue | Solution |
|---|---|
agentctrl.db missing |
Created automatically on first API start |
| Port 8080 in use | Use --port 8081 |
| "database is locked" | Only one process writes at a time; don't run API + runner simultaneously against same agent |
| Provider CLI not found | Check core/data/cli_tools.json and install the CLI tool |
go.sum out of date |
cd core && go mod tidy |
Agent Control is an open-source project. Contributions are welcome in any form:
- Bug reports & feature requests — Open a GitHub Issue
- Code — Fork, branch, and submit a PR with a clear description
- Documentation — Improve READMEs, add examples, write tutorials
- CLI tool definitions — Add support for new CLI-based AI tools via
cli_tools.json
See AGENTS.md for repository conventions and guidelines.
MIT © Serif Colakel
Built with Go, Expo, and the belief that your CLI tools deserve a job board.















