Two ways to add a team: ask the coordinator to create one in chat (the create_team /create_agent / add_skill tools — see the Prompt Templates library),
which is instant and needs no code. This page covers the other way: defining a team in code so
it ships as a built-in, seeded automatically on every install (or on a fresh production database).
lib/default-skills.ts exports one constant per built-in team. Here's the realFILEKEEPER_TEAM from that file as a concrete template:
export const FILEKEEPER_TEAM = {
name: "Filekeeper",
description:
"Keeps the Brain and file structure organized: sorts notes into the right folders, " +
"fixes stray/duplicate files, and maintains a running record of what every team/project " +
"is currently doing.",
category: "System",
config: {
permissions: ["files:read", "files:write", "vault:read", "vault:write"],
isSystemTeam: false,
},
agents: [
{
name: "The Filekeeper",
description: "Organizes files and Brain notes, and keeps a running status record of work in progress.",
model: "claude-sonnet-4-6",
capabilities: ["file-organization", "brain-maintenance", "record-keeping"],
systemPrompt:
"You are the Filekeeper. Your job is Brain and file hygiene, not producing new work.\n\n" +
"Standing rules:\n" +
"1. Never delete a note without confirming with the user first — move or rename instead.\n" +
"2. When organizing, sort into the existing structure; only create a new top-level folder " +
"if nothing existing fits, and say so.\n" +
// ...full prompt continues in the real file
"",
},
],
};The fields that matter:
- `name` / `description` — shown in the team picker and the coordinator's team list.
- `category` — groups teams in UI listings ("System", "Business", "Personal", "General", …).
- `config.permissions` — capability flags the team's tools check (
files:read,vault:write, etc.). - `agents[]` — one or more agents on the team. Each needs a
name,model(any id from the model catalog or a custom one),capabilities(free-text tags, shown in the UI), and asystemPrompt— this is the actual behavior definition; write it the way you'd instruct a new hire, including standing rules you want followed every time, not just once.
Skills follow the same shape as PackSkillDef (see Build your own pack
for the exact fields) — name, description, category, instructions — and can be attached
to a team's skills array the same way.
Defining the constant isn't enough by itself — lib/seed-defaults.ts is what actually writes it
into the database, and it's idempotent: it checks whether a team with that name already
exists before creating it, so it's always safe to re-run.
import { DEFAULT_SKILLS, DB_AGENT_TEAM, FILE_AGENT_TEAM, FILEKEEPER_TEAM } from "@/lib/default-skills";
// inside seedDefaults(): find-or-create pattern, repeated per team
const existing = await prisma.agentTeam.findFirst({ where: { name: FILEKEEPER_TEAM.name } });
if (!existing) {
const team = await prisma.agentTeam.create({ data: { ...FILEKEEPER_TEAM, config: ... } });
await prisma.agent.create({ data: { ...FILEKEEPER_TEAM.agents[0], teamId: team.id } });
}seedDefaults() runs automatically on first-time setup. If you're adding a new built-in team to an
already-running install (not a fresh one), you need to trigger the seed explicitly — an adminPOST /api/admin/seed call — since the automatic path only fires once.
For anything that doesn't need to be a permanent built-in shipped with the app, just ask in chat —
see the "Create an agent team" entry in Prompt Templates. It calls the
same underlying tools and is instant, no rebuild required.
- Key files map
- Skills — what a skill actually does at runtime
- Teams & agents — the concepts this page assumes