[object Object]

← back to Cli Printing Press

chore(cli): add lefthook pre-push lint and deny --no-verify bypass (#39)

99d2dde8137a5983988379c546c7db1e506f751b · 2026-03-28 23:08:20 -0700 · Trevin Chow

* chore(cli): add lefthook pre-push lint and deny --no-verify bypass

Adds lefthook.yml with a pre-push hook that runs golangci-lint on
changed files, catching lint errors before they reach CI. Updates
AGENTS.md with the lint command, README with setup instructions,
and .claude/settings.json to deny --no-verify bypass.

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

* docs(cli): add PATH troubleshooting note to lefthook install instructions

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 99d2dde8137a5983988379c546c7db1e506f751b
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sat Mar 28 23:08:20 2026 -0700

    chore(cli): add lefthook pre-push lint and deny --no-verify bypass (#39)
    
    * chore(cli): add lefthook pre-push lint and deny --no-verify bypass
    
    Adds lefthook.yml with a pre-push hook that runs golangci-lint on
    changed files, catching lint errors before they reach CI. Updates
    AGENTS.md with the lint command, README with setup instructions,
    and .claude/settings.json to deny --no-verify bypass.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    * docs(cli): add PATH troubleshooting note to lefthook install instructions
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
 .claude/settings.json |  6 ++++++
 AGENTS.md             |  5 ++++-
 README.md             | 23 +++++++++++++++++++++++
 lefthook.yml          |  6 ++++++
 4 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/.claude/settings.json b/.claude/settings.json
index 4dc3775a..51a1f5f4 100644
--- a/.claude/settings.json
+++ b/.claude/settings.json
@@ -2,6 +2,12 @@
   "enabledPlugins": {
     "compound-engineering@every-marketplace": true
   },
+  "permissions": {
+    "deny": [
+      "Bash(git commit --no-verify:*)",
+      "Bash(git push --no-verify:*)"
+    ]
+  },
   "hooks": {
     "PostToolUse": [
       {
diff --git a/AGENTS.md b/AGENTS.md
index 2bf49f13..43c71a26 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,12 +1,15 @@
 # CLI Printing Press - Development Conventions
 
-## Build & Test
+## Build, Test & Lint
 
 ```bash
 go build -o ./printing-press ./cmd/printing-press
 go test ./...
+golangci-lint run --new-from-rev=origin/main ./...
 ```
 
+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 ./...`
+
 **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.
 
 ## Project Structure
diff --git a/README.md b/README.md
index 051ab97c..abd308b9 100644
--- a/README.md
+++ b/README.md
@@ -351,6 +351,29 @@ Synthesized from post-mortems on Notion and Linear runs. 14 changes to the skill
 
 **Emboss:** Now opt-in only. Offered at end of run, never triggered automatically.
 
+## Development
+
+After cloning, install git hooks so lint errors are caught before they reach CI:
+
+```bash
+go install github.com/evilmartians/lefthook@latest
+~/go/bin/lefthook install
+```
+
+> **Note:** If `lefthook` isn't found after `go install`, your `$GOPATH/bin` (`~/go/bin` by default) may not be in your `PATH`. Either use the full path as shown above, or add `export PATH="$HOME/go/bin:$PATH"` to your `~/.zshrc`.
+
+This adds a pre-push hook that runs `golangci-lint` on changed files. The same linter config (`.golangci.yml`) runs in CI — lefthook just catches failures locally first.
+
+If you also want `golangci-lint` locally:
+
+```bash
+# macOS
+brew install golangci-lint
+
+# or via go
+go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+```
+
 ## Credits
 
 - **Peter Steinberger** ([@steipete](https://github.com/steipete)) - [discrawl](https://github.com/steipete/discrawl) and [gogcli](https://github.com/steipete/gogcli) set the bar. The quality scoring system is inspired by his work. discrawl v0.2.0's sync architecture directly influenced the printing press templates.
diff --git a/lefthook.yml b/lefthook.yml
new file mode 100644
index 00000000..1c98da7a
--- /dev/null
+++ b/lefthook.yml
@@ -0,0 +1,6 @@
+pre-push:
+  commands:
+    lint:
+      glob: "*.go"
+      run: golangci-lint run --new-from-rev=origin/main ./...
+      fail_text: "golangci-lint failed. Fix lint errors before pushing."

← cc098e67 feat(cli): accept name or path in emboss command (#38)  ·  back to Cli Printing Press  ·  ci: re-trigger release-please after enabling PR creation per 7d9f8c7c →