Skip to content

flotilla

npm Verify License

Portable, Claude-Code-native wave-orchestration toolkit. Plan a batch of independently-grabbable issues, dispatch parallel AFK agents in isolated worktrees, review each with a schema-validated verdict, land via PRs — with cross-wave conflict/parallelism reasoning as the universal core.

Stable. The orchestration has been driving flotilla's own development across fifty-plus live waves, and runs in installed form — plugin plus published engine — in independent consumer repos beyond this one, operated by more than one person. Three surfaces are semver contracts: the engine's package-root export surface, the wave.config.json schema (both since 1.0.0), and the CLI's output surface (since 1.1.0). CHANGELOG.md names what each release added and what remains unproven.

What flotilla is

flotilla turns a backlog of tracker issues into a wave: a batch of independently-grabbable work items that a Coordinator plans, then dispatches to parallel AFK (away-from-keyboard) agents, each isolated in its own git worktree. Every agent's work is reviewed by a second, universal Reviewer agent before anything lands — the review returns a schema-validated verdict, not free prose, so routing to approve / request-changes / stop is deterministic rather than inferred. Landing happens via pull requests against a protected default branch; nothing is ever pushed directly to it.

Quickstart

Prerequisites: Node 20.11 or newer (the engine's declared floor), git, a repository on GitHub or Bitbucket Cloud whose default branch is protected, and a tracker token resolvable through a lookup command.

flotilla installs as two pieces — the skills as a Claude Code plugin, the engine from the public npm registry — and nothing is copied into your repo. In Claude Code, inside the repo you want to run waves in:

  1. Install the plugin:

    /plugin marketplace add formtrieb/flotilla
    /plugin install flotilla@formtrieb
    
  2. Run the wave-setup skill. The one-time bootstrap: it interviews you on three things (your tracker, the label set that marks an issue agent-ready, your build/test commands), installs the engine pinned into your repo, and writes wave.config.json — the single binding every other skill reads (ADR-0032). It also does the unglamorous parts for you: scaffolds the credential lookup so no token ever lands in a settings file, writes the permission allowlist a wave needs to run unattended, and preflights the live tracker and code-host preconditions before you ever plan a wave. Fix anything the preflights flag before continuing.

  3. Get a few issues wave-ready. triage works an existing issue into shape, or to-issues slices a plan/PRD into ready issues — each carrying a declared file scope, a risk/worker classification, and acceptance criteria. Hand-authoring in the same shape works too.

  4. Run the wave: wave-plan shows what can run side by side (read-only — you pick the ids), wave-create materializes the batch, wave-start dispatches one isolated Worker per issue plus a Reviewer per Worker. It ends with every row as an open, reviewed PR — flotilla never merges on its own.

  5. Land the PRs, then wave-close. It computes the advisory merge order, cleans up the agent worktrees, and archives the wave's record. Session died mid-wave? wave-resume picks up exactly where it stopped.

The full adoption path — every step above in detail, plus the preconditions that fail silently if skipped — is docs/ONBOARDING.md. Read its checklist before your first real wave.

Five terms that carry the rest

The docs use a precise vocabulary; these five are enough to read everything else. The full glossary is CONTEXT.md.

Term What it is
Wave One batch of independently-grabbable issues, dispatched to parallel agents in isolated worktrees, reviewed, and landed via PRs.
Conflict map Pure set-intersection over each issue's declared file globs — answers before dispatch which work can safely run in parallel, both inside a wave and against what other waves already claimed.
Claim The coarse state a wave writes to your tracker (queued → in-flight → in-review) so humans and concurrent waves can see what is taken. One-way: the tracker is a projection, never the authority.
Spine The wave's durable, repo-local markdown record — a write-ahead log. It is what makes a killed Coordinator resumable.
Reviewer The independent, read-only agent that re-runs your verify commands and checks every acceptance criterion before a PR opens, returning a schema-validated verdict — the ground truth for whether the work is actually done.

Capabilities, in three lines: GitHub Issues and Linear both ship full tracker adapters — claim ledger, needs-attention, frontier — with Linear alone able to mirror that frontier back as a native Project/Initiative update. GitHub and Bitbucket Cloud both create and land PRs through the engine's own host-pr seam, never gh. Only GitHub can arm a PR to land itself once checks go green — Bitbucket Cloud's API has no per-PR auto-merge call, so --auto there merges what's already clean and leaves the rest for a human. The full dated, per-cell matrix: docs/CAPABILITIES.md.

The pipeline

flowchart LR
    setup["wave-setup<br>one-time bootstrap"]
    subgraph planning["Planning"]
        direction LR
        g["goal<br>the finish line"] --> t["triage"] --> p["to-prd"] --> i["to-issues"]
    end
    subgraph lifecycle["Wave lifecycle"]
        direction LR
        wp["wave-plan"] --> wc["wave-create"] --> ws["wave-start<br>Workers + Reviewers"] --> wx["wave-close"]
        wr["wave-resume"] -. "Coordinator died?<br>reconcile + re-dispatch" .-> ws
    end
    setup --> planning --> lifecycle
Loading
Skill Phase What it does
wave-setup Bootstrap, once per repo Interviews you on tracker, eligibility labels, and verify commands; installs the engine and writes wave.config.json — the one engine.cli binding every other skill reads.
goal Planning Manages a named finish line as a container on your tracker: cuts its opening frontier as bare placeholder tickets, curates who belongs, and reports what is still open. Read-only status pass; it never stamps readiness, never dispatches, and never declares the goal reached.
triage Planning Works an incoming issue into shape: categorize, reproduce, gather what's missing, mark it ready for an agent or a human.
to-prd Planning Captures a design conversation as a PRD, published as a tracker issue ready for slicing.
to-issues Planning Slices a plan or PRD into independently-grabbable, wave-eligible issues — each with a declared file scope, risk/worker classification, and acceptance criteria.
wave-plan Wave lifecycle Draws the wave-eligible candidate set and cross-checks it against what other waves already claimed. Read-only and advisory — you pick the ids.
wave-create Wave lifecycle Materializes the chosen ids into a durable spine (a write-ahead log) after DoR and conflict checks; sets the soft queued claim on each issue.
wave-start Wave lifecycle Dispatches a worktree-isolated Worker per row, then a universal Reviewer per Worker; routes each schema-validated verdict deterministically. Ends with every row in-review — it never merges.
wave-close Wave lifecycle Computes the advisory merge order, cleans up agent worktrees, archives the spine. Opt-in --auto arms the order-free PRs for auto-merge.
wave-resume Wave lifecycle Reconstructs a killed Coordinator's state from the spine, the live worktrees, and on-disk sidecars; re-dispatches only what actually needs it.
wave-reviewer Wave lifecycle The read-only pre-PR quality gate wave-start dispatches for every row: re-runs verify against the wave anchor, checks each acceptance criterion with evidence, predicts sibling merge conflicts.
report Utility, consumer-side Files a fully-analyzed finding about flotilla itself — found while running the installed plugin/engine in your repo — upstream at flotilla's repo in the house format. Consent-first: it never files without your explicit go.
grill-with-docs Utility Stress-tests a design decision against the domain model and the ADRs before it's built, updating the docs inline as decisions settle.
wave-shared Library The shared schemas and conventions the execution skills load; invoked by its siblings, never directly.

The thing that stays true regardless of stack or tracker is the conflict/parallelism reasoning: every issue declares the file globs it touches, and a pure set-intersection over those globs answers "how much work goes into one wave, and can two waves run side by side?" Everything else — which tracker, which verify commands, which code host — is an adapter around that core.

Architecture in one screen

flotilla is two layers: a pure engine that is already harness-agnostic, and adapters that diverge freely per consumer.

flowchart TB
    subgraph skills["Claude Code skills — the dispatch driver"]
        S["wave-* · goal · triage · to-prd · to-issues · report"]
    end
    subgraph engine["Engine (tools/wave) — pure TypeScript, imports only node:* + fast-glob + micromatch"]
        CM["computeConflictMap<br>glob-set math"]
        SM["state machine<br>+ DoR gate"]
        MO["merge-order<br>algorithm"]
        SCH["WorkerReport /<br>ReviewerVerdict schemas"]
    end
    subgraph stores["IssueStore adapters — one conformance suite, unchanged across all three"]
        MD["MarkdownFsStore"]
        GH["GitHubIssuesStore"]
        LN["LinearIssuesStore"]
    end
    SP["SpineStore<br>per-wave spine as local markdown (WAL)"]
    S -->|"engine.cli<br>(setup-time binding, ADR-0032)"| engine
    engine -->|"IssueView"| stores
    engine --> SP
Loading
Seam What it is
IssueView The canonical contract. Every adapter's whole job is read(id) → IssueView (id, risk, worker, declared files, blocked-by, acceptance criteria, coarse status) — the engine never knows which tracker an issue came from.
IssueStore create · read · transition · close · listOpen, plus facets for triage state, needs-attention flagging, closing-probe reads, minimal authored-content amends, and the Goal container whose frontier is derived rather than written.
SpineStore The per-wave orchestration spine as durable local markdown — the write-ahead log a killed Coordinator resumes from.
Two-scope state Fine-grained states live only in the spine. The tracker sees a coarse projection — available → queued → in-flight → in-review → done, plus an orthogonal needs-attention flag — so humans and concurrent waves can see what is claimed.
Conflict map computeConflictMap is wave-agnostic pure glob-set math: feed it (candidate wave) ∪ (everything queued or in-flight) and it answers directly whether two waves can run side by side.

Two properties worth knowing before you read further: the engine ships as raw TypeScript with no build step (tsc --noEmit is the type gate), and its public API is a deliberate, drift-guarded list — every module export is either deliberately public at the package root or on a reason-carrying allowlist, and a symbol in neither fails the test suite. There is deliberately no dispatch-host abstraction: the engine calls no agent-harness primitives; the Claude Code skills are the dispatch driver, and the schema-validated-subagent-return guarantee (agents cannot silently fabricate a result) is a property of that driver.

Going deeper

  • Adopting flotilla in your repodocs/ONBOARDING.md: the Quickstart above in full detail, the preconditions checklist, credential mechanics, and the vendor-copy fallback for repos that cannot install a plugin. Before the setup-time binding exists, npx @formtrieb/flotilla-engine prints the engine's verb list (exploration only — unpinned and slow; wave-setup replaces it with the pinned binding).
  • Why it works this waydocs/CHARTER.md for the architecture, docs/adr/ for the individual decisions with the options that were rejected and why.
  • The vocabulary in fullCONTEXT.md, the domain glossary.
  • Contributing to flotilla itself? Start with CLAUDE.md. Cutting a release? docs/RELEASING.md.

License & provenance

flotilla is licensed under Apache-2.0. Parts of it were seeded from other sources under their own terms — see PROVENANCE.md for the seed points and the retained upstream notices.

About

Portable, Claude-Code-native wave-orchestration toolkit — plan a batch of independently-grabbable issues, dispatch parallel AFK agents in isolated worktrees, review each, land via PRs.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages