Skip to main content
This guide walks you through building an orchestrator agent — an agent that calls other agents to complete complex workflows. By the end, you’ll have a working orchestrator that coordinates multiple leaf agents.
This is a hands-on tutorial. For reference documentation on orchestration concepts, see Orchestration. For SDK details, see SDK Reference.

Quick Start with Templates

The fastest way to scaffold an orchestrator is with orch init --template. Three orchestration patterns are available:
Each template generates a complete project with orchagent.json, main.py, schema.json, requirements.txt, and README.md. Update manifest.dependencies with your actual agents, edit the orchestration logic, and publish. All templates support JavaScript via --language javascript.
Templates are a great starting point. Read on to understand how orchestration works under the hood, or jump straight to Part 4: Publish and Run if you’ve already customized your template.

Prerequisites

  • orchagent CLI installed and authenticated (orch login)
  • At least one published agent to use as a dependency (or follow along to create both)
  • An LLM API key configured (Anthropic recommended for managed loop agents)

Choose Your Approach

orchagent supports two orchestration patterns. Choose based on how much control you need: Both approaches use the same dependency system, publishing flow, and security model.

Part 1: Build a Leaf Agent

Before building the orchestrator, you need at least one agent to call. If you already have published agents, skip to Part 2. Here’s a minimal tool agent that scans code for leaked secrets:

leak-finder/orchagent.json

Agents are callable by default (callable: true). You only need to set "callable": false to explicitly opt out (e.g., for always-on services like Discord bots).

leak-finder/main.py

Publish it:

Part 2: Build the Orchestrator

A managed loop orchestrator uses an LLM tool-use loop. The LLM reads your prompt, sees the available tools, and decides which dependencies to call and in what order. You don’t write code — just the prompt and tool definitions. Create a directory with three files:

security-review/orchagent.json

Key fields explained:
Strict mode is the default. Orchestrators with dependencies default to orchestration_mode: "strict" — bash is disabled and the agent must use its custom tools. To keep bash available, set "orchestration_mode": "flexible" in your manifest.
custom_tools is required for managed-loop orchestrators. If you declare manifest.dependencies but don’t add matching custom_tools, the LLM has no way to call your dependencies. It will waste all turns exploring the filesystem instead. Use orch scaffold orchestration to auto-generate the correct custom_tools from your dependencies.
The command field must use the exact format: python3 /home/user/helpers/orch_call.py org/agent@version. This helper script is pre-installed in every managed loop sandbox. It reads the tool input, calls the dependency through the gateway, and returns the result.

security-review/prompt.md

security-review/schema.json

Option B: Code Runtime

A code runtime orchestrator runs your code directly. You control the execution flow — which agents to call, in what order, and how to process results. Use this when you need deterministic logic, custom data transformation, or parallel fan-out. Code runtime orchestrators can be written in Python or JavaScript.

security-review/orchagent.json

security-review/main.py

security-review/requirements.txt

orchagent-sdk must be in your requirements.txt. It is installed automatically inside the sandbox at runtime, but the install takes approximately 55 seconds — factor this into your timeout budget (see Timeout Budgeting).

Part 3: Workspace Secrets

If your agent (or any agent in the chain) needs external API keys or credentials at runtime, use workspace secrets combined with the required_secrets field.

Adding Secrets

  1. Go to your orchagent DashboardSettingsSecrets
  2. Add each secret (e.g., EXTERNAL_API_KEY, DATABASE_URL)

Declaring Required Secrets

In your orchagent.json, list which secrets your agent needs:
At runtime, these secrets are injected as environment variables into your agent’s sandbox. Secrets not listed in required_secrets will not be available, even if they exist in your workspace.
Do not add ORCHAGENT_SERVICE_KEY to required_secrets. The gateway automatically injects a temporary service key for agents that have manifest dependencies. Adding your own workspace secret named ORCHAGENT_SERVICE_KEY will override the auto-injected key and break orchestration with confusing billing errors.

Part 4: Publish and Run

Publishing Order

Always publish bottom-up — leaf agents before orchestrators. The gateway validates that all declared dependencies exist at publish time. The easiest way is --all from the parent directory — it auto-detects the dependency graph and publishes in the correct order:
Manual alternative:
If you try to publish the orchestrator before its dependencies, you’ll get a “Dependency not found” error.

Running Your Orchestrator


Timeout Budgeting

Sandboxes need time to start up and install dependencies. Plan your timeouts accordingly: Rules of thumb:
  • Managed loop orchestrators: Set timeout_seconds to at least 300 (5 minutes). The LLM loop, sandbox setup, and dependency calls all share this budget.
  • Code runtime orchestrators: Set timeout_seconds to at least 180 (3 minutes) to account for SDK installation + dependency call overhead.
  • manifest.timeout_ms should match or exceed timeout_seconds × 1000.
  • Leaf agents with no SDK dependency are fast (~5s startup). Set their timeouts lower.
The platform adds a 120-second buffer to your timeout for sandbox lifecycle management. A timeout_seconds: 300 agent gets a sandbox that lives for 420 seconds. You don’t need to account for this buffer yourself.

Multi-Level Orchestration

Orchestrators can call other orchestrators, creating multi-level chains. Each level runs in its own isolated sandbox.
For multi-level chains:
  • The top-level agent’s max_hops must be at least equal to the deepest chain depth
  • Each level decrements the hop count by 1
  • Timeouts propagate down — ensure the top-level timeout is large enough for the entire chain
  • Publishing order is strictly bottom-up: deepest leaf agents first, then mid-level orchestrators, then the top-level agent

Troubleshooting

”Dependency not found” on publish

All dependencies must be published before the orchestrator. Publish leaf agents first.

Agent runs but dependency calls return empty results

Agents are callable by default. If the dependency has "callable": false set explicitly, remove it or set it to true. The gateway blocks agent-to-agent calls to non-callable agents.

”MISSING_BILLING_ORG” error

This usually means ORCHAGENT_SERVICE_KEY was overridden by a workspace secret. Remove ORCHAGENT_SERVICE_KEY from your required_secrets — the gateway injects it automatically.

Secrets are empty inside the sandbox

Your agent must declare required_secrets in orchagent.json. Secrets added to the dashboard are only injected into sandboxes that explicitly request them.

Timeout / “peer closed connection”

The SDK install (~55s) plus sandbox startup (~5s) consumes budget before your code runs. Increase timeout_seconds to give your agent more time. For orchestrators, 300s is a safe starting point.

Dependency returns error but no details

Wrap SDK calls in try/catch and log the error:

Complete File Checklist

Managed Loop Orchestrator

Code Runtime Orchestrator (Python)

Code Runtime Orchestrator (JavaScript)


Testing Your Orchestrator

Orchestrators are hard to test because they depend on live sub-agents. Mocked fixtures solve this — they run the full LLM agent loop but return deterministic mock responses for sub-agent calls instead of hitting the network.

Step 1: Create a mocked fixture

Create tests/fixture-mock-basic.json:
The mocks keys must match the custom tool name fields in your orchagent.json. Each value is the JSON response the LLM will see when it calls that tool.

Step 2: Run the tests

The output shows the full agent loop — which tools the LLM chose to call, the mock responses injected, and whether the final output matches your expectations:

What gets tested

Mocked tests exercise the full reasoning pipeline:
  1. The LLM reads your prompt and the user’s input
  2. It decides which tools to call (and in what order)
  3. Custom tools return your mock responses instead of calling real sub-agents
  4. The LLM processes the results and calls submit_result
  5. The final output is validated against expected_output or expected_contains
Built-in tools (bash, read_file, write_file, list_files) still execute normally — only custom tools listed in mocks are intercepted.

File structure with tests

You can mix mocked and non-mocked fixtures in the same tests/ directory. orch test automatically routes each fixture to the correct runner based on whether it has a mocks field.
Mocked tests are ideal for CI/CD — they verify the LLM’s reasoning without requiring deployed sub-agents. See the CI/CD Guide for GitHub Actions setup.

Next Steps

Orchestration Reference

Concepts, patterns, rate limits, and troubleshooting reference

SDK Reference

Complete API reference for the orchagent-sdk package

Manifest Format

All orchagent.json fields and validation rules

Agent Types

Understand execution engines and when to use each