VibeFlow CLI flag reference
Contents
vf init --ai --autopilot- How It is Enforced
- What to Do When You Add a New File and Coverage Drops
- bun:coverage Quirks
- Anti-Patterns Suite
- When You Have a Real Coverage Blocker
This document tracks every non-trivial flag in the VibeFlow CLI that the release notes, marketing copy, or new contributors need to know about. It is maintained alongside the source: when a flag is added or its behavior changes, update the entry here in the same commit.
vf init --ai --autopilot
Added in: feat(ai-init): add --autopilot flag for engine auto-fallback
Summary: When the chosen engine is unavailable or returns a permission/unauthorized error, automatically fall back to the next-best ready engine instead of failing hard.
Default: false (preserves pre-existing single-shot behavior; a
failure is the user’s problem to debug).
Scope: The flag is on vf init --ai, NOT a global flag. Only the
AI-powered enrichment phase (Phase 2 of vf init) is affected. The
deterministic baseline (Phase 1) is unchanged.
Behavior:
- If
forceEngine(from--engine) is set and the engine is not ready, autopilot clearsforceEngineand falls through toselectBestEngine(readiness), which picks the next-best engine in priority order:claude > copilot > codex. - If the engine invocation reports the CLI as unavailable (e.g.
copilotbinary missing), autopilot retries with the next-best engine. - If the engine spawner returns a permission-denied or unauthorized
response (e.g. copilot missing
--allow-allflags), autopilot retries with the next-best engine. - Timeouts and unknown non-zero status codes are NOT retried — those indicate an engine-side issue, not a fallback opportunity.
- Retries are capped at 3 (4 total attempts). The fallback engine must be DIFFERENT from the one that just failed (the loop never retries the same engine twice).
- The
AiInitResultincludes afallback: { original, used }field when the chosen engine differs from the original request. The CLI surfaces this as✔ AI analysis complete (used; fell back from original via --autopilot).
Result on total failure: If every engine fails (or the only
candidate is unavailable), the result reason is wrapped with
— exhausted 3 autopilot fallbacks; original request was <engine> so
the caller knows fallback was attempted and gave up.
Non-retryable failures (preserved single-shot): When autopilot is off, the loop is bypassed entirely. A failure on the first attempt returns immediately — no fallback is attempted. The original error message is preserved verbatim.
Tests: 7 new tests in test/ai-init.test.ts (autopilot flag
block) and 2 new tests in test/commands-coverage.test.ts (CLI
integration). All pass; 100% lcov line coverage maintained.
Coverage policy: 100% lcov, 100% branch, always
The vibeflow-docs repo is contractually at 100% line and branch coverage. Every PR must keep it that way.
How it’s enforced
scripts/coverage-gate.cjs— parsescoverage/lcov.infoafterbun test --coverage --coverage-reporter=lcovruns. Refuses merge if anysrc/*.tsfile is below 100% line or branch.bun run coverage:check— runs the lcov generator + the gate.bun run check— runs typecheck + lint + test + coverage:check..github/workflows/ci.yml— runsbun run checkon a self-hosted runner (PR #30 + #31). If red, the PR cannot merge.
What to do when you add a new file and coverage drops
Option A: Cover the new code with a test (always preferred)
- Add the new src/ file.
- Add
test/foo.test.tswith at least oneexpect()per public function. - Run
bun run coverage:checkto confirm.
Option B: Inline unreachable defensive code
If a catch block or if (cond) return; is truly unreachable in
practice, use the single-statement form:
// Bad — bun:coverage counts the } as a separate line, drops coverage.
if (cond) {
return;
}
// Good — no standalone }, the line is the same.
if (cond) return;
Option C: Extract a test seam (last resort)
If the code path is hard to test (real network, real fs), inject
the dependency. See src/commands.ts for examples.
bun:coverage quirks
- Standalone
}on its own line is counted as executable. Inline single-statement blocks to avoid. - bun:coverage emits no BRDA records, so branch coverage
shows as 0/0 in the lcov. The plan called this out — the
::notice::line incoverage-gate.cjsdocuments this. setInterval(() => {...}, 25000)callback body never hits in tests because tests complete in <25s. Either exercise the callback in a test, or use aninject.timerseam.
Anti-patterns suite
test/coverage-anti-patterns.test.ts is the contract that locks
the 100% invariant. A future agent that introduces a top-level
spawn, an empty catch, or a test using raw Bun.spawn will fail
this suite BEFORE the coverage gate runs.
When you have a real coverage blocker
Open an issue with: file + line, the code that can’t be hit, and
the runtime condition. A maintainer can add an inject seam, add
a // biome-ignore, or accept the gap and document the rationale.
Do NOT silently merge <100% coverage. The 100% invariant is load- bearing: future contributors rely on it.
Related: Master Spec · Generated Files Edit this page on GitHub