Skip to main content
Tasks are the fundamental units of work in Stoneforge. They support rich metadata, complex workflows, and automatic status management through dependencies.

Task Lifecycle

Tasks flow through a well-defined lifecycle from creation to completion:

Task Status

Stoneforge defines 8 task statuses with specific semantics:
Meaning: Not ready for work, needs triage or planningTypical Use:
  • Ideas from brainstorming
  • Tasks awaiting priority assignment
  • Work that needs breaking down
Transitions To: OPEN, DEFERRED, CLOSED
const task = await api.create({
  type: 'task',
  title: 'Investigate performance issue',
  status: 'backlog', // Default
  priority: 3,
  createdBy: directorId,
});
Meaning: Ready for work, can be assignedTypical Use:
  • Tasks in the ready queue
  • Available for worker assignment
  • All dependencies resolved
Transitions To: IN_PROGRESS, BLOCKED, DEFERRED, CLOSED
await api.updateStatus(taskId, {
  status: 'open',
});
Meaning: Currently being worked onTypical Use:
  • Worker actively executing
  • Code changes in progress
  • Has assignee
Transitions To: OPEN, REVIEW, BLOCKED, DEFERRED, CLOSED
await api.updateStatus(taskId, {
  status: 'in_progress',
});
Meaning: Waiting on dependency
CRITICAL: Never set status: 'blocked' manually! This status is computed from dependencies.
Auto-Set When:
  • A blocking dependency is added
  • A blocker task is reopened
Auto-Cleared When:
  • All blocking dependencies are resolved
Transitions To: OPEN, IN_PROGRESS, DEFERRED, CLOSED
// This makes task B blocked automatically
await api.addDependency({
  blockerId: taskAId,  // Must complete first
  blockedId: taskBId,  // Will be blocked
  type: 'blocks',
  createdBy: directorId,
});
Meaning: Deliberately postponedTypical Use:
  • Low priority work
  • Waiting for external factors
  • Paused for later consideration
Transitions To: OPEN, IN_PROGRESS, BACKLOG
await api.updateStatus(taskId, {
  status: 'deferred',
});
Meaning: Work complete, awaiting mergeTypical Use:
  • Code complete and pushed
  • Waiting for merge steward
  • Tests need to run
Transitions To: CLOSED, IN_PROGRESS, OPEN
await api.updateStatus(taskId, {
  status: 'review',
});

Priority System

Stoneforge uses a 5-level priority system where 1 is highest:

Priority 1: CRITICAL

Use for:
  • Production outages
  • Security vulnerabilities
  • Data loss bugs
  • Blocking incidents

Priority 2: HIGH

Use for:
  • Important features
  • Significant bugs
  • Customer-facing issues
  • Sprint goals

Priority 3: MEDIUM

Use for:
  • Standard work items
  • Planned features
  • Minor bugs
  • Default priority

Priority 4: LOW

Use for:
  • Nice-to-have improvements
  • Refactoring
  • Technical debt
  • Polish work
Use for:
  • Can be done when time permits
  • Future considerations
  • Long-term ideas

Setting Priority

// At creation
const task = await api.create({
  type: 'task',
  title: 'Fix login redirect',
  priority: 1, // CRITICAL
  taskType: 'bug',
  createdBy: directorId,
});

// Update existing task
await api.update(taskId, {
  priority: 2, // Downgrade to HIGH
});

Effective Priority

Stoneforge calculates effective priority considering:
  1. Base priority - The task’s assigned priority
  2. Deadline proximity - Boosts priority as deadline approaches
  3. Dependency depth - Increases priority for tasks blocking others
  4. Age - Slight boost for tasks waiting too long
import { sortByEffectivePriority } from '@stoneforge/quarry';

// Get tasks sorted by effective priority
const tasks = await api.list({ status: 'open' });
const sortedTasks = sortByEffectivePriority(tasks, {
  deadlineWeight: 0.3,
  dependencyWeight: 0.2,
  ageWeight: 0.1,
});
Gotcha: sortByEffectivePriority() mutates the array in place and returns the same reference.

Complexity Scale

Tasks can have a complexity rating (1-5) where 1 is simplest:
LevelNameTypical Scope
1TRIVIALSingle-line changes, typo fixes
2SIMPLESmall, well-defined changes
3MEDIUMModerate changes, some research needed (default)
4COMPLEXSignificant changes, multiple components
5VERY_COMPLEXLarge scope, architectural changes
const task = await api.create({
  type: 'task',
  title: 'Refactor authentication system',
  complexity: 5, // VERY_COMPLEX
  priority: 2,
  createdBy: directorId,
});

Task Types

Four built-in task type classifications:
Defect requiring fix
await api.create({
  type: 'task',
  title: 'Users can't login after password reset',
  taskType: 'bug',
  priority: 1,
  createdBy: directorId,
});

Task Assignment

Tasks can have two types of assignment:

Assignee vs Owner

Assignee

Who is currently working on it
  • Set automatically by Dispatch Daemon
  • Cleared on handoff
  • One assignee at a time
await api.update(taskId, {
  assignee: workerId,
});

Owner

Who is responsible for completion
  • Set manually by Director or human
  • Persists through handoffs
  • Accountability tracking
await api.update(taskId, {
  owner: teamLeadId,
});

Automatic Assignment

The Dispatch Daemon assigns tasks to available workers:
  1. Query ready tasks - OPEN status, no assignee, not blocked
  2. Sort by effective priority - Highest priority first
  3. Find available worker - Idle ephemeral workers
  4. Assign and dispatch - Send task details to worker
// This happens automatically when daemon is running
// Worker receives task via inbox with dispatch message

Manual Assignment

For persistent workers or special cases:
// Assign to specific worker
await api.update(taskId, {
  assignee: persistentWorkerId,
  status: 'in_progress',
});

// Worker can then check their assigned tasks
const myTasks = await api.list({
  assignee: workerId,
  status: ['open', 'in_progress'],
});

Task Handoff

When a worker cannot complete a task, they hand off to another worker:
1

Worker Initiates Handoff

sf task handoff abc123 --message "Completed API integration but hit CORS issue - needs infrastructure access"
2

System Updates Task

  • Clears assignee
  • Preserves worktree and branch in metadata
  • Appends handoff note to description
  • Records handoff in session history
3

Next Worker Continues

  • Daemon assigns to next available worker
  • Worker spawns in existing worktree
  • Sees previous work and handoff notes
  • Continues from where last worker stopped

Handoff Metadata

Handoff information is preserved in task metadata:
// Task metadata after handoff
{
  orchestrator: {
    handoffBranch: 'agent/worker-1/abc123-api-integration',
    handoffWorktree: '.stoneforge/.worktrees/worker-1-api',
    lastSessionId: 'sess-xyz789',
    handoffAt: '2026-03-02T10:30:00.000Z',
    handoffHistory: [
      {
        sessionId: 'sess-xyz789',
        message: 'Completed API integration...',
        branch: 'agent/worker-1/abc123-api-integration',
        handoffAt: '2026-03-02T10:30:00.000Z',
      },
    ],
  },
}

Handoff Notes in Description

Handoff messages are appended to the task’s description document:
## Original Description
Implement REST API for user authentication...

[AGENT HANDOFF NOTE]: Completed API integration. Unable to resolve CORS issue - requires infrastructure access. Branch contains working local implementation.

Scheduling and Deadlines

Tasks support two time-based fields:

Scheduled For

When the task becomes actionable:
const task = await api.create({
  type: 'task',
  title: 'Deploy to production',
  scheduledFor: '2026-03-15T09:00:00.000Z',
  priority: 2,
  createdBy: directorId,
});

// Task won't appear in ready queue until scheduled time

Deadline

External deadline constraint:
const task = await api.create({
  type: 'task',
  title: 'Q1 report generation',
  deadline: '2026-03-31T23:59:59.000Z',
  priority: 2,
  createdBy: directorId,
});

// Effective priority increases as deadline approaches

Acceptance Criteria

Define what “done” means for a task:
const task = await api.create({
  type: 'task',
  title: 'Implement password reset flow',
  acceptanceCriteria: `
- User receives email with reset link
- Link expires after 1 hour
- New password meets complexity requirements
- User can login with new password
- Old sessions are invalidated
  `,
  createdBy: directorId,
});
Workers receive acceptance criteria in their task dispatch message to guide execution.

Querying Tasks

By Status

// Ready for work
const readyTasks = await api.ready();

// Blocked by dependencies
const blockedTasks = await api.blocked();

// By specific status
const inProgressTasks = await api.list({
  status: 'in_progress',
});

By Assignment

// Tasks for specific worker
const workerTasks = await api.list({
  assignee: workerId,
});

// Unassigned and ready
const available = await api.list({
  status: 'open',
  assignee: null,
});

By Priority

// High priority tasks
const urgent = await api.list({
  priority: [1, 2], // CRITICAL or HIGH
});

Complex Queries

// Critical bugs in progress
const criticalBugs = await api.list({
  taskType: 'bug',
  priority: 1,
  status: 'in_progress',
});

// Overdue tasks
const overdue = await api.list({
  status: ['open', 'in_progress'],
}).then(tasks => 
  tasks.filter(t => 
    t.deadline && new Date(t.deadline) < new Date()
  )
);

Task Creation Patterns

Simple Task

const task = await api.create({
  type: 'task',
  title: 'Fix typo in README',
  priority: 4,
  complexity: 1,
  createdBy: directorId,
});

Task with Description

// Create description document first
const description = await api.create({
  type: 'document',
  title: 'Authentication Task Description',
  content: 'Implement OAuth 2.0...',
  contentType: 'text/markdown',
  createdBy: directorId,
});

// Create task referencing description
const task = await api.create({
  type: 'task',
  title: 'Implement OAuth authentication',
  descriptionRef: description.id,
  priority: 2,
  createdBy: directorId,
});

Task with Owner and Assignee

const task = await api.create({
  type: 'task',
  title: 'Code review for PR #42',
  owner: teamLeadId,
  assignee: seniorDevId,
  priority: 2,
  createdBy: directorId,
});

Next Steps

Dependencies

Learn how to block tasks and create relationships

Orchestration Loop

See how tasks are automatically dispatched

Workflows

Build multi-step task sequences

Agent Roles

Understand who creates and executes tasks

Build docs developers (and LLMs) love