Skip to content

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

  1. Create a headless worktree (no tmux)
  2. Wait for the agent to finish
  3. Run a batch of tasks from a TOML file
  4. 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:

bash
$ owt new "Run security audit on all API endpoints" --headless
Task: 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:

bash
$ owt wait security --timeout 600
Waiting 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: COMPLETED

The --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

bash
#!/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:

bash
#!/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
done

owt 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:

bash
#!/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
done

You 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:

bash
$ owt list --json
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

bash
#!/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
fi

Example: GitHub Actions

yaml
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 tests

Headless vs. Interactive Mode

FeatureInteractive (default)Headless (--headless)
tmux sessionYesNo
Control PlaneYesNo
owt sendYesNo
owt waitOptionalPrimary interface
owt shipYesYes
CI/CD friendlyNoYes

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?