[object Object]

← back to Cli Printing Press

fix(ci): add gofmt pre-commit hook and lint pushed files (#83)

c4a7dcf2e6c18ef5ad88de1751186b1eecac4352 · 2026-03-30 19:52:02 -0700 · Trevin Chow

* fix(ci): add pre-commit gofmt hook and document formatting requirement

Adds a lefthook pre-commit hook that auto-formats staged Go files with
gofmt before commit. This catches formatting issues from subagents and
code generators that run go build/vet but not gofmt. Updated AGENTS.md
to document the formatting requirement explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): convert if/else chain to switch for staticcheck QF1003

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): run full golangci-lint on pre-push, not just changed files

Removes --new-from-rev=origin/main from the pre-push hook so local
lint matches CI behavior. Previously the local hook only linted files
changed since main, which meant pre-existing issues from merged PRs
were invisible locally but caught by CI — causing surprise failures
on unrelated PRs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): lint only pushed Go files, not full repo

Every committed file already passes gofmt via the pre-commit hook.
The pre-push lint only needs to check the files being pushed, not
the entire repo. CI remains the full-repo safety net.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit c4a7dcf2e6c18ef5ad88de1751186b1eecac4352
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Mon Mar 30 19:52:02 2026 -0700

    fix(ci): add gofmt pre-commit hook and lint pushed files (#83)
    
    * fix(ci): add pre-commit gofmt hook and document formatting requirement
    
    Adds a lefthook pre-commit hook that auto-formats staged Go files with
    gofmt before commit. This catches formatting issues from subagents and
    code generators that run go build/vet but not gofmt. Updated AGENTS.md
    to document the formatting requirement explicitly.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    * fix(cli): convert if/else chain to switch for staticcheck QF1003
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    * fix(ci): run full golangci-lint on pre-push, not just changed files
    
    Removes --new-from-rev=origin/main from the pre-push hook so local
    lint matches CI behavior. Previously the local hook only linted files
    changed since main, which meant pre-existing issues from merged PRs
    were invisible locally but caught by CI — causing surprise failures
    on unrelated PRs.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    * fix(ci): lint only pushed Go files, not full repo
    
    Every committed file already passes gofmt via the pre-commit hook.
    The pre-push lint only needs to check the files being pushed, not
    the entire repo. CI remains the full-repo safety net.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
 AGENTS.md                       | 7 +++++--
 internal/generator/generator.go | 9 ++++++---
 lefthook.yml                    | 9 ++++++++-
 3 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index d80932e4..5db2c2f1 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -5,10 +5,13 @@
 ```bash
 go build -o ./printing-press ./cmd/printing-press
 go test ./...
-golangci-lint run --new-from-rev=origin/main ./...
+gofmt -w ./...
+golangci-lint run ./...
 ```
 
-A pre-push hook runs `golangci-lint` automatically on `git push`. The same config (`.golangci.yml`: errcheck, govet, staticcheck, unused) runs in CI. To run lint manually: `golangci-lint run --new-from-rev=origin/main ./...`
+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 ./...`
+
+**Always run `gofmt -w ./...` after writing Go code.** 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.
 
 **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/internal/generator/generator.go b/internal/generator/generator.go
index 90775f14..79bc212b 100644
--- a/internal/generator/generator.go
+++ b/internal/generator/generator.go
@@ -178,14 +178,17 @@ func (g *Generator) Generate() error {
 	}
 
 	for tmplName, outPath := range singleFiles {
-		data := any(g.Spec)
-		if tmplName == "readme.md.tmpl" {
+		var data any
+		switch tmplName {
+		case "readme.md.tmpl":
 			data = g.readmeData()
-		} else if tmplName == "helpers.go.tmpl" {
+		case "helpers.go.tmpl":
 			data = &helpersTemplateData{
 				APISpec:     g.Spec,
 				HelperFlags: computeHelperFlags(g.Spec),
 			}
+		default:
+			data = g.Spec
 		}
 		if err := g.renderTemplate(tmplName, outPath, data); err != nil {
 			return fmt.Errorf("rendering %s: %w", tmplName, err)
diff --git a/lefthook.yml b/lefthook.yml
index 5cdc4818..90ae45eb 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -1,3 +1,10 @@
+pre-commit:
+  commands:
+    fmt:
+      glob: "*.go"
+      run: gofmt -w {staged_files} && git add {staged_files}
+      stage_fixed: true
+
 pre-push:
   commands:
     fmt:
@@ -6,5 +13,5 @@ pre-push:
       fail_text: "gofmt failed. Run 'gofmt -w .' to fix."
     lint:
       glob: "*.go"
-      run: golangci-lint run --new-from-rev=origin/main ./...
+      run: golangci-lint run {push_files}
       fail_text: "golangci-lint failed. Fix lint errors before pushing."

← 14b9e74f fix(skills): merge codex detection into setup contract (#84)  ·  back to Cli Printing Press  ·  fix(skills): add mandatory sniff gate checkpoint before abso 5bc0b6b8 →