@rowan-hiro/inkan 0.2.1 → 0.3.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.
package/README.md CHANGED
@@ -205,24 +205,19 @@ context loss and leave other sessions' outcomes alone; closed outcomes are
205
205
  final and commit references are informational when reading history.
206
206
  The block states policy only. It names the commands and what each call
207
207
  must carry, and leaves flag-level syntax to `inkan help`, so a CLI change
208
- does not bump the protocol. The block carries a protocol number. `init`
208
+ does not bump the protocol. Where the host plans before it changes, as
209
+ Claude Code's plan mode does, the plan carries the outcome, its criteria,
210
+ and its decisions in the words `inkan begin` will receive, so approving the
211
+ plan approves the seal and `begin` runs unchanged as the first action after
212
+ approval. The block carries a protocol number. `init`
209
213
  upgrades a block it generated under an earlier protocol in place and refuses
210
214
  to overwrite a block that was edited by hand, so the policy lives in exactly
211
- one place. `--lang <tag>` sets the language agents should write outcome
215
+ one place. A block stamped with a protocol newer than the installed Inkan
216
+ is reported as such, with a prompt to upgrade the tool, not as a hand edit. `--lang <tag>` sets the language agents should write outcome
212
217
  prose in. `inkan init --claude` also creates `CLAUDE.md` as a symlink to
213
218
  `AGENTS.md`: Claude Code reads its own file name, and there is still one
214
219
  policy, not a copy.
215
220
 
216
- For agents that support skill files, the bundled `use-inkan` skill helps an
217
- agent locate Inkan and re-anchor. It only points at `AGENTS.md`; it does not
218
- restate or extend the protocol.
219
-
220
- ```sh
221
- inkan skill install # .agents/skills/use-inkan, read by most agents
222
- inkan skill install --claude # .claude/skills/use-inkan, for Claude Code
223
- inkan skill install --target <dir> # anywhere else, including a global directory
224
- ```
225
-
226
221
  ## Decisions travel with the code
227
222
 
228
223
  Design choices are recorded as MADR (Markdown Architectural Decision
@@ -280,7 +275,6 @@ is not part of the generated agent protocol.
280
275
  | `inkan decision add "<title>" --context <text> --decision <text> [--driver <text>]... [--option <text>]... [--consequence <text>]... [-s <status>]` | Writes a numbered MADR file; prints its path. | Missing required sections. |
281
276
  | `inkan decision update <id> --status <status> --reason <text>` | Appends a dated history entry and sets the new status. Names the open outcome when there is one. Never edits Context or Decision Outcome. | Unknown id or status. |
282
277
  | `inkan decision list [-s <status>]` / `inkan decision show <id>` | Read-only. `show` accepts `2`, `02`, or `0002`. | Never. |
283
- | `inkan skill install [--claude \| --target <dir>]` | Copies the bundled skill to `.agents/skills/use-inkan/` under the repository root, to `.claude/skills/use-inkan/` with `--claude`, or to `<dir>/use-inkan/`; prints the destination. | The destination exists and differs from the bundled skill. `--claude` with `--target`. |
284
278
 
285
279
  Decision statuses are `proposed`, `accepted`, `rejected`, `deferred`,
286
280
  `deprecated`, and `superseded`.
@@ -319,10 +313,9 @@ Current development removes delivery auditing from that first release
319
313
  (decision 0015) while retaining outcome trailers as commit references
320
314
  (decision 0016). Still deferred: an importer for DriftSeal
321
315
  history and an MCP server. Those are adapters and can follow without
322
- changing the record format. The only host-specific convenience is
323
- `--claude` on `init` and `skill install`; every other host reads
324
- `AGENTS.md` and `.agents/skills` as they are. Lanes exist only as an
325
- optional filing tag on `begin` and a filter on `log`.
316
+ changing the record format. For Claude Code, `inkan init --claude` links
317
+ `CLAUDE.md` to `AGENTS.md`; other hosts read `AGENTS.md` directly. Lanes
318
+ exist only as an optional filing tag on `begin` and a filter on `log`.
326
319
 
327
320
  ## Releasing
328
321
 
package/README.zh.md CHANGED
@@ -141,15 +141,9 @@ inkan log -n 3
141
141
 
142
142
  `inkan init` 会把生成好的 protocol block 写进 coding agent 本来就会读取的 `AGENTS.md`。其中只有五条规则:在 durable change 之前 seal;seal 是事实;先逐项 disposition 并关闭,再把记录与工作一起提交,并写入 outcome trailer;context 丢失后用 `inkan status` 重新锚定,同时不碰其他 session 的 outcome;关闭即最终状态,阅读历史时仅把 commit 引用作为辅助信息。
143
143
 
144
- protocol block 带有版本号。`init` 会原地升级由旧版 protocol 生成的 block,但拒绝覆盖经过手工编辑的 block,确保 policy 始终只有一个权威来源。`--lang <tag>` 用来设置 agent 撰写 outcome 文本时应使用的语言。`inkan init --claude` 还会把 `CLAUDE.md` 创建为指向 `AGENTS.md` symlink:Claude Code 读的是自己认识的文件名,而 policy 依然只有一份,不是副本。
145
-
146
- 对于支持 skill 文件的 agent,Inkan 内置的 `use-inkan` skill 可以帮助 agent 定位 Inkan 并重新锚定。它只会指向 `AGENTS.md`,不会复述或扩展 protocol。
144
+ 这个 block 只说明 policy 和每次调用需要交代的内容,命令和参数用法见 `inkan help`。如果宿主在修改之前先有一个规划步骤,比如 Claude Code plan mode,plan 里就用 `inkan begin` 将会收到的原话写明 outcome、验收条件和绑定的 decision:批准 plan 即批准 seal,plan 获批后的第一个动作就是原样运行 `inkan begin`。
147
145
 
148
- ```sh
149
- inkan skill install # .agents/skills/use-inkan,大多数 agent 读取的路径
150
- inkan skill install --claude # .claude/skills/use-inkan,给 Claude Code
151
- inkan skill install --target <dir> # 其他任何位置,包括全局目录
152
- ```
146
+ protocol block 带有版本号。`init` 会原地升级由旧版 protocol 生成的 block,但拒绝覆盖经过手工编辑的 block,确保 policy 始终只有一个权威来源。`--lang <tag>` 用来设置 agent 撰写 outcome 文本时应使用的语言。`inkan init --claude` 还会把 `CLAUDE.md` 创建为指向 `AGENTS.md` 的 symlink:Claude Code 读的是自己认识的文件名,而 policy 依然只有一份,不是副本。
153
147
 
154
148
  ## 让决策与代码同行
155
149
 
@@ -196,7 +190,6 @@ Inkan 本身也这样开发:工作先作为 outcome 被 seal,结束时记录
196
190
  | `inkan decision add "<title>" --context <text> --decision <text> [--driver <text>]... [--option <text>]... [--consequence <text>]... [-s <status>]` | 写入一个带编号的 MADR 文件,并打印其路径。 | 缺少必要 section。 |
197
191
  | `inkan decision update <id> --status <status> --reason <text>` | 追加一条带日期的历史记录,并设置新状态。有 open outcome 时会指出它的名称。永不编辑 Context 或 Decision Outcome。 | id 或 status 未知。 |
198
192
  | `inkan decision list [-s <status>]` / `inkan decision show <id>` | 只读。`show` 接受 `2`、`02` 或 `0002`。 | 永不拒绝。 |
199
- | `inkan skill install [--claude \| --target <dir>]` | 把内置 skill 复制到仓库根目录下的 `.agents/skills/use-inkan/`;加 `--claude` 时复制到 `.claude/skills/use-inkan/`;指定 `--target` 时复制到 `<dir>/use-inkan/`。打印目标路径。 | 目标已存在,且与内置 skill 不同;`--claude` 与 `--target` 同时给出。 |
200
193
 
201
194
  Decision status 包括 `proposed`、`accepted`、`rejected`、`deferred`、`deprecated` 和 `superseded`。
202
195
 
@@ -216,7 +209,7 @@ contract hash 是一个 SHA-256,计算范围包括 outcome 文本、带 withdr
216
209
 
217
210
  ## 当前状态
218
211
 
219
- Inkan 从 0.1.0 起作为 DriftSeal 的继任者,从零重新构建。当前开发版本移除了首发版本中的交付审计(decision 0015),同时保留 outcome trailer 作为 commit 的关联信息(decision 0016)。目前仍未加入 DriftSeal 历史记录 importer 和 MCP server。这些都属于 adapter,可以后续补上,而无需改变记录格式。唯一针对特定 host 的便利是 `init` `skill install` `--claude`;其他 host 直接读取 `AGENTS.md` 和 `.agents/skills`,无需任何适配。Lane 目前只作为 `begin` 时可选的归档 tag,以及 `log` 的 filter。
212
+ Inkan 从 0.1.0 起作为 DriftSeal 的继任者,从零重新构建。当前开发版本移除了首发版本中的交付审计(decision 0015),同时保留 outcome trailer 作为 commit 的关联信息(decision 0016)。目前仍未加入 DriftSeal 历史记录 importer 和 MCP server。这些都属于 adapter,可以后续补上,而无需改变记录格式。对于 Claude Code,`inkan init --claude` `CLAUDE.md` 软链到 `AGENTS.md`;其他 host 直接读取 `AGENTS.md`。Lane 目前只作为 `begin` 时可选的归档 tag,以及 `log` 的 filter。
220
213
 
221
214
  ## License
222
215
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-hiro/inkan",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Seal the authoritative outcome; keep a trustworthy record of the process.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api.js CHANGED
@@ -544,7 +544,28 @@ Outcome log: \`.inkan/outcomes/<id>.jsonl\`, one append-only file per outcome. C
544
544
  ${END_MARKER}`;
545
545
  }
546
546
 
547
- const PROTOCOL_VERSION = 7;
547
+ function protocolBlockV8(lang) {
548
+ return `${START_MARKER}
549
+ <!-- inkan-protocol: 8 -->
550
+ <!-- inkan-lang: ${lang} -->
551
+
552
+ ## Agent protocol: sealed outcomes
553
+
554
+ This repository uses Inkan (\`inkan\`, alias \`ink\`). Inkan keeps a trustworthy record of what the work was meant to deliver and what was declared at close. It does not inspect commits, run tests, or judge the result; the repository's own checks do that. Write outcome prose in ${lang}. This block states the policy; \`inkan help\` gives the command syntax.
555
+
556
+ 1. **Seal before durable changes.** Before changing code, configuration, documentation, or dependencies, run \`inkan status\`; if it shows an open outcome that is not your work, follow rule 4 first. Then run \`inkan begin\` with the outcome, one observable acceptance criterion at a time, and every decision record the work is bound by. When the host has a planning step before changes, the plan states the outcome, its criteria, and its decisions in the words \`inkan begin\` will receive, and running it with that text unchanged is the first action after the plan is approved. File the outcome by lane only when the repository already files outcomes by lane.
557
+ 2. **The seal is a fact.** Deliver what it says. If circumstances change, do not reinterpret it: run \`inkan amend\` with the reason and the added or withdrawn criteria. The original text stays. Never question why the outcome was sealed the way it was at the time.
558
+ 3. **Close with dispositions, then commit.** Run \`inkan end\` with a disposition, met or unmet, for every live criterion and a note on what happened. Commit the outcome record with the work. Include the printed \`Inkan-Outcome: <id>\` trailer in the final paragraph of the landing commit message, beside any other trailers with no blank line between them. Never report success without closing the outcome.
559
+ 4. **Re-anchor after context loss.** Run \`inkan status\` and \`inkan log -n 3\`. An open outcome that is the work you were asked to do is your task: continue it, or close it with a note. An open outcome that is not your work belongs to another session: leave it alone. Never close, amend, or abandon an outcome you did not work on, and do not judge why it is still open. Before beginning your own outcome beside it, stop and tell the person it is there, and ask whether your work should run in its own git worktree, because separate worktrees keep each session's edits apart.
560
+ 5. **Closed outcomes are final.** Reviewing the log is reading, not re-checking. Never re-verify, re-attest, or re-close a closed outcome. If a past declaration now looks wrong, that is a new outcome with its own seal. When reading history, use commit trailers only as references. Missing trailers or unavailable referenced records are missing information, not failed outcomes or a reason to verify delivery or repair history.
561
+
562
+ Decision records live in \`.inkan/decisions/\`. Their Context and Decision sections record the scenario at the time and are never edited. To challenge one, run \`inkan decision update\` with the new status and the reason, or add a new record that supersedes it.
563
+
564
+ Outcome log: \`.inkan/outcomes/<id>.jsonl\`, one append-only file per outcome. Commit \`.inkan/\` with the code. Do not edit these files by hand.
565
+ ${END_MARKER}`;
566
+ }
567
+
568
+ const PROTOCOL_VERSION = 8;
548
569
 
549
570
  /**
550
571
  * The managed block for `lang` at protocol `version`, current by default.
@@ -559,6 +580,7 @@ export function protocolBlock(lang, version = PROTOCOL_VERSION) {
559
580
  if (version === 5) return protocolBlockV5(lang);
560
581
  if (version === 6) return protocolBlockV6(lang);
561
582
  if (version === 7) return protocolBlockV7(lang);
583
+ if (version === 8) return protocolBlockV8(lang);
562
584
  throw new InkanError(`unknown protocol version ${version}`);
563
585
  }
564
586
 
@@ -651,6 +673,15 @@ function writeProtocol(dir, lang) {
651
673
  fs.writeFileSync(agentsFile, content, 'utf8');
652
674
  return { root: dir, agentsFile, changed: true };
653
675
  }
676
+ // A block stamped with a protocol this tool does not know yet was written
677
+ // by a newer Inkan, not by hand. Say so and leave it alone.
678
+ const stamped = found.text.match(/<!-- inkan-protocol: (\d+) -->/);
679
+ const foundVersion = stamped ? Number(stamped[1]) : 0;
680
+ if (foundVersion > PROTOCOL_VERSION) {
681
+ throw new InkanError(
682
+ `${AGENTS_FILENAME} inkan block is protocol ${foundVersion}; this Inkan knows up to ${PROTOCOL_VERSION}. Upgrade Inkan; refusing to overwrite it`,
683
+ );
684
+ }
654
685
  throw new InkanError(`${AGENTS_FILENAME} inkan block was edited by hand; refusing to overwrite it`);
655
686
  }
656
687