This guide walks you through building a real orchestrator agent that calls multiple sub-agents to perform a comprehensive security review. By the end, you’ll have a working 3-agent pipeline deployed on orchagent.
What You’ll Build
You (or a schedule/webhook)
│
▼
security-review (orchestrator)
├── leak-finder (scans for hardcoded secrets)
└── vuln-scanner (checks for known vulnerabilities)
The orchestrator calls both sub-agents in parallel, combines their results, and returns a unified security report.
Prerequisites: orch login completed, an Anthropic or OpenAI API key in your vault (orch secrets set ANTHROPIC_API_KEY sk-ant-...).
Want to skip the setup? Use orch init my-orchestrator --template fan-out to scaffold a complete parallel orchestrator instantly. Templates are also available for pipeline (sequential) and map-reduce patterns. See Building an Orchestrator for details.
Step 1: Create the Leaf Agents
Leaf agents do focused, single tasks. Start with these two.
leak-finder (code runtime)
orch init leak-finder --type agent
cd leak-finder
orchagent.json:
{
"name" : "leak-finder" ,
"type" : "tool" ,
"description" : "Scans a GitHub repo URL for hardcoded secrets and API keys" ,
"supported_providers" : [ "anthropic" , "openai" ],
"runtime" : {
"command" : "python main.py"
}
}
main.py:
import json
import sys
import subprocess
def main ():
input_data = json.load(sys.stdin)
repo_url = input_data.get( "url" , "" )
# Clone and scan
subprocess.run([ "git" , "clone" , "--depth" , "1" , repo_url, "/tmp/repo" ],
capture_output = True , timeout = 30 )
# Simple pattern scan (real agents would use more sophisticated detection)
import re
findings = []
from pathlib import Path
for f in Path( "/tmp/repo" ).rglob( "*" ):
if f.is_file() and f.suffix in ( ".py" , ".js" , ".ts" , ".env" , ".yaml" , ".json" ):
try :
text = f.read_text( errors = "ignore" )
if re.search( r ' ( sk- [ a-zA-Z0-9 ] {20,} | AKIA [ A-Z0-9 ] {16} ) ' , text):
findings.append({ "file" : str (f.relative_to( "/tmp/repo" )), "type" : "api_key" })
except Exception :
pass
print (json.dumps({ "findings" : findings, "files_scanned" : len ( list (Path( "/tmp/repo" ).rglob( "*" )))}))
if __name__ == "__main__" :
main()
schema.json:
{
"input" : {
"type" : "object" ,
"properties" : {
"url" : { "type" : "string" , "description" : "GitHub repo URL to scan" }
},
"required" : [ "url" ]
},
"output" : {
"type" : "object" ,
"properties" : {
"findings" : { "type" : "array" },
"files_scanned" : { "type" : "integer" }
}
}
}
Agents are callable by default. You only need to set "callable": false to explicitly opt out (e.g., for always-on services).
vuln-scanner (direct LLM)
A simple prompt-based agent that uses an LLM to analyze code for vulnerabilities.
orch init vuln-scanner
cd vuln-scanner
orchagent.json:
{
"name" : "vuln-scanner" ,
"type" : "prompt" ,
"description" : "Analyzes code snippets for common security vulnerabilities" ,
"supported_providers" : [ "anthropic" , "openai" ]
}
prompt.md:
You are a security vulnerability scanner. Analyze the following code or repository description for common security vulnerabilities (OWASP Top 10, hardcoded credentials, SQL injection, XSS, etc.).
Return a JSON object with:
- "vulnerabilities": array of { "severity": "high"|"medium"|"low", "type": string, "description": string }
- "risk_score": number 0-1
Input: {{code}}
Step 2: Create the Orchestrator
orch init security-review --type tool
cd security-review
orchagent.json:
{
"name" : "security-review" ,
"type" : "tool" ,
"description" : "Comprehensive security review combining leak detection and vulnerability scanning" ,
"supported_providers" : [ "anthropic" , "openai" ],
"runtime" : {
"command" : "python main.py"
},
"timeout_seconds" : 120 ,
"manifest" : {
"manifest_version" : 1 ,
"dependencies" : [
{ "id" : "yourorg/leak-finder" , "version" : "v1" },
{ "id" : "yourorg/vuln-scanner" , "version" : "v1" }
],
"max_hops" : 2 ,
"timeout_ms" : 120000 ,
"per_call_downstream_cap" : 10
}
}
Replace yourorg with your actual org slug (shown in orch whoami).
main.py:
import asyncio
import json
import sys
from orchagent import AgentClient
async def main ():
input_data = json.load(sys.stdin)
repo_url = input_data.get( "url" , "" )
# Create client (auto-reads orchestration env vars)
client = AgentClient()
# Call both agents in parallel
leak_result, vuln_result = await asyncio.gather(
client.call( "yourorg/leak-finder@v1" , { "url" : repo_url}),
client.call( "yourorg/vuln-scanner@v1" , { "code" : f "Repository: { repo_url } " }),
)
# Combine results
report = {
"repo" : repo_url,
"leaked_secrets" : leak_result.get( "findings" , []),
"vulnerabilities" : vuln_result.get( "vulnerabilities" , []),
"risk_score" : vuln_result.get( "risk_score" , 0 ),
"summary" : (
f "Found { len (leak_result.get( 'findings' , [])) } leaked secrets "
f "and { len (vuln_result.get( 'vulnerabilities' , [])) } vulnerabilities"
),
}
print (json.dumps(report))
if __name__ == "__main__" :
asyncio.run(main())
requirements.txt:
Step 3: Run It
# Cloud execution (default — recommended for orchestrators)
orch run yourorg/security-review --data '{"url": "https://github.com/user/repo"}'
The orchestrator will:
Receive the input
Call leak-finder and vuln-scanner in parallel
Wait for both to complete
Return the combined security report
Step 4: Automate It
Cron schedule (daily scan)
orch schedule create yourorg/security-review \
--cron "0 9 * * 1-5" \
--timezone "America/New_York" \
--input '{"url": "https://github.com/yourorg/main-app"}'
Webhook trigger (on PR events)
orch schedule create yourorg/security-review --webhook
# Save the webhook URL → add to GitHub repo settings → Webhooks
Key Concepts Recap
Concept What It Means callableWhether other agents can call this agent (default: true) manifest.dependenciesDeclares which agents the orchestrator can call max_hopsMaximum depth of nested agent calls per_call_downstream_capBudget passed to each dependency call (limits child agent spending, not this agent’s own calls) orchagent-sdkPython/JS library that handles auth, call chain, and deadlines Parallel calls Use asyncio.gather() (Python) or Promise.all() (JS) for concurrent sub-agent calls
Troubleshooting
“DEPENDENCY_NOT_ALLOWED” error?
The agent you’re calling isn’t in your manifest.dependencies array
“Agent not callable” error?
The sub-agent has "callable": false set explicitly — remove it or set to true and republish
Timeout errors?
Your orchestrator’s timeout_seconds must be larger than the sum of all sequential sub-agent calls
Use parallel calls (asyncio.gather) when sub-agents are independent
SDK not found in sandbox?
Add orchagent-sdk to your requirements.txt (Python) or package.json (JS)
Next Steps
Orchestration Reference Full orchestration API: skills, call patterns, rate limits
SDK Reference Complete Python and JavaScript SDK docs