Squad Squad

SDK-First Squad Mode

Phase 1 — Type-safe team configuration with builder functions.

Squad now supports SDK-First Mode: define your team in TypeScript with full type safety, runtime validation, and editor autocomplete. Instead of manually maintaining markdown files in .squad/, you write clean TypeScript, and squad build generates the governance markdown.


What gets generated

Running squad build generates these files:

FileConditionContains
.squad/team.mdAlwaysTeam roster, member list, project context
.squad/routing.mdIf routing definedRouting rules and default agent
.squad/agents/{name}/charter.mdFor each agentAgent role, model, tools, capabilities
.squad/ceremonies.mdIf ceremonies definedCeremony schedule and agenda

Protected files (never overwritten):

  • .squad/decisions.md / .squad/decisions-archive.md
  • .squad/agents/*/history.md
  • .squad/orchestration-log/*

What is SDK-First Mode?

In SDK-First Mode:

  1. You write a squad.config.ts (or squad/index.ts) with builder functions
  2. Squad validates your config at runtime with type guards
  3. squad build generates .squad/ markdown files automatically
  4. You version control only your TypeScript source — markdown is generated

This replaces manual .squad/team.md, .squad/routing.md, and agent charters with a single source of truth in code.

When to use SDK mode: For a comparison of SDK-first mode versus CLI mode, see the Getting started guide.


Quick Start

1. Install the SDK

npm install @bradygaster/squad-sdk

2. Create squad.config.ts

import {
  defineSquad,
  defineTeam,
  defineAgent,
  defineRouting,
} from '@bradygaster/squad-sdk';

export default defineSquad({
  team: defineTeam({
    name: 'Core Squad',
    description: 'The main engineering team',
    members: ['@edie', '@mcmanus'],
  }),

  agents: [
    defineAgent({
      name: 'edie',
      role: 'TypeScript Engineer',
      model: 'claude-sonnet-4',
      tools: ['grep', 'edit', 'powershell'],
      capabilities: [{ name: 'type-system', level: 'expert' }],
    }),
    defineAgent({
      name: 'mcmanus',
      role: 'DevRel',
      model: 'claude-haiku-4.5',
      capabilities: [{ name: 'documentation', level: 'expert' }],
    }),
  ],

  routing: defineRouting({
    rules: [
      { pattern: 'feature-*', agents: ['@edie'], tier: 'standard' },
      { pattern: 'docs-*', agents: ['@mcmanus'], tier: 'lightweight' },
    ],
    defaultAgent: '@coordinator',
  }),
});

3. Run squad build

squad build

This generates:

  • .squad/team.md — team roster and context
  • .squad/routing.md — routing rules
  • .squad/agents/{name}/charter.md — agent charters
  • .squad/ceremonies.md — (if ceremonies defined)

Start a new SDK-first project

squad init --sdk

This generates .squad/ markdown files and a squad.config.ts at your project root using the defineSquad() builder syntax. Your TypeScript config is the source of truth — edit it, then run squad build to regenerate .squad/.

For the full team initialization flow, see How teams form (Init Mode) in the getting started guide.


Migrating an Existing Squad to SDK-First

squad migrate --to sdk        # generate squad.config.ts from existing .squad/
squad migrate --to sdk --dry-run  # preview without writing

The migrate command reads your existing .squad/ files (team.md, routing.md, agent charters) and generates a squad.config.ts that reproduces your current configuration using typed builders.

What Gets Migrated

SourceGenerated
.squad/team.md rosterdefineTeam({ members: [...] })
.squad/agents/*/charter.mddefineAgent({ name, role, ... }) per agent
.squad/routing.md rulesdefineRouting({ rules: [...] })
.squad/ceremonies.mddefineCeremony() entries
.squad/casting/policy.jsondefineCasting() block

What’s Preserved (Not Migrated)

  • decisions.md — append-only ledger, stays as-is
  • agents/*/history.md — personal knowledge, stays as-is
  • orchestration-log/, log/ — append-only archives

Reverting to Markdown

squad migrate --to markdown

This runs squad build to ensure .squad/ is current, then removes squad.config.ts.

Legacy Migration

squad migrate --from ai-team   # rename .ai-team/ → .squad/

This replaces the old squad upgrade --migrate-directory command.


Builder functions

Each builder accepts a configuration object, validates it at runtime, and returns the typed value.

Common types reference

All builders share these core patterns:

// Base types used across multiple builders
interface AgentCapability {
  readonly name: string;
  readonly level: 'expert' | 'proficient' | 'basic';
}

interface RoutingRule {
  readonly pattern: string;
  readonly agents: readonly string[];
  readonly tier?: 'direct' | 'lightweight' | 'standard' | 'full';
  readonly priority?: number;
}

// Lifecycle and status
type AgentStatus = 'active' | 'inactive' | 'retired';
type FallbackBehavior = 'ask' | 'default-agent' | 'coordinator';
type OverflowStrategy = 'reject' | 'generic' | 'rotate';
type ConfidenceLevel = 'low' | 'medium' | 'high';
type SkillSource = 'manual' | 'observed' | 'earned' | 'extracted';

defineTeam(config)

Define team metadata, project context, and member roster.

const team = defineTeam({
  name: 'Core Squad',
  description: 'The main engineering team',
  projectContext: 'Building a React/Node recipe app...',
  members: ['@edie', '@fenster', '@hockney'],
});
FieldTypeRequiredNotes
namestringTeam name (non-empty)
descriptionstringOne-liner
projectContextstringInjected into agent prompts; describe the codebase, tech stack, conventions
membersstring[]Agent refs ("@edie" or "edie"); order matters for routing fallback

defineAgent(config)

Define a single agent with role, charter, model preference, tools, and capability profile.

const edie = defineAgent({
  name: 'edie',
  role: 'TypeScript Engineer',
  charter: 'Expert in type systems and test-driven development',
  model: 'claude-sonnet-4',
  tools: ['grep', 'edit', 'powershell', 'view'],
  capabilities: [
    { name: 'type-system', level: 'expert' },
    { name: 'testing', level: 'proficient' },
  ],
  status: 'active',
});
FieldTypeRequiredNotes
namestringUnique identifier (kebab-case, no @)
rolestringHuman-readable title
charterstringCharacter description or link to charter
modelstringModel preference (e.g., "claude-sonnet-4", "claude-haiku-4.5")
toolsstring[]Allowed tools (e.g., ["grep", "edit", "view"])
capabilitiesAgentCapability[]Capability list with proficiency levels (see Common Types)
statusAgentStatusLifecycle: 'active' (default), 'inactive', 'retired'

defineRouting(config)

Define typed routing rules with pattern matching, priority, and tier.

const routing = defineRouting({
  rules: [
    { pattern: 'feature-*', agents: ['@edie'], tier: 'standard', priority: 1 },
    { pattern: 'docs-*', agents: ['@mcmanus'], tier: 'lightweight' },
    { pattern: 'test-*', agents: ['@edie', '@fenster'], tier: 'full' },
  ],
  defaultAgent: '@coordinator',
  fallback: 'coordinator',
});
FieldTypeRequiredNotes
rulesRoutingRule[]Pattern-based routing rules (see Common Types)
defaultAgentstringFallback agent ref
fallbackFallbackBehavior'ask', 'default-agent', or 'coordinator'

Routing tiers: direct (skip ceremony), lightweight (quick handoff), standard (normal workflow), full (maximum governance).


defineCeremony(config)

Define ceremonies (standups, retros, etc.) with schedule, participants, and agenda.

const standup = defineCeremony({
  name: 'standup',
  trigger: 'schedule',
  schedule: '0 9 * * 1-5',  // Cron: 9 AM weekdays
  participants: ['@edie', '@mcmanus', '@fenster'],
  agenda: 'Yesterday / Today / Blockers',
});
FieldTypeRequiredNotes
namestringCeremony name
triggerstringEvent that triggers ceremony (e.g., "schedule", "pr-merged")
schedulestringCron expression or human-readable frequency
participantsstring[]Agent refs
agendastringFreeform agenda or template
hooksstring[]Hook names that fire during ceremony

defineHooks(config)

Define the governance hook pipeline — write paths, blocked commands, PII scrubbing, reviewer gates.

const hooks = defineHooks({
  allowedWritePaths: ['src/**', 'test/**', '.squad/**'],
  blockedCommands: ['rm -rf /', 'DROP TABLE', 'delete from'],
  maxAskUser: 3,
  scrubPii: true,
  reviewerLockout: true,
});
FieldTypeRequiredNotes
allowedWritePathsstring[]Glob patterns (e.g., ["src/**", "docs/**"])
blockedCommandsstring[]Dangerous commands to block
maxAskUsernumberMax user prompts per session
scrubPiibooleanAnonymize email/phone before logging
reviewerLockoutbooleanPrevent PR author from approving own PR

defineCasting(config)

Define casting configuration — universe allowlists and overflow strategy.

const casting = defineCasting({
  allowlistUniverses: ['The Usual Suspects', 'Breaking Bad'],
  overflowStrategy: 'generic',
  capacity: {
    'The Usual Suspects': 8,
    'Breaking Bad': 5,
  },
});
FieldTypeRequiredNotes
allowlistUniversesstring[]Permitted fictional universes
overflowStrategyOverflowStrategy'reject', 'generic', or 'rotate'
capacityRecord<string, number>Max agents per universe

defineTelemetry(config)

Define OpenTelemetry configuration for observability.

const telemetry = defineTelemetry({
  enabled: true,
  endpoint: 'http://localhost:4317',
  serviceName: 'squad-prod',
  sampleRate: 1.0,
  aspireDefaults: true,
});
FieldTypeRequiredNotes
enabledbooleanMaster on/off switch (default: false)
endpointstringOTLP receiver endpoint (e.g., "http://localhost:4317")
serviceNamestringOTel service name
sampleRatenumberTrace sample rate (0.0 – 1.0)
aspireDefaultsbooleanApply Aspire-compatible defaults for dashboard integration

defineSkill()

Define a reusable skill that agents can load on demand.

import { defineSkill } from '@bradygaster/squad-sdk';

const gitWorkflow = defineSkill({
  name: 'git-workflow',
  description: 'Squad branching model and PR conventions',
  domain: 'workflow',
  confidence: 'high',
  source: 'manual',
  content: `
    ## Patterns
    - Branch from dev: squad/{issue-number}-{slug}
    - PRs target dev, not main
    - Three-branch model: dev → insiders → main
  `,
});
FieldTypeRequiredDescription
namestringUnique skill name (kebab-case)
descriptionstringWhat this skill teaches
domainstringCategory (e.g., ‘orchestration’, ‘testing’)
confidenceConfidenceLevel'low', 'medium', or 'high'
sourceSkillSource'manual', 'observed', 'earned', or 'extracted'
contentstringThe skill body (patterns, examples)
toolsSkillTool[]MCP tools relevant to this skill

Skills defined in squad.config.ts are generated to .squad/skills/{name}/SKILL.md when you run squad build.


defineSquad(config)

Compose all builders into a single SDK config.

export default defineSquad({
  version: '1.0.0',
  team: defineTeam({ /* ... */ }),
  agents: [
    defineAgent({ /* ... */ }),
    defineAgent({ /* ... */ }),
  ],
  routing: defineRouting({ /* ... */ }),
  ceremonies: [defineCeremony({ /* ... */ })],
  hooks: defineHooks({ /* ... */ }),
  casting: defineCasting({ /* ... */ }),
  telemetry: defineTelemetry({ /* ... */ }),
});

squad build command

Compile TypeScript Squad definitions into .squad/ markdown.

Usage:

squad build [options]

Flags:

FlagWhat it does
--checkValidate without writing; exit 0 if matches disk, exit 1 if drift
--dry-runShow what would be generated without writing
--watchRebuild on .ts file changes (coming soon)

Examples:

# Rebuild all generated files
squad build

# Validate that generated files match disk (useful in CI/CD)
squad build --check

# Preview changes before writing
squad build --dry-run

Config discovery

squad build discovers your config in this order:

  1. squad/index.ts — SDK-First config
  2. squad.config.ts — Alternative location
  3. squad.config.js — JavaScript fallback

The config must export: export default config (default export), export { config } (named export), or export { squadConfig } (alias).


Validation

All builders perform runtime validation with typed error messages. Example:

defineAgent({
  name: 'edie',
  // Missing required 'role' field
});
// BuilderValidationError: [defineAgent] "role" must be a non-empty string

You manually maintain this file and agent charters.

After (SDK-First)

export default defineSquad({
  team: defineTeam({
    name: 'Core Squad',
    members: ['@edie'],
  }),
  agents: [
    defineAgent({
      name: 'edie',
      role: 'TypeScript Engineer',
    }),
  ],
});

Run squad build and the markdown is generated. Version control your TypeScript, not the markdown.


Best Practices

  1. Keep squad.config.ts at project root — easier to discover
  2. Use defineSquad() for composition — ensures all sections are validated together
  3. Add capabilities — helps the coordinator understand agent expertise
  4. Document project context — inject into agent prompts via TeamDefinition.projectContext
  5. Use consistent tier names — team members should understand routing tiers
  6. Validate in CI — add squad build --check to your CI pipeline
  7. Don’t edit generated markdown — it will be overwritten; edit squad.config.ts instead

Examples

Full SDK-First Config

import {
  defineSquad,
  defineTeam,
  defineAgent,
  defineRouting,
  defineHooks,
  defineCasting,
  defineTelemetry,
} from '@bradygaster/squad-sdk';

export default defineSquad({
  version: '1.0.0',

  team: defineTeam({
    name: 'Platform Squad',
    description: 'Full-stack platform engineering team',
    projectContext: `
      React/Node monorepo. TypeScript strict mode.
      Uses Vitest for testing, ESLint for linting.
      Deploys to Vercel (frontend) and AWS Lambda (backend).
    `,
    members: ['@edie', '@mcmanus', '@fenster', '@hockney'],
  }),

  agents: [
    defineAgent({
      name: 'edie',
      role: 'TypeScript Engineer',
      model: 'claude-sonnet-4',
      tools: ['grep', 'edit', 'powershell', 'view'],
      capabilities: [
        { name: 'type-system', level: 'expert' },
        { name: 'testing', level: 'proficient' },
        { name: 'architecture', level: 'proficient' },
      ],
    }),

    defineAgent({
      name: 'mcmanus',
      role: 'DevRel',
      model: 'claude-haiku-4.5',
      tools: ['grep', 'view', 'edit'],
      capabilities: [
        { name: 'documentation', level: 'expert' },
        { name: 'developer-experience', level: 'expert' },
      ],
    }),

    defineAgent({
      name: 'fenster',
      role: 'Test Lead',
      model: 'claude-sonnet-4',
      capabilities: [
        { name: 'testing', level: 'expert' },
        { name: 'qa', level: 'proficient' },
      ],
    }),

    defineAgent({
      name: 'hockney',
      role: 'Frontend Specialist',
      model: 'claude-opus-4.6',
      capabilities: [
        { name: 'frontend', level: 'expert' },
        { name: 'ui-ux', level: 'proficient' },
      ],
    }),
  ],

  routing: defineRouting({
    rules: [
      {
        pattern: 'feature-*',
        agents: ['@edie', '@hockney'],
        tier: 'standard',
        priority: 1,
      },
      {
        pattern: 'docs-*',
        agents: ['@mcmanus'],
        tier: 'lightweight',
      },
      {
        pattern: 'test-*',
        agents: ['@fenster'],
        tier: 'standard',
      },
      {
        pattern: 'bug-*',
        agents: ['@edie', '@fenster'],
        tier: 'full',
        priority: 0,
      },
    ],
    defaultAgent: '@coordinator',
    fallback: 'coordinator',
  }),

  hooks: defineHooks({
    allowedWritePaths: [
      'src/**',
      'test/**',
      'docs/**',
      '.squad/**',
      'package.json',
    ],
    blockedCommands: ['rm -rf /', 'DROP TABLE'],
    maxAskUser: 3,
    scrubPii: true,
    reviewerLockout: true,
  }),

  casting: defineCasting({
    allowlistUniverses: ['The Usual Suspects', 'Breaking Bad'],
    overflowStrategy: 'generic',
    capacity: {
      'The Usual Suspects': 8,
    },
  }),

  telemetry: defineTelemetry({
    enabled: true,
    endpoint: 'http://localhost:4317',
    serviceName: 'squad-platform',
    sampleRate: 1.0,
    aspireDefaults: true,
  }),
});

See Also