@kylecheng3146/agent-ops 0.1.5 → 0.1.7

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 (49) hide show
  1. package/README.md +104 -6
  2. package/dist/packages/cli/src/args.js +33 -1
  3. package/dist/packages/cli/src/bin.js +40 -3
  4. package/dist/packages/cli/src/cli.js +13 -2
  5. package/dist/packages/cli/src/codex-loop-process.js +70 -0
  6. package/dist/packages/cli/src/commands/hook.js +16 -1
  7. package/dist/packages/cli/src/commands/init.js +4 -1
  8. package/dist/packages/cli/src/commands/review.js +97 -10
  9. package/dist/packages/cli/src/commands/update.js +3 -0
  10. package/dist/packages/cli/src/context.js +60 -0
  11. package/dist/packages/cli/src/hook-process.js +128 -15
  12. package/dist/packages/cli/src/loop-entry.js +8 -0
  13. package/dist/packages/cli/src/version.js +1 -1
  14. package/dist/packages/cli/src/wizard.js +71 -7
  15. package/dist/runtime/src/adapters/claude/config.js +57 -11
  16. package/dist/runtime/src/adapters/claude/events.js +7 -0
  17. package/dist/runtime/src/adapters/claude/output.js +2 -1
  18. package/dist/runtime/src/adapters/codex/config.js +39 -4
  19. package/dist/runtime/src/adapters/codex/events.js +7 -0
  20. package/dist/runtime/src/config/merge.js +17 -2
  21. package/dist/runtime/src/fs/managed-block.js +35 -18
  22. package/dist/runtime/src/hooks/codex-loop.js +439 -0
  23. package/dist/runtime/src/install/codex-loop.js +139 -0
  24. package/dist/runtime/src/install/doctor.js +108 -9
  25. package/dist/runtime/src/install/harness.js +8 -10
  26. package/dist/runtime/src/install/ownership.js +37 -2
  27. package/dist/runtime/src/install/plan.js +81 -9
  28. package/dist/runtime/src/install/profiles.js +5 -3
  29. package/dist/runtime/src/install/uninstall.js +1 -1
  30. package/dist/runtime/src/install/update.js +5 -1
  31. package/dist/runtime/src/logging/local-log.js +25 -0
  32. package/dist/runtime/src/review/execute.js +120 -0
  33. package/dist/runtime/src/review/extract.js +71 -0
  34. package/dist/runtime/src/review/invocation.js +52 -0
  35. package/dist/runtime/src/review/probe.js +48 -0
  36. package/dist/runtime/src/review/result.js +2 -2
  37. package/dist/runtime/src/review/roles.js +35 -0
  38. package/dist/runtime/src/review/runner.js +38 -4
  39. package/dist/runtime/src/schema/validate.js +70 -1
  40. package/dist/runtime/src/task/service.js +40 -0
  41. package/docs/en/guides/configuration.md +138 -2
  42. package/docs/en/spec/harness-adapters.md +50 -12
  43. package/docs/en/spec/review.md +37 -4
  44. package/docs/zh-TW/guides/configuration.md +126 -5
  45. package/docs/zh-TW/spec/harness-adapters.md +44 -12
  46. package/docs/zh-TW/spec/review.md +33 -3
  47. package/package.json +1 -1
  48. package/schemas/config.schema.json +30 -1
  49. package/schemas/manifest.schema.json +12 -1
@@ -23,12 +23,143 @@ configured with `$OPENCODE_CONFIG_DIR`, the plugin is placed under its
23
23
  `plugins/` directory instead. The installer discovers writable harness
24
24
  surfaces and applies the selected target policy; use
25
25
  `--hook-target <harness>=<surface-id>` when the managed default is not the
26
- intended surface. Project-local Claude settings require that explicit target.
26
+ intended surface. Project-local Claude hooks use `.claude/settings.json` by
27
+ default; select `.claude/settings.local.json` explicitly when that is the
28
+ intended surface.
27
29
  Advisory and guardrail hooks are registered only when the selected profile
28
30
  implies them. Advisory runs through the real SessionStart path and is
29
31
  fail-open. Claude and Codex lifecycle support is `supported`; OpenCode begins
30
32
  at app initialization and is honestly reported as `degraded`.
31
33
 
34
+ ### External review targets
35
+
36
+ `agent-ops review` can call another agent CLI to review your work. It is
37
+ disabled by default: an absent `reviewRoles` field, an absent
38
+ `--review-target` flag, and the interactive question's default all mean off.
39
+ Enable it during `agent-ops init`, or by hand:
40
+
41
+ ```json
42
+ {
43
+ "reviewRoles": [
44
+ { "role": "independent-review", "targets": ["codex", "agy"] }
45
+ ]
46
+ }
47
+ ```
48
+
49
+ `targets` is an **ordered fallback chain**. Supported targets and the read-only
50
+ flags they are launched with:
51
+
52
+ | Target | Invocation | Read-only |
53
+ | --- | --- | --- |
54
+ | `codex` | `codex exec` | `-s read-only` |
55
+ | `agy` (Antigravity) | `agy -p` | `--sandbox --mode plan` |
56
+ | `claude` | `claude -p` | `--permission-mode plan` |
57
+
58
+ `opencode` is **not** a review target even though it is a supported harness.
59
+ Its `--agent plan` is rejected as a subagent and silently falls back to a
60
+ writable agent, so it cannot satisfy the read-only precondition. A target with
61
+ no read-only flag is skipped rather than run unsandboxed.
62
+
63
+ The chain advances only when no review happened — the executable is missing,
64
+ the spawn failed, or the attempt timed out (120s per target by default,
65
+ overridable with `timeoutMs`). A `FAIL` verdict is **terminal**: the chain
66
+ never retries another target after a real verdict, because that would be
67
+ automated review shopping. Unparseable output is terminal too, since it points
68
+ at a prompt or CLI-version mismatch worth surfacing.
69
+
70
+ If Claude Code is the host (`CLAUDECODE` is set), `claude` is moved to the end
71
+ of the chain. It still runs when it is the only configured target, with a
72
+ `reviewer == host` warning.
73
+
74
+ Criterion descriptions come from the task bound to the current session, so a
75
+ review needs an attached task; `--criterion` filters those ids. Results are
76
+ appended to the task's evidence with a `review:<target>:` prefix, and only
77
+ while the task is active — a completed task is printed, never rewritten.
78
+
79
+ `--yes` is still required for every review run: init selection decides which
80
+ targets are permitted, `--yes` decides whether to spend money now.
81
+
82
+ Because target authentication is not sniffed from stderr, an unauthenticated
83
+ CLI surfaces as one review failure. Diagnose it with:
84
+
85
+ ```bash
86
+ agent-ops doctor # presence only: no tokens, no network
87
+ agent-ops doctor --check-auth # one real print call per target
88
+ ```
89
+
90
+ `--check-auth` is a dedicated flag; `--yes` stays inert for doctor. Doctor
91
+ reports what to do but never fixes it: every target authenticates through
92
+ interactive OAuth, so there is no `--fix`. Run `<target> login` yourself.
93
+
94
+ ### Project-local loop profile
95
+
96
+ `--profile loop` is an opt-in project-scope profile. Select `codex`, `claude`,
97
+ or both (for example, `--harness codex,claude`); it requires a
98
+ POSIX-compatible `bash` and does not support Windows launchers yet. Start with
99
+ a dry run:
100
+
101
+ ```bash
102
+ agent-ops init --dry-run --scope project --harness codex,claude --profile loop --json
103
+ agent-ops init --scope project --harness codex,claude --profile loop --yes
104
+ ```
105
+
106
+ For each selected supported harness, agent-ops owns exactly one small launcher:
107
+ `.codex/hooks/agent-ops-loop.sh` or `.claude/hooks/agent-ops-loop.sh`. Both
108
+ launchers delegate to the same installed Node runtime, so they do not copy a
109
+ project-specific loop script. Codex also gets `.codex/config.toml` only when it
110
+ is absent. First installation seeds, without replacing existing content,
111
+ `loop-goal.md`, `loop-state.md`, and `loop-telemetry.jsonl` under the selected
112
+ harness directory. A hash-commented `.gitignore` block ignores those local
113
+ files.
114
+
115
+ The loop runs `SessionStart`, `UserPromptSubmit`, `PreToolUse`,
116
+ `PermissionRequest`, `PostToolUse`, `PreCompact`, `PostCompact`,
117
+ `SubagentStart`, and `SubagentStop`, but never adds `Stop`. It blocks only
118
+ high-confidence literal secrets in prompts or Bash commands, plus dangerous
119
+ Bash commands (including broad recursive deletion and `git reset --hard`). Codex uses its native
120
+ exit-code blocking mechanism; Claude Code receives its documented native JSON
121
+ decision shape. A `PermissionRequest`, including
122
+ `sandbox_permissions: "require_escalated"`, only records an outcome and emits
123
+ no allow or deny decision, preserving the host's normal approval flow.
124
+
125
+ Session context, telemetry, and compaction state are deliberately bounded.
126
+ Telemetry contains only timestamp, event, outcome, and rule identifier—not raw
127
+ prompts, commands, or credentials—and rotates by byte size. A pre-compaction
128
+ Git-status snapshot is redacted and written into a dedicated block in
129
+ `loop-state.md`, leaving surrounding user content intact. Installer update and
130
+ uninstall own only the launchers, native handler registrations, and exact
131
+ `.gitignore` block; goals, state, telemetry, and `config.toml` remain local
132
+ user files. If an existing `.codex/config.toml` explicitly says
133
+ `[features]` then `hooks = false`, planning stops with
134
+ `CODEX_LOOP_HOOKS_DISABLED` before any write.
135
+
136
+ Codex and Claude Code require their normal project-hook trust/review flow for
137
+ these generated handlers. The loop is a focused guardrail, not a complete
138
+ sandbox, permission bypass, or Stop-verification feature. See the [Codex hook
139
+ documentation](https://developers.openai.com/codex/config-advanced#hooks) and
140
+ the [Claude Code hook documentation](https://code.claude.com/docs/en/hooks)
141
+ before enabling it.
142
+
143
+ ### Runtime-failure safeguards
144
+
145
+ For the ordinary `guardrails` profile, `command-policy` is the only capability with a fail-closed failure mode. Claude
146
+ Code can emit its documented denial shape at native `PreToolUse` for a
147
+ classified invalid installed configuration. The managed OpenCode
148
+ `tool.execute.before` plugin can throw its documented command-policy denial or
149
+ unavailable-runtime error for its supported Bash surface. Codex is explicitly
150
+ non-enforcing (`unknown`). These are agent-ops output and plugin contracts, not
151
+ proof that a host honors a denial. `SessionStart` and `Stop` failure paths stay
152
+ fail-open for every adapter.
153
+
154
+ Claude's invalid-config fallback has four safeguards: (1) an absent project
155
+ configuration stays fail-open, so only an invalid `.agent-ops/config.json` can
156
+ reach the fallback; (2) the manifest must safely prove that the current harness
157
+ is installed; (3) a human can export `AGENT_OPS_DISABLE=1` in the shell before
158
+ launching the host to restore fail-open temporarily; and (4) a Claude Code
159
+ denial names the config path and tells the user to repair it or temporarily set
160
+ that shell variable. The variable is read only from the hook-process environment
161
+ and cannot be set in agent-ops configuration, a manifest, or managed files.
162
+
32
163
  `guardrails` installs command policy but does not enable Stop verification. Stop
33
164
  is a separate config-v2 feature and must be explicitly enabled with at least
34
165
  one confirmed command:
@@ -58,7 +189,12 @@ agent-ops update
58
189
  agent-ops trust grant
59
190
  ```
60
191
 
61
- Without `update`, doctor reports `UPDATE_REQUIRED`; without the new trust
192
+ Without `update`, doctor can report `UPDATE_REQUIRED` for registration drift.
193
+ Separately, after a toolkit upgrade or effective profile or capability change
194
+ alters an intact path-independent managed rules artifact,
195
+ `artifact-staleness` reports `DEGRADED` with `UPDATE_REQUIRED`. `agent-ops
196
+ update` regenerates the artifact and clears that result; a missing or
197
+ hash-mismatched artifact remains an `artifacts` `FAIL`. Without the new trust
62
198
  grant, trust-gated hooks remain stale. Stop is report-only: it continues the
63
199
  harness for `PASS`, `FAIL`, or `UNKNOWN`, emits only bounded command ID, exit
64
200
  code, test-count, config-hash, and timestamp evidence, and never completes a
@@ -2,8 +2,11 @@
2
2
 
3
3
  OpenCode plugin behavior in this document was checked against the [official
4
4
  plugin documentation](https://opencode.ai/docs/plugins/) and [Bun shell
5
- documentation](https://bun.sh/docs/runtime/shell) on 2026-07-31. Revalidate:
6
- when either vendor reference changes.
5
+ documentation](https://bun.sh/docs/runtime/shell) on 2026-07-31. Codex and
6
+ Claude Code loop-hook behavior was checked against their [Codex hook
7
+ documentation](https://developers.openai.com/codex/config-advanced#hooks) and
8
+ [Claude Code hook documentation](https://code.claude.com/docs/en/hooks) on
9
+ 2026-08-03. Revalidate: when any vendor reference changes.
7
10
 
8
11
  ## HARNESS-ADAPTER-001
9
12
 
@@ -42,18 +45,19 @@ capabilities and MUST track generated source as one whole-file artifact.
42
45
 
43
46
  The opencode shim MUST invoke the absolute runtime path from the selected
44
47
  project directory, MUST fail open for
45
- advisory events, and MUST fail closed for command-policy events when the
48
+ advisory events, and MUST throw its documented command-policy error when the
46
49
  runtime is unavailable.
47
50
 
48
51
  - Trigger: The generated plugin invokes `agent-ops` or receives an invalid runtime decision.
49
52
  - Action: Keep normalization and native output encoding in the runtime adapter,
50
- throw the policy reason for a deny decision, and run lifecycle-summary through
51
- the shared advisory implementation. App-scoped plugin initialization remains
52
- degraded for per-session lifecycle fidelity.
53
+ throw its documented policy reason for a deny decision, and run
54
+ lifecycle-summary through the shared advisory implementation. App-scoped
55
+ plugin initialization remains degraded for per-session lifecycle fidelity.
53
56
  - Evidence: Shim import tests cover allow, deny, and missing-runtime behavior;
54
- doctor reports OpenCode lifecycle support as `DEGRADED`.
55
- - Positive: `A missing runtime does not block SessionStart but blocks a bash tool before execution.`
56
- - Negative: `Fall back to a PATH-resolved agent-ops executable or claim app initialization is a per-session Stop-equivalent.`
57
+ denial fixtures assert output shape only; doctor reports OpenCode lifecycle
58
+ support as `DEGRADED`.
59
+ - Positive: `When the runtime is unavailable, SessionStart stays fail-open and the generated plugin throws its documented command-policy error for a Bash pre-tool hook.`
60
+ - Negative: `Fall back to a PATH-resolved agent-ops executable, claim an OpenCode host honors a thrown denial, or claim app initialization is a per-session Stop-equivalent.`
57
61
 
58
62
  ## HARNESS-ADAPTER-005
59
63
 
@@ -67,11 +71,31 @@ decoding, normalized events, native output encoding, and runtime-failure output.
67
71
  including its support level and runtime-failure mode; do not add native
68
72
  events to a universal union.
69
73
  - Evidence: Every declared `supported` registration is exercised through the
70
- real CLI hook process, and unsupported Stop/lifecycle registrations are not
71
- reported as enforcement success.
72
- - Positive: `Claude command-policy reaches a native PreToolUse denial through runHookCommand.`
74
+ real CLI hook process; denial-shape fixtures assert documented wire shapes,
75
+ not host runtime enforcement; unsupported Stop/lifecycle registrations are
76
+ not reported as enforcement success.
77
+ - Positive: `A fail-closed Claude command-policy runtime failure produces the documented PreToolUse denial shape through runHookCommand.`
73
78
  - Negative: `Mark SessionStart supported while dispatchHookEvent has no advisory implementation.`
74
79
 
80
+ ## HARNESS-ADAPTER-006
81
+
82
+ The project-local `loop` profile MUST be opt-in, project scoped, and use one
83
+ shared runtime behind minimal Codex and Claude Code launchers. It MUST NOT copy
84
+ policy into project-specific scripts or alter an ordinary permission request.
85
+
86
+ - Trigger: A project selects `loop` with Codex, Claude Code, or both.
87
+ - Action: Generate only the selected `.codex/hooks/agent-ops-loop.sh` and/or
88
+ `.claude/hooks/agent-ops-loop.sh` launchers, register the documented loop
89
+ lifecycle events except `Stop`, and preserve foreign hook groups. Block only
90
+ high-confidence literal credentials at `UserPromptSubmit` or Bash
91
+ `PreToolUse`, and dangerous Bash commands at `PreToolUse`, using the documented native denial shape. Emit no
92
+ decision for `PermissionRequest`, including escalated permissions.
93
+ - Evidence: Install-plan, loop-runtime, update, uninstall, and doctor tests
94
+ cover generated paths, Codex/Claude wire output, privacy bounds,
95
+ configuration conflict handling, state preservation, and registration drift.
96
+ - Positive: `A Claude PreToolUse dangerous Bash command receives a native deny while a PermissionRequest produces no allow or deny decision.`
97
+ - Negative: `Copy a project loop policy into both shell launchers, auto-approve sandbox escalation, or add a loop Stop handler.`
98
+
75
99
  The current registration matrix is intentionally asymmetric:
76
100
 
77
101
  | Capability | Codex | Claude Code | OpenCode |
@@ -80,6 +104,20 @@ The current registration matrix is intentionally asymmetric:
80
104
  | command-policy | unknown | supported | supported |
81
105
  | optional-stop-verify | unsupported | supported | degraded |
82
106
 
107
+ For runtime-failure handling, only `command-policy` is fail-closed. Claude
108
+ Code can emit its documented `PreToolUse` denial shape for a classified invalid
109
+ installed configuration; the managed OpenCode `tool.execute.before` plugin can
110
+ throw its documented denial or unavailable-runtime error for its supported Bash
111
+ surface. Codex remains `unknown` and never emits a denial. Fixture tests assert
112
+ these wire and plugin shapes only; they do not prove that a host honors a
113
+ denial. Every `SessionStart` and `Stop` failure path remains fail-open.
114
+
83
115
  Stop verification is explicit, trusted, report-only, and disabled by default.
84
116
  Every Stop result continues the native harness and may carry only bounded
85
117
  command evidence; it is never task-completion evidence.
118
+
119
+ The `loop` profile is separate from the ordinary capability matrix above. It
120
+ stores only bounded local event metadata, returns bounded redacted session
121
+ context, and preserves local goal, state, telemetry, and Codex TOML files on
122
+ update or uninstall. A clearly parsed `[features]` / `hooks = false` in an
123
+ existing Codex configuration MUST reject loop planning before any write.
@@ -22,11 +22,44 @@ A review result MUST preserve PASS, FAIL, or NOT_RUN and MUST NOT convert NOT_RU
22
22
 
23
23
  ## REVIEW-HARNESS-001
24
24
 
25
- A review invocation MUST resolve to exactly one concrete harness, even when an
26
- installation supports multiple harnesses.
25
+ A review invocation MUST resolve to exactly one concrete review target, even
26
+ when an installation supports multiple harnesses.
27
27
 
28
28
  - Trigger: Running `review` with a harness selection.
29
- - Action: Select one of `codex`, `claude`, or `opencode`; keep multi-harness installation separate from review execution.
29
+ - Action: Select one of `codex`, `agy`, or `claude`; keep multi-harness installation separate from review execution.
30
30
  - Evidence: Argument parsing rejects `all`, `both`, and comma-separated multi-harness values for review.
31
- - Positive: `review --harness opencode` resolves one harness.
31
+ - Positive: `review --harness claude` resolves one target.
32
32
  - Negative: `Run one review invocation against every installed harness implicitly.`
33
+
34
+ ## REVIEW-READONLY-001
35
+
36
+ A review target MUST be launched with its own read-only mechanism, and a target
37
+ without one MUST be skipped rather than run unsandboxed.
38
+
39
+ - Trigger: Building a review invocation for a configured target.
40
+ - Action: Pass `-s read-only` (codex), `--sandbox --mode plan` (agy), or `--permission-mode plan` (claude); treat any other target as ineligible.
41
+ - Evidence: The spawned argv contains the target's read-only flags.
42
+ - Positive: `opencode is not a review target: --agent plan silently falls back to a writable agent.`
43
+ - Negative: `Trust the prompt to stop the reviewer from editing files.`
44
+
45
+ ## REVIEW-CHAIN-001
46
+
47
+ Configured targets form an ordered fallback chain that MUST advance only when
48
+ no review happened, and MUST NOT advance past a verdict.
49
+
50
+ - Trigger: A configured target is missing, fails to spawn, or times out.
51
+ - Action: Try the next target; on PASS, FAIL, or unparseable output, stop and report that outcome.
52
+ - Evidence: The number of spawned attempts matches the failures that preceded the verdict.
53
+ - Positive: `codex FAIL is final; agy is never asked for a second opinion.`
54
+ - Negative: `Retry other targets after a FAIL until one reports PASS.`
55
+
56
+ ## REVIEW-CONTRACT-001
57
+
58
+ A response that breaks the reply contract MUST be reported as NOT_RUN, not as
59
+ FAIL.
60
+
61
+ - Trigger: The reviewer omits, duplicates, or invents a criterion, or returns blank evidence.
62
+ - Action: Report `NOT_RUN` with reason `unparseable-output`, write no evidence, and keep FAIL for judged inadequacy.
63
+ - Evidence: The result reason distinguishes a protocol violation from a verdict.
64
+ - Positive: `NOT_RUN: unparseable-output; one criterion was missing.`
65
+ - Negative: `Record a failed review because the model's JSON was malformed.`
@@ -21,11 +21,128 @@ User scope 下,Codex 與 opencode 的 routing file 分別位於 `.codex/` 與
21
21
  `$OPENCODE_CONFIG_DIR`,則 plugin 會放在其 `plugins/` 目錄。只有 profile
22
22
  有暗示時才會註冊 advisory 與 guardrail hook。Installer 會 discovery 可寫入的
23
23
  harness surface 並套用選定的 target policy;若不是 managed default,請使用
24
- `--hook-target <harness>=<surface-id>` 明確選擇。Project-local Claude settings
25
- 必須明確指定 target。Advisory 會經由真正的 SessionStart path 執行並 fail-open;
24
+ `--hook-target <harness>=<surface-id>` 明確選擇。Project-local Claude hook 預設
25
+ 使用 `.claude/settings.json`;只有要使用 `.claude/settings.local.json` 時才需
26
+ 明確選擇。Advisory 會經由真正的 SessionStart path 執行並 fail-open;
26
27
  Claude 與 Codex lifecycle support 為 `supported`,OpenCode 從 app initialization
27
28
  開始,因此誠實標示為 `degraded`。
28
29
 
30
+ ### 外部 review 目標
31
+
32
+ `agent-ops review` 可以呼叫另一個 agent CLI 來審查你的工作。預設關閉 ——
33
+ 缺少 `reviewRoles` 欄位、缺少 `--review-target` 旗標、互動式問題的預設值,
34
+ 三者都代表關閉。在 `agent-ops init` 時啟用,或手動設定:
35
+
36
+ ```json
37
+ {
38
+ "reviewRoles": [
39
+ { "role": "independent-review", "targets": ["codex", "agy"] }
40
+ ]
41
+ }
42
+ ```
43
+
44
+ `targets` 是**有序的後備鏈**。支援的目標與其唯讀旗標:
45
+
46
+ | 目標 | 呼叫方式 | 唯讀 |
47
+ | --- | --- | --- |
48
+ | `codex` | `codex exec` | `-s read-only` |
49
+ | `agy`(Antigravity)| `agy -p` | `--sandbox --mode plan` |
50
+ | `claude` | `claude -p` | `--permission-mode plan` |
51
+
52
+ `opencode` **不是** review 目標,即使它是支援的 harness。它的 `--agent plan`
53
+ 會被判定為 subagent 而遭拒,並靜默退回可寫入的 agent,因此無法滿足唯讀前置
54
+ 條件。沒有唯讀旗標的目標會被跳過,不會在無沙箱狀態下執行。
55
+
56
+ 只有在「根本沒審到」時才換下一家 —— 執行檔不存在、spawn 失敗、或逾時
57
+ (每個目標預設 120 秒,可用 `timeoutMs` 覆寫)。`FAIL` 判定是**終局**:
58
+ 拿到真實判定後絕不再試下一家,否則就變成自動化的 review shopping。
59
+ 無法解析的輸出同樣終局,因為那代表 prompt 約定或 CLI 版本不合,該浮出來修。
60
+
61
+ 若 host 是 Claude Code(`CLAUDECODE` 已設定),`claude` 會被移到鏈尾。
62
+ 當它是唯一設定的目標時仍會執行,並附上 `reviewer == host` 警告。
63
+
64
+ criterion 描述來自當前 session 綁定的 task,所以 review 需要已附加的 task;
65
+ `--criterion` 用來篩選這些 id。結果會以 `review:<target>:` 前綴附加到 task 的
66
+ evidence,且僅在 task 為 active 時寫入 —— 已完成的 task 只印出,絕不改寫。
67
+
68
+ 每次執行 review 仍需 `--yes`:init 的勾選決定「允許哪些目標」,
69
+ `--yes` 決定「現在是否要花錢」。
70
+
71
+ 因為不從 stderr 嗅探認證狀態,未登入的 CLI 會表現為一次 review 失敗。
72
+ 用以下指令診斷:
73
+
74
+ ```bash
75
+ agent-ops doctor # 只驗執行檔存在:零 token、零網路
76
+ agent-ops doctor --check-auth # 每個目標一次真實 print 呼叫
77
+ ```
78
+
79
+ `--check-auth` 是專屬旗標;`--yes` 對 doctor 維持惰性。doctor 只回報該做什麼,
80
+ 不會代為修復:所有目標都經由互動式 OAuth 認證,因此沒有 `--fix`。
81
+ 請自行執行 `<target> login`。
82
+
83
+ ### Project-local loop profile
84
+
85
+ `--profile loop` 是明確 opt-in 的 project-scope profile。請選擇 `codex`、
86
+ `claude` 或兩者(例如 `--harness codex,claude`);它需要 POSIX-compatible
87
+ `bash`,目前尚未支援 Windows launcher。建議先 dry run:
88
+
89
+ ```bash
90
+ agent-ops init --dry-run --scope project --harness codex,claude --profile loop --json
91
+ agent-ops init --scope project --harness codex,claude --profile loop --yes
92
+ ```
93
+
94
+ 對每個選定且支援的 harness,agent-ops 只擁有一個小型 launcher:
95
+ `.codex/hooks/agent-ops-loop.sh` 或 `.claude/hooks/agent-ops-loop.sh`。兩個
96
+ launcher 都委派給同一個已安裝的 Node runtime,因此不會複製 project-specific
97
+ loop script。Codex 只會在 `.codex/config.toml` 不存在時建立它。首次安裝會在不
98
+ 覆寫既有內容的前提下,於選定 harness directory 建立 `loop-goal.md`、
99
+ `loop-state.md` 與 `loop-telemetry.jsonl`;並以 hash-commented `.gitignore`
100
+ block 忽略這些 local file。
101
+
102
+ Loop 會執行 `SessionStart`、`UserPromptSubmit`、`PreToolUse`、
103
+ `PermissionRequest`、`PostToolUse`、`PreCompact`、`PostCompact`、
104
+ `SubagentStart` 與 `SubagentStop`,但永遠不加入 `Stop`。它只攔截
105
+ high-confidence 的 literal secret prompt 或 Bash command,以及危險 Bash command
106
+ (包括 broad recursive deletion 與 `git reset --hard`)。Codex 使用原生 exit-code blocking
107
+ mechanism;Claude Code 則取得文件化的 native JSON decision shape。
108
+ `PermissionRequest`(包括 `sandbox_permissions: "require_escalated"`)只記錄
109
+ outcome,不會輸出 allow 或 deny decision,因此 host 原本的 approval flow 保持
110
+ 權威。
111
+
112
+ Session context、telemetry 與 compaction state 都受到明確上限。Telemetry 只含
113
+ timestamp、event、outcome 與 rule identifier,不會存 raw prompt、command 或
114
+ credential,並依 byte size rotation。PreCompact 的 Git-status snapshot 會先
115
+ redact,再寫入 `loop-state.md` 的專用 block,周圍的 user content 保持不變。
116
+ installer update 與 uninstall 只管理 launcher、native handler registration 與
117
+ 精確的 `.gitignore` block;goal、state、telemetry 與 `config.toml` 都保留為 local
118
+ user file。若既有 `.codex/config.toml` 明確寫有 `[features]` 後的
119
+ `hooks = false`,planning 會在任何 write 之前以
120
+ `CODEX_LOOP_HOOKS_DISABLED` 停止。
121
+
122
+ Codex 與 Claude Code 對這些 generated handler 仍須走各自正常的 project-hook
123
+ trust/review flow。Loop 是聚焦的 guardrail,不是完整 sandbox、permission bypass
124
+ 或 Stop-verification feature。啟用前請閱讀 [Codex hook
125
+ 文件](https://developers.openai.com/codex/config-advanced#hooks)與 [Claude Code
126
+ hook 文件](https://code.claude.com/docs/en/hooks)。
127
+
128
+ ### Runtime-failure 保護措施
129
+
130
+ 對一般 `guardrails` profile 而言,只有 `command-policy` 具有 fail-closed failure mode。當已安裝的 config 被分類
131
+ 為無效時,Claude Code 可在原生 `PreToolUse` 輸出文件化的 denial shape。受管理的
132
+ OpenCode `tool.execute.before` plugin 可在其支援的 Bash surface
133
+ 上 throw 文件化的 command-policy denial 或 unavailable-runtime error。Codex 明確
134
+ 不執行強制措施(`unknown`)。這些是 agent-ops 的 output 與 plugin contract,不
135
+ 證明 host 會實際遵守 denial。所有 adapter 的 `SessionStart` 與 `Stop` failure path
136
+ 都維持 fail-open。
137
+
138
+ Claude 的無效 config fallback 有四項防護:(1) 缺少 project configuration 時保持
139
+ fail-open,因此只有無效的 `.agent-ops/config.json` 能進入 fallback;(2) manifest
140
+ 必須安全地證明目前 harness 已安裝;(3) 使用者可在啟動 host 前於 shell export
141
+ `AGENT_OPS_DISABLE=1`,暫時恢復 fail-open;(4) Claude Code denial 會列出 config
142
+ path,並告知使用者修正它或暫時設定該 shell variable。此 variable 只從
143
+ hook-process environment 讀取,不能由 agent-ops configuration、manifest 或
144
+ managed file 設定。
145
+
29
146
  `guardrails` 只安裝 command policy,不會啟用 Stop verification。Stop 是獨立的
30
147
  config v2 feature,必須明確啟用且至少提供一個已確認的 command:
31
148
 
@@ -54,9 +171,13 @@ agent-ops update
54
171
  agent-ops trust grant
55
172
  ```
56
173
 
57
- 未執行 `update` 時,doctor 會回報 `UPDATE_REQUIRED`;未重新 grant trust
58
- 時,trust-gated hook 仍會是 stale。Stop report-only:`PASS`、`FAIL`
59
- `UNKNOWN` 都會讓 harness 繼續,只輸出有界的 command ID、exit code、test-count、
174
+ 未執行 `update` 時,doctor 可因 registration drift 回報 `UPDATE_REQUIRED`。另
175
+ 外,toolkit upgrade effective profile capability change 使完整的
176
+ path-independent managed rules artifact 改變時,`artifact-staleness` 會回報帶有
177
+ `UPDATE_REQUIRED` 的 `DEGRADED`。`agent-ops update` 會重新產生 artifact 並清除
178
+ 這個結果;artifact 缺失或 hash 不符時,`artifacts` check 仍為 `FAIL`。未重新
179
+ grant trust 時,trust-gated hook 仍會是 stale。Stop 是 report-only:`PASS`、`FAIL`
180
+ 與 `UNKNOWN` 都會讓 harness 繼續,只輸出有界的 command ID、exit code、test-count、
60
181
  config-hash 與 timestamp evidence,且永遠不會完成 task。Config v1 會決定性遷移
61
182
  為 Stop disabled 的 v2;舊 binary 無法讀取遷移後的 config,routing migration
62
183
  一旦套用即為單向,降版前請先閱讀 release notes。
@@ -1,8 +1,8 @@
1
1
  # Harness Adapter
2
2
 
3
- English source version: 2026-07-31. Revalidate: when the English specification or either vendor reference changes.
3
+ English source version: 2026-08-03. Revalidate: when the English specification or any vendor reference changes.
4
4
 
5
- 本文件所述 OpenCode plugin 行為已於 2026-07-31 依據[官方 plugin 文件](https://opencode.ai/docs/plugins/)與[Bun shell 文件](https://bun.sh/docs/runtime/shell)檢查。
5
+ 本文件所述 OpenCode plugin 行為已於 2026-07-31 依據[官方 plugin 文件](https://opencode.ai/docs/plugins/)與[Bun shell 文件](https://bun.sh/docs/runtime/shell)檢查;Codex 與 Claude Code loop-hook 行為已於 2026-08-03 依據 [Codex hook 文件](https://developers.openai.com/codex/config-advanced#hooks) 與 [Claude Code hook 文件](https://code.claude.com/docs/en/hooks) 檢查。
6
6
 
7
7
  ## HARNESS-ADAPTER-001
8
8
 
@@ -37,17 +37,17 @@ Adapter MUST 具備冪等性,且 MUST NOT 刪除使用者擁有的 handler。
37
37
 
38
38
  ## HARNESS-ADAPTER-004
39
39
 
40
- OpenCode shim MUST 從選定的 project directory 呼叫 absolute runtime path;runtime 不可用時,MUST 對 advisory event fail open,並對 command-policy event fail closed
40
+ OpenCode shim MUST 從選定的 project directory 呼叫 absolute runtime path;runtime 不可用時,MUST 對 advisory event fail open,並 MUST throw 文件化的 command-policy error
41
41
 
42
42
  - Trigger: 產生的 plugin 呼叫 `agent-ops`,或收到無效的 runtime decision。
43
43
  - Action: 將 normalization 與 native output encoding 留在 runtime adapter;deny
44
- decision 要 throw policy reason;lifecycle-summary 經由 shared advisory
45
- implementation 執行。Plugin initialization 仍是 app-scoped 而非 per-session,
46
- 因此 per-session lifecycle fidelity 仍為 degraded。
47
- - Evidence: shim import 測試涵蓋 allow、deny 與 missing-runtime;doctor
48
- OpenCode lifecycle support 回報 `DEGRADED`。
49
- - Positive: `runtime 不可用時不阻擋 SessionStart,但會在 bash tool 執行前阻擋它。`
50
- - Negative: `退回 PATH-resolved 的 agent-ops executable,或宣稱 app initialization 等同於 per-session Stop。`
44
+ decision 要 throw 文件化的 policy reason;lifecycle-summary 經由 shared
45
+ advisory implementation 執行。Plugin initialization 仍是 app-scoped 而非
46
+ per-session,因此 per-session lifecycle fidelity 仍為 degraded。
47
+ - Evidence: shim import 測試涵蓋 allow、deny 與 missing-runtime;denial fixture
48
+ 只斷言 output shape;doctor 對 OpenCode lifecycle support 回報 `DEGRADED`。
49
+ - Positive: `runtime 不可用時,SessionStart 維持 fail-open,而生成的 plugin 會在 Bash pre-tool hook 中 throw 文件化的 command-policy error。`
50
+ - Negative: `退回 PATH-resolved 的 agent-ops executable、宣稱 OpenCode host 一定會遵守 thrown denial,或宣稱 app initialization 等同於 per-session Stop。`
51
51
 
52
52
  ## HARNESS-ADAPTER-005
53
53
 
@@ -60,10 +60,30 @@ event、native output encode 與 runtime-failure output。
60
60
  - Action: 在所屬 harness 加入 capability-to-native registration,包含 support
61
61
  level 與 runtime-failure mode;不得將 native event 加入 universal union。
62
62
  - Evidence: 每個宣告為 `supported` 的 registration 都經由真實 CLI hook process
63
- 執行,未支援的 Stop/lifecycle registration 不得回報 enforcement success。
64
- - Positive: `Claude command-policy 經由 runHookCommand 抵達 native PreToolUse denial。`
63
+ 執行;denial-shape fixture 只斷言文件化的 wire shape,不證明 host runtime
64
+ enforcement;未支援的 Stop/lifecycle registration 不得回報 enforcement success。
65
+ - Positive: `fail-closed 的 Claude command-policy runtime failure 會透過 runHookCommand 產生文件化的 PreToolUse denial shape。`
65
66
  - Negative: `dispatchHookEvent 尚未提供 advisory implementation 卻將 SessionStart 標為 supported。`
66
67
 
68
+ ## HARNESS-ADAPTER-006
69
+
70
+ Project-local `loop` profile MUST 是 opt-in、project scoped,並在最小的 Codex 與
71
+ Claude Code launcher 後使用同一個 shared runtime。它 MUST NOT 將 policy 複製到
72
+ project-specific script,也不得改變一般 permission request。
73
+
74
+ - Trigger: Project 以 Codex、Claude Code 或兩者選擇 `loop`。
75
+ - Action: 只產生選定的 `.codex/hooks/agent-ops-loop.sh` 與/或
76
+ `.claude/hooks/agent-ops-loop.sh` launcher,註冊文件化的 loop lifecycle event
77
+ (不含 `Stop`),並保留 foreign hook group。只在 `UserPromptSubmit` 或 Bash
78
+ `PreToolUse` 的 high-confidence literal credential,以及 `PreToolUse` 的危險 Bash command 時,使用
79
+ 文件化的 native denial shape 進行 blocking。對 `PermissionRequest`(包括
80
+ escalated permission)不得輸出 decision。
81
+ - Evidence: Install-plan、loop-runtime、update、uninstall 與 doctor test 覆蓋
82
+ generated path、Codex/Claude wire output、privacy bound、configuration conflict
83
+ handling、state preservation 與 registration drift。
84
+ - Positive: `Claude PreToolUse 的危險 Bash command 取得 native deny,而 PermissionRequest 不產生 allow 或 deny decision。`
85
+ - Negative: `將 project loop policy 複製到兩個 shell launcher、auto-approve sandbox escalation,或加入 loop Stop handler。`
86
+
67
87
  目前 registration matrix 刻意不對稱:
68
88
 
69
89
  | Capability | Codex | Claude Code | OpenCode |
@@ -72,6 +92,18 @@ event、native output encode 與 runtime-failure output。
72
92
  | command-policy | unknown | supported | supported |
73
93
  | optional-stop-verify | unsupported | supported | degraded |
74
94
 
95
+ Runtime-failure 處理中,只有 `command-policy` 為 fail-closed。當已安裝的 config
96
+ 被分類為無效時,Claude Code 可輸出文件化的 `PreToolUse` denial shape;受管理的
97
+ OpenCode `tool.execute.before` plugin 可在其支援的 Bash surface 上 throw 文件化的
98
+ denial 或 unavailable-runtime error。Codex 維持 `unknown` 且絕不輸出 denial。
99
+ Fixture test 只斷言這些 wire 與 plugin shape;它們不證明 host 會實際遵守 denial。
100
+ 每個 `SessionStart` 與 `Stop` failure path 都維持 fail-open。
101
+
75
102
  Stop verification 必須明確啟用、具備 trust、為 report-only 且預設 disabled。
76
103
  每個 Stop 結果都會讓 native harness 繼續,最多攜帶有界 command evidence,永遠
77
104
  不是 task-completion evidence。
105
+
106
+ `loop` profile 與上方 ordinary capability matrix 分離。它只保存有界的 local
107
+ event metadata、回傳有界且 redacted 的 session context,並在 update 或 uninstall
108
+ 時保留 local goal、state、telemetry 與 Codex TOML file。既有 Codex configuration
109
+ 中清楚解析出的 `[features]` / `hooks = false` MUST 在任何 write 前拒絕 loop planning。
@@ -24,10 +24,40 @@ English source version: 2026-07-23. Revalidate: when the English specification c
24
24
 
25
25
  ## REVIEW-HARNESS-001
26
26
 
27
- 即使 installation 支援多個 harness,一次 review invocation MUST 解析成恰好一個 concrete harness
27
+ 即使 installation 支援多個 harness,一次 review invocation MUST 解析成恰好一個 concrete review target
28
28
 
29
29
  - Trigger: 使用 harness selection 執行 `review`。
30
- - Action: 從 `codex`、`claude` 或 `opencode` 中選一個;multi-harness installation 與 review execution 分開處理。
30
+ - Action: 從 `codex`、`agy` 或 `claude` 中選一個;multi-harness installation 與 review execution 分開處理。
31
31
  - Evidence: argument parsing 會拒絕 review 使用 `all`、`both` 或逗號分隔的多 harness 值。
32
- - Positive: `review --harness opencode` 解析成一個 harness
32
+ - Positive: `review --harness claude` 解析成一個 target
33
33
  - Negative: `讓一次 review invocation 隱式跑過所有已安裝 harness。`
34
+
35
+ ## REVIEW-READONLY-001
36
+
37
+ review target MUST 以其自身的唯讀機制啟動;沒有唯讀機制的 target MUST 被跳過,而非在無沙箱狀態下執行。
38
+
39
+ - Trigger: 為已設定的 target 組建 review invocation。
40
+ - Action: 傳入 `-s read-only`(codex)、`--sandbox --mode plan`(agy)或 `--permission-mode plan`(claude);其餘 target 視為不合格。
41
+ - Evidence: spawn 出的 argv 含該 target 的唯讀旗標。
42
+ - Positive: `opencode 不是 review target:--agent plan 會靜默退回可寫入的 agent。`
43
+ - Negative: `信任 prompt 能阻止審查者修改檔案。`
44
+
45
+ ## REVIEW-CHAIN-001
46
+
47
+ 已設定的 targets 組成有序後備鏈,MUST 僅在「沒有審到」時換下一家,且 MUST NOT 在取得判定後繼續往下試。
48
+
49
+ - Trigger: 某個已設定的 target 不存在、spawn 失敗或逾時。
50
+ - Action: 試下一個 target;遇到 PASS、FAIL 或無法解析的輸出即停止並回報該結果。
51
+ - Evidence: spawn 次數等於判定之前的失敗次數。
52
+ - Positive: `codex 的 FAIL 是終局;不會再問 agy 第二意見。`
53
+ - Negative: `FAIL 之後改試其他 target,直到有人回報 PASS。`
54
+
55
+ ## REVIEW-CONTRACT-001
56
+
57
+ 違反回覆約定的回應 MUST 回報為 NOT_RUN,而非 FAIL。
58
+
59
+ - Trigger: 審查者遺漏、重複或憑空新增 criterion,或給出空白 evidence。
60
+ - Action: 以 reason `unparseable-output` 回報 `NOT_RUN`,不寫入任何 evidence,並保留 FAIL 表示「經審查判定不合格」。
61
+ - Evidence: 結果的 reason 能區分協議違規與判定結果。
62
+ - Positive: `NOT_RUN:unparseable-output;缺少一條 criterion。`
63
+ - Negative: `因為模型的 JSON 格式錯誤就記錄一次失敗的審查。`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kylecheng3146/agent-ops",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Evidence-driven development loops for Codex, Claude Code, and opencode",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,7 +20,36 @@
20
20
  "type": "array",
21
21
  "uniqueItems": true,
22
22
  "items": {
23
- "enum": ["core", "advisory", "guardrails"]
23
+ "enum": ["core", "advisory", "guardrails", "loop"]
24
+ }
25
+ },
26
+ "reviewRoles": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["role", "targets"],
32
+ "properties": {
33
+ "role": {
34
+ "enum": [
35
+ "mechanical",
36
+ "implementation",
37
+ "deep-reasoning",
38
+ "independent-review"
39
+ ]
40
+ },
41
+ "targets": {
42
+ "type": "array",
43
+ "minItems": 1,
44
+ "uniqueItems": true,
45
+ "items": {
46
+ "enum": ["codex", "agy", "claude"]
47
+ }
48
+ },
49
+ "model": { "type": "string", "minLength": 1 },
50
+ "effort": { "type": "string", "minLength": 1 },
51
+ "timeoutMs": { "type": "integer", "minimum": 1 }
52
+ }
24
53
  }
25
54
  },
26
55
  "verification": {