Spec Workflow

How to create and manage specification documents in the swarm project.

Overview

Swarm uses a spec-first development process. Before implementing a feature or making significant changes, you write specification documents that capture the design, contracts, and invariants. These specs serve as the authoritative source of truth for implementation and are stored in specs/.

Why Specs First?

  1. Clarity — Forces you to think through the design before writing code
  2. Reviewability — Easier to review a design document than a large code PR
  3. Agent-friendly — AI agents can read specs to understand what to implement
  4. Traceability — Each implementation task links back to its spec

Spec Categories

The specs/ directory contains three categories of documents:

Architecture Decision Records (ADRs)

ADRs document significant architectural choices with rationale. They live in docs/src/adr/ and are numbered sequentially:

docs/src/adr/
  001-tokio-async.md
  002-sqlite-messaging.md
  003-agent-backend-trait.md
  ...

Write an ADR when you need to:

  • Choose between competing approaches (e.g., SQLite vs Redis for messaging)
  • Make a decision that affects the whole system (e.g., async runtime choice)
  • Document why something was done a certain way for future contributors

Contract Documents

Contracts define the precise interface and behavior of a module or subsystem. They're the most common spec type:

specs/
  contract-config-schema.md
  contract-agent-state-machine.md
  contract-mailbox-schema.md
  ...

A contract includes:

  • File location (which source files implement it)
  • Type definitions (structs, enums, traits)
  • Method signatures and behavior
  • Invariants and validation rules
  • Error handling

Plan Documents

Plans describe a multi-step implementation strategy. They're used for larger efforts that span multiple sessions:

specs/
  plan-sdk-integration.md
  plan-mailbox-migration.md

Writing a Spec

Step 1: Choose the Right Type

SituationSpec Type
Choosing between approachesADR
Defining a module's interfaceContract
Planning a multi-session effortPlan

Step 2: Create the File

Use a descriptive name with the appropriate prefix:

# Contract
touch specs/contract-my-feature.md

# ADR (in docs)
touch docs/src/adr/011-my-decision.md

Step 3: Write the Content

Contract Template

# Contract: [Feature Name]

## File Location

`swarm/src/my_module.rs`

## Overview

Brief description of what this module does and why it exists.

## Type Definitions

```rust
pub struct MyStruct {
    pub field: Type,
}

pub enum MyEnum {
    Variant1,
    Variant2 { data: String },
}

Methods

MethodSignatureDescription
new()fn new() -> SelfCreate instance
process()async fn process(&self, input: Value) -> Result<Output>Process input

Invariants

  1. [Rule that must always hold]
  2. [Another rule]

Error Handling

ErrorWhenRecovery
MyError::NotFoundItem doesn't existReturn error to caller
  • [Link to related spec or ADR]

#### ADR Template

```markdown
# ADR-NNN: [Title]

## Status

Accepted | Proposed | Superseded by ADR-XXX

## Context

What problem are we solving? What constraints exist?

## Decision

What did we decide?

## Consequences

### Positive
- Benefit 1
- Benefit 2

### Negative
- Tradeoff 1

### Neutral
- Observation

Step 4: File Tasks from the Spec

After writing the spec, create beads tasks that reference it:

bd create "Implement MyStruct per specs/contract-my-feature.md"
bd create "Add tests for MyStruct per specs/contract-my-feature.md"
bd create "Add MyStruct to registry per specs/contract-my-feature.md"

Break large specs into small, independently implementable tasks. Each task should:

  • Reference the spec file
  • Describe a specific deliverable
  • Be completable in a single session

The Full Workflow

1. Identify need       →  "We need feature X"
2. Write spec          →  specs/contract-feature-x.md
3. Review spec         →  Get feedback, iterate
4. File tasks          →  bd create "Implement X per specs/..."
5. Implement           →  Pick up tasks with bd ready
6. Verify              →  Check implementation against spec
7. Update spec         →  If the implementation diverged, update the spec

Spec Conventions

Do

  • Be precise about types — Use real Rust type signatures, not pseudocode
  • Include invariants — Document rules that must always hold
  • List error cases — Every error variant with when it occurs
  • Link related specs — Cross-reference ADRs and other contracts
  • Keep specs updated — When implementation changes, update the spec

Don't

  • Don't write implementation code — Specs describe what, not how
  • Don't duplicate — Reference other specs instead of copying
  • Don't over-specify — Leave implementation details to the implementer
  • Don't write stale specs — Archive or update specs that no longer apply

Existing Specs

The specs/ directory currently contains 59 documents:

  • 10 ADRs — Major architectural decisions
  • ~46 contracts — Module interfaces and behavior
  • 3 plans — Multi-session implementation strategies

Use ls specs/ to see all spec files, or check specs/README.md for an index.