Skip to content

[Chore] pre-push-gate.sh — upgrade from advisory reminder to blocking check-runner #111

@atlas-apex

Description

@atlas-apex

Driver

pre-push-gate.sh today reminds the user to run lint / typecheck / test / build before git push — prints the checklist and exits 0. The rule it enforces (from .claude/rules/pr-workflow.md) is explicitly labelled a HARD STOP"Never push without running CI checks locally." A reminder is not a hard stop. Observed failure mode: the gate prints, the agent continues, CI fails on the PR, cycle wastes time.

Scope

Upgrade pre-push-gate.sh from advisory to blocking:

  1. Read the project's pre-push command set from config (new field, default ships the canonical set):

    # .claude/project-config.json
    pre_push:
      commands:
        - name: lint
          run: "npm run lint"
        - name: typecheck
          run: "npm run typecheck"
        - name: test
          run: "npm run test"
        - name: build
          run: "npm run build"
      skip_marker: "<!-- pre-push: skip -->"   # for emergency hotfix paths
  2. Execute each command in sequence. Capture stdout/stderr.

  3. On any non-zero: exit 2 with a concise summary naming the failing command + a pointer to the full output log.

  4. Escape hatch: the skip marker, written into the most recent commit message, lets a push through. Use for true emergencies — leaves a grep-able trace.

  5. Skip condition (silent, no block): no .claude/project-config.json and no package.json — treat as a non-runnable repo (e.g. docs-only).

  6. Performance: run commands in parallel where safe (lint + typecheck are independent; test + build typically are). Configurable.

Acceptance Criteria

  • Hook runs configured commands on git push and blocks (exit 2) on any red.
  • Hook reads the command list from project config; ships a sensible default.
  • Failing command name + last 20 lines of output included in the block message.
  • Skip marker in the HEAD commit bypasses the gate (and prints a warning that it was bypassed).
  • docs/rule-audit.md updates the hook's entry from "advisory" to "blocking".
  • Fixtures in .claude/hooks/tests/ cover pass, fail, skip, and no-config paths.

Risks / Dependencies

  • Slow commands (build) extend push time from seconds to minutes. Mitigation: parallel execution; option to disable build via config.
  • Command failures that aren't the developer's fault (flaky tests, transient network) cause false blocks. Mitigation: skip marker escape hatch, clear.
  • Hook executes arbitrary commands from config — careful about executable paths, quoting, set -e behaviour. Lean on shellcheck; add a test that malformed config fails loudly rather than silently.
  • Shares config schema with apexyard#109. Land after [Chore] Make ticket-prefix whitelist + schema project-configurable (not hardcoded) #109.

Glossary

Term Definition
Advisory hook Prints a message and exits 0. Cannot block.
Blocking hook Exits 2, which Claude Code surfaces as a block and refuses the tool call.
Skip marker A token in a commit message or body that tells the hook to let this invocation through, with a visible warning.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — material gap or user-impactingenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions