Skip to main content

Overview

Stewards are automated maintenance agents that handle system tasks like code review, documentation upkeep, and error recovery. Stoneforge provides four built-in steward focuses, each specialized for a specific type of maintenance work.

Built-in Steward Focuses

Merge Steward

Reviews and merges completed work branches. Runs tests, resolves conflicts, and auto-merges to main.

Docs Steward

Scans documentation for outdated content, broken links, and missing API docs. Auto-merges documentation fixes.

Recovery Steward

Monitors system health. Detects stuck tasks, orphaned processes, and stale worktrees. Creates recovery tasks.

Custom Steward

Executes user-defined workflow playbooks for specialized maintenance (dependency updates, code quality scans, etc.).

Merge Steward

Purpose

Automate code review and merge process for completed tasks.

How It Works

1

Task Completion Trigger

When a worker completes a task (sf task complete <task-id>), the task enters REVIEW status with mergeStatus: pending.
2

Automatic Dispatch

The dispatch daemon assigns the task to an available merge steward.
3

Branch Sync

Daemon syncs the task’s branch with the target branch (usually main) before spawning the steward.
4

Review and Test

Steward:
  • Resolves any merge conflicts
  • Reviews changes against acceptance criteria
  • Runs test suite (if configured)
  • Checks for documentation updates
5

Merge or Create Fix Task

  • Tests pass: Squash-merge to main, push, cleanup branch/worktree
  • Tests fail or conflicts: Create fix task, assign to original worker

Configuration

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

const api = createOrchestratorAPI(storage);

const mergeSteward = await api.registerSteward({
  name: 'm-steward-1',
  stewardFocus: 'merge',
  triggers: [
    { type: 'event', event: 'task_completed' },
  ],
  createdBy: directorId,
  maxConcurrentTasks: 2,  // Review 2 PRs in parallel
});

Service Configuration

Customize merge behavior:
import { createMergeStewardService } from '@stoneforge/smithy';

const mergeService = createMergeStewardService(
  api,
  taskAssignment,
  dispatchService,
  agentRegistry,
  {
    workspaceRoot: process.cwd(),
    testCommand: 'npm run test:ci',
    testTimeoutMs: 5 * 60 * 1000,
    autoMerge: true,
    autoCleanup: true,
    deleteBranchAfterMerge: true,
    mergeStrategy: 'squash',  // or 'merge'
    autoPushAfterMerge: true,
    targetBranch: 'main',
    stewardEntityId: mergeSteward.id,
  },
  worktreeManager
);

Responsibilities

  • Conflict Resolution: Resolve ALL merge conflicts, including complex logic conflicts
  • Test Execution: Run test suite before merging (configurable)
  • Acceptance Criteria Verification: Ensure all task acceptance criteria are met
  • Documentation Check: Verify relevant docs were updated
  • Fix Task Creation: Create detailed fix tasks when tests fail or conflicts can’t be resolved
  • Branch Cleanup: Delete merged branches and clean up worktrees
See the Merge Review Guide for detailed merge steward workflows.

Docs Steward

Purpose

Maintain documentation quality by detecting and fixing common issues.

How It Works

1

Schedule-Based Scanning

Runs on a schedule (e.g., nightly) to scan all documentation.
2

Issue Detection

Scans for:
  • Broken external links (HTTP 404, timeout)
  • Broken internal links (missing files)
  • Outdated API references (compare with code)
  • Missing documentation for new APIs
  • Inconsistent formatting
3

Auto-Fix or Report

  • Simple fixes (broken links, formatting): Auto-fix and merge
  • Complex issues (missing docs, outdated content): Create tasks

Configuration

const docsSteward = await api.registerSteward({
  name: 'd-steward-1',
  stewardFocus: 'docs',
  triggers: [
    { type: 'cron', schedule: '0 2 * * *' },  // Nightly at 2am
  ],
  createdBy: directorId,
  maxConcurrentTasks: 1,
});

Service Configuration

import { createDocsStewardService } from '@stoneforge/smithy';

const docsService = createDocsStewardService(
  api,
  taskAssignment,
  dispatchService,
  {
    workspaceRoot: process.cwd(),
    docsDirectory: 'docs',
    autoFix: true,  // Auto-merge simple fixes
    createTasksForComplex: true,  // Create tasks for complex issues
    scanExternalLinks: true,
    externalLinkTimeout: 5000,
  },
  worktreeManager
);

Responsibilities

  • Link Validation: Check all markdown links (internal and external)
  • API Documentation Coverage: Ensure all public APIs are documented
  • Consistency Checks: Verify formatting, heading hierarchy, code block syntax
  • Auto-Fix: Merge simple fixes automatically (broken links, formatting)
  • Task Creation: Create documentation tasks for complex issues

Example Scan Output

Docs Scan Report (2026-03-02)

Broken Links:
  - docs/api/authentication.md:15 -> /api/v2/login (404)
  - docs/guides/setup.md:42 -> https://example.com/guide (timeout)

Missing API Docs:
  - src/api/users.ts: createUser() function has no documentation
  - src/api/tasks.ts: updateTask() missing parameters documentation

Actions Taken:
  - Fixed 2 broken internal links (auto-merged)
  - Created task: "Document createUser() API" (task-123)
  - Created task: "Update authentication docs for v2 API" (task-124)

Recovery Steward

Purpose

Monitor system health and recover from failures automatically.

How It Works

1

Continuous Monitoring

Runs periodically (e.g., every 15 minutes) to check system state.
2

Issue Detection

Detects:
  • Stuck tasks (in IN_PROGRESS for >2 hours with no updates)
  • Orphaned agent sessions (agent crashed, session still active)
  • Stale worktrees (directory exists but task is closed)
  • Merge conflicts stuck in testing status for >1 hour
3

Automatic Recovery

  • Stuck tasks: Reset to OPEN, increment resumeCount, reassign
  • Orphaned sessions: Terminate session, cleanup worktree
  • Stale worktrees: Remove worktree, delete branch
  • Stuck merges: Re-trigger merge steward

Configuration

const recoverySteward = await api.registerSteward({
  name: 'r-steward-1',
  stewardFocus: 'recovery',
  triggers: [
    { type: 'cron', schedule: '*/15 * * * *' },  // Every 15 minutes
  ],
  createdBy: directorId,
  maxConcurrentTasks: 1,
});

Responsibilities

  • Stuck Task Detection: Find tasks with no progress updates
  • Session Health: Detect crashed agent sessions
  • Worktree Cleanup: Remove abandoned worktrees
  • Merge Recovery: Restart stuck merge reviews
  • Resource Monitoring: Track disk space, memory usage (optional)
  • Alert Generation: Notify operators of critical issues

Detection Criteria

IssueDetection RuleRecovery Action
Stuck taskIN_PROGRESS status, no updates for 2+ hoursReset to OPEN, increment resumeCount
Orphaned sessionSession marked running, agent process not foundTerminate session, cleanup worktree
Stale worktreeWorktree exists, task is CLOSED, branch mergedRemove worktree, delete local branch
Stuck mergemergeStatus: testing, no updates for 1+ hourReset to pending, re-dispatch

Example Recovery Report

Recovery Report (2026-03-02 14:15)

Stuck Tasks Detected:
  - task-456: IN_PROGRESS for 3h 22m (last update: 2026-03-02 10:53)
    Action: Reset to OPEN, resumeCount: 1 -> 2
  
Orphaned Sessions:
  - e-worker-3: Session active but process not found (PID 12345)
    Action: Terminated session, cleaned up worktree

Stale Worktrees:
  - .stoneforge/.worktrees/e-worker-2-old-feature
    Task: CLOSED (merged 2 days ago)
    Action: Removed worktree, deleted branch

All issues resolved.

Custom Steward

Purpose

Execute user-defined workflow playbooks for specialized maintenance tasks.

How It Works

Custom stewards reference a Playbook (Workflow element) that defines step-by-step procedures:
import { createPlaybook } from '@stoneforge/core';

// 1. Create the playbook
const playbook = await createPlaybook({
  title: 'Dependency Update Checker',
  content: `## Check for Outdated Dependencies

### Steps

1. Run: \`npm outdated --json\`
2. Filter packages with major updates
3. Create update tasks for each package
4. Notify team channel
`,
  createdBy: operatorId,
  tags: ['maintenance', 'dependencies'],
});

const savedPlaybook = await api.create(playbook);

// 2. Register steward with playbook reference
const customSteward = await api.registerSteward({
  name: 'dep-update-steward',
  stewardFocus: 'custom',
  playbookId: savedPlaybook.id,
  triggers: [
    { type: 'cron', schedule: '0 2 * * 1' },  // Weekly on Monday at 2am
  ],
  createdBy: directorId,
});

Playbook Structure

See the Playbooks Guide for detailed playbook creation.

Use Cases

  • Check for outdated npm/pip/cargo dependencies
  • Create update tasks for major version bumps
  • Auto-update patch versions
  • Run linters and type checkers
  • Detect code smells with static analysis
  • Create fix tasks for violations
  • Run npm audit or snyk test
  • Check for hardcoded secrets
  • Validate SSL certificates
  • Delete stale branches
  • Archive old issues/PRs
  • Clean up temporary files
  • Gather code coverage stats
  • Track bundle size over time
  • Generate performance reports

Steward Lifecycle

Registration and Startup

// Register steward
const steward = await api.registerSteward({
  name: 'm-steward-1',
  stewardFocus: 'merge',
  triggers: [
    { type: 'event', event: 'task_completed' },
  ],
  createdBy: directorId,
});

// Steward is now registered and listening for triggers
// Dispatch daemon will assign tasks when triggered

Trigger and Dispatch

┌─────────────────────────────────────────────┐
│          Trigger Event                │
│    (task_completed OR cron)          │
└───────────────┬─────────────────────────────┘


┌─────────────────────────────────────────────┐
│        Dispatch Daemon               │
│   Finds available steward           │
└───────────────┬─────────────────────────────┘


┌─────────────────────────────────────────────┐
│      Steward Spawns                 │
│   In isolated worktree              │
└───────────────┬─────────────────────────────┘


┌─────────────────────────────────────────────┐
│     Executes Workflow              │
│   (review, scan, cleanup, etc.)    │
└───────────────┬─────────────────────────────┘


┌─────────────────────────────────────────────┐
│      Reports Results               │
│   (docs, messages, tasks)          │
└───────────────┬─────────────────────────────┘


┌─────────────────────────────────────────────┐
│       Session Ends                 │
│   Worktree cleaned up               │
└─────────────────────────────────────────────┘

Deactivation

// Temporarily disable steward
await api.update(stewardId, {
  metadata: { ...steward.metadata, maxConcurrentTasks: 0 },
});

// Re-enable
await api.update(stewardId, {
  metadata: { ...steward.metadata, maxConcurrentTasks: 1 },
});

// Permanently remove
await api.delete(stewardId);

Best Practices

Start with Merge Steward

Merge steward provides the most immediate value by automating code review and merging.

Add Docs Steward for Large Codebases

If you have >50 documentation files, a docs steward prevents documentation drift.

Recovery Steward for Production

Essential for long-running systems to detect and recover from stuck tasks and orphaned sessions.

Custom Stewards for Specialized Needs

Use playbooks for project-specific maintenance (dependency updates, security scans, etc.).

Steward Concurrency

// Merge steward: higher concurrency for parallel reviews
await api.registerSteward({
  name: 'm-steward-1',
  stewardFocus: 'merge',
  maxConcurrentTasks: 3,  // Review 3 PRs in parallel
  ...
});

// Recovery steward: single-threaded to avoid race conditions
await api.registerSteward({
  name: 'r-steward-1',
  stewardFocus: 'recovery',
  maxConcurrentTasks: 1,  // One recovery run at a time
  ...
});

Multiple Stewards of Same Focus

You can register multiple stewards with the same focus:
// Two merge stewards for higher throughput
const mergeSteward1 = await api.registerSteward({
  name: 'm-steward-1',
  stewardFocus: 'merge',
  maxConcurrentTasks: 2,
  createdBy: directorId,
});

const mergeSteward2 = await api.registerSteward({
  name: 'm-steward-2',
  stewardFocus: 'merge',
  maxConcurrentTasks: 2,
  createdBy: directorId,
});

// Now 4 PRs can be reviewed in parallel (2 per steward)

Monitoring Stewards

List Active Stewards

import { createAgentRegistry } from '@stoneforge/smithy';

const registry = createAgentRegistry(api);

const stewards = await registry.getStewards();

for (const steward of stewards) {
  console.log(`${steward.name} (${steward.metadata?.stewardFocus})`);
  console.log(`  Triggers:`, steward.metadata?.triggers);
  console.log(`  Max concurrent:`, steward.metadata?.maxConcurrentTasks);
}

Query Steward Activity

// Get tasks assigned to stewards
const stewardTasks = await api.list({
  type: 'task',
  assignee: stewardId,
});

console.log(`Steward has ${stewardTasks.length} active tasks`);

// Check steward channel for notifications
const channel = await registry.getAgentChannel(stewardId);
const messages = await api.getChannelMessages(channel.id);

console.log(`Steward sent ${messages.length} notifications`);

Troubleshooting

Symptom: Tasks complete but merge steward never triggersPossible causes:
  1. Steward has maxConcurrentTasks: 0 (disabled)
  2. Trigger event doesn’t match (e.g., task_created instead of task_completed)
  3. Dispatch daemon not running
Solution:
// Verify steward config
const steward = await api.getAgent(stewardId);
console.log('Triggers:', steward.metadata?.triggers);
console.log('Max tasks:', steward.metadata?.maxConcurrentTasks);

// Check daemon is running
// In smithy-server logs, look for: "Dispatch daemon started"
Symptom: Steward keeps processing the same task repeatedlyCause: Task status not updating correctly after steward completesSolution: Ensure steward properly closes or updates task status:
// After merge succeeds
await api.update(taskId, {
  status: TaskStatus.CLOSED,
  closedAt: createTimestamp(),
});

// Update merge status
await mergeService.updateMergeStatus(taskId, 'merged');
Symptom: Custom steward spawns but doesn’t execute playbookCause: Playbook has syntax errors or bash commands failSolution: Test playbook commands manually:
# Extract playbook content
sf show <playbook-id> --json | jq -r '.content' > /tmp/playbook.md

# Test bash snippets
bash -c 'your command here'

Merge Review Guide

Detailed merge steward workflow

Playbooks

Create custom steward playbooks

Custom Agents

Customize steward prompts and behaviors

Build docs developers (and LLMs) love