Agents
Once routed, agents run in full agentic mode with tool access:
- Claude:
-p(non-interactive),--permission-mode bypassPermissions(autonomous) oracceptEdits(supervised),--output-format json, system prompt via--append-system-prompt - Codex:
execsubcommand with--sandbox workspace-write -c 'approval_policy="never"'(autonomous) or--dangerously-bypass-approvals-and-sandbox(full access);-c 'sandbox_workspace_write.network_access=true'; system+agent prompt combined - OpenCode:
opencode runwith--dangerously-skip-permissionsand combined prompt - Grok:
grok --output-format streaming-messages-json,--permission-mode bypassPermissions(autonomous) oracceptEdits(supervised), system prompt via--system-prompt-override, task prompt via--prompt-file. Task runs use--sandbox offbecause the workspace profile cannot write a worktree git dir that lives outside the cwd. Deny rules still blockrmandgit push. - Kimi / MiniMax: spawned via their CLIs with the prompt as stdin; combined system+task prompt
Agents execute inside an isolated git worktree created for the task (not your main repo), so they can read project files, edit code, and run commands.
tmux Runner
Agent sessions run inside tmux sessions. Orch spawns the agent CLI as the tmux session shell, so tmux provides the PTY. There is no external PTY process or portable_pty crate. Prompt files are written to per-attempt directories for auditability.
Agent Output
The agent writes a JSON file to ~/.orch/state/{repo}/tasks/{id}/attempts/{n}/output.json. Task metadata (branch, worktree, agent, model, attempts, memory, etc.) is stored in the unified SQLite database at ~/.orch/orch.db. The expected agent output format:
{
"status": "done|in_progress|blocked|needs_review",
"summary": "what was done",
"reason": "why blocked/needs_review",
"accomplished": ["list of completed items"],
"remaining": ["list of remaining items"],
"blockers": ["list of blockers"],
"files_changed": ["list of modified files"],
"needs_help": false,
"delegations": [{"title": "...", "body": "...", "labels": [], "suggested_agent": "codex"}]
}PATH Configuration
When orch runs as a service (e.g. via brew services), agents start with a minimal PATH that may not include tools like bun, anchor, cargo, or solana. There are two ways to fix this:
Option 1: Create ~/.path (recommended)
Create a ~/.path file that exports your development tool paths:
# ~/.path
export PATH="/opt/homebrew/bin:$PATH"
export PATH="$HOME/.bun/bin:$PATH"
export PATH="$HOME/.cargo/bin:$PATH"
export PATH="$HOME/.local/bin:$PATH"Orch sources this file before launching agents, so any tool on your PATH will be available to agents when the runner is configured to inherit the shell environment.
Option 2: Default fallback
If ~/.path doesn't exist, orch automatically prepends these well-known directories (only when they exist on disk):
/opt/homebrew/bin/opt/homebrew/sbin/usr/local/bin$HOME/.cargo/bin$HOME/.local/bin$HOME/.bun/bin
Safety Rules
Agents are constrained by rules in the system prompt and by runner-enforced tool allowlists/denylists:
- No
rm:--disallowedToolsblocksrm— agents must usetrash(macOS) ortrash-put(Linux) - No commits to main: agents must always work in feature branches
- GitHub issue linking: if a task has a linked issue, the agent receives the issue reference for branch naming and PR linking
- Cost-conscious sub-agents: agents are instructed to use cheap models for routine sub-agent work
OS Sandbox
With workflow.sandbox: os, task and review agents run inside Seatbelt on macOS or bubblewrap on Linux, through the sandbox-jail crate. A project sets workflow.sandbox: false in its .orch.yml to run its agents without it.
| The agent | Paths |
|---|---|
| May write | Its worktree. In the git dir, the objects, the task's branch, remote refs and the task's own worktree dir. The temp dirs. The home's top-level dirs but .config, .claude, .ssh, .gnupg, bin, Library and .local, and inside those Library/Caches, Library/Logs, .local/share and .local/state |
| May not write | Everything else, among it every file at the top of the home and any new one there, ~/.claude.json, ~/.config, the agents' settings, every PATH dir inside the home such as ~/.cargo/bin, cargo's config.toml and gradle's init scripts, the git dir's hooks, config and other branches, the hooks and config of every other repository found up to four levels below a writable home dir when the policy is built, the worktree's .git file and .orch.yml, every main checkout but its .git, and ~/.orch but the task's own worktree (and orch.db for job tasks) |
| May not read | Credentials: ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/.docker/config.json, .netrc, .npmrc and the like. The login keychain stays readable and security stays runnable, since Claude reads its login through them. An agent can read any item whose access list trusts security, as it can today without the sandbox |
| May not connect to | A unix socket outside the worktree and $TMPDIR: tmux's, Docker's, the ssh-agent's. On macOS, any service but the basic ones and the keychain's, so open cannot start an app outside the sandbox |
| May not run (macOS) | launchctl and setuid binaries such as sudo |
The agent's environment drops TMUX, TMUX_PANE and SSH_AUTH_SOCK. The network stays open. Codex runs with its own sandbox off, since Seatbelt cannot nest. shipcheck cannot start its own sandbox inside this one either, so a sandboxed agent's prompt has it run the project's checks itself, and the push hook runs shipcheck outside.
When the sandbox cannot start, the task blocks with the reason and no agent runs. A path the agent needs and cannot write shows up as Operation not permitted in its output.
Worktrees
Orch creates worktrees before launching agents. Agents do NOT create worktrees themselves.
Path: ~/.orch/worktrees/<project>/<branch>/ — worktrees are always placed under ~/.orch/worktrees with a project/branch layout. Worktrees live in orch home directory (ORCH_HOME, default ~/.orch) and are safe to remove by the cleanup process once branches are merged.
Steps:
gh issue develop <issue> --base main --name <branch>— registers branch with GitHubgit branch <branch> main— creates branch from maingit worktree add <path> <branch>— creates worktree- Agent runs inside the worktree directory
After an agent finishes, orch handles all git operations: pushing the branch, creating the PR, and linking it to the issue. Agents only commit — they do not push or create PRs. The runner injects GH_TOKEN into the environment for read-only operations (e.g., checking CI status), but agents should not call GitHub write APIs directly. Attribution footers (for example: Created by claude[bot] via Orch) are added to issue and PR comments so it's clear which agent produced the content.
Context Enrichment
Every agent receives a rich context built from multiple sources:
| Context | Source | When |
|---|---|---|
| System prompt | prompts/agent_system.md | Always |
| Task details | SQLite store (~/.orch/orch.db) | Always |
| Agent profile | Router-generated role, tools, and constraints | Always |
| Error history | SQLite store | On retries |
| Last error | Task store last_error field | On retries |
| GitHub issue comments | GitHub API | If issue linked |
| Prior run context | contexts/task-{id}.md | On retries |
| Tool call summaries | .orch/tools-{id}.json | On retries |
| Repo tree | git ls-files | Always |
| Project instructions | CLAUDE.md + AGENTS.md + README.md, a file read once when one links to the other | If files exist |
| Parent/sibling context | Parent task summary + accomplished | If child task |
| Git diff | Uncommitted changes | On retries |
Error Handling
When a task fails:
- Error is recorded in
last_errorandhistory - The failed agent or model gets a cooldown, and the task is re-routed (see Cooldowns)
- A structured comment is posted on the linked GitHub issue with an attribution footer (for example:
Created by claude[bot] via Orch) so it's clear which agent produced the comment - After
workflow.max_attempts(default 5) the task goes toblocked, and orch removes any forcedagent:*label so/retryroutes it freely
orch task retry <id> # reset a task to new (a done task is refused)
orch task unblock <id> # reset a blocked task to new
orch task unblock all # reset all blocked tasks to newCooldowns
A failed run puts the agent or the model in a cooldown, and the router skips it until the cooldown ends. Cooldowns are stored in SQLite and survive a restart.
| Failure | Cooldown |
|---|---|
| One-off model failure: empty or cut off output, an unparseable review, an opaque provider error | That model, 5 minutes, then 15 minutes |
| Model not found, not supported or region blocked | That model, 4 hours, growing to 7 days |
| Other model-unavailable error | That model, 5 minutes, growing to 4 hours |
| Billing cycle exhausted on a known model | That model, 4 hours, growing to 7 days |
| Generic agent failure | That agent, 5 minutes, growing to 4 hours |
| Out of credits | That agent, 1 hour, growing to 8 hours |
| Org-level disabled | That agent, 2 hours, growing to 8 hours |
| Billing cycle exhausted, model unknown | That agent, 24 hours, growing to 7 days |
| Rate limit with a "try again at" time | Until that time |
| Silence | That model for engine.silence_cooldown (1 hour, 4 hours after 5 silences in 24 hours), and the agent for 120 seconds |
| Review timeout | None, the task goes back to needs_review |
A success resets the agent's failure counts, so the next failure starts from the base again.
An agent is degraded, and skipped, when all its models are cooled or it has dispatch.degraded_rate_limit_threshold (3) rate-limit rows in the last dispatch.health_check_window_hours (6). Only rows of type rate count. Failed runs and timeouts keep their own cooldowns and do not count.
orch cooldown list # active cooldowns and degraded agents
orch cooldown clear <key> # clear one cooldown (claude or claude:sonnet) and that agent's rate-limit window
orch cooldown clear --all # clear every cooldown and every agent's rate-limit windowThe running service picks a clear up on its next tick. That includes the GitHub 5xx circuit breaker: a cleared cooldown:github:5xx closes it and empties its error window.
Codex Sandbox Notes
Codex runs under the exec subcommand. The sandbox flag depends on workflow.permissions.mode and workflow.permissions.sandbox:
| Mode | Sandbox | Flags |
|---|---|---|
autonomous | (any) | --sandbox workspace-write -c 'approval_policy="never"' |
supervised | workspace-write | -c 'approval_policy="on-request"' --sandbox workspace-write |
autonomous | full-access | --dangerously-bypass-approvals-and-sandbox |
The runner also sets:
-c 'sandbox_workspace_write.network_access=true'(must precedeexec— placing it after silently leaves the sandbox network-blocked)-c 'shell_environment_policy.inherit=all'(sobun,cargo, etc. work)
--full-auto is not used — it was deprecated in Codex 0.128.0. Do not reintroduce it.