In the previous chapter, Distributed Permission System, we learned how to make our swarm safe by requiring permission for dangerous actions.
But safety isn't just about stopping bad commands. It's also about memory.
Imagine you are playing a long video game. You've spent hours building your character. Suddenly, the power goes out. If you didn't click "Save Game," you lose everything.
Team State Persistence is the "Save Game" feature for your AI Swarm.
When you run a Swarm application, you might have:
tmux windows or background threads).The Use Case: You are running a complex coding task. Your computer freezes and you have to force-quit the terminal.
This layer acts as the HR Database. It records who is hired, where they sit (Pane ID), and what they are doing.
To make the swarm "crash-proof," we rely on simple files stored on your hard drive.
config.json)
Every team has a folder on your disk. Inside that folder is a config.json file. This is the single source of truth. It contains:
This is a fancy term for "loading the save file." When the application starts, or when you switch context, the code reads this JSON file to rebuild the Javascript objects in memory.
If an agent is fired (removed) or the session ends, we need to clean up. This involves deleting the JSON file andβcruciallyβkilling the terminal window associated with that agent so it doesn't clutter your screen.
As a developer, you interact with this system primarily through helper functions in teamHelpers.ts.
Let's say you want to know if a specific agent is part of the current team.
import { readTeamFile } from './teamHelpers.js';
// 1. Load the data from disk
const teamData = readTeamFile("MyDevTeam");
if (teamData) {
// 2. Access the members list
console.log(`There are ${teamData.members.length} agents.`);
// 3. Find a specific person
const bob = teamData.members.find(m => m.name === "Bob");
}
What happens here: The system synchronously reads the JSON file, parses it, and gives you a standard JavaScript object.
If an agent finishes a task, we should update the database so the Leader knows they are free.
import { setMemberActive } from './teamHelpers.js';
// Update the file on disk asynchronously
await setMemberActive(
"MyDevTeam",
"Bob",
false // isActive = false (Idle)
);
What happens here:
false.How does the system ensure data isn't lost during a crash?
Let's look at how we structure this data and manage the files.
TeamFile)
In teamHelpers.ts, we define exactly what a team looks like. This ensures consistency.
// teamHelpers.ts
export type TeamFile = {
name: string;
leadAgentId: string; // The "CEO"
members: Array<{
name: string;
agentId: string;
tmuxPaneId: string; // The physical location
isActive?: boolean; // Working or Idle?
backendType?: 'tmux' | 'iterm' | 'in_process';
}>
}
We rarely overwrite the whole file blindly. We usually read, modify, and write.
// Inside teamHelpers.ts
export async function setMemberMode(teamName, memberName, mode) {
// 1. Read
const teamFile = readTeamFile(teamName);
if (!teamFile) return false;
// 2. Modify in memory
const updatedMembers = teamFile.members.map(m =>
m.name === memberName ? { ...m, mode } : m
);
// 3. Write back to disk
writeTeamFile(teamName, { ...teamFile, members: updatedMembers });
}
When a session ends gracefully, we don't want to leave "ghost" files. We call cleanupSessionTeams.
// Inside teamHelpers.ts
export async function cleanupSessionTeams() {
// Get list of teams created this session
const teams = Array.from(getSessionCreatedTeams());
// 1. Kill the actual terminal panes (Tmux/iTerm)
await Promise.all(teams.map(name => killOrphanedTeammatePanes(name)));
// 2. Delete the folders from the disk
await Promise.all(teams.map(name => cleanupTeamDirectories(name)));
}
Why this matters: If we didn't do step 1, your terminal would eventually have 100 open tabs from old sessions. If we didn't do step 2, your disk would fill up with old JSON files.
In reconnection.ts, we use the persisted data to restore the application state (AppState) when the app launches.
// reconnection.ts
export function computeInitialTeamContext() {
// Check CLI args to see if we are a specific agent
const context = getDynamicTeamContext();
// Load the HR file to verify we exist
const teamFile = readTeamFile(context.teamName);
return {
teamName: context.teamName,
leadAgentId: teamFile.leadAgentId,
// ... restore other context
};
}
Congratulations! You have completed the Swarm Architecture Tutorial.
Let's recap the journey:
You now understand the full lifecycle of an AI Agent in the Swarm project: from being spawned in a colorful window, to asking for permission, to persisting its state on your hard drive.
Happy Swarming!
Generated by Code IQ