This tutorial shows how to use Open Orchestrator in headless mode -- without tmux or the Control Plane -- for CI/CD pipelines, scripts, and batch automation.
What You'll Do
- Create a headless worktree (no tmux)
- Wait for the agent to finish
- Run a batch of tasks from a TOML file
- Parse JSON output for CI integration
Step 1: Create a Headless Worktree
The --headless flag creates a worktree without a tmux session. The AI agent runs as a background process:
$ owt new "Run security audit on all API endpoints" --headlessTask: Run security audit on all API endpoints
Branch: run-security-audit
Accept? [Y/n/edit]: Y
Creating worktree...
Branch: run-security-audit
Path: ../my-app-run-security-audit
Detecting project type...
Detected: node (npm)
Installing dependencies... Done.
Launching AI agent (headless)...
Tool: claude-code
Task: "Run security audit on all API endpoints"
Headless worktree created. Use 'owt wait security' to block until done.No tmux session is created. The agent runs directly in the worktree directory.
Step 2: Wait for Completion
Block your script until the agent finishes:
$ owt wait security --timeout 600Waiting for run-security-audit... ● WORKING (2m elapsed)
Waiting for run-security-audit... ● WORKING (4m elapsed)
Waiting for run-security-audit... ✓ COMPLETED (5m 23s)
Done. Agent finished with status: COMPLETEDThe --timeout flag sets the maximum wait time in seconds (default: 600). If the agent doesn't finish in time, owt wait exits with a non-zero status code.
Using in CI Scripts
#!/bin/bash
set -e
owt new "Run security audit" --headless --yes
owt wait security --timeout 600
# Check results
owt list --json | jq '.[] | select(.name | contains("security"))'Step 3: Scripting Multiple Tasks
To run several tasks in one CI job, drive owt new --headless per task and combine it with owt wait and owt ship. Each task gets its own headless worktree (no tmux), and the script ships only the ones that complete successfully.
Sequential Tasks
Process a list of tasks one at a time, shipping each as it completes:
#!/bin/bash
set -e
tasks=(
"Add input validation to user endpoints"
"Add rate limiting middleware"
"Write API documentation for v2 endpoints"
)
for task in "${tasks[@]}"; do
echo "Starting: $task"
owt new "$task" --headless --yes
# Resolve the branch for the worktree just created
branch=$(owt list --json | jq -r '.[0].name')
owt wait "$branch" --timeout 900
status=$(owt list --json | jq -r ".[] | select(.name==\"$branch\") | .status")
if [ "$status" = "COMPLETED" ]; then
echo "Shipping $branch"
owt ship "$branch"
else
echo "$branch finished with status: $status -- not shipping"
exit 1
fi
doneowt ship commits, merges, and cleans up the worktree once the agent has completed.
Parallel Tasks
To run tasks concurrently, create all the headless worktrees first, then wait on each one before shipping:
#!/bin/bash
set -e
tasks=(
"Add input validation to user endpoints"
"Add rate limiting middleware"
"Write API documentation for v2 endpoints"
)
branches=()
# Launch every task as a headless worktree
for task in "${tasks[@]}"; do
owt new "$task" --headless --yes
branches+=("$(owt list --json | jq -r '.[0].name')")
done
# Wait for each to finish, then ship the successful ones
for branch in "${branches[@]}"; do
owt wait "$branch" --timeout 900
status=$(owt list --json | jq -r ".[] | select(.name==\"$branch\") | .status")
if [ "$status" = "COMPLETED" ]; then
owt ship "$branch"
else
echo "$branch finished with status: $status"
fi
doneYou can also use owt queue to stage worktrees for shipping and owt sync to keep long-running worktrees up to date with the base branch during the run.
Step 4: JSON Output for CI Integration
Several commands support --json for machine-readable output:
$ owt list --json[
{
"name": "run-security-audit",
"branch": "run-security-audit",
"status": "COMPLETED",
"ai_tool": "claude",
"task": "Run security audit on all API endpoints",
"last_active": "2026-03-14T10:35:00Z"
}
]Example: CI Pipeline Script
#!/bin/bash
set -e
# Create and wait for the task
owt new "$TASK_DESCRIPTION" --headless --yes
BRANCH=$(owt list --json | jq -r '.[0].name')
owt wait "$BRANCH" --timeout 900
# Check status
STATUS=$(owt list --json | jq -r ".[] | select(.name==\"$BRANCH\") | .status")
if [ "$STATUS" = "COMPLETED" ]; then
echo "Agent completed successfully"
owt ship "$BRANCH"
else
echo "Agent finished with status: $STATUS"
exit 1
fiExample: GitHub Actions
jobs:
ai-task:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Open Orchestrator
run: pip install open-orchestrator
- name: Run AI task
run: |
owt new "Add missing unit tests" --headless --yes
owt wait tests --timeout 600
- name: Ship if successful
run: owt ship testsHeadless vs. Interactive Mode
| Feature | Interactive (default) | Headless (--headless) |
|---|---|---|
| tmux session | Yes | No |
| Control Plane | Yes | No |
owt send | Yes | No |
owt wait | Optional | Primary interface |
owt ship | Yes | Yes |
| CI/CD friendly | No | Yes |
Use interactive mode for development workflows where you want to monitor and interact with agents. Use headless mode for automation, CI/CD, and scripted workflows.
What's Next?
- Solo Feature Build -- Interactive single-agent walkthrough
- Multi-Agent Sprint -- Parallel agent orchestration
- Commands Reference -- Full CLI reference