flow
plugin Β· agent-ops
The /flow workflow engine: a PM-agnostic, dual-mode (manual and autonomous) system that carries product work from capture to done across one stage spine, with a runnable-TypeScript engine and a pluggable tracker adapter.
What this package does
Adds slash commands
Files will be staged under .dork/marketplaces/dorkos/flow/
Adds skill files
Files will be staged under .dork/marketplaces/dorkos/flow/
Installs lifecycle hooks
Files will be staged under .dork/marketplaces/dorkos/flow/
The full permission preview, including external network hosts, is shown when you confirm install in DorkOS.
flow β the /flow engine
One unified, PM-agnostic workflow system spanning capture β done. A single identifiable installable unit: manual stages you drive from the terminal, and an autonomous loop seated on DorkOS Pulse.
This README is the manual. See SPEC.md for the contract (the
stage model, the PMClient promotion surface, the config schema, the FlowRun
record, and the typed engine), CHARTER.md for the 15 goals the
system is audited against, and the published guide series
on dorkos.ai for the user-facing reference. These three docs and the guides ship
with the package (charter G15), under docs/.
[!IMPORTANT] Autonomous mode depends on a running DorkOS server (Pulse). Manual mode does not.
/flow,/flow:<stage>, and/flow auto(terminal draining) run without the server. The autonomous Pulse-seated loop (${CLAUDE_PLUGIN_ROOT}/skills/flow-drain/) requires the DorkOS server running to host the chokidar watcher + croner.
Installing
Install the plugin from the marketplace, then run /flow:init β it picks your
tracker, generates and conformance-gates the adapter for it, and scaffolds the
config triad.
The engine oracles under scripts/ run on node --experimental-strip-types and
need one npm package, zod. /flow:init checks for it and offers to install
it; to do it yourself, from this directory:
--omit=dev is worth stating explicitly: a shell carrying NODE_ENV=production
installs nothing from a bare npm install, which leaves the engine unable to run
its own oracles. Contributors working on the plugin want --include=dev instead,
which adds the Vitest engine-oracle suite, tsc, Prettier, and the
config.schema.json generator.
Stages
One canonical spine β the unit of "where work is." Spec status, tracker state, labels, and loop phase are all projected from the stage by the adapter, never authored independently.
- CAPTURE β quick, low-commitment intake of a raw thought as an
idea. Does not evaluate or classify. (capturing-work) - TRIAGE β classify freeform input into a type, or evaluate a captured item
(accept / reject / needs-research / needs-refinement) and make the
simple-vs-complex routing call. (
triaging-work) - IDEATE β shape a complex brief into a structured ideation artifact.
(
ideating-features) - SPECIFY β turn ideation into a frozen specification + draft ADRs.
(
specifying-work) - DECOMPOSE β break the spec into
03-tasks.jsontasks (mirrored to the tracker as a checklist; promote a sub-issue only atsize β₯ "xl"). (decomposing-work) - EXECUTE β implement the tasks across dependency-aware batches in an
isolated worktree. (
executing-specs) - VERIFY β run the touched surface, capture proof-of-completion evidence,
open the PR, and hand off to review. (
verifying-work) - REVIEW β the human gate. The engine parks here; there is no skill and no command. On approval + green CI it resumes into DONE.
- DONE β close the work, create follow-ups, run the project-pulse check, and
tear down the worktree. (
closing-work) - MONITOR / SIGNAL β the optional tail that keeps the loop spinning.
Match on a tracker state's category (backlog | unstarted | started | completed | canceled), never its display name β that is what keeps the
system portable across teams and trackers.
Modes
The trigger source is orthogonal to the execution mode β a 2Γ2, not a single axis:
- Manual + Step β
/flow:<stage>advances one stage and stops. Questions arrive interactively. Server-free. - Manual + Autonomous β
/flow autodrains the ready queue sequentially from the terminal, carrying each item to its review gate. Server-free. - PM-driven + Step β rare; an explicit single-stage advance triggered by a tracker transition.
- PM-driven + Autonomous β the default seat: a Pulse tick claims the top-ranked eligible item and carries it to its gate in a fresh per-item session. Requires the DorkOS server (see below).
Every stage is autonomous-capable. The human is pulled in by uncertainty (the calibration ladder), not by stage β which is why IDEATE asks freely while EXECUTE asks rarely, as an emergent property of one rule.
Command β state map
Each /flow:<stage> command is a thin trigger (β€ ~40 LOC) over the stage
skill. A PM transition into a stage and the slash command are two triggers for
the same skill. The mapping is generated from config.json
stages:
/flow (no stage) is the orchestrator: it resolves a stage name, a work item, a
project (by name, spec slug, or umbrella id), or auto, then routes to the matching
command. Naming a project routes by its state: project-scoped single-item dispatch when it
has agent/ready children, or advancing its umbrella one stage when it has none yet
(/flow auto|continue <project> narrow the queue modes to that one project). With no
arguments at all, it offers four intents: Capture new Β· Work on a project (pick
from the active projects) Β· Continue the queue (claim the next-ranked item, carry it to
its gate, then stop) Β· Triage the backlog, with a specific item or auto (drain the
whole queue) reachable as free text. "Continue the queue" is one tick of auto.
Beside the stages sits the whole-backlog sweep: /flow:groom
(grooming-backlog) audits every open item against the fourteen groom
invariants (scripts/audit-backlog.ts), closes shipped/duplicate/junk work
with cited evidence behind a human gate, reconciles projects with reality, and
applies the readiness gate honestly β then proves the result with a
before/after run of the dispatch oracle. /flow:groom check is the read-only
audit half. Run it when the queue starves, after a large programme lands, or
before turning on autonomy: the dispatch policy is only as truthful as the
labels it reads, and a ready label nobody audits decays into noise.
Gates
Involvement is uncertainty-gated, not stage-gated (the calibration ladder, spec Β§5). The hard gates:
- Question / soft-escalation β any stage, dynamic; driven by the calibration ladder. Row 0 (the floor) always stops for irreversible/destructive, outward-facing, secrets/spend/prod, or material-scope-change actions, even at full confidence.
- Plan-approval gate (after DECOMPOSE) β off by default
(
gates.planApproval: false). The engine flows DECOMPOSE β EXECUTE and surfaces plan assumptions at the review gate. Flip it on for a pre-code checkpoint. - Human-review gate (after VERIFY) β always on. PR + evidence β review
state β assign the human β stop. On approval + green CI β auto-merge + close +
teardown. v1 caveat: the engine parks here and does not detect approval
β merge the approved PR yourself, then run
/flow:done <issue>to close the item and tear down the worktree. The merge-decision logic (evaluateAutoMerge, Β§6 below) is built + tested; the detection + execution that fires it unattended (poll/webhook-driven resume-on-approval) is the P2 server Extension. - Circuit breaker β stop + escalate if a unit exceeds
estimate Γ Nwall-clock or the token budget.
Auto-merge recovery ladder (spec Β§6): approval authorizes one specific state β this diff, green, cleanly mergeable. If that state can't be reproduced at merge time, the engine checks mergeable? Β· CI green? Β· functionally unchanged? and routes each failure through the calibration ladder (mechanical conflict β resolve
- announce; real tradeoff β bounce; behavior drift β re-request approval).
Adapter interface
The tracker adapter skill is the v1 PMClient: it owns every tracker
call over a config-driven transport (connection.transport: an account-pinned
CLI or an in-session MCP server) and fulfils the capability verbs as a
documented prose contract. Generic stage skills and commands call it by naming
a verb (e.g. "via the adapter, transition the item β¦") and never touch a tracker
string β a grep guard enforces zero tracker API strings outside the adapter.
Which adapter is a config value, not a code path. tracker in config.json
is an adapter slug, and it names the skill directory the engine reads:
skills/<tracker>-adapter/SKILL.md. This repo ships linear-adapter as the
reference adapter, and linear is the default; /flow:init generates the adapter
for any other tracker you pick and gates it on the same conformance harness, so
adopting Jira or GitHub Issues is a setup run, not a fork.
The verbs: getCurrentUser, getProjects, resolveProject, getProject,
getProjectWork, getEligibleWork, getInbox, getRelations, claim,
transition, comment, assignToHuman, attachEvidence, needsInput, link,
createSubIssue, plus the contract's one optional verb, completeProject
(this adapter supports it; another tracker's adapter may not, and callers
degrade rather than fail when it is absent). The adapter normalizes
every tracker into one WorkItem shape so the dispatch policy and stage skills
never see a tracker-specific field. Full verb contract: the reference adapter's
SKILL.md and the tracker-neutral
adapters/SPEC.md; the typed interface PMClient
the P5 server build promotes it into is in SPEC.md.
The adapter also owns the display convention: every work item shown to a human
is rendered as PROJ-157 - Title (identifier first, the identifier linked where the
surface supports it), never a bare key.
Autonomous mode & the server dependency
The autonomous loop is seated on DorkOS Pulse via a file-based schedule
(${CLAUDE_PLUGIN_ROOT}/skills/flow-drain/SKILL.md). Pulse already provides a contextless
code-loop (croner) that dispatches a fresh, isolated, resumable, runtime-agnostic
agent session per run β so there is no scheduler to build.
- One tick = one issue. Each croner fire is a fresh run-session
(
sessionId = run.id) that claims and works exactly one issue to its gate, then ends β preserving fresh-session-per-issue. - Activation is install at project scope, then approve. The
schedule:block inskills/flow-drain/SKILL.mdis what makes the file a scheduled task; a DorkOS release that has schedule discovery reads it straight out of the skills roots it watches, with nothing copied by hand, and the tick waits on the Schedules page until you approve it β installing a package can never arm its own cron. On a DorkOS build without schedule discovery, or on any other harness, wire an external scheduler instead (seedocs/bring-your-own-scheduler.mdx). Running it still needs the DorkOS server (it hosts the watcher + croner) and the project's DorkOS agent registered. No build step, no migration; edits to the file are picked up live. - Crash/stall recovery is driven by the durable
FlowRunrecord + the next-tick recovery ladder (spec Β§12): aneeds-inputitem is never reclaimed; an orphanedagent/claimeditem is adopted + resumed (re-attach the worktree at HEAD, resume the session) or restarted clean, withattemptCountguarding against runaway retries.
Autonomous mode depends on a running DorkOS server (Pulse); manual mode does not. A generic
claude -p-per-issue watcher seat (for non-DorkOS repos) is designed but not built in v1 β soautonomy.seataccepts onlypulsetoday, andwatcherrejoins the enum when the seat ships. (The "watcher" is the external poller that fires a headlessclaude -ptick per issue β not a prompt.)
Configuration
Defaults live in config.json, validated against the
Zod-generated config.schema.json (authored as the
@dorkos/flow FlowConfigSchema, bridged via z.toJSONSchema). The resolved
defaults encode the key decisions: planApproval: false, subIssueThreshold: "xl",
perIssue: "fresh-session", seat: "pulse". See SPEC.md β
Config schema reference for the full contract.
tracker is an adapter slug, not a fixed list: it names the skill directory
the engine reads (skills/<tracker>-adapter/), so it accepts any lowercase slug
(^[a-z][a-z0-9-]*$) /flow:init has generated a conforming adapter for. It
defaults to linear, the reference adapter shipped here. Full detail:
config/CONFIG.md.
A per-repo WORKFLOW.md override at the repo root is part of the config
contract (Decision #15), but v1 reads .agents/flow/config.json only β
applying the override is the promoted config loader's job (DOR-90 / the P5 server
build), not the v1 harness skills. A WORKFLOW.md will not take effect yet.
Templates
The system owns a template set under templates/,
loaded by skills (not projected to any harness):
templates/records/β tracker work-item bodies by type (ideaΒ·researchΒ·hypothesisΒ·taskΒ·project), each with## Validation criteria+## On Completion.templates/docs/β the filesystem doc scaffolds (ideation Β· specification Β·03-tasks.jsonΒ· ADR).templates/pr.mdβ the PR template the VERIFY stage fills at the review gate.
Install
dorkos install flowOr browse the catalog inside DorkOS at /marketplace.