Squad Squad

SDK Reference

⚠️ Experimental — Squad is alpha software. APIs, commands, and behavior may change between releases.

Complete reference for @bradygaster/squad-sdk — the programmatic API for Squad.

npm install @bradygaster/squad-sdk

All imports work from the barrel export:

import { resolveSquad, loadConfig, SquadCoordinator, defineTool } from '@bradygaster/squad-sdk';

Resolution

Find .squad/ directories on disk.

FunctionDescription
resolveSquad(startPath?)Find .squad/ walking up from startPath (throws if not found)
resolveGlobalSquadPath()Get personal squad directory path (platform-specific)
ensureSquadPath(startPath?)Like resolveSquad, but creates .squad/ if missing
const squadPath = resolveSquad();                // '/home/user/project/.squad'
const globalPath = resolveGlobalSquadPath();      // Platform-specific: ~/.config/squad/ (Linux), ~/Library/Application Support/squad/ (macOS), %APPDATA%\squad\ (Windows)
const safePath = ensureSquadPath();               // Creates if needed

Configuration

loadConfig(squadPath): Promise<ConfigLoadResult>

Load and validate Squad configuration asynchronously.

const config = await loadConfig('./.squad');
config.team.name;           // Team name
Object.keys(config.agents); // Agent names
config.routing.workTypes;   // Routing rules

loadConfigSync(squadPath): ConfigLoadResult

Synchronous version for scripts and CLI tools.

defineConfig(partial): SquadConfig

Create a typed config with defaults and editor autocomplete:

// squad.config.ts
import { defineConfig } from '@bradygaster/squad-sdk';

export default defineConfig({
  team: { name: 'my-squad', root: '.squad' },
  agents: {
    backend: { model: 'claude-sonnet-4', tools: ['route', 'memory', 'decision'] },
  },
  routing: {
    workTypes: [
      { pattern: /\bAPI|backend\b/i, targets: ['backend'], tier: 'standard' },
    ],
  },
  models: {
    default: 'claude-sonnet-4',
    fallbackChains: {
      premium: ['claude-opus-4', 'gpt-4.1'],
      standard: ['claude-sonnet-4', 'gpt-4.1'],
      fast: ['claude-haiku-3.5', 'gpt-4.1-mini'],
    },
  },
});

Key Types

interface ConfigLoadResult {
  team: { name: string; root: string; description?: string };
  agents?: Record<string, AgentConfig>;
  routing?: RoutingConfig;
  models?: ModelConfig;
}

interface AgentConfig {
  role: string;
  model?: string;
  tools?: string[];
  status?: 'active' | 'inactive';
}

Builder Functions (SDK-First Mode)

Type-safe team configuration with runtime validation. Each builder accepts a config object, validates it, and returns the typed value.

New in Phase 1 — SDK-First Mode lets you define teams in TypeScript instead of manually maintaining markdown. Run squad build to generate .squad/ files.

See SDK-First Mode Guide for comprehensive documentation and examples.

defineTeam(config): TeamDefinition

Define team metadata, members, and project context.

const team = defineTeam({
  name: 'Platform Squad',
  description: 'Full-stack engineering team',
  projectContext: 'React/Node monorepo, TypeScript strict mode',
  members: ['@edie', '@mcmanus', '@fenster'],
});

Type:

interface TeamDefinition {
  readonly name: string;
  readonly description?: string;
  readonly projectContext?: string;
  readonly members: readonly string[];
}

defineAgent(config): AgentDefinition

Define a single agent with role, tools, model, and capabilities.

const edie = 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' },
  ],
  status: 'active',
});

Type:

interface AgentDefinition {
  readonly name: string;
  readonly role: string;
  readonly charter?: string;
  readonly model?: string;
  readonly tools?: readonly string[];
  readonly capabilities?: readonly AgentCapability[];
  readonly status?: 'active' | 'inactive' | 'retired';
}

interface AgentCapability {
  readonly name: string;
  readonly level: 'expert' | 'proficient' | 'basic';
}

defineRouting(config): RoutingDefinition

Define routing rules with pattern matching and tier assignment.

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

Type:

interface RoutingDefinition {
  readonly rules: readonly RoutingRule[];
  readonly defaultAgent?: string;
  readonly fallback?: 'ask' | 'default-agent' | 'coordinator';
}

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

defineCeremony(config): CeremonyDefinition

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

const standup = defineCeremony({
  name: 'standup',
  trigger: 'schedule',
  schedule: '0 9 * * 1-5',
  participants: ['@edie', '@mcmanus'],
  agenda: 'Yesterday / Today / Blockers',
});

Type:

interface CeremonyDefinition {
  readonly name: string;
  readonly trigger?: string;
  readonly schedule?: string;
  readonly participants?: readonly string[];
  readonly agenda?: string;
  readonly hooks?: readonly string[];
}

defineHooks(config): HooksDefinition

Define governance hooks — write paths, blocked commands, PII scrubbing.

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

Type:

interface HooksDefinition {
  readonly allowedWritePaths?: readonly string[];
  readonly blockedCommands?: readonly string[];
  readonly maxAskUser?: number;
  readonly scrubPii?: boolean;
  readonly reviewerLockout?: boolean;
}

defineCasting(config): CastingDefinition

Define casting configuration — universe allowlists and overflow behavior.

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

Type:

interface CastingDefinition {
  readonly allowlistUniverses?: readonly string[];
  readonly overflowStrategy?: 'reject' | 'generic' | 'rotate';
  readonly capacity?: Readonly<Record<string, number>>;
}

defineTelemetry(config): TelemetryDefinition

Define OpenTelemetry configuration for observability.

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

Type:

interface TelemetryDefinition {
  readonly enabled?: boolean;
  readonly endpoint?: string;
  readonly serviceName?: string;
  readonly sampleRate?: number;
  readonly aspireDefaults?: boolean;
}

defineSquad(config): SquadSDKConfig

Compose all builders into a single SDK config.

export default defineSquad({
  version: '1.0.0',
  team: defineTeam({ /* ... */ }),
  agents: [defineAgent({ /* ... */ })],
  routing: defineRouting({ /* ... */ }),
});

Type:

interface SquadSDKConfig {
  readonly version?: string;
  readonly team: TeamDefinition;
  readonly agents: readonly AgentDefinition[];
  readonly routing?: RoutingDefinition;
  readonly ceremonies?: readonly CeremonyDefinition[];
  readonly hooks?: HooksDefinition;
  readonly casting?: CastingDefinition;
  readonly telemetry?: TelemetryDefinition;
}

SquadClient

Wraps @github/copilot-sdk with lifecycle management and auto-reconnection.

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

const client = new SquadClient({
  port: 3000,
  auth: { token: process.env.COPILOT_TOKEN },
  reconnection: { maxRetries: 5, backoffMs: 1000 },
});

await client.connect();

Connection states: disconnected → connecting → connected → reconnecting → error

SquadClientWithPool

Production-ready client composing SquadClient, SessionPool, and EventBus:

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

const squad = new SquadClientWithPool({
  client: clientOptions,
  pool: { maxConcurrent: 10, idleTimeout: 60_000 },
});

const session = await squad.createSession({ agent: 'backend' });
const response = await session.sendMessage('Implement the /users endpoint');
await session.destroy();

Session states: creating → active → idle → error → destroyed


Coordinator

Central routing and orchestration engine.

SquadCoordinator

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

const coordinator = new SquadCoordinator({ teamRoot: './.squad', enableParallel: true });
await coordinator.initialize();

const decision = await coordinator.route('refactor the API');
// decision.tier:      'direct' | 'lightweight' | 'standard' | 'full'
// decision.agents:    ['backend', 'tester']
// decision.parallel:  true
// decision.rationale: 'Backend refactor with test coverage'

await coordinator.execute(decision, 'refactor the API');
await coordinator.shutdown();

selectResponseTier(context): TierName

const tier = selectResponseTier({ complexity: 'high', budget: 10, userTeam: true });
// → 'standard' or 'full'

getTier(name): TierDefinition

const tier = getTier('standard');
tier.maxAgents;     // Max parallel agents
tier.defaultModel;  // Default model
tier.toolset;       // Available tools

Event Handling

Typed pub/sub for session lifecycle events:

squad.events.on('session.created', (event) => {
  console.log(`Session ${event.sessionId} started`);
});

squad.events.on('session.status_changed', (event) => {
  if (event.payload.status === 'error') { /* handle */ }
});

Events: session.created, session.destroyed, session.status_changed, tool execution events.


Tools & Hooks

defineTool<TArgs>(config): SquadTool<TArgs>

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

const myTool = defineTool<{ query: string }>({
  name: 'search_docs',
  description: 'Search project documentation',
  parameters: {
    type: 'object',
    properties: { query: { type: 'string' } },
    required: ['query'],
  },
  handler: async (args) => ({
    textResultForLlm: `Found results for "${args.query}"`,
    resultType: 'success',
  }),
});

ToolRegistry

const registry = new ToolRegistry('./.squad');
registry.getTools();                                    // All tools
registry.getToolsForAgent(['squad_route', 'squad_decide']); // Agent-specific
registry.getTool('squad_route');                         // Single lookup

Built-in tools:

ToolPurpose
squad_routeRoute a task to another agent
squad_decideWrite decisions to the inbox
squad_memoryAppend to agent history
squad_statusQuery session pool state
squad_skillRead/write agent skills

HookPipeline

Intercept tool calls before (PreToolUseHook) and after (PostToolUseHook) execution:

import { HookPipeline, type PreToolUseHook } from '@bradygaster/squad-sdk';

const auditHook: PreToolUseHook = async (toolName, params, context) => {
  console.log(`Agent ${context.agentId} calling ${toolName}`);
  return { action: 'allow' };
};

const pipeline = new HookPipeline();
pipeline.addPreHook(auditHook);

Hook actions: allow, block, modify

Built-in policies: ReviewerLockout, File Guards, Shell Restrictions, Rate Limits, PII Filters.


Agents & Casting

onboardAgent(options): Promise<OnboardResult>

const result = await onboardAgent({
  teamRoot: './.squad',
  agentName: 'data-analyst',
  role: 'backend',
  displayName: 'Dana — Data Analyst',
  projectContext: 'A recipe sharing app',
});
// result.agentDir, result.charterPath, result.historyPath

CastingEngine

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

const engine = new CastingEngine({ universes: ['The Wire'], activeUniverse: 'The Wire' });
const members = await engine.castTeam([
  { role: 'lead', title: 'Lead Developer' },
  { role: 'backend', title: 'Backend Engineer' },
]);
// members[0].name → 'Stringer', members[0].universe → 'The Wire'

Runtime Constants

import { MODELS, TIMEOUTS, AGENT_ROLES } from '@bradygaster/squad-sdk';

MODELS.premium;  // ['claude-opus-4.6', 'gpt-5.2', ...]
MODELS.standard; // ['claude-sonnet-4.5', 'gpt-5.1', ...]
MODELS.fast;     // ['claude-haiku-4.5', 'gpt-5-mini', ...]

TIMEOUTS.agentInitMs;        // 30000
TIMEOUTS.agentExecuteMs;     // 300000
TIMEOUTS.coordinatorRouteMs; // 5000

Upstream Inheritance

Share skills, decisions, and routing across teams.

import { readUpstreamConfig, resolveUpstreams, buildInheritedContextBlock } from '@bradygaster/squad-sdk';

const config = await readUpstreamConfig('./.squad');
const resolved = await resolveUpstreams(config, './.squad');
const contextBlock = buildInheritedContextBlock(resolved);

Upstream types: local, git, export


Observability (OpenTelemetry)

Quick Setup

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

const telemetry = await initSquadTelemetry({
  endpoint: 'http://localhost:4318',
  serviceName: 'my-squad',
  eventBus: myEventBus,
});

// ... run agents ...
await telemetry.shutdown();

Low-Level Control

import { initializeOTel, shutdownOTel, getTracer, getMeter } from '@bradygaster/squad-sdk';

await initializeOTel({ endpoint: 'http://localhost:4318' });

const tracer = getTracer('my-component');
const span = tracer.startSpan('my-work');
// ... do work ...
span.end();

const meter = getMeter('my-component');
const counter = meter.createCounter('requests_total');
counter.add(1);

await shutdownOTel();

Error Classes

All errors extend SquadError with severity, category, and recoverability:

ErrorWhen
SDKConnectionErrorConnection failures (retryable)
AuthenticationErrorBad credentials (fatal)
SessionLifecycleErrorSession state transitions
ToolExecutionErrorTool call failures
ModelAPIErrorModel unavailable or rate limited
ConfigurationErrorInvalid config (includes field + reason)
RateLimitErrorToo many requests
ValidationErrorSchema validation failures

Exports at a Glance

ExportTypeModule
resolveSquadfunctionresolution
resolveGlobalSquadPathfunctionresolution
ensureSquadPathfunctionresolution
MODELSconstantruntime/constants
TIMEOUTSconstantruntime/constants
AGENT_ROLESconstantruntime/constants
loadConfig / loadConfigSyncfunctionconfig
onboardAgentfunctionagents
CastingEngine / CastingHistoryclasscasting
SquadCoordinatorclasscoordinator
selectResponseTier / getTierfunctioncoordinator
defineTool / ToolRegistryfunction/classtools
initializeOTel / shutdownOTelfunctionruntime/otel
getTracer / getMeterfunctionruntime/otel
initSquadTelemetryfunctionruntime/otel-init

See Also