@astrosheep/keiyaku 2.9.4 → 2.9.6

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 (143) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/agents/call-terms.js +1 -0
  3. package/build/agents/harness/execution-handle.js +1 -0
  4. package/build/agents/harness/outcome.js +31 -5
  5. package/build/agents/harness/projection.js +151 -78
  6. package/build/agents/harness/router.js +2 -1
  7. package/build/agents/providers/claude-agent-sdk/adapter.js +13 -1
  8. package/build/agents/providers/claude-agent-sdk/registration.js +2 -1
  9. package/build/agents/providers/codex-app-server/adapter.js +43 -10
  10. package/build/agents/providers/codex-app-server/events.js +23 -0
  11. package/build/agents/providers/codex-app-server/registration.js +2 -1
  12. package/build/agents/providers/opencode-sdk/adapter.js +7 -0
  13. package/build/agents/providers/opencode-sdk/registration.js +2 -1
  14. package/build/agents/providers/pi/adapter.js +10 -0
  15. package/build/agents/providers/pi/events.js +4 -3
  16. package/build/agents/providers/pi/registration.js +3 -1
  17. package/build/agents/types.js +2 -0
  18. package/build/cli/commands/akuma/akuma/meta.js +1 -1
  19. package/build/cli/commands/akuma/list/meta-ls.js +1 -1
  20. package/build/cli/commands/akuma/view/meta.js +1 -1
  21. package/build/cli/commands/contract/amend/meta.js +4 -4
  22. package/build/cli/commands/contract/arc/handler.js +1 -1
  23. package/build/cli/commands/contract/arc/meta.js +4 -4
  24. package/build/cli/commands/contract/audit/handler.js +16 -0
  25. package/build/cli/commands/contract/audit/meta.js +16 -0
  26. package/build/cli/commands/contract/bind/meta.js +20 -11
  27. package/build/cli/commands/contract/catalog.js +2 -0
  28. package/build/cli/commands/contract/forfeit/meta.js +1 -1
  29. package/build/cli/commands/contract/log/meta.js +1 -1
  30. package/build/cli/commands/contract/petition/handler.js +1 -2
  31. package/build/cli/commands/contract/petition/meta.js +6 -6
  32. package/build/cli/commands/contract/renew/handler.js +2 -2
  33. package/build/cli/commands/contract/renew/meta.js +4 -4
  34. package/build/cli/commands/metadata.js +3 -2
  35. package/build/cli/commands/projection/call/meta.js +4 -1
  36. package/build/cli/commands/projection/kill/meta.js +1 -1
  37. package/build/cli/commands/projection/revive/meta.js +4 -1
  38. package/build/cli/commands/projection/status/meta.js +1 -1
  39. package/build/cli/commands/projection/tell/handler.js +1 -1
  40. package/build/cli/commands/projection/tell/meta.js +4 -1
  41. package/build/cli/commands/projection/wait/meta.js +1 -1
  42. package/build/cli/commands/skills/install/meta.js +1 -1
  43. package/build/cli/commands/skills/skills/meta.js +1 -1
  44. package/build/cli/commands/system/completion/meta.js +1 -1
  45. package/build/cli/commands/system/dump-env/meta.js +1 -1
  46. package/build/cli/commands/system/guide/meta.js +1 -1
  47. package/build/cli/commands/task/add/handler.js +2 -2
  48. package/build/cli/commands/task/add/meta.js +4 -1
  49. package/build/cli/commands/task/doctor/meta.js +1 -1
  50. package/build/cli/commands/task/done/meta.js +1 -1
  51. package/build/cli/commands/task/drop/meta.js +1 -1
  52. package/build/cli/commands/task/ls/handler.js +10 -4
  53. package/build/cli/commands/task/ls/meta.js +3 -3
  54. package/build/cli/commands/task/show/meta.js +1 -1
  55. package/build/cli/commands/task/start/meta.js +1 -1
  56. package/build/cli/commands/task/stop/meta.js +1 -1
  57. package/build/cli/commands/task/task/meta.js +1 -1
  58. package/build/cli/commands/task/update/handler.js +2 -3
  59. package/build/cli/commands/task/update/meta.js +4 -1
  60. package/build/cli/completion.js +9 -2
  61. package/build/cli/flags.js +19 -3
  62. package/build/cli/help.js +3 -3
  63. package/build/cli/index.js +59 -75
  64. package/build/cli/output-stream-error-policy.js +19 -5
  65. package/build/cli/parse-flags.js +19 -2
  66. package/build/cli/parse-metadata.js +1 -7
  67. package/build/cli/parse-selectors.js +1 -0
  68. package/build/cli/parse.js +16 -7
  69. package/build/cli/projection-address.js +6 -1
  70. package/build/cli/render/audit.js +121 -0
  71. package/build/cli/render/errors.js +18 -1
  72. package/build/cli/render/format.js +5 -2
  73. package/build/cli/render/misc.js +3 -1
  74. package/build/cli/render/projection-activity.js +12 -6
  75. package/build/cli/render/status.js +28 -18
  76. package/build/cli/render/success-response.js +6 -5
  77. package/build/cli/render/task.js +12 -43
  78. package/build/cli/render/terminal-failure.js +7 -2
  79. package/build/cli/render/wait.js +36 -8
  80. package/build/config/env-keys.js +2 -0
  81. package/build/config/env.js +3 -0
  82. package/build/core/amend.js +20 -94
  83. package/build/core/arc.js +14 -6
  84. package/build/core/audit/candidate.js +48 -0
  85. package/build/core/audit/coordinates.js +180 -0
  86. package/build/core/audit/evidence.js +158 -0
  87. package/build/core/audit/facade.js +42 -0
  88. package/build/core/audit/readiness.js +4 -0
  89. package/build/core/audit/report.js +38 -0
  90. package/build/core/audit.js +1 -0
  91. package/build/core/bind.js +1 -1
  92. package/build/core/call/execution.js +1 -0
  93. package/build/core/contract-view.js +2 -3
  94. package/build/core/draft.js +33 -20
  95. package/build/core/entry.js +3 -4
  96. package/build/core/markdown/lex.js +2 -1
  97. package/build/core/projection/generation/database.js +41 -16
  98. package/build/core/projection/generation/model.js +22 -2
  99. package/build/core/projection/generation/projection-generation-execution.js +20 -7
  100. package/build/core/projection/generation/projection-generation-launcher.js +4 -4
  101. package/build/core/projection/generation/projection-generation-runner.js +1 -0
  102. package/build/core/projection/generation/store.js +1 -1
  103. package/build/core/projection/generation/transitions.js +19 -3
  104. package/build/core/projection/index.js +2 -2
  105. package/build/core/projection/projection-execution-observer.js +35 -21
  106. package/build/core/projection/projection-life-observer.js +16 -2
  107. package/build/core/projection/projection-status.js +67 -22
  108. package/build/core/projection/projection-terminal-failure.js +2 -0
  109. package/build/core/projection/projection-wait.js +6 -9
  110. package/build/core/projection/projection-wake.js +30 -6
  111. package/build/core/renew.js +41 -22
  112. package/build/core/scope.js +129 -2
  113. package/build/core/seal.js +36 -15
  114. package/build/core/settlement/petition-claim-gates.js +4 -33
  115. package/build/core/settlement/petition-preview.js +1 -1
  116. package/build/core/settlement/petition.js +10 -3
  117. package/build/core/settlement/settlement.js +3 -10
  118. package/build/core/settlement/verification.js +59 -0
  119. package/build/core/status/board.js +48 -28
  120. package/build/core/stored-agent-event.js +3 -2
  121. package/build/core/task/board.js +1 -0
  122. package/build/core/task/commands.js +20 -12
  123. package/build/core/task/document.js +5 -0
  124. package/build/core/task/index.js +1 -1
  125. package/build/core/task/model.js +8 -1
  126. package/build/core/task/query.js +214 -0
  127. package/build/core/task/settlement-git.js +115 -16
  128. package/build/core/task/settlement-policy.js +17 -9
  129. package/build/core/task/source-board.js +1 -0
  130. package/build/core/task/task-contract.js +125 -51
  131. package/build/core/task/task-store-repository.js +1 -0
  132. package/build/core/task/task.js +2 -0
  133. package/build/flow-error.js +2 -4
  134. package/build/generated/version.js +2 -2
  135. package/build/git/diff/parsers.js +23 -13
  136. package/build/git/diff/structured.js +127 -0
  137. package/build/index.js +7 -7
  138. package/build/telemetry/logger.js +4 -2
  139. package/package.json +1 -1
  140. package/skills/keiyaku/SKILL.md +2 -2
  141. package/skills/keiyaku-akuma/SKILL.md +17 -6
  142. package/skills/keiyaku-task/SKILL.md +16 -7
  143. package/skills/keiyaku-workflow/SKILL.md +48 -13
@@ -0,0 +1,127 @@
1
+ import { createGit, wrapGitError } from "../core.js";
2
+ import { diffPathspecArgs } from "./pathspec.js";
3
+ import { parseHunkRange, parseUnifiedHunks, splitDiffByFile } from "./parsers.js";
4
+ function parseRawDiff(output) {
5
+ const fields = output.split("\0");
6
+ const files = [];
7
+ let index = 0;
8
+ while (index < fields.length) {
9
+ const header = fields[index++];
10
+ if (!header)
11
+ continue;
12
+ const statusToken = header.trim().split(/\s+/).at(-1) ?? "";
13
+ const status = statusToken[0];
14
+ if (status !== "A" && status !== "M" && status !== "D" && status !== "R" && status !== "C" && status !== "T" && status !== "U")
15
+ continue;
16
+ const firstPath = fields[index++] ?? "";
17
+ if (status === "R" || status === "C") {
18
+ const path = fields[index++] ?? "";
19
+ files.push({
20
+ oldPath: firstPath,
21
+ path,
22
+ status,
23
+ similarity: Number.parseInt(statusToken.slice(1), 10) || 0,
24
+ });
25
+ }
26
+ else {
27
+ files.push({ path: firstPath, status });
28
+ }
29
+ }
30
+ return files;
31
+ }
32
+ function withoutTerminalPatchDelimiter(patch) {
33
+ return patch.endsWith("\n") ? patch.slice(0, -1) : patch;
34
+ }
35
+ function parseNumstat(output) {
36
+ const fields = output.split("\0");
37
+ const stats = [];
38
+ let index = 0;
39
+ while (index < fields.length) {
40
+ const record = fields[index++];
41
+ if (!record)
42
+ continue;
43
+ const [added = "0", removed = "0", path = ""] = record.split("\t");
44
+ const binary = added === "-" || removed === "-";
45
+ if (path) {
46
+ stats.push({ path, insertions: binary ? 0 : Number.parseInt(added, 10) || 0, deletions: binary ? 0 : Number.parseInt(removed, 10) || 0, binary });
47
+ continue;
48
+ }
49
+ const oldPath = fields[index++] ?? "";
50
+ const newPath = fields[index++] ?? "";
51
+ stats.push({ path: newPath, oldPath, insertions: binary ? 0 : Number.parseInt(added, 10) || 0, deletions: binary ? 0 : Number.parseInt(removed, 10) || 0, binary });
52
+ }
53
+ return stats;
54
+ }
55
+ function structuredLines(raw, oldStart, newStart) {
56
+ let oldLine = oldStart;
57
+ let newLine = newStart;
58
+ const lines = [];
59
+ for (const line of raw) {
60
+ if (line.startsWith("\"))
61
+ continue;
62
+ if (line.startsWith("+")) {
63
+ lines.push({ kind: "addition", content: line.slice(1), oldLine: null, newLine: newLine++ });
64
+ }
65
+ else if (line.startsWith("-")) {
66
+ lines.push({ kind: "deletion", content: line.slice(1), oldLine: oldLine++, newLine: null });
67
+ }
68
+ else {
69
+ lines.push({ kind: "context", content: line.startsWith(" ") ? line.slice(1) : line, oldLine: oldLine++, newLine: newLine++ });
70
+ }
71
+ }
72
+ return lines;
73
+ }
74
+ function parsePatchHunks(section) {
75
+ return parseUnifiedHunks([...section]).hunks.flatMap((hunk, index) => {
76
+ const range = parseHunkRange(hunk.header);
77
+ if (!range)
78
+ return [];
79
+ return [{
80
+ index,
81
+ header: hunk.header,
82
+ oldStart: range.oldStart,
83
+ oldLines: range.oldLines,
84
+ newStart: range.newStart,
85
+ newLines: range.newLines,
86
+ lines: structuredLines(hunk.lines, range.oldStart, range.newStart),
87
+ }];
88
+ });
89
+ }
90
+ export async function readStructuredDiff(cwd, from, to, options = {}) {
91
+ const git = createGit(cwd);
92
+ const range = `${from}..${to}`;
93
+ const pathspec = diffPathspecArgs({ excludePaths: options.excludePaths });
94
+ try {
95
+ const [raw, numstat, patch] = await Promise.all([
96
+ git.raw(["diff", "--raw", "-z", "--find-renames", range, ...pathspec]),
97
+ git.raw(["diff", "--numstat", "-z", "--find-renames", range, ...pathspec]),
98
+ git.raw(["diff", "--no-color", "--no-ext-diff", "--unified=3", "--find-renames", range, ...pathspec]),
99
+ ]);
100
+ const rawFiles = parseRawDiff(raw);
101
+ const stats = parseNumstat(numstat);
102
+ const sections = splitDiffByFile(withoutTerminalPatchDelimiter(patch));
103
+ const files = rawFiles.map((file, index) => {
104
+ const stat = stats[index];
105
+ return {
106
+ ...file,
107
+ insertions: stat?.insertions ?? 0,
108
+ deletions: stat?.deletions ?? 0,
109
+ binary: stat?.binary ?? false,
110
+ hunks: parsePatchHunks(sections[index] ?? []),
111
+ };
112
+ });
113
+ return {
114
+ from,
115
+ to,
116
+ files,
117
+ stat: {
118
+ filesChanged: files.length,
119
+ insertions: files.reduce((sum, file) => sum + file.insertions, 0),
120
+ deletions: files.reduce((sum, file) => sum + file.deletions, 0),
121
+ },
122
+ };
123
+ }
124
+ catch (error) {
125
+ throw wrapGitError(`diff --find-renames ${range}`, error, cwd);
126
+ }
127
+ }
package/build/index.js CHANGED
@@ -3,10 +3,10 @@ import { VERSION, GIT_HASH } from "./generated/version.js";
3
3
  import * as fs from "node:fs/promises";
4
4
  import { getConfig, initializeConfig } from "./config/env.js";
5
5
  import { ENV_KEYS } from "./config/env-keys.js";
6
- import { logErrorWithCause } from "./telemetry/logger.js";
6
+ import { formatErrorWithCause } from "./telemetry/logger.js";
7
7
  import { runProjectionGenerationRuntime } from "./core/projection/index.js";
8
8
  import { renderCliHelp, runCliCommand } from "./cli/index.js";
9
- import { installCliOutputStreamErrorPolicy } from "./cli/output-stream-error-policy.js";
9
+ import { installCliOutputStreamErrorPolicy, writeCliOutput } from "./cli/output-stream-error-policy.js";
10
10
  import { assertSubagentCliCommandAllowed } from "./cli/subagent-guard.js";
11
11
  installCliOutputStreamErrorPolicy(process.stdout, process.stderr);
12
12
  const packageVersion = VERSION;
@@ -45,16 +45,16 @@ async function main() {
45
45
  args: cliArgs,
46
46
  });
47
47
  if (cliArgs.length === 1 && cliArgs[0] === "--version") {
48
- console.log(GIT_HASH ? `${packageVersion} (${GIT_HASH})` : packageVersion);
48
+ await writeCliOutput(process.stdout, `${GIT_HASH ? `${packageVersion} (${GIT_HASH})` : packageVersion}\n`);
49
49
  return;
50
50
  }
51
51
  if (cliArgs.length === 0 || (cliArgs.length === 1 && (cliArgs[0] === "--help" || cliArgs[0] === "-h"))) {
52
- console.log(renderCliHelp(packageVersion));
52
+ await writeCliOutput(process.stdout, `${renderCliHelp(packageVersion)}\n`);
53
53
  return;
54
54
  }
55
55
  process.exitCode = await runCliCommand(cliArgs);
56
56
  }
57
- main().catch((err) => {
58
- logErrorWithCause("Fatal error:", err, { mirrorToDebugLog: false });
59
- process.exit(1);
57
+ await main().catch(async (err) => {
58
+ await writeCliOutput(process.stderr, `${formatErrorWithCause("Fatal error:", err)}\n`);
59
+ process.exitCode = 1;
60
60
  });
@@ -31,6 +31,9 @@ function stringifyUnknown(error) {
31
31
  return String(error);
32
32
  }
33
33
  }
34
+ export function formatErrorWithCause(message, error) {
35
+ return `${message} ${stringifyUnknown(error)}`;
36
+ }
34
37
  export function logInfo(message, options = {}) {
35
38
  log("info", message, options);
36
39
  }
@@ -41,6 +44,5 @@ export function logError(message, options = {}) {
41
44
  log("error", message, options);
42
45
  }
43
46
  export function logErrorWithCause(message, error, options = {}) {
44
- const details = stringifyUnknown(error);
45
- logError(`${message} ${details}`, options);
47
+ logError(formatErrorWithCause(message, error), options);
46
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/keiyaku",
3
- "version": "2.9.4",
3
+ "version": "2.9.6",
4
4
  "description": "CLI for running iterative keiyaku workflows with Codex subagents.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,7 +25,7 @@ cd .keiyaku/wt/<place> # work here yourself, or call an Ak
25
25
  keiyaku call <akuma> "fix it" # worker leaves reviewed source as a dirty tree
26
26
  # host coordinator reviews, then git -C <worktree> add/commit accepted paths
27
27
  keiyaku status # is anything stuck? what's next?
28
- keiyaku petition <<'EOF' # done: seal + settle; the oath is required
28
+ keiyaku petition - <<'EOF' # done: seal + settle; the oath is required
29
29
  ## Oath
30
30
  I fixed the flaky test; suite is green.
31
31
  EOF
@@ -33,7 +33,7 @@ EOF
33
33
  ```
34
34
 
35
35
  That's the whole loop. Skip the task when the work needs no planning:
36
- `keiyaku bind --place NAME --objective TEXT --scope GLOB --checks CHECK` (or the same as Markdown on stdin — `bind --help` shows the shape).
36
+ `keiyaku bind --place NAME --objective TEXT --scope GLOB --checks CHECK` (or the same as Markdown through `keiyaku bind -` — `bind --help` shows the shape).
37
37
 
38
38
  ## Getting oriented
39
39
 
@@ -8,9 +8,10 @@ allowed-tools: Bash(keiyaku *)
8
8
 
9
9
  Running devils. Contract lifecycle = `keiyaku-workflow` skill.
10
10
 
11
- ## Mind model
11
+ ## Core ideas
12
12
 
13
- - **profile** — a devil you can call (`keiyaku akuma ls`). Markdown file: frontmatter = provider/model config, body = its instructions. Project `.keiyaku/akuma/` > user `~/.keiyaku/akuma/` > builtin.
13
+ - **profile** — callable configuration: frontmatter selects provider/model;
14
+ Markdown body gives instructions. Project overrides user, which overrides builtin.
14
15
  - **projection** (`name/8hex`) — one live run of a devil. This is the id for `wait` / `tell` / `kill`.
15
16
  - **artifact** (`rsp_…`) — what a finished run left behind. This is the id for `revive`.
16
17
 
@@ -22,6 +23,7 @@ failed/dead state alone is not a reason to revive.
22
23
 
23
24
  ```bash
24
25
  keiyaku akuma ls # who's callable
26
+ keiyaku akuma view NAME # resolved profile + live projections
25
27
  keiyaku call NAME "do the thing" # run in foreground until it finishes
26
28
  keiyaku call NAME --wait 10m "do the thing" # bounded: after 10m you get a snapshot, it keeps running
27
29
  keiyaku call NAME --detach "do the thing" # fire and forget; note the projection id
@@ -34,19 +36,28 @@ keiyaku kill <proj-id> # stop it; record survives, revive
34
36
  keiyaku status # forgot an id? it's on the board
35
37
  ```
36
38
 
39
+ ## Configuration
40
+
41
+ ```text
42
+ <repo>/.keiyaku/akuma/<name>.md project profile
43
+ <KEIYAKU_HOME>/akuma/<name>.md user profile (normally ~/.keiyaku)
44
+ ```
45
+
46
+ Use `keiyaku akuma view NAME` to inspect the resolved source and configuration.
47
+
37
48
  ## Expectations
38
49
 
39
50
  - Omit tell's bracketed `--wait DURATION` option for silent success: exit 0,
40
51
  zero output. Supply it to perform the ordinary bounded join after acceptance.
41
52
  Silence **is** the receipt — do not re-send. Effects show up in `wait`/`status`.
42
- - Body is required for `call`/`tell`. Piping stdin without a literal `-` does nothing.
53
+ - Body is required for `call`/`tell`. Literal `-` selects stdin; unselected
54
+ piped bytes are ignored and cannot change an argv body.
43
55
  - A `--wait`/`--timeout` expiry prints a live snapshot and exits 0 — the run continues; rejoin with `wait` anytime.
44
56
  - `wait` is repeatable: on a finished run it shows the final transcript again.
45
- - Only `--contract ADDR` attaches a new call to a contract (by place, slug, or full id). Without it, call is standalone; `--bare` remains an explicit synonym. `call` only — `revive` takes neither and follows artifact provenance.
46
57
 
47
58
  ## Occasional flags
48
59
 
49
60
  - `--incognito` — no artifact written, no revive possible (call)
50
61
  - `--effort LEVEL` — provider effort override; needs a model set (call, revive, tell)
51
- - `-C DIR` — run relative to another directory (all akuma commands)
52
- - `--repo DIR` — you almost never need this: the repo is inferred from where you stand (`-C` included). Only for the rare case where the contract ledger lives in a *different* repo. Never pass it the same value as `-C`.
62
+ - `--repo DIR` — override repository inference only when the contract ledger
63
+ lives in a different repository.
@@ -8,22 +8,26 @@ allowed-tools: Bash(keiyaku *)
8
8
 
9
9
  Planning notes that live in the repo. Executing them is `keiyaku-workflow` (`bind --task`).
10
10
 
11
- ## Mind model
11
+ ## Core ideas
12
12
 
13
- A task is a Markdown file in `.keiyaku/tasks/` — id `k-<12hex>`, priority 0–3 (0 highest, default 2), optional body. It has no branch and runs nothing; it's the queue you pull from. States:
13
+ A task is a tracked planning fact, not a worker or execution. Its immutable ID
14
+ is a normalized title slug with a numeric collision suffix when needed. It has
15
+ priority 0–3 (0 highest), optional body, and no branch of its own.
14
16
 
15
17
  ```
16
18
  open ⇄ in_progress → done | drop
17
19
  ```
18
20
 
19
- **Ready** = open + every `needs` dependency done. Ready is computed for you — `status` and `task ls` surface it.
21
+ **Ready** = open + every `needs` dependency satisfied. `needs` only orders
22
+ tasks; binding is what turns ready planning facts into one executable contract.
20
23
 
21
24
  ## Common usage
22
25
 
23
26
  ```bash
24
- keiyaku task add "fix the flaky pump test" # body: pipe stdin for details
27
+ keiyaku task add - < task.md # literal - reads the task body from stdin
25
28
  keiyaku task add "title" --pri 1 --needs k-aaa # priority + dependency at birth
26
- keiyaku task ls # all open, priority order
29
+ keiyaku task ls # all nonterminal tasks
30
+ keiyaku task ls --filter state=ready --sort priority,modified
27
31
  keiyaku task show k-xxxx # full detail and parent-children tree
28
32
  keiyaku task start k-xxxx # mark in_progress (start ≠ execute)
29
33
  keiyaku task stop k-xxxx # back to open
@@ -41,10 +45,15 @@ keiyaku task doctor # check board integrity
41
45
  ## Promoting to a contract
42
46
 
43
47
  ```bash
44
- keiyaku bind --task k-xxxx
48
+ keiyaku bind --task fix-parser
49
+ keiyaku bind --task fix-parser --task fix-parser-help - < contract.md
45
50
  ```
46
51
 
47
- Only a **ready** task binds. in_progress → `task stop` first; blocked → finish its needs first. Binding links the task to the contract; the contract's intent you still write yourself — the title doesn't auto-expand into a spec.
52
+ Only ready tasks bind. Multi-bind only when the tasks describe one delivery
53
+ intent, share a coherent write surface, and should settle together; otherwise
54
+ keep separate contracts and express order with task `needs` or contract
55
+ `--after`. The first task supplies name/objective defaults; provide a partial
56
+ bind document for any missing `Scope` or `Checks`.
48
57
 
49
58
  ## Gotcha
50
59
 
@@ -8,9 +8,15 @@ allowed-tools: Bash(keiyaku *)
8
8
 
9
9
  How a contract lives. Running akuma is the `keiyaku-akuma` skill; task planning is `keiyaku-task`.
10
10
 
11
- ## Mind model
11
+ ## Core ideas
12
12
 
13
- A contract = one branch + one linked worktree + a ledger (its record file in the repo). A sandbox worker edits and tests inside that worktree, then hands the host coordinator an uncommitted dirty tree plus its changed-file and check report. The host reviews and commits accepted bytes before running workflow verbs that seal or rewrite delivery. States:
13
+ - A contract is one delivery intent with one ledger, branch, and linked worktree.
14
+ - Workers edit and test; the host reviews their dirty tree and commits accepted bytes.
15
+ - `audit` reads one pinned candidate. `petition` is the settlement action.
16
+ - Scope is an audit boundary, not a write lock. Amend changed intent before delivery.
17
+ - An arc is a named story chapter for one coherent stretch inside the contract.
18
+
19
+ Lifecycle:
14
20
 
15
21
  ```
16
22
  bound → active → petitioned → claimed | forfeited
@@ -21,9 +27,10 @@ bound → active → petitioned → claimed | forfeited
21
27
  ```bash
22
28
  keiyaku bind --place fix-pump --objective "make the pump test pass" \
23
29
  --scope "src/pump/**" --checks "pump tests green"
24
- # or the same four fields as Markdown: keiyaku bind < contract.md
30
+ # or the same four fields as Markdown: keiyaku bind - < contract.md
25
31
  # (# <name> / ## Objective / ## Scope / ## Checks)
26
- # or promote a ready task: keiyaku bind --task k-xxxx
32
+ # or promote one or more ready tasks:
33
+ keiyaku bind --task fix-parser --task fix-parser-help - < contract.md
27
34
 
28
35
  cd .keiyaku/wt/fix-pump # worker edits/tests here and leaves a dirty tree
29
36
 
@@ -31,7 +38,10 @@ cd .keiyaku/wt/fix-pump # worker edits/tests here and leaves a dirty tr
31
38
  git -C .keiyaku/wt/fix-pump add -- <accepted-paths>
32
39
  git -C .keiyaku/wt/fix-pump commit -m "fix pump"
33
40
 
34
- keiyaku petition <<'EOF'
41
+ # Rehearse the exact pinned delivery before settlement:
42
+ keiyaku @fix-pump audit
43
+
44
+ keiyaku petition - <<'EOF'
35
45
  ## Oath
36
46
  I made the pump test pass; ran the suite, all green.
37
47
  EOF
@@ -41,37 +51,62 @@ EOF
41
51
  # The oath is required (OATH_MISSING otherwise) and checked for presence, not content.
42
52
  ```
43
53
 
54
+ A task is optional planning, not a prerequisite. Bind directly for new work;
55
+ use `--task` only when promoting existing tracked planning into this contract.
56
+
44
57
  That's the whole small case: bind → worker dirty-tree handoff → host review/commit → petition.
45
58
 
46
- Commissioned workers never run `git add`, `git commit`, or another command that writes Git metadata. Codex workspace-write deliberately keeps `.git` and a linked worktree's resolved gitdir read-only; adding either location to writable roots is not an authorization mechanism. A worker-side Git metadata refusal is therefore not failed delivery. The host coordinator alone commits accepted bytes with native Git, then continues `arc`, `renew`, or `petition`.
59
+ Multi-bind tasks only when they are evidence for the same delivery intent, share
60
+ one coherent write surface, and should settle together. This reduces competing
61
+ contracts/worktrees; it does not replace `needs` or contract `--after` ordering.
62
+
63
+ `audit` is read-only and never invokes an Akuma or settles the contract. Exit 0
64
+ means it constructed the report, not that the candidate is acceptable. Use
65
+ `--diff-budget BYTES` for bounded output and `--json` for complete typed facts.
66
+
67
+ Commissioned workers never write Git metadata. The host alone reviews and
68
+ commits accepted bytes before `arc`, `renew`, or `petition`.
69
+
70
+ Dispatch rule: every time a dispatcher sends a worker, whether through
71
+ `keiyaku call` or any other agent tool, the prompt must explicitly tell that
72
+ worker to read the worktree-root `.keiyaku/KEIYAKU.md` first and follow its
73
+ objective, scope, and checks. The file is the contract-body carrier; do not
74
+ copy its rendered body into a dispatch prompt.
47
75
 
48
76
  ## Mid-flight commands (use when needed, skip otherwise)
49
77
 
50
78
  ```bash
51
- keiyaku arc < arc.md # optional iteration boundary: seals the current intent, opens
79
+ keiyaku arc - < arc.md # optional iteration boundary: seals the current intent, opens
52
80
  # the next. Markdown: # <title> / ## Objective / ## Brief.
53
81
  # Only needed when one contract has multiple distinct pushes.
54
82
  keiyaku renew # main moved under you → rebase onto it. Refuses on conflict
55
83
  # instead of guessing; resolve, then renew again.
56
- keiyaku amend < amendment.md # scope/checks changed → update the paper before the code
84
+ keiyaku amend - < amendment.md # scope/checks changed → update the paper before the code
85
+ # Scope terms can be appended durably during a lifecycle operation:
86
+ keiyaku @fix-pump arc --append-scope "docs/generated/**" - < arc.md
87
+ keiyaku @fix-pump renew --append-scope "docs/generated/**"
57
88
  keiyaku log # this contract's history
58
89
  ```
59
90
 
60
91
  `amend` accepts prose plus an optional ordered scope-pattern delta:
61
92
 
62
- ```markdown
93
+ ````markdown
63
94
  Clarify the owned documentation surface.
64
95
 
65
- ## Scope Add
96
+ ## Scope Append
97
+ ```
66
98
  docs/**
67
99
  !docs/generated/**
68
100
  ```
101
+ ````
69
102
 
70
- `Scope Add` appends patterns to the contract; it is not set-union semantics.
71
- Patterns retain ordered Git-ignore behavior, so a later `!pattern` excludes a
72
- previous match and can narrow the effective scope.
103
+ `Scope Append` appends ordered raw gitignore-subset lines in one column-zero
104
+ backtick fence; `Scope Add` and Markdown bullets are rejected. A later
105
+ `!pattern` can narrow earlier scope. Use `--append-scope PATTERN` when a
106
+ lifecycle operation discovers one durable term.
73
107
 
74
108
  Gotchas:
109
+ - `-C DIR` selects the effective working directory; repository discovery starts there.
75
110
  - Base drift blocks petition — if main moved, `renew` first; petition tells you.
76
111
  - After an explicit `arc` seals, new loose commits need another `arc` before `renew`/`petition` accept them.
77
112
  - Not in the worktree? Address a contract with `--contract ADDR` (place, slug, or full id) or the `keiyaku @addr <verb>` prefix.