实战 B1:Claude Code 项目初始化与配置——CLAUDE.md 编写艺术与 Skills 实战
实战教程系列 系列 B:B1 Claude Code 配置实战 ← 本文 | B2 日常开发 | B3 审查与重构 | B4 多 Agent | B5 大型项目
Claude Code 的 CLAUDE.md 和 Codex 的 AGENTS.md 名字相似但用法不同——CLAUDE.md 更偏向"持久化指令"而非"项目文档"。本文通过三个案例,展示如何让 Claude Code 真正理解你的项目。
案例 1:CLAUDE.md 编写艺术——从最小到最优
背景:你有一个 Python 数据处理服务,结构如下:
data-pipeline/
src/
extractors/ # 数据提取
transformers/ # 数据转换
loaders/ # 数据加载
tests/
pyproject.toml
CLAUDE.md
第一版:最小可行 CLAUDE.md
很多人的第一版 CLAUDE.md 就是复制 README。不要这样做。README 是给人读的,CLAUDE.md 是给 AI 读的——前者重背景和动机,后者重操作和约束。
# Data Pipeline Project
## Commands
- Install: `uv sync`
- Lint: `ruff check .`
- Type check: `mypy src/`
- Test: `pytest tests/ -v`
- Run pipeline: `python -m src.main --config config/prod.yaml`
## Rules
- Use Python 3.12+ features (match/case, type unions with |)
- All public functions must have type annotations
- Data classes use `@dataclass(slots=True)` for performance
- Errors use custom exception hierarchy in `src/exceptions.py`
- Never commit data files or .env files
为什么这是"最小可行":
- Commands 部分告诉 Claude 如何验证工作——这是最重要的部分
- Rules 是可机械检查的——"所有 public 函数必须有类型注解"
- 没有背景故事、没有架构哲学——那些是给人读的
第二版:添加上下文
当项目变复杂后,Claude 需要更多上下文来做正确决策:
## Architecture Notes
- Extractors are I/O-bound (HTTP calls, file reads) — use async
- Transformers are CPU-bound (Pandas) — keep synchronous
- Loaders write to PostgreSQL via asyncpg — use connection pools
- Pipeline stages communicate via Parquet files in /tmp/pipeline/
- Config is validated with Pydantic models in src/config.py
## Testing Strategy
- Extractors: mock HTTP responses with responses library
- Transformers: snapshot testing with pytest-snapshot
- Loaders: test against local Postgres in Docker
- Integration tests require `docker compose up db` first
为什么需要这些:
- I/O bound vs CPU bound 告诉 Claude 选择正确的并发策略
- 通信方式(Parquet 文件路径)防止 Claude 假设了错误的接口
- 测试策略让 Claude 知道该用什么 mock 工具
第三版:不该写什么
# 不要写
## Project History
This project started in 2023 when we realized the old ETL tool couldn't scale...
——Claude 不需要知道历史
## Team Members
Alice (Tech Lead), Bob (Backend), Charlie (Data Engineer)...
——Claude 不需要知道人名,除非影响代码归属
## Future Plans
Q3 we plan to migrate to Apache Beam...
——未来的计划不是当前事实,会误导 Claude
CLAUDE.md 黄金法则:只写 Claude 执行当前任务需要知道的。如果你发现自己在写背景故事,那是 README 的内容。
案例 2:Skills 系统实战
背景:你的团队需要标准化的部署流程。从旧版 .claude/commands/ 迁移到新版 Skills 系统。
迁移前的 command(旧版)
.claude/commands/deploy.md:
请执行以下部署步骤:
1. 运行 `uv run pytest tests/ -v` 确保测试通过
2. 运行 `uv run ruff check .` 确保 lint 通过
3. 构建 Docker 镜像:`docker build -t data-pipeline:latest .`
4. 推送到 ECR:`aws ecr get-login-password | docker login...`
5. 更新 ECS 服务:`aws ecs update-service --cluster...`
6. 等待部署完成并检查健康状态
旧版的问题:
- 每次都需要 Claude 理解全文才能执行
- 没有动态上下文——Docker tag、集群名等硬编码
- 不能被 Claude 自动发现和触发
迁移到 SKILL.md(新版)
.claude/skills/deploy/SKILL.md:
---
description: Deploy the data pipeline to production ECS. Use when user asks to deploy, ship, or release.
allowed-tools: Bash(aws:*), Bash(docker:*), Bash(uv:*)
---
## Current Git Status
!`git status --short`
!`git log -1 --oneline`
## Deployment Steps
1. Verify tests pass:
```bash
uv run pytest tests/ -v
- Verify lint passes:
uv run ruff check .
- Build and tag Docker image with the current git SHA:
export TAG=$(git rev-parse --short HEAD)
docker build -t data-pipeline:$TAG .
- Push to ECR (repository URL from project config):
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_REPO
docker tag data-pipeline:$TAG $ECR_REPO:$TAG
docker push $ECR_REPO:$TAG
- Update ECS service:
aws ecs update-service --cluster data-pipeline --service data-pipeline --force-new-deployment
- Wait for deployment to stabilize (poll every 10s, timeout 5min):
aws ecs wait services-stable --cluster data-pipeline --services data-pipeline
Post-Deploy Verification
After deployment succeeds, check the health endpoint:
curl -f https://pipeline.example.com/health
Report the HTTP status and response body.
**新版的关键改进**:
- `!` 动态注入:每次执行前 `!`git log`` 拉取最新 commit 信息,tag 使用 git SHA 而非硬编码
- `allowed-tools` 限制:skill 只能运行指定前缀的 bash 命令,防止误操作
- `description` 自动发现:当用户说"部署"或"上线"时,Claude 自动加载此 skill
- 调用方式:`/deploy`(斜杠命令)或 Claude 自动触发
### 动态上下文注入的最佳实践
`!command` 语法是 Claude Code Skills 的杀手级特性。常见用法:
```markdown
## Current branch
!`git branch --show-current`
## Changed files
!`git diff --name-only HEAD`
## Latest CI status
!`gh run list --limit 1 --json status,conclusion`
## Python version
!`python --version`
这些命令在 skill 加载时执行,输出内联到 prompt 中——Claude 看到的不是命令本身,而是命令的实时结果。这意味着每次执行 skill 时,上下文都是最新的。
案例 3:MCP 服务器配置
背景:让 Claude Code 直接查询生产数据库的 schema 和行数,而不是让你手动复制粘贴。
配置 PostgreSQL MCP
在 .claude/settings.json 或 ~/.claude/settings.json 中:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost:5432/mydb"]
}
}
}
重启 Claude Code 后,运行 /mcp 确认连接状态。
实战用法
@postgres 查询 users 表的 schema,告诉我哪些列有索引。
@postgres 统计 orders 表中过去 7 天每天的订单量。
@postgres 找到所有没有外键约束的表。
OAuth 认证的 MCP(如 GitHub)
对于需要 OAuth 的服务(GitHub、Google Drive、Slack),配置更简单:
- 运行
/mcp打开 MCP 面板 - 搜索 "GitHub" 并添加
- Claude Code 生成授权链接
- 在浏览器中完成 OAuth 登录
- Token 自动写回配置——不需要手动粘贴
常见陷阱:
- MCP 连接超时:检查服务器是否在运行,
/mcp面板中的状态是否为 connected - 权限不足:MCP 服务器的权限受 Claude Code 的审批策略约束。如果 MCP 工具调用需要审批,检查
/permissions设置 - 环境变量未传递:MCP 命令运行在干净的 shell 环境中。需要的环境变量要在配置中显式传递
CLAUDE.md vs AGENTS.md 快速对比
| 维度 | CLAUDE.md (Claude Code) | AGENTS.md (Codex) |
|---|---|---|
| 加载时机 | 每次会话启动 | 每次会话启动 |
| 推荐长度 | 200 行以内 | 200 行以内 |
| 主要内容 | 命令 + 规则 + 架构 | 命令 + 约定 + 审查清单 |
| 嵌套支持 | 否(单文件) | 是(子目录覆盖) |
| 配套机制 | Skills(按需加载) | Skills(按需加载) |
| 动态上下文 | !command 语法 |
MCP/插件 |
实操清单
- 创建项目级
CLAUDE.md,至少包含 Commands 和 Rules 两部分 - 从 README 中提取操作信息,去掉背景故事和团队名单
- 检查 CLAUDE.md 是否符合"只写 AI 执行当前任务需要知道的"原则
- 将旧版
.claude/commands/迁移到.claude/skills/<name>/SKILL.md - 在 Skill 中使用
!command动态注入上下文(如!git diff HEAD) - 配置
allowed-tools限制 Skill 的命令权限 - 配置至少一个 MCP 服务器(如 PostgreSQL 或 GitHub)
- 运行
/mcp确认连接状态 - 创建符号链接
CLAUDE.md → AGENTS.md实现双工具共享配置