@zyaiting/keelson 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +15 -12
  2. package/README_CN.md +15 -12
  3. package/hooks/codebuddy-session.mjs +13 -28
  4. package/hooks/codex-session.mjs +16 -0
  5. package/hooks/prompt-state.mjs +5 -29
  6. package/hooks/session-start.mjs +7 -0
  7. package/hooks/workflow-guard.mjs +95 -0
  8. package/package.json +1 -1
  9. package/registry/platforms.json +4 -4
  10. package/registry/runtime-hashes.json +41 -0
  11. package/skills/keelson/SKILL.md +6 -3
  12. package/skills/keelson/references/build.md +12 -0
  13. package/skills/keelson/references/discover.md +5 -3
  14. package/skills/keelson/references/frontend.md +1 -1
  15. package/skills/keelson/references/interview.md +26 -7
  16. package/skills/keelson/references/land.md +2 -0
  17. package/skills/keelson/references/shape.md +3 -3
  18. package/skills/keelson/references/verify.md +1 -1
  19. package/skills/keelson/templates/resident-block.md +1 -1
  20. package/skills/keelson/templates/workflow.md +3 -3
  21. package/skills/zh/keelson/SKILL.md +6 -3
  22. package/skills/zh/keelson/references/build.md +12 -0
  23. package/skills/zh/keelson/references/discover.md +5 -3
  24. package/skills/zh/keelson/references/frontend.md +1 -1
  25. package/skills/zh/keelson/references/interview.md +26 -7
  26. package/skills/zh/keelson/references/land.md +2 -0
  27. package/skills/zh/keelson/references/shape.md +3 -3
  28. package/skills/zh/keelson/references/verify.md +2 -0
  29. package/skills/zh/keelson/templates/resident-block.md +1 -1
  30. package/skills/zh/keelson/templates/workflow.md +3 -3
  31. package/src/cli.js +4 -3
  32. package/src/commands/ablate.js +2 -1
  33. package/src/commands/ask.js +4 -1
  34. package/src/commands/context.js +7 -0
  35. package/src/commands/doctor.js +3 -1
  36. package/src/commands/hook.js +6 -1
  37. package/src/commands/init.js +12 -7
  38. package/src/commands/new.js +1 -1
  39. package/src/commands/platforms.js +1 -1
  40. package/src/commands/start.js +33 -0
  41. package/src/commands/uninstall.js +1 -1
  42. package/src/lib/decisions.js +3 -1
  43. package/src/lib/hook-context.js +30 -0
  44. package/src/lib/markdown.js +1 -1
  45. package/src/lib/rules.js +10 -2
  46. package/src/lib/workflow.js +102 -0
  47. package/src/platforms/integration.js +75 -93
  48. package/src/platforms/runtime.js +68 -17
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center"><img src="https://raw.githubusercontent.com/Atingaii/keelson/main/docs/assets/keelson-banner.png" alt="Keelson" width="620"></p>
2
2
 
3
- <p align="center"><strong>Start with a conversation. Leave work the next session can build on.</strong></p>
3
+ <p align="center"><strong>Clarify the goal. Build to the contract. Keep what you learn.</strong></p>
4
4
  <p align="center">Project memory, engineering guidance, and acceptance checks for your coding agent. Describe the outcome; keep decisions and verification alongside the code.</p>
5
5
 
6
6
  <p align="center">
@@ -16,16 +16,13 @@
16
16
  <a href="https://github.com/Atingaii/keelson/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT license"></a>
17
17
  </p>
18
18
 
19
- <p align="center"><img src="https://raw.githubusercontent.com/Atingaii/keelson/main/docs/assets/keelson-demo.gif" alt="Real agent conversation replay: a task-filter request followed by implementation, verification, and archiving" width="100%"></p>
20
- <p align="center"><sub>Initialized example repository · Translated excerpts from a real session, with waits shortened · Just describe the task</sub></p>
21
-
22
19
  ## Why Keelson?
23
20
 
24
21
  Keelson brings software engineering practices into everyday agent conversations: agree on the outcome, preserve the reasoning, and check the result. It addresses four recurring problems.
25
22
 
26
23
  **1. The agent builds the wrong thing.**
27
24
 
28
- “Add a filter” leaves room for different defaults, edge cases, and compatibility choices. Keelson guides the agent to inspect the code and turn the request into concrete acceptance examples before implementation. This applies **behaviour-driven development**: use examples to expose disagreement early, asking only about choices that affect the direction.
25
+ “Add a filter” leaves room for different defaults, edge cases, and compatibility choices. Keelson guides the agent to inspect the code, automatically investigate unclear goals and connected decisions, then turn the request into concrete acceptance examples before implementation. This applies **behaviour-driven development**: use examples to expose disagreement early, asking only about choices that affect the direction.
29
26
 
30
27
  **2. Every session needs the same explanation.**
31
28
 
@@ -47,7 +44,7 @@ Keelson combines an **Agent Skill + local CLI**. The skill guides the agent's wo
47
44
  - A coding agent that can read project files, make changes, and run commands.
48
45
  - A local project directory; Git is recommended for tracking code and project knowledge.
49
46
 
50
- Keelson generates integrations for Codex, Claude Code, OpenCode, Gemini CLI, and other hosts. See [Agent support](https://github.com/Atingaii/keelson/blob/main/docs/platforms.md) for capabilities and validation coverage.
47
+ Claude Code, Codex CLI and CodeBuddy CLI are the primary supported hosts. Keelson also generates integrations for other coding agents. See [Agent support](https://github.com/Atingaii/keelson/blob/main/docs/platforms.md) for capabilities and validation coverage.
51
48
 
52
49
  ## Quick start
53
50
 
@@ -57,24 +54,30 @@ Keelson generates integrations for Codex, Claude Code, OpenCode, Gemini CLI, and
57
54
  npm install -g @zyaiting/keelson
58
55
  ```
59
56
 
60
- **2. Initialize your project**, using Codex here:
57
+ **2. Initialize your project**, selecting your CLI:
61
58
 
62
59
  ```bash
63
60
  cd /path/to/your/project
64
- keelson init --codex
61
+ keelson init --claude # Claude Code
62
+ # or: keelson init --codex
63
+ # or: keelson init --codebuddy
65
64
  ```
66
65
 
67
66
  **3. Open your agent in that directory and describe the task.** Initialize once, then keep working through conversation.
68
67
 
69
- > Add a priority filter to the task list: show everything by default, with an option for high-priority tasks only. Keep existing calls compatible, add tests, and verify the result.
68
+ > Add a priority filter to the task list.
70
69
 
71
70
  To upgrade, run `npm install -g @zyaiting/keelson@latest`, then `keelson update` in your project. See the [setup guide](https://github.com/Atingaii/keelson/blob/main/docs/getting-started.md) and [supported agents](https://github.com/Atingaii/keelson/blob/main/docs/platforms.md).
72
71
 
73
72
  ## From request to completion
74
73
 
75
- **UnderstandScope → Implement and verifyArchive and resume**
74
+ **InvestigateDecide → Implement Independently review Verify Preserve knowledge**
75
+
76
+ After initialization, ordinary requests trigger the relevant workflow automatically: investigate requirements, clarify material choices with recommendations, apply engineering and UI/UX guidance, implement, verify, and preserve the result for later sessions. You do not need to name a skill or manage workflow commands. Clear edits use a minimal change record. A simple gap gets one question; connected uncertainties get the whole ready decision frontier, with recommendations and reasons for each choice. The agent resumes authorized work once those choices are settled.
77
+
78
+ Before implementation, the agent starts the settled change and loads its declared specs and rules. Review gets a separate context pack built from the request and contracts. Verified changes promote durable decisions into project specs, so later work starts with what the project has learned.
76
79
 
77
- The agent loads relevant guidance, maintains acceptance criteria, and runs project checks. It wraps up when the gates pass, asking for your input when a choice changes the plan. Small edits stay lightweight.
80
+ Claude Code, Codex and CodeBuddy integrations restore workflow context and gate supported file edits. Codex requires the generated hooks to be trusted in `/hooks` when prompted; other host permissions remain in effect. Disabled hooks fall back to installed guidance and the shared CLI. See [automation and its boundaries](https://github.com/Atingaii/keelson/blob/main/docs/automation.md).
78
81
 
79
82
  You can also ask:
80
83
 
@@ -82,7 +85,7 @@ You can also ask:
82
85
  - **Improve an interface:** “Polish the settings page, keep our brand, preserve input when saving fails, and check the mobile flow.”
83
86
  - **Resume:** “Continue the previous change. First check what's left.”
84
87
 
85
- Frontend work has 22 composable [design actions](https://github.com/Atingaii/keelson/blob/main/docs/frontend.md), discoverable with `keelson design`, including critique, simplification, polish, and adaptation. Checking the actual interface requires the agent to use a browser.
88
+ The agent automatically selects from 22 composable [design actions](https://github.com/Atingaii/keelson/blob/main/docs/frontend.md), discoverable with `keelson design`, including critique, simplification, polish, and adaptation when the work affects an interface. Checking the actual interface requires the agent to use a browser.
86
89
 
87
90
  ## What stays in your project?
88
91
 
package/README_CN.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center"><img src="https://raw.githubusercontent.com/Atingaii/keelson/main/docs/assets/keelson-banner.png" alt="Keelson" width="620"></p>
2
2
 
3
- <p align="center"><strong>在仓库里对话,让每次开发都有据可循、有处接续。</strong></p>
3
+ <p align="center"><strong>让 Agent 先想清楚,再按规范做完,把经验留在仓库。</strong></p>
4
4
  <p align="center">为编码 Agent 提供项目记忆、工程方法和验收流程。你描述目标,Agent 推进实现,把决策与验证留在代码旁。</p>
5
5
 
6
6
  <p align="center">
@@ -16,16 +16,13 @@
16
16
  <a href="https://github.com/Atingaii/keelson/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT license"></a>
17
17
  </p>
18
18
 
19
- <p align="center"><img src="https://raw.githubusercontent.com/Atingaii/keelson/main/docs/assets/keelson-demo-zh.gif" alt="真实 Agent 对话回放:用户提出任务筛选需求,Agent 完成实现、验证与归档" width="100%"></p>
20
- <p align="center"><sub>已初始化的示例仓库 · 真实会话节选,等待已压缩 · 用户只需提出需求</sub></p>
21
-
22
19
  ## 为什么选择 Keelson?
23
20
 
24
21
  Keelson 将软件工程中的成熟做法带进日常 Agent 对话:先对齐结果,留下决策依据,再检查实际产出。它围绕四个常见问题展开。
25
22
 
26
23
  **1. Agent 做出来的,并不是你想要的。**
27
24
 
28
- “加个筛选”背后,还有默认行为、边界情况和兼容性。Keelson 引导 Agent 先读代码,把需求变成具体的验收示例,再开始实现。这借鉴了**行为驱动开发(BDD)**:通过例子尽早发现理解偏差,只对影响方向的选择提问。
25
+ “加个筛选”背后,还有默认行为、边界情况和兼容性。Keelson 引导 Agent 先读代码,自动调查模糊目标和相互关联的选择,把需求变成具体的验收示例,再开始实现。这借鉴了**行为驱动开发(BDD)**:通过例子尽早发现理解偏差,只对影响方向的选择提问。
29
26
 
30
27
  **2. 换个会话,又得解释同一个项目。**
31
28
 
@@ -47,7 +44,7 @@ Keelson 由 **Agent Skill + 本地 CLI** 组成:Skill 指导 Agent 如何工
47
44
  - 一个能读取项目、修改文件并执行命令的编码 Agent。
48
45
  - 一个本地项目目录;建议使用 Git 管理代码和项目知识。
49
46
 
50
- 支持生成 Codex、Claude Code、OpenCode、Gemini CLI 等宿主的集成入口;各宿主的能力与验证范围见 [Agent 支持](https://github.com/Atingaii/keelson/blob/main/docs/platforms.md)。
47
+ 重点适配 **Claude Code、Codex CLI CodeBuddy CLI**,也支持其他编码 Agent 的集成入口;各宿主的能力与验证范围见 [Agent 支持](https://github.com/Atingaii/keelson/blob/main/docs/platforms.md)。
51
48
 
52
49
  ## 快速开始
53
50
 
@@ -57,24 +54,30 @@ Keelson 由 **Agent Skill + 本地 CLI** 组成:Skill 指导 Agent 如何工
57
54
  npm install -g @zyaiting/keelson
58
55
  ```
59
56
 
60
- **2. 在你的项目中初始化**,以 Codex 为例:
57
+ **2. 在你的项目中初始化**,选择使用的 CLI:
61
58
 
62
59
  ```bash
63
60
  cd /path/to/your/project
64
- keelson init --codex --lang zh
61
+ keelson init --claude --lang zh # Claude Code
62
+ # 或:keelson init --codex --lang zh
63
+ # 或:keelson init --codebuddy --lang zh
65
64
  ```
66
65
 
67
66
  **3. 在这个目录启动 Agent,直接提出需求。** 初始化只需一次;后续正常对话即可。
68
67
 
69
- > 给任务列表加一个优先级筛选:默认显示全部,也能只看高优先级。保持现有调用兼容,补齐测试并完成验证。
68
+ > 给任务列表加一个优先级筛选。
70
69
 
71
70
  升级 CLI:`npm install -g @zyaiting/keelson@latest`,然后在项目中运行 `keelson update`。更多设置见[上手教程](https://github.com/Atingaii/keelson/blob/main/docs/zh/getting-started.md);其他宿主见 [Agent 支持](https://github.com/Atingaii/keelson/blob/main/docs/platforms.md)。
72
71
 
73
72
  ## 从一句需求到一次完成
74
73
 
75
- **理解目标明确范围实现与验证归档与接续**
74
+ **调查决策实现独立复核 → 验证 → 知识回写**
75
+
76
+ 初始化后,普通需求自动触发相应流程:调查需求、带着推荐澄清关键选择、应用工程与 UI/UX 指导、实现、验证,并保留结果供后续会话接续。你无需点名 Skill 或管理工作流命令。明确的小修改使用最小变更记录;简单缺口一次问一个,复杂问题一轮问完前提已明确的整组决定,每题给推荐与理由。决定明确后继续已授权的工作。
77
+
78
+ 实现前,Agent 自动启动已澄清的变更,加载声明的规范与规则;复核使用从原始需求和契约生成的独立上下文包。验收后,持久决策回写到项目规范,下次开发继续使用这些知识。
76
79
 
77
- Agent 按任务读取需要的指导,维护验收标准并执行项目检查;条件满足后自动收尾。遇到影响方案的选择时再与你确认,普通小修改保持轻量。
80
+ Claude Code、Codex 和 CodeBuddy 集成均支持恢复流程上下文,并对受支持的文件修改执行启动门禁。Codex 首次提示时需在 `/hooks` 中信任生成的 hooks;各宿主原有权限确认继续生效。禁用 hooks 时,由已安装指导驱动相同 CLI。详见[自动化机制与边界](https://github.com/Atingaii/keelson/blob/main/docs/zh/automation.md)。
78
81
 
79
82
  你也可以这样说:
80
83
 
@@ -82,7 +85,7 @@ Agent 按任务读取需要的指导,维护验收标准并执行项目检查
82
85
  - **改善界面:**“优化设置页,保留品牌风格,保存失败时不要丢输入,并检查手机端体验。”
83
86
  - **接着开发:**“继续上次的改动,先确认还剩什么。”
84
87
 
85
- 前端任务有 22 个可组合的[设计动作](https://github.com/Atingaii/keelson/blob/main/docs/zh/frontend.md),可通过 `keelson design` 查看,包括审视、简化、打磨和适配。实际界面效果需要 Agent 使用浏览器检查。
88
+ 涉及界面的任务中,Agent 会从 22 个可组合的[设计动作](https://github.com/Atingaii/keelson/blob/main/docs/zh/frontend.md)中按需选择,包括审视、简化、打磨和适配;可通过 `keelson design` 查看。实际界面效果需要 Agent 使用浏览器检查。
86
89
 
87
90
  ## 项目里会留下什么?
88
91
 
@@ -1,16 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  // CodeBuddy session bridge for Keelson.
3
- // SessionStart/UserPromptSubmit: touch local session runtime and inject a tiny focus hint.
3
+ // SessionStart/UserPromptSubmit: restore workflow and declared project contracts.
4
4
  // PreToolUse(Bash|PowerShell): deterministically prepend KEELSON_SESSION_ID to the command.
5
5
  // Raw CodeBuddy session ids are never written to disk.
6
- import crypto from 'node:crypto';
7
6
  import fs from 'node:fs';
8
- import path from 'node:path';
9
- import { runtimeDir } from '../src/lib/runtime-path.js';
7
+ import { findProjectRoot } from '../src/lib/paths.js';
8
+ import { hookEnvironment, sessionContext } from '../src/lib/hook-context.js';
9
+ import { writeSession } from '../src/lib/session.js';
10
10
 
11
- const hash = (value, n) => crypto.createHash('sha256').update(String(value)).digest('hex').slice(0, n);
12
- const readJson = (p) => { try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return null; } };
13
- const writeJson = (p, v) => { fs.mkdirSync(path.dirname(p), { recursive: true }); fs.writeFileSync(p, JSON.stringify(v, null, 2) + '\n'); };
14
11
  const shellQuote = (v) => `'${String(v).replace(/'/g, "'\\''")}'`;
15
12
 
16
13
  let input = {};
@@ -19,17 +16,13 @@ try {
19
16
  if (raw.trim()) input = JSON.parse(raw);
20
17
  } catch {}
21
18
 
22
- const root = input.cwd || process.env.CODEBUDDY_PROJECT_DIR || process.cwd();
19
+ const root = findProjectRoot(process.env.CODEBUDDY_PROJECT_DIR || input.cwd || process.cwd());
23
20
  const sessionId = typeof input.session_id === 'string' ? input.session_id.trim() : '';
24
- if (!sessionId || !fs.existsSync(path.join(root, '.keelson'))) process.exit(0);
21
+ if (!sessionId || !root) process.exit(0);
25
22
 
26
- const opaque = hash(`codebuddy:${sessionId}`, 32);
27
- const key = hash(opaque, 24);
28
- const sessionFile = path.join(runtimeDir(root), 'sessions', `${key}.json`);
29
- const session = readJson(sessionFile) || { schema: 1, change: null, createdAt: new Date().toISOString() };
30
- session.updatedAt = new Date().toISOString();
31
- session.source = 'codebuddy';
32
- writeJson(sessionFile, session);
23
+ const env = hookEnvironment('codebuddy', input);
24
+ const opaque = env.KEELSON_SESSION_ID;
25
+ writeSession(root, { source: 'codebuddy' }, env);
33
26
 
34
27
  const event = input.hook_event_name || '';
35
28
  if (event === 'PreToolUse' && ['bash', 'powershell'].includes(String(input.tool_name || '').toLowerCase())) {
@@ -44,8 +37,6 @@ if (event === 'PreToolUse' && ['bash', 'powershell'].includes(String(input.tool_
44
37
  continue: true,
45
38
  hookSpecificOutput: {
46
39
  hookEventName: 'PreToolUse',
47
- permissionDecision: 'allow',
48
- permissionDecisionReason: 'Keelson attached the opaque session identity used only for local work-focus routing.',
49
40
  modifiedInput: {
50
41
  ...input.tool_input,
51
42
  command: injected,
@@ -55,13 +46,7 @@ if (event === 'PreToolUse' && ['bash', 'powershell'].includes(String(input.tool_
55
46
  process.exit(0);
56
47
  }
57
48
 
58
- const changesDir = path.join(root, '.keelson', 'changes');
59
- const active = fs.existsSync(changesDir)
60
- ? fs.readdirSync(changesDir, { withFileTypes: true })
61
- .filter((d) => d.isDirectory() && d.name !== 'archive' && fs.existsSync(path.join(changesDir, d.name, 'change.md')))
62
- .map((d) => d.name)
63
- : [];
64
- const focused = session.change && active.includes(session.change) ? session.change : null;
65
- if (focused) process.stdout.write(`[keelson] session focus: ${focused}; use the existing change unless the user requests an independent outcome.\n`);
66
- else if (active.length === 1) process.stdout.write(`[keelson] resume candidate: ${active[0]}; bind only if this prompt continues that work.\n`);
67
- else if (active.length > 1) process.stdout.write(`[keelson] active changes: ${active.join(', ')}; no session focus, so do not guess.\n`);
49
+ if (['SessionStart', 'UserPromptSubmit'].includes(event)) {
50
+ try { process.stdout.write(sessionContext(root, env, event, 'codebuddy') + '\n'); }
51
+ catch (error) { process.stdout.write(`[keelson] Context restoration needs attention: ${error.message}\n`); }
52
+ }
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import { findProjectRoot } from '../src/lib/paths.js';
4
+ import { hookEnvironment, sessionContext } from '../src/lib/hook-context.js';
5
+
6
+ let input = {};
7
+ try { input = JSON.parse(fs.readFileSync(0, 'utf8')); } catch { process.exit(0); }
8
+ const root = findProjectRoot(input.cwd || process.cwd());
9
+ if (!root) process.exit(0);
10
+ const event = input.hook_event_name || 'SessionStart';
11
+ try {
12
+ const context = sessionContext(root, hookEnvironment('codex', input), event, 'codex');
13
+ process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: event, additionalContext: context } }) + '\n');
14
+ } catch (error) {
15
+ process.stdout.write(`[keelson] Context restoration needs attention: ${error.message}\n`);
16
+ }
@@ -5,10 +5,10 @@ import crypto from 'node:crypto';
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
7
  import { runtimeDir } from '../src/lib/runtime-path.js';
8
+ import { workflowHint } from '../src/lib/workflow.js';
8
9
 
9
10
  const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
10
11
  const k = path.join(root, '.keelson');
11
- const changesDir = path.join(k, 'changes');
12
12
  if (!fs.existsSync(k)) process.exit(0);
13
13
 
14
14
  const read = (p) => (fs.existsSync(p) ? fs.readFileSync(p, 'utf8').replace(/\r\n?/g, '\n') : '');
@@ -35,32 +35,8 @@ if (sessionPath) {
35
35
  session.source = 'claude-prompt';
36
36
  writeJson(sessionPath, session);
37
37
  }
38
- if (!fs.existsSync(changesDir)) process.exit(0);
39
-
40
- const summarize = (name) => {
41
- const dir = path.join(changesDir, name);
42
- const change = read(path.join(dir, 'change.md'));
43
- if (!change) return null;
44
- const tasks = read(path.join(dir, 'tasks.md'));
45
- const total = (tasks.match(/^\s*[-*]\s+\[[ xX]\]/gm) || []).length;
46
- const done = (tasks.match(/^\s*[-*]\s+\[[xX]\]/gm) || []).length;
47
- const ledger = read(path.join(dir, 'ledger.md'));
48
- const verifies = [...ledger.matchAll(/^###\s+Verify:[\s\S]*?exit\s*(?:code)?\s*[:=]?\s*(\d+)/gim)];
49
- const lastExit = verifies.length ? Number(verifies.at(-1)[1]) : null;
50
- const explicit = (change.match(/^status:\s*([\w-]+)/m) || [])[1];
51
- const verify = verifies.length ? (lastExit === 0 ? 'passed' : 'failed') : 'not-run';
52
- const open = (change.match(/^##\s+Open questions?\s*\n([\s\S]*?)(?=^##\s|(?![\s\S]))/im) || [])[1] || '';
53
- const openCount = (open.match(/^\s*[-*]\s+(?!…|none)/gim) || []).length;
54
- return `${name} · ${explicit || (total ? (done < total ? 'in-progress' : 'awaiting verification') : 'in-progress')} · verify ${verify}${total ? ` · ${done}/${total} tasks` : ''}${openCount ? ` · ${openCount} open` : ''}`;
55
- };
56
-
57
- if (session?.change) {
58
- const line = summarize(session.change);
59
- if (line) process.stdout.write(`[keelson] focus: ${line}\n`);
60
- process.exit(0);
38
+ try {
39
+ process.stdout.write(workflowHint(root, { ...process.env, ...(envIdentity ? { KEELSON_SESSION_ID: envIdentity } : {}) }) + '\n');
40
+ } catch (error) {
41
+ process.stdout.write(`[keelson] Cannot restore workflow: ${error.message}. Run keelson doctor before implementation.\n`);
61
42
  }
62
-
63
- const names = fs.readdirSync(changesDir, { withFileTypes: true })
64
- .filter((d) => d.isDirectory() && d.name !== 'archive' && fs.existsSync(path.join(changesDir, d.name, 'change.md')))
65
- .map((d) => d.name);
66
- if (names.length === 1) process.stdout.write(`[keelson] resume candidate: ${summarize(names[0])}; bind only if this prompt continues that work\n`);
@@ -5,6 +5,7 @@ import crypto from 'node:crypto';
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
7
  import { runtimeDir } from '../src/lib/runtime-path.js';
8
+ import { activeWorkflow, phaseContext, renderPhaseContext, workflowHint } from '../src/lib/workflow.js';
8
9
 
9
10
  const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
10
11
  const k = path.join(root, '.keelson');
@@ -57,6 +58,7 @@ if (sessionPath) {
57
58
  session = readJson(sessionPath) || { schema: 1, change: null, createdAt: new Date().toISOString() };
58
59
  session.updatedAt = new Date().toISOString();
59
60
  session.source = 'claude-session-start';
61
+ session.injectedContexts = []; // compact/resume must restore previously injected constraints.
60
62
  writeJson(sessionPath, session);
61
63
  }
62
64
 
@@ -91,4 +93,9 @@ if (ordered.length) {
91
93
  lines.push('', '--- Active work ---');
92
94
  for (const c of ordered.slice(0, 6)) lines.push(`${c.name}${c.name === focused ? ' [focus]' : ''}: ${c.tier}${c.status ? `, ${c.status}` : ''}${c.total ? `, ${c.done}/${c.total} tasks` : ''}${c.owner ? `, ${c.owner}` : ''}`);
93
95
  }
96
+ try {
97
+ const env = { ...process.env, ...(envIdentity ? { KEELSON_SESSION_ID: envIdentity } : {}) };
98
+ lines.push('', workflowHint(root, env));
99
+ if (focused) lines.push(renderPhaseContext(phaseContext(root, activeWorkflow(root, focused, env))));
100
+ } catch (error) { lines.push(`[keelson] Context restoration needs attention: ${error.message}`); }
94
101
  process.stdout.write(lines.join('\n') + '\n');
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ // Host-specific file-tool gates and phase context injection. Shell/MCP writers
3
+ // remain host-policy territory; this is a workflow guard, not a sandbox.
4
+ import crypto from 'node:crypto';
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { findProjectRoot } from '../src/lib/paths.js';
8
+ import { hookEnvironment } from '../src/lib/hook-context.js';
9
+ import { readSession, writeSession } from '../src/lib/session.js';
10
+ import { activeWorkflow, implementationBlockers, phaseContext, renderPhaseContext } from '../src/lib/workflow.js';
11
+
12
+ let input = {};
13
+ try { input = JSON.parse(fs.readFileSync(0, 'utf8')); } catch { process.exit(2); }
14
+ const host = process.argv[2] || 'claude';
15
+ const projectDir = host === 'claude' ? process.env.CLAUDE_PROJECT_DIR : host === 'codebuddy' ? process.env.CODEBUDDY_PROJECT_DIR : null;
16
+ const root = findProjectRoot(projectDir || input.cwd || process.cwd());
17
+ if (!root) process.exit(0);
18
+ const env = hookEnvironment(host, input);
19
+ const event = input.hook_event_name || 'PreToolUse';
20
+ const tool = input.tool_name;
21
+ const output = (fields) => process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: event, ...fields } }) + '\n');
22
+
23
+ try {
24
+ const session = readSession(root, env);
25
+ const name = session.state?.change;
26
+ if (host === 'codex' && event === 'SubagentStart' && !name) {
27
+ // session_id is the root, not necessarily the spawning parent. Let the
28
+ // assigned task name its change rather than inheriting an unrelated focus.
29
+ output({ additionalContext: '[keelson] Preserve your assigned scope, including read-only work. If your task includes KEELSON_CHANGE=<name>, run `keelson focus <name>`, then `keelson context --phase check` for review or `--phase implement` for implementation before doing that work. Do not infer a task from the root session or sole repository candidate. Without a marker, keep discovery read-only; create or select a change only when the task explicitly requires implementation. These commands do not grant permission to edit.' });
30
+ process.exit(0);
31
+ }
32
+ const workflow = activeWorkflow(root, name, env);
33
+ // Never infer an unrelated session's change from the sole repository candidate.
34
+ if (!name) workflow.change = null;
35
+ const args = input.tool_input ?? {};
36
+ const file = args.file_path ?? args.notebook_path;
37
+ const patch = host === 'codex' && tool === 'apply_patch';
38
+ const editing = patch || ['Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'NotebookWrite'].includes(tool);
39
+ const files = patch
40
+ ? [...String(args.command ?? '').matchAll(/^\*\*\* (?:Add File|Update File|Delete File|Move to): (.+)\r?$/gm)].map((m) => m[1].trim())
41
+ : typeof file === 'string' ? [file] : [];
42
+ const relative = files.map((f) => path.relative(root, path.resolve(input.cwd || root, f)).replace(/\\/g, '/'));
43
+ const planningOnly = relative.length > 0 && relative.every((f) => f.startsWith('.keelson/') && !f.split('/').includes('..'));
44
+ if (editing && !planningOnly) {
45
+ const blockers = implementationBlockers(workflow.change, workflow.changes);
46
+ if (blockers.length) {
47
+ output({ permissionDecision: 'deny', permissionDecisionReason: blockers.join(' ') + ' The agent should resolve this within existing authorization; do not ask the user to run workflow commands.' });
48
+ process.exit(0);
49
+ }
50
+ }
51
+ if (editing && planningOnly) process.exit(0);
52
+ if (!workflow.change) process.exit(0);
53
+ if (host === 'codex' && ['spawn_agent', 'Agent', 'Task'].includes(tool)) {
54
+ const markers = [...String(args.message ?? args.prompt ?? '').matchAll(/^\s*KEELSON_CHANGE=([^\s]+)[ \t]*$/gm)];
55
+ if (markers.length !== 1 || markers[0][1] !== name) {
56
+ output({ permissionDecision: 'deny', permissionDecisionReason: `Add the single line KEELSON_CHANGE=${name} to this child task so its own CLI session can bind the assigned change. Keep its phase, original instructions and any read-only scope. The agent should correct the task prompt; do not ask the user to run workflow commands.` });
57
+ process.exit(0);
58
+ }
59
+ }
60
+ const descriptor = `${input.agent_type ?? ''} ${args.subagent_type ?? args.agent_type ?? ''} ${args.description ?? ''} ${args.prompt ?? args.message ?? ''}`;
61
+ const reviewing = /KEELSON_PHASE=check|keelson-check|\breview\b|\breviewer\b|复核|审查/i.test(descriptor);
62
+ if (event === 'SubagentStart' && !reviewing && !/KEELSON_PHASE=implement|keelson-implement/i.test(descriptor)) {
63
+ // Generic agent_type carries no parent's prompt or reliable phase. The
64
+ // Agent/Task hook already injected the appropriate pack into that prompt.
65
+ const hint = '[keelson] Follow the phase and contracts in your task prompt. If they are missing, load `keelson context --phase check` for review or `--phase implement` for implementation. Preserve your assigned scope; context is not permission to edit.';
66
+ // A bound Codex child can safely receive its own packs. An unbound child
67
+ // received explicit binding instructions above, never a guessed root task.
68
+ const packs = host === 'codex' ? ['implement', 'check'].map((phase) => renderPhaseContext(phaseContext(root, workflow, phase))) : [];
69
+ output({ additionalContext: [hint, ...packs].join('\n\n') });
70
+ process.exit(0);
71
+ }
72
+ const phase = reviewing ? 'check' : 'implement';
73
+ const pack = phaseContext(root, workflow, phase, relative);
74
+ const context = renderPhaseContext(pack);
75
+ if (['Agent', 'Task'].includes(tool) && typeof args.prompt === 'string') {
76
+ // Preserve every original argument and normal host permission checks.
77
+ if (host === 'codex') output({ additionalContext: context });
78
+ else output({ [host === 'codebuddy' ? 'modifiedInput' : 'updatedInput']: { ...args, prompt: `${args.prompt}\n\n${context}` } });
79
+ } else if (event === 'SubagentStart') {
80
+ output({ additionalContext: context });
81
+ } else if (host === 'codex' && input.agent_id) {
82
+ // Codex does not emit SessionStart when a child compacts or resumes. Do
83
+ // not suppress the next contract pack on the basis of a pre-compact cache.
84
+ output({ additionalContext: context });
85
+ } else if (host !== 'codebuddy') {
86
+ const digest = crypto.createHash('sha256').update(`${input.agent_id ?? 'main'}\n${context}`).digest('hex');
87
+ if (!(session.state?.injectedContexts ?? []).includes(digest)) {
88
+ output({ additionalContext: context });
89
+ writeSession(root, { injectedContexts: [...(session.state?.injectedContexts ?? []).slice(-15), digest] }, env);
90
+ }
91
+ }
92
+ } catch (error) {
93
+ if (event === 'PreToolUse') output({ permissionDecision: 'deny', permissionDecisionReason: `Keelson context could not be loaded: ${error.message}. Repair the declared context before retrying.` });
94
+ else output({ additionalContext: `Keelson context could not be loaded: ${error.message}. Investigate before implementation.` });
95
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zyaiting/keelson",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Local, verifiable check records and durable decisions for AI-assisted code changes.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 2,
3
- "updated": "2026-09-20",
4
- "note": "Adapters describe generated discovery paths, not a promise of live end-to-end host parity. Codex session identity has been exercised locally. Other hosts have adapter contract tests; hooks are supported only where listed. Native session identity sources include CODEX_THREAD_ID, Claude hooks, Pi environment and explicit KEELSON_SESSION_ID. No source means an honest degraded state. Default installation is lightweight; --vendor explicitly copies package guidance.",
3
+ "updated": "2026-09-21",
4
+ "note": "Adapters describe generated discovery paths, not a promise of live end-to-end host parity. Codex session identity has been exercised locally. Other hosts have adapter contract tests; Claude Code, Codex and CodeBuddy have workflow hook adapters; hook execution depends on the host version, trust and settings. Native session identity sources include CODEX_THREAD_ID, Claude hooks, Pi environment and explicit KEELSON_SESSION_ID. No source means an honest degraded state. Default installation is lightweight; --vendor explicitly copies package guidance.",
5
5
  "platforms": {
6
6
  "claude": {
7
7
  "label": "Claude Code",
@@ -19,7 +19,7 @@
19
19
  "bin": "codex",
20
20
  "instructions": "AGENTS.md",
21
21
  "skillsDir": ".agents/skills",
22
- "hooks": false,
22
+ "hooks": true,
23
23
  "confidence": "verified",
24
24
  "support": "first-class",
25
25
  "sessionFocus": "native",
@@ -71,7 +71,7 @@
71
71
  "bin": "codebuddy",
72
72
  "instructions": "CODEBUDDY.md",
73
73
  "skillsDir": ".codebuddy/skills",
74
- "hooks": false,
74
+ "hooks": true,
75
75
  "confidence": "documented",
76
76
  "support": "first-class",
77
77
  "sessionFocus": "native",
@@ -0,0 +1,41 @@
1
+ {
2
+ "source": "Generated from published @zyaiting/keelson 0.4.0 and 0.4.1 (English/Chinese, lean/guided, guide on/off). Hashes include paths and normalized file bytes; only exact generated content may be replaced.",
3
+ "versions": {
4
+ "0.4.0": {
5
+ "shims": [
6
+ "cebe268136c46d9b190f31d5521770a8fe81dd0aa53dfccfd1dfbf39dafa26e7",
7
+ "5cef12b9c5aec6410040c1f5033fc60cc76fd9837bc73abfef147e36096b981a"
8
+ ],
9
+ "skills": [
10
+ "490534b10c8f594cd8ca40dc4817f56f1d9e84bca1cff973c45d857f367269d1",
11
+ "a8cdf54fc5e68a03d74c4d8a8a1f714997c1340318b3c664fab1d3473c865dd7",
12
+ "7d56a7c7197f2363bbbace9149465ade63c8308eb2dfed15d76fbcf892dd5a58",
13
+ "4e2ca439e8e11683d8913ab72f05537cbbde4afa6d61ad0e0848a59f9cf7bae7"
14
+ ],
15
+ "workflows": [
16
+ "455f5bb4060b984cd1839aed452fb82cbc09101d81d28630bdaa9547aca6d050",
17
+ "9099f590ae1b8192de759cc9b9d2187d37961b841e80bedd6175c23eac752af1",
18
+ "73f8562e785d8259d853257d02ac1e0688a5882d8c8e701b42a4e289b317be31",
19
+ "ca267bd38b5353684e3deb7d1774bb75d25005381541ba67597cd9fb530ad538"
20
+ ]
21
+ },
22
+ "0.4.1": {
23
+ "shims": [
24
+ "4afd7eb69ca1ab1913c73737e56890ca6e363881b1cedc76e95f97b0e5d528e3",
25
+ "a2d88237dbaa7a9aa0fc5340e73690737a5c58f13013dff93604d2414f3fef38"
26
+ ],
27
+ "skills": [
28
+ "bc676907188784049abf44f271643ea726b82ad34eb3af994bbf1b382f8e3d5f",
29
+ "9f2a472f526646a3f1e180bb1cf9f1aaec74a0da5f4e937c9ca1ed5d88f11602",
30
+ "adb328b4553e9d3d5e1826f91ffd10528b7f7b6b04565e0c1801606d04509686",
31
+ "d7ac8d6b0e8c849cca28f574fc6fb355aa863f90c93fbf2165a43a1d14cabe34"
32
+ ],
33
+ "workflows": [
34
+ "455f5bb4060b984cd1839aed452fb82cbc09101d81d28630bdaa9547aca6d050",
35
+ "9099f590ae1b8192de759cc9b9d2187d37961b841e80bedd6175c23eac752af1",
36
+ "73f8562e785d8259d853257d02ac1e0688a5882d8c8e701b42a4e289b317be31",
37
+ "ca267bd38b5353684e3deb7d1774bb75d25005381541ba67597cd9fb530ad538"
38
+ ]
39
+ }
40
+ }
41
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: keelson
3
- description: Engineering control plane for coding work in repositories with a .keelson/ directory. Use for exploring an idea, changing code, fixing/debugging, frontend design and UX review, continuing prior work, or improving recurring engineering failures. Keeps conversation sessions separate from durable work items so users can keep asking questions without having to announce when a task starts or ends.
3
+ description: Engineering workflow for repositories with a .keelson/ directory. Apply automatically to ordinary requests to explore an idea, build or change a feature, fix a bug, create or improve an interface, continue prior work, or improve recurring engineering failures. Routes discovery, design, implementation, verification and project memory without requiring skill names or workflow commands.
4
4
  ---
5
5
 
6
6
  # Keelson
@@ -21,6 +21,8 @@ Completion is **not** an intent and never depends on the user saying “done”.
21
21
 
22
22
  - For interface design, review, interaction or responsive work, load `frontend.md`; use `keelson design` for focused action briefs. Keep browser observations distinct from code checks.
23
23
 
24
+ Route from the requested outcome and repository evidence, not special vocabulary. Users describe work; the agent loads guidance and runs workflow commands. Automatically include `model.md` for conflicting terms or shared boundaries, `engineer.md` for non-obvious design choices, and `frontend.md` when the affected path includes a user interface, even without an explicit design request. During implementation use `build.md`; complete with `verify.md` → `land.md` → `reconcile.md` within existing authorization. `guide: true` adds teaching, not activation; both profiles use this workflow by default.
25
+
24
26
  ## Operating rules
25
27
 
26
28
  - A conversation/session is only a focus pointer. Ending a window, going idle, or continuing to ask questions MUST NOT mark a change complete.
@@ -28,9 +30,10 @@ Completion is **not** an intent and never depends on the user saying “done”.
28
30
  - On Resume, use `keelson focus --auto`; branch match or a sole active change may be suggested. Never silently bind an ambiguous session.
29
31
  - If `NOW.md` says “First contact”, infer and confirm `INTENT.md`; do not inventory the whole repository into specs/rules.
30
32
  - Non-trivial modifying work starts from current context; shared modules get `keelson impact <files>`.
31
- - Ask only at the decision frontier. Run the triggered blindspot pass, then use `interview.md`: up to three independent ready owner-owned decisions per round, skipping settled answers, concrete scenario/options, recommended default, and `not sure` as a valid route. Never ask what repo evidence, an experiment, or agent engineering judgment can settle.
33
+ - Automatically assess discovery needs on new goals, material follow-ups and changed premises using `interview.md`; unresolved goals, connected product choices or high-impact commitments trigger deeper discovery without special wording. Clear tasks proceed directly. Ask one ready owner decision for a simple gap, or the whole ready frontier for connected uncertainty, with concrete options, a recommendation and reason; reuse settled answers and investigate facts yourself.
32
34
  - Route non-obvious mechanisms/architecture through `engineer.md`: reduce to facts, outcome, constraints, and invariants; state a falsifiable hypothesis; use the cheapest experiment/ablation that can discriminate; complexity must earn its keep with evidence.
33
- - Size only the work: trivial = direct edit; quick = lightweight change; spec = acceptance + behavior delta + plan within existing user authorization; clarify only unresolved owner choices.
35
+ - Size only the work: trivial = minimal quick change; quick = lightweight change; spec = acceptance + behavior delta + plan within existing user authorization; clarify only unresolved owner choices.
36
+ - Before product edits, automatically run `keelson start` for the focused change, then load `keelson context --phase implement`; after new material decisions, restart only once they are settled. Users need not run these commands.
34
37
  - Artifacts are information containers, not ceremony. Do not create empty roadmap/glossary/rule/task/ledger/handoff/spec files.
35
38
  - `tasks.md` is an execution plan, not completion authority. Unchecked plan items never override satisfied acceptance + fresh evidence; reconcile or remove stale tasks when the implementation path changes.
36
39
  - Knowledge maintenance is internal. During RECONCILE, automatically rewrite/split/dedupe pressured durable docs and let `land` auto-shard large specs; never ask the owner to maintain Keelson unless a product-semantic decision is required.
@@ -2,6 +2,16 @@
2
2
 
3
3
  Execute `tasks.md` slice by slice. You choose how; these notes cover the parts that are easy to get wrong.
4
4
 
5
+ ## Enter implementation with the current plan
6
+ <!-- keelson: id=build.start | without: an agent edits product files before resolving the plan or reads an unrelated change's rules | sunset: never -->
7
+
8
+ For modifying work, create the smallest useful change, record concrete acceptance, and run `keelson start` automatically within the owner's existing authorization. Trivial work uses a minimal quick change without a separate plan or interview. Start rejects open decisions, assumptions, missing acceptance and active prerequisites; it records the current plan and declares phase context in `context.json`. Reopened decisions or changed plan/delta require resolving the affected branches and starting again. Do not ask the owner to operate the workflow.
9
+
10
+ Read `keelson context --phase implement` before editing. The pack contains current and delta specs, relevant rules, decisions and checks; `context.json` can declare additional project-relative files per `implement`/`check` phase. Add newly affected paths to context routing. For spec work, retain the owner's original request and material follow-ups in `request.md` so the reviewer sees the actual requested outcome. Do not replace it with your implementation summary.
11
+
12
+ Claude Code, Codex and CodeBuddy have native gates for supported file-editing tools and hooks for session context. Codex requires trusted hooks. Shell/MCP writers and other hosts must follow this same protocol through the agent. This is not a sandbox or proof of user authorization.
13
+
14
+
5
15
  ## Rulings, not stalls
6
16
  <!-- keelson: id=build.rulings | without: agent parks the session on questions the plan already answers; or decides silently and the reasoning is lost | sunset: never -->
7
17
 
@@ -21,6 +31,8 @@ When tasks are mostly independent and the host offers subagents, dispatch a fres
21
31
 
22
32
  More agents are not a linear throughput multiplier. When tasks share mutable state or the same contract, or need constant synchronization, coordination and merge cost can exceed the parallelism benefit; keep them sequential. Parallelize only when boundaries are clear, outputs are independently verifiable, and the merge contract is explicit. Do not try to rescue tightly coupled work by simply adding agents.
23
33
 
34
+ For a tracked task, include a standalone `KEELSON_CHANGE=<change-name>` line and the phase in each child task. In Codex the child automatically runs `keelson focus <change-name>` and `keelson context --phase implement` (or `check` for review) before working. Each child has its own thread identity; never infer its task from the root session. Preserve assigned read-only scope. When resuming a child with an existing focus, retain it unless the new assignment explicitly changes it. Untracked read-only investigation needs no change or marker.
35
+
24
36
  After each task, a reviewer subagent (tier ≥ `standard`, never below the implementer) checks the diff against the spec and the rules. Record both in the ledger:
25
37
 
26
38
  ```markdown
@@ -1,6 +1,8 @@
1
1
  # Discovering what is wanted
2
2
 
3
- The user often cannot describe the whole requirement in the first sentence, and they should not need to know which engineering choice matters. Discovery finds the problem behind the request before anyone picks a database. Use `interview.md` for owner-owned uncertainty; load `design-lenses.md` only when the work triggers a real cross-domain risk.
3
+ The user often cannot describe the whole requirement in the first sentence, and they should not need to know which engineering choice matters. Discovery finds the problem behind the request before anyone picks a database. Apply `interview.md` automatically to determine depth from the goal, unresolved choices and consequences, including when the user simply asks to build something. Load `design-lenses.md` only when the work triggers a real cross-domain risk.
4
+
5
+ During read-only requests, reuse existing artifacts but keep all new write-backs, decisions and notes in the conversation, even when a change is active. The persistence steps below apply only within existing write authorization.
4
6
 
5
7
  ## Scenario before technology
6
8
  <!-- keelson: id=discover.scenario-first | without: the first question is a technology choice the owner cannot answer, and the product is shaped by whatever they guessed | sunset: never -->
@@ -42,11 +44,11 @@ Before asking, classify the gap by who can resolve it:
42
44
  |---|---|
43
45
  | Already established in repository/context | Use it; cite the source in the write-back |
44
46
  | Reality-owned (code behaviour, API contract, measurement, dependency capability) | Investigate or run a small experiment |
45
- | User-owned and load-bearing (goal, scope, acceptance, risk tolerance, public commitment) | Ask one question |
47
+ | User-owned and load-bearing (goal, scope, acceptance, risk tolerance, public commitment) | Ask one question for a simple gap or the whole ready frontier for connected uncertainty |
46
48
  | Non-load-bearing or cheap to reverse | Decide under authorization, or leave unresolved for a later slice |
47
49
  | Evidence exhausted | Mark it UNKNOWN; do not convert uncertainty into a user belief |
48
50
 
49
- Choose the gap with the highest practical value of information: the answer most likely to change the next slice, weighted by the cost of being wrong. Before asking, apply the `interview.md` question protocol. After the answer, update the write-back and reassess the frontier. "Exactly one question" is a bottleneck for **blocking uncertainty**, not a ritual: when no user-owned load-bearing gap exists, ask nothing and proceed.
51
+ Use `interview.md` to choose a single question for a simple gap or the whole ready frontier for connected uncertainty. Prioritize by practical value of information: the answer most likely to change the next slice, weighted by the cost of being wrong. Before asking, apply the `interview.md` question protocol. After the answer, update the write-back and reassess the frontier. Question count follows decision complexity: when no user-owned load-bearing gap exists, ask nothing and proceed.
50
52
 
51
53
  ## Scope guard
52
54
  <!-- keelson: id=discover.scope-guard | without: a first request asks for five independent domains at once, and integration risk, debugging cost, and requirement churn compound | sunset: never -->
@@ -1,6 +1,6 @@
1
1
  # Frontend design
2
2
 
3
- Use for creating, improving, diagnosing or verifying an interface people see and operate. Keep the existing change lifecycle; add design judgment and observable interface acceptance.
3
+ Apply automatically when the requested work or affected code creates, changes, diagnoses or verifies an interface people see and operate. Users need not request a design action or name this reference. Keep the existing change lifecycle; add design judgment and observable interface acceptance, scoped to the affected user journey.
4
4
 
5
5
  ## Route by the problem
6
6
  <!-- keelson: id=frontend.routing | without: Small UI fixes turn into broad redesigns and every request loads all guidance | sunset: never -->