Sub-agents
Sub-agents are specialized LLM workers that the main agent can delegate mechanical tasks to. They run synchronously via subagent_invoke and return structured results. The main agent doesn’t need to handle the implementation details — it just calls the sub-agent by name.
The idea is to offload cheap, focused tasks (summarize this, find these files, groom this memory) to fast small models rather than burning context and cost on the main agent.
Built-in sub-agents
Section titled “Built-in sub-agents”Talon ships five built-in sub-agents:
| Name | Model | Purpose |
|---|---|---|
session-summarizer | claude-haiku-4-5 | Compress transcripts into structured summaries for session rotation |
memory-groomer | claude-haiku-4-5 | Consolidate and prune stale memory items |
memory-retriever | claude-haiku-4-5 | Find relevant memories via keyword + LLM reranking |
file-searcher | claude-haiku-4-5 | Search files with rg/grep/node cascade, ranked by relevance |
spark-coder | gpt-5.4-spark (OpenAI) | Fast single-shot code generation; returns file operations |
These run automatically as part of Talon’s internal operations (rolling context window, memory grooming) but are also available for direct invocation.
Invoking a sub-agent
Section titled “Invoking a sub-agent”The main agent calls subagent_invoke with a name and optional input object:
subagent_invoke({ name: "memory-retriever", input: { query: "user's preferred response format" }})The daemon handles model resolution, capability validation, and execution. The result is returned synchronously.
Required capability: subagent.invoke
The persona’s subagents list is an explicit allow-list:
personas: - name: assistant subagents: - session-summarizer - memory-retriever - memory-groomer - file-searcher capabilities: allow: - subagent.invokeCustom sub-agents
Section titled “Custom sub-agents”You can write your own sub-agents. They live in three locations, searched in this order:
./subagents/<name>/— project-level (highest precedence)<dataDir>/subagents/<name>/— data directory- Built-in agents — shipped with Talon
A sub-agent directory needs at minimum a manifest and an entry point:
subagents/my-agent/ subagent.yaml # manifest index.ts # entry point exporting a run() function prompts/ # optional prompt fragmentsManifest (subagent.yaml)
Section titled “Manifest (subagent.yaml)”name: my-agentdescription: Does a specific mechanical taskmodel: claude-haiku-4-5requiredCapabilities: - memory.access:threadThe requiredCapabilities list is validated against the invoking persona’s grants. If any required capability is missing, the sub-agent is rejected at invocation time.
requiresEnv — environment-gated loading
Section titled “requiresEnv — environment-gated loading”Sub-agents can declare environment variables they require. If any are missing, the loader silently skips the sub-agent at startup (info log, not a warning).
name: spark-coderrequiresEnv: - OPENAI_API_KEYThis lets you ship sub-agents that depend on optional credentials. Users without the env var simply don’t get the sub-agent loaded — no errors, no noise.
Entry point (index.ts)
Section titled “Entry point (index.ts)”import type { SubAgentInput, SubAgentResult } from '@talon/subagents/subagent-types';
export async function run(input: SubAgentInput): Promise<SubAgentResult> { // Your logic here return { output: "result" };}spark-coder
Section titled “spark-coder”Fast code generation using OpenAI’s GPT-5.4 Spark model. Designed for single-shot file generation inside an agentic loop — the parent agent describes what to generate, spark-coder produces structured file operations, and the parent handles I/O.
Requires: OPENAI_API_KEY in the environment.
Input:
| Field | Type | Required | Description |
|---|---|---|---|
task | string | Yes | What to generate |
contextFiles | [{path, content}] | — | Existing files for context |
constraints | string | — | Style/dependency constraints |
Output: { files: [{path, content, action}], explanation }
actionis"create"or"replace"- Paths are always relative — absolute paths and
..traversal are rejected by schema
Example:
subagent_invoke({ name: "spark-coder", input: { task: "Add a validateEmail utility function", contextFiles: [ { path: "src/utils/index.ts", content: "export function formatDate..." } ], constraints: "TypeScript strict mode, no external deps" }})Returns:
{ "files": [ { "path": "src/utils/validate.ts", "content": "export function validateEmail(email: string): boolean { ... }", "action": "create" } ], "explanation": "Created validateEmail in a dedicated utility file."}Multi-provider model resolution
Section titled “Multi-provider model resolution”Sub-agents declare a model name in their manifest. Talon resolves this against the available providers at runtime via the Vercel AI SDK.
Supported providers:
| Provider | Model prefix examples |
|---|---|
| Anthropic | claude-haiku-4-5, claude-sonnet-4-6 |
| OpenAI | gpt-4o, gpt-4o-mini |
gemini-2.0-flash | |
| Ollama | ollama/llama3.2, ollama/mistral |
To use a non-Anthropic model, set the relevant API key in your environment and reference the model name in the manifest. The daemon picks the right provider automatically.
name: fast-summarizermodel: gpt-4o-miniCLI testing
Section titled “CLI testing”Test any sub-agent without a running daemon:
npx talonctl run-subagent --name memory-retriever --input '{"query": "user preferences"}'This loads the sub-agent, resolves its model, and runs it in isolation. Useful for developing and debugging custom sub-agents before wiring them into a live persona.
# test with a JSON file for complex inputsnpx talonctl run-subagent --name my-agent --input-file ./test-input.json