Skip to main content
The orchagent SDK provides a simple interface for building orchestrator agents that call other agents. It handles authentication, call chain propagation, and error handling automatically. SDKs are available for both Python and JavaScript/TypeScript.

Installation

pip install orchagent-sdk
Requires Python 3.9+.

Basic Usage

The SDK provides AgentClient for calling other agents from within your agent. Most agents use stdin/stdout — create a client with no arguments and the SDK reads all context from environment variables:
import json, sys
from orchagent import AgentClient

input_data = json.loads(sys.stdin.read())
client = AgentClient()  # Reads ORCHAGENT_SERVICE_KEY + context from env

result = await client.call("joe/leak-finder@v1", {"url": input_data["repo_url"]})
print(json.dumps({"findings": result}))
The SDK automatically extracts context from environment variables (injected by the gateway):
  • Service key for authentication
  • Call chain for cycle detection
  • Deadline for timeout propagation
  • Remaining hops count

Local vs Server Mode

Both SDKs automatically detect whether to route calls locally or through the gateway based on the ORCHAGENT_LOCAL_EXECUTION environment variable.
ModeORCHAGENT_LOCAL_EXECUTIONBehavior
ServerNot set or falseCalls route through api.orchagent.io
LocaltrueCalls route to locally running agents
When you run an orchestrator with orch run --with-deps, the CLI automatically sets ORCHAGENT_LOCAL_EXECUTION=true so your agent calls dependencies locally.

Server Mode (Default)

In server mode, calls go through the gateway which handles routing, authentication, and sandbox management.

Local Mode

In local mode, calls go directly to locally running agent processes. The SDK spawns subprocesses using python3 for .py entrypoints and node for .js entrypoints.

API Reference

AgentClient

The main class for calling other agents.

Creating a Client

from orchagent import AgentClient

# From environment variables (recommended — reads ORCHAGENT_SERVICE_KEY etc.)
client = AgentClient()

# From an incoming HTTP request (advanced — for custom FastAPI servers)
# Propagates call chain, deadline, and billing context from headers
client = AgentClient.from_request(request)

# With explicit configuration
client = AgentClient(
    service_key="sk_agent_...",
    gateway_url="https://api.orchagent.io"
)

call()

Call another agent asynchronously.
result = await client.call(
    agent_id,      # Required: "org/name@version"
    input_data,    # Required: dict of input parameters
    endpoint=None, # Optional: specific endpoint (default: agent's default)
    timeout=None   # Optional: timeout in seconds (default: inherited from request)
)
Parameters:
ParameterTypeRequiredDescription
agent_idstrYesAgent identifier in format org/name@version
input_datadict / objectYesInput parameters for the agent
endpointstrNoSpecific endpoint to call (e.g., "deep-scan")
timeoutfloat / numberNoTimeout in seconds, overrides inherited deadline
Returns: dict / object - The agent’s response data Raises: DependencyCallError, TimeoutExceededError, CallChainCycleError

Examples

# Basic call
result = await client.call("joe/summarizer@v1", {"text": document})

# Call specific endpoint
result = await client.call("joe/scanner@v1", {"url": repo}, endpoint="deep-scan")

# Override timeout
result = await client.call("joe/analyzer@v1", {"data": data}, timeout=60.0)

Environment Variables

The SDK uses these environment variables:
VariableRequiredDescription
ORCHAGENT_SERVICE_KEYYesService key for agent authentication (sk_agent_...)
ORCHAGENT_GATEWAY_URLNoGateway URL (default: https://api.orchagent.io)
ORCHAGENT_LOCAL_EXECUTIONNoSet to true to route calls locally
ORCHAGENT_CALL_CHAINNoPropagated automatically; tracks call ancestry
ORCHAGENT_DEADLINENoPropagated automatically; deadline timestamp
ORCHAGENT_SKILLS_DIRNoPath to mounted skills directory (only set when skills are passed). Contains .md files and manifest.json.
When running on orchagent’s servers, ORCHAGENT_SERVICE_KEY is automatically injected into your agent’s environment.

Error Handling

Both SDKs provide specific exception/error types for different failure modes:
from orchagent import (
    AgentClient,
    DependencyCallError,
    TimeoutExceededError,
    CallChainCycleError
)

try:
    result = await client.call("joe/analyzer@v1", input_data)
except DependencyCallError as e:
    # The called agent returned an error
    print(f"Agent error: {e.status_code}")
    print(f"Response: {e.response_body}")
except TimeoutExceededError:
    # Request exceeded deadline
    print("Call timed out")
except CallChainCycleError:
    # Cycle detected (A -> B -> A)
    print("Circular dependency detected")

Exception Reference

ExceptionWhen RaisedCommon Causes
DependencyCallErrorAgent returned non-2xx statusAgent bug, invalid input, agent unavailable
TimeoutExceededErrorDeadline exceededSlow agent, network issues, timeout too short
CallChainCycleErrorCycle detected in call chainA calls B calls A (circular dependency)

Handling Partial Failures

When calling multiple agents, handle failures gracefully:
import asyncio

async def analyze_repo(client, repo_url):
    results = {}

    # Use asyncio.gather with return_exceptions=True
    outcomes = await asyncio.gather(
        client.call("joe/leak-finder@v1", {"url": repo_url}),
        client.call("joe/vuln-scanner@v1", {"url": repo_url}),
        return_exceptions=True
    )

    for name, outcome in zip(["secrets", "vulnerabilities"], outcomes):
        if isinstance(outcome, Exception):
            results[name] = {"error": str(outcome)}
        else:
            results[name] = outcome

    return results

Best Practices

When to Use the SDK

  • Building orchestrators - Agents that compose multiple leaf agents
  • Multi-step workflows - Chaining agent calls in sequence
  • Fan-out patterns - Calling multiple agents in parallel

Recommendations

  1. Use AgentClient() / new AgentClient() for stdin/stdout agents (the common case) — the SDK reads all context from environment variables injected by the gateway. Use from_request() / fromRequest() only for custom HTTP servers (FastAPI, Express, etc.) where you need to propagate call chain and deadline from incoming request headers.
  2. Handle all exception types - Don’t let DependencyCallError crash your agent
  3. Use parallel calls when possible - Fan-out to independent agents with asyncio.gather() (Python) or Promise.allSettled() (JavaScript)
  4. Pin dependency versions - Use org/agent@v1, not org/agent@latest
  5. Set reasonable timeouts - Account for all dependency calls in your timeout_ms
  6. Return partial results on failure - Don’t fail completely if one dependency fails
# Parallel calls with error handling
async def review(client, repo):
    secrets, vulns = await asyncio.gather(
        client.call("joe/leak-finder@v1", {"url": repo}),
        client.call("joe/vuln-scanner@v1", {"url": repo}),
        return_exceptions=True
    )

    return {
        "secrets": secrets if not isinstance(secrets, Exception) else None,
        "vulnerabilities": vulns if not isinstance(vulns, Exception) else None,
    }

Anti-patterns to Avoid

  • Don’t hardcode service keys — use AgentClient() (reads from env) or from_request(request) (reads from HTTP headers) to inherit context automatically
  • Don’t ignore the call chain — it prevents cycles and tracks lineage
  • Don’t hardcode gateway URLs — use the environment variable

Agent Storage

The SDK also includes a storage module for persistent shared state between agents. See the dedicated Agent Storage page for the full reference.
from orchagent import storage

storage.set("signals", "2026-03-05", {"pending": [], "done": []})
data = storage.get("signals", "2026-03-05")
storage.update("signals", "2026-03-05", lambda doc: {**doc, "status": "done"})

Agent Messages

Send messages from your agents to orch-hq. Use messages for briefings, alerts, reports — anything your agent wants to tell you. See the dedicated Agent Messages page for the full reference.
from orchagent import message

message.send("Daily Brief", "Here's what's happening today...")
message.send("Build Failed", "Error in main.py line 42", level="error")

Agent Tasks

Create and manage tasks from your agents. Tasks appear in orch-hq’s Tasks panel, grouped by urgency. See the dedicated Agent Tasks page for the full reference.
from orchagent import task

task.create("Fix login bug", due_date="2026-03-20", project="StockSure", priority="high")
overdue = task.list(status="open", overdue=True)
task.complete(task_id)

Next Steps

Orchestration

Learn how to build orchestrator agents that compose multiple agents together

Agent Storage

Persistent shared state for multi-agent coordination and checkpoints

Messages

Send messages and notifications from your agents

Tasks

Create and manage tasks from your agents