session-start-hook

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Startup 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 install
The 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:
  • $CLAUDE_PROJECT_DIR
    - Repository root path
  • $CLAUDE_ENV_FILE
    - Path to write environment variables
  • $CLAUDE_CODE_REMOTE
    - If running in a remote environment (i.e. Claude code on the web)
Use
$CLAUDE_ENV_FILE
to persist variables for the session:
bash
echo 'export PYTHONPATH="."' >> "$CLAUDE_ENV_FILE"
Use
$CLAUDE_CODE_REMOTE
to only run a script in a remote env:
bash
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
  exit 0
fi
可用的环境变量如下:
  • $CLAUDE_PROJECT_DIR
    - 仓库根路径
  • $CLAUDE_ENV_FILE
    - 用于写入环境变量的文件路径
  • $CLAUDE_CODE_REMOTE
    - 判断是否运行在远程环境(即网页端的Claude Code)
使用
$CLAUDE_ENV_FILE
为当前会话持久化环境变量:
bash
echo 'export PYTHONPATH="."' >> "$CLAUDE_ENV_FILE"
使用
$CLAUDE_CODE_REMOTE
判断仅在远程环境中执行脚本:
bash
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
  exit 0
fi

Workflow

工作流程

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
    /
    package-lock.json
    → npm
  • pyproject.toml
    /
    requirements.txt
    → pip/Poetry
  • Cargo.toml
    → cargo
  • go.mod
    → go
  • Gemfile
    → bundler
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
    /
    package-lock.json
    → npm
  • pyproject.toml
    /
    requirements.txt
    → pip/Poetry
  • Cargo.toml
    → cargo
  • go.mod
    → go
  • Gemfile
    → bundler
此外,通读所有相关文档(如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 (
    ~/.claude/skills/
    ) and project scope (
    .claude/skills/
    ) — that's what
    ./dotfiles/sync.sh
    is for.
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
fi
The check is local (fast
diff
) — network only when stale. The default repo (
camacho/ai-skills
) can be overridden with
AI_SKILLS_REPO
.
Dotfiles-missing check (surface as a session prompt, not a stderr warning):
bash
undefined
创建用于安装依赖的脚本。
核心原则:
  • 首次迭代不要使用异步模式,仅当用户明确要求时再切换
  • 除非用户另有要求,否则仅为网页端编写钩子(参考$CLAUDE_CODE_REMOTE的用法)
  • 容器状态会在钩子执行完成后缓存,优先选择能利用缓存的依赖安装方式(比如优先用npm install而非npm ci)
  • 具备幂等性(多次运行安全无副作用)
  • 非交互模式(无需用户输入)
SessionStart钩子中禁止添加的内容:
  • 不要在用户作用域(
    ~/.claude/skills/
    )和项目作用域(
    .claude/skills/
    )之间复制Skill —— 该功能由
    ./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
检查为本地执行(快速
diff
对比)—— 仅当版本过时时才会发起网络请求。默认仓库(
camacho/ai-skills
)可通过
AI_SKILLS_REPO
环境变量覆盖。
Dotfiles缺失检查(作为会话提示展示,而非标准错误警告):
bash
undefined

Surface 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
undefined
EOF
chmod +x .claude/hooks/session-start.sh
undefined

4. Register in Settings

4. 在设置中注册

Add to
.claude/settings.json
(create if doesn't exist):
json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"
          }
        ]
      }
    ]
  }
}
If
.claude/settings.json
exists, merge the hooks configuration.
添加到
.claude/settings.json
(如果文件不存在则创建):
json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"
          }
        ]
      }
    ]
  }
}
如果
.claude/settings.json
已存在,则合并钩子配置。

5. Validate Hook

5. 校验钩子

Run the hook script directly:
bash
CLAUDE_CODE_REMOTE=true ./.claude/hooks/session-start.sh
IMPORTANT: 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
    1. Session hook execution (include details if it failed)
    2. linter execution (include details if it failed)
    3. 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 once they merge the session start hook into their repo's default branch, all future sessions will use it.
所有操作已完成。在给用户的最终回复中,按照以下格式提供详细总结:
  • 所做变更的总结
  • 校验结果
    1. 会话钩子执行结果(如果失败请包含详细信息)
    2. Lint工具执行结果(如果失败请包含详细信息)
    3. 测试执行结果(如果失败请包含详细信息)
  • 钩子执行模式:同步
    • 告知用户钩子当前以同步模式运行,以及对应的优缺点。告知用户如果想要更快的会话启动速度,可以切换为异步模式。
      • 优点:保证依赖在会话启动前完成安装,避免Claude在依赖准备完成前尝试运行测试或Lint工具导致的竞态问题
      • 缺点:远程会话需要等待会话启动钩子执行完成后才会启动
  • 告知用户一旦将会话启动钩子合并到仓库的默认分支,所有未来的会话都会自动使用该配置。