Workflows, branching & CI/CD
- Delivery workflow
- Branching models
- Autonomous work: the Ralph loop
- CI/CD for the aiflow repo
- Building locally the same way CI does
Delivery workflow
Issue (GitHub / GitLab / Bitbucket / …)
└─ /intake-issue ─▶ Beads tasks (with acceptance criteria)
└─ /decompose (task-master) ─▶ subtasks + dependencies
└─ bd ready --claim ─▶ pick & claim a task
└─ /implement ─▶ code + tests, Google style (implementer)
└─ /review-ac ─▶ gate vs acceptance criteria (reviewer)
└─ commit (Conventional Commits + bead id) ─▶ PR ─▶ release
└─ aiflow close-sync ─▶ push + Dolt-sync issues
└─ aiflow next ─▶ next ready task (loop)
One feature end to end — task, pre-analysis, PO question with recorded decision, versioned +
secured API, tests + .http file, review gate, close:

A task is DONE only when: acceptance criteria met • tests pass • style/lint clean • review gate passed • bead closed • sync gate honoured • the queue refreshed.
Queue mode — a closed task is not a finished session
Beads is an authoritative work queue, not a notepad. Closing a bead ends a task; the agent then
refreshes the queue and starts the next one instead of asking you what to do. aiflow next picks
it, ranked: higher priority first, then the task that unblocks the most others, then the
epic/workstream in progress, then a natural continuation of the bead just closed
(aiflow next --after <closed-id>). It exits 3 when nothing is actionable.
There are exactly four reasons to stop, and the agent must name the one that applies:
- the queue holds nothing actionable,
- everything left is blocked by unresolved dependencies (
bd blocked), - continuing needs a decision, clarification, credential or permission only you have,
- you said stop.
This does not rely on the model remembering. With Claude Code, the Stop hook
.claude/hooks/queue-continue.* checks the queue when the agent tries to end its turn and hands
the next ready task back. It fires at most once per stop, so naming a legitimate reason always
ends the session. Turn it off per project with .aiflow/config.json → beads.queueMode = false, or
for one session with AIFLOW_QUEUE_MODE=off. Copilot and Codex have no Stop-hook equivalent —
run aiflow next yourself after each close.
Queue mode changes nothing about the gates: every task still needs its acceptance criteria, its
review pass and its recorded decisions, work outside a bead’s scope becomes a new bead, and
merging to main or cutting a release still requires your explicit confirmation.
Branching models
Configured at aiflow init / change-settings (only when VCS = git). aiflow writes
.aiflow/branching.json + a readable docs/branching.md, creates permanent branches, seeds
VERSION, and installs enforcement.
- Model —
simple(main + develop) ·gitflow(feature/*/bugfix/*from develop,hotfix/*from main) ·none. - main is restricted (gitflow) — only
develop,hotfix/*, orchore/*may ever land onmain;feature/*/bugfix/*always merge todevelop. Doc-only and CI/workflow-file-only changes count aschore/*. - Strict rules — enforce branch sources/targets and naming.
- PR-only — no direct push to main/develop; merge only via a validated PR.
- Auto-release — develop carries
X.Y.0-SNAPSHOT; merging into main strips it (minor release).aiflow hotfix <name>carriesX.Y.(Z+1)-HOTFIX; merging into main strips it (patch release) and also merges into develop.chore/*→ main never releases, andmainis never allowed to carry a-SNAPSHOT/-HOTFIXversion. Releasing always needs explicit human confirmation — never automatic. - Version strategy — SemVer or CalVer; optional release tags.
- chore/* — chore branches independent of feature/hotfix rules.
Enforcement: the pre-push hook blocks direct pushes to protected branches, blocks
feature/*/bugfix/* merges onto main, and rejects any push to main with a
-SNAPSHOT/-HOTFIX version; aiflow protect applies real server-side branch protection on
GitHub; aiflow release [--yes] [--push] prints a dry run, and only bumps the version, tags, and
bumps develop once run with --yes.
Autonomous work: the Ralph loop
For larger tasks, hand off to the Ralph loop — the agent iterates on the same task until it signals completion. Runs on open-ralph-wiggum, agent-agnostic: Claude Code, OpenAI Codex CLI, or GitHub Copilot CLI.
- Interactive, Claude Code only:
/ralph-loop— a separate Claude Code plugin skill. - Headless (any agent):
aiflow ralph "implement bd-12" [--agent claude-code|codex|copilot]— defaults to the first agent enabled in.aiflow/config.json → agents.*if--agentis omitted; tuned viaRALPH_MAX_ITERATIONS(env). Needs Bun +npm i -g @th0rgal/ralph-wiggum(installed byaiflow install-deps). Completion-promise auto-stop isn’t always reliable with every agent —--max-iterationsis the real safety bound. - In CI: the same loop runs via
.github/workflows/agent.ymlon manual dispatch, theagentissue label, or nightly. - Containerised:
docker/run.shruns it in a container using Podman or Docker (auto-detected; override withAIFLOW_CONTAINER=podman|docker).
CI/CD for the aiflow repo
.github/workflows/ci.yml— validates the toolchain on push/PR:bash -non all scripts, shellcheck (advisory), JSON validation of templates, PowerShell parse, and a dry-run build of the per-OS archives (uploaded as an artifact)..github/workflows/release.yml— on every push tomain, ifVERSIONhas no matching tag it builds per-OS archives (linux.tar.gz,macos.tar.gz,windows.zip+ SHA256SUMS), tagsv<VERSION>, and publishes a GitHub Release. BumpVERSION, push → a release is cut..github/workflows/pages.yml— builds and deploys this documentation site.
Projects generated by aiflow also get their own ci.yml (detects Node/Python/Go/Dart → format +
tests) and agent.yml (Ralph loop in CI; auth from ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN
repo secrets).
Building locally the same way CI does
ver=$(cat VERSION); stage="aiflow-$ver"
mkdir -p "dist/$stage" && cp -r bin lib templates install.sh install.ps1 README*.md LICENSE VERSION "dist/$stage/"
( cd dist && tar -czf "aiflow-$ver-linux.tar.gz" "$stage" )