init-pipeline
Init Pipeline
Scaffold pipeline enforcement infrastructure into the current project: Claude Code hooks for skill compliance, git guardrails for safety, and pre-commit hooks for code quality. Detects existing tools before suggesting defaults.
When to use
- Automatically invoked by
/executeStep 0 if.claude/hooks/enforce-classification.shis missing - Manually by the user when setting up a new project for pipeline work
What it sets up
All files are created in the target project, not in the Skill Kit repo.
1. Git guardrails (Claude Code hook)
Invoke /git-guardrails-claude-code with project scope.
This blocks dangerous git commands (git push, git reset --hard, git clean -f, git branch -D, git checkout ., git restore .) via a PreToolUse hook on Bash.
2. TDD classification gate (Claude Code hook)
Create .claude/hooks/enforce-classification.sh and make it executable. This blocks Write/Edit to implementation files unless the /execute Step 3 classification gate has been passed.
The hook checks for either .claude/.tdd-active (TDD invoked) or .claude/.tdd-skipped (visual frontend, explicitly opted out). No path checking beyond the trigger surface — it enforces "did you go through the gate?"
Install-time: ask which file patterns constitute implementation code. Before scaffolding the hook, present the user with the default include list and ask:
"The TDD classification gate fires on Write/Edit of files matching a pattern list. Default:
*.ts, *.tsx, *.astro, *.py, *.go, *.rb, *.java, *.rs, *.js, *.jsx, *.vue, *.svelte. Over-gating is acceptable — classification is a quick decision at the top of /execute, though backend/behavior-heavy matches will trigger a full /tdd cycle. Accept the default, or customize for this project?"
Use the confirmed list (default or customized) to populate the IMPL_PATTERNS array in the hook body below. Over-gating is acceptable — the cost of an extra classification prompt is lower than the cost of silent under-fire on a polyglot project. If /init-pipeline is running non-interactively (auto-invoked by /execute Step 0), accept the default list and record that fact in the hook body via a leading comment.
Skip logic stays extension-agnostic. Tests, type declarations, and config files are detected by path substring (*test*, *spec*, .d.ts, .config.*) rather than per-language expansion.
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Implementation patterns — populated at install time from the user's answer to
# the /init-pipeline trigger-surface question. Over-gating is intended.
IMPL_PATTERNS=("*.ts" "*.tsx" "*.astro" "*.py" "*.go" "*.rb" "*.java" "*.rs" "*.js" "*.jsx" "*.vue" "*.svelte")
MATCHED=0
for pattern in "${IMPL_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == $pattern ]]; then MATCHED=1; break; fi
done
if [ $MATCHED -eq 0 ]; then exit 0; fi
# Skip test files and type declarations (extension-agnostic)
if [[ "$FILE_PATH" == *test* || "$FILE_PATH" == *spec* || "$FILE_PATH" == *.d.ts ]]; then
exit 0
fi
# Skip config files (drizzle.config, vite.config, etc.)
if [[ "$FILE_PATH" == *.config.* ]]; then
exit 0
fi
# Check for classification markers
if [ ! -f "$CLAUDE_PROJECT_DIR/.claude/.tdd-active" ] && [ ! -f "$CLAUDE_PROJECT_DIR/.claude/.tdd-skipped" ]; then
echo '{"decision":"block","reason":"BLOCKED: classify work in /execute Step 3 before writing implementation files. Either invoke /tdd (backend/behavior-heavy) or create .claude/.tdd-skipped (visual frontend)."}' >&2
exit 2
fi
exit 0
After writing, run: chmod +x .claude/hooks/enforce-classification.sh
3. Claude Code settings
Create or merge .claude/settings.json with both hooks:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/enforce-classification.sh"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous-git.sh"
}
]
}
]
}
}
If .claude/settings.json already exists, merge the hooks.PreToolUse entries — do not overwrite existing settings.
4. Pre-commit hooks and package manager enforcement
Detect before suggesting. Before invoking any setup, check what the project already uses:
# Package manager — check lockfiles
ls pnpm-lock.yaml package-lock.json yarn.lock bun.lockb 2>/dev/null
# Formatter/linter — check deps and configs
grep -E "biome|prettier|eslint|oxlint|dprint" package.json 2>/dev/null
ls biome.json biome.jsonc .prettierrc .prettierrc.* prettier.config.* .eslintrc* eslint.config.* 2>/dev/null
# Hook manager — check for existing setup
ls lefthook.yml .husky 2>/dev/null
Present findings to the user and ask for confirmation:
- If a formatter/linter is detected → "Found [tool]. I'll use it for pre-commit hooks."
- If none detected → "No formatter/linter found. I'd suggest Biome (handles both formatting and linting, fast, zero-config). Want Biome, or something else?"
- If a hook manager is detected → "Found [Lefthook/Husky]. I'll use it." (Suggest migrating Husky to Lefthook if Husky is found.)
- If none detected → "No hook manager found. I'd suggest Lefthook. OK?"
- If a package manager lockfile is detected → use that package manager
- If none detected → "No lockfile found. I'd suggest pnpm. OK?"
After user confirms, invoke /setup-pre-commit with the confirmed tools.
Recommended Lefthook + Biome config (when both are confirmed):
# Pre-push hook for vitest run should be added after test suite stabilizes.
pre-commit:
commands:
check:
glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
run: pnpm biome check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}
stage_fixed: true
Key flags: --no-errors-on-unmatched prevents false failures when no staged files match, --files-ignore-unknown=true avoids Biome choking on unsupported files, --colors=off gives cleaner hook output. Skip typecheck in pre-commit (too slow) — add it as a pre-push hook later.
Package manager enforcement: If the confirmed package manager is pnpm (detected or chosen), add the only-allow guard:
{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}
For npm or yarn, skip this step — only-allow is only needed when enforcing pnpm specifically.
5. Quality gate (Claude Code hook — optional)
Ask the user: "Do you want a quality gate hook that runs feedback loops during editing? This catches issues while Claude works, not just at commit time."
If yes, create .claude/hooks/quality-gate.sh and make it executable. This runs as a PostToolUse hook on Write|Edit, providing immediate feedback after each file change.
Detect available feedback loops first. Check package.json scripts for check/lint, tsc/typecheck, and test/vitest. Only include loops that actually exist.
#!/bin/bash
# Quality gate — runs after each Write/Edit to catch issues early.
# Only runs on TypeScript/JavaScript files. Skips test/config files.
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Only gate TypeScript/JavaScript implementation files
if [[ ! "$FILE_PATH" == *.ts && ! "$FILE_PATH" == *.tsx && ! "$FILE_PATH" == *.js && ! "$FILE_PATH" == *.jsx ]]; then
exit 0
fi
# Skip test files, type declarations, config files
if [[ "$FILE_PATH" == *test* || "$FILE_PATH" == *spec* || "$FILE_PATH" == *.d.ts || "$FILE_PATH" == *.config.* ]]; then
exit 0
fi
# 1. Biome check (fast — format + lint)
BIOME_OUTPUT=$(pnpm biome check src/ 2>&1)
BIOME_EXIT=$?
# 2. TypeScript type check
TSC_OUTPUT=$(pnpm tsc --noEmit 2>&1)
TSC_EXIT=$?
if [ $BIOME_EXIT -ne 0 ] || [ $TSC_EXIT -ne 0 ]; then
if [ $BIOME_EXIT -ne 0 ]; then
echo "Biome errors found:" >&2
echo "$BIOME_OUTPUT" >&2
echo "" >&2
fi
if [ $TSC_EXIT -ne 0 ]; then
echo "TypeScript errors found:" >&2
echo "$TSC_OUTPUT" >&2
fi
exit 2
fi
# 3. Run tests for changed files only (vitest import graph analysis)
VITEST_OUTPUT=$(pnpm vitest run --changed 2>&1)
VITEST_EXIT=$?
if [ $VITEST_EXIT -ne 0 ]; then
echo "Tests failed for changed files:" >&2
echo "$VITEST_OUTPUT" >&2
exit 2
fi
exit 0
Project-specific extensions: If the project has domain-specific smoke tests (e.g., RAG agent tests, API health checks), append them after the generic checks. Use git diff --name-only HEAD to scope them to relevant directories.
After writing, run: chmod +x .claude/hooks/quality-gate.sh
Add the PostToolUse hook to .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/quality-gate.sh"
}
]
}
]
}
}
Merge into existing settings — do not overwrite.
6. .gitignore additions
Append these lines if not already present:
.claude/.tdd-active
.claude/.tdd-skipped
.claude/.ralph-checked
.claude/.ralph-checked is reserved here but created by /setup-ralph-loop, which is auto-invoked by /execute when a multi-slice task needs AFK bounds or may be run manually. /init-pipeline does not create the marker itself.
Verification
Before considering setup complete, check:
-
.claude/hooks/enforce-classification.shexists and is executable - Hook's
IMPL_PATTERNSarray matches the project's implementation surface as confirmed during install (default list or customized answer) -
.claude/hooks/block-dangerous-git.shexists and is executable -
.claude/settings.jsonhas both PreToolUse hooks configured - If quality gate accepted:
.claude/hooks/quality-gate.shexists, is executable, and PostToolUse hook is in settings - Hook manager config exists (e.g.
lefthook.yml) - Pre-commit hooks run successfully
-
.gitignorehas marker entries - No existing project settings were overwritten
Handoff
- Expected input: any project that will use
/execute - Produces: complete enforcement infrastructure — Claude Code hooks, git guardrails, pre-commit hooks using detected or user-confirmed tools
- Auto-invoked by:
/executeStep 0 when.claude/hooks/enforce-classification.shis missing - Invokes:
/git-guardrails-claude-code(project scope),/setup-pre-commit - Supports downstream:
/tdd(marker creation),/execute(marker cleanup); reserves.claude/.ralph-checkedfor/setup-ralph-loop, which creates the marker itself (auto-invoked by/executefor multi-slice work, or run manually)
More from chrislacey89/skills
pre-merge
Primary pipeline review step after verified implementation. Use to create a PR with lineage and run architectural review before merge. Not for QA intake, planning, or implementation work.
21execute
Primary pipeline execution step after /prd-to-issues or for clearly scoped implementation work. Use to build, verify, and commit a concrete slice, delegating to /tdd for backend work and behavior-heavy frontend logic when red-green-refactor will reduce risk. Not for shaping or pre-merge review.
20prd-to-issues
Primary pipeline decomposition step after /write-a-prd. Use when a shaped PRD is ready to become implementation-ready slices with boundary maps and dependency order. Not for unresolved scope, appetite, or solution direction.
13write-a-prd
Primary pipeline shaping step after /research and before /prd-to-issues. Use when the problem is understood well enough to turn into a bounded PRD issue. May invoke /design-an-interface or /api-design-review when interface or contract uncertainty remains. Not for discovery, decomposition, or implementation-ready work.
13research
Primary pipeline step after /shape and before /write-a-prd. Use to verify current docs, versions, repo patterns, and key unknowns before shaping. Invokes /api-design-review when API contract risk is high. Not for underdefined problems or implementation-ready work.
12setup-ralph-loop
Infrastructure skill for setting up Ralph loop scripts for Claude-driven AFK execution. Use when a repo wants a HITL-to-AFK runner around /execute with bounded iterations, GitHub-native durable state, and explicit feedback loops. Not a normal feature-delivery stage; it prepares the repo for safer autonomous execution.
11