Most AI coding workflows suffer from two core failure modes:
-
The Ghost Exit: The runner finishes with exit code
0, but made zero code edits and wrote zero reports. - The Context Amnesia: On multi-file tasks, models forget prior architectural decisions, rewrite already completed work, or validate their own hallucinations with "looks good to me."
To solve this, I designed wb-flow β an open-source, zero-dependency orchestrator that turns chaotic agent chats into a deterministic, wave-based engineering pipeline.
Here is the complete architectural map of how it works under the hood:
flowchart TD
subgraph group_setup["Setup Surface"]
node_install_cli["Install CLI<br/>[install.js]"]
node_initializer["Project Initializer<br/>[init.js]"]
node_wrapper_generator["Agent Wrappers<br/>[wrappers.js]"]
node_command_templates["Command Templates"]
end
subgraph group_planning["Planning Commands"]
node_plan_command["Plan Procedure"]
node_wave_parser["Plan Parser<br/>[wave_parser.js]"]
node_next_generator["Next Generator<br/>[next.js]"]
end
subgraph group_execution["Wave Execution"]
node_work_command["Work Procedure"]
node_wave_runner["Wave Runner<br/>[wave.js]"]
node_wave_generator["Wave Generator<br/>[wave_generator.js]"]
end
subgraph group_validation["Validation State"]
node_valid_command["Validation Procedure"]
node_plan_linter["Plan Linter<br/>[lint.js]"]
node_run_watcher["Run Watcher<br/>[watch.js]"]
node_report_archiver["Report Archiver<br/>[archive.js]"]
end
subgraph group_routing["Model Routing"]
node_wave_router["Model Router<br/>[wave_router.js]"]
node_model_manager["Model Manager<br/>[model.js]"]
node_model_catalog["Model Catalog<br/>[models.json]"]
end
node_developer(("Developer"))
node_coding_agent(("Coding Agent"))
node_model_providers(("Model Providers"))
node_developer -->|"requests workflow"| node_coding_agent
node_coding_agent -->|"runs bootstrap"| node_install_cli
node_install_cli -->|"starts setup"| node_initializer
node_initializer -->|"writes wrappers"| node_wrapper_generator
node_initializer -->|"copies templates"| node_command_templates
node_wrapper_generator -->|"renders procedures"| node_command_templates
node_coding_agent -->|"runs planning"| node_plan_command
node_coding_agent -->|"runs work"| node_work_command
node_coding_agent -->|"runs validation"| node_valid_command
node_work_command -->|"starts wave"| node_wave_runner
node_valid_command -->|"starts validation"| node_wave_runner
node_wave_runner -->|"parses plan"| node_wave_parser
node_wave_runner -->|"generates dispatch"| node_wave_generator
node_wave_generator -->|"reads task cells"| node_wave_parser
node_wave_generator -->|"routes roles"| node_wave_router
node_wave_router -->|"reads catalog"| node_model_catalog
node_model_manager -->|"updates catalog"| node_model_catalog
node_model_manager -.->|"probes models"| node_model_providers
node_wave_generator -.->|"dispatches work"| node_model_providers
node_coding_agent -->|"runs lint"| node_plan_linter
node_plan_linter -->|"checks structure"| node_wave_parser
node_coding_agent -->|"watches runs"| node_run_watcher
node_coding_agent -->|"archives reports"| node_report_archiver
node_coding_agent -->|"derives next"| node_next_generator
node_next_generator -->|"reads plan"| node_wave_parser
classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
class node_install_cli,node_initializer,node_wrapper_generator,node_command_templates toneBlue
class node_plan_command,node_wave_parser,node_next_generator toneAmber
class node_work_command,node_wave_runner,node_wave_generator toneMint
class node_valid_command,node_plan_linter,node_run_watcher,node_report_archiver toneRose
class node_wave_router,node_model_manager,node_model_catalog,node_developer,node_coding_agent,node_model_providers toneIndigo
The 5 Architectural Pillars
1. Setup Surface (init.js, wrappers.js)
Instead of locking developers into a single closed ecosystem, wb-flow generates native command wrappers for Claude Code, Codex, OpenCode, Gemini CLI, and Cursor. Any assistant can invoke the exact same slash commands.
2. Planning Commands & DAG (wave_parser.js, next.js)
The plan is stored in Markdown tables directly on disk. The parser extracts a Directed Acyclic Graph (DAG) and partitions tasks into parallel execution Waves (Wave A, Wave B, Wave C).
3. Wave Runner (wave.js, wave_generator.js)
Runs independent tasks in parallel using isolated workers. Before any task runs, a workspace hash snapshot is taken.
4. Validation & Gatekeeper (lint.js, watch.js, archive.js)
- Gate 1: Checks the runner process exit code.
-
Gate 2 (Content-Hash Gate): Compares workspace file hashes. If the agent exited cleanly with code 0 but touched zero files, it is marked as a
NO-OPand rejected. -
Independent Model Validation: An entirely different LLM is dispatched to run unit tests and score the worker's evidence before any task can be marked
β Valid.
5. Dynamic Model Routing (wave_router.js, models.json)
You can assign specific models to specific roles:
- Lightweight models for mechanical tasks.
- Heavy reasoning models (e.g. Claude Opus, GPT-5) for planning.
- Independent models for adversarial validation.
Try it out
The entire engine has zero external npm dependencies and runs on plain Node.js.
- π Documentation: flow.wbc-ui.com
- π GitHub: wissemb11/wb-flow
If you find this approach interesting or want to test multi-model wave execution in your repo, star the repo on GitHub and let me know your thoughts in the comments!
Top comments (0)