
Terrain --- prepares the ground so agents don't have to guess where to stand.
🔗 GitHub:https://github.com/sopaco/terrain
团队在 CI 流水线中经常遇到:
- 每次合并都要重新生成文档------但其实只有几个文件变了
- 知识资产与代码脱节却无人察觉------直到 AI 助手基于过时信息给出了错误建议
- 每个 CI 环境都要手动安装工具链------CodeGraph、RTK、Skills 反复配置
- 流水线输出难以集成到 Agent 工作流------需要把信息转换成 Agent 能理解的格式
Terrain 的设计哲学就是为自动化而生:JSON 输出、增量刷新、无界面运行、工具链一键部署。
核心能力:CLI 优先,JSON 贯穿始终
Terrain 的所有命令都设计为可在脚本和流水线中直接调用:
- JSON 标准输出 --- 每条
terrain tools命令都输出 JSON,无需解析定制格式 - NDJSON 事件流 ---
terrain ask query --stream输出逐行 JSON 事件,可实时流式消费 - 无界面运行 --- CLI 不依赖任何显示服务,可在纯终端环境运行
#mermaid-svg-iapg7xK6czwi5iIC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iapg7xK6czwi5iIC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iapg7xK6czwi5iIC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iapg7xK6czwi5iIC .error-icon{fill:#552222;}#mermaid-svg-iapg7xK6czwi5iIC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iapg7xK6czwi5iIC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iapg7xK6czwi5iIC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iapg7xK6czwi5iIC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iapg7xK6czwi5iIC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iapg7xK6czwi5iIC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iapg7xK6czwi5iIC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iapg7xK6czwi5iIC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iapg7xK6czwi5iIC .marker.cross{stroke:#333333;}#mermaid-svg-iapg7xK6czwi5iIC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iapg7xK6czwi5iIC p{margin:0;}#mermaid-svg-iapg7xK6czwi5iIC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-iapg7xK6czwi5iIC .cluster-label text{fill:#333;}#mermaid-svg-iapg7xK6czwi5iIC .cluster-label span{color:#333;}#mermaid-svg-iapg7xK6czwi5iIC .cluster-label span p{background-color:transparent;}#mermaid-svg-iapg7xK6czwi5iIC .label text,#mermaid-svg-iapg7xK6czwi5iIC span{fill:#333;color:#333;}#mermaid-svg-iapg7xK6czwi5iIC .node rect,#mermaid-svg-iapg7xK6czwi5iIC .node circle,#mermaid-svg-iapg7xK6czwi5iIC .node ellipse,#mermaid-svg-iapg7xK6czwi5iIC .node polygon,#mermaid-svg-iapg7xK6czwi5iIC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iapg7xK6czwi5iIC .rough-node .label text,#mermaid-svg-iapg7xK6czwi5iIC .node .label text,#mermaid-svg-iapg7xK6czwi5iIC .image-shape .label,#mermaid-svg-iapg7xK6czwi5iIC .icon-shape .label{text-anchor:middle;}#mermaid-svg-iapg7xK6czwi5iIC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iapg7xK6czwi5iIC .rough-node .label,#mermaid-svg-iapg7xK6czwi5iIC .node .label,#mermaid-svg-iapg7xK6czwi5iIC .image-shape .label,#mermaid-svg-iapg7xK6czwi5iIC .icon-shape .label{text-align:center;}#mermaid-svg-iapg7xK6czwi5iIC .node.clickable{cursor:pointer;}#mermaid-svg-iapg7xK6czwi5iIC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iapg7xK6czwi5iIC .arrowheadPath{fill:#333333;}#mermaid-svg-iapg7xK6czwi5iIC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iapg7xK6czwi5iIC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iapg7xK6czwi5iIC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iapg7xK6czwi5iIC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iapg7xK6czwi5iIC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iapg7xK6czwi5iIC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iapg7xK6czwi5iIC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iapg7xK6czwi5iIC .cluster text{fill:#333;}#mermaid-svg-iapg7xK6czwi5iIC .cluster span{color:#333;}#mermaid-svg-iapg7xK6czwi5iIC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iapg7xK6czwi5iIC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iapg7xK6czwi5iIC rect.text{fill:none;stroke-width:0;}#mermaid-svg-iapg7xK6czwi5iIC .icon-shape,#mermaid-svg-iapg7xK6czwi5iIC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iapg7xK6czwi5iIC .icon-shape p,#mermaid-svg-iapg7xK6czwi5iIC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iapg7xK6czwi5iIC .icon-shape .label rect,#mermaid-svg-iapg7xK6czwi5iIC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iapg7xK6czwi5iIC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iapg7xK6czwi5iIC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iapg7xK6czwi5iIC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 流水线集成
JSON 输出
NDJSON 流
增量刷新
CI 流水线
terrain tools
terrain ask query --stream
terrain refresh
terrain-core
无 LLM 调用
terrain-agent
知识检索 + LLM
典型 CI 用法:合并时自动刷新知识
bash
# 在 CI 脚本中:合并后自动刷新知识资产
terrain refresh .
# 输出项目新鲜度到日志
terrain project freshness-cached --project my-repo
# 如果新鲜度低于阈值,标记为警告
terrain tools freshness --project my-repo | jq '.score'
这意味着每次代码合并后,知识资产自动更新,无需人工干预。 新成员 clone 仓库后看到的一切知识都是最新的。
环境标准化:terrain env apply 一键部署
在 CI 或新环境中,一条命令安装所有 Agent 工具链:
bash
# 预览将要安装的组件
terrain env plan
# 一键安装:Skills、CodeGraph、RTK、AGENTS.md 片段
terrain env apply
# 验证安装状态
terrain env status
| 组件 | 说明 |
|---|---|
| Skills | 标准化工作流程指令(知识查询、SDD、Ask、架构分析) |
| CodeGraph | 符号调用关系图谱 |
| RTK | 压缩 Shell 输出,节省 Token |
| AGENTS.md | 统一项目约定片段 |

Terrain 的环境配置界面,一键为所有 Agent 部署标准化工具链。
跨平台分发:npm + 预编译安装包
| 方式 | 适用场景 | 安装方式 |
|---|---|---|
| npm 包 | CI/CD、无头服务器、Agent 流水线 | npm install -g @terrain-ai/cli |
| 预编译安装包 | 本地开发、桌面使用 | GitHub Releases 下载 |
| Node.js shim | npm 环境中的工具调用 | 自动安装 |
- macOS(Apple Silicon) 和 Windows x64 均有预编译二进制
@terrain-ai/cli和@terrain-ai/rtk均可通过 npm 全局安装- 桌面应用通过 Tauri 打包,内置 CLI,无需额外安装
核心技术:为什么适合流水线?
Rust 原生核心,离线可运行
所有核心计算由 terrain-core(纯 Rust)完成:
- 无运行时依赖 --- 单一二进制,不依赖 Node.js/Python/数据库
- 离线执行 --- scan、pack、search、freshness 不调用 LLM
- 确定性输出 --- 相同输入产生相同 JSON 输出,适合自动化断言
增量刷新引擎
#mermaid-svg-o2YkNgt772FHn7RD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-o2YkNgt772FHn7RD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-o2YkNgt772FHn7RD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-o2YkNgt772FHn7RD .error-icon{fill:#552222;}#mermaid-svg-o2YkNgt772FHn7RD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-o2YkNgt772FHn7RD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-o2YkNgt772FHn7RD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-o2YkNgt772FHn7RD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-o2YkNgt772FHn7RD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-o2YkNgt772FHn7RD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-o2YkNgt772FHn7RD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-o2YkNgt772FHn7RD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-o2YkNgt772FHn7RD .marker.cross{stroke:#333333;}#mermaid-svg-o2YkNgt772FHn7RD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-o2YkNgt772FHn7RD p{margin:0;}#mermaid-svg-o2YkNgt772FHn7RD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-o2YkNgt772FHn7RD .cluster-label text{fill:#333;}#mermaid-svg-o2YkNgt772FHn7RD .cluster-label span{color:#333;}#mermaid-svg-o2YkNgt772FHn7RD .cluster-label span p{background-color:transparent;}#mermaid-svg-o2YkNgt772FHn7RD .label text,#mermaid-svg-o2YkNgt772FHn7RD span{fill:#333;color:#333;}#mermaid-svg-o2YkNgt772FHn7RD .node rect,#mermaid-svg-o2YkNgt772FHn7RD .node circle,#mermaid-svg-o2YkNgt772FHn7RD .node ellipse,#mermaid-svg-o2YkNgt772FHn7RD .node polygon,#mermaid-svg-o2YkNgt772FHn7RD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-o2YkNgt772FHn7RD .rough-node .label text,#mermaid-svg-o2YkNgt772FHn7RD .node .label text,#mermaid-svg-o2YkNgt772FHn7RD .image-shape .label,#mermaid-svg-o2YkNgt772FHn7RD .icon-shape .label{text-anchor:middle;}#mermaid-svg-o2YkNgt772FHn7RD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-o2YkNgt772FHn7RD .rough-node .label,#mermaid-svg-o2YkNgt772FHn7RD .node .label,#mermaid-svg-o2YkNgt772FHn7RD .image-shape .label,#mermaid-svg-o2YkNgt772FHn7RD .icon-shape .label{text-align:center;}#mermaid-svg-o2YkNgt772FHn7RD .node.clickable{cursor:pointer;}#mermaid-svg-o2YkNgt772FHn7RD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-o2YkNgt772FHn7RD .arrowheadPath{fill:#333333;}#mermaid-svg-o2YkNgt772FHn7RD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-o2YkNgt772FHn7RD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-o2YkNgt772FHn7RD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o2YkNgt772FHn7RD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-o2YkNgt772FHn7RD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o2YkNgt772FHn7RD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-o2YkNgt772FHn7RD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-o2YkNgt772FHn7RD .cluster text{fill:#333;}#mermaid-svg-o2YkNgt772FHn7RD .cluster span{color:#333;}#mermaid-svg-o2YkNgt772FHn7RD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-o2YkNgt772FHn7RD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-o2YkNgt772FHn7RD rect.text{fill:none;stroke-width:0;}#mermaid-svg-o2YkNgt772FHn7RD .icon-shape,#mermaid-svg-o2YkNgt772FHn7RD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o2YkNgt772FHn7RD .icon-shape p,#mermaid-svg-o2YkNgt772FHn7RD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-o2YkNgt772FHn7RD .icon-shape .label rect,#mermaid-svg-o2YkNgt772FHn7RD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o2YkNgt772FHn7RD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-o2YkNgt772FHn7RD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-o2YkNgt772FHn7RD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 变更文件
变更模块
无变更
Git 代码仓库
ProjectScanner
收集 Git 元数据
哪些文件变了?
repomix 重新打包
更新对应 C4 文档
跳过文档生成
更新 context.md
重新计算新鲜度评分
输出 JSON 结果
只处理变化的部分------这是增量刷新与传统全量重新生成的核心区别。一个 10 万行代码的项目,如果只修改了几个文件,刷新可能只需几秒。
流水线友好的输出格式
bash
# JSON 输出可直接被 jq/脚本处理
terrain tools read-context --project my-repo | jq '.modules[].name'
# NDJSON 流可实时消费
terrain ask query "系统如何处理请求?" --project my-repo --stream | while read line; do
echo "$line" | jq '.type'
done
# 适合 CI 日志和断言
terrain project freshness-cached --project my-repo > freshness.json
完整 CI 示例
bash
#!/bin/bash
# .github/workflows/terrain-knowledge.yml
name: Update Knowledge Assets
on: [push, pull_request]
jobs:
refresh-knowledge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Terrain CLI
run: npm install -g @terrain-ai/cli
- name: Refresh knowledge assets
run: |
terrain refresh .
terrain project freshness-cached --project my-repo
- name: Check freshness threshold
run: |
SCORE=$(terrain project overview --project my-repo | jq '.freshness_score')
if [ "$SCORE" -lt 50 ]; then
echo "::warning::Knowledge assets are stale (score: $SCORE)"
fi
适合谁?
- DevOps 工程师 --- 将知识资产更新纳入 CI 流水线
- 平台团队 --- 标准化所有项目的 Agent 环境
- 大规模团队 --- 新仓库自动获得知识资产,无需手动配置
- ACP 集成者 --- 将
terrain toolsJSON API 接入自动化 Agent 循环 - 开源项目维护者 --- 让贡献者 clone 后立刻拥有完整的项目知识
"JSON 输出、增量刷新、一键部署------为自动化而生的知识流水线。"