← back to Cli Printing Press
ci(ci): guard low-risk checks and setup docs (#347)
3f7410de27fc69f9aff6238059d3be81d8d24bb1 · 2026-04-27 11:36:42 -0700 · Trevin Chow
* docs(ci): document lefthook setup safeguards
* ci(ci): skip low-risk lint and golden work
Files touched
M .github/workflows/golden.ymlM .github/workflows/lint.ymlM AGENTS.mdM README.mdM lefthook.yml
Diff
commit 3f7410de27fc69f9aff6238059d3be81d8d24bb1
Author: Trevin Chow <trevin@trevinchow.com>
Date: Mon Apr 27 11:36:42 2026 -0700
ci(ci): guard low-risk checks and setup docs (#347)
* docs(ci): document lefthook setup safeguards
* ci(ci): skip low-risk lint and golden work
---
.github/workflows/golden.yml | 33 +++++++++++++++++++++++++++++++++
.github/workflows/lint.yml | 33 +++++++++++++++++++++++++++++++++
AGENTS.md | 4 ++--
README.md | 13 ++++++++++++-
lefthook.yml | 2 +-
5 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/golden.yml b/.github/workflows/golden.yml
index 4669d1e1..67f2adcb 100644
--- a/.github/workflows/golden.yml
+++ b/.github/workflows/golden.yml
@@ -16,12 +16,45 @@ jobs:
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+
+ - name: Check whether golden verification is needed
+ id: changes
+ shell: bash
+ run: |
+ set -euo pipefail
+
+ git fetch --no-tags --prune origin "${{ github.base_ref }}"
+ mapfile -t changed < <(git diff --name-only --diff-filter=ACMR "origin/${{ github.base_ref }}...HEAD")
+
+ echo "Changed files:"
+ printf ' %s\n' "${changed[@]}"
+
+ needs_golden=false
+ for file in "${changed[@]}"; do
+ case "$file" in
+ cmd/*|internal/*|catalog/*|testdata/golden/*|scripts/golden.sh|go.mod|go.sum|.github/workflows/golden.yml)
+ needs_golden=true
+ break
+ ;;
+ esac
+ done
+
+ echo "needs_golden=$needs_golden" >> "$GITHUB_OUTPUT"
+
+ - name: Skip golden verification
+ if: steps.changes.outputs.needs_golden != 'true'
+ run: |
+ echo "Skipping golden verification: no generator, CLI, catalog, golden fixture, module, or golden workflow files changed."
- uses: actions/setup-go@v6
+ if: steps.changes.outputs.needs_golden == 'true'
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum
- name: Verify golden outputs
+ if: steps.changes.outputs.needs_golden == 'true'
run: scripts/golden.sh verify
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 5cfebac4..af73f666 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -16,14 +16,47 @@ jobs:
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+
+ - name: Check whether Go lint is needed
+ id: changes
+ shell: bash
+ run: |
+ set -euo pipefail
+
+ git fetch --no-tags --prune origin "${{ github.base_ref }}"
+ mapfile -t changed < <(git diff --name-only --diff-filter=ACMR "origin/${{ github.base_ref }}...HEAD")
+
+ echo "Changed files:"
+ printf ' %s\n' "${changed[@]}"
+
+ needs_lint=false
+ for file in "${changed[@]}"; do
+ case "$file" in
+ *.go|go.mod|go.sum|.golangci.yml|.github/workflows/lint.yml)
+ needs_lint=true
+ break
+ ;;
+ esac
+ done
+
+ echo "needs_lint=$needs_lint" >> "$GITHUB_OUTPUT"
+
+ - name: Skip Go lint
+ if: steps.changes.outputs.needs_lint != 'true'
+ run: |
+ echo "Skipping golangci-lint: no Go, module, lint config, or lint workflow files changed."
- uses: actions/setup-go@v6
+ if: steps.changes.outputs.needs_lint == 'true'
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum
- uses: golangci/golangci-lint-action@v9
+ if: steps.changes.outputs.needs_lint == 'true'
with:
version: v2.11.4
diff --git a/AGENTS.md b/AGENTS.md
index d7394cb4..39d227ee 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -45,9 +45,9 @@ go fmt ./...
golangci-lint run ./...
```
-A pre-commit hook runs `gofmt -w` on staged Go files automatically. A pre-push hook runs `golangci-lint`. The same config (`.golangci.yml`: errcheck, govet, staticcheck, unused) runs in CI. To run lint manually: `golangci-lint run ./...`
+A pre-commit hook runs `gofmt -w` on staged Go files automatically. A pre-push hook runs `golangci-lint`. The same config (`.golangci.yml`: errcheck, govet, staticcheck, unused) runs in CI. Install hooks with `brew install lefthook && lefthook install --reset-hooks-path`; `--reset-hooks-path` clears stale local `core.hooksPath` settings that block hook sync. Avoid `lefthook install --force` unless intentionally overriding a custom hooks path. To run lint manually: `golangci-lint run ./...`
-**Always run `go fmt ./...` after writing Go code.** Use `go fmt`, not raw `gofmt` — `gofmt` doesn't accept Go package patterns, and `gofmt -w .` would walk into `testdata/golden/expected/` and rewrite frozen golden fixtures. `go fmt ./...` skips `testdata` and `vendor` by convention. Subagents and code generators often produce valid but unformatted Go. The pre-commit hook catches this for commits in the repo, but code written to external directories (e.g., `~/printing-press/library/`) must be formatted explicitly.
+**After writing Go code, format it with `go fmt ./...` before handing back work.** This is intentionally redundant with the pre-commit hook: `gofmt` is idempotent, and the hook is a safety net for commits while agents often stop before committing. Use `go fmt ./...` for repo-wide formatting and `gofmt -w path/to/file.go` only for explicit files. Do not run `gofmt -w ./...` — `gofmt` does not accept Go package patterns. Do not run `gofmt -w .` from the repo root — it can walk into `testdata/golden/expected/` and rewrite frozen golden fixtures. `go fmt ./...` formats package files and skips `testdata` and `vendor` by convention. Code written to external directories (e.g., `~/printing-press/library/`) must be formatted explicitly because repo hooks will not see it.
**IMPORTANT: Always use relative paths for build output.** Never build to `/tmp` or any shared absolute path. Multiple worktrees run concurrently and will stomp on each other. Use `./printing-press` exactly as shown above.
diff --git a/README.md b/README.md
index 16431c82..4f83c119 100644
--- a/README.md
+++ b/README.md
@@ -454,7 +454,18 @@ go fmt ./...
golangci-lint run ./...
```
-A pre-push lefthook hook runs `golangci-lint` on changed files; the same config (`.golangci.yml`) runs in CI. Install hooks with `brew install lefthook && lefthook install`. To test local skill changes, run `claude --plugin-dir .` so `/printing-press` loads from your working copy. See [AGENTS.md](AGENTS.md) for full conventions, glossary, and release flow.
+A pre-push lefthook hook runs `golangci-lint` on changed files; the same config (`.golangci.yml`) runs in CI.
+
+Install hooks with:
+
+```bash
+brew install lefthook
+lefthook install --reset-hooks-path
+```
+
+Use `--reset-hooks-path` so stale local `core.hooksPath` settings do not block hook sync. Avoid `lefthook install --force` unless intentionally overriding a custom hooks path.
+
+To test local skill changes, run `claude --plugin-dir .` so `/printing-press` loads from your working copy. See [AGENTS.md](AGENTS.md) for full conventions, glossary, and release flow.
### Golden Output Harness
diff --git a/lefthook.yml b/lefthook.yml
index 52ab241a..1e7ac169 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -45,7 +45,7 @@ pre-push:
run: |
unformatted="$(git ls-files '*.go' ':!:testdata/golden/expected/**' | xargs gofmt -l)"
test -z "$unformatted" || { printf '%s\n' "$unformatted"; exit 1; }
- fail_text: "gofmt failed. Run 'gofmt -w .' to fix."
+ fail_text: "gofmt failed. Run 'go fmt ./...' to fix. Do not run 'gofmt -w .' from the repo root; it can rewrite golden fixtures."
lint:
glob: "*.go"
run: golangci-lint run ./...
← 4c64ffe6 ci(ci): improve workflow coverage and guards (#346)
·
back to Cli Printing Press
·
docs(cli): add MIT LICENSE matching README declaration (#349 f3c18d4c →