Summary
Add a two-branch testing/stable workflow to finpilot, mirroring the pattern used by bluefin-lts. This gives anyone who clones the template an automatic testing pipeline: PRs land on main (builds :stable-testing images), and the pull GitHub App promotes tested changes to stable (builds :stable production images).
Motivation
Currently finpilot has a single-branch model where main builds :stable images directly. There's no way to test image changes before they become production. Bluefin-lts solves this with a two-branch model and pull[bot] for automatic promotion — this issue brings that same pattern to the template.
Design Decisions
| Decision |
Choice |
Rationale |
| Production branch name |
stable |
Matches existing :stable tag convention |
| Testing branch name |
main |
Matches bluefin-lts where main is the testing branch |
| pull[bot] reviewers |
OWNER placeholder |
Users replace with their GitHub username during setup |
| Build triggers |
Push to both branches |
Immediate builds on merge, matches latest bluefin-lts (no cron) |
Implementation Tasks
Task 1: Create .github/pull.yml
Create pull[bot] configuration:
version: "1"
rules:
- base: stable
upstream: main
mergeMethod: hardreset
mergeUnstable: false
reviewers:
- OWNER
conflictReviewers:
- OWNER
label: "promotion"
conflictLabel: "promotion-conflict"
This tells pull[bot] to auto-create PRs from main → stable using hardreset, and skip promotion if CI is failing (mergeUnstable: false).
Task 2: Modify .github/workflows/build.yml
Four changes needed:
2a. Update triggers:
- Add
stable branch to push and pull_request triggers
- Remove
schedule cron (push triggers replace it)
- Add
merge_group support
2b. Add env vars:
PRODUCTION_BRANCH: stable # The branch that produces :stable images
TESTING_BRANCH: main # The branch where PRs land, produces :stable-testing images
2c. Add "Determine image tag" step (after "Prepare environment", before "Checkout"):
- name: Determine image tag
id: determine-tag
env:
REF_NAME: ${{ github.ref_name }}
EVENT_NAME: ${{ github.event_name }}
run: |
# If not on the production branch, this is a testing build
if [ "${REF_NAME}" != "${PRODUCTION_BRANCH}" ]; then
echo "DEFAULT_TAG=${DEFAULT_TAG}-testing" >> ${GITHUB_ENV}
echo "Building testing image: ${DEFAULT_TAG}-testing"
else
echo "Building production image: ${DEFAULT_TAG}"
fi
This mirrors the bluefin-lts logic from reusable-build-image.yml line 153.
2d. Relax publish conditions:
Change the if: guards on "Login to GHCR" and "Push to GHCR" from:
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
To:
if: github.event_name != 'pull_request'
This allows publishing from both main and stable pushes while still blocking PR builds. Apply the same change to the commented-out cosign steps.
Task 3: Rewrite .github/SETUP_CHECKLIST.md
Update the setup checklist to include:
- Instructions to create the
stable branch
- Instructions to install the pull GitHub App
- Replace
OWNER placeholder in .github/pull.yml
- Workflow diagram showing the testing → promotion → stable flow
- Deploy instructions for both
:stable-testing and :stable images
Task 4: Update README.md
- Build System section: Document dual-branch builds and pull[bot] promotion
- Development Workflow section (5): Add table of branches/tags/purposes, step-by-step workflow, testing commands
- Deploy section (6): Show both
:stable-testing and :stable deployment commands
Task 5: Update AGENTS.md
- Branch Strategy:
main = testing (:stable-testing), stable = production (:stable), pull[bot] handles promotion
- Repository Structure tree: Add
.github/pull.yml, update build.yml description
- Release Workflow (section 8): Document both branches, all workflows, image tags, promotion flow
- Image Tags Reference: Split into stable branch (production) and main branch (testing) sections
- Critical Rules 7-9: Update to reflect pull[bot] promotion instead of Release Please
- Image Signing: Remove reference to nonexistent
build-testing.yml
Task 6: Update CONTRIBUTING.md
Add an "Agent-Driven Development Workflow" section covering:
- The 8-step workflow (branch → PR → merge → testing image → pull[bot] → approve → stable image)
- Instructions for AI agents (always target
main, use conventional commits)
- Instructions for humans (review PRs, test images, approve promotions)
Task 7: Add Justfile comment
Add clarifying comment to line 2:
export default_tag := env("DEFAULT_TAG", "stable") # CI overrides to "stable-testing" on main branch
Task 8: Create stable branch
After all changes are committed to main:
git checkout main
git checkout -b stable
git push origin stable
git checkout main
Task 9: Final validation
- YAML validation on
build.yml and pull.yml
just check passes
git diff main..stable shows no differences (stable is a copy of main)
- All commits use conventional commit format
Files Changed
| File |
Action |
Purpose |
.github/pull.yml |
Create |
pull[bot] config for main→stable promotion |
.github/workflows/build.yml |
Modify |
Dual-branch triggers, testing tag logic, relaxed publish guards |
.github/SETUP_CHECKLIST.md |
Modify |
pull[bot] install and stable branch creation steps |
README.md |
Modify |
Document two-branch workflow and image tags |
AGENTS.md |
Modify |
Update branch strategy, release workflow, image tags |
CONTRIBUTING.md |
Modify |
Add agent-driven development workflow |
Justfile |
Modify |
Clarifying comment about CI tag override |
Files NOT Changed
| File |
Reason |
Containerfile |
Same image, different tags only |
.github/workflows/clean.yml |
Already handles all tags |
.github/workflows/validate-*.yml |
Already trigger on PRs to main |
.github/renovate.json5 |
Renovate PRs already target main |
build/, custom/ |
Scripts and config are tag-agnostic |
Key Technical Reference
Implementation Plan
A detailed implementation plan with exact file diffs and commit messages is available. An AI coding agent can execute this plan task-by-task using conventional commits.
Summary
Add a two-branch testing/stable workflow to finpilot, mirroring the pattern used by bluefin-lts. This gives anyone who clones the template an automatic testing pipeline: PRs land on
main(builds:stable-testingimages), and the pull GitHub App promotes tested changes tostable(builds:stableproduction images).Motivation
Currently finpilot has a single-branch model where
mainbuilds:stableimages directly. There's no way to test image changes before they become production. Bluefin-lts solves this with a two-branch model and pull[bot] for automatic promotion — this issue brings that same pattern to the template.Design Decisions
stable:stabletag conventionmainmainis the testing branchOWNERplaceholderImplementation Tasks
Task 1: Create
.github/pull.ymlCreate pull[bot] configuration:
This tells pull[bot] to auto-create PRs from
main→stableusing hardreset, and skip promotion if CI is failing (mergeUnstable: false).Task 2: Modify
.github/workflows/build.ymlFour changes needed:
2a. Update triggers:
stablebranch topushandpull_requesttriggersschedulecron (push triggers replace it)merge_groupsupport2b. Add env vars:
2c. Add "Determine image tag" step (after "Prepare environment", before "Checkout"):
This mirrors the bluefin-lts logic from
reusable-build-image.ymlline 153.2d. Relax publish conditions:
Change the
if:guards on "Login to GHCR" and "Push to GHCR" from:To:
This allows publishing from both
mainandstablepushes while still blocking PR builds. Apply the same change to the commented-out cosign steps.Task 3: Rewrite
.github/SETUP_CHECKLIST.mdUpdate the setup checklist to include:
stablebranchOWNERplaceholder in.github/pull.yml:stable-testingand:stableimagesTask 4: Update
README.md:stable-testingand:stabledeployment commandsTask 5: Update
AGENTS.mdmain= testing (:stable-testing),stable= production (:stable), pull[bot] handles promotion.github/pull.yml, updatebuild.ymldescriptionbuild-testing.ymlTask 6: Update
CONTRIBUTING.mdAdd an "Agent-Driven Development Workflow" section covering:
main, use conventional commits)Task 7: Add Justfile comment
Add clarifying comment to line 2:
Task 8: Create
stablebranchAfter all changes are committed to
main:Task 9: Final validation
build.ymlandpull.ymljust checkpassesgit diff main..stableshows no differences (stable is a copy of main)Files Changed
.github/pull.yml.github/workflows/build.yml.github/SETUP_CHECKLIST.mdREADME.mdAGENTS.mdCONTRIBUTING.mdJustfileFiles NOT Changed
Containerfile.github/workflows/clean.yml.github/workflows/validate-*.yml.github/renovate.json5build/,custom/Key Technical Reference
reusable-build-image.ymlline 153Implementation Plan
A detailed implementation plan with exact file diffs and commit messages is available. An AI coding agent can execute this plan task-by-task using conventional commits.