Custom agents
The built-in agents do not do one job that your project needs. For example, you want each new bug report labeled, or each pull request that changes the public API to get a note about the docs.
A custom agent does that job. You write it with TanStack AI: a defineAgent with your own instructions, tools and MCP servers. The forge runs its code in a sandbox for each issue or pull request, calls the model for it, and gives it the forge's tools.
You need admin access to the repository.
1. Write the factory file
Save this file as house.ts:
import { defineFactory } from '@tanstack-source/ci'
import { forgeTools } from '@tanstack-source/ci/agent'
import { chat, defineAgent } from '@tanstack/ai'
export default defineFactory('house', {
agents: {
'label-bugs': {
agent: defineAgent({
name: 'label-bugs',
description: 'Adds the bug label to new issues that report a bug.',
run: (ctx) =>
chat({
adapter: ctx.forge!.model(),
systemPrompts: [
'You read one new issue of this repository.',
'If it reports a bug, add the label "bug" with the label tool.',
'Then record the verdict "bug" or "not-bug" with record_verdict.',
],
tools: forgeTools(ctx, ['label', 'record_verdict']),
messages: ctx.messages,
...ctx.forward,
}),
}),
on: ['issue.opened'],
trigger: { on: 'everyone' },
budget: { maxTokens: 50_000 },
},
},
})
Each agent has two parts:
agent: a TanStack AI agent. Itsrunis your code. It can use any tool, MCP client or package of TanStack AI.- The forge fields next to it:
on(the events that start it),trigger(who starts it) andbudget.
In run, ctx.forge connects your agent to the forge:
ctx.forge.model(): the model of the agent. The forge calls the model with the key and counts the tokens againstbudget. The sandbox never gets the key.forgeTools(ctx, [...]): the forge's tools, such aslabel,commentandrecord_verdict. The forge runs each call with the limits of the built-in agents.ctx.messages: the first message, with the issue or pull request and its comments.
2. Check the file on your machine
defineFactory checks the forge fields when the file runs. It throws an error that names the factory, the agent and the field. With Node.js 22.12 or later, run:
pnpm add -D @tanstack-source/ci @tanstack/ai
node --experimental-strip-types house.ts
If the file has a problem, the command prints the error and stops with exit code 1.
3. Save the file in the vault
- Open Agents, then Open factory settings, then go to Custom agents.
- Type
housein File name. - Upload
house.ts, or paste it in Contents. - Click Save file.
Or with the CLI:
src factory upload-agent house house.ts
src factory agents
The file is encrypted in the vault, for admins only. After you save it, no page shows its contents again. A file name has lowercase letters, digits and dashes, up to 40.
After you save the file, the forge bundles it: the file and the packages that it imports become one JavaScript file. It can take a few seconds. Then the Custom agents card shows label-bugs under Loaded from the vault, with its file and its events.
4. See it run
Custom agents run only while at least one built-in agent is on. If every built-in agent is off, turn one on first: see Turn on the agents.
Open a new issue. In its Factory panel, Runs shows a run of label-bugs, with its verdict, and the issue gets the bug label.
Done
Your agent runs with the same limits as the built-in agents, as the same bot, with no key and no token in its sandbox.
Next:
- Give your agent an MCP server or an API with a key: MCP servers and secrets.
- Let your agent push a fix or open a pull request: Agents that change code.
- Every field, tool and limit: Custom agents reference.
Fix an error in the file
If a file has an error, no custom agent runs. The built-in agents still run. Admins see the errors in these places:
- Agents, Open factory settings, Custom agents: a red alert lists each error, with its file name.
src factory agents: it prints the errors on stderr, after the list of files, and exits 0.- REST and MCP:
GET /repos/<owner>/<repo>/factory/agents/status, and the toolget_custom_agent_status.
To fix it:
- Read the error. It starts with the file, for example
factory/house.ts:. - Fix the file, and run it with Node.js as in step 2.
- Save the file again, with the same name.
The alert goes away, and the card lists the agents that loaded. The Factory panel of an issue does not show these errors: an error can quote the file, and only admins read it.
Keep the file in the repository
You can keep the file in git:
- In the factory settings, set Custom agents come from to .source/factory.ts on the default branch.
- Click Save rules.
- Commit the file as
.source/factory.tsto the default branch.
The forge reads this file from the tip of the default branch only. A pull request cannot change the agents that run on it. With this source, the files in the vault do not run. The Custom agents card shows the agents that loaded from .source/factory.ts, or its errors.
This file can also import the other files and the packages of your repository. The forge bundles it in a checkout of the default branch, and installs the packages from your lockfile first. See The bundle of the repository file.
Give it the tools of an MCP server
A custom agent can also use a connected MCP server, such as Linear. These tools are not in tools. The connection picks the agent:
- Open the repository's MCP tab.
- On the card of the connection, under Agents, select the agent by its name, for example
label-bugs. - Turn on the tools that it needs, then click Save agents and tools.
The agent sees the tools as <connection>_<tool>, for example linear_list_issues. Say in the prompt when to use them. See Give your factory an MCP server.
With the CLI, the id of a custom agent is custom:<name>:
src mcp tools linear --agent triage --agent custom:label-bugs
--agent replaces the agents of the connection, so name each agent that must keep it.