Driver
CI fails on pushes for things that are cheap to catch locally (markdownlint MD032, site-counts hook-count drift, shellcheck) — most recently on PR #504. The framework already ships pre-push-gate.sh (#111), a blocking pre-push check-runner that reads .pre_push.commands from .claude/project-config.json and blocks git push on any non-zero check. But the framework repo itself never populated .pre_push.commands (the hook's own comment notes this: "the apexyard framework repo itself before it configures its own CI in a separate ticket"), so it silently no-ops here. Wire it up so the framework dog-foods its own pre-push gate.
Scope
- Add
.pre_push.commands to .claude/project-config.json mirroring the locally-runnable CI jobs (from .github/workflows/):
markdownlint → the same markdownlint-cli2 invocation markdown-lint.yml uses (honour .markdownlint*.json)
shellcheck → shellcheck .claude/hooks/*.sh (match shellcheck.yml scope)
site-counts → bash .claude/hooks/tests/test_site_counts.sh
subpacks → bash .claude/hooks/tests/test_subpack_extraction.sh
- (Exclude
lychee/link-check — slow + network-flaky, not pre-push-friendly; leave it CI-only.)
pre-push-gate.sh is a Claude Code hook → only fires on pushes made through Claude. Add a real git pre-push hook for terminal pushes: a committed .githooks/pre-push running the same command set, plus a one-line opt-in (git config core.hooksPath .githooks) documented in docs/ and ideally auto-set by /setup. Keep the skip-marker escape hatch consistent with pre-push-gate.sh.
- Make each command degrade gracefully if its tool is missing (e.g.
command -v shellcheck / npx guard) so a contributor without a tool installed gets a clear "install X" message, not a cryptic failure.
Acceptance Criteria
Risks / Dependencies
Low. Builds on existing pre-push-gate.sh (#111). Don't make it so slow that contributors routinely skip-marker around it (exclude the slow link-check).
Glossary
| Term |
Definition |
| pre-push-gate.sh |
Existing Claude Code PreToolUse hook (#111) that runs .pre_push.commands and blocks git push on failure. |
| core.hooksPath |
Git config pointing at a committed hooks dir, so a real git pre-push hook ships in-repo and covers terminal pushes. |
Driver
CI fails on pushes for things that are cheap to catch locally (markdownlint MD032, site-counts hook-count drift, shellcheck) — most recently on PR #504. The framework already ships
pre-push-gate.sh(#111), a blocking pre-push check-runner that reads.pre_push.commandsfrom.claude/project-config.jsonand blocksgit pushon any non-zero check. But the framework repo itself never populated.pre_push.commands(the hook's own comment notes this: "the apexyard framework repo itself before it configures its own CI in a separate ticket"), so it silently no-ops here. Wire it up so the framework dog-foods its own pre-push gate.Scope
.pre_push.commandsto.claude/project-config.jsonmirroring the locally-runnable CI jobs (from.github/workflows/):markdownlint→ the samemarkdownlint-cli2invocationmarkdown-lint.ymluses (honour.markdownlint*.json)shellcheck→shellcheck .claude/hooks/*.sh(matchshellcheck.ymlscope)site-counts→bash .claude/hooks/tests/test_site_counts.shsubpacks→bash .claude/hooks/tests/test_subpack_extraction.shlychee/link-check — slow + network-flaky, not pre-push-friendly; leave it CI-only.)pre-push-gate.shis a Claude Code hook → only fires on pushes made through Claude. Add a real git pre-push hook for terminal pushes: a committed.githooks/pre-pushrunning the same command set, plus a one-line opt-in (git config core.hooksPath .githooks) documented indocs/and ideally auto-set by/setup. Keep the skip-marker escape hatch consistent withpre-push-gate.sh.command -v shellcheck/npxguard) so a contributor without a tool installed gets a clear "install X" message, not a cryptic failure.Acceptance Criteria
.pre_push.commandspopulated; a deliberately-broken commit (lint error / count drift) is BLOCKED bypre-push-gate.shon a Claude-drivengit push..githooks/pre-pushruns the same set and blocks a terminalgit pushon red;core.hooksPathwiring documented.Risks / Dependencies
Low. Builds on existing
pre-push-gate.sh(#111). Don't make it so slow that contributors routinely skip-marker around it (exclude the slow link-check).Glossary
.pre_push.commandsand blocksgit pushon failure.