hooks-builder

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hooks Builder

钩子构建器

A comprehensive guide for creating Claude Code hooks — event-driven automation that monitors and controls Claude's actions.
为Claude Code创建钩子的综合指南——用于监控和控制Claude操作的事件驱动型自动化工具。

Quick Reference

快速参考

The 10 Hook Events

10种钩子事件

EventWhen It FiresCan Block?Supports Matchers?
PreToolUseBefore tool executesYESYES (tool names)
PermissionRequestPermission dialog shownYESYES (tool names)
PostToolUseAfter tool succeedsNoYES (tool names)
NotificationClaude sends notificationNoYES
UserPromptSubmitUser submits promptYESNo
StopClaude finishes respondingCan force continueNo
SubagentStopSubagent finishesCan force continueNo
PreCompactBefore context compactionNoYES (manual/auto)
SessionStartSession beginsNoYES (startup/resume/clear/compact)
SessionEndSession endsNoNo
事件触发时机是否可阻止?是否支持匹配器?
PreToolUse工具执行前是(工具名称)
PermissionRequest显示权限对话框时是(工具名称)
PostToolUse工具执行成功后是(工具名称)
NotificationClaude发送通知时
UserPromptSubmit用户提交提示词时
StopClaude完成响应时可强制继续
SubagentStop子代理完成时可强制继续
PreCompact上下文压缩前是(手动/自动)
SessionStart会话开始时是(启动/恢复/清除/压缩)
SessionEnd会话结束时

Exit Code Semantics

退出代码语义

Exit CodeMeaningEffect
0Successstdout parsed as JSON for control
2Blocking errorVETO — stderr shown to Claude
OtherNon-blocking errorstderr logged in debug mode
退出代码含义效果
0成功stdout解析为JSON用于控制
2阻塞错误否决 —— stderr会显示给Claude
其他非阻塞错误stderr在调试模式下记录

Configuration Locations

配置文件位置

~/.claude/settings.json          → Personal hooks (all projects)
.claude/settings.json            → Project hooks (team, committed)
.claude/settings.local.json      → Local overrides (not committed)
~/.claude/settings.json          → Personal hooks (all projects)
.claude/settings.json            → Project hooks (team, committed)
.claude/settings.local.json      → Local overrides (not committed)

Essential Environment Variables

关键环境变量

VariableDescription
$CLAUDE_PROJECT_DIR
Project root directory
$CLAUDE_CODE_REMOTE
Remote/local indicator
$CLAUDE_ENV_FILE
Environment persistence path (SessionStart)
$CLAUDE_PLUGIN_ROOT
Plugin directory (plugin hooks)
变量描述
$CLAUDE_PROJECT_DIR
项目根目录
$CLAUDE_CODE_REMOTE
远程/本地指示器
$CLAUDE_ENV_FILE
环境持久化路径(SessionStart)
$CLAUDE_PLUGIN_ROOT
插件目录(插件钩子)

Key Commands

核心命令

bash
/hooks              # View active hooks
claude --debug      # Enable debug logging
chmod +x script.sh  # Make script executable

bash
/hooks              # View active hooks
claude --debug      # Enable debug logging
chmod +x script.sh  # Make script executable

6-Phase Workflow

六阶段工作流

Phase 1: Requirements Gathering

阶段1:需求收集

Use AskUserQuestion to clarify:
  1. What event should trigger this hook?
    • Tool execution (Pre/Post/Permission) → PreToolUse, PostToolUse, PermissionRequest
    • User input → UserPromptSubmit
    • Response completion → Stop, SubagentStop
    • Session lifecycle → SessionStart, SessionEnd
    • Context management → PreCompact
    • Notifications → Notification
  2. What should happen when triggered?
    • Observe only (logging, metrics)
    • Block/allow based on conditions
    • Modify inputs before execution
    • Add context to prompts
    • Force continuation
  3. Should it block, modify, or just observe?
    • Observer: PostToolUse, Notification, SessionEnd (can't block)
    • Gatekeeper: PreToolUse, PermissionRequest, UserPromptSubmit (can block)
    • Transformer: PreToolUse with updatedInput (can modify)
    • Controller: Stop, SubagentStop (can force continue)
  4. What are the security implications?
    • Will it handle untrusted input?
    • Could it expose sensitive data?
    • Does it need to access external systems?
使用AskUserQuestion来明确以下内容:
  1. 钩子应该由什么事件触发?
    • 工具执行(预处理/后处理/权限)→ PreToolUse、PostToolUse、PermissionRequest
    • 用户输入 → UserPromptSubmit
    • 响应完成 → Stop、SubagentStop
    • 会话生命周期 → SessionStart、SessionEnd
    • 上下文管理 → PreCompact
    • 通知 → Notification
  2. 触发后应该执行什么操作?
    • 仅观察(日志记录、指标统计)
    • 根据条件阻止/允许
    • 执行前修改输入
    • 为提示词添加上下文
    • 强制继续执行
  3. 它应该是阻塞、修改还是仅观察?
    • 观察者:PostToolUse、Notification、SessionEnd(不可阻止)
    • 守门人:PreToolUse、PermissionRequest、UserPromptSubmit(可阻止)
    • 转换器:带updatedInput的PreToolUse(可修改)
    • 控制器:Stop、SubagentStop(可强制继续)
  4. 有哪些安全影响?
    • 是否会处理不可信输入?
    • 是否可能泄露敏感数据?
    • 是否需要访问外部系统?

Phase 2: Event Selection

阶段2:事件选择

Match event to use case:
Use CaseBest Event
Block dangerous operationsPreToolUse
Auto-format code after writesPostToolUse
Validate user promptsUserPromptSubmit
Setup environmentSessionStart
Ensure task completionStop
Log all tool usagePostToolUse with
"*"
matcher
Protect sensitive filesPreToolUse for Write/Edit
Add project contextUserPromptSubmit
Determine if matchers are needed:
  • Specific tools? → Use matcher:
    "Write|Edit"
  • All tools? → Use
    "*"
    or omit matcher
  • MCP tools? → Use
    mcp__server__tool
    pattern
  • Bash commands? → Use
    Bash(git:*)
    pattern
根据用例匹配事件:
用例最佳事件
阻止危险操作PreToolUse
写入后自动格式化代码PostToolUse
验证用户提示词UserPromptSubmit
环境设置SessionStart
确保任务完成Stop
记录所有工具使用情况
"*"
匹配器的PostToolUse
保护敏感文件针对Write/Edit的PreToolUse
添加项目上下文UserPromptSubmit
确定是否需要匹配器:
  • 特定工具? → 使用匹配器:
    "Write|Edit"
  • 所有工具? → 使用
    "*"
    或省略匹配器
  • MCP工具? → 使用
    mcp__server__tool
    模式
  • Bash命令? → 使用
    Bash(git:*)
    模式

Phase 3: Matcher Design

阶段3:匹配器设计

Matcher Pattern Syntax:
json
// Exact match (case-sensitive!)
"matcher": "Write"

// OR pattern
"matcher": "Write|Edit"

// Prefix match
"matcher": "Notebook.*"

// Contains match
"matcher": ".*Read.*"

// All tools
"matcher": "*"

// MCP tools
"matcher": "mcp__memory__.*"

// Bash sub-patterns
"matcher": "Bash(git:*)"
Common Matcher Patterns:
PatternMatches
"Write"
Only Write tool
"Write|Edit"
Write OR Edit
"Bash"
All Bash commands
"Bash(git:*)"
Only git commands
"Bash(npm:*)"
Only npm commands
"mcp__.*__.*"
All MCP tools
".*"
or
"*"
Everything
匹配器模式语法:
json
// Exact match (case-sensitive!)
"matcher": "Write"

// OR pattern
"matcher": "Write|Edit"

// Prefix match
"matcher": "Notebook.*"

// Contains match
"matcher": ".*Read.*"

// All tools
"matcher": "*"

// MCP tools
"matcher": "mcp__memory__.*"

// Bash sub-patterns
"matcher": "Bash(git:*)"
常见匹配器模式:
模式匹配对象
"Write"
仅Write工具
"Write|Edit"
Write或Edit
"Bash"
所有Bash命令
"Bash(git:*)"
仅git命令
"Bash(npm:*)"
仅npm命令
"mcp__.*__.*"
所有MCP工具
".*"
"*"
所有对象

Phase 4: Implementation

阶段4:实现

Choose implementation approach:
  1. Inline command (simple, no external file):
    json
    {
      "type": "command",
      "command": "echo \"$(date) | $tool_name\" >> ~/.claude/audit.log"
    }
  2. External script (complex logic, reusable):
    json
    {
      "type": "command",
      "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/validate.sh"
    }
  3. Prompt-based (LLM evaluation, intelligent decisions):
    json
    {
      "type": "prompt",
      "prompt": "Analyze if all tasks are complete: $ARGUMENTS",
      "timeout": 30
    }
Script Template (Bash):
bash
#!/bin/bash
set -euo pipefail
选择实现方式:
  1. 内联命令(简单,无需外部文件):
    json
    {
      "type": "command",
      "command": "echo \"$(date) | $tool_name\" >> ~/.claude/audit.log"
    }
  2. 外部脚本(复杂逻辑,可复用):
    json
    {
      "type": "command",
      "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/validate.sh"
    }
  3. 基于提示词(大语言模型评估,智能决策):
    json
    {
      "type": "prompt",
      "prompt": "Analyze if all tasks are complete: $ARGUMENTS",
      "timeout": 30
    }
脚本模板(Bash):
bash
#!/bin/bash
set -euo pipefail

Read JSON input from stdin

Read JSON input from stdin

input=$(cat)
input=$(cat)

Parse fields with jq

Parse fields with jq

tool_name=$(echo "$input" | jq -r '.tool_name // empty') file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')
tool_name=$(echo "$input" | jq -r '.tool_name // empty') file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')

Your logic here

Your logic here

if [[ "$file_path" == ".env" ]]; then echo "BLOCKED: Cannot modify .env files" >&2 exit 2 fi
if [[ "$file_path" == ".env" ]]; then echo "BLOCKED: Cannot modify .env files" >&2 exit 2 fi

Success - output decision

Success - output decision

echo '{"decision": "approve"}' exit 0

**Script Template (Python):**
```python
#!/usr/bin/env python3
import sys
import json
echo '{"decision": "approve"}' exit 0

**脚本模板(Python):**
```python
#!/usr/bin/env python3
import sys
import json

Read JSON input from stdin

Read JSON input from stdin

data = json.load(sys.stdin)
data = json.load(sys.stdin)

Extract fields

Extract fields

tool_name = data.get('tool_name', '') tool_input = data.get('tool_input', {}) file_path = tool_input.get('file_path', '')
tool_name = data.get('tool_name', '') tool_input = data.get('tool_input', {}) file_path = tool_input.get('file_path', '')

Your logic here

Your logic here

if '.env' in file_path: print("BLOCKED: Cannot modify .env files", file=sys.stderr) sys.exit(2)
if '.env' in file_path: print("BLOCKED: Cannot modify .env files", file=sys.stderr) sys.exit(2)

Success - output decision

Success - output decision

output = {"decision": "approve"} print(json.dumps(output)) sys.exit(0)
undefined
output = {"decision": "approve"} print(json.dumps(output)) sys.exit(0)
undefined

Phase 5: Security Hardening

阶段5:安全加固

CRITICAL: Hooks execute shell commands with YOUR permissions.
Security Checklist:
  • All variables quoted:
    "$VAR"
    not
    $VAR
  • JSON parsed with jq or json.load (not grep/sed)
  • Paths validated (no
    ..
    , normalized)
  • No sensitive data in logs/output
  • No sudo or privilege escalation
  • Script tested manually first
  • Project hooks audited before running
  • Timeout set appropriately
  • Error handling for all failure modes
Secure Patterns:
bash
undefined
重要提示:钩子会以你的权限执行Shell命令。
安全检查清单:
  • 所有变量都加引号:
    "$VAR"
    而非
    $VAR
  • 使用jq或json.load解析JSON(而非grep/sed)
  • 路径验证(无
    ..
    ,已规范化)
  • 日志/输出中无敏感数据
  • 无sudo或权限提升操作
  • 脚本先手动测试
  • 项目钩子运行前先审计
  • 设置适当的超时时间
  • 所有失败模式都有错误处理
安全模式示例:
bash
undefined

UNSAFE - injection risk

UNSAFE - injection risk

rm $file_path
rm $file_path

SAFE - quoted, prevents flag injection

SAFE - quoted, prevents flag injection

rm -- "$file_path"
rm -- "$file_path"

UNSAFE - parsing risk

UNSAFE - parsing risk

cat "$input" | grep "field"
cat "$input" | grep "field"

SAFE - proper JSON parsing

SAFE - proper JSON parsing

echo "$input" | jq -r '.field'

**Defense in Depth:**
1. Input validation (parse JSON properly)
2. Path sanitization (normalize, check boundaries)
3. Output sanitization (no sensitive data)
4. Fail-safe defaults (block on error, not allow)
5. Timeout protection (prevent infinite loops)
echo "$input" | jq -r '.field'

**深度防御措施:**
1. 输入验证(正确解析JSON)
2. 路径清理(规范化、检查边界)
3. 输出清理(无敏感数据)
4. 故障安全默认值(错误时阻塞而非允许)
5. 超时保护(防止无限循环)

Phase 6: Testing

阶段6:测试

Step 1: Manual Script Testing
bash
undefined
步骤1:手动脚本测试
bash
undefined

Create mock input

Create mock input

cat > /tmp/mock-input.json << 'EOF' { "session_id": "test-123", "hook_event_name": "PreToolUse", "tool_name": "Write", "tool_input": { "file_path": "/path/to/file.txt", "content": "test content" } } EOF
cat > /tmp/mock-input.json << 'EOF' { "session_id": "test-123", "hook_event_name": "PreToolUse", "tool_name": "Write", "tool_input": { "file_path": "/path/to/file.txt", "content": "test content" } } EOF

Test script

Test script

cat /tmp/mock-input.json | ./my-hook.sh echo "Exit code: $?"

**Step 2: Edge Case Testing**
- Empty inputs: `{}`
- Missing fields: `{"tool_name": "Write"}`
- Malicious inputs: `{"tool_input": {"file_path": "; rm -rf /"}}`
- Large inputs: 10KB+ content
- Unicode: paths with special characters

**Step 3: Integration Testing**
```bash
cat /tmp/mock-input.json | ./my-hook.sh echo "Exit code: $?"

**步骤2:边缘情况测试**
- 空输入:`{}`
- 缺失字段:`{"tool_name": "Write"}`
- 恶意输入:`{"tool_input": {"file_path": "; rm -rf /"}}`
- 大输入:10KB+内容
-  Unicode:含特殊字符的路径

**步骤3:集成测试**
```bash

Start Claude with debug mode

Start Claude with debug mode

claude --debug
claude --debug

Trigger the tool your hook targets

Trigger the tool your hook targets

Watch debug output for hook execution

Watch debug output for hook execution


**Step 4: Verification**
```bash

**步骤4:验证**
```bash

Check hooks are registered

Check hooks are registered

/hooks
/hooks

Watch hook execution

Watch hook execution

claude --debug 2>&1 | grep -i hook

---
claude --debug 2>&1 | grep -i hook

---

Hook Patterns

钩子模式

Observer Pattern

观察者模式

Log without blocking — use PostToolUse or Notification.
json
{
  "hooks": {
    "PostToolUse": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "echo \"$(date) | $tool_name\" >> ~/.claude/audit.log"
      }]
    }]
  }
}
仅记录不阻塞 —— 使用PostToolUse或Notification。
json
{
  "hooks": {
    "PostToolUse": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "echo \"$(date) | $tool_name\" >> ~/.claude/audit.log"
      }]
    }]
  }
}

Gatekeeper Pattern

守门人模式

Block dangerous actions — use PreToolUse or PermissionRequest.
json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{
        "type": "command",
        "command": "python3 ~/.claude/hooks/file-protector.py"
      }]
    }]
  }
}
阻止危险操作 —— 使用PreToolUse或PermissionRequest。
json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{
        "type": "command",
        "command": "python3 ~/.claude/hooks/file-protector.py"
      }]
    }]
  }
}

Transformer Pattern

转换器模式

Modify inputs before execution — use PreToolUse with updatedInput.
python
undefined
执行前修改输入 —— 使用带updatedInput的PreToolUse。
python
undefined

In script, output:

In script, output:

output = { "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "allow", "updatedInput": { "content": add_license_header(original_content) } } } print(json.dumps(output))
undefined
output = { "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "allow", "updatedInput": { "content": add_license_header(original_content) } } } print(json.dumps(output))
undefined

Orchestrator Pattern

编排器模式

Coordinate multiple events — combine SessionStart + PreToolUse + PostToolUse.
json
{
  "hooks": {
    "SessionStart": [{
      "matcher": "startup",
      "hooks": [{"type": "command", "command": "~/.claude/hooks/setup-env.sh"}]
    }],
    "PreToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{"type": "command", "command": "~/.claude/hooks/validate.sh"}]
    }],
    "PostToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{"type": "command", "command": "~/.claude/hooks/format.sh"}]
    }]
  }
}

协调多个事件 —— 组合SessionStart + PreToolUse + PostToolUse。
json
{
  "hooks": {
    "SessionStart": [{
      "matcher": "startup",
      "hooks": [{"type": "command", "command": "~/.claude/hooks/setup-env.sh"}]
    }],
    "PreToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{"type": "command", "command": "~/.claude/hooks/validate.sh"}]
    }],
    "PostToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{"type": "command", "command": "~/.claude/hooks/format.sh"}]
    }]
  }
}

Common Pitfalls

常见陷阱

1. Forgetting Exit Code 2 for Blocking

1. 忘记用退出代码2来阻塞

bash
undefined
bash
undefined

WRONG - exit 1 doesn't block

WRONG - exit 1 doesn't block

echo "Error" >&2 exit 1
echo "Error" >&2 exit 1

RIGHT - exit 2 blocks Claude

RIGHT - exit 2 blocks Claude

echo "BLOCKED: reason" >&2 exit 2
undefined
echo "BLOCKED: reason" >&2 exit 2
undefined

2. Case Sensitivity in Matchers

2. 匹配器的大小写敏感性

json
// WRONG - won't match "Write" tool
"matcher": "write"

// RIGHT - case-sensitive match
"matcher": "Write"
json
// WRONG - won't match "Write" tool
"matcher": "write"

// RIGHT - case-sensitive match
"matcher": "Write"

3. Unquoted Variables (Injection Risk)

3. 未加引号的变量(注入风险)

bash
undefined
bash
undefined

WRONG - command injection vulnerability

WRONG - command injection vulnerability

rm $file_path
rm $file_path

RIGHT - properly quoted

RIGHT - properly quoted

rm -- "$file_path"
undefined
rm -- "$file_path"
undefined

4. Missing Shebang in Scripts

4. 脚本中缺少Shebang

bash
undefined
bash
undefined

WRONG - no shebang, may fail

WRONG - no shebang, may fail

set -euo pipefail
set -euo pipefail

RIGHT - explicit interpreter

RIGHT - explicit interpreter

#!/bin/bash set -euo pipefail
undefined
#!/bin/bash set -euo pipefail
undefined

5. Not Making Scripts Executable

5. 未设置脚本可执行权限

bash
undefined
bash
undefined

Don't forget!

Don't forget!

chmod +x ~/.claude/hooks/my-hook.sh
undefined
chmod +x ~/.claude/hooks/my-hook.sh
undefined

6. Forgetting to Quote Paths in JSON

6. JSON中路径未加引号

json
// WRONG - spaces in path will break
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/script.sh"

// RIGHT - quoted path
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/script.sh"
json
// WRONG - spaces in path will break
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/script.sh"

// RIGHT - quoted path
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/script.sh"

7. No Error Handling

7. 缺少错误处理

bash
undefined
bash
undefined

WRONG - silent failures

WRONG - silent failures

input=$(cat) tool=$(echo "$input" | jq -r '.tool_name')
input=$(cat) tool=$(echo "$input" | jq -r '.tool_name')

RIGHT - handle errors

RIGHT - handle errors

input=$(cat) || { echo "Failed to read input" >&2; exit 1; } tool=$(echo "$input" | jq -r '.tool_name') || { echo "Failed to parse JSON" >&2; exit 1; }
undefined
input=$(cat) || { echo "Failed to read input" >&2; exit 1; } tool=$(echo "$input" | jq -r '.tool_name') || { echo "Failed to parse JSON" >&2; exit 1; }
undefined

8. Logging Sensitive Data

8. 记录敏感数据

bash
undefined
bash
undefined

WRONG - may log secrets

WRONG - may log secrets

echo "Processing: $input" >> /tmp/debug.log
echo "Processing: $input" >> /tmp/debug.log

RIGHT - sanitize before logging

RIGHT - sanitize before logging

echo "Processing tool: $tool_name" >> /tmp/debug.log

---
echo "Processing tool: $tool_name" >> /tmp/debug.log

---

When to Use Hooks

钩子的适用场景

USE hooks for:
  • Security enforcement (block dangerous operations)
  • Code quality automation (format, lint on save)
  • Compliance and auditing (log all actions)
  • Environment setup (consistent configuration)
  • Workflow automation (notifications, integrations)
  • Input validation (prompt checking)
  • Task completion verification
DON'T use hooks for:
  • Adding new capabilities (use Skills)
  • Delegating complex work (use Agents)
  • User-invoked prompts (use Commands)
  • Simple one-off tasks (just ask Claude)

适合使用钩子的场景:
  • 安全实施(阻止危险操作)
  • 代码质量自动化(保存时格式化、 lint检查)
  • 合规与审计(记录所有操作)
  • 环境设置(一致的配置)
  • 工作流自动化(通知、集成)
  • 输入验证(提示词检查)
  • 任务完成验证
不适合使用钩子的场景:
  • 添加新功能(使用Skills)
  • 委托复杂工作(使用Agents)
  • 用户调用的提示词(使用Commands)
  • 简单一次性任务(直接询问Claude即可)

Files in This Skill

本Skill包含的文件

Templates (Progressive Complexity)

模板(复杂度递进)

  • templates/basic-hook.md
    — Single event, inline command
  • templates/with-scripts.md
    — External shell scripts
  • templates/with-decisions.md
    — Permission control, input modification
  • templates/with-prompts.md
    — LLM-based evaluation
  • templates/production-hooks.md
    — Complete multi-event system
  • templates/basic-hook.md
    —— 单事件、内联命令
  • templates/with-scripts.md
    —— 外部Shell脚本
  • templates/with-decisions.md
    —— 权限控制、输入修改
  • templates/with-prompts.md
    —— 基于大语言模型的评估
  • templates/production-hooks.md
    —— 完整的多事件系统

Examples (18 Complete Hooks)

示例(18个完整钩子)

  • examples/security-hooks.md
    — Protection, validation, auditing
  • examples/quality-hooks.md
    — Formatting, linting, testing
  • examples/workflow-hooks.md
    — Setup, context, notifications
  • examples/security-hooks.md
    —— 保护、验证、审计
  • examples/quality-hooks.md
    —— 格式化、Lint检查、测试
  • examples/workflow-hooks.md
    —— 设置、上下文、通知

Reference

参考文档

  • reference/syntax-guide.md
    — Complete JSON schemas, all events
  • reference/best-practices.md
    — Security, design, team deployment
  • reference/troubleshooting.md
    — 10 common issues, testing methodology
  • reference/syntax-guide.md
    —— 完整JSON schema、所有事件
  • reference/best-practices.md
    —— 安全、设计、团队部署
  • reference/troubleshooting.md
    —— 10个常见问题、测试方法