[object Object]

← back to Cli Printing Press

fix(skills): emit PRINTING_PRESS_BIN marker so later phases survive PATH non-inheritance (#1399)

2698690ee63c41016fa0f9f86470631ee55e0a8b · 2026-05-14 12:08:48 -0700 · Trevin Chow

* fix(skills): emit PRINTING_PRESS_BIN marker so later phases survive PATH non-inheritance

The Printing Press skills' preflight contracts did `export PATH=...` to
prefer the local repo build, but `export` only affects the single Bash
tool call it runs in. Subsequent Bash tool calls open a fresh shell where
the user's default PATH resolves bare `printing-press` to whatever was
last `go install`-ed globally, silently shadowing the local build the
preflight just chose.

Resolve the absolute binary path in preflight and emit it as a captured
`PRINTING_PRESS_BIN=<abs-path>` marker the agent substitutes into every
later invocation. Add an optional `[binary-shadow]` advisory in the main
skill that surfaces version drift between the local build and a global
on disk. Apply the same minimal change to catalog/publish/score sibling
skills, which share the identical defective pattern.

Document the marker and absolute-path rule in references/setup-checks.md
as section 6 (unconditional, applies every run).

Closes #1259

* fix(skills): capture PRINTING_PRESS_BIN in setup-checks preamble before sections 3 and 4

The original section ordering had the version-check sections (3 min-binary-version,
4 standalone-upgrade confirmation) run before section 6 introduced the absolute-path
rule. An agent following sections in order would invoke `printing-press version --json`
through the user's default PATH for those checks, which is the exact shadow bug the
PR fixes.

Move the unconditional PRINTING_PRESS_BIN capture into a Preamble block that runs
before any numbered section, and update sections 3 and 4 to explicitly invoke
`<PRINTING_PRESS_BIN> version --json`. Section 6 now covers only the optional
`[binary-shadow]` advisory.

Surfaced by Greptile on #1399.

* fix(skills): re-resolve PRINTING_PRESS_BIN after section 4 go install

After the user accepts the standalone upgrade, `go install` writes to
`$(go env GOBIN)` or `$(go env GOPATH)/bin`, which may not be the same
path the contract captured at preflight (e.g. the pre-upgrade binary
lived at /opt/homebrew/bin/printing-press). Without re-resolution the
agent kept invoking the stale pre-upgrade binary while reporting a
successful upgrade.

Add a one-shot Bash snippet in section 4 that re-emits
`PRINTING_PRESS_BIN=<abs-path>` from `go env GOBIN/GOPATH`, falling back
to `command -v printing-press`. The agent captures the new value and
overrides the preamble capture for the rest of the run.

Surfaced by Greptile on #1399.

Files touched

Diff

commit 2698690ee63c41016fa0f9f86470631ee55e0a8b
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Thu May 14 12:08:48 2026 -0700

    fix(skills): emit PRINTING_PRESS_BIN marker so later phases survive PATH non-inheritance (#1399)
    
    * fix(skills): emit PRINTING_PRESS_BIN marker so later phases survive PATH non-inheritance
    
    The Printing Press skills' preflight contracts did `export PATH=...` to
    prefer the local repo build, but `export` only affects the single Bash
    tool call it runs in. Subsequent Bash tool calls open a fresh shell where
    the user's default PATH resolves bare `printing-press` to whatever was
    last `go install`-ed globally, silently shadowing the local build the
    preflight just chose.
    
    Resolve the absolute binary path in preflight and emit it as a captured
    `PRINTING_PRESS_BIN=<abs-path>` marker the agent substitutes into every
    later invocation. Add an optional `[binary-shadow]` advisory in the main
    skill that surfaces version drift between the local build and a global
    on disk. Apply the same minimal change to catalog/publish/score sibling
    skills, which share the identical defective pattern.
    
    Document the marker and absolute-path rule in references/setup-checks.md
    as section 6 (unconditional, applies every run).
    
    Closes #1259
    
    * fix(skills): capture PRINTING_PRESS_BIN in setup-checks preamble before sections 3 and 4
    
    The original section ordering had the version-check sections (3 min-binary-version,
    4 standalone-upgrade confirmation) run before section 6 introduced the absolute-path
    rule. An agent following sections in order would invoke `printing-press version --json`
    through the user's default PATH for those checks, which is the exact shadow bug the
    PR fixes.
    
    Move the unconditional PRINTING_PRESS_BIN capture into a Preamble block that runs
    before any numbered section, and update sections 3 and 4 to explicitly invoke
    `<PRINTING_PRESS_BIN> version --json`. Section 6 now covers only the optional
    `[binary-shadow]` advisory.
    
    Surfaced by Greptile on #1399.
    
    * fix(skills): re-resolve PRINTING_PRESS_BIN after section 4 go install
    
    After the user accepts the standalone upgrade, `go install` writes to
    `$(go env GOBIN)` or `$(go env GOPATH)/bin`, which may not be the same
    path the contract captured at preflight (e.g. the pre-upgrade binary
    lived at /opt/homebrew/bin/printing-press). Without re-resolution the
    agent kept invoking the stale pre-upgrade binary while reporting a
    successful upgrade.
    
    Add a one-shot Bash snippet in section 4 that re-emits
    `PRINTING_PRESS_BIN=<abs-path>` from `go env GOBIN/GOPATH`, falling back
    to `command -v printing-press`. The agent captures the new value and
    overrides the preamble capture for the rest of the run.
    
    Surfaced by Greptile on #1399.
---
 skills/printing-press-catalog/SKILL.md           | 19 +++++++++-
 skills/printing-press-publish/SKILL.md           | 19 +++++++++-
 skills/printing-press-score/SKILL.md             | 19 +++++++++-
 skills/printing-press/SKILL.md                   | 46 ++++++++++++++++++++++--
 skills/printing-press/references/setup-checks.md | 44 ++++++++++++++++++++---
 5 files changed, 138 insertions(+), 9 deletions(-)

diff --git a/skills/printing-press-catalog/SKILL.md b/skills/printing-press-catalog/SKILL.md
index aaeab8f5..2432d8d4 100644
--- a/skills/printing-press-catalog/SKILL.md
+++ b/skills/printing-press-catalog/SKILL.md
@@ -46,7 +46,9 @@ _scope_dir="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
 _scope_dir="$(cd "$_scope_dir" && pwd -P)"
 
 # Prefer local build when running from inside the printing-press repo.
+_press_repo=false
 if [ -x "$_scope_dir/printing-press" ] && [ -d "$_scope_dir/cmd/printing-press" ]; then
+  _press_repo=true
   export PATH="$_scope_dir:$PATH"
   echo "Using local build: $_scope_dir/printing-press"
 elif ! command -v printing-press >/dev/null 2>&1; then
@@ -60,6 +62,19 @@ elif ! command -v printing-press >/dev/null 2>&1; then
   return 1 2>/dev/null || exit 1
 fi
 
+# Resolve and emit the absolute path the agent must use for every later
+# `printing-press` invocation. `export PATH` above only affects this one
+# Bash tool call; subsequent calls open a fresh shell and resolve bare
+# `printing-press` against the user's default PATH, where a stale global
+# can silently shadow the local build. The agent captures this marker and
+# substitutes the absolute path into every later invocation.
+if [ "$_press_repo" = "true" ]; then
+  PRINTING_PRESS_BIN="$_scope_dir/printing-press"
+else
+  PRINTING_PRESS_BIN="$(command -v printing-press 2>/dev/null || true)"
+fi
+echo "PRINTING_PRESS_BIN=$PRINTING_PRESS_BIN"
+
 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"
@@ -74,7 +89,9 @@ mkdir -p "$PRESS_RUNSTATE" "$PRESS_LIBRARY"
 ```
 <!-- PRESS_SETUP_CONTRACT_END -->
 
-After running the setup contract, check binary version compatibility. Read the `min-binary-version` field from this skill's YAML frontmatter. Run `printing-press version --json` and parse the version from the output. Compare it to `min-binary-version` using semver rules. If the installed binary is older than the minimum, stop immediately and tell the user: "printing-press binary vX.Y.Z is older than the minimum required vA.B.C. Run `go install github.com/mvanhorn/cli-printing-press/v4/cmd/printing-press@latest` to update."
+After running the setup contract, capture the `PRINTING_PRESS_BIN=<abs-path>` line from stdout. **Every subsequent `printing-press ...` invocation in this skill must use that absolute path** (substitute the value, not the literal `$PRINTING_PRESS_BIN` token) — `export PATH` above only affects the single Bash tool call it runs in, so later calls open a fresh shell where bare `printing-press` resolves against the user's default `PATH` and a stale global can shadow the local build.
+
+After capturing the binary path, check binary version compatibility. Read the `min-binary-version` field from this skill's YAML frontmatter. Run `<PRINTING_PRESS_BIN> version --json` and parse the version from the output. Compare it to `min-binary-version` using semver rules. If the installed binary is older than the minimum, stop immediately and tell the user: "printing-press binary vX.Y.Z is older than the minimum required vA.B.C. Run `go install github.com/mvanhorn/cli-printing-press/v4/cmd/printing-press@latest` to update."
 
 Generated CLIs are published to `$PRESS_LIBRARY/`, not to the repo.
 
diff --git a/skills/printing-press-publish/SKILL.md b/skills/printing-press-publish/SKILL.md
index 6a891c31..958945c7 100644
--- a/skills/printing-press-publish/SKILL.md
+++ b/skills/printing-press-publish/SKILL.md
@@ -46,7 +46,9 @@ _scope_dir="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
 _scope_dir="$(cd "$_scope_dir" && pwd -P)"
 
 # Prefer local build when running from inside the printing-press repo.
+_press_repo=false
 if [ -x "$_scope_dir/printing-press" ] && [ -d "$_scope_dir/cmd/printing-press" ]; then
+  _press_repo=true
   export PATH="$_scope_dir:$PATH"
   echo "Using local build: $_scope_dir/printing-press"
 elif ! command -v printing-press >/dev/null 2>&1; then
@@ -60,6 +62,19 @@ elif ! command -v printing-press >/dev/null 2>&1; then
   return 1 2>/dev/null || exit 1
 fi
 
+# Resolve and emit the absolute path the agent must use for every later
+# `printing-press` invocation. `export PATH` above only affects this one
+# Bash tool call; subsequent calls open a fresh shell and resolve bare
+# `printing-press` against the user's default PATH, where a stale global
+# can silently shadow the local build. The agent captures this marker and
+# substitutes the absolute path into every later invocation.
+if [ "$_press_repo" = "true" ]; then
+  PRINTING_PRESS_BIN="$_scope_dir/printing-press"
+else
+  PRINTING_PRESS_BIN="$(command -v printing-press 2>/dev/null || true)"
+fi
+echo "PRINTING_PRESS_BIN=$PRINTING_PRESS_BIN"
+
 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"
@@ -76,7 +91,9 @@ mkdir -p "$PRESS_RUNSTATE" "$PRESS_LIBRARY" "$PRESS_MANUSCRIPTS" "$PRESS_CURRENT
 ```
 <!-- PRESS_SETUP_CONTRACT_END -->
 
-After running the setup contract, check binary version compatibility. Read the `min-binary-version` field from this skill's YAML frontmatter. Run `printing-press version --json` and parse the version from the output. Compare it to `min-binary-version` using semver rules. If the installed binary is older than the minimum, stop immediately and tell the user: "printing-press binary vX.Y.Z is older than the minimum required vA.B.C. Run `go install github.com/mvanhorn/cli-printing-press/v4/cmd/printing-press@latest` to update."
+After running the setup contract, capture the `PRINTING_PRESS_BIN=<abs-path>` line from stdout. **Every subsequent `printing-press ...` invocation in this skill must use that absolute path** (substitute the value, not the literal `$PRINTING_PRESS_BIN` token) — `export PATH` above only affects the single Bash tool call it runs in, so later calls open a fresh shell where bare `printing-press` resolves against the user's default `PATH` and a stale global can shadow the local build.
+
+After capturing the binary path, check binary version compatibility. Read the `min-binary-version` field from this skill's YAML frontmatter. Run `<PRINTING_PRESS_BIN> version --json` and parse the version from the output. Compare it to `min-binary-version` using semver rules. If the installed binary is older than the minimum, stop immediately and tell the user: "printing-press binary vX.Y.Z is older than the minimum required vA.B.C. Run `go install github.com/mvanhorn/cli-printing-press/v4/cmd/printing-press@latest` to update."
 
 ## Configuration
 
diff --git a/skills/printing-press-score/SKILL.md b/skills/printing-press-score/SKILL.md
index 3dc14556..f883361c 100644
--- a/skills/printing-press-score/SKILL.md
+++ b/skills/printing-press-score/SKILL.md
@@ -42,7 +42,9 @@ _scope_dir="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
 _scope_dir="$(cd "$_scope_dir" && pwd -P)"
 
 # Prefer local build when running from inside the printing-press repo.
+_press_repo=false
 if [ -x "$_scope_dir/printing-press" ] && [ -d "$_scope_dir/cmd/printing-press" ]; then
+  _press_repo=true
   export PATH="$_scope_dir:$PATH"
   echo "Using local build: $_scope_dir/printing-press"
 elif ! command -v printing-press >/dev/null 2>&1; then
@@ -56,6 +58,19 @@ elif ! command -v printing-press >/dev/null 2>&1; then
   return 1 2>/dev/null || exit 1
 fi
 
+# Resolve and emit the absolute path the agent must use for every later
+# `printing-press` invocation. `export PATH` above only affects this one
+# Bash tool call; subsequent calls open a fresh shell and resolve bare
+# `printing-press` against the user's default PATH, where a stale global
+# can silently shadow the local build. The agent captures this marker and
+# substitutes the absolute path into every later invocation.
+if [ "$_press_repo" = "true" ]; then
+  PRINTING_PRESS_BIN="$_scope_dir/printing-press"
+else
+  PRINTING_PRESS_BIN="$(command -v printing-press 2>/dev/null || true)"
+fi
+echo "PRINTING_PRESS_BIN=$PRINTING_PRESS_BIN"
+
 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"
@@ -72,7 +87,9 @@ mkdir -p "$PRESS_RUNSTATE" "$PRESS_LIBRARY" "$PRESS_MANUSCRIPTS" "$PRESS_CURRENT
 ```
 <!-- PRESS_SETUP_CONTRACT_END -->
 
-After running the setup contract, check binary version compatibility. Read the `min-binary-version` field from this skill's YAML frontmatter. Run `printing-press version --json` and parse the version from the output. Compare it to `min-binary-version` using semver rules. If the installed binary is older than the minimum, stop immediately and tell the user: "printing-press binary vX.Y.Z is older than the minimum required vA.B.C. Run `go install github.com/mvanhorn/cli-printing-press/v4/cmd/printing-press@latest` to update."
+After running the setup contract, capture the `PRINTING_PRESS_BIN=<abs-path>` line from stdout. **Every subsequent `printing-press ...` invocation in this skill must use that absolute path** (substitute the value, not the literal `$PRINTING_PRESS_BIN` token) — `export PATH` above only affects the single Bash tool call it runs in, so later calls open a fresh shell where bare `printing-press` resolves against the user's default `PATH` and a stale global can shadow the local build.
+
+After capturing the binary path, check binary version compatibility. Read the `min-binary-version` field from this skill's YAML frontmatter. Run `<PRINTING_PRESS_BIN> version --json` and parse the version from the output. Compare it to `min-binary-version` using semver rules. If the installed binary is older than the minimum, stop immediately and tell the user: "printing-press binary vX.Y.Z is older than the minimum required vA.B.C. Run `go install github.com/mvanhorn/cli-printing-press/v4/cmd/printing-press@latest` to update."
 
 Current-run state is resolved from `$PRESS_RUNSTATE`. Published CLIs are resolved from `$PRESS_LIBRARY`. Archived manuscripts are resolved from `$PRESS_MANUSCRIPTS`.
 
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index 216d234a..4db82b1e 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -177,6 +177,46 @@ if ! command -v go >/dev/null 2>&1; then
   return 1 2>/dev/null || exit 1
 fi
 
+# Resolve and emit the absolute path the agent must use for every later
+# `printing-press` invocation. `export PATH` above only affects this one
+# Bash tool call; subsequent calls open a fresh shell and resolve bare
+# `printing-press` against the user's default PATH. When a global is
+# installed at a stale version, that silently shadows the local build the
+# preflight just chose. Handing the agent an absolute path eliminates the
+# shadow.
+if [ "$_press_repo" = "true" ] && [ -x "$_scope_dir/printing-press" ]; then
+  PRINTING_PRESS_BIN="$_scope_dir/printing-press"
+else
+  PRINTING_PRESS_BIN="$(command -v printing-press 2>/dev/null || true)"
+fi
+echo "PRINTING_PRESS_BIN=$PRINTING_PRESS_BIN"
+
+# Shadow detector (advisory). When a local build is in use, surface any
+# differing global so the user can see at a glance that the two binaries
+# disagree. Detect-only: the absolute path emitted above is the one the
+# agent will actually invoke; this warning does not change selection.
+if [ "$_press_repo" = "true" ] && [ -x "$_scope_dir/printing-press" ]; then
+  _global_bin=""
+  for _candidate in "$HOME/go/bin/printing-press" "/usr/local/bin/printing-press" "/opt/homebrew/bin/printing-press"; do
+    if [ -x "$_candidate" ] && [ "$_candidate" != "$_scope_dir/printing-press" ]; then
+      _global_bin="$_candidate"
+      break
+    fi
+  done
+  if [ -n "$_global_bin" ]; then
+    _local_v="$("$_scope_dir/printing-press" version --json 2>/dev/null | sed -nE 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p')"
+    _global_v="$("$_global_bin" version --json 2>/dev/null | sed -nE 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p')"
+    if [ -n "$_local_v" ] && [ -n "$_global_v" ] && [ "$_local_v" != "$_global_v" ]; then
+      echo ""
+      echo "[binary-shadow] local build v$_local_v differs from global v$_global_v at $_global_bin"
+      echo "PRESS_BIN_LOCAL_VERSION=$_local_v"
+      echo "PRESS_BIN_GLOBAL_VERSION=$_global_v"
+      echo "PRESS_BIN_GLOBAL_PATH=$_global_bin"
+      echo ""
+    fi
+  fi
+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"
@@ -333,9 +373,11 @@ CODEX_CONSECUTIVE_FAILURES=0
 ```
 <!-- PRESS_SETUP_CONTRACT_END -->
 
-**MANDATORY: Read and apply [references/setup-checks.md](references/setup-checks.md) immediately after the setup contract bash block runs, before any other action.** It handles five signals the contract emits to stdout: `[setup-error]` (refuse to run, surface the install instructions), `[repo-upgrade-available]` (interactive `AskUserQuestion` prompt + optional repo pull), the min-binary-version compatibility check (hard stop if binary is too old), `[upgrade-available]` (interactive `AskUserQuestion` prompt + optional standalone binary upgrade), and `[browser-tools-missing]` (interactive `AskUserQuestion` prompt + optional install of browser-use and/or agent-browser). Skipping the reference will cause the skill to proceed with a missing or out-of-date binary, or hit a mid-flight install prompt if browser-sniff is later needed. Do not skip.
+**MANDATORY: Read and apply [references/setup-checks.md](references/setup-checks.md) immediately after the setup contract bash block runs, before any other action.** It handles six signals the contract emits to stdout: `[setup-error]` (refuse to run, surface the install instructions), `[repo-upgrade-available]` (interactive `AskUserQuestion` prompt + optional repo pull), the min-binary-version compatibility check (hard stop if binary is too old), `[upgrade-available]` (interactive `AskUserQuestion` prompt + optional standalone binary upgrade), `[browser-tools-missing]` (interactive `AskUserQuestion` prompt + optional install of browser-use and/or agent-browser), and the `PRINTING_PRESS_BIN=<abs-path>` marker plus optional `[binary-shadow]` warning (capture the path; use it for every subsequent `printing-press` invocation). Skipping the reference will cause the skill to proceed with a missing or out-of-date binary, hit a mid-flight install prompt if browser-sniff is later needed, or invoke the wrong binary because a stale global on `PATH` shadowed the local build. Do not skip.
+
+**Absolute-path rule.** The preflight contract always emits `PRINTING_PRESS_BIN=<absolute path>` to stdout. Capture this value and substitute it (the resolved absolute path, not the literal `$PRINTING_PRESS_BIN` token) for every subsequent `printing-press ...` invocation in this skill, references, and any sub-skill you delegate to. The `export PATH=...` line inside the contract only affects the single Bash tool call it runs in; later Bash tool calls open fresh shells and resolve bare `printing-press` against the user's default `PATH`, where a stale globally-installed binary (`$HOME/go/bin/printing-press`, Homebrew copy, etc.) will silently shadow the local build the preflight just chose. Bash code examples below are written `printing-press generate ...` for readability — replace `printing-press` with the captured absolute path each time you actually run one.
 
-Only after preflight completes successfully (no `[setup-error]`; any `[repo-upgrade-available]`, `[upgrade-available]`, or `[browser-tools-missing]` was offered to the user) should you proceed to the Orientation & Briefing section below.
+Only after preflight completes successfully (no `[setup-error]`; any `[repo-upgrade-available]`, `[upgrade-available]`, or `[browser-tools-missing]` was offered to the user; `PRINTING_PRESS_BIN` is captured) should you proceed to the Orientation & Briefing section below.
 
 ## Orientation & Briefing
 
diff --git a/skills/printing-press/references/setup-checks.md b/skills/printing-press/references/setup-checks.md
index d550c511..d7214a40 100644
--- a/skills/printing-press/references/setup-checks.md
+++ b/skills/printing-press/references/setup-checks.md
@@ -1,8 +1,16 @@
 # Setup Checks
 
-Post-contract checks the skill must run after executing the bash setup contract block in `SKILL.md`. These handle five signals the contract emits to stdout: `[setup-error]`, `[repo-upgrade-available]`, `[upgrade-available]`, `[browser-tools-missing]`, and the `min-binary-version` compatibility check.
+Post-contract checks the skill must run after executing the bash setup contract block in `SKILL.md`. These handle six signals the contract emits to stdout: `[setup-error]`, `[repo-upgrade-available]`, the `min-binary-version` compatibility check, `[upgrade-available]`, `[browser-tools-missing]`, and the always-emitted `PRINTING_PRESS_BIN=<abs-path>` marker (with optional `[binary-shadow]` advisory).
 
-Apply these in order. Each section is conditional — do nothing if its trigger isn't present.
+Apply these in order. The preamble below runs unconditionally; each numbered section after it is conditional — do nothing if its trigger isn't present.
+
+## Preamble: Capture the absolute binary path (unconditional)
+
+Before applying any numbered section below, capture the `PRINTING_PRESS_BIN=<absolute path to the binary>` line the contract emitted to stdout. Every `printing-press ...` invocation referenced anywhere below — including the `version --json` calls in sections 3 and 4 — must be made using that absolute path (substitute the captured value, not the literal `$PRINTING_PRESS_BIN` token). The contract's `export PATH=...` line only affects the single Bash tool call it runs in; later Bash tool calls open fresh shells where bare `printing-press` resolves against the user's default `PATH`, and a stale globally-installed binary (`$HOME/go/bin/printing-press` from an earlier `go install`, a Homebrew copy, etc.) will silently shadow the local repo build the contract selected. Using the absolute path eliminates the shadow.
+
+If `PRINTING_PRESS_BIN` was emitted as an empty value (`PRINTING_PRESS_BIN=`), the contract was unable to resolve a binary; this should have already been surfaced as `[setup-error]` (handled in section 1 below). Treat an empty value here as a setup-error fallback and stop.
+
+This rule applies to *all* `printing-press` references in the rest of this document. Where sections below write `printing-press version --json` or similar, read that as shorthand for `<PRINTING_PRESS_BIN> version --json` with the captured value substituted.
 
 ## 1. Refusal: missing prerequisite
 
@@ -56,7 +64,7 @@ If no `[repo-upgrade-available]` line was emitted, skip this section entirely.
 
 ## 3. Min-binary-version compatibility
 
-Check binary version compatibility against the skill's declared minimum. Read the `min-binary-version` field from the skill's YAML frontmatter. Run `printing-press version --json` and parse the version from the output. Compare it to `min-binary-version` using semver rules.
+Check binary version compatibility against the skill's declared minimum. Read the `min-binary-version` field from the skill's YAML frontmatter. Run `<PRINTING_PRESS_BIN> version --json` (using the absolute path captured in the preamble — not bare `printing-press`, which would resolve against the user's default `PATH` and could interrogate a stale global) and parse the version from the output. Compare it to `min-binary-version` using semver rules.
 
 If the installed binary is older than the minimum, stop the skill immediately and tell the user:
 
@@ -86,7 +94,19 @@ If the user picks **Yes**, run:
 go install github.com/mvanhorn/cli-printing-press/v4/cmd/printing-press@latest
 ```
 
-After it completes, confirm with `printing-press version --json` and tell the user `"Upgraded to v<new>."` **Continue this current setup run with the freshly installed binary on disk — do not stop, do not reload the session, do not skip the remaining checks (min-binary-version compatibility, etc.).**
+After `go install` completes, **re-resolve `PRINTING_PRESS_BIN`** before confirming. `go install` writes to `$(go env GOBIN)` if set, otherwise `$(go env GOPATH)/bin` — which may not be the same path the contract originally captured (e.g. when the pre-upgrade binary was at `/opt/homebrew/bin/printing-press` or `/usr/local/bin/printing-press`, the new binary lives at `$GOPATH/bin/printing-press` and the old one is unchanged). Run this re-resolution in a single Bash call so its stdout becomes the new captured value:
+
+```bash
+_gobin="$(go env GOBIN 2>/dev/null)"
+[ -z "$_gobin" ] && _gobin="$(go env GOPATH 2>/dev/null)/bin"
+if [ -x "$_gobin/printing-press" ]; then
+  echo "PRINTING_PRESS_BIN=$_gobin/printing-press"
+else
+  echo "PRINTING_PRESS_BIN=$(command -v printing-press 2>/dev/null || true)"
+fi
+```
+
+Capture the new `PRINTING_PRESS_BIN=<abs-path>` value and use it for every subsequent `printing-press ...` invocation in the rest of this run, overriding the value captured in the preamble. Then confirm with `<PRINTING_PRESS_BIN> version --json` and tell the user `"Upgraded to v<new>."` **Continue this current setup run with the freshly installed binary on disk — do not stop, do not reload the session, do not skip the remaining checks (min-binary-version compatibility, etc.).**
 
 Separately, as out-of-band advice for the user's *next* session (not a stop signal for this run), tell them they can also refresh their installed skill files outside the repo checkout by running one of:
 
@@ -165,3 +185,19 @@ If an install command fails (no Python, no Node.js, network error), surface the
 If the user picks **Skip for this run**, continue without prompting further this run. The decision is not cached — the prompt re-fires on the next run if the tool is still missing.
 
 If no `[browser-tools-missing]` line was emitted, skip this section entirely.
+
+## 6. Optional shadow advisory
+
+If the setup contract output contains a line starting with `[binary-shadow]`, parse the follow-up lines:
+
+- `PRESS_BIN_LOCAL_VERSION=<version reported by the local build>`
+- `PRESS_BIN_GLOBAL_VERSION=<version reported by the differing global on PATH>`
+- `PRESS_BIN_GLOBAL_PATH=<absolute path to the differing global>`
+
+Surface a single-line note to the user before continuing — informational only, do not prompt:
+
+> "Note: a global printing-press v`<global>` is installed at `<path>` but the local repo build is v`<local>`. This run will use the local build (the absolute path the preflight selected); the global is unchanged."
+
+Then continue. Do not modify or remove the global. The note exists so the user can reconcile the divergence on their own time (typically with `go install ...@latest` once they want the new version everywhere).
+
+If no `[binary-shadow]` line was emitted, skip the advisory and continue.

← ac83f0fd fix(generator): support single-env basic auth credentials (#  ·  back to Cli Printing Press  ·  fix(cli): isolate typed-table upsert failures with per-item 89f38c4c →