Orch
An autonomous task orchestration engine that delegates work to AI coding agents (Claude, Codex, OpenCode, Kimi, MiniMax, Grok). Runs as a background service, manages isolated worktrees, syncs with GitHub Issues, and handles the full task lifecycle from routing to PR creation.
Features
- Multi-agent support — Route tasks to Claude, Codex, OpenCode, Kimi, MiniMax, or Grok based on task complexity
- Multi-project — Manage multiple repositories from a single service
- GitHub Issues integration — Two-way sync with GitHub Issues as the source of truth
- GitHub Projects V2 — Automatic project board column sync on status changes
- Isolated worktrees — Each task runs in its own git worktree, never touching the main repo
- Live session streaming — Watch agents work in real-time via
orch stream(all sessions) ororch stream <task_id> - Control session — Conversational ops assistant via
orch chat— ask about tasks, create new ones, check status in natural language - Internal tasks — SQLite-backed tasks for cron jobs and maintenance (no GitHub issue clutter)
- Job scheduler — Cron-like scheduled tasks with native Rust cron matching
- Automatic PR creation — Branches pushed, PRs created, and comments posted automatically
- Complexity-based routing — Router assigns
simple|medium|complexand config maps to models - Agent memory — Learnings persist across retries so agents don't repeat mistakes
- Per-task artifacts — Organized per-repo, per-task, per-attempt directory structure
Installation
On Linux, install the prebuilt binary with cargo-binstall, or build from source with cargo:
Run it as a systemd user service with orch serve as its command, then orch service start|stop|restart|status drives it through systemctl --user.
Quick Start
1. Initialize orch for your project
This creates:
~/.orch/config.yml— global configuration (shared defaults + project registry).orch.yml— project-specific configuration (in your project root)
2. Start the service
Or use Homebrew services:
3. Create a task
# Create an internal task (SQLite only, no GitHub issue)
# Create a GitHub issue task
4. Watch the magic
The service automatically:
- Routes tasks to the best agent based on content
- Creates isolated worktrees
- Runs the agent in a tmux session
- Pushes branches and creates PRs
- Updates GitHub issue status and project board
GitHub Authentication
Orch needs a GitHub token to sync issues and open PRs. The simplest setup is gh auth login — no extra config needed.
Tokens are resolved in this order (first match wins):
GH_TOKENenvironment variableGITHUB_TOKENenvironment variablegh.auth.tokenin~/.orch/config.ymlgh auth tokenCLI (enabled by default viagh.allow_gh_fallback: true)
For organizations, GitHub App auth is supported:
# ~/.orch/config.yml
github:
token_mode: github_app
app_id: "123456"
private_key_path: "/path/to/app-private-key.pem"
Orch generates JWTs from the private key (valid for 9 minutes) and caches the installation token until expiry.
Security: Service Deployments (Homebrew / launchd)
When running as a background service (e.g., brew services start orch), the service process does not inherit your shell environment. Pass the token securely:
Option A — ~/.private file (sourced automatically by runner scripts):
# ~/.private (chmod 600)
Option B — launchd EnvironmentVariables in the plist:
EnvironmentVariables
GH_TOKEN
ghp_xxxxxxxxxxxxxxxxxxxx
Option C — GitHub App (recommended for teams): no long-lived token needed; the service exchanges a short-lived JWT for an installation token automatically.
Important: Orch never writes
GH_TOKENinto runner scripts on disk. Tokens are injected into the tmux session environment at spawn time and exist only in process memory.
CLI Reference
Service Management
Task Management
Plan import
orch plan import reads a roadmap and creates one GitHub issue per task. Depends on is stored as a blocked-by link. Owner: human adds the owner:human and no-agent labels, so orch skips that task. A second run edits an issue only when the title, body or labels changed. A task dropped from the file is listed and left open. An open blocked-by link does not hold a task.
Project Management
GitHub Projects V2 Board
Job Management (Scheduled Tasks)
Utility Commands
Smart Commits
orch commit groups the working tree's staged + unstaged + untracked changes
into one or more logical commits by path, then asks the current chat agent
(orch chat's sticky /agent + /model) to draft a Conventional Commits
message for each group from the file list and unified diff. The diff is capped
at commit.max_diff_bytes bytes per group (default 32 KB) so the call stays
cheap and predictable. Edit, accept, or reject the drafts interactively; pass
--yes to skip the prompt or -m to override entirely.
Fallback behaviour: if no agent is available (all cooled, no API key, offline)
the heuristic message survives, a one-line warning is logged, and you still get
the editor unless --yes was passed. Use --no-llm to force the heuristic
path (handy for scripts and tests). The agent prompt lives at
prompts/commit_message.md.
Control Session (Chat)
In the REPL, use /model and /agent to manage the sticky agent:model selection:
orch> /model sonnet # Infer agent (claude)
orch> /model minimax:sonnet # Explicit agent:model
orch> /model opencode:minimax-m2.5-free # OpenCode with specific model
orch> /agent codex # Switch agent and its default model
orch> /agent grok # Switch to Grok (CLI default model)
orch> /agent # Show current agent:model
orch> /model # Show current agent:model
Configuration
Global config (~/.orch/config.yml)
Shared defaults and project registry. All settings here apply to every project unless overridden.
# Project registry — list of local paths
# Each path must contain a .orch.yml with gh.repo
projects:
- /Users/me/Projects/my-app
- /Users/me/Projects/my-lib
workflow:
auto_close: true
review_owner: "@owner"
enable_review_agent: false
max_attempts: 10
timeout_seconds: 1800
router:
mode: "llm" # "llm" | "round_robin" | "local" (Ollama)
agent: "claude" # which LLM performs routing
model: "haiku" # fast/cheap model for classification
timeout_seconds: 60
max_route_attempts: 3 # LLM failures before falling back to round-robin
max_tasks_per_tick: 1 # max routing decisions per engine tick
weighted_round_robin: false
fallback_executor: "codex"
model_map:
simple:
claude: haiku
codex: gpt-5.1-codex-mini
medium:
claude: sonnet
codex: gpt-5.2
complex:
claude: opus
codex: gpt-5.3-codex
review:
claude: sonnet
codex: gpt-5.2
# Agent CLIs to discover in $PATH
agents:
- claude
- codex
- opencode
- kimi
- minimax
- grok
git:
name: "orch[bot]"
email: "orch@orch.bot"
Project config (.orch.yml)
Place in your project root. Values here override global defaults.
See .orch.yml for a real-world example — orch uses itself to build, review, and improve its own codebase.
# Required — identifies this project on GitHub
gh:
repo: "owner/repo"
project_id: "PVT_..." # optional: GitHub Projects V2
project_status_field_id: "..." # optional
project_status_map: # optional
backlog: "option-id-1"
in_progress: "option-id-2"
review: "option-id-3"
done: "option-id-4"
# Optional overrides
workflow:
max_attempts: 5
router:
fallback_executor: "codex"
required_tools:
- cargo
- bun
# Per-project scheduled jobs
jobs:
- id: code-review
schedule: "0 4,17 * * *"
task:
title: "Code review"
body: "Review the codebase for bugs and improvements"
labels:
enabled: true
Task Statuses
| Status | Description |
|---|---|
new |
Task created, awaiting routing |
routed |
Agent assigned, awaiting dispatch |
in_progress |
Agent actively working in tmux session |
needs_review |
Agent completed, awaiting review agent dispatch (automatic) |
in_review |
Review agent actively reviewing the PR |
done |
PR merged, worktree cleaned up |
blocked |
Requires human attention (max review cycles, agent failures) |
Label-Based Routing
Override the router by adding labels to GitHub issues:
| Label | Effect |
|---|---|
agent:claude |
Force Claude executor |
agent:codex |
Force Codex executor |
agent:opencode |
Force OpenCode executor |
agent:kimi |
Force Kimi executor |
agent:minimax |
Force MiniMax executor |
agent:grok |
Force Grok executor |
complexity:simple |
Use simple model tier |
complexity:medium |
Use medium model tier |
complexity:complex |
Use complex model tier |
no-agent |
Skip agent routing (manual task) |
Architecture
Orch is built in Rust with a modular architecture:
src/
├── main.rs # CLI entrypoint (clap)
├── control.rs # Control session (orch chat) — context assembly, agent invocation
├── config/
│ └── mod.rs # Config loading, hot-reload, multi-project
├── store/ # Unified SQLite task store (tasks, metrics, KV, rate limits)
├── parser.rs # Agent response normalization
├── cron.rs # Cron expression matching
├── template.rs # Template rendering
├── tmux.rs # tmux session management
├── security.rs # Secret scanning + redaction
├── home.rs # Home directory (~/.orch/) + per-repo state paths
├── cmd.rs # Command execution helpers with error context
├── cmd_cache.rs # Cached command results
├── repo_context.rs # Per-repo task-local context
├── webhook_status.rs # Webhook health tracking
├── backends/ # External task backends
│ ├── mod.rs # ExternalBackend trait
│ └── github.rs # GitHub Issues + Projects V2 sync
├── channels/ # Communication channels
│ ├── transport.rs # Output broadcasting
│ ├── capture.rs # tmux output capture
│ ├── notification.rs # Unified notifications
│ ├── stream.rs # Live output streaming
│ ├── tmux.rs # tmux bridge
│ ├── github.rs # GitHub webhooks
│ ├── slack.rs # Slack integration
│ ├── telegram.rs # Telegram bot
│ ├── discord.rs # Discord registration + REST helpers
│ └── discord_ws.rs # Discord Gateway websocket (real-time events)
├── cli/ # CLI command implementations
│ ├── mod.rs # Init, agents, board, project, metrics, stream
│ ├── chat.rs # Control session (REPL, single-message, history)
│ ├── task.rs # Task CRUD
│ ├── job.rs # Job management
│ └── service.rs # Service lifecycle
├── github/ # GitHub API helpers
│ ├── cli_wrapper.rs # gh CLI wrapper
│ ├── http.rs # Native HTTP client (reqwest, connection pooling)
│ ├── token.rs # Token resolution (env, config, gh CLI, GitHub App)
│ ├── types.rs # Issue, Comment, Label, PR review types
│ └── projects.rs # Projects V2 GraphQL operations
└── engine/ # Core orchestration
├── mod.rs # Main event loop, project init, struct defs
├── tick.rs # Core tick phases (sessions, routing, dispatch, unblock)
├── sync.rs # Periodic sync (cleanup, PR review, mentions, skills)
├── review.rs # PR review pipeline (review agent, auto-merge, re-route)
├── cleanup.rs # Worktree cleanup, merged-PR detection, store helpers
├── commands.rs # Owner /slash commands in issue comments
├── tasks.rs # Task manager (internal + external, unified store)
├── router/ # Agent routing (label, round-robin, LLM)
│ ├── mod.rs # Router logic and RouteResult
│ ├── config.rs # Router configuration
│ └── weights.rs # Routing weight signals
├── jobs.rs # Job scheduler + self-review
└── runner/ # Task execution
├── mod.rs # Full task lifecycle
├── task_init.rs # Guard checks, worktree setup, invocation building
├── session.rs # tmux session lifecycle and output collection
├── context.rs # Prompt context building
├── worktree.rs # Git worktree management
├── agent.rs # Agent invocation + prompt building
├── agents/ # Per-agent runners (Claude, Codex, OpenCode, Kimi, MiniMax, Grok)
├── response.rs # Response parsing, weight signals
├── response_handler.rs # Success path: commit, push, PR
├── fallback.rs # Error classification and recovery strategies
└── git_ops.rs # Auto-commit, push, PR creation
Task Artifacts
Task artifacts are organized per-repo, per-task, per-attempt:
~/.orch/state/{owner}/{repo}/tasks/{id}/
attempts/
1/
prompt-sys.md # System prompt
prompt-msg.md # Task prompt
runner.sh # Runner script
exit.txt # Exit code
stderr.txt # Agent stderr
output.json # Agent response
result.json # Parsed result (status, summary, etc.)
2/ # Retry attempt
...
Task metadata (branch, worktree, agent, model, attempts, pr_number, memory, etc.) is stored in the unified SQLite database at ~/.orch/orch.db, not in per-task JSON files.
Development
Building from source
Running tests
Install nextest: cargo binstall cargo-nextest (requires cargo-binstall).
Logs
- Service log:
~/.orch/state/orch.log - Homebrew stdout:
/opt/homebrew/var/log/orch.log - Homebrew stderr:
/opt/homebrew/var/log/orch.error.log
Documentation
- AGENTS.md — Agent and developer notes (also exposed as
CLAUDE.mdvia symlink) - docs/architecture.md — System architecture and diagrams
- docs/content/ — User-facing reference: getting started, CLI, configuration, routing, jobs, channels, agents, alerting, GitHub sync, workflow
License
MIT