In the previous AgentTool chapter, we learned how to spawn "Sub-Agents" to handle complex tasks. However, those sub-agents were blocking. While the sub-agent was thinking, the main application was frozen, waiting for the result.
But what if you want to keep working while an AI helper does something else in the background?
Enter Teammates.
Teammates are independent AI agents that run alongside your main session. Unlike standard sub-agents, they don't block you. You can ask a teammate to "Research this library," and while they are reading documentation in the background, you can continue coding with the main agent.
Imagine you are fixing a bug. You need to know how a specific API works, but you don't want to lose your train of thought in the code.
React.useId works."useId works..."Without Teammates, you would have to sit and watch a loading spinner for 2 minutes.
We don't launch a whole new terminal window. Teammates run inside the same Node.js process as the main application. We use JavaScript's asynchronous nature to let them work "in parallel" with the user.
Every teammate needs a name (e.g., "Researcher", "QA") and a specific job. Most importantly, they need their own Context.
If the Teammate changes a variable in its memory, it shouldn't accidentally change a variable in the Main Agent's memory. We use something called AsyncLocalStorage to keep their brains separate.
Since teammates run in the background, we need a way to stop them. If you quit the app, or if the teammate gets stuck, we need a "Kill Switch." Each teammate has its own AbortController.
While users trigger teammates via chat, developers trigger them via code. Here is how we define a "spawn" configuration.
To spawn a teammate, we need to know who they are and what they should do.
const spawnConfig = {
name: "Researcher",
teamName: "CoreTeam",
// The mission we give them
prompt: "Read the docs for React 18 and summarize concurrency.",
// Visuals for the UI
color: "blue",
planModeRequired: false
};
When triggered, the system returns a success object containing the Agent ID.
{
success: true,
agentId: "Researcher@CoreTeam",
taskId: "task_12345",
// A handle to kill the agent if needed
abortController: AbortController {}
}
Spawning a teammate is a delicate operation. We have to create a new "virtual thread" inside our application.
Name@Team).Here is the visual flow:
The core logic is in utils/swarm/spawnInProcess.ts.
First, we generate a deterministic ID and a control switch (AbortController).
// utils/swarm/spawnInProcess.ts
export async function spawnInProcessTeammate(config, context) {
const { name, teamName } = config;
// 1. Create a unique ID (e.g., "Researcher@CoreTeam")
const agentId = formatAgentId(name, teamName);
// 2. Create a "Kill Switch" specific to this agent
// If the main app dies, this stays alive until explicitly killed
const abortController = createAbortController();
// ...
}
Explanation: We create abortController immediately. This allows us to cancel the teammate's specific task later without killing the whole application.
This is the most important part. We use createTeammateContext to isolate the agent.
// utils/swarm/spawnInProcess.ts
// 3. Create the isolated environment
const teammateContext = createTeammateContext({
agentId,
agentName: name,
parentSessionId: getSessionId(), // Link to parent for logging
abortController,
// ... other props
});
Explanation: This context object holds the agent's permissions and history. By creating a new one, we ensure the teammate doesn't see the Main Agent's private thoughts.
We need the Ink UI Framework to display the teammate's status. We do this by adding a "Task" to the global state.
// utils/swarm/spawnInProcess.ts
const taskState = {
// Standard task properties
type: 'in_process_teammate',
status: 'running',
identity: { agentId, color }, // Who is this?
prompt: config.prompt, // What are they doing?
// Connect the kill switch
abortController
};
// 4. Update the global store
registerTask(taskState, context.setAppState);
Explanation: registerTask puts this data into the Global Store. The UI listens to the store and immediately renders a new "Running" indicator in the sidebar.
When the job is done (or cancelled), we use the killInProcessTeammate function.
// utils/swarm/spawnInProcess.ts
export function killInProcessTeammate(taskId, setAppState) {
setAppState((prev) => {
const task = prev.tasks[taskId];
// 1. Trigger the kill switch
task.abortController?.abort();
// 2. Mark as killed in the UI
return {
...prev,
tasks: {
...prev.tasks,
[taskId]: { ...task, status: 'killed' }
}
};
});
}
Explanation: We find the task in the state, pull the trigger on the abortController, and update the status so the UI shows "Stopped."
Teammates represent the shift from "Chatbot" to "Organization."
claudeCode.
You have learned that Teammates are background workers that allow you to multitask. By using In-Process Spawning and Context Isolation, claudeCode can run multiple AI agents simultaneously in a single application. Each teammate has a name, a job, and a "Kill Switch" to keep them under control.
Now that we have built the entire systemβfrom State Management to Teammatesβlet's review what makes this entire project special compared to other tools.
Generated by Code IQ