orch supports custom agents, allowing you to use any CLI tool as an agent backend. This is useful for proprietary tools, self-hosted models, or specialized workflows.
Custom agents are external processes that:
- Accept a prompt as input
- Work on the task
- Exit when done (or wait for input)
orch manages the tmux session and monitors the agent's state.
orch run my-issue --agent custom --agent-cmd "my-agent run"# .orch/config.yaml
agent: custom
custom:
command: my-agent run
prompt_template: "{{issue}}"A custom agent is any CLI tool that can accept a prompt and work on it.
- Accept prompt as command-line argument or stdin
- Run in a terminal (tmux compatible)
- Exit with code 0 on success
- Exit with non-zero code on failure
#!/bin/bash
# my-agent.sh - Simple custom agent wrapper
PROMPT="$1"
# Your custom logic here
echo "Working on: $PROMPT"
# Call your actual agent/tool
my-internal-tool --prompt "$PROMPT"
# Exit with appropriate code
exit $?Usage:
custom:
command: /path/to/my-agent.sh#!/usr/bin/env python3
"""Custom agent wrapper for orch."""
import sys
import subprocess
def main():
if len(sys.argv) < 2:
print("Usage: my-agent <prompt>")
sys.exit(1)
prompt = sys.argv[1]
# Your custom agent logic
result = call_your_model(prompt)
# Apply changes, etc.
apply_result(result)
sys.exit(0)
if __name__ == "__main__":
main()Custom agents receive these environment variables from orch:
| Variable | Description |
|---|---|
ORCH_ISSUE_ID |
Issue ID |
ORCH_RUN_ID |
Run ID |
ORCH_RUN_PATH |
Path to run document |
ORCH_WORKTREE_PATH |
Git worktree path |
ORCH_BRANCH |
Git branch name |
#!/bin/bash
echo "Working in: $ORCH_WORKTREE_PATH"
echo "Issue: $ORCH_ISSUE_ID"
echo "Branch: $ORCH_BRANCH"Most agents accept the prompt as a command-line argument:
custom:
command: my-agent
# orch runs: my-agent "the prompt"For agents that read from stdin:
custom:
command: my-agent --stdin
prompt_via_stdin: true
# orch pipes prompt to stdinFor agents that read from a file:
custom:
command: my-agent --prompt-file ${PROMPT_FILE}
prompt_via_file: true
# orch writes prompt to PROMPT_FILE and sets environment variableorch monitors custom agents the same way as built-in agents, looking for:
Configure patterns that indicate success:
custom:
command: my-agent
completion_patterns:
- "Task completed successfully"
- "Done!"
- "PR created:"Configure patterns that indicate failure:
custom:
command: my-agent
error_patterns:
- "Error:"
- "Failed:"
- "Exception:"Configure patterns that indicate the agent needs input:
custom:
command: my-agent
blocked_patterns:
- "Waiting for input"
- "Please provide:"
- "?"custom:
command: ollama run codellama
prompt_template: "{{issue}}"custom:
command: ./scripts/api-agent.sh
env:
API_KEY: ${MY_API_KEY}
API_URL: https://my-api.example.comcustom:
command: ./scripts/multi-tool-agent.sh
prompt_template: |
Task: {{issue_title}}
{{issue}}
Available tools: git, make, dockercustom:
command: terraform-agent
prompt_template: |
Infrastructure task: {{issue_title}}
{{issue}}
Use Terraform to implement this infrastructure change.Define different custom agents for different purposes:
# In presets
presets:
terraform:
agent: custom
agent_cmd: terraform-agent
kubernetes:
agent: custom
agent_cmd: k8s-agent
local-llm:
agent: custom
agent_cmd: ollama run codellamaUse with:
orch run --preset terraform infra-issue
orch run --preset local-llm code-issueRun setup before the agent:
custom:
setup_script: ./scripts/agent-setup.sh
command: my-agentRun cleanup after the agent:
custom:
command: my-agent
cleanup_script: ./scripts/agent-cleanup.shCheck:
- Command path is correct
- Script has execute permissions
- Dependencies are available
Debug:
orch run --verbose my-issue --agent custom --agent-cmd "my-agent"If orch can't detect your agent's state:
- Configure explicit completion/error patterns
- Ensure agent outputs recognizable messages
- Check daemon logs:
tail -f .orch/daemon.log
Verify environment variables are passed:
# Add to your agent script
env | grep ORCH- Clear output: Make your agent output clear status messages
- Exit codes: Use proper exit codes (0 = success)
- Logging: Log to stderr for debugging, stdout for user-visible output
- Graceful shutdown: Handle SIGTERM for clean stopping
- Progress indicators: Output periodic progress to avoid "stalled" detection