@jh-cairn/cairn
v0.1.23
Published
Project-level state machine, gates, context directory, and auditable workflow orchestrator for Claude Code / Codex
Maintainers
Readme
cairn
在 Claude Code / Codex / opencode 之上补齐「项目级状态机、门禁、上下文目录、可审计流程」的编排器 CLI。
cairn(玛尼堆 / 路标石堆)是一个本地优先的编排层,把变更从「想法」到「合并」的过程变成显式、可强制、可审计的流程。
核心概念
- 状态机 — 跨会话的流程真相,决定下一步、约束路径、支持恢复
- 门禁 — 状态流转前置条件,质量阀门 + 失败回灌的自纠正环
- 审计 — append-only 事件流(
events.jsonl,每条事件带链式 hash),既是审计、也是状态真相;执行器对.cairn/的写入被 hook 拦截(Claude Code),无 hook 机制的执行器由执行前后快照比对兜底(guardrail_violation事件,链被重写直接 halt) - 多执行器 — 内置 claude-code / codex / opencode 适配器,任意 CLI 可经
type: custom命令模板接入;支持 per-state 路由(如实现用 codex、评审 judge 用 claude) - GitLab 投影 — 状态转移自动同步到 GitLab(scoped label、MR ready 状态、issue note)
安装
npm install -g @jh-cairn/cairn本仓库开发:
npm install
npm run build
npm link # 全局注册 cairn 命令开发阶段可直接用 npx tsx src/index.ts 运行。
快速开始
# 1. 初始化项目(每个项目一次;TTY 下交互选择执行器,或用 --executor 直接指定)
cairn init
cairn init --executor codex # claude-code | codex | opencode
cairn init --force # 覆盖已有 config.yaml(其他文件不动)
# 2. 开始一个任务(幂等:拉 issue → 档位裁决 → 开分支 + Draft MR → 打开所配执行器)
cairn start https://gitlab.com/group/project/-/issues/42
# 小任务走轻量流程(跳过规格阶段)
cairn start 42 --flow lite
# 3. 之后只需要一个命令:告诉你现在卡在哪、需要你做什么
cairn next # 或在 Claude Code 里 /cairn:next
# 4. 查看进度(阶段视图:规格 / 实现 / 评审 / 完成)
cairn statusnext 的输出只有三类:DECIDE(需要你批准/决策,给你看批准卡片)、WAIT(不需要你,在等 agent/CI/评审)、STUCK(出问题了,给你三个封闭选项)。完整使用说明见用户手册;架构全景见 docs/architecture.md。
命令
Porcelain(日常只需要这三个):
| 命令 | 说明 |
|------|------|
| cairn start <issue-url \| iid \| 名称> [--flow lite\|standard\|full] | 幂等入口:建任务(issue 拉取 + 档位裁决 + 分支 + Draft MR + 同名 spec change)或恢复会话 |
| cairn next | 唯一推进动词:跑门禁、自动流转,只在需要你的地方停下(DECIDE/WAIT/STUCK;--json/--approve/--retry --feedback/--abandon --reason) |
| cairn status [--verbose] [--json] | 阶段视图(规格/实现/评审/完成 + 档位);--verbose 看内部 state/门禁/批准/历史 + 下一步建议;--json 输出解释报告(为什么卡住) |
Plumbing(高级 / CI):
| 命令 | 说明 |
|------|------|
| cairn init [--executor <name>] [--force] | 初始化 cairn(选择执行器写入 config.yaml、创建 .cairn/、CLAUDE.md/AGENTS.md、hooks、斜杠命令;选 opencode 时另生成 .opencode/command/ + opencode.json,选 codex 时打印 ~/.codex/ 配置指引) |
| cairn task new <ref> | 创建任务(不开会话)——接受 GitLab issue URL、iid 或本地名称 |
| cairn gate --task <id> | 运行门禁(--gate <name> 单个,--approve <name> 手动通过人工门禁,--format json) |
| cairn advance --task <id> | 手动闸门:跑门禁并尝试推进(trigger: manual),成功后自动提交 cairn 产物并同步 GitLab |
| cairn escalate --task <id> --to <tier> | 档位升降(降档必须 --down --reason,留审计事件) |
| cairn run --task <id> | headless 编排循环:execute → gate → 失败回灌 → 重试,直到终态或卡在外部门禁 |
| cairn sync [--task <id>] | 刷新 issue 镜像 + label 漂移对账(本地状态是真相) |
| cairn verify --task <id> [--step] | 审计取证:链式 hash 校验 + 逐事件回放 + state.json 漂移检测 |
| cairn spec <new\|list\|status\|instructions\|apply-info\|validate\|archive> | 变更规格管理 |
| cairn flow check [--strict] [--profile <name>] [--target gitlab-dap] [--json] | 检查 flow 定义:图结构 / 门禁语义 / 路径预览 / target 兼容性诊断 |
| cairn flow guide | 输出当前版本的权威 agent 指引(markdown,随 CLI 升级) |
| cairn ui | 本地只读 Web 仪表盘(任务时间线 + 审计报告导出) |
| cairn mcp | stdio MCP server(刻意不含 advance——推进权在人) |
| cairn hook stop | Stop hook:跑确定性门禁,失败回灌给执行器(有限轮次) |
| cairn hook pre-tool-use | PreToolUse hook:拦截执行器对 .cairn/ 的写入 |
Claude Code 斜杠命令
cairn init 自动生成 .claude/commands/cairn/ 目录,在 Claude Code 中可直接使用:
| 命令 | 说明 | 底层 |
|------|------|------|
| /cairn:next | 唯一推进动词:呈现 DECIDE/WAIT/STUCK 决策卡片,按用户决定批准/打回/放弃 | CLI: cairn next --json |
| /cairn:start <ref> | 开始/恢复任务 | CLI: cairn start |
| /cairn:status | 状态仪表盘(状态 + 门禁 + 上下文) | MCP: cairn_status + cairn_context |
| /cairn:check [gate] | 运行门禁检查 | MCP: cairn_check_gate |
| /cairn:context | 获取当前状态的上下文包 | MCP: cairn_context |
| /cairn:advance | 推进状态机(先跑全部门禁) | CLI: cairn advance |
| /cairn:note <text> | 追加审计备注 | MCP: cairn_note |
| /cairn:issue <iid> | 拉取 GitLab issue 到本地上下文 | MCP: cairn_pull_issue |
| /cairn:task <ref> | 创建任务(GitLab issue URL/iid 或本地名称) | CLI: cairn task new |
| /cairn:sync | 刷新 issue 镜像 + label 漂移对账 | CLI: cairn sync |
| /cairn:verify | 验证审计事件链式 hash | CLI: cairn verify |
| /cairn:approve <gate> | 手动通过 human 门禁 | CLI: cairn gate --approve |
advance、task、approve等走 CLI 而不是 MCP——推进权和写操作保留在人手中。
两种运行模式
交互模式(cairn start)
开发者驱动。cairn 组装上下文、启动所配执行器的 TUI(claude / codex / opencode)。Claude Code 下门禁和审计经 hooks 实时强制;其余执行器由执行前后快照比对做补偿检测。会话退出后按执行器恢复 transcript(~/.claude/projects / ~/.codex/sessions / opencode SQLite),记 executed 事件(成本不可观测记 null)+ 规格产物变更记 artifact_produced 事件。
开发者 → cairn start → 组装上下文 → exec <executor TUI>
↓
Stop hook(claude)/ 事后快照比对(codex/opencode)
↓
确定性门禁 → 回灌编排模式(cairn run)
cairn 驱动。循环 headless 调用执行器(claude -p / codex exec --json / opencode run --format json),跑门禁,失败回灌,直到终态或卡在外部门禁(人工审批/MR/pipeline)。
cairn run → executor(headless)→ gate → pass? → advance → 继续
↓ fail
回灌 reasons → 重试(最多 max_retries 次)
↓ external gate
exit 2(等待人工/CI)多执行器
执行器在 cairn init 时选定(写入 config.yaml 的 executor:),也可 per-state 路由混用:
executor: claude-code
routing:
states:
implement: { executor: codex } # 实现交给 codex
judge: { executor: claude-code } # judge 独立路由(永不自评)| 能力 | claude-code | codex | opencode |
|------|-------------|-------|----------|
| headless / 结构化输出 | ✅ JSON | ✅ JSONL | ✅ --format json 事件流 |
| 会话恢复 | ✅ --session-id | ✅ exec resume | ✅ --session |
| judge output schema | ✅(探测 --json-schema) | ✅(--output-schema,自动补 additionalProperties:false) | prompt 内嵌 schema + 解析重试 |
| 权限/沙箱 | --permission-mode | -s 三档 sandbox | --agent plan(只读)/ --auto |
| .cairn/ 写保护 | PreToolUse hook 实时拦截 | 事后补偿检测 | 事后补偿检测 |
| 交互 transcript 恢复 | ✅ | ✅ | ✅ |
| 成本观测 | ✅ USD | 记 null(只报 token) | 记 null |
CLI flag 均运行时探测(缓存于 .cairn/.capabilities.json),版本漂移自动降级。其他任意 CLI(Gemini CLI、Aider…)经 config.yaml 的 executors: { <name>: { type: custom, run_cmd: "..." } } 接入,模板占位符:{prompt} {promptFile} {model} {cwd} {schemaFile} {permission} {allowedTools}。
状态机流程
flow.yaml(v2)按任务风险定义三档 flow profile,档位由 --flow 显式指定或从 issue label 推断(缺省 standard):
lite: implement → review → done # bug/文案/配置
standard: align → implement → review → done # 默认档
full: spec → plan → implement → review → archive → done # 涉敏/合规, 逐级审批每个状态绑定门禁,门禁全过才能转移(全绿且无人工门禁时自动流转)。implement 状态支持失败回灌和重试(按轮次计,最多 3 轮)。diff 触碰 tier_floor 声明的关键路径时强制升档;降档必须人显式发起且给理由。旧版 v1 flow.yaml 原样兼容(映射为 full 档)。
门禁类型
| 类型 | 判定方 | 例子 |
|------|--------|------|
| deterministic | shell 命令退出码 | build, test, lint, secrets |
| human | approved 事件(锚定产物 hash,批后改动自动失效) | alignment_approved |
| llm_judge | 独立 LLM 评判(rubric + diff → JSON 裁决,与写码 agent 分离路由) | spec_match |
| gitlab_mr | GitLab MR approval | mr_approved |
| gitlab_pipeline | GitLab pipeline 状态 | pipeline_green |
GitLab 集成
cairn start <iid/url>— 拉取 issue 内容,自动创建分支和 Draft MR- 状态转移 — 自动设置 phase 投影的 scoped label(
flow::spec/flow::impl/flow::review/flow::done;异常态flow::stuck/flow::awaiting-approval/flow::abandoned) - 进入评审 — 自动将 MR 标记为 Ready
- 审计锚点 — 转移事件的 chain hash 写入 issue note;停靠等批时批准卡片贴成 note
目录结构
.cairn/
config.yaml # 执行器 / 模型路由 / 档位规则(tier_inference / tier_floor)
flow.yaml # 状态机定义(v2: 三档 profile + 门禁 + phase 投影 + on_done)
context.md # per-state 注入上下文(生成物,gitignore)
rubrics/ # llm_judge 评分标准(含防注入条款)
transcripts/ # 会话 transcript 暂存(gitignore,随后归入 steps/)
tasks/<id>/
meta.json # 任务元数据(issue iid、branch、MR iid、tier)
state.json # 当前状态(事件折叠的派生缓存,gitignore)
events.jsonl # append-only 审计日志(链式 hash;merge=union;
# 人工批准即 approved 事件,锚定 artifact hash)
steps/<n>-<state>/ # 每步产物:prompt.md / diff.patch / gate-verdicts.json / transcript.jsonl
.claude/
commands/cairn/ # 斜杠命令(/cairn:status 等)
skills/cairn-flow/ # 薄 shim skill:指向 `cairn flow guide`(权威指引在 CLI 里)
settings.json # hooks 配置(Stop 门禁回灌 / PreToolUse 写入拦截)
.opencode/ # 选 opencode 执行器时由 init 生成
command/cairn-*.md # 自定义命令(/cairn-next 等,CLI 优先)
opencode.json # opencode 的 cairn MCP server 配置(.mcp.json 的等价物)Git 产物管理
cairn 产物(.cairn/、.claude/settings.json、specs/)在 advance 转移成功和 start 会话退出后自动提交,不需要手动提交两次。
gitignore(派生/临时文件):
.cairn/context.md— 每次会话重新生成.cairn/tasks/*/state.json— events.jsonl 的折叠缓存.cairn/tasks/*/.stop-hook.json— hook 临时状态.cairn/transcripts/— 会话原始 transcript
gitattributes:
events.jsonl merge=union— 并行分支合并时自动 union
退出码
| 码 | 含义 | |----|------| | 0 | 成功 | | 1 | 通用错误 | | 2 | 门禁阻塞(含外部门禁等待) | | 3 | 执行器错误 | | 4 | 预算超限 |
自定义门禁
编辑 .cairn/flow.yaml 中的 gates 部分(未列出的门禁用内置默认定义):
gates:
test: { type: deterministic, cmd: "npm test" }
lint: { type: deterministic, cmd: "npm run lint" }
build: { type: deterministic, cmd: "npm run build" }
alignment_approved: { type: human }
spec_match: { type: llm_judge, rubric: ".cairn/rubrics/spec_match.md" }
mr_approved: { type: gitlab_mr, min_approvals: 1 }
pipeline_green: { type: gitlab_pipeline }支持变量替换:$CHANGE(任务 ID)、$TASK_DIR(任务目录路径)、$STATE(当前状态)。
技术栈
TypeScript + Node.js, commander, execa, yaml
License
MIT
