orchestrating-agents · diff
v0.8.1 to v0.9.0
21 added, 508 removed. Audit A to A.
---
name: orchestrating-agents
- description: Orchestrates parallel API instances, delegated sub-tasks, and multi-agent workflows with streaming and tool-enabled delegation patterns. Routes by surface — native subagents in Cowork and Claude Code, httpx fan-out on claude.ai — and covers Gemini delegation via the Cloudflare AI Gateway on every surface. Use for parallel analysis, multi-perspective reviews, or complex task decomposition.
+ description: DEPRECATED, renamed to orchestrating-chat-agents. Kept so existing imports of its scripts keep working; every module here loads the same module from orchestrating-chat-agents. Use orchestrating-chat-agents for parallel Claude calls over the API from claude.ai, and dispatching-subagents for fan-out in Claude Code.
metadata:
- version: 0.8.1
+ version: 0.9.0
---
- ## SURFACE ROUTING — read first
-
- Fan-out has three possible engines. Which exist depends on where you are running.
- **Pick the engine before writing any orchestration code.**
-
- | Engine | claude.ai | Cowork | Claude Code / CCotw |
- |---|:---:|:---:|:---:|
- | Native subagents (`Agent` / `Task` / `Workflow`) | ✗ | ✓ | ✓ |
- | Gemini via CF AI Gateway (`invoking-gemini`) | ✓ | ✓ | ✓ |
- | This skill's httpx fan-out (raw Anthropic API) | ✓ | last resort | last resort |
-
- **Primary discriminator — check the tool list, not the filesystem.** If an `Agent`,
- `Task`, or `Workflow` tool is callable, native subagents exist. That single fact
- decides the row. Everything below is elaboration.
-
- ### If native subagents exist (Cowork, Claude Code, CCotw)
-
- **Use them. Do not hand-roll from this skill.** The managed runtime gives
- 16-concurrent / 1000-agent ceilings, an approval gate, adversarial cross-review,
- and in-session resume — all of which this skill would reimplement worse. Route
- model and effort per **`agent-routing`** (calibrated on 300 measured Haiku calls);
- do not re-derive that here.
-
- Which native mechanism to use (Agent tool, Workflow, or headless `claude -p`
- children launched from one background command) is **`dispatching-subagents`**.
- In Claude Code the `claude` binary authenticates through the host, so a headless
- fan-out needs no API key either.
-
- Cowork adds one option Claude Code doesn't: subagents can be **declared** rather
- than spawned ad hoc, as `agents/*.md` in a plugin — frontmatter `name`,
- `description`, `model`, `effort`, `maxTurns`, `tools`, `disallowedTools`,
- `skills`, `memory`, `background`, `isolation: worktree`. They appear as
- `plugin-name:agent-name`. Note `hooks`, `mcpServers`, and `permissionMode` are
- refused in plugin agents for security, so a declared agent inherits the session's
- MCP connections and cannot bring its own.
-
- Reach back into this skill on those surfaces only for what the runtime lacks:
- stall detection, or a long-lived `ConversationThread`. **Inter-agent messaging is
- NOT on that list** — the runtime ships `SendMessage` and `ListAgents`, and
- `AgentPool` reimplements them worse.
-
- #### Native inter-agent messaging — `SendMessage` / `ListAgents`
-
- `ListAgents` discovers reachable agents; `SendMessage` delivers plain text to one
- by name or id. Both reach subagents, agent-team teammates, and independent
- sessions. Official docs: `code.claude.com/docs/en/cross-session-messaging`
- (shipped v2.1.224, macOS and Linux).
-
- Four measured behaviors the docs do not state. Each cost a round trip to find;
- full method and verbatim receipts in `oaustegard/experiments` →
- `subagent-messaging/RESULTS.md`.
-
- - **NEVER reply using the incoming envelope's `from` attribute.** For subagents
- that value is the agent *type* (`general-purpose`), not an address, and the
- send fails with `No agent named 'general-purpose' is reachable`. Two
- same-type peers emit identical `from` values, so it cannot distinguish
- senders even in principle. Both the `SendMessage` description and the harness
- footer on every delivered message instruct otherwise. **Capture the agentId
- from the spawn result and address that.**
- - **Subagents have no `ListAgents`.** `ToolSearch("select:ListAgents")` returns
- `No matching deferred tools found` — absent, not unloaded. A subagent reaches
- `"main"` and any address handed to it in its prompt, and nothing else. **The
- topology is a star through the main conversation, not a mesh: hand every peer
- its siblings' ids at spawn, or they cannot coordinate.**
- - **Delivery queues and never interrupts.** The receiver reads between tool
- calls, so a peer inside a long `Bash` call is unreachable until it surfaces.
- - **A send to a completed agent resumes it with full context, and the agent
- cannot tell.** Asked directly, a resumed agent reports no gap or restart
- marker. Instructions shaped as "if you were resumed, do X" never fire —
- **state the resume in the message.** Each resume replays the transcript:
- ~40k tokens for a small agent, and a measured eight-round chain ran
- 199k → 324k. **Batch questions into one send.**
-
- Contested: `anthropics/claude-code#48160` and `ruvnet/ruflo#2028` report that
- subagents can receive but not originate `SendMessage`. A CCotw subagent
- originated three sends successfully on 2026-08-12 with no
- `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` set. **Verify origination in your own
- environment before designing around either claim.**
-
- ### If native subagents do NOT exist (claude.ai chat and project sessions)
-
- Two engines, and **Gemini is the default** — see `subagent-delegation-protocol`
- in ops. Use this skill's httpx fan-out when you specifically want Claude-family
- output, multi-turn threads with cached history, or inter-agent messaging.
-
- ### Gemini via Cloudflare — available on every surface
-
- Even where native subagents exist, Gemini is the right call for
- mechanical-but-large work (extractions, ports, boilerplate, schema transforms)
- and for a genuinely independent second opinion in a judge panel — a different
- model family fails differently, which is the whole point of a panel.
-
- Call mechanics live in **`invoking-gemini`**; do not duplicate them here. Three
- things that bite:
-
- - Pass the **explicit model string** `gemini-3.6-flash`. The `flash` alias still
- resolves to 3.5 until that plugin's model table regenerates.
- - `thinking_level` is a string in `{minimal, low, medium, high}`, default
- `medium`. Set `minimal` for mechanical generation or the model silently spends
- its output budget reasoning — symptom is an empty or truncated response.
- - Credentials come from the CF AI Gateway config, BYOK. Requests route through
- the gateway rather than Google directly.
-
- ### Non-negotiable on all surfaces
-
- **Review is not delegable.** Diff security- and protocol-critical paths
- line-by-line against source, run syntax/lint checks, live-test whatever is
- network-testable. Delegated output ships only after your own review, regardless
- of which model produced it or which engine ran it.
-
- Cross-model review tools (`challenge`, `verify_patch`) keep their own model
- config, often deliberately a Claude. This routing does not silently repoint them.
-
- # Orchestrating Agents
-
- This skill enables programmatic API invocations for advanced workflows including parallel processing, task delegation, and multi-agent analysis using the Anthropic API.
-
- ## Quick Start
-
- ### Single Invocation
-
- ```python
- import sys
- sys.path.append('/mnt/skills/user/orchestrating-agents/scripts')
- from claude_client import invoke_claude
-
- response = invoke_claude(
- prompt="Analyze this code for security vulnerabilities: ...",
- model="claude-sonnet-5-5"
- )
- print(response)
- ```
-
- Default model is `claude-sonnet-5-5` ($2/$10 per MTok); `claude-opus-5-5` ($4/$20) for
- open-ended work and `claude-haiku-5-5` ($0.10/$0.50, prompts up to 100K tokens, 1M context)
- for cheap first-pass calls. These models reject non-default sampling parameters, so
- `temperature` / `top_p` / `top_k` are accepted by the wrappers but only sent to legacy
- (4.x / 3.x) model ids. They also think adaptively; the wrappers return the joined `text`
- blocks, never `content[0]`.
-
- ### Parallel Multi-Perspective Analysis
-
- ```python
- from claude_client import invoke_parallel
-
- prompts = [
- {
- "prompt": "Analyze from security perspective: ...",
- "system": "You are a security expert"
- },
- {
- "prompt": "Analyze from performance perspective: ...",
- "system": "You are a performance optimization expert"
- },
- {
- "prompt": "Analyze from maintainability perspective: ...",
- "system": "You are a software architecture expert"
- }
- ]
-
- results = invoke_parallel(prompts, model="claude-sonnet-5-5")
-
- for i, result in enumerate(results):
- print(f"\n=== Perspective {i+1} ===")
- print(result)
- ```
-
- ### Parallel with Shared Cached Context (Recommended)
-
- For parallel operations with shared base context, use caching to reduce costs by up to 90%:
-
- ```python
- from claude_client import invoke_parallel
-
- # Large context shared across all sub-agents (e.g., codebase, documentation)
- base_context = """
- <codebase>
- ...large codebase or documentation (1000+ tokens)...
- </codebase>
- """
-
- prompts = [
- {"prompt": "Find security vulnerabilities in the authentication module"},
- {"prompt": "Identify performance bottlenecks in the API layer"},
- {"prompt": "Suggest refactoring opportunities in the database layer"}
- ]
-
- # First sub-agent creates cache, subsequent ones reuse it
- results = invoke_parallel(
- prompts,
- shared_system=base_context,
- cache_shared_system=True # 90% cost reduction for cached content
- )
- ```
-
- ### Multi-Turn Conversation with Auto-Caching
-
- For sub-agents that need multiple rounds of conversation:
-
- ```python
- from claude_client import ConversationThread
-
- # Create a conversation thread (auto-caches history)
- agent = ConversationThread(
- system="You are a code refactoring expert with access to the codebase",
- cache_system=True
- )
-
- # Turn 1: Initial analysis
- response1 = agent.send("Analyze the UserAuth class for issues")
- print(response1)
-
- # Turn 2: Follow-up (reuses cached system + turn 1)
- response2 = agent.send("How would you refactor the login method?")
- print(response2)
-
- # Turn 3: Implementation (reuses all previous context)
- response3 = agent.send("Show me the refactored code")
- print(response3)
- ```
-
- ### Streaming Responses
-
- For real-time feedback from sub-agents:
-
- ```python
- from claude_client import invoke_claude_streaming
-
- def show_progress(chunk):
- print(chunk, end='', flush=True)
-
- response = invoke_claude_streaming(
- "Write a comprehensive security analysis...",
- callback=show_progress
- )
- ```
-
- ### Parallel Streaming
-
- Monitor multiple sub-agents simultaneously:
-
- ```python
- from claude_client import invoke_parallel_streaming
-
- def agent1_callback(chunk):
- print(f"[Security] {chunk}", end='', flush=True)
-
- def agent2_callback(chunk):
- print(f"[Performance] {chunk}", end='', flush=True)
-
- results = invoke_parallel_streaming(
- [
- {"prompt": "Security review: ..."},
- {"prompt": "Performance review: ..."}
- ],
- callbacks=[agent1_callback, agent2_callback]
- )
- ```
-
- ### Interruptible Operations
-
- Cancel long-running parallel operations:
-
- ```python
- from claude_client import invoke_parallel_interruptible, InterruptToken
- import threading
- import time
-
- token = InterruptToken()
-
- # Run in background
- def run_analysis():
- results = invoke_parallel_interruptible(
- prompts=[...],
- interrupt_token=token
- )
- return results
-
- thread = threading.Thread(target=run_analysis)
- thread.start()
-
- # Interrupt after 5 seconds
- time.sleep(5)
- token.interrupt()
- ```
-
- ## Core Functions
-
- | Function | Module | Purpose |
- |---|---|---|
- | `invoke_claude()` | core | Single synchronous invocation, full parameter control |
- | `invoke_parallel()` | core | Concurrent invocations, results in input order |
- | `invoke_claude_streaming()` | core | Single invocation, token-by-token callback |
- | `invoke_parallel_streaming()` | core | Concurrent invocations with per-agent stream callbacks |
- | `invoke_parallel_interruptible()` | core | Concurrent invocations cancellable mid-flight |
- | `ConversationThread` | core | Stateful multi-turn thread with cached history |
- | `StallDetector` | core | Flags agents idle beyond a timeout |
- | `TaskTracker` | task_state | Tracks task status across an orchestration run |
- | `invoke_with_retry()` | orchestration | Single invocation with backoff on transient errors |
- | `invoke_parallel_managed()` | orchestration | Concurrency-limited parallel run with retry, stall hooks, reconciliation |
-
- Full signatures, parameters, and worked examples for each:
- [references/function-reference.md](references/function-reference.md).
-
- ## Example Workflows
-
- See [references/workflows.md](references/workflows.md) for detailed examples including:
- - Multi-expert code review
- - Parallel document analysis
- - Recursive task delegation
- - Advanced Agent SDK delegation patterns
- - Prompt caching workflows
-
- ## Execute Mode (Default Sub-Agent Prompt)
-
- For autonomous sub-agents that should execute without asking questions:
-
- ```python
- from claude_client import invoke_claude, EXECUTE_MODE
-
- response = invoke_claude(
- prompt="Review auth.py for SQL injection vulnerabilities",
- system=f"You are a security expert.\n\n{EXECUTE_MODE}"
- )
- ```
-
- `EXECUTE_MODE` encodes these principles (adapted from OpenAI Codex):
- - Make assumptions instead of asking questions; state them briefly
- - Think ahead: what else might be needed?
- - Report failures with what you tried and what you'll do next
- - Summarize deliverables and how to validate them
-
- ## Agent Pool (Named Agents with Messaging)
-
- For workflows where multiple agents need to communicate:
-
- ```python
- from agent_pool import AgentPool
-
- pool = AgentPool(
- shared_system="You are reviewing the auth module of a web app.",
- max_depth=3, # prevent recursive spawn explosion
- max_agents=10,
- )
-
- # Spawn named agents with roles
- pool.spawn("security", system=f"Focus on vulnerabilities.\n\n{pool.EXECUTE_MODE}")
- pool.spawn("perf", system=f"Focus on performance.\n\n{pool.EXECUTE_MODE}")
-
- # Run turns (pending inter-agent messages auto-injected)
- sec_result = pool.run("security", "Review the login flow")
-
- # Agent-to-agent messaging
- pool.send("security", to="perf",
- content="Auth does N+1 queries in the session check loop",
- trigger_turn=True) # auto-runs perf with this context
-
- # Broadcast to all agents
- pool.broadcast("security", "Auth uses bcrypt cost=12, 200ms per hash")
-
- # Query pool state
- pool.agents() # ["security", "perf"]
- pool.agent_info("perf") # {name, depth, children, pending_messages, turns}
- ```
-
- ### Spawn Reservation (Atomic Agent Creation)
-
- For complex workflows where agent creation might fail:
-
- ```python
- from agent_pool import AgentPool
-
- pool = AgentPool(shared_system="Code review team")
-
- # Reservation pattern: name is reserved, rolled back on exception
- with pool.reserve("analyst", parent="lead") as res:
- res.configure(system="You analyze code complexity.", model="claude-opus-5-5")
- # If configure or any other work raises, the name is released
- # Agent "analyst" is now live
-
- # Depth limits prevent unbounded recursion
- pool.spawn("sub-analyst", parent="analyst") # depth=2, OK
- pool.spawn("sub-sub", parent="sub-analyst") # depth=3, raises ValueError
- ```
-
- ### When to Use AgentPool vs invoke_parallel
-
- | Pattern | Use When |
- |---------|----------|
- | `invoke_parallel()` | Independent tasks, no inter-agent communication needed |
- | `AgentPool` | Agents need to share findings, build on each other's work, or have parent/child relationships |
- | `invoke_parallel_managed()` | Independent tasks with retry, stall detection, concurrency limits |
-
-
-
- ## Setup
-
- **Prerequisites:**
-
- 1. Install anthropic library:
- ```bash
- uv pip install anthropic
- ```
-
- 2. Configure the API key **as a file the shell reads directly** — never as
- something a tool call returns.
-
- On claude.ai the project's files are mounted at `/mnt/project`, so the key can
- be sourced without ever entering context:
-
- ```bash
- set -a; . /mnt/project/ANTHROPIC.env 2>/dev/null; set +a
- ```
-
- ⚠️ **Do not use `project_read` to fetch a credential, on any surface.** Small
- docs are returned *inline*, so the key lands in the transcript — verified
- 2026-07-30: the documented "large text is written to a local file" branch does
- not fire even at 64 KB. In Cowork there is no `/mnt/project` mount at all and
- no safe read path, so the key must arrive by a route the shell can read
- (synced skill directory, or fetched by a script from the CF config store).
- Writing is safe in both directions — `project_write` with `local_path` keeps
- contents out of context — but reading is not.
-
- Get your API key: https://console.anthropic.com/settings/keys
-
- Installation check:
- ```bash
- python3 -c "import anthropic; print(f'✓ anthropic {anthropic.__version__}')"
- ```
-
- ## Error Handling
-
- The module provides comprehensive error handling:
-
- ```python
- from claude_client import invoke_claude, ClaudeInvocationError
-
- try:
- response = invoke_claude("Your prompt here")
- except ClaudeInvocationError as e:
- print(f"API Error: {e}")
- print(f"Status: {e.status_code}")
- print(f"Details: {e.details}")
- except ValueError as e:
- print(f"Configuration Error: {e}")
- ```
-
- Common errors:
- - **API key missing**: Add ANTHROPIC_API_KEY.txt to project knowledge (see Setup above)
- - **Rate limits**: Reduce max_workers or add delays
- - **Token limits**: Reduce prompt size or max_tokens
- - **Network errors**: Automatic retry with exponential backoff
-
-
- ## Prompt Caching
-
- For detailed caching workflows and best practices, see [references/workflows.md](references/workflows.md#prompt-caching-workflows).
-
- ## Performance Considerations
-
- **Token efficiency:**
- - Parallel calls use more tokens but save wall-clock time
- - Use prompt caching for shared context (90% cost reduction)
- - Use concise system prompts to reduce overhead
- - Consider token budgets when setting max_tokens
-
- **Rate limits:**
- - Anthropic API has per-minute rate limits
- - Default max_workers=5 is safe for most tiers
- - Adjust based on your API tier and rate limits
-
- **Cost management:**
- - Each invocation consumes API credits
- - Monitor usage in Anthropic Console
- - Use smaller models (`claude-haiku-5-5`) for simple tasks
- - Use prompt caching for repeated context (90% savings)
- - Cache lifetime: 5 minutes, refreshed on each use
-
- ## Best Practices
-
- 1. **Use parallel invocations for independent tasks only**
- - Don't parallelize sequential dependencies
- - Each parallel task should be self-contained
-
- 2. **Test with small batches first**
- - Verify prompts work before scaling
- - Check token usage and costs
-
- ## Token Efficiency
+ # Orchestrating Agents (deprecated)
- Loading this skill costs roughly 2k tokens. On surfaces with native subagents the
- routing table at the top is usually all you need — read it, spawn natively, and
- skip the rest of the file.
+ Renamed to [orchestrating-chat-agents](../orchestrating-chat-agents/SKILL.md) on 2026-10-11.
- ## See Also
+ ## Why
- **Routing companions — read these before choosing an engine:**
+ The old name sent requests to the wrong skill. Shown only skill names, Haiku, Sonnet and
+ Opus 5.5 routed 10 of 45 parallel-dispatch requests here, work that belongs to
+ `dispatching-subagents`. Of seven candidate names, `orchestrating-chat-agents` caught the
+ most of this skill's own requests (19/21 against 15/21) without drawing more of the
+ others' (`oaustegard/experiments` subagent-skill-choice). The content is the same: API
+ fan-out from surfaces with no native subagents, and Gemini delegation.
- - `agent-routing` skill — model + effort selection for **native** subagents
- (Haiku/Sonnet/Opus, cascades, verifier gates). Calibrated on measured data.
- Applies to Cowork and Claude Code; explicitly not to claude.ai.
- - `invoking-gemini` skill — call mechanics for the CF AI Gateway path, model
- table, and `thinking_level` semantics.
- - `subagent-delegation-protocol` (ops config) — why Gemini is the claude.ai
- default, the Sonnet fallback config, and the non-delegable-review rule.
+ ## Where things went
- **This skill's own internals:**
+ | you want | go to |
+ |---|---|
+ | parallel Claude calls over the API from claude.ai, `ConversationThread`, `AgentPool` | `orchestrating-chat-agents` |
+ | fan-out in Claude Code: Agent tool vs Workflow vs headless `claude -p` | `dispatching-subagents` |
+ | `SendMessage` / `ListAgents` between native subagents | `dispatching-subagents/references/native-messaging.md` |
+ | which model or effort a subagent gets | `agent-routing` |
- - [references/function-reference.md](references/function-reference.md) - Full signatures for every function this skill exposes
- - [references/api-reference.md](references/api-reference.md) - Anthropic API details: models, rate limits, caching
- - [references/workflows.md](references/workflows.md) - Worked orchestration examples
- - [Anthropic API Docs](https://docs.anthropic.com/claude/reference) - Official documentation
+ `scripts/` here holds shims, so `sys.path.insert(0, '/mnt/skills/user/orchestrating-agents/scripts')`
+ followed by `from claude_client import invoke_claude` still works. Point new code at
+ `/mnt/skills/user/orchestrating-chat-agents/scripts`.