generateCoreWorkflows took a WorkflowPreset and named the parameter _preset.
Every repository got the same buddy.yml whichever of the eight presets a maintainer chose — so the interactive picker, the --preset flag, the setup summary and the README's preset table all described a choice with no effect. generateConfigFile never received the preset at all, so strategy, templates, custom and autoMerge reached nothing either.
The docs had already noticed. docs/cli/setup.md said outright:
Every preset writes the same
buddy.yml… The preset records the cadence you intended.
Why it wasn't just passing the argument
The preset data doesn't survive naive use:
- Six of eight presets give updates and the dashboard the same cron. The generated
determine-jobsstep was an if/elif chain — the first branch wins, the other job never runs. testingandcustomuse the stringmanualwhere a cron goes. Emitted verbatim, that's YAML GitHub refuses to parse.minimal's weekly slot collides with the fixed health-report cron, so one tick has to start three jobs.
So crons now come from a schedulePlan keyed by expression, and both places the workflow names a cron — the schedule: trigger list and the matcher reading github.event.schedule — render from it. Two tests assert the lists agree in both directions.
| Preset | Updates | Dashboard | Strategy | Auto-merge |
|---|---|---|---|---|
| Standard | 0 9 * * 1,3,5 | same tick | all | — |
| High Frequency | 0 */6 * * * | 0 9 * * * | all | patch only |
| Security Focused | 0 */4 * * * | 0 9 * * * | all | patch only |
| Minimal | 0 9 * * 1 | same tick | all | — |
| Development/Testing | */15 * * * * | manual | patch | — |
| Custom | manual | manual | all | — |
A second bug this surfaced
The weekly dependency-health report was gated on github.event.schedule == '0 9 * * 1' — a cron declared in the trigger list that determine-jobs had no branch for.
So run_check, run_update and run_dashboard were all false → setup was skipped → report, which needs: [determine-jobs, setup], was skipped with it.
That job has never run once, anywhere it was generated. It now gates on a run_report output like every other job, and setup runs for a report-only tick.
Deliberate choices
- Cleanup and the health report stay fixed, not preset-driven. Housekeeping doesn't get cheaper or riskier with cadence, and a preset that could switch it off would let stale branches pile up silently.
- Auto-merge generates as
patch-only. The preset carries a bare boolean; both presets that set it describe auto-merging patches. Turningtrueinto an unconditional auto-merge would hand a new repo something more dangerous than it asked for. autoMergeStrategyis dropped when rendering custom workflows into the config —BuddyConfighas no field for it, and emitting it would put an excess property in abuddy.config.tsthe user hasn't written a line of.
One thing to look at
Scheduled runs now use the preset's declared strategy instead of the hardcoded patch. Six presets declare all, which contradicts their own descriptions (Standard says "Daily patch updates, weekly minor updates, monthly major updates").
That's a preset-data question rather than a generator one — and it's now a one-line answer in one place instead of an unreachable field. Say the word and I'll change the data.
Tests
1966 → 1987. New test/workflow-presets.test.ts covers the collision cases, the manual sentinel, trigger/matcher agreement, and the unreachable report. The generated config is loaded back as a real module and run through validateConfig, so "valid TypeScript that evaluates to a valid config" is checked rather than assumed.
Four existing suites asserted cron: '0 */2 * * *' — a constant no preset produced. They now assert the schedule the preset in play actually asks for.
Lint ✓ · typecheck ✓ · check:docs ✓ · 1987 pass / 0 fail
🤖 Generated with Claude Code