Phase-gated workflow enforcement for AI-assisted development.
AI is water, not an adversary. It flows the path of least resistance. Waterfall builds infrastructure where the path of least resistance is the correct output. Constraints shape behavior. Verification replaces trust. Behavioral evidence replaces self-report.
A system of shell scripts, hooks, and verification gates that enforce a development protocol:
RESEARCH → DESIGN → SPEC → IMPLEMENT → WIRE → DOCUMENT → VERIFY
- Source files are locked except during IMPLEMENT and WIRE phases
- Human approval (password required) gates RESEARCH→DESIGN and DESIGN→SPEC
- AI can only advance forward through phases it's allowed to
- Verification gauntlet runs automatically — fail and you loop back to fix
- Every transition is audited with timestamps
The AI doesn't need to be trusted or distrusted. The system makes the correct path the easiest path.
Every AI coding tool has the same failure mode: the AI says "done" when it isn't. It writes tests that test nothing. It skips steps. It claims fixes work without proving them.
The standard response is better prompts, better models, more guardrails in the prompt. That's fighting water by building walls. Water finds cracks.
Waterfall doesn't fight the water. It builds channels. The AI can't edit source files until a spec exists. It can't skip verification. It can't mark work complete without passing automated checks. The protocol is enforced by root-owned scripts and file permissions, not by asking nicely.
just begin <task> # Start a new workflow (enters RESEARCH)
just approve # Approve RESEARCH→DESIGN or DESIGN→SPEC (requires password)
just fix # Go back to fix issues (VERIFY/DOCUMENT→WIRE, WIRE→IMPLEMENT, IMPLEMENT→SPEC)
just reset # Emergency reset to NONE
just phase # Check current phase
just status # Full diagnostic
just audit # View audit logjust advance # Move to the next phase (forward only; RESEARCH and DESIGN need human approval)
just phase # Check current phase| Phase | Who decides | Source files | What happens |
|---|---|---|---|
| RESEARCH | Human starts | Locked | Gather info, write to docs/research/ |
| DESIGN | Human approves | Locked | Present architecture, write to docs/designs/ |
| SPEC | AI advances | Locked | Detailed spec any model can follow |
| IMPLEMENT | AI advances | Writable | Write code per spec |
| WIRE | AI advances | Writable | Integrate into project |
| DOCUMENT | AI advances | Locked | Update all documentation |
| VERIFY | Automated | Locked | Run gauntlet; fail → loop to WIRE |
When advancing from VERIFY, all scripts in .workflow/verify.d/ run automatically.
Starter checks (installed by default):
01-doc-coverage.sh— Checks that source modules have doc files and doc files have source sections02-wire-check.sh— Checks that newly added files are referenced somewhere (heuristic)03-format-lint.sh— Auto-detects language and runs formatters/linters
Rust projects also get:
04-rust-wire-check.sh— Four-layer gate: dead_code annotation ban, mod cross-reference check, dead code detection on new files viacargo check, integration test check
If any check fails, the workflow loops back to WIRE automatically. You fix, then advance again. This loop continues until everything passes.
The starter checks catch common mistakes. Add your own domain-specific verification scripts — any executable .sh in .workflow/verify.d/ runs in sort order. The gauntlet is only as strong as the checks you put in it.
- Linux (uses ACLs, setfacl, sudoers). Windows users: use WSL. macOS: not currently supported.
- just command runner
- jq for JSON processing
aclpackage (sudo apt install aclon Debian/Ubuntu)- sudo access for installation
The installer checks for these and fails early with actionable messages if anything is missing.
git clone https://github.com/clanker-lover/waterfall.git
cd waterfall
sudo ./install.shThis installs system scripts to /usr/local/bin/, language-specific verifiers to /usr/local/share/waterfall/, creates /etc/workflow-projects.conf, and sets up scoped sudoers for your user.
sudo workflow-init $HOME/my-project "src tests"
cd ~/my-project
just statusNote: Use $HOME not ~ with sudo — ~ expands to root's homedir under sudo.
sudo workflow-init $HOME/my-existing-project "src tests"This adds the workflow structure (.workflow/, docs/) to your project. Existing justfile, CLAUDE.md, and .gitignore are preserved. Source directories will be changed to root ownership for phase enforcement — commit or stash work first. The script will confirm before proceeding.
./install-hooks.shInstalls a phase-enforcement hook into ~/.claude/hooks/. The hook gives friendlier error messages when the AI tries to write outside the allowed phase. Not required — filesystem enforcement works without it.
my-project/
├── .workflow/
│ ├── config # SOURCE_DIRS, SOURCE_FILES, ARTIFACT_DIRS
│ ├── state.json # Current workflow metadata
│ ├── verify.d/ # Verification scripts (pluggable)
│ │ ├── 01-doc-coverage.sh
│ │ ├── 02-wire-check.sh
│ │ └── 03-format-lint.sh
├── .workflow-state # Current phase (written by root-owned scripts)
├── .workflow-audit # Transition log
├── justfile # Workflow commands
├── CLAUDE.md # AI instructions (optional)
└── docs/
├── workflow/ # Phase prompt templates
├── research/ # Research artifacts
├── designs/ # Design documents
├── specs/ # Specifications
├── modules/ # Module documentation
└── clusters/ # Cluster documentation
Two structural constraints do the heavy lifting:
-
File permissions — Source directories are root-owned. ACLs grant write access only during IMPLEMENT/WIRE, revoked automatically on phase transition. This works with any AI tool — Claude Code, Codex, OpenHands, or a model you run locally. No hooks required.
-
State machine — Root-owned script validates every phase change. Invalid transitions are refused. VERIFY→NONE requires all gauntlet scripts to pass. RESEARCH→DESIGN and DESIGN→SPEC require human password.
Optional: Claude Code hooks add real-time feedback when the AI tries to write outside the allowed phase. Without hooks, the AI hits "permission denied" from the filesystem and adapts. Hooks give a friendlier error explaining why.
The AI cooperates because cooperating is the easiest path, not because it's told to.
Edit .workflow/config:
SOURCE_DIRS="src lib tests"
SOURCE_FILES="Cargo.toml pyproject.toml"
ARTIFACT_DIRS=".git target node_modules __pycache__"Drop any executable script in .workflow/verify.d/:
#!/bin/bash
# 04-my-check.sh
set -euo pipefail
echo "=== My Custom Check ==="
# Exit 0 = pass, exit 1 = fail
your-check-command || { echo "FAILED"; exit 1; }
echo "PASSED"The format-lint verifier auto-detects:
- Rust —
cargo fmt --check+cargo clippy(plus 4-layer wire check for Rust projects) - Python —
ruff checkorblack --check - TypeScript/JavaScript —
eslint - Go —
go vet - GDScript —
gdformat --check
Add more by editing 03-format-lint.sh or adding a new verifier.
sudo rm /usr/local/bin/workflow-{init,state,gate,approve,acl}
sudo rm -rf /usr/local/share/waterfall/
sudo rm /etc/sudoers.d/waterfall
sudo chattr -i /etc/workflow-projects.conf && sudo rm /etc/workflow-projects.confTo remove hooks: rm ~/.claude/hooks/workflow-gate-hook.py and remove the hook entry from ~/.claude/settings.json.
This is AI guidance, not AI containment. It is not a security boundary and does not pretend to be.
- Not adversary-proof — The gate uses string matching on commands. A sufficiently creative bypass is always possible. This is fine. The system is designed to make the correct path easier, not to make the wrong path impossible. If the AI finds a crack, fix the channel.
- Fail-open hooks — The Claude Code hook allows operations if the gate script is missing, times out, or errors. This is intentional. A workflow tool that blocks your work because of a bug in itself is worse than no tool. Change
sys.exit(0)tosys.exit(2)inworkflow-gate-hook.pyif you prefer fail-closed. - Linux only — ACLs, setfacl, chattr, and root ownership are Linux-specific. No macOS or Windows support.
- Starter verification — The default gauntlet checks (doc coverage, wire check, format/lint) are heuristics, not proofs. They catch common mistakes. Add your own verification scripts to
.workflow/verify.d/for domain-specific checks that matter to your project.
See docs/philosophy.md for the full design rationale.
The short version: stop negotiating with the river. Don't make AI smarter — make the correct path easier than the wrong path. Every constraint you add is a channel that guides the water where you want it to go. When the AI finds a crack, that's your crack to fix, not the AI's fault.
MIT