Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/bradygaster/squad/llms.txt

Use this file to discover all available pages before exploring further.

The hello-squad sample is the recommended starting point for the Squad SDK. In under 100 lines of TypeScript it demonstrates the four core SDK primitives — directory resolution, agent casting, agent onboarding, and casting history — using a themed team drawn from The Usual Suspects universe. No GitHub token is required; everything runs locally in a temp directory.

What you’ll build

1

Resolve the .squad/ directory

Call resolveSquad(root) to locate an existing .squad/ directory or confirm it exists. The sample creates a fresh directory under os.tmpdir() so the demo never writes into your repository.
const demoRoot = join(tmpdir(), 'hello-squad-demo');
const squadDir = join(demoRoot, '.squad');
mkdirSync(squadDir, { recursive: true });

const resolved = resolveSquad(demoRoot);
// → /tmp/hello-squad-demo/.squad
2

Cast a team from The Usual Suspects

Pass a universe, teamSize, and requiredRoles array to CastingEngine.castTeam(). The engine assigns characters from the chosen universe to roles based on personality fit and returns typed CastMember objects.
const engine = new CastingEngine();
const roles: AgentRole[] = ['lead', 'developer', 'tester', 'scribe'];

const team: CastMember[] = engine.castTeam({
  universe: 'usual-suspects',
  teamSize: roles.length,
  requiredRoles: roles,
});
3

Onboard each agent

For every cast member, call onboardAgent() to create an agent directory under .squad/agents/<name>/ containing two files: charter.md (role, project context, and personality) and history.md (an empty cast log ready for entries).
await onboardAgent({
  teamRoot: demoRoot,
  agentName: member.name.toLowerCase(),
  role: member.role,
  displayName: member.displayName,
  projectContext: 'Hello Squad demo — beginner SDK sample.',
  userName: 'DemoUser',
});
4

Display the team roster

Iterate the CastMember[] array to render a formatted table showing each agent’s name, role, and personality trait. This is the human-readable summary of the cast.
for (const m of team) {
  const name = m.name.padEnd(11);
  const role = m.role.padEnd(16);
  const personality = m.personality.slice(0, 40).padEnd(40);
  console.log(`  │ ${name}${role}${personality} │`);
}
5

Track casting history

Create a CastingHistory instance and call recordCast() after each cast. Then cast the same config a second time and verify that agent names are identical — the casting system is deterministic, so names persist across runs and can be used as stable identifiers.
const history = new CastingHistory();
history.recordCast(team, config);

const team2 = engine.castTeam(config);
history.recordCast(team2, config);

const match = team.every((m, i) => m.name === team2[i].name);
// → true: names are deterministic across casts

Full source

/**
 * hello-squad — Beginner sample for @bradygaster/squad-sdk
 *
 * Demonstrates:
 *  1. resolveSquad() — locate or create a .squad/ directory
 *  2. CastingEngine  — cast a themed team from a universe
 *  3. onboardAgent() — onboard each agent with a charter
 *  4. CastingHistory — persistent name registry
 */

import { mkdirSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import {
  resolveSquad,
  CastingEngine,
  CastingHistory,
  onboardAgent,
} from '@bradygaster/squad-sdk';
import type { CastMember, AgentRole } from '@bradygaster/squad-sdk';

// ── Helpers ──────────────────────────────────────────────────────────

function hr(label: string): void {
  console.log(`\n${'─'.repeat(60)}`);
  console.log(`  ${label}`);
  console.log('─'.repeat(60));
}

// ── Main ─────────────────────────────────────────────────────────────

async function main(): Promise<void> {
  console.log('🎬 hello-squad — Squad SDK beginner sample\n');

  // ── Step 1: Resolve (or create) a .squad/ directory ──────────────
  hr('Step 1 — Resolve .squad/ directory');

  const demoRoot = join(tmpdir(), 'hello-squad-demo');
  const squadDir = join(demoRoot, '.squad');

  if (!existsSync(squadDir)) {
    mkdirSync(squadDir, { recursive: true });
    console.log(`✅ Created demo .squad/ at: ${squadDir}`);
  } else {
    console.log(`✅ .squad/ already exists at: ${squadDir}`);
  }

  const resolved = resolveSquad(demoRoot);
  console.log(`   resolveSquad() → ${resolved ?? '(not found)'}`);

  // ── Step 2: Cast a team of 4 agents ──────────────────────────────
  hr('Step 2 — Cast a team from "The Usual Suspects"');

  const engine = new CastingEngine();
  const roles: AgentRole[] = ['lead', 'developer', 'tester', 'scribe'];

  const team: CastMember[] = engine.castTeam({
    universe: 'usual-suspects',
    teamSize: roles.length,
    requiredRoles: roles,
  });

  console.log(`\n  Universe: The Usual Suspects`);
  console.log(`  Team size: ${team.length}\n`);

  for (const member of team) {
    console.log(`  🎭 ${member.displayName}`);
    console.log(`     Personality: ${member.personality}`);
    console.log(`     Backstory:   ${member.backstory}\n`);
  }

  // ── Step 3: Onboard each agent ───────────────────────────────────
  hr('Step 3 — Onboard agents');

  for (const member of team) {
    const agentDir = join(squadDir, 'agents', member.name.toLowerCase());
    if (existsSync(agentDir)) {
      console.log(`  ⏭  ${member.name} already onboarded — skipping`);
      continue;
    }

    const result = await onboardAgent({
      teamRoot: demoRoot,
      agentName: member.name.toLowerCase(),
      role: member.role,
      displayName: member.displayName,
      projectContext: 'Hello Squad demo — a beginner sample showcasing the SDK casting & onboarding APIs.',
      userName: 'DemoUser',
    });

    console.log(`  ✅ ${member.displayName}`);
    console.log(`     Dir:     ${result.agentDir}`);
    console.log(`     Charter: ${result.charterPath}`);
    console.log(`     History: ${result.historyPath}`);
  }

  // ── Step 4: Display the team roster ──────────────────────────────
  hr('Step 4 — Team roster');

  console.log('\n  ┌─────────────┬──────────────────┬──────────────────────────────────────────┐');
  console.log('  │ Name        │ Role             │ Personality                              │');
  console.log('  ├─────────────┼──────────────────┼──────────────────────────────────────────┤');

  for (const m of team) {
    const name = m.name.padEnd(11);
    const role = m.role.padEnd(16);
    const personality = m.personality.slice(0, 40).padEnd(40);
    console.log(`  │ ${name}${role}${personality} │`);
  }

  console.log('  └─────────────┴──────────────────┴──────────────────────────────────────────┘');

  // ── Step 5: Casting registry — names are persistent ──────────────
  hr('Step 5 — Casting history (persistent names)');

  const history = new CastingHistory();

  const config = { universe: 'usual-suspects' as const, teamSize: 4, requiredRoles: roles };
  history.recordCast(team, config);

  const team2 = engine.castTeam(config);
  history.recordCast(team2, config);

  console.log(`\n  Casting records: ${history.size}`);
  console.log('  Cast #1 names:', team.map(m => m.name).join(', '));
  console.log('  Cast #2 names:', team2.map(m => m.name).join(', '));

  const match = team.every((m, i) => m.name === team2[i].name);
  console.log(`  Names match across casts: ${match ? '✅ Yes' : '❌ No'}`);

  const serialized = history.serializeHistory();
  console.log(`  Serialized history version: ${serialized.version}`);
  console.log(`  Records in history: ${serialized.records.length}`);

  const keyserHistory = history.getAgentHistory('Keyser');
  console.log(`  Keyser appeared in ${keyserHistory.length} cast(s)`);

  hr('Done! 🎉');
}

main().catch((err) => {
  console.error('❌ Fatal error:', err);
  process.exit(1);
});

Key APIs used

resolveSquad(root)

resolveSquad(root: string): string | null
Searches root for a .squad/ directory and returns the absolute path if found, or null if the directory doesn’t exist. Use this to locate an existing team workspace rather than constructing the path manually.

CastingEngine.castTeam(config)

engine.castTeam({
  universe: string,
  teamSize: number,
  requiredRoles: AgentRole[],
}): CastMember[]
Selects characters from the named universe and assigns them to the requested roles. Returns a CastMember[] array where each member has name, displayName, role, personality, and backstory fields. The assignment is deterministic: the same config always produces the same names.

onboardAgent(options)

Creates .squad/agents/<name>/charter.md and .squad/agents/<name>/history.md for a new agent. Returns { agentDir, charterPath, historyPath }.
teamRoot
string
required
Absolute path to the project root containing (or that will contain) the .squad/ directory.
agentName
string
required
Filesystem-safe lowercase identifier for the agent (used as the directory name).
role
AgentRole
required
The agent’s role: "lead", "developer", "tester", or "scribe".
displayName
string
Human-readable name shown in rosters and logs (e.g., "Keyser — Lead").
projectContext
string
A short description of the project. Written into charter.md so the agent understands its context.
userName
string
The human developer’s name. Recorded in the charter as the agent’s primary collaborator.

CastingHistory

MethodDescription
recordCast(team, config)Persist a cast assignment. Call after each castTeam().
serializeHistory()Serialize all records to a JSON-safe object for storage. Returns { version, records[] }.
getAgentHistory(name)Return all cast records where the given agent name appears.
sizeNumber of cast records currently in history.

Running the sample

cd samples/hello-squad
npm install
npm start
No environment variables or external services are required. The sample writes to os.tmpdir()/hello-squad-demo/ so your repository stays clean.

Expected output

🎬 hello-squad — Squad SDK beginner sample

────────────────────────────────────────────────────────────
  Step 1 — Resolve .squad/ directory
────────────────────────────────────────────────────────────
✅ Created demo .squad/ at: /tmp/hello-squad-demo/.squad
   resolveSquad() → /tmp/hello-squad-demo/.squad

────────────────────────────────────────────────────────────
  Step 2 — Cast a team from "The Usual Suspects"
────────────────────────────────────────────────────────────
  Universe: The Usual Suspects
  Team size: 4

  🎭 Keyser — Lead
     Personality: Quietly commanding; sees the whole board before anyone else.
     Backstory:   ...

────────────────────────────────────────────────────────────
  Step 3 — Onboard agents
────────────────────────────────────────────────────────────
  ✅ Keyser — Lead
     Dir:     /tmp/hello-squad-demo/.squad/agents/keyser
     Charter: /tmp/hello-squad-demo/.squad/agents/keyser/charter.md
     History: /tmp/hello-squad-demo/.squad/agents/keyser/history.md
  ✅ McManus — Developer
  ✅ Fenster — Tester
  ✅ Verbal  — Scribe

────────────────────────────────────────────────────────────
  Step 4 — Team roster
────────────────────────────────────────────────────────────
  ┌─────────────┬──────────────────┬──────────────────────────────────────────┐
  │ Name        │ Role             │ Personality                              │
  ├─────────────┼──────────────────┼──────────────────────────────────────────┤
  │ Keyser      │ lead             │ Quietly commanding; sees the whole bo... │
  │ McManus     │ developer        │ Bold and improvisational; figures it  ... │
  │ Fenster     │ tester           │ Paranoid attention to detail; spots    ... │
  │ Verbal      │ scribe           │ Quietly observant; captures everything ... │
  └─────────────┴──────────────────┴──────────────────────────────────────────┘

────────────────────────────────────────────────────────────
  Step 5 — Casting history (persistent names)
────────────────────────────────────────────────────────────
  Casting records: 2
  Cast #1 names: Keyser, McManus, Fenster, Verbal
  Cast #2 names: Keyser, McManus, Fenster, Verbal
  Names match across casts: ✅ Yes
  Serialized history version: 1
  Records in history: 2
  Keyser appeared in 2 cast(s)

────────────────────────────────────────────────────────────
  Done! 🎉
────────────────────────────────────────────────────────────
Exact Personality and Backstory text comes from the universe definition inside the SDK. If you swap universe: 'usual-suspects' for another universe, you’ll see different character names and traits while all five steps remain identical.

Next steps

Casting Guide

Deep-dive into universes, role assignment, and how to define your own cast configurations.

SDK Overview

Full reference for every exported class, function, and type in @bradygaster/squad-sdk.

SDK-First Mode

Build agents entirely in TypeScript without any markdown files or CLI setup.

Advanced Patterns

Pipelines, governance hooks, streaming, cost-aware routing, and custom storage providers.

Build docs developers (and LLMs) love