Skip to content

gabrielkoerich/orch

Repository files navigation

Orch

CI

An autonomous task orchestrator that delegates work to AI coding agents (Claude, Codex, OpenCode, Kimi, MiniMax). 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, or MiniMax 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) or orch 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|complex and 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

brew tap gabrielkoerich/homebrew-tap brew install orch

Quick Start

1. Initialize orch for your project

cd /path/to/your/project orch init

This creates:

  • ~/.orch/config.yml — global configuration (shared defaults + project registry)
  • .orch.yml — project-specific configuration (in your project root)

2. Start the service

orch service start

Or use Homebrew services:

brew services start orch

3. Create a task

# Create an internal task (SQLite only, no GitHub issue) orch task add "Fix authentication bug" --body "Users can't login with OAuth" # Create a GitHub issue task orch task add "Update README" --labels "documentation,good-first-issue"

4. Watch the magic

The service automatically:

  1. Routes tasks to the best agent based on content
  2. Creates isolated worktrees
  3. Runs the agent in a tmux session
  4. Pushes branches and creates PRs
  5. Updates GitHub issue status and project board

GitHub Authentication

Orch requires GitHub authentication to sync with issues and create PRs. Three methods are supported:

Personal Access Token (Recommended for individuals)

# Set as environment variable export GH_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx" # Or configure in ~/.orch/config.yml gh: auth: token: "ghp_xxxxxxxxxxxxxxxxxxxx"

GitHub App (Recommended for organizations)

Better audit trails and scoped permissions for team automation:

github: token_mode: github_app app_id: "123456" private_key_path: "/path/to/app-private-key.pem"

The orchestrator automatically generates JWTs and refreshes installation tokens before expiry.

gh CLI (Default fallback)

The simplest setup — just authenticate once and everything works:

gh auth login

Orch calls gh auth token automatically when GH_TOKEN/GITHUB_TOKEN are not set. This fallback is enabled by default (gh.allow_gh_fallback: true).

To disable it (enforce explicit token configuration):

# ~/.orch/config.yml gh: allow_gh_fallback: false

See Configuration for details and run orch auth check to verify your setup.

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) export GH_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx"

Option B — launchd EnvironmentVariables in the plist:

<key>EnvironmentVariables</key> <dict> <key>GH_TOKEN</key> <string>ghp_xxxxxxxxxxxxxxxxxxxx</string> </dict>

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_TOKEN into 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

orch serve # Run the orchestrator service (foreground) orch service start # Start background service orch service stop # Stop background service orch service restart # Restart service orch service status # Check service status

Task Management

orch task list # List all tasks orch task list --status new # Filter by status orch task get <id> # Get task details orch task add "Title" # Create internal task orch task add "Title" --labels "bug,urgent" # Create GitHub issue orch task route <id> # Manually route a task to an agent orch task run <id> # Manually run a task orch task run # Run next available routed task orch task retry <id> # Reset task to new for re-routing orch task unblock <id> # Unblock a blocked task orch task unblock all # Unblock all blocked/needs_review tasks orch task publish <id> # Promote internal task to GitHub issue orch task attach <id> # Attach to running tmux session orch task live # List active agent sessions orch task kill <id> # Kill a running agent session orch task cost <id> # Show token cost breakdown orch task close <id> # Manually mark a task as done orch task close <id> --note "msg" # Mark done with a comment

Project Management

orch project list # List all registered projects orch project add # Register current directory as a project orch project add /path/to/dir # Register a specific project path orch project remove /path # Unregister a project

GitHub Projects V2 Board

orch board list # List accessible GitHub Projects V2 boards orch board link <id> # Link current repo to a board by ID orch board sync # Re-discover field IDs and update config orch board info # Show current board config

Job Management (Scheduled Tasks)

orch job list # List scheduled jobs orch job add "0 9 * * *" "Morning review" # Daily at 9am orch job add "*/30 * * * *" "Check CI" --type bash --command "scripts/ci-check.sh" orch job remove <id> # Remove a job orch job enable <id> # Enable a job orch job disable <id> # Disable a job orch job tick # Run one scheduler tick (for testing)

Utility Commands

orch init # Initialize orch for current project orch init --repo owner/repo # Initialize with specific repo orch agents # List installed agent CLIs orch metrics # Show task metrics summary (24h) orch stream # Stream ALL running agent sessions orch stream <task_id> # Stream a single task orch log # Show last 50 log lines orch log 100 # Show last N lines orch log watch # Tail logs live orch version # Show version orch config <key> # Read config value (e.g., orch config gh.repo) orch completions <shell> # Generate shell completions (bash, zsh, fish)

Control Session (Chat)

orch chat # Interactive REPL orch chat "what's running?" # Single message mode orch chat --session ops # Use a named session profile orch chat history # Show recent messages orch chat history --search "bean" # Search past conversations

In the REPL, use /model to switch models:

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> /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" (default) or "round_robin" agent: "claude" # which LLM performs routing model: "haiku" # fast/cheap model for classification timeout_seconds: 60 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 agents: claude: allowed_tools: [...] # Claude Code tool allowlist opencode: permission: { ... } # OpenCode permission config models: [...] # Available models git: name: "orch[bot]" email: "orch@orch.bot"

Project config (.orch.yml)

Place in your project root. Values here override global defaults.

# 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: [review] 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
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.rs # 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) ├── response.rs # Response parsing, weight signals ├── response_handler.rs # Success path: commit, push, PR, budget ├── 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

git clone https://github.com/gabrielkoerich/orch.git cd orch cargo build --release

Running tests

cargo nextest run # preferred (matches CI) cargo test # fallback if nextest is not installed

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

License

MIT