Trellis (mindfold-ai) - 完整学习教程

Trellis (mindfold-ai) - 完整学习教程

教程级别: 从零到一 预计学习时间: 4-6 小时 前置知识: 命令行操作、Git 基础、至少一种 AI 编码助手(Claude Code 或 Cursor)的基本使用、Python 基础概念、JSON/YAML 配置文件格式

注意:本教程针对 mindfold-ai/Trellis——面向 AI 编码平台的框架和工具集。与微软的 microsoft/TRELLIS(3D 资产生成模型)是完全不同的项目。

环境搭建指南

系统要求

项目 要求
操作系统 macOS、Linux、Windows
Node.js 18+(用于 npm 安装 Trellis CLI)
Python 3.8+(Hook 脚本执行)
Git 2.5+(并行会话需要 Git Worktree 支持)
AI 编码平台 至少安装一种:Claude Code、Cursor、OpenCode 等

安装步骤

# 第一步:全局安装 Trellis CLI
npm install -g @mindfoldhq/trellis@latest

# 第二步:验证安装
trellis --version

执行结果:

0.3.6
# 第三步:进入你的项目目录(如果还没有项目,先创建一个)
mkdir my-project && cd my-project
git init

# 第四步:初始化 Trellis(-u 指定你的用户名)
trellis init -u developer-name

# 如果团队使用多个 AI 编码平台,同时初始化多平台支持
trellis init --cursor --opencode --codex -u developer-name

执行结果:

✓ Trellis initialized for project: my-project
✓ Created .trellis/ directory structure
✓ Created .claude/ directory structure
✓ Generated Hook configurations
✓ Welcome, developer-name!

验证安装

# 验证 Trellis 目录结构是否正确生成
ls -la .trellis/

# 验证 Hook 配置是否正确生成
cat .claude/settings.json | python3 -m json.tool

执行结果:

# ls 输出
drwxr-xr-x  workflow.md
drwxr-xr-x  spec/
drwxr-xr-x  workspace/
drwxr-xr-x  tasks/
drwxr-xr-x  scripts/

# settings.json 输出(简化)
{
    "hooks": {
        "SessionStart": [...],
        "PreToolUse": [...],
        "PostToolUse": [...],
        "SubagentStop": [...]
    }
}

注意事项: - 确保项目已经初始化了 Git 仓库(git init),Trellis 依赖 Git 进行版本管理和并行会话。 - 如果 trellis 命令未找到,检查 npm 全局安装路径是否在 PATH 中。运行 npm config get prefix 查看全局安装路径。 - Python 环境需要可执行。Hook 脚本通过 pythonpython3 命令调用,确保系统中有可用的 Python 解释器。


第一部分:入门篇

1.1 理解 Trellis 的核心概念——为什么需要 Hook 注入

概念讲解:

使用 AI 编码助手(如 Claude Code)时,传统做法是在项目根目录创建 CLAUDE.md.cursorrules 文件,写入编码规范和项目约定。问题是:AI 可能不读取或不遵守这些文件中的指令

想象你在管理一个建筑工地。你把施工规范写在一本手册里放在工地上,希望每个工人都去读。但有些工人可能不读,或者读了一半就忘了。Trellis 的解决方案是:不依赖工人自觉阅读,而是在每个工人进场时,把规范直接"注入"到他们的工作指南中

这就是 Hook 强制注入的核心思想:

  1. 传统方式CLAUDE.md / .cursorrules → AI"可选"读取 → 可能忽略
  2. Trellis 方式:Hook 在特定事件触发时 → 自动执行脚本 → 将规范强制注入到 AI 上下文

代码示例: 查看 Hook 如何在会话启动时注入规范

# 查看项目初始化后生成的 Hook 配置
cat .claude/settings.json
{
  "hooks": {
    "SessionStart": [{
      "command": "python .claude/hooks/session-start.py",
      "timeout": 30
    }],
    "PreToolUse": [{
      "command": "python .claude/hooks/inject-subagent-context.py",
      "matcher": "Agent"
    }],
    "PostToolUse": [{
      "command": "python .claude/hooks/sync-workspace.py"
    }],
    "SubagentStop": [{
      "command": "python .claude/hooks/ralph-loop.py",
      "matcher": "check"
    }]
  }
}
# 查看 session-start.py 脚本的内容(了解它做了什么)
head -30 .claude/hooks/session-start.py

执行结果:

# session-start.py 的核心逻辑:读取 workflow.md 和 workspace 上下文,
# 将它们作为 Hook 输出注入到当前 AI 会话中。
# 当你启动 Claude Code 时,这个脚本自动执行,
# workflow.md 中的规范就被加载到 AI 的上下文窗口中。

练习题: 1. 打开 .trellis/workflow.md 文件,查看其中包含的内容。思考:这些内容如果写在 CLAUDE.md 中,AI 是否一定会读取?Trellis 通过 Hook 注入后有什么不同? 2. 尝试修改 workflow.md 中的一段文字,然后在 Claude Code 中开启新会话,观察 AI 是否使用了你修改后的内容。


1.2 理解项目结构——Trellis 的文件系统

概念讲解:

Trellis 初始化后在项目中创建两个核心目录:

  • .trellis/:团队共享的项目配置,包含规范、任务和工作空间。这个目录应该提交到 Git,团队成员共享。
  • .claude/:Claude Code 平台的配置,包含 Agent 定义、Hook 脚本和斜杠命令。部分内容需要提交到 Git。
.trellis/                          ← 团队共享(提交到 Git)
├── workflow.md                    # 工作流指南——启动时自动注入
├── worktree.yaml                  # 多 Agent 并行配置
├── spec/                          # 规范库——核心!
│   ├── frontend/                  # 前端规范(React 组件模式、CSS 约定等)
│   ├── backend/                   # 后端规范(API 设计、数据库模式等)
│   └── guides/                    # 决策与分析框架
├── workspace/{your-name}/         # 个人工作日志(.gitignore)
├── tasks/                         # 任务状态文件(task.json)
└── scripts/                       # 工具脚本

.claude/                           ← 平台配置
├── settings.json                  # Hook 注册配置
├── agents/                        # Agent 角色定义
│   ├── dispatch.md                # 调度 Agent——纯路由,不读规范
│   ├── implement.md               # 实现 Agent——执行编码
│   ├── check.md                   # 检查 Agent——质量验证
│   └── research.md                # 研究 Agent——调研分析
├── commands/                      # 斜杠命令
│   └── trellis/                   # Trellis 专用命令
└── hooks/                         # Hook 脚本
    ├── session-start.py           # 会话启动 → 注入上下文
    ├── inject-subagent-context.py # Agent 调用 → 注入规范
    └── ralph-loop.py              # Agent 停止 → 质量检查

代码示例: 查看目录结构

# 查看 Trellis 生成的完整目录结构
find .trellis -type f | head -20
find .claude -type f | head -20

执行结果:

# .trellis 目录
.trellis/workflow.md
.trellis/spec/frontend/.gitkeep
.trellis/spec/backend/.gitkeep
.trellis/spec/guides/.gitkeep
.trellis/workspace/developer-name/.gitkeep
.trellis/tasks/.gitkeep

# .claude 目录
.claude/settings.json
.claude/agents/dispatch.md
.claude/agents/implement.md
.claude/agents/check.md
.claude/agents/research.md
.claude/hooks/session-start.py
.claude/hooks/inject-subagent-context.py
.claude/hooks/ralph-loop.py

练习题: 1. 阅读 .claude/agents/dispatch.md 文件,理解 Dispatch Agent 的职责。为什么它是"纯路由"? 2. 阅读 .claude/agents/implement.md 文件,理解 Implement Agent 在执行编码任务时会遵循哪些规则。


1.3 第一次使用——编写你的第一个 Spec

概念讲解:

Spec(规范)是 Trellis 的核心。一个 Spec 是一个 Markdown 文件,描述了项目中某个方面的编码规范。例如:API 端点命名规范、错误处理模式、React 组件结构等。

Spec 写在 .trellis/spec/ 目录下,按类别组织: - frontend/:前端相关规范 - backend/:后端相关规范 - shared/:前后端共享规范 - guides/:决策框架和分析指南

代码示例: 创建你的第一个 Spec

# 创建共享规范目录(如果不存在)
mkdir -p .trellis/spec/shared

# 创建一个错误处理规范
cat > .trellis/spec/shared/error-handling.md << 'EOF'
# 错误处理规范

## API 错误响应格式

所有 REST API 端点必须使用统一的错误响应格式:

```json
{
  "code": "ERROR_CODE_NAME",
  "message": "面向用户的错误描述",
  "details": {}
}

错误码命名规范

  • 使用大写蛇形命名法(UPPER_SNAKE_CASE)
  • 格式:{模块}_{错误类型},例如 USER_NOT_FOUNDORDER_INVALID_STATUS
  • 禁止使用模糊的错误码(如 ERRORFAIL

HTTP 状态码映射

  • 400:请求参数错误(PARAM_MISSINGPARAM_INVALID
  • 401:未认证(AUTH_REQUIRED
  • 403:无权限(PERMISSION_DENIED
  • 404:资源不存在(RESOURCE_NOT_FOUND
  • 500:服务器内部错误(INTERNAL_ERROR

禁止事项

  • 禁止直接抛出原始异常(raw exception)给前端
  • 禁止在错误响应中暴露堆栈跟踪或内部实现细节
  • 禁止使用 HTTP 200 返回错误信息(必须使用正确的错误状态码) EOF

echo "错误处理规范已创建"


**执行结果:**

错误处理规范已创建


**练习题:**
1. 再创建一个后端规范文件 `.trellis/spec/backend/api-design.md`,定义 REST API 的 URL 命名规范(如使用复数名词、嵌套资源表示等)。
2. 创建一个前端规范文件 `.trellis/spec/frontend/component-patterns.md`,定义 React 组件的文件结构和命名约定。

---

## 第二部分:进阶篇

### 2.1 JSONL 规范控制——让每种 Agent 只看它需要的规范

**详细讲解:**

上节我们创建了多个 Spec 文件。但问题是:如果项目有 50 个 Spec 文件,全部加载会占用大量上下文窗口。Trellis 的解决方案是 **JSONL 规范控制**——每种 Agent 角色有一个 `.jsonl` 文件,精确指定该 Agent 需要加载哪些 Spec。

这是一个 JSONL 文件(每行一个 JSON 对象),包含两个字段:
- `file`:Spec 文件的路径
- `reason`:为什么要注入这个 Spec(给 AI 提供上下文说明)

**代码示例:** 配置 Implement Agent 的规范注入

```bash
# 创建 Implement Agent 的 JSONL 控制文件
cat > .claude/agents/implement.jsonl << 'EOF'
{"file": ".trellis/spec/backend/api-design.md", "reason": "REST API URL 命名规范"}
{"file": ".trellis/spec/shared/error-handling.md", "reason": "错误处理和错误码规范"}
EOF

# 创建 Check Agent 的 JSONL 控制文件
# Check Agent 需要验证错误处理规范是否被正确遵循
cat > .claude/agents/check.jsonl << 'EOF'
{"file": ".trellis/spec/shared/error-handling.md", "reason": "验证错误处理规范是否被遵循"}
{"file": ".claude/commands/trellis/finish-work.md", "reason": "Lint 检查"}
{"file": ".claude/commands/trellis/finish-work.md", "reason": "TypeCheck 检查"}
EOF

echo "JSONL 控制文件已创建"

执行结果:

JSONL 控制文件已创建

验证 JSONL 文件格式:

# 验证 JSONL 格式是否正确(每行必须是合法 JSON)
python3 -c "
import json, sys
for i, line in enumerate(open('.claude/agents/implement.jsonl'), 1):
    try:
        obj = json.loads(line.strip())
        print(f'第 {i} 行: ✓ file={obj[\"file\"]}, reason={obj[\"reason\"]}')
    except json.JSONDecodeError as e:
        print(f'第 {i} 行: ✗ JSON 格式错误: {e}')
        sys.exit(1)
print('所有行格式正确!')
"

执行结果:

第 1 行: ✓ file=.trellis/spec/backend/api-design.md, reason=REST API URL 命名规范
第 2 行: ✓ file=.trellis/spec/shared/error-handling.md, reason=错误处理和错误码规范
所有行格式正确!

注意事项: - JSONL 文件中每行必须是独立的合法 JSON 对象,不能有多余的逗号或换行。 - file 路径是相对于项目根目录的路径,确保文件确实存在。 - reason 字段帮助 AI 理解为什么这个规范被注入,写清楚原因有助于 AI 更好地遵从规范。 - 如果 Spec 文件路径不存在,Hook 脚本执行时会跳过该条目并输出警告日志。

练习题: 1. 为 Research Agent 创建 research.jsonl 文件,指定它需要加载的规范(如分析框架和决策指南)。 2. 故意在 implement.jsonl 中写入一个不存在的文件路径,观察 Hook 脚本执行时的行为。


2.2 规范渐进披露——根据任务类型过滤规范

详细讲解:

上一节我们配置了每种 Agent 应该加载哪些规范。但还有更精细的需求:同一个 Agent 执行不同类型的任务时,应该加载不同的规范子集

例如,Implement Agent 执行前端任务时,不需要加载后端 Java 规范;执行后端任务时,不需要加载 React 组件规范。这就是规范渐进披露(Spec Progressive Disclosure)

Trellis 通过 _SPEC_MAP 实现这个过滤。_SPEC_MAP 定义了任务类型与规范类别的映射关系:

# _SPEC_MAP 核心逻辑(概念代码)
_SPEC_MAP = {
    "frontend": {"frontend", "shared", "guides"},        # 前端任务:只加载前端+共享+指南
    "backend":  {"backend-java", "shared", "cross-service", "guides"},  # 后端任务:只加载后端+共享+跨服务+指南
    "fullstack": None,  # 全栈任务:加载所有规范(None 表示不过滤)
}

工作原理: 1. Dispatch Agent 分析任务类型(frontend/backend/fullstack) 2. PreToolUse Hook 触发,读取任务类型 3. inject-subagent-context.py 根据 _SPEC_MAP 过滤 .jsonl 中的规范列表 4. 只有与任务类型匹配的规范被注入到 AI 上下文中

代码示例: 创建按类别组织的规范体系

# 创建前端规范
mkdir -p .trellis/spec/frontend

cat > .trellis/spec/frontend/component-patterns.md << 'EOF'
# React 组件规范

## 文件结构

每个 React 组件必须遵循以下文件结构:

components/ ├── Button/ │ ├── Button.tsx # 组件实现 │ ├── Button.test.tsx # 单元测试 │ ├── Button.module.css # 样式(使用 CSS Modules) │ └── index.ts # 导出


## 命名规范

- 组件文件名:PascalCase(如 `UserProfile.tsx`)
- 样式文件:`*.module.css`(必须使用 CSS Modules)
- 测试文件:`*.test.tsx`

## 禁止事项

- 禁止使用 inline styles
- 禁止在组件中直接调用 API(必须通过自定义 Hook)
EOF

# 创建后端规范(Java 示例)
mkdir -p .trellis/spec/backend

cat > .trellis/spec/backend/service-layer.md << 'EOF'
# Service 层规范

## 四层架构

所有后端接口必须遵循以下四层架构:

Controller → ServiceImpl → Manager → Dao


- **Controller**:只负责参数校验和响应封装,不含业务逻辑
- **ServiceImpl**:业务逻辑编排,事务管理
- **Manager**:通用业务封装,可被多个 ServiceImpl 复用
- **Dao**:数据访问层,只做数据库操作

## 禁止事项

- 禁止在 Controller 中编写业务逻辑
- 禁止在 ServiceImpl 中直接拼接 SQL
- 禁止跨层级调用(如 Controller 直接调用 Dao)
EOF

# 创建跨服务规范(微服务架构)
mkdir -p .trellis/spec/cross-service

cat > .trellis/spec/cross-service/api-contract.md << 'EOF'
# 跨服务 API 契约规范

## 接口变更原则

- 任何接口字段的修改(新增、删除、类型变更)必须通知下游服务
- 使用 Proto/GRPC 定义服务间契约
- 禁止直接修改已发布的 Proto 字段类型(必须新增字段)

## 影响分析

修改接口前,使用 GitNexus 分析下游服务影响范围。
EOF

echo "规范体系创建完成"

执行结果:

规范体系创建完成

验证规范类别划分:

# 查看当前规范目录结构,验证类别划分
find .trellis/spec -name "*.md" -type f | sort

执行结果:

.trellis/spec/backend/api-design.md
.trellis/spec/backend/service-layer.md
.trellis/spec/cross-service/api-contract.md
.trellis/spec/frontend/component-patterns.md
.trellis/spec/shared/error-handling.md

注意事项: - 规范目录名称(如 frontendbackendshared)需要与 _SPEC_MAP 中的类别名称对应。 - shared 目录下的规范会被前端和后端任务共同加载,放置两个领域都需要的通用规范。 - 如果项目没有微服务架构,可以不需要 cross-service 目录。 - fullstack 任务类型会加载所有规范,适用于涉及前后端同时修改的任务。

练习题: 1. 更新 implement.jsonl,添加新创建的前端和后端规范条目。然后思考:当任务类型为 frontend 时,哪些条目会被过滤掉? 2. 创建一个 guides/ 目录下的决策框架文件(如 api-versioning-guide.md),说明 API 版本迁移的决策流程。


2.3 四种 Agent 角色——理解分工协作

详细讲解:

Trellis 定义了四种专用 Agent,每种有明确的职责和规范注入策略。理解这四种角色的分工是使用 Trellis 的关键。

Agent 职责 规范注入 类比
Dispatch 接收任务,分析类型,调度子 Agent 不注入任何规范(纯路由) 项目经理
Implement 执行编码任务 通过 implement.jsonl 注入编码规范 开发工程师
Check 执行质量检查,输出完成标记 通过 check.jsonl 注入质量标准 质量工程师
Research 执行技术调研和代码分析 通过 research.jsonl 注入分析框架 技术顾问

关键设计:Dispatch Agent 是"纯路由"。它不读取任何规范,只负责分析任务类型并调度对应的子 Agent。所有上下文注入由 Hook 系统管理。这样设计的好处是:Dispatch Agent 的上下文窗口不被规范占用,全部用于任务分析和调度决策。

代码示例: 查看 Agent 定义文件

# 查看 Dispatch Agent 的定义
cat .claude/agents/dispatch.md
# Dispatch Agent

你是一个任务调度 Agent。你的职责是:

1. 接收用户的任务请求
2. 分析任务类型(frontend / backend / fullstack / research)
3. 调度对应的子 Agent 执行任务

## 调度规则

- 编码任务 → 调度 Implement Agent,完成后调度 Check Agent
- 调研任务 → 调度 Research Agent
- 不要自己执行任何编码或分析工作
- 不要读取任何规范文件(你的上下文由 Hook 管理)

## 任务状态更新

每次调度后,更新 `.trellis/tasks/task.json` 中的任务状态。
# 查看 Check Agent 的定义(关注完成标记机制)
cat .claude/agents/check.md
# Check Agent

你是一个质量检查 Agent。你的职责是:

1. 验证代码实现是否符合项目规范
2. 执行类型检查,完成后输出 `TYPECHECK_FINISH`
3. 执行代码检查(Lint),完成后输出 `LINT_FINISH`
4. 如果发现问题,修复后重新检查

## 完成标记

当你完成所有检查后,必须在输出中包含以下标记:
- `TYPECHECK_FINISH` — 类型检查通过
- `LINT_FINISH` — 代码检查通过

这些标记会被 Ralph Loop 验证。缺少标记将阻止你完成任务。

执行结果:

(显示上述 Markdown 文件内容)

练习题: 1. 阅读所有四种 Agent 的 .md 定义文件,对比它们的职责差异。思考:为什么 Dispatch 不注入任何规范? 2. 尝试修改 check.md,添加一个新的完成标记(如 TEST_FINISH),要求 Check Agent 在测试通过后输出该标记。


第三部分:高级篇

3.1 Ralph Loop 质量控制——确保 AI 不"偷懒"

详细讲解:

Ralph Loop 是 Trellis 最独特的质量保障机制。问题背景:AI 编码助手可能声称"已完成"任务,但实际未执行所有检查步骤。例如,Check Agent 说"代码检查通过",但没有真正运行 Lint。

Ralph Loop 的工作流程:

  1. Check Agent 执行检查任务,在输出中包含完成标记(如 TYPECHECK_FINISHLINT_FINISH
  2. Check Agent 尝试停止(触发 SubagentStop Hook)
  3. ralph-loop.py 脚本执行,扫描 Agent 的输出是否包含所有要求的完成标记
  4. 如果所有标记都存在 → 允许 Agent 停止
  5. 如果有标记缺失 → 阻止停止,返回缺失标记列表 → Agent 继续修复 → 重新触发检查
  6. 最多循环 N 次(防止无限循环)

代码示例: 配置 Ralph Loop 的完成标记

# 更新 check.jsonl,定义 Check Agent 需要验证的规范和对应标记
cat > .claude/agents/check.jsonl << 'EOF'
{"file": ".trellis/spec/shared/error-handling.md", "reason": "验证错误处理规范"}
{"file": ".trellis/spec/backend/service-layer.md", "reason": "验证四层架构规范"}
{"file": ".claude/commands/trellis/finish-work.md", "reason": "Lint"}
{"file": ".claude/commands/trellis/finish-work.md", "reason": "TypeCheck"}
EOF

echo "Ralph Loop 完成标记配置已更新"

执行结果:

Ralph Loop 完成标记配置已更新

Ralph Loop 验证逻辑(概念代码):

# ralph-loop.py 的核心验证逻辑(概念代码,理解工作原理)
import sys

def check_completion_markers(agent_output, required_markers):
    """检查 Agent 输出是否包含所有要求的完成标记"""
    missing = []
    for marker in required_markers:
        if marker not in agent_output:
            missing.append(marker)

    if missing:
        # 有标记缺失 → 阻止停止,返回缺失信息
        print(f"BLOCK: 以下完成标记缺失: {', '.join(missing)}")
        print("请继续执行相关检查并输出对应标记。")
        sys.exit(2)  # 非零退出码阻止 Agent 停止
    else:
        # 所有标记存在 → 允许停止
        print("APPROVE: 所有完成标记验证通过。")
        sys.exit(0)

# 要求的完成标记来自 check.jsonl 中的 reason 字段
required_markers = ["TYPECHECK_FINISH", "LINT_FINISH"]

注意事项: - 完成标记的名称是在 check.jsonlreason 字段中定义的,确保标记名称在 check.mdralph-loop.py 之间一致。 - Ralph Loop 有最大迭代次数限制,防止 Check Agent 无法修复问题时的无限循环。如果达到最大次数仍有标记缺失,Agent 会被强制停止并报告未通过的检查。 - 完成标记应该是唯一的、不会在普通文本中意外出现的字符串(如 TYPECHECK_FINISH 而不是 done)。

练习题: 1. 在 check.jsonl 中添加一个新的条目,要求 Check Agent 验证 API 设计规范,并输出 API_CHECK_FINISH 标记。 2. 思考:如果 Check Agent 的输出中包含了 TYPECHECK_FINISH 字符串但实际没有运行类型检查,Ralph Loop 能检测到吗?这说明了什么?


3.2 Git Worktree 并行会话——让多个 Agent 同时工作

详细讲解:

当团队有多个独立任务需要同时处理时,单个 AI 会话串行执行效率太低。Trellis 基于 Git Worktree 实现多 Agent 并行执行。

Git Worktree 允许同一个仓库同时拥有多个工作目录,每个目录对应不同的分支。Trellis 为每个并行 Agent 创建一个独立的 worktree,Agent 在自己的 worktree 中工作,完成后合并回主分支。

代码示例: 配置并行会话

# 查看 worktree 配置文件
cat .trellis/worktree.yaml
# .trellis/worktree.yaml
# 定义并行会话配置
sessions:
  - name: "feature-auth"
    task: "实现用户认证模块"
    branch: "feature/auth"
  - name: "feature-order-api"
    task: "实现订单 API 模块"
    branch: "feature/order-api"
# 查看当前 Git Worktree 状态
git worktree list

执行结果:

/Users/developer/my-project        abc1234 [main]

并行会话的工作流程(概念说明):

# 步骤 1:创建 worktree 用于并行 Agent
git worktree add .trellis/worktrees/feature-auth feature/auth

# 步骤 2:在独立 worktree 中启动 Agent(概念命令)
# Trellis 会自动管理这个过程
# 每个 Agent 在自己的 worktree 中独立工作

# 步骤 3:Agent 完成后合并
git checkout main
git merge feature/auth
git worktree remove .trellis/worktrees/feature-auth

注意事项: - 并行任务之间不能有依赖关系。如果任务 B 依赖任务 A 的输出,它们必须串行执行。 - Worktree 目录在 .gitignore 中应被忽略,不要提交到版本控制。 - 合并时可能产生冲突,需要人工或 AI 辅助解决。 - 并行 Agent 数量受限于 AI 编码平台的并发会话能力和 GPU/API 配额。

练习题: 1. 使用 git worktree add 手动创建一个 worktree,在其中做一次代码修改,然后合并回主分支。这有助于理解 Trellis 并行会话的底层机制。 2. 思考:如果两个并行 Agent 修改了同一个文件的不同位置,合并时会发生什么?


3.3 任务生命周期管理——从创建到完成

详细讲解:

Trellis 将 AI 编码从"自由对话"转变为"任务驱动"。每个任务有明确的状态、类型和执行阶段,持久化在 .trellis/tasks/task.json 中。

任务状态流转:

pending → in_progress → completed
                ↓
           in_progress (Check 阶段)

任务阶段(next_action):

[
  {"phase": 1, "action": "implement"},  // 阶段 1:实现
  {"phase": 2, "action": "check"},      // 阶段 2:检查
  {"phase": 3, "action": "finish"}      // 阶段 3:完成
]

代码示例: 查看和操作任务状态

# 查看当前任务列表
ls .trellis/tasks/

执行结果:

task.json
# 查看任务状态
cat .trellis/tasks/task.json
{
  "title": "实现用户注册 API",
  "status": "in_progress",
  "dev_type": "backend",
  "current_phase": 1,
  "next_action": [
    {"phase": 1, "action": "implement"},
    {"phase": 2, "action": "check"},
    {"phase": 3, "action": "finish"}
  ],
  "created_at": "2026-04-04T10:00:00Z",
  "updated_at": "2026-04-04T10:30:00Z"
}

注意事项: - task.json 记录了任务的完整状态,支持跨会话恢复。如果 AI 会话意外中断,下次启动时可以从当前阶段继续。 - dev_type 字段决定了规范渐进披露的过滤规则(frontend/backend/fullstack),确保正确设置。 - current_phasenext_action 数组配合使用,Dispatch Agent 根据当前阶段调度对应的子 Agent。

练习题: 1. 手动创建一个 task.json 文件,定义一个前端任务(dev_type: "frontend")。思考:这个任务会加载哪些规范?不会加载哪些? 2. 思考跨会话恢复的场景:如果在 Implement 阶段会话中断,下次启动时 Trellis 如何知道应该继续实现而不是重新开始?


3.4 最佳实践

  1. Spec 编写原则:每个 Spec 文件应该聚焦于一个主题(如"错误处理"、"API 设计"、"组件模式"),不要在一个文件中混合多个不相关的主题。文件名使用小写连字符命名(如 error-handling.mdapi-design.md)。

  2. JSONL 维护原则:每次新增或删除 Spec 文件时,同步更新对应的 .jsonl 文件。可以编写简单的验证脚本确保 .jsonl 中引用的文件都存在。

  3. 完成标记设计原则:标记名称应该具有描述性(如 TYPECHECK_FINISH 而非 DONE1),避免在普通文本中意外出现。

  4. 团队协作原则.trellis/ 目录应提交到 Git,确保所有团队成员共享同一套规范。.trellis/workspace/ 目录应添加到 .gitignore(个人工作日志不需要共享)。

  5. 版本管理原则:Trellis 当前处于 v0.x 版本,API 可能变化。在 .trellis/ 目录中添加版本标记文件,升级前在测试项目中验证兼容性。


第四部分:实战项目

项目需求

构建一个 Trellis 规范验证工具,实现以下功能:

  1. 扫描 .trellis/spec/ 目录下所有规范文件
  2. 验证 JSONL 控制文件中引用的规范是否存在
  3. 检查完成标记的一致性(check.jsonl 中的标记是否在 check.md 中定义)
  4. 生成验证报告

本项目的知识点覆盖: - 1.2 节:Trellis 目录结构和文件组织 - 2.1 节:JSONL 规范控制文件的格式和作用 - 3.1 节:Ralph Loop 完成标记机制

项目设计

trellis-validator/
├── validate.py          # 主脚本:验证逻辑
├── README.md            # 使用说明
└── .trellis/            # 测试用的 Trellis 配置
    ├── spec/            # 测试规范文件
    └── ...

完整实现代码

# validate.py —— Trellis 规范验证工具
# 验证 Spec 文件完整性、JSONL 引用有效性和完成标记一致性

import json
import os
import sys
from pathlib import Path


def find_project_root():
    """查找项目根目录(包含 .trellis/ 的目录)"""
    current = Path.cwd()
    while current != current.parent:
        if (current / ".trellis").exists():
            return current
        current = current.parent
    return None


def scan_spec_files(project_root):
    """扫描 .trellis/spec/ 目录下所有规范文件"""
    # 知识点 1.2:理解 Trellis 目录结构
    spec_dir = project_root / ".trellis" / "spec"
    if not spec_dir.exists():
        print(f"错误:规范目录不存在: {spec_dir}")
        return {}

    # 按类别收集规范文件
    spec_by_category = {}
    for md_file in sorted(spec_dir.rglob("*.md")):
        # 类别是 spec/ 下的第一级子目录名
        relative = md_file.relative_to(spec_dir)
        category = str(relative.parts[0]) if len(relative.parts) > 1 else "root"
        if category not in spec_by_category:
            spec_by_category[category] = []
        spec_by_category[category].append(str(md_file.relative_to(project_root)))

    return spec_by_category


def validate_jsonl_references(project_root):
    """验证 JSONL 文件中引用的规范文件是否存在"""
    # 知识点 2.1:JSONL 规范控制文件的格式和作用
    agents_dir = project_root / ".claude" / "agents"
    results = {"valid": [], "missing": [], "parse_errors": []}

    if not agents_dir.exists():
        print("警告:.claude/agents/ 目录不存在")
        return results

    for jsonl_file in sorted(agents_dir.glob("*.jsonl")):
        with open(jsonl_file, "r", encoding="utf-8") as f:
            for line_num, line in enumerate(f, 1):
                line = line.strip()
                if not line:
                    continue
                try:
                    entry = json.loads(line)
                    spec_path = project_root / entry["file"]
                    if spec_path.exists():
                        results["valid"].append({
                            "jsonl": str(jsonl_file.name),
                            "line": line_num,
                            "file": entry["file"],
                            "reason": entry["reason"]
                        })
                    else:
                        results["missing"].append({
                            "jsonl": str(jsonl_file.name),
                            "line": line_num,
                            "file": entry["file"],
                            "reason": entry["reason"]
                        })
                except json.JSONDecodeError as e:
                    results["parse_errors"].append({
                        "jsonl": str(jsonl_file.name),
                        "line": line_num,
                        "error": str(e)
                    })

    return results


def check_completion_markers(project_root):
    """检查完成标记的一致性"""
    # 知识点 3.1:Ralph Loop 完成标记机制
    check_jsonl = project_root / ".claude" / "agents" / "check.jsonl"
    check_md = project_root / ".claude" / "agents" / "check.md"

    results = {"markers_in_jsonl": [], "markers_in_md": [], "inconsistent": []}

    if not check_jsonl.exists():
        print("警告:check.jsonl 不存在,跳过完成标记检查")
        return results

    # 从 check.jsonl 提取标记
    markers_from_jsonl = set()
    with open(check_jsonl, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            try:
                entry = json.loads(line)
                reason = entry.get("reason", "").upper()
                # 常见标记关键词
                for keyword in ["LINT", "TYPECHECK", "TEST", "CHECK"]:
                    if keyword in reason:
                        marker = f"{keyword}_FINISH"
                        markers_from_jsonl.add(marker)
                        results["markers_in_jsonl"].append({
                            "marker": marker,
                            "source": entry["file"]
                        })
            except json.JSONDecodeError:
                pass

    # 从 check.md 提取标记
    markers_from_md = set()
    if check_md.exists():
        with open(check_md, "r", encoding="utf-8") as f:
            content = f.read()
            for keyword in ["LINT_FINISH", "TYPECHECK_FINISH", "TEST_FINISH", "CHECK_FINISH"]:
                if keyword in content:
                    markers_from_md.add(keyword)
                    results["markers_in_md"].append({"marker": keyword})

    # 检查一致性
    jsonl_only = markers_from_jsonl - markers_from_md
    md_only = markers_from_md - markers_from_jsonl
    for marker in jsonl_only:
        results["inconsistent"].append({
            "marker": marker,
            "issue": "标记在 check.jsonl 中引用,但未在 check.md 中定义"
        })
    for marker in md_only:
        results["inconsistent"].append({
            "marker": marker,
            "issue": "标记在 check.md 中定义,但未在 check.jsonl 中引用"
        })

    return results


def generate_report(spec_results, jsonl_results, marker_results):
    """生成验证报告"""
    print("=" * 60)
    print("Trellis 规范验证报告")
    print("=" * 60)

    # 1. Spec 文件扫描结果
    print("\n📋 Spec 文件扫描结果:")
    total_specs = sum(len(files) for files in spec_results.values())
    print(f"  共发现 {total_specs} 个规范文件,分布在 {len(spec_results)} 个类别中")
    for category, files in spec_results.items():
        print(f"  - {category}/:{len(files)} 个文件")
        for f in files:
            print(f"      {f}")

    # 2. JSONL 引用验证结果
    print(f"\n🔗 JSONL 引用验证结果:")
    print(f"  ✓ 有效引用:{len(jsonl_results['valid'])} 个")
    print(f"  ✗ 缺失文件:{len(jsonl_results['missing'])} 个")
    print(f"  ✗ 格式错误:{len(jsonl_results['parse_errors'])} 个")

    for item in jsonl_results["missing"]:
        print(f"  ⚠ [{item['jsonl']}:L{item['line']}] 文件不存在: {item['file']} (原因: {item['reason']})")

    for item in jsonl_results["parse_errors"]:
        print(f"  ⚠ [{item['jsonl']}:L{item['line']}] JSON 格式错误: {item['error']}")

    # 3. 完成标记一致性检查
    print(f"\n🏷 完成标记一致性检查:")
    print(f"  check.jsonl 中的标记:{[m['marker'] for m in marker_results['markers_in_jsonl']]}")
    print(f"  check.md 中的标记:{[m['marker'] for m in marker_results['markers_in_md']]}")

    if marker_results["inconsistent"]:
        print(f"  ⚠ 发现 {len(marker_results['inconsistent'])} 个不一致:")
        for item in marker_results["inconsistent"]:
            print(f"    - {item['marker']}: {item['issue']}")
    else:
        print("  ✓ 所有完成标记一致")

    # 4. 总结
    issues_count = (
        len(jsonl_results["missing"])
        + len(jsonl_results["parse_errors"])
        + len(marker_results["inconsistent"])
    )
    print(f"\n{'=' * 60}")
    if issues_count == 0:
        print("✅ 验证通过!所有配置正确。")
    else:
        print(f"❌ 发现 {issues_count} 个问题,请修复后重新验证。")
    print(f"{'=' * 60}")


def main():
    """主入口"""
    # 知识点 1.2:定位项目根目录
    project_root = find_project_root()
    if project_root is None:
        print("错误:未找到 .trellis/ 目录。请在 Trellis 项目根目录中运行此脚本。")
        sys.exit(1)

    print(f"项目根目录: {project_root}")

    # 知识点 1.2:扫描规范文件
    spec_results = scan_spec_files(project_root)

    # 知识点 2.1:验证 JSONL 引用
    jsonl_results = validate_jsonl_references(project_root)

    # 知识点 3.1:检查完成标记一致性
    marker_results = check_completion_markers(project_root)

    # 生成报告
    generate_report(spec_results, jsonl_results, marker_results)


if __name__ == "__main__":
    main()

代码解析

  1. 扫描规范文件(知识点 1.2)scan_spec_files 函数递归扫描 .trellis/spec/ 目录,按类别(frontend/backend/shared 等)收集所有 Markdown 规范文件。使用了 Path.rglob("*.md") 进行文件搜索。

  2. 验证 JSONL 引用(知识点 2.1)validate_jsonl_references 函数读取所有 .jsonl 文件,逐行解析 JSON,检查每个 file 路径是否存在。同时捕获 JSON 格式错误,帮助开发者快速定位配置问题。

  3. 完成标记一致性(知识点 3.1)check_completion_markers 函数分别从 check.jsonlcheck.md 提取完成标记,交叉验证一致性。如果 JSONL 中引用的标记未在 MD 中定义(或反之),报告为不一致。

扩展挑战

  1. 添加 Spec 内容验证:检查每个 Spec 文件是否包含必要的章节(如"禁止事项"章节),确保规范的格式统一。提示:使用正则表达式或简单的字符串匹配。

  2. 添加 _SPEC_MAP 验证:验证规范文件的目录分类是否与 _SPEC_MAP 中定义的类别名称匹配。提示:扫描 spec/ 下的子目录名,与 _SPEC_MAP 中的集合取交集验证。

  3. CI/CD 集成:将验证脚本集成到 GitHub Actions 或 GitLab CI 中,每次提交时自动验证 Trellis 配置的完整性。提示:在 CI 配置文件中添加 python validate.py 步骤,非零退出码阻止合并。


第五部分:常见问题与排查指南

常见错误及解决方案

错误信息 原因 解决方案
trellis: command not found npm 全局安装路径不在 PATH 中 运行 npm config get prefix 查看路径,将其添加到 PATH:export PATH="$(npm config get prefix)/bin:$PATH"
Python not found 运行 Hook 时报错 系统中 python 命令不可用 安装 Python 3 或创建软链接:ln -s /usr/bin/python3 /usr/local/bin/python
Hook 脚本执行超时 session-start.py 超过 30 秒超时 检查 workflow.md 文件大小,如果过大考虑拆分。或增大 .claude/settings.json 中的 timeout
JSONL 解析错误 .jsonl 文件中有非法 JSON 行 运行 python3 -c "import json; [json.loads(l) for l in open('.claude/agents/implement.jsonl') if l.strip()]" 验证格式
Spec 文件未被注入 .jsonl 文件中的路径错误或文件不存在 检查路径是否相对于项目根目录,确保文件确实存在
Dispatch Agent 读取了规范 Hook 配置中 matcher 字段缺失 确保 .claude/settings.json 中 PreToolUse Hook 的 matcher 设置为 "Agent"
Ralph Loop 无限循环 Check Agent 无法满足检查条件 检查完成标记名称是否在 check.mdcheck.jsonl 之间一致。确认最大迭代次数设置合理
Git Worktree 创建失败 分支名称冲突或 Git 状态不干净 先提交或暂存当前更改(git stash),然后重新创建 worktree
任务状态不一致 task.json 手动编辑导致格式错误 删除 task.json 让 Trellis 重新生成,或使用 JSON 验证工具检查格式
规范不生效(AI 仍忽略规范) Hook 未正确注册或脚本无执行权限 检查 .claude/settings.json 中 Hook 配置是否正确,确认 .claude/hooks/ 下脚本有执行权限(chmod +x

调试技巧

  1. 手动执行 Hook 脚本排查问题:如果 Hook 不生效,手动运行脚本查看输出和错误信息:
# 手动执行 session-start Hook,查看注入内容
python3 .claude/hooks/session-start.py

# 检查脚本的退出码
echo "退出码: $?"
  1. 验证 JSONL 文件完整性:批量检查所有 JSONL 文件的格式和引用有效性:
# 一行命令验证所有 JSONL 文件
for f in .claude/agents/*.jsonl; do
    echo "=== $f ==="
    python3 -c "
import json, sys
errors = 0
for i, line in enumerate(open('$f'), 1):
    line = line.strip()
    if not line: continue
    try:
        json.loads(line)
    except json.JSONDecodeError as e:
        print(f'  L{i}: {e}')
        errors += 1
print(f'  共 {errors} 个错误' if errors else '  ✓ 格式正确')
"
done
  1. 查看 Trellis 工作日志:检查 .trellis/workspace/ 目录下的日志文件,了解 Hook 的执行历史和任务状态变化。

第六部分:学习路线推荐

官方文档推荐阅读顺序

  1. Trellis README - 重点关注安装步骤和快速入门,理解 Trellis 的核心定位。GitHub 地址:mindfold-ai/Trellis

  2. .trellis/workflow.md - Trellis 初始化后自动生成的工作流指南,在 Claude Code 启动时自动注入。理解 Trellis 的默认工作流设计。

  3. .claude/agents/ 目录 - 逐个阅读四种 Agent 的定义文件(dispatch.md、implement.md、check.md、research.md),理解角色分工。

  4. .claude/hooks/ 目录 - 阅读 Hook 脚本源码,理解 SessionStart、PreToolUse、SubagentStop 三种 Hook 的具体实现。

  5. Trellis 官网 - trytrellis.app 查看最新功能介绍和更新日志。

推荐进阶资源

  • Claude Code Hooks 文档 - 深入理解 Claude Code 的原生 Hook API,这是 Trellis 的底层机制。理解 Hook 的事件类型、配置方式和执行模型。

  • Git Worktree 教程 - 掌握 Git Worktree 的基本操作,理解 Trellis 并行会话的底层原理。推荐阅读 Git 官方文档 - git-worktree

  • MCP(Model Context Protocol) - 了解 Trellis 集成的 MCP 工具(ABCoder、GitNexus、Playwright 等)的工作原理,扩展 Trellis 的能力边界。

相关框架对比学习

  • Superpowersobra/superpowers)- 对比理解"可选 Skill 加载"与"Hook 强制注入"的设计差异。Superpowers 的 14 个模块化 Skill 提供了另一种 AI 编码增强的思路。

  • BMAD Methodbmad-code-org/BMAD-METHOD)- 对比理解"文档驱动"与"Hook 驱动"的团队协作方式。BMAD 的四阶段敏捷循环提供了完整的方法论参考。

  • Claude Code 原生 Skills - 理解 CLAUDE.md.claude/commands/ 等 Claude Code 原生配置机制,评估在哪些场景下原生机制已足够,哪些场景需要 Trellis 的增强能力。