{"id":50312500,"url":"https://github.com/5queezer/tanstack-ai-subagents","last_synced_at":"2026-05-28T22:01:52.335Z","repository":{"id":355247927,"uuid":"1227359384","full_name":"5queezer/tanstack-ai-subagents","owner":"5queezer","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-02T16:07:23.000Z","size":24,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-02T17:23:51.562Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/5queezer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-02T15:18:15.000Z","updated_at":"2026-05-02T16:07:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/5queezer/tanstack-ai-subagents","commit_stats":null,"previous_names":["5queezer/tanstack-ai-subagents"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/5queezer/tanstack-ai-subagents","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5queezer%2Ftanstack-ai-subagents","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5queezer%2Ftanstack-ai-subagents/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5queezer%2Ftanstack-ai-subagents/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5queezer%2Ftanstack-ai-subagents/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/5queezer","download_url":"https://codeload.github.com/5queezer/tanstack-ai-subagents/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5queezer%2Ftanstack-ai-subagents/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33627946,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-28T22:01:49.508Z","updated_at":"2026-05-28T22:01:52.323Z","avatar_url":"https://github.com/5queezer.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @5queezer/tanstack-ai-subagents\n\nReusable subagent routing and execution helpers for TanStack AI applications.\n\nUse it when one assistant needs to decide whether to answer directly, use tools, write a plan, or delegate bounded work to one or more specialist workers.\n\n![30s routing demo: deterministic routing to bounded worker fanout](demo/routing-in-action.svg)\n\n[Raw asciinema cast](demo/routing-in-action.cast)\n\n## Why\n\nTanStack AI gives you model and tool primitives. This package adds a small orchestration layer for applications that want focused worker fanout without giving up control over models, tools, validation, or UI.\n\nThe core opinion: **LLM-as-router is the wrong default for finite routing decisions.** When the route set is known, routing should be fast, deterministic, cheap, and testable.\n\nThis package supports three orchestration entry modes:\n\n1. **Deterministic routing** — call `routeSubagentRequest(...)` or `route_subagents` to classify intent without an LLM.\n2. **Deterministic routing plus execution** — call `route_subagents`, then `run_subagents` with the resulting routing note for auditable worker execution. This is the most advanced/auditable path when paired with `staged_dag` topology and a verifier.\n3. **Model-directed delegation** — expose `delegate_subagents` and let the model choose bounded workers through normal tool calling.\n\nWorker execution then uses one of three topologies: `single`, `parallel`, or `staged_dag`.\n\n```mermaid\nflowchart TD\n  A[User prompt] --\u003e|0 ms| B{Orchestration entry mode}\n\n  B --\u003e|µs, no model call| C[Deterministic routing only]\n  C --\u003e|µs| C1[routeSubagentRequest / route_subagents]\n  C1 --\u003e|µs| C2[Routing note: answer, use tools, plan, spawn, refuse]\n\n  B --\u003e|µs routing + worker runtime| D[Deterministic routing plus execution]\n  D --\u003e|µs| D1[route_subagents]\n  D1 --\u003e|worker runtime| D2[run_subagents with routingNote]\n\n  B --\u003e|1 model tool-decision round| E[Model-directed delegation]\n  E --\u003e|model latency| E1[delegate_subagents tool call]\n  E1 --\u003e|worker runtime| E2[Model supplies worker briefs]\n\n  D2 --\u003e|0 ms| F{Execution topology}\n  E2 --\u003e|0 ms| F\n\n  F --\u003e|~1 worker runtime| G[single]\n  F --\u003e|~max worker runtime| H[parallel]\n  F --\u003e|~sum of stage runtimes| I[staged_dag]\n\n  G --\u003e|0 ms aggregation| J[Worker results]\n  H --\u003e|0 ms aggregation| J\n  I --\u003e|0 ms aggregation| J\n\n  J --\u003e|optional verifier runtime| K[Optional verifier]\n  J --\u003e|optional recursive tool call| M[recursive_delegate_subagents]\n  M --\u003e|nested worker runtime, depth-limited| F\n  K --\u003e|0 ms| L[Application integrates findings]\n```\n\nUse deterministic routing for production paths with known intents. Use deterministic routing plus `staged_dag` execution and a verifier when you need the strongest control, auditability, and validation. Use model-directed delegation when open-ended context, provider-native tool calling, or conversational flexibility is more valuable than repeatability.\n\n## Features\n\n- Deterministic score-based routing with `routeSubagentRequest(...)`\n- TanStack AI tool factories for `route_subagents`, `run_subagents`, `delegate_subagents`, and `recursive_delegate_subagents`\n- Bounded worker validation with configurable `maxWorkers`, `maxConcurrency`, and `policy.maxToolsPerWorker`\n- Optional runtime tool selection for workers from application-provided registries, including MCP/OpenAPI-loaded tools\n- Research-aligned delegation contracts: worker authority, risk, verification criteria, and dependencies\n- Parallel and staged-DAG worker execution with topology metadata\n- Configurable dependency-failure handling: skip dependents, abort, or continue\n- Output validation for required markdown sections and simple required JSON fields\n- Worker retry policy plus aggregate cost/token/turn budget guards\n- Package-managed recursive delegation with nested run provenance and depth limits\n- Trace summaries for task/stage events\n- Optional verifier callbacks before integration\n- Repair-task planning helpers for failed verifier results\n- Run-history listing/formatting helpers for persisted subagent run records\n- Consumer-defined tool registries and worker profiles\n- Per-worker lifecycle callbacks\n- Background run handles with `startSubagents(...)`\n- Provider-agnostic model adapter injection\n\n## Installation\n\n```bash\nnpm install @5queezer/tanstack-ai-subagents @tanstack/ai zod\n```\n\n`@tanstack/ai` and `zod` are peer dependencies. This is not an official TanStack package.\n\nRequirements:\n\n- Node.js `\u003e=18`\n- ESM project or compatible bundler/runtime\n\n## Quick start\n\nThis example runs deterministic routing, then executes workers with a fake runner. Real applications usually pass TanStack AI `chat`, a model adapter, and concrete tools instead.\n\n```ts\nimport { routeSubagentRequest, runSubagents } from '@5queezer/tanstack-ai-subagents'\n\nconst routingNote = routeSubagentRequest('Review frontend and backend independently')\n\nconst result = await runSubagents({\n  originalPrompt: 'Review frontend and backend independently',\n  routingNote,\n  workers: [\n    worker('frontend', 'Review frontend code'),\n    worker('backend', 'Review backend code'),\n  ],\n}, {\n  tools: { repo_read: { name: 'repo_read' } },\n  runner: async (brief) =\u003e ({\n    name: brief.name,\n    status: 'completed',\n    output: `${brief.name}: no issues found`,\n  }),\n})\n\nconsole.log(result.action)   // 'spawn_multiple_specialists'\nconsole.log(result.topology) // 'parallel'\n\nfunction worker(name: string, objective: string) {\n  return {\n    name,\n    objective,\n    scope: 'read-only repository inspection',\n    nonGoals: 'Do not edit files',\n    toolNames: ['repo_read'],\n    expectedOutput: 'Concise findings with evidence',\n  }\n}\n```\n\nRunnable examples are in [`examples/`](examples/):\n\n```bash\nnpm run build\nnode examples/01-deterministic-routing.mjs\nnode examples/02-route-then-run.mjs\nnode examples/03-delegate-subagents-tool.mjs\nnode examples/04-staged-dag-with-verification.mjs\nnode examples/05-recursive-delegation.mjs\n```\n\n### Process-backed workers\n\nUse `createProcessWorkerRunner(...)` when workers should run in isolated OS processes instead of the in-process TanStack AI chat adapter. The runner sends `{ brief, input }` as JSON on stdin by default, captures stdout/stderr, converts non-zero exits to failed worker results, and streams chunks through `onWorkerUpdate`.\n\n```ts\nimport { createProcessWorkerRunner, runSubagents } from '@5queezer/tanstack-ai-subagents'\n\nconst runner = createProcessWorkerRunner({\n  command: 'node',\n  args: ['worker.js'],\n  timeoutMs: 30_000,\n})\n\nconst result = await runSubagents(input, {\n  tools,\n  runner,\n  onWorkerUpdate: (update, brief) =\u003e {\n    console.log(`[${brief.name}] ${update.stream}: ${update.chunk}`)\n  },\n})\n```\n\n## Usage\n\n### 1. Deterministic routing\n\n`routeSubagentRequest(...)` returns a structured routing note. The default router uses dependency-free intent scoring instead of an LLM call.\n\n```ts\nimport { routeSubagentRequest } from '@5queezer/tanstack-ai-subagents'\n\nconst note = routeSubagentRequest('Debug frontend and backend independently')\n\nconsole.log(note.chosenAction) // 'spawn_multiple_specialists'\nconsole.log(note.rationale)\n```\n\nCustomize the router when your app has domain-specific vocabulary:\n\n```ts\nimport { createSubagentRouter } from '@5queezer/tanstack-ai-subagents'\n\nconst route = createSubagentRouter({\n  intents: {\n    incident: ['incident', 'outage', 'sev1'],\n    security: ['oauth', 'permission', 'vulnerability'],\n  },\n  highRiskTerms: ['pci', 'production database'],\n  parallelTerms: ['ios', 'android'],\n  areaTerms: ['frontend', 'backend', 'mobile'],\n})\n\nconst note = route('Investigate sev1 across ios and android')\n```\n\n### 2. TanStack AI tools\n\nExpose deterministic routing and execution as tools:\n\n```ts\nimport { chat } from '@tanstack/ai'\nimport {\n  createRunSubagentsTool,\n  createSubagentRouterTool,\n} from '@5queezer/tanstack-ai-subagents'\n\nimport { getChatModel } from './ai-provider'\nimport { githubGet, githubSearch } from './tools'\n\nconst tools = {\n  github_search: githubSearch,\n  github_get: githubGet,\n}\n\nconst profiles = {\n  explore: {\n    toolNames: ['github_search', 'github_get'],\n    systemPrompt: 'Explore the assigned task and return concise findings with evidence.',\n  },\n}\n\nexport const serverTools = [\n  createSubagentRouterTool(),\n  createRunSubagentsTool({\n    chat,\n    getAdapter: getChatModel,\n    tools,\n    profiles,\n  }),\n]\n```\n\n### 3. Model-directed delegation\n\nIf you want the model to choose workers through normal tool calling, expose `delegate_subagents`. The package still validates worker count, tool access, profiles, dependencies, and delegation policy.\n\n```ts\nimport { createDelegateSubagentsTool } from '@5queezer/tanstack-ai-subagents'\n\nexport const serverTools = [\n  createDelegateSubagentsTool({\n    chat,\n    getAdapter: getChatModel,\n    tools,\n    profiles,\n    maxWorkers: 4,\n  }),\n]\n```\n\n### 4. Recursive delegation\n\nUse `recursive_delegate_subagents` when a worker is allowed to delegate nested bounded work. The package tracks nested run provenance and enforces `policy.maxRecursiveDepth`.\n\n```ts\nimport { createRecursiveDelegateSubagentsTool } from '@5queezer/tanstack-ai-subagents'\n\nconst recursiveDelegate = createRecursiveDelegateSubagentsTool({\n  chat,\n  getAdapter: getChatModel,\n  tools,\n  profiles,\n  policy: { maxRecursiveDepth: 2 },\n  recursiveContext: parentInput.recursiveContext,\n})\n```\n\nRecursive results are attached to the parent result as `childRuns`, with `runId`, `parentRunId`, `rootRunId`, and `depth` metadata.\n\n## Delegation contracts\n\nEach worker brief is a lightweight contract. The package validates contracts before any worker runs.\n\n```ts\n{\n  name: 'release-verifier',\n  objective: 'Check whether findings support release',\n  dependsOn: ['implementation', 'tests'],\n  scope: 'worker outputs and validation evidence',\n  nonGoals: 'Do not publish or mutate state',\n  toolNames: ['repo_read'],\n  authority: 'read_only',\n  risk: 'medium',\n  verificationCriteria: 'Release recommendation follows from worker evidence',\n  expectedOutput: 'Release recommendation with caveats',\n}\n```\n\nValidation includes:\n\n- `spawn_one_specialist` requires exactly one worker.\n- `spawn_multiple_specialists` requires two or more workers.\n- `maxConcurrency` limits how many ready workers run at once.\n- Worker names must be unique.\n- Workers can specify `toolNames`, use a `profile`, or rely on `toolSelector` when configured.\n- Requested or selected tools must exist in the configured tool registry.\n- Each worker may use at most `policy.maxToolsPerWorker` tools; default is `5`.\n- `dependsOn` entries must reference known workers.\n- Dependency cycles are rejected.\n- Dependency depth is capped by `policy.maxDepth`; default is `4`.\n- `external_side_effect` authority requires `policy: { riskTolerance: 'high' }`.\n- `policy.onWorkerFailure` controls dependency behavior: `skip_dependents` (default), `abort`, or `continue`.\n- `policy.maxRetries` retries transient worker failures; default is `1` attempt.\n- `policy.maxCost`, `policy.maxTokens`, and `policy.maxTurns` enforce aggregate usage budgets when worker results report `usage`.\n\nWorkers without dependencies run in parallel. Workers with `dependsOn` run as a staged DAG. Results include `topology: 'single' | 'parallel' | 'staged_dag'` plus a lightweight `trace` summary of stage/task events. Set `maxConcurrency` to cap how many workers in a parallel stage may run at once; by default each stage may run up to `maxWorkers` workers.\n\nFor maximum control and auditability, use deterministic routing plus `staged_dag` workers and a `verifier`. This path captures the routing rationale, enforces worker contracts, preserves dependency order, and records verification before your application integrates the findings.\n\nRecursive delegation is first-class when workers use `recursive_delegate_subagents`. The package records nested `childRuns`, assigns `runId` / `parentRunId` / `rootRunId`, tracks `depth`, and enforces `policy.maxRecursiveDepth`. Manual recursion is still possible if your application exposes ordinary `run_subagents` or `delegate_subagents` tools to workers, but those manual calls do not get package-managed recursive provenance unless they pass the inherited `recursiveContext`.\n\n## Output validation and verification\n\nWorkers can request lightweight output validation before their result is accepted:\n\n```ts\n{\n  name: 'release-verifier',\n  objective: 'Check release evidence',\n  scope: 'worker outputs',\n  nonGoals: 'Do not mutate state',\n  toolNames: ['repo_read'],\n  expectedOutput: 'Markdown report with evidence',\n  expectedSections: ['Summary', 'Evidence'],\n}\n```\n\nFor machine-readable outputs, set `jsonSchema: { required: ['fieldName'] }` to require valid JSON with the listed top-level fields. Failed validation turns that worker result into `status: 'failed'` with the validation error.\n\nUse `verifier` when delegated work must be checked before integration.\n\n```ts\nconst result = await runSubagents(input, {\n  tools,\n  policy: { requireVerification: true, maxDepth: 3 },\n  runner,\n  verifier: async (runResult) =\u003e ({\n    status: 'verified',\n    summary: `Checked ${runResult.workers.length} workers`,\n    checkedWorkers: runResult.workers.map((worker) =\u003e worker.name),\n  }),\n})\n\nconsole.log(result.verification?.status)\n```\n\nIf `policy.requireVerification` is true and no verifier is configured, the result includes `verification.status === 'needs_review'`.\n\nIf a verifier worker or verifier callback fails in your application flow, `planVerifierRepairTasks(...)` can turn the failure plus prior worker outputs into bounded follow-up repair tasks.\n\n## Tools and profiles\n\nThe package does not ship concrete worker tools. Applications provide a registry and workers reference tools by name:\n\n```ts\nconst tools = {\n  github_search: githubSearch,\n  github_get: githubGet,\n}\n```\n\nProfiles define reusable worker capabilities:\n\n```ts\nconst profiles = {\n  verify: {\n    toolNames: ['test_runner'],\n    systemPrompt: 'Verify the assigned task and report exact commands and evidence.',\n    model: 'provider/verification-model',\n  },\n}\n```\n\nA worker can use `profile: 'verify'` instead of listing `toolNames` directly.\n\nFor runtime-loaded registries, such as MCP servers generated from `openapi.json`, provide a `toolSelector`. The selector runs before validation for workers without `toolNames` or `profile`, receives the current runtime catalog, and must return a bounded subset of tool names:\n\n```ts\nconst result = await runSubagents(input, {\n  chat,\n  getAdapter,\n  tools: mcpTools,\n  policy: { maxToolsPerWorker: 5 },\n  toolSelector: async ({ worker, availableTools, maxTools }) =\u003e {\n    // Use deterministic matching, embeddings, or an LLM planner here.\n    // Always return names from availableTools and no more than maxTools.\n    return chooseRelevantTools(worker, availableTools).slice(0, maxTools)\n  },\n})\n```\n\nResolution order is explicit `worker.toolNames`, then `worker.profile`, then `toolSelector`. The orchestrator validates the final names against the registry and cap before workers run.\n\n## Background runs\n\n`startSubagents(...)` starts orchestration and returns a handle immediately:\n\n```ts\nimport { startSubagents } from '@5queezer/tanstack-ai-subagents'\n\nconst handle = startSubagents(input, options)\n\nconsole.log(handle.runId, handle.status) // running\nconst result = await handle.result\nconsole.log(handle.status) // completed or failed\n```\n\n## API\n\n```ts\ncreateSubagentRouter(config?)\ncreateSubagentRouterTool(options?)\ncreateRunSubagentsTool(options)\ncreateDelegateSubagentsTool(options)\ncreateRecursiveDelegateSubagentsTool(options)\nrouteSubagentRequest(prompt)\nrunSubagents(input, options)\nstartSubagents(input, options)\nvalidateRunSubagentsInput(input, options)\n```\n\nKey exported types:\n\n```ts\nSubagentAction\nSubagentRouter\nSubagentRouterConfig\nSubagentRoutingNote\nSubagentWorkerBrief\nSubagentWorkerResult\nRunSubagentsInput\nDelegateSubagentsToolInput\nRunSubagentsResult\nRunSubagentsOptions\nDelegationAuthority\nDelegationPolicy\nSubagentTopology\nSubagentVerificationResult\nSubagentRecursiveContext\nSubagentProfile\nSubagentRunHandle\nSubagentToolRegistry\nSubagentToolDescriptor\nSubagentToolSelector\n```\n\n## Development\n\n```bash\nnpm install\nnpm test\nnpm run build\nnpm run typecheck\nnpm pack --dry-run\n```\n\n`npm test` builds the TypeScript source and runs the Node test suite, including smoke tests for every `.mjs` file in `examples/`.\n\n## Design boundaries\n\nThis package owns:\n\n- routing notes\n- validation\n- bounded fanout\n- staged-DAG execution\n- partial failure handling\n- lifecycle callbacks\n- background run handles\n- profile resolution\n- runtime tool selection hooks\n- TanStack AI tool factories\n\nYour application owns:\n\n- model providers\n- concrete tools\n- profile definitions\n- runtime tool registry loading and selector strategy\n- durable trace storage and persistence\n- prompts and UI\n- final integration of worker findings\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F5queezer%2Ftanstack-ai-subagents","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F5queezer%2Ftanstack-ai-subagents","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F5queezer%2Ftanstack-ai-subagents/lists"}