一份 Markdown,
几条规则。
旅程地图是项目里的一份 Markdown 文件。agent 按这里的格式读写它,journey.sh 在写入前按这些规则检查。平时不需要手写,但知道它长什么样,更容易看懂每次修改。
文件与结构
每条旅程一个文件,放在项目的 .journey/ 目录里,文件名就是旅程的名字。通过脚本提交的修改,记在同名的 .log 文件里。
your-project/
└── .journey/
├── onboarding.md
└── onboarding.log文件按顺序分三部分:
- 前言:用两行 --- 包住的旅程信息。
- 里程碑:二级标题,按旅程顺序排列。
- 步骤:三级标题,写在所属里程碑下面。
一个完整的例子
---
journey: First-time onboarding
created: 2026-05-16
last-modified: 2026-05-16
personas:
- name: Sarah
role: Design manager, recently switched jobs
type: primary
- name: IT-Bot
role: Automated onboarding system
type: system
active-categories: [emotional, service-layers, failure]
custom-fields:
- team_urgency: "Internal priority rating (P0-P3)"
---
## Milestone: account-setup
- title: Account setup
- description: Sarah creates and configures her account for first use
### Step: discover-signup-page
- persona: [Sarah]
- description: Finds the signup link in the Slack welcome channel
- emotion: Cautious curiosity
- channel: Slack #welcome
- failureMode: Link expired or not posted
- recoveryPath: Asks a colleague to share the link
- team_urgency: P1
- next: → configure-workspace
### Step: configure-workspace
- persona: [Sarah, IT-Bot]
- description: Fills in the workspace settings form
- emotion: Frustrated
- _provenance: user-modified, 2026-05-18
- dropoffRate: 40%
- _provenance: source: analytics-2026-Q2
- exitPoint: true这个例子能通过 validate。
必填字段
下面这些字段每份文件都要有。必填字段写在最前面,空一行后再写可选字段。
| 字段 | 位置 | 记录什么 |
|---|---|---|
journey | 前言 | 旅程的名称。 |
created | 前言 | 创建日期,ISO 格式。 |
last-modified | 前言 | 最后修改日期。通过脚本提交时自动更新。 |
personas | 前言 | 参与者列表,每项包含 name、role 和 type。 |
## Milestone: <id> | 里程碑 | 标题行。id 用 kebab-case,在文件内唯一。 |
title / description | 里程碑 | 里程碑的名称和它涵盖的内容。 |
### Step: <id> | 步骤 | 标题行。id 用 kebab-case,在文件内唯一。 |
persona | 步骤 | 这一步有谁参与,写成数组。 |
description | 步骤 | 这一步发生了什么。 |
personas 的 type
| type | 含义 |
|---|---|
primary | 这条旅程的主角。 |
secondary | 其他参与的人。 |
system | 自动化系统或机器人。 |
backstage | 主角看不到的员工或团队。 |
前言里的可选字段
| 字段 | 可选 | 记录什么 |
|---|---|---|
structure | 是 | 层级说明,默认是 Journey > Milestone > Step。 |
active-categories | 是 | 只主动建议哪些字段类别。不写就是自然模式。 |
custom-fields | 是 | 自定义字段的登记表,每项带一句说明。 |
validate 会检查:前言的四个必填字段、每个步骤的 persona 和 description、id 是否为 kebab-case 且不重复、引用是否指向存在的步骤、字段名是否在 schema 里或已经登记。里程碑的 title 和 description 是格式要求,validate 不检查。
字段的写法
每个字段是一行列表项:短横线、字段名、冒号、值。
- emotion: Frustrated - persona: [Sarah, IT-Bot] - backstage: - system: IT-Bot - action: Serves the configuration form - painPoint: - "Didn't know what half the options meant" - "Page felt broken during cold start" - next: → configure-workspace - branchCondition: If configuration fails → abandon-setup
- 简单值直接写在冒号后面。
- 数组用方括号。
- 嵌套值和同一字段的多条内容,用缩进的子项。
- 用 → 加步骤 id 引用另一个步骤。指向不存在的步骤会被 validate 拒绝。
可选字段共 93 个,分 13 类,见字段参考。
组合字段
有三个字段是对一组原子字段的概括。概括和细节说的是同一件事,所以同一个概念只填一层。
| 组合字段 | 汇总自 |
|---|---|
frontstage | doing、frontstageAction、touchpoint、physicalEvidence |
backstage | backstageAction、backstageStaff、systems |
supportProcesses | supportProcess、dependencies、policy |
- 两层都有时,以原子字段为准,组合字段由它们重新生成,并标上 auto-composite。
- 只聊到概括层面时,可以只写组合字段。
- agent 不会要求你在两层之间转换。
- schema 里没有里程碑级的组合字段。跨步骤的总结要么写成步骤上的组合字段,要么登记成自定义字段。
- doing: Clicks through the configuration wizard - frontstageAction: System shows the settings form - frontstage: Sarah steps through the wizard; the system shows the settings form - _provenance: auto-composite
自定义字段
schema 里没有的概念,用带前缀的自定义字段记录,并登记在前言的 custom-fields 里。
| 前缀 | 用于 | 示例 |
|---|---|---|
team_ | 团队内部的概念 | team_urgency |
vertical_ | 行业特有的概念 | vertical_complianceTier |
experiment_ | 假设与实验 | experiment_variantId |
<自定>_ | 其他你自己定义的范围 | onboarding_nuxScore |
journey.sh commit onboarding register-field team_urgency "Internal priority rating (P0-P3)"
- agent 遇到新概念时,会先提议一个前缀,你确认后再登记。
- 未登记的带前缀字段,validate 会拒绝。
- 名字必须是 <前缀>_<名称> 的形式。没有前缀的名字,register-field 会拒绝登记,并建议一个带前缀的写法;validate 也会把它当作未知字段拒绝。
来源标记的四种状态
来源标记记录一个字段的值从哪来。它是例外,不是常态:大多数字段不带标记,只有依据和人工锁定才会写。
| 状态 | 写法 | 含义 |
|---|---|---|
| 模型生成 | (不写) | 默认状态。agent 根据对话写入,大多数字段都是这样,修改时可以直接更新。 |
| 人工修改 | _provenance: user-modified, <date> | 你改过这个值,或明确要求按原话锁定。之后 agent 不会不问就改它。 |
| 有来源 | _provenance: source: <ref> | 根据你作为依据提供的材料填写,例如访谈、数据或事故报告。 |
| 自动汇总 | _provenance: auto-composite | 由原子字段生成的组合字段。 |
- emotion: Frustrated
- _provenance: user-modified, 2026-05-18
- dropoffRate: 40%
- _provenance: source: analytics-2026-Q2
- backstage:
- system: IT-Bot
- action: Serves the configuration form
- _provenance: source: incident-report-2026-04- 标记写在它所标注的字段下一行,多缩进一级。缩进决定它属于哪个字段,嵌套字段也可以各带一个。
- 没有缩进的 _provenance 会被 validate 拒绝。
- 一个字段同一时间只有一种状态,以最新的为准。
- 建图时 agent 不会逐条解释它写了哪些标记;修改时会读取标记,表达时会把它们呈现出来。
类别激活
可选字段分 13 类。默认是自然模式:前言里不写 active-categories,agent 按对话内容从任何类别建议字段。
记录了三到五个步骤后,如果一直在用同几类字段,agent 会问你要不要只关注这些类别。你同意后,它把这些类别写进前言。
active-categories: [emotional, service-layers, failure, temporal]
你也可以一开始就指定。指定后,agent 优先从这些类别建议;其他类别的字段在你提到时照样可以写,只是不会被主动建议。
命令参考
journey.sh 是 skill 自带的 shell 脚本,只用 bash 和 awk。平时由 agent 调用,你也可以自己运行:在项目根目录执行,脚本路径指向安装好的 skill,例如:
bash ~/.claude/skills/journey/scripts/journey.sh validate onboarding
下表省略了 journey.sh 前缀。
| 命令 | 作用 | 说明 |
|---|---|---|
validate <journey> | 检查一条旅程 | 通过时输出 OK 和步骤、里程碑数量;不通过时逐条列出 ERROR 和行号。 |
new <journey> --block-file <file> | 新建旅程 | agent 写好整份文件,也可以从 stdin 读入。先校验再写入,并记一条 create。同名旅程已存在时拒绝。 |
query <filter> | 按条件找步骤 | 在 .journey/ 里的所有旅程中查找。每行一个结果:旅程、步骤 id、原因。 |
search <text> | 全文搜索 | 不区分大小写。输出旅程、步骤、行号和那一行的内容。 |
audit [--journey X] [--since DATE] [--author A] [--target T] | 查看修改记录 | 按时间排序,同一秒内的记录保持写入顺序。 |
whoami | 查看修改署谁的名 | 依次取:set-author 保存的名字、git 的 user.name、系统用户名。来源是 fallback 时,agent 会问你一次该署什么名。 |
set-author <name> | 保存署名 | 存在你自己的配置目录里(默认 ~/.config/journey-skill/author),不会写进旅程文件。 |
theme <file.html> … | 给 HTML 输出配色 | 见「模板与主题」。 |
commit 的操作
写法是 journey.sh commit <journey> <操作> [参数]。插入和替换用的块从 --block-file 或 stdin 读入。
| 操作 | 作用 | 说明 |
|---|---|---|
insert-step --after <id> | 插入一个步骤 | 也可以用 --before。块以 ### Step: <id> 开头,id 不能和已有步骤重复。 |
replace-step <id> | 替换一个步骤 | 值没变的顶层字段会保留原来的来源标记。 |
remove-step <id> | 删除一个步骤 | 如果还有别的步骤引用它,删除后的文件不合规,会被拒绝。先改引用。 |
insert-milestone --after <id> | 插入一个里程碑 | 也可以用 --before,锚点是里程碑 id。块以 ## Milestone: <id> 开头,id 不能和已有里程碑重复。 |
remove-milestone <id> | 删除一个里程碑 | 连同它下面的所有步骤一起删除。 |
register-field <scope>_<name> "<description>" | 登记自定义字段 | 写进前言的 custom-fields。名字必须带前缀。 |
每个 commit 都可以带 --note "<原因>" 和 --author "<名字>"。写入前会更新 last-modified 并校验整份文件;不通过就什么都不写。通过后记一条修改记录。
query 的过滤条件
| 过滤条件 | 找出 |
|---|---|
failure-no-recovery | 有 failureMode 但没有 recoveryPath 的步骤。 |
moment-no-evidence | 有 momentOfTruth,但它没有 source 标记,步骤上也没有 metric、kpi 或 dropoffRate。 |
user-modified | 带人工修改标记的步骤。 |
persona:<name> | persona 里包含这个角色的步骤。 |
field:<name> | 有这个字段的步骤。 |
missing:<name> | 缺这个字段的步骤。 |
修改记录
每条旅程旁边有一个同名的 .log 文件,每行一次修改,用制表符分隔:时间(UTC)、作者、旅程、操作、目标、备注。只有脚本会写它。
2026-10-19T01:07:52Z 林 meeting-room insert-step check-in 行政:加签到,防止有人占着不用 2026-10-19T01:07:52Z 林 meeting-room remove-step check-in 撤回:签到没有证据;空占来自预订本身(leave-room)
环境变量
| 环境变量 | 默认值 | 用途 |
|---|---|---|
JOURNEY_DIR | ./.journey | 旅程文件和修改记录所在的目录。 |
JOURNEY_SCHEMA | skill 自带的 references/journey.schema.md | 校验用的字段表。 |
JOURNEY_AUTHOR_FILE | ~/.config/journey-skill/author | set-author 保存署名的位置。 |
已知限制
- 只支持一个人写入。没有文件锁,两个 commit 同时改同一条旅程,可能丢掉其中一次修改。
- commit 不会自动改写 next。增删步骤后,前后步骤的引用由 agent 在块里写好;指向不存在步骤的引用会被 validate 拦下。
- replace-step 只为值没变的顶层字段保留来源标记。嵌套字段的标记要由 agent 随块重写。
- 直接手改文件不经过校验,也不会留下修改记录。改完可以运行一次 validate。
- query 和 search 每次实时读取文件,没有索引。
- 没有 render 命令。HTML 由 agent 生成,theme 只负责配色。
- 脚本只处理本地文件。Notion 和 Drive 通过各自的 MCP 读写;没有存储时,agent 在对话里输出完整文件,由你保存。