Attractor — workflow dashboard

10 valid · 2 invalid fixtures · generated 2026-05-15T23:05:13Z

Filter by REQ tag (AND)

Valid workflows (10)

failure-no-route.dot

source

Demonstrates the "fail-fast, no fix-up loop" pattern.

REQ-DOD-VALIDATE-ERRORSREQ-EXEC-EDGE-ROUTING
description
Demonstrates the "fail-fast, no fix-up loop" pattern.

Per SPEC §6.1, when a node reports FAILURE the engine requires an
explicit `label="FAILURE"` outgoing edge to continue; if none
exists the run ends with status `incomplete`. The last paragraph
of §6.1 spells this out as a legitimate design choice:

    Terminating on failure (run ends `incomplete`, `captured_output`
    preserved on the worktree branch for inspection) is a legitimate
    workflow design: not every author wants fix-up loops everywhere.

So this is NOT an invalid graph — it parses, it validates, it
describes a workflow where any verify failure ends the run cleanly
for human triage. The fixture lives at `workflows/` (not under
`invalid/`) to make that explicit.

`attractor validate workflows/failure-no-route.dot` MUST accept
the graph. The "missing FAILURE edge" condition is a runtime
check, not a structural one (§6.1 last paragraph).

REQs exercised: REQ-EXEC-EDGE-ROUTING (the runtime side: SUCCESS
may take the unlabeled default edge; FAILURE without a labeled
edge ends the run incomplete). The validator-time piece of
REQ-DOD-VALIDATE-ERRORS is covered by the genuinely-invalid
fixtures still under `workflows/invalid/`.
FailureNoRoute start Start implement Implement start->implement exit Exit verify Verify implement->verify verify->exit

github-issue.dot

source

Fetch and implement a GitHub issue, then verify with Python checks.

REQ-EXEC-EDGE-ROUTINGREQ-EXEC-GOAL-GATESREQ-EXEC-REVISIT-CONTEXTREQ-EXEC-RUN-ARGUMENTSREQ-EXEC-VERIFY-FIXUP-IDIOMREQ-HUMAN-GATE
description
Fetch and implement a GitHub issue, then verify with Python checks.

Requirements:
  gh must be installed and authenticated in the run environment.

Outputs:
  issue.json - raw metadata from `gh issue view`.
  issue.md   - normalized issue title/body/metadata for agent nodes.

Run:
  uv run attractor run workflows/github-issue.dot https://github.com/<owner>/<repo>/issues/<number>

Expected behaviour:
  start -> fetch_issue -> plan -> approve_plan -> implement -> verify
  verify SUCCESS -> approve_diff -> exit
  verify FAILURE -> fixup -> verify

REQs exercised: REQ-EXEC-RUN-ARGUMENTS, REQ-HUMAN-GATE,
REQ-EXEC-VERIFY-FIXUP-IDIOM, REQ-EXEC-GOAL-GATES,
REQ-EXEC-EDGE-ROUTING, REQ-EXEC-REVISIT-CONTEXT.
GitHubIssue start Start fetch_issue Fetch issue with gh start->fetch_issue exit Exit plan Plan issue work fetch_issue->plan SUCCESS approve_plan Approve plan? plan->approve_plan SUCCESS revise_plan Revise plan plan->revise_plan FAILURE approve_plan->revise_plan revise implement Implement approve_plan->implement approve revise_plan->approve_plan verify Verify Python checks implement->verify fixup Fix verification failure verify->fixup FAILURE approve_diff Approve final diff? verify->approve_diff SUCCESS fixup->verify approve_diff->exit approve approve_diff->implement revise

implement.dot

source

Implement a feature described in goal.md, verify with pytest + ruff + pyright.

description
Implement a feature described in goal.md, verify with pytest + ruff + pyright.

Inputs (placed in the run worktree before launch):
  goal.md  — what to build (issue body, SPEC excerpt, free-form)

Outputs (left on the worktree branch refs/heads/attractor/run/<id>/worktree):
  plan.md         — implementation plan, written by `plan` node
  <code edits>    — committed at each successful node boundary (§6.4)

Run:   attractor run workflows/implement.dot --input goal.md=path/to/goal.md
Diff:  git diff main..attractor/run/<run-id>/worktree
Implement start Start plan Plan start->plan exit Exit approve_plan Approve plan? plan->approve_plan approve_plan->plan revise implement Implement approve_plan->implement approve verify Verify (pytest + ruff + pyright) implement->verify fixup Fix verify->fixup FAILURE approve_diff Approve final diff? verify->approve_diff SUCCESS fixup->verify approve_diff->exit approve approve_diff->implement revise

multi-gate.dot

source

A workflow with three human gates including a revise loop. The middle

REQ-CLI-RUN-LIFECYCLEREQ-EXEC-EDGE-ROUTINGREQ-EXEC-REVISIT-CONTEXTREQ-HUMAN-GATE
description
A workflow with three human gates including a revise loop. The middle
gate expects the user to supply `--reason <text>` when choosing `revise`
(§11); the rewrite agent reads that reason out of its entry-edge context
as `predecessor_reason` (§6.3) and uses it to steer the rewrite.

Inputs (placed in the worktree before launch):
  brief.md — what to draft.

Expected behaviour:
  start -> draft -> gate_outline -> gate_review (revise/--reason loops
  back to rewrite -> gate_review) -> gate_publish -> exit.

Three gates total:
  gate_outline   — approve/revise (no reason needed; revise loops to draft)
  gate_review    — approve/revise; revise expects --reason; loops via rewrite
  gate_publish   — approve/abandon; abandon ends the run incomplete is OK
                   because no goal_gate=true node exists; here run completes
                   cleanly via exit either way.

REQs exercised: REQ-HUMAN-GATE, REQ-EXEC-REVISIT-CONTEXT
(predecessor_reason on visit 2 of `rewrite`), REQ-EXEC-EDGE-ROUTING,
REQ-CLI-RUN-LIFECYCLE (run respond --reason).
MultiGate start Start draft Draft outline start->draft exit Exit gate_outline Outline OK? draft->gate_outline gate_outline->draft revise expand Expand to full draft gate_outline->expand approve gate_review Review draft expand->gate_review rewrite Rewrite per reviewer reason gate_review->rewrite revise gate_publish Publish? gate_review->gate_publish approve rewrite->gate_review gate_publish->exit abandon publish Publish gate_publish->publish approve publish->exit

parallel-agents-merge.dot

source

Parallel agents + agent merge pattern (SPEC §6.10.3).

description
Parallel agents + agent merge pattern (SPEC §6.10.3).

Three agents work independently on separate modules; a merger agent
combines their branch refs into the main worktree; verification
confirms the merged result.

Run: attractor run workflows/parallel-agents-merge.dot
ParallelAgentsMerge start Start plan Plan start->plan exit Exit fanout fanout plan->fanout agent_a Refactor module A fanout->agent_a a agent_b Refactor module B fanout->agent_b b agent_c Refactor module C fanout->agent_c c join join agent_a->join agent_b->join agent_c->join join->exit FAILURE merger Merge branches join->merger SUCCESS verify Verify merged result merger->verify verify->exit SUCCESS fixup Fix merge issues verify->fixup FAILURE fixup->verify

parallel-verifiers.dot

source

Parallel verifiers + fixup pattern (SPEC §6.9.5).

description
Parallel verifiers + fixup pattern (SPEC §6.9.5).

Runs pytest, ruff, and pyright concurrently; if any fail the fixup
agent reads the combined captured output and loops back.  The join's
max_visits=3 bounds the retry loop at 3 verification attempts.

Run: attractor run workflows/parallel-verifiers.dot
ParallelVerifiers start Start implement Implement start->implement exit Exit fanout run verifiers implement->fanout tests Run tests fanout->tests tests lint Lint fanout->lint lint typecheck Type-check fanout->typecheck typecheck join all green? tests->join lint->join typecheck->join join->exit SUCCESS fixup Fix join->fixup FAILURE fixup->fanout

preflight.dot

source

Two verify/fixup pairs surrounding the implementation stage, per §6.6's

REQ-EXEC-GOAL-GATESREQ-EXEC-MAX-VISITSREQ-EXEC-REVISIT-CONTEXTREQ-EXEC-VERIFY-FIXUP-IDIOM
description
Two verify/fixup pairs surrounding the implementation stage, per §6.6's
"preflight verify before implementation, final verify before exit" idiom.
Each verify is goal_gate=true and has its own FAILURE→fixup→verify loop
bounded by max_visits.

Inputs (placed in the worktree before launch):
  goal.md — feature description.

Expected behaviour:
  start -> preflight -> [preflight_fixup loop if env broken] -> implement
         -> verify -> [fixup loop if tests/clippy fail] -> exit
  With max_visits=4 on each verify node, each loop bounds at 4 verify
  executions + 3 fixup executions before run ends `incomplete` (§6.3
  worked example).

REQs exercised: REQ-EXEC-VERIFY-FIXUP-IDIOM, REQ-EXEC-GOAL-GATES,
REQ-EXEC-MAX-VISITS, REQ-EXEC-REVISIT-CONTEXT (fixup reads verify's
captured_output via the FAILURE-edge payload).
Preflight start Start preflight Preflight (toolchain) start->preflight exit Exit preflight_fixup Repair toolchain / inputs preflight->preflight_fixup FAILURE implement Implement preflight->implement SUCCESS preflight_fixup->preflight verify Final verify (test + clippy) implement->verify verify->exit SUCCESS fixup Fix verify->fixup FAILURE fixup->verify

stylesheet-cascade.dot

source

Exercises §10's specificity rules end-to-end.

REQ-EXEC-CONFIG-CASCADEREQ-ROUTING-STYLESHEET
description
Exercises §10's specificity rules end-to-end.

  Stylesheet (most-specific last for readability, but specificity is by
  selector type, not source order):
    *               { model: claude-haiku-4-5;  reasoning_effort: low;  }
    .heavy          { model: claude-sonnet-4-6; reasoning_effort: high; }
    .heavy          { reasoning_effort: medium; }   // last-wins within bucket
    #critical_node  { model: claude-opus-4-7; }

  Plus one per-node `model="..."` attribute that overrides the stylesheet.

Expected effective config per node (assuming the engine resolves
stylesheet even on non-agent nodes but applies model/reasoning_effort
only to agents, per §10):

  universal_node       model=haiku-4-5,  reasoning_effort=low
                       (only universal selector matches)

  classed_node         model=sonnet-4-6, reasoning_effort=medium
                       (.heavy beats *; the second .heavy rule
                       overrides reasoning_effort within the class
                       bucket via last-wins)

  critical_node        model=opus-4-7,   reasoning_effort=medium
                       (#id beats .class beats *; opus from id rule.
                       reasoning_effort: §10 ¶2 last-wins-per-
                       declaration applies inside the .heavy bucket,
                       so the second .heavy rule rewrites it to
                       medium; #critical_node does not set
                       reasoning_effort and so cannot recover the
                       earlier `high`.)

  override_node        model=gpt-5.2,    reasoning_effort=high
                       (per-node `model=` beats stylesheet; class
                       contributes reasoning_effort=medium then the
                       per-node attr does not touch effort... but
                       per-node `reasoning_effort=high` here makes
                       the override explicit)

Inputs:  none.
Expected behaviour: linear traversal, all four agent nodes invoked with
the model resolved per the cascade above.

REQs exercised: REQ-ROUTING-STYLESHEET (universal, class, id; specificity;
last-wins within bucket; per-node override), REQ-EXEC-CONFIG-CASCADE
(graph defaults → stylesheet → per-node attrs).
StylesheetCascade start Start universal_node Universal selector only start->universal_node exit Exit classed_node Class selector wins over universal universal_node->classed_node critical_node ID selector wins over class + universal classed_node->critical_node override_node Per-node attributes beat all selectors critical_node->override_node override_node->exit

tool-only.dot

source

A workflow with zero agent (box) nodes — only tool (parallelogram) and

REQ-DOT-ATTRIBUTES-V01REQ-DOT-SHAPE-HANDLERSREQ-EXEC-EDGE-ROUTINGREQ-EXEC-GOAL-GATESREQ-EXEC-LOCAL-ENVREQ-EXEC-NODE-LIFECYCLEREQ-EXEC-TOOL-CAPTUREREQ-HUMAN-GATE
description
A workflow with zero agent (box) nodes — only tool (parallelogram) and
human (hexagon) handlers. Exercises traversal, goal_gate satisfaction,
FAILURE-edge routing, and human-gate routing without ever invoking the
LLM client. Useful as an integration-test fixture: runs with no provider
keys set.

Inputs:  none.
Outputs: `release.txt` and `build.log` left on the worktree branch.

Expected behaviour:
  start -> clean -> build -> test -> approve_release -> exit (happy path)
  On `test` FAILURE the run ends `incomplete` (no fixup loop here — the
  test node is goal_gate=true and there is no FAILURE→fixup→test loop).
  On `approve_release=reject` the run loops back to `build`.

Cross-shell contract: every `script` here uses only commands that behave
identically under `sh -c` (Unix) and `pwsh -NoProfile -Command` (Windows
per SPEC §6.8): `echo`, `cat`, `&&`, and `>` redirection. No `rm -rf`,
`test`, `[ ]`, or other POSIX-only builtins — they trip pwsh.

REQs exercised: REQ-DOT-SHAPE-HANDLERS (parallelogram, hexagon, Mdiamond,
Msquare), REQ-DOT-ATTRIBUTES-V01 (script, goal_gate, max_visits, label),
REQ-EXEC-NODE-LIFECYCLE, REQ-EXEC-EDGE-ROUTING (SUCCESS unlabeled default,
FAILURE explicit), REQ-EXEC-GOAL-GATES, REQ-EXEC-LOCAL-ENV,
REQ-EXEC-TOOL-CAPTURE, REQ-HUMAN-GATE.
ToolOnly start Start clean Clean start->clean exit Exit build Build clean->build test Smoke test build->test approve_release Ship it? test->approve_release approve_release->exit ship approve_release->build reject

triage.dot

source

A diagnose agent that deliberately decides the issue isn't auto-fixable

REQ-AGENT-TOOLS-V01REQ-EXEC-EDGE-ROUTINGREQ-EXEC-OUTCOMES-DYNAMICREQ-EXEC-REVISIT-CONTEXTREQ-HUMAN-GATE
description
A diagnose agent that deliberately decides the issue isn't auto-fixable
and calls report_outcome("FAILURE", "<reason>") (§6.2 case b, §8.2).
The FAILURE edge routes to a downstream agent which reads the reason
out of its entry-edge context payload (§6.3 entry-edge context with
predecessor_outcome + captured_output) and uses it to brief a human
reviewer at the next gate.

Inputs (placed in the worktree before launch):
  bug.md — symptom description (e.g. "intermittent CI flake on test_x").

Expected behaviour:
  start -> diagnose
    - SUCCESS (root cause is in the code): -> patch -> verify -> exit
    - FAILURE (e.g. external infra / not-our-bug):
        -> brief_reviewer (reads captured_output) -> human_review
        -> abandon | force_patch

REQs exercised: REQ-EXEC-OUTCOMES-DYNAMIC (case b: agent calls
report_outcome), REQ-EXEC-EDGE-ROUTING (FAILURE requires explicit edge),
REQ-EXEC-REVISIT-CONTEXT (entry-edge context: predecessor_node,
entry_edge_label, predecessor_outcome, captured_output), REQ-HUMAN-GATE,
REQ-AGENT-TOOLS-V01 (report_outcome).
Triage start Start diagnose Diagnose start->diagnose exit Exit brief_reviewer Brief reviewer diagnose->brief_reviewer FAILURE patch Patch diagnose->patch SUCCESS human_review Reviewer decision brief_reviewer->human_review verify Verify patch patch->verify verify->exit SUCCESS verify->brief_reviewer FAILURE human_review->exit abandon human_review->patch force_patch

Invalid fixtures (2)

cycle-no-max-visits.dot

source

INVALID FIXTURE.

REQ-DOD-VALIDATE-ERRORSREQ-EXEC-MAX-VISITSREQ-EXEC-VERIFY-FIXUP-IDIOM
description
INVALID FIXTURE.

Violates §6.3: the `verify` node sits in a cycle with `fixup` but
neither the node nor the graph supplies a `max_visits` /
`default_max_visits` bound. Without a cap the engine would loop
forever on persistent failures.

`attractor validate workflows/invalid/cycle-no-max-visits.dot` should
reject this with an actionable diagnostic (per REQ-DOD-VALIDATE-ERRORS),
e.g.:
  error: node `verify` participates in a cycle (verify -> fixup -> verify)
  with no max_visits attribute and no graph default_max_visits; bound
  the loop with `max_visits=<N>` on `verify` or add
  `default_max_visits=<N>` to the graph attributes

No line/column applies — the error is whole-graph (cycle detection),
not token-level. A nice-to-have: the diagnostic could point at the
offending node's declaration line.

REQs exercised (negative case): REQ-EXEC-MAX-VISITS, REQ-EXEC-VERIFY-FIXUP-IDIOM,
REQ-DOD-VALIDATE-ERRORS.
CycleNoMaxVisits start Start implement Implement start->implement exit Exit verify Verify implement->verify verify->exit SUCCESS fixup Fix verify->fixup FAILURE fixup->verify

missing-exit.dot

source

INVALID FIXTURE.

REQ-DOD-VALIDATE-ERRORSREQ-DOT-SHAPE-HANDLERS
description
INVALID FIXTURE.

Violates §5.3: "Exit. Exactly one per graph." This file declares a
start node and an agent node but no `Msquare` node — there is nowhere
for traversal to terminate.

`attractor validate workflows/invalid/missing-exit.dot` should reject
this with an actionable diagnostic (per REQ-DOD-VALIDATE-ERRORS), e.g.:
  error: no exit node found (expected exactly one node with shape=Msquare
  or type="exit"); add `exit [shape=Msquare, label="Exit"]` and route
  to it from a terminal stage

No line/column applies — the error is graph-level, not token-level.

REQs exercised (as a negative case): REQ-DOT-SHAPE-HANDLERS (exactly
one Msquare per graph), REQ-DOD-VALIDATE-ERRORS.
MissingExit start Start plan Plan start->plan