# CI Workflow Implementation Plan (Plan 4d) > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add a single Gitea Actions CI workflow that runs `go vet` + `gofmt` check + `go build` + `go test -race` + `shellcheck` + `goreleaser check` inside an `archlinux:latest` container on every push and PR. **Architecture:** One workflow file (`.gitea/workflows/ci.yml`), one job with sequential steps. The Arch container gives environmental fidelity; `actions/setup-go@v5` pins Go via `go-version-file: go.mod` for reproducibility. **Tech Stack:** Gitea Actions, archlinux:latest container, Go (version pinned in go.mod), shellcheck, goreleaser v2. **Spec:** `docs/superpowers/specs/2026-04-14-ci-workflow-design.md` --- ## File Structure **New files:** - `.gitea/workflows/ci.yml` — single-job CI workflow **No other files change.** --- ## Task 1: Pre-flight — verify all CI steps pass locally Before writing the workflow, run every command it will execute locally to confirm the repo is in a CI-passing state. If any command fails, either the plan's step is wrong or the repo has a latent issue — either way, CI will fail without this check. **Files:** none (validation only) - [ ] **Step 1: `go vet ./...`** ```bash cd /home/marvin/git-clones/ArduinoArchSetup go vet ./... ``` Expected: exit 0, no output. If warnings appear, STOP and report — fixing them is out of scope for this plan but must happen before CI can land. - [ ] **Step 2: `gofmt` check** ```bash cd /home/marvin/git-clones/ArduinoArchSetup diff=$(gofmt -l .) if [ -n "$diff" ]; then echo "FILES NEEDING FMT:"; echo "$diff"; exit 1; fi echo "gofmt clean" ``` Expected: `gofmt clean`. If any files are listed, STOP and report. Fixing formatting is out of scope — do NOT auto-fix in this plan. The user should decide whether to format in a separate commit first. - [ ] **Step 3: `go build ./...`** ```bash cd /home/marvin/git-clones/ArduinoArchSetup go build ./... ``` Expected: exit 0, no output. - [ ] **Step 4: `go test -race ./...`** ```bash cd /home/marvin/git-clones/ArduinoArchSetup go test -race ./... ``` Expected: all packages report `ok` or `no test files`. Failures = STOP and report. Race detector findings = STOP and report (they indicate real concurrency bugs). - [ ] **Step 5: `shellcheck bootstrap.sh`** ```bash command -v shellcheck || { echo "shellcheck not installed; install via: sudo pacman -S shellcheck"; exit 1; } shellcheck /home/marvin/git-clones/ArduinoArchSetup/bootstrap.sh ``` Expected: exit 0, no output. If shellcheck isn't installed locally, install it (`sudo pacman -S shellcheck`) and retry. If findings appear, STOP and report — bootstrap.sh was validated by `bash -n` only, so this is the first shellcheck run. - [ ] **Step 6: `goreleaser check`** ```bash command -v goreleaser || command -v /home/marvin/go/bin/goreleaser || { echo "goreleaser missing"; exit 1; } (command -v goreleaser && goreleaser check) || /home/marvin/go/bin/goreleaser check ``` Expected: `• 1 configuration file(s) validated` or equivalent success message. - [ ] **Step 7: No commit** This task is informational. If all six steps passed, proceed to Task 2. If any failed, report findings to the controller and HALT — the CI workflow cannot land until the repo is in a passing state. --- ## Task 2: Author `.gitea/workflows/ci.yml` **Files:** - Create: `.gitea/workflows/ci.yml` - [ ] **Step 1: Write the workflow file** Create `/home/marvin/git-clones/ArduinoArchSetup/.gitea/workflows/ci.yml`: ```yaml name: ci on: push: pull_request: jobs: test: runs-on: ubuntu-latest container: image: archlinux:latest steps: - name: Install container prereqs run: pacman -Sy --needed --noconfirm base-devel git shellcheck - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 - name: Setup Go uses: actions/setup-go@v5 with: go-version-file: go.mod cache: true - name: go vet run: go vet ./... - name: gofmt check run: | diff=$(gofmt -l .) if [ -n "$diff" ]; then echo "files need gofmt:" echo "$diff" exit 1 fi - name: go build run: go build ./... - name: go test -race run: go test -race ./... - name: shellcheck bootstrap.sh run: shellcheck bootstrap.sh - name: Install goreleaser run: go install github.com/goreleaser/goreleaser/v2@latest - name: goreleaser check run: $(go env GOPATH)/bin/goreleaser check ``` - [ ] **Step 2: Validate YAML syntax** ```bash cd /home/marvin/git-clones/ArduinoArchSetup python3 -c "import yaml; yaml.safe_load(open('.gitea/workflows/ci.yml'))" && echo "yaml ok" ``` Expected: `yaml ok`. - [ ] **Step 3: Sanity-check step ordering against spec** Open the file and confirm the step order matches the spec's Section "Job steps": 1. Install container prereqs 2. Checkout 3. Setup Go 4. go vet 5. gofmt check 6. go build 7. go test -race 8. shellcheck bootstrap.sh 9. Install goreleaser 10. goreleaser check No grouping or reordering. This is only a human-verified check (no command). - [ ] **Step 4: Commit** ```bash cd /home/marvin/git-clones/ArduinoArchSetup git add .gitea/workflows/ci.yml git commit -m "ci: add Gitea Actions workflow for test, vet, fmt, build, shellcheck, goreleaser check" ``` Do NOT add any Co-Authored-By trailer — repo convention forbids it. --- ## Notes for the executing agent - **One file, one job.** Don't split into multiple jobs or multiple workflows. The spec is explicit. - **Do not try to run the workflow itself** — that requires a Gitea Actions runner (Plan 4c Task 9, currently deferred). The workflow will queue when pushed until a runner is online; that's fine. - **If Task 1 reveals failures** in `go vet`, `gofmt`, `go test -race`, or `shellcheck`, stop and escalate. Those are pre-existing issues the controller needs to address in a separate commit/plan; this plan only adds the workflow that detects them. - **Why `$(go env GOPATH)/bin/goreleaser` explicitly** in step 10: `go install` puts binaries in `GOPATH/bin`, which isn't on `$PATH` inside the stock Arch container. Using the absolute path is simpler than mutating PATH. - **YAML indentation is significant.** Use 2-space indents matching the example above. Do not substitute tabs.