[object Object]

← back to Cli Printing Press

fix(skills): preflight Go toolchain before generation runs (#973)

0562bca80e8588b02130edeec8dab7d0a3b1ec1d · 2026-05-10 14:47:27 -0700 · Trevin Chow

* fix(skills): preflight Go toolchain before generation runs

Generation produced 10K+ lines of Go scaffolding before the post-generation
`go mod tidy` quality gate failed with "exec: 'go': executable file not found
in $PATH". A user installed via `go install` but their interactive shell PATH
had `~/go/bin/printing-press` without `go` itself (WSL setup quirk; common when
the binary is invoked directly).

The preflight already runs `command -v go` inside the binary-not-found error
fallback to pick between two install messages, but never when the binary is
present. Add an unconditional Go-toolchain check after binary detection so the
binary-present + Go-absent path aborts in 30 seconds with an actionable
`[setup-error] Go toolchain not found.` block, before any AskUserQuestion.

Generalize section 1 of references/setup-checks.md so the existing handler
covers either missing prerequisite. Lock the new check in with a contract test.

Closes #793

* fix(skills): correct test comment scope for Go-toolchain check

Files touched

Diff

commit 0562bca80e8588b02130edeec8dab7d0a3b1ec1d
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sun May 10 14:47:27 2026 -0700

    fix(skills): preflight Go toolchain before generation runs (#973)
    
    * fix(skills): preflight Go toolchain before generation runs
    
    Generation produced 10K+ lines of Go scaffolding before the post-generation
    `go mod tidy` quality gate failed with "exec: 'go': executable file not found
    in $PATH". A user installed via `go install` but their interactive shell PATH
    had `~/go/bin/printing-press` without `go` itself (WSL setup quirk; common when
    the binary is invoked directly).
    
    The preflight already runs `command -v go` inside the binary-not-found error
    fallback to pick between two install messages, but never when the binary is
    present. Add an unconditional Go-toolchain check after binary detection so the
    binary-present + Go-absent path aborts in 30 seconds with an actionable
    `[setup-error] Go toolchain not found.` block, before any AskUserQuestion.
    
    Generalize section 1 of references/setup-checks.md so the existing handler
    covers either missing prerequisite. Lock the new check in with a contract test.
    
    Closes #793
    
    * fix(skills): correct test comment scope for Go-toolchain check
---
 internal/pipeline/contracts_test.go              | 14 ++++++++++++++
 skills/printing-press/SKILL.md                   | 17 +++++++++++++++++
 skills/printing-press/references/setup-checks.md |  8 ++++----
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/internal/pipeline/contracts_test.go b/internal/pipeline/contracts_test.go
index ed3bf55c..538525f5 100644
--- a/internal/pipeline/contracts_test.go
+++ b/internal/pipeline/contracts_test.go
@@ -96,6 +96,20 @@ func TestPrintingPressSkillUsesRunRootStateFile(t *testing.T) {
 	assert.Contains(t, skill, `"working_dir": "$CLI_WORK_DIR"`)
 }
 
+func TestPrintingPressSkillPreflightChecksGoToolchain(t *testing.T) {
+	skillPath := filepath.Join("..", "..", "skills", "printing-press", "SKILL.md")
+	full := readContractFile(t, skillPath)
+	block := extractContractBlock(t, full)
+
+	// The Go-toolchain presence check fires after the binary detection block
+	// exits cleanly (binary found or PATH-augmented). It catches binary-present
+	// + Go-absent and fails fast instead of crashing 5+ minutes later in the
+	// post-generation `go mod tidy` quality gate.
+	assert.Contains(t, block, `if ! command -v go >/dev/null 2>&1; then`)
+	assert.Contains(t, block, `[setup-error] Go toolchain not found.`)
+	assert.Contains(t, block, `https://go.dev/dl/`)
+}
+
 func TestPrintingPressSkillUsesRunstateForBuilds(t *testing.T) {
 	skill := readContractFile(t, filepath.Join("..", "..", "skills", "printing-press", "SKILL.md"))
 
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index 9a3b2c69..68e6fbe1 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -160,6 +160,23 @@ elif ! command -v printing-press >/dev/null 2>&1; then
   fi
 fi
 
+# Verify the Go toolchain is on PATH. Generation runs Go-based quality gates
+# (go mod tidy, go vet, etc.) after writing thousands of lines of scaffolding,
+# so a missing `go` only surfaces 5+ minutes in. Fail-fast costs one command -v
+# call when Go is present and converts a late, opaque failure into a 30-second
+# actionable abort.
+if ! command -v go >/dev/null 2>&1; then
+  echo ""
+  echo "[setup-error] Go toolchain not found."
+  echo ""
+  echo "The Printing Press generator runs Go-based quality gates after generation."
+  echo "Install Go 1.26.3 or newer from https://go.dev/dl/, then verify with:"
+  echo "  go version"
+  echo "Then re-run /printing-press."
+  echo ""
+  return 1 2>/dev/null || exit 1
+fi
+
 PRESS_BASE="$(basename "$_scope_dir" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9_-]/-/g; s/^-+//; s/-+$//')"
 if [ -z "$PRESS_BASE" ]; then
   PRESS_BASE="workspace"
diff --git a/skills/printing-press/references/setup-checks.md b/skills/printing-press/references/setup-checks.md
index cd7cfb05..dfd71044 100644
--- a/skills/printing-press/references/setup-checks.md
+++ b/skills/printing-press/references/setup-checks.md
@@ -4,13 +4,13 @@ Post-contract checks the skill must run after executing the bash setup contract
 
 Apply these in order. Each section is conditional — do nothing if its trigger isn't present.
 
-## 1. Refusal: missing binary
+## 1. Refusal: missing prerequisite
 
-If the setup contract output contains a line starting with `[setup-error]`, the printing-press binary is not installed and the contract has already exited non-zero.
+If the setup contract output contains a line starting with `[setup-error]`, a required prerequisite is missing (the printing-press binary or the Go toolchain) and the contract has already exited non-zero.
 
-**Stop the skill immediately.** Do not proceed to research, generation, or any other work. Surface the message the contract printed (it includes the exact `go install` command) verbatim to the user.
+**Stop the skill immediately.** Do not proceed to research, generation, or any other work. Surface the message the contract printed (it includes the exact install command or download URL) verbatim to the user.
 
-The user must install the binary in their terminal before re-running. Do not offer to auto-install — the README's two-step install is the source of truth, and silent auto-install hides failure modes (network, wrong GOPATH) inside an opaque skill invocation.
+The user must install the missing prerequisite in their terminal before re-running. Do not offer to auto-install — the README's two-step install is the source of truth for the binary, and silent auto-install hides failure modes (network, wrong GOPATH, no Go toolchain) inside an opaque skill invocation.
 
 ## 2. Interactive repo upgrade prompt
 

← ab6edbef fix(cli): route explicit --csv/--quiet/--plain above piped-p  ·  back to Cli Printing Press  ·  fix(cli): preserve hand-edits to templated files on --force 618fa456 →