Skip to main content

@stoneforge/smithy

Multi-agent orchestration layer built on top of @stoneforge/quarry. Defines agent roles, manages sessions across multiple providers, dispatches tasks automatically, and isolates work in Git worktrees.
Provider-Agnostic: Supports Claude Code, OpenCode, and OpenAI Codex with a unified interface.

Installation

npm install @stoneforge/smithy
Includes @stoneforge/quarry, @stoneforge/storage, and @stoneforge/core as dependencies.

Optional Providers

# OpenCode provider (optional)
npm install @opencode-ai/sdk
Claude Code provider (@anthropic-ai/claude-agent-sdk) is included by default.

Quick Start

import { createOrchestratorAPI } from '@stoneforge/smithy';
import { createStorage, initializeSchema } from '@stoneforge/storage';

const storage = createStorage({ path: '.stoneforge/db.sqlite' });
initializeSchema(storage);

// OrchestratorAPI extends QuarryAPI
const api = createOrchestratorAPI(storage);

// Register a director
const director = await api.registerDirector({
  name: 'lead',
  createdBy: humanEntityId,
});

console.log(`Director registered: ${director.id}`);

Agent Roles

Director

Strategic planner that creates tasks, sets priorities, and coordinates workers.
role
'director'
required
Agent role identifier
maxConcurrentTasks
number
default:"1"
Max tasks this director can manage simultaneously
const director = await api.registerDirector({
  name: 'MainDirector',
  createdBy: humanEntityId,
  maxConcurrentTasks: 1,
  provider: 'claude',
  model: 'claude-sonnet-4-20250514',
});

Worker

Executes assigned tasks. Two modes:
Spawned automatically for a single task, exits on completion.
const worker = await api.registerWorker({
  name: 'e-worker-1',
  workerMode: 'ephemeral',
  createdBy: director.id,
  reportsTo: director.id,
});

// Worktree path: agent/{worker-name}/{task-id}-{slug}

Steward

Handles maintenance workflows.
Reviews and merges completed work branches.
const steward = await api.registerSteward({
  name: 'm-steward-1',
  stewardFocus: 'merge',
  triggers: [
    { type: 'event', event: 'task_completed' },
  ],
  createdBy: director.id,
});

OrchestratorAPI

Extends QuarryAPI with agent-specific operations.

Agent Registration

const director = await api.registerDirector({
  name: string,
  createdBy: EntityId,
  maxConcurrentTasks?: number,
  provider?: 'claude' | 'opencode' | 'codex',
  model?: string,
  executablePath?: string,
});

Agent Queries

// Get by ID
const agent = await api.getAgent(entityId);

// Get by name
const agentByName = await api.getAgentByName('dev-1');

// List all
const allAgents = await api.listAgents();

// List by role
const workers = await api.listAgents({ role: 'worker' });
const stewards = await api.getStewards();

Task Assignment

// Auto-generates branch and worktree paths
const task = await api.assignTaskToAgent(taskId, workerId);

Session Management

await api.updateAgentSession(agentId, 'session-123', 'running');
// States: 'idle' | 'running' | 'suspended' | 'terminated'

Providers

Supported agent providers:
Default provider, included as a dependency.
const director = await api.registerDirector({
  name: 'lead',
  provider: 'claude',
  model: 'claude-sonnet-4-20250514',
  createdBy: humanEntityId,
});

Scaling with Multiple Plans

To run 10+ agents concurrently, split them across multiple Claude MAX/Pro plans:
  1. Create profile wrappers for each plan
  2. Set CLAUDE_CONFIG_DIR to separate directories
  3. Authenticate each profile
  4. Set executablePath per agent:
const worker = await api.registerWorker({
  name: 'dev-1',
  workerMode: 'ephemeral',
  provider: 'claude',
  executablePath: '~/.config/claude-profiles/profile-1/claude-code',
  createdBy: director.id,
});

Git Worktree Isolation

Workers operate in isolated Git worktrees to prevent conflicts.

Worktree Paths

agent/{worker-name}/{task-id}-{slug}
Example: agent/e-worker-1/task-123-implement-auth

Git Utilities

import { createWorktree, listWorktrees } from '@stoneforge/smithy/git';

await createWorktree({
  branch: 'agent/worker-1/feat-auth',
  path: '.stoneforge/.worktrees/worker-1-feat-auth',
});

Services

AgentRegistry

import { AgentRegistry } from '@stoneforge/smithy/services';

const registry = new AgentRegistry(storage, api);

// Register
const agent = await registry.register({
  name: 'worker-1',
  role: 'worker',
  createdBy: directorId,
});

// Lookup
const found = await registry.getByName('worker-1');
const workers = await registry.listByRole('worker');

DispatchService

import { DispatchService } from '@stoneforge/smithy/services';

const dispatch = new DispatchService(api, registry);

// Match ready tasks to available workers
const assignments = await dispatch.dispatchReadyTasks();
console.log(`Assigned ${assignments.length} tasks`);

DispatchDaemon

import { DispatchDaemon } from '@stoneforge/smithy/services';

const daemon = new DispatchDaemon(api, dispatch);

// Start polling loop
await daemon.start({
  intervalMs: 5000, // Poll every 5 seconds
});

// Stop
await daemon.stop();

MergeStewardService

import { MergeStewardService } from '@stoneforge/smithy/services';

const mergeSteward = new MergeStewardService(api, gitOps);

// Review a completed task
const result = await mergeSteward.reviewAndMerge(taskId, {
  testCommand: 'npm test',
  mergeStrategy: 'squash',
  autoCleanup: true,
});

if (result.merged) {
  console.log('Merge successful');
} else {
  console.log(`Tests failed: ${result.reason}`);
}

Prompts

Customize agent behavior with prompt overrides.

Built-in Prompts

Located in packages/smithy/src/prompts/:
  • director.md — Director role
  • worker.md — Ephemeral worker
  • persistent-worker.md — Persistent worker
  • steward-base.md — Base steward
  • steward-merge.md — Merge steward
  • steward-docs.md — Docs steward
  • steward-recovery.md — Recovery steward

Override Prompts

Place custom prompts in .stoneforge/prompts/:
.stoneforge/
  prompts/
    director.md
    worker.md
    steward-merge.md
Prompts are loaded in order: built-in → project overrides.
import { loadPrompt } from '@stoneforge/smithy';

const directorPrompt = await loadPrompt('director');

Entry Points

import { createOrchestratorAPI } from '@stoneforge/smithy';
// All exports

API Reference

Agent Types

type AgentRole = 'director' | 'worker' | 'steward';
type WorkerMode = 'ephemeral' | 'persistent';
type StewardFocus = 'merge' | 'docs' | 'recovery' | 'custom';
type SessionState = 'idle' | 'running' | 'suspended' | 'terminated';

Orchestrator Metadata

interface OrchestratorMeta {
  branch?: string;
  worktree?: string;
  sessionId?: string;
  mergeStatus?: 'pending' | 'merged' | 'failed';
}

Provider Interface

interface AgentProvider {
  headless: HeadlessProvider;
  interactive: InteractiveProvider;
}

interface HeadlessProvider {
  spawn(options: SpawnOptions): Promise<ChildProcess>;
}

interface InteractiveProvider {
  start(options: StartOptions): Promise<void>;
}
Multi-Provider: Smithy supports multiple agent providers with a unified interface. Switch providers per-agent without code changes.

Next Steps

Quarry API

Learn the underlying data API

UI Components

Build a web dashboard for agents

Build docs developers (and LLMs) love