session-start-hook
npx skills add https://github.com/laurigates/claude-plugins --skill session-start-hook
Agent 安装分布
Skill 文档
/hooks:session-start-hook
Generate a SessionStart hook that prepares your repository for Claude Code on the web â installing dependencies, configuring environment variables, and verifying that tests and linters work.
When to Use This Skill
| Use this skill when… | Use /hooks:hooks-configuration instead when… |
|---|---|
| Setting up a repo for Claude Code on the web | Configuring other hook types (PreToolUse, Stop, etc.) |
| Need automatic dependency install in web sessions | Need general hooks knowledge or debugging |
| Want tests/linters verified on session start | Writing custom hook logic from scratch |
| Onboarding a project to remote Claude Code | Understanding hook lifecycle events |
Context
Detect project stack:
- Lockfiles: !
find . -maxdepth 1 \( -name 'package-lock.json' -o -name 'yarn.lock' -o -name 'pnpm-lock.yaml' -o -name 'bun.lockb' -o -name 'poetry.lock' -o -name 'uv.lock' -o -name 'Cargo.lock' -o -name 'go.sum' -o -name 'Gemfile.lock' \) 2>/dev/null - Project files: !
find . -maxdepth 1 \( -name 'package.json' -o -name 'pyproject.toml' -o -name 'requirements.txt' -o -name 'Cargo.toml' -o -name 'go.mod' -o -name 'Gemfile' -o -name 'pom.xml' \) -o -maxdepth 1 -name 'build.gradle*' 2>/dev/null - Linter configs: !
find . -maxdepth 1 \( -name 'biome.json' -o -name 'biome.jsonc' -o -name '.eslintrc*' -o -name 'eslint.config.*' \) 2>/dev/null - Existing settings: !
cat .claude/settings.json 2>/dev/null - Existing hooks dir: !
find . -maxdepth 2 -type d -name 'scripts' 2>/dev/null
Parameters
| Flag | Default | Description |
|---|---|---|
--remote-only |
off | Wrap script in CLAUDE_CODE_REMOTE guard â hook exits immediately in local sessions |
--no-verify |
off | Skip test/linter verification step in the generated script |
Execution
Phase 1: Detect Project Stack
Identify all languages and tooling from the context above.
Language detection:
| File Present | Language | Package Manager (from lockfile) |
|---|---|---|
package.json |
Node.js | npm (package-lock.json), yarn (yarn.lock), pnpm (pnpm-lock.yaml), bun (bun.lockb) |
pyproject.toml |
Python | poetry (poetry.lock), uv (uv.lock), pip (fallback) |
requirements.txt |
Python | pip |
Cargo.toml |
Rust | cargo |
go.mod |
Go | go modules |
Gemfile |
Ruby | bundler |
pom.xml |
Java | maven |
build.gradle* |
Java/Kotlin | gradle |
Test runner detection:
| Language | How to Detect | Test Command |
|---|---|---|
| Node.js | scripts.test in package.json |
npm test / bun test / etc. |
| Python | [tool.pytest] in pyproject.toml, or pytest in deps |
pytest |
| Rust | always available | cargo test |
| Go | always available | go test ./... |
| Ruby | Gemfile contains rspec or minitest |
bundle exec rspec / bundle exec rake test |
| Java | pom.xml / build.gradle | mvn test / gradle test |
Linter detection:
| Config File | Linter | Command |
|---|---|---|
biome.json / biome.jsonc |
Biome | npx biome check . |
.eslintrc* / eslint.config.* |
ESLint | npx eslint . |
[tool.ruff] in pyproject.toml |
Ruff | ruff check . |
Cargo.toml |
Clippy | cargo clippy |
Report detected stack to user before generating.
Phase 2: Generate Hook Script
Create the script at scripts/claude-session-start.sh (or .claude/hooks/session-start.sh if no scripts/ directory exists).
Script template â adapt per detected stack:
#!/bin/bash
# Claude Code SessionStart Hook
# Generated by /hooks:session-start-hook
# Installs dependencies and verifies tooling for web sessions
{{ if --remote-only }}
# Only run in remote/web sessions
if [ "$CLAUDE_CODE_REMOTE" != "true" ]; then
exit 0
fi
{{ endif }}
CONTEXT_PARTS=()
# ââââ Dependency Installation ââââ
{{ if Node.js detected }}
if [ -f "package.json" ]; then
{{ npm ci / yarn install --frozen-lockfile / pnpm install --frozen-lockfile / bun install --frozen-lockfile }}
CONTEXT_PARTS+=("Node.js dependencies installed via {{ pm }}")
fi
{{ endif }}
{{ if Python detected }}
if [ -f "pyproject.toml" ]; then
{{ poetry install / uv sync / pip install -e '.[dev]' }}
CONTEXT_PARTS+=("Python dependencies installed via {{ pm }}")
elif [ -f "requirements.txt" ]; then
pip install -r requirements.txt 2>/dev/null
CONTEXT_PARTS+=("Python dependencies installed via pip")
fi
{{ endif }}
{{ if Rust detected }}
if [ -f "Cargo.toml" ]; then
cargo fetch 2>/dev/null
CONTEXT_PARTS+=("Rust dependencies fetched")
fi
{{ endif }}
{{ if Go detected }}
if [ -f "go.mod" ]; then
go mod download 2>/dev/null
CONTEXT_PARTS+=("Go dependencies downloaded")
fi
{{ endif }}
{{ if Ruby detected }}
if [ -f "Gemfile" ]; then
bundle install 2>/dev/null
CONTEXT_PARTS+=("Ruby dependencies installed via bundler")
fi
{{ endif }}
{{ if Java/maven detected }}
if [ -f "pom.xml" ]; then
mvn dependency:resolve -q 2>/dev/null
CONTEXT_PARTS+=("Java dependencies resolved via maven")
fi
{{ endif }}
{{ if Java/gradle detected }}
if [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
gradle dependencies --quiet 2>/dev/null
CONTEXT_PARTS+=("Java/Kotlin dependencies resolved via gradle")
fi
{{ endif }}
# ââââ Environment Variables ââââ
if [ -n "$CLAUDE_ENV_FILE" ]; then
{{ per language: export PATH, NODE_ENV, PYTHONDONTWRITEBYTECODE, etc. }}
fi
{{ unless --no-verify }}
# ââââ Verify Tooling ââââ
{{ if test runner detected }}
if {{ test command --bail / -x / quick mode }} 2>/dev/null; then
CONTEXT_PARTS+=("Tests: passing")
else
CONTEXT_PARTS+=("Tests: FAILING - investigate before making changes")
fi
{{ endif }}
{{ if linter detected }}
if {{ lint command --max-diagnostics=0 / --quiet }} 2>/dev/null; then
CONTEXT_PARTS+=("Linter: clean")
else
CONTEXT_PARTS+=("Linter: issues detected")
fi
{{ endif }}
{{ end unless }}
# ââââ Report Context ââââ
CONTEXT=$(printf '%s\n' "${CONTEXT_PARTS[@]}")
if [ -n "$CONTEXT" ]; then
jq -n --arg ctx "$CONTEXT" '{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": $ctx
}
}'
fi
exit 0
Adapt the template by:
- Including only sections for detected languages
- Using the correct package manager commands with frozen lockfile flags
- Using the correct test runner and linter commands
- Setting appropriate environment variables per language
Phase 3: Configure .claude/settings.json
Read existing .claude/settings.json if it exists. Merge the SessionStart hook â preserve all existing configuration.
If a SessionStart hook already exists, ask the user whether to:
- Replace the existing SessionStart hook
- Add alongside the existing hook (both will run)
- Abort and keep existing configuration
Configuration to merge:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR/scripts/claude-session-start.sh\"",
"timeout": 120
}
]
}
]
}
}
Use timeout: 120 (2 minutes) for dependency installation. Adjust path if script is in .claude/hooks/ instead of scripts/.
Phase 4: Finalize
- Make the script executable:
chmod +x <script-path> - Create
.claude/directory if needed for settings.json - Report summary of what was created
Phase 5: Verify (unless –no-verify)
Run the generated script locally to confirm it executes without errors. Report results.
Post-Actions
After generating the hook:
- Suggest committing the new files:
scripts/claude-session-start.sh .claude/settings.json - If
--remote-onlywas NOT used, mention the flag for web-only behavior - If the project needs network access beyond defaults, remind about Claude Code web network settings
- Mention
matcheroptions:"startup"(new sessions),"resume"(resumed),""(all events)
SessionStart Matcher Reference
| Matcher | Fires When |
|---|---|
"startup" |
New session starts |
"resume" |
Session is resumed |
"clear" |
After /clear command |
"compact" |
After context compaction |
"" (empty) |
All SessionStart events |
Agentic Optimizations
| Context | Approach |
|---|---|
| Quick setup, skip verification | /hooks:session-start-hook --remote-only --no-verify |
| Full setup with verification | /hooks:session-start-hook |
| Web-only with tests | /hooks:session-start-hook --remote-only |
| Dependency install commands | Use --frozen-lockfile / ci variants for reproducibility |
| Test verification | Use --bail=1 / -x for fast failure |
| Linter verification | Use --max-diagnostics=0 / --quiet for pass/fail only |
Quick Reference
| Item | Value |
|---|---|
| Script location | scripts/claude-session-start.sh or .claude/hooks/session-start.sh |
| Settings location | .claude/settings.json |
| Timeout | 120 seconds (adjustable) |
| Output format | JSON with hookSpecificOutput.additionalContext |
| Environment persistence | Via CLAUDE_ENV_FILE |
| Remote detection | CLAUDE_CODE_REMOTE=true |