session-start-hook
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseStartup Hook Skill for Claude Code
面向Claude Code的启动钩子Skill
Create SessionStart hooks that install dependencies so tests and linters work in Claude Code sessions (CLI, web, or API).
创建SessionStart钩子用于自动安装依赖,确保测试和Lint工具可在Claude Code会话(CLI、网页端或API)中正常运行。
Hook Basics
钩子基础
Input (via stdin)
输入(通过标准输入stdin)
json
{
"session_id": "abc123",
"source": "startup|resume|clear|compact",
"transcript_path": "/path/to/transcript.jsonl",
"permission_mode": "default",
"hook_event_name": "SessionStart",
"cwd": "/workspace/repo"
}json
{
"session_id": "abc123",
"source": "startup|resume|clear|compact",
"transcript_path": "/path/to/transcript.jsonl",
"permission_mode": "default",
"hook_event_name": "SessionStart",
"cwd": "/workspace/repo"
}Async Mode
异步模式
bash
#!/bin/bash
set -euo pipefail
echo '{"async": true, "asyncTimeout": 300000}'
npm installThe hook runs in background while the session starts. Using async mode reduces latency, but introduces a race condition where the agent loop might depend on something that is being done in the startup hook before it completed.
bash
#!/bin/bash
set -euo pipefail
echo '{"async": true, "asyncTimeout": 300000}'
npm install钩子会在会话启动时后台运行。使用异步模式可降低延迟,但会引入竞态问题:Agent 循环可能在启动钩子执行完成前,就依赖钩子中正在处理的资源。
Environment Variables
环境变量
Available environment variables:
- - Repository root path
$CLAUDE_PROJECT_DIR - - Path to write environment variables
$CLAUDE_ENV_FILE - - If running in a remote environment (i.e. Claude code on the web)
$CLAUDE_CODE_REMOTE
Use to persist variables for the session:
$CLAUDE_ENV_FILEbash
echo 'export PYTHONPATH="."' >> "$CLAUDE_ENV_FILE"Use to only run a script in a remote env:
$CLAUDE_CODE_REMOTEbash
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
exit 0
fi可用的环境变量如下:
- - 仓库根路径
$CLAUDE_PROJECT_DIR - - 用于写入环境变量的文件路径
$CLAUDE_ENV_FILE - - 判断是否运行在远程环境(即网页端的Claude Code)
$CLAUDE_CODE_REMOTE
使用为当前会话持久化环境变量:
$CLAUDE_ENV_FILEbash
echo 'export PYTHONPATH="."' >> "$CLAUDE_ENV_FILE"使用判断仅在远程环境中执行脚本:
$CLAUDE_CODE_REMOTEbash
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
exit 0
fiWorkflow
工作流程
Make a todo list for all the tasks in this workflow and work on them one after another
为该工作流的所有任务创建待办清单,按顺序逐一完成
1. Analyze Dependencies
1. 分析依赖
Find dependency manifests and analyze them. Examples:
- /
package.json→ npmpackage-lock.json - /
pyproject.toml→ pip/Poetryrequirements.txt - → cargo
Cargo.toml - → go
go.mod - → bundler
Gemfile
Additionally, read though any documentation (i.e. README.md or similar) to see if you can get additional context on how the environment setup works
查找依赖清单文件并进行分析,示例如下:
- /
package.json→ npmpackage-lock.json - /
pyproject.toml→ pip/Poetryrequirements.txt - → cargo
Cargo.toml - → go
go.mod - → bundler
Gemfile
此外,通读所有相关文档(如README.md或同类文件),获取更多环境配置相关的上下文信息
2. Design Hook
2. 设计钩子
Create a script that installs dependencies.
Key principles:
- Don't use async mode in the first iteration. Only switch to it if the user asks for it
- Write the hook only for the web unless user asks otherwise (see $CLAUDE_CODE_REMOTE)
- The container state gets cached after the hook completes, prefer dependency install methods that take advantage of that (i.e. prefer npm install over npm ci)
- Be idempotent (safe to run multiple times)
- Non-interactive (no user input)
What NOT to put in a SessionStart hook:
- Do NOT copy skills between user scope () and project scope (
~/.claude/skills/) — that's what.claude/skills/is for../dotfiles/sync.sh
Skills freshness check (install if missing or outdated):
bash
SKILLS_DIR="$HOME/.claude/skills"
REPO_SKILLS_DIR="${CLAUDE_PROJECT_DIR}/dotfiles/claude/skills"
SKILLS_REPO="${AI_SKILLS_REPO:-camacho/ai-skills}"
skills_stale() {
[[ ! -d "$SKILLS_DIR" ]] && return 0 # missing → stale
if [[ -d "$REPO_SKILLS_DIR" ]]; then
# Compare repo snapshot to installed — if different, stale
! diff -rq "$REPO_SKILLS_DIR" "$SKILLS_DIR" >/dev/null 2>&1 && return 0
fi
return 1 # up to date
}
if skills_stale; then
echo "Skills missing or outdated — installing from $SKILLS_REPO..."
if command -v npx &>/dev/null; then
npx skills install "$SKILLS_REPO" --scope personal \
|| echo "Warning: skills install failed — project-scope skills still available" >&2
else
echo '{"message": "Skills are outdated but npx not found.\n\nRun: ./dotfiles/sync.sh push", "continue": true}'
fi
fiThe check is local (fast ) — network only when stale. The default repo () can be overridden with .
diffcamacho/ai-skillsAI_SKILLS_REPODotfiles-missing check (surface as a session prompt, not a stderr warning):
bash
undefined创建用于安装依赖的脚本。
核心原则:
- 首次迭代不要使用异步模式,仅当用户明确要求时再切换
- 除非用户另有要求,否则仅为网页端编写钩子(参考$CLAUDE_CODE_REMOTE的用法)
- 容器状态会在钩子执行完成后缓存,优先选择能利用缓存的依赖安装方式(比如优先用npm install而非npm ci)
- 具备幂等性(多次运行安全无副作用)
- 非交互模式(无需用户输入)
SessionStart钩子中禁止添加的内容:
- 不要在用户作用域()和项目作用域(
~/.claude/skills/)之间复制Skill —— 该功能由.claude/skills/负责。./dotfiles/sync.sh
Skill新鲜度检查(缺失或过时则自动安装):
bash
SKILLS_DIR="$HOME/.claude/skills"
REPO_SKILLS_DIR="${CLAUDE_PROJECT_DIR}/dotfiles/claude/skills"
SKILLS_REPO="${AI_SKILLS_REPO:-camacho/ai-skills}"
skills_stale() {
[[ ! -d "$SKILLS_DIR" ]] && return 0 # 缺失 → 已过时
if [[ -d "$REPO_SKILLS_DIR" ]]; then
# 对比仓库快照和已安装版本 —— 存在差异则判定为过时
! diff -rq "$REPO_SKILLS_DIR" "$SKILLS_DIR" >/dev/null 2>&1 && return 0
fi
return 1 # 已是最新版本
}
if skills_stale; then
echo "Skill缺失或版本过时 —— 正在从$SKILLS_REPO安装..."
if command -v npx &>/dev/null; then
npx skills install "$SKILLS_REPO" --scope personal \
|| echo "警告:Skill安装失败 —— 项目作用域的Skill仍可使用" >&2
else
echo '{"message": "Skill版本过时但未找到npx。\n\n执行命令:./dotfiles/sync.sh push", "continue": true}'
fi
fi检查为本地执行(快速对比)—— 仅当版本过时时才会发起网络请求。默认仓库()可通过环境变量覆盖。
diffcamacho/ai-skillsAI_SKILLS_REPODotfiles缺失检查(作为会话提示展示,而非标准错误警告):
bash
undefinedSurface a visible prompt if user dotfiles are missing — informational only
如果用户dotfiles缺失则展示可见提示 —— 仅作通知用途
if [[ ! -d "$HOME/.claude/skills" ]]; then
echo '{"message": "~/.claude/skills not found.\n\nRun: ./dotfiles/sync.sh push\n\nThis sets up user-level skills and configs from the dotfiles repo.", "continue": true}'
exit 0
fi
Using the hook's JSON `message` field (instead of stderr) surfaces this inside Claude's session context where the user will see and act on it. `"continue": true` keeps the session running — this is informational, not a blocker.if [[ ! -d "$HOME/.claude/skills" ]]; then
echo '{"message": "未找到~/.claude/skills。\n\n执行命令:./dotfiles/sync.sh push\n\n该命令会从dotfiles仓库初始化用户级的Skill和配置。", "continue": true}'
exit 0
fi
使用钩子的JSON`message`字段(而非标准错误)可以将提示展示在Claude的会话上下文中,用户可以看到并处理。`"continue": true`会保持会话运行 —— 该提示仅作通知,不会阻塞流程。3. Create Hook File
3. 创建钩子文件
bash
mkdir -p .claude/hooks
cat > .claude/hooks/session-start.sh << 'EOF'
#!/bin/bash
set -euo pipefail
echo '{"async": true, "asyncTimeout": 300000}'bash
mkdir -p .claude/hooks
cat > .claude/hooks/session-start.sh << 'EOF'
#!/bin/bash
set -euo pipefail
echo '{"async": true, "asyncTimeout": 300000}'Install dependencies here
在此处安装依赖
EOF
chmod +x .claude/hooks/session-start.sh
undefinedEOF
chmod +x .claude/hooks/session-start.sh
undefined4. Register in Settings
4. 在设置中注册
Add to (create if doesn't exist):
.claude/settings.jsonjson
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"
}
]
}
]
}
}If exists, merge the hooks configuration.
.claude/settings.json添加到(如果文件不存在则创建):
.claude/settings.jsonjson
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"
}
]
}
]
}
}如果已存在,则合并钩子配置。
.claude/settings.json5. Validate Hook
5. 校验钩子
Run the hook script directly:
bash
CLAUDE_CODE_REMOTE=true ./.claude/hooks/session-start.shIMPORTANT: Verify dependencies are installed and script completes successfully.
直接运行钩子脚本:
bash
CLAUDE_CODE_REMOTE=true ./.claude/hooks/session-start.sh重要提示:确认依赖已安装且脚本执行成功。
6. Validate Linter
6. 校验Lint工具
IMPORTANT: Figure out what the right command is to run the linters and run it for an example file. No need to lint the whole project. If there are any issues, update the startup script accordingly and re-test.
重要提示:确认执行Lint的正确命令,选取一个示例文件执行即可,无需校验整个项目。如果存在问题,对应更新启动脚本并重新测试。
7. Validate Test
7. 校验测试
IMPORTANT: Figure out what the right command is to run the tests and run it for one test. No need to run the whole test suite. If there are any issues, update the startup script accordingly and re-test.
重要提示:确认执行测试的正确命令,选取单个测试用例执行即可,无需运行整个测试套件。如果存在问题,对应更新启动脚本并重新测试。
8. Commit and push
8. 提交并推送
Make a commit and push it to the remote branch
生成提交并推送到远程分支
Wrap up
收尾
We're all done. In your last message to the user, Provide a detailed summary to the user with the format below:
- Summary of the changes made
- Validation results
- Session hook execution (include details if it failed)
- linter execution (include details if it failed)
- test execution (include details if it failed)
- Hook execution mode: Syncronous
- inform user that hook is running syncronous and the below trade-offs. Let them know that we can change it to async if they prefer faster session startup.
- Pros: Guarantees dependencies are installed before your session starts, preventing race conditions where Claude might try to run tests or linters before they're ready
- Cons: Your remote session will only start once the session start hook is completed
- inform user that hook is running syncronous and the below trade-offs. Let them know that we can change it to async if they prefer faster session startup.
- inform user that once they merge the session start hook into their repo's default branch, all future sessions will use it.
所有操作已完成。在给用户的最终回复中,按照以下格式提供详细总结:
- 所做变更的总结
- 校验结果
- 会话钩子执行结果(如果失败请包含详细信息)
- Lint工具执行结果(如果失败请包含详细信息)
- 测试执行结果(如果失败请包含详细信息)
- 钩子执行模式:同步
- 告知用户钩子当前以同步模式运行,以及对应的优缺点。告知用户如果想要更快的会话启动速度,可以切换为异步模式。
- 优点:保证依赖在会话启动前完成安装,避免Claude在依赖准备完成前尝试运行测试或Lint工具导致的竞态问题
- 缺点:远程会话需要等待会话启动钩子执行完成后才会启动
- 告知用户钩子当前以同步模式运行,以及对应的优缺点。告知用户如果想要更快的会话启动速度,可以切换为异步模式。
- 告知用户一旦将会话启动钩子合并到仓库的默认分支,所有未来的会话都会自动使用该配置。