kairos-chain 3.95.0 → 3.96.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +119 -0
  3. data/lib/kairos_mcp/capability.rb +20 -4
  4. data/lib/kairos_mcp/tools/capability_status.rb +3 -1
  5. data/lib/kairos_mcp/version.rb +1 -1
  6. data/templates/knowledge/multi_llm_review_workflow/multi_llm_review_workflow.md +125 -27
  7. data/templates/skillsets/agent/bin/agent_policy_report.rb +26 -0
  8. data/templates/skillsets/agent/config/policies/default_2026_10_20.rb +34 -0
  9. data/templates/skillsets/agent/lib/agent/hooks.rb +178 -4
  10. data/templates/skillsets/agent/lib/agent/policy_report.rb +665 -0
  11. data/templates/skillsets/agent/lib/agent/precedents.rb +5 -2
  12. data/templates/skillsets/agent/lib/agent/review.rb +185 -25
  13. data/templates/skillsets/agent/lib/agent/run.rb +1 -1
  14. data/templates/skillsets/agent/lib/agent/seats.rb +634 -0
  15. data/templates/skillsets/agent/lib/agent/service.rb +37 -4
  16. data/templates/skillsets/agent/plugin/SKILL.md +27 -5
  17. data/templates/skillsets/agent/skillset.json +6 -3
  18. data/templates/skillsets/agent/test/test_agent1_dsl.rb +5 -5
  19. data/templates/skillsets/agent/test/test_agent1_hooks_service.rb +3 -1
  20. data/templates/skillsets/agent/test/test_agent1_persona_seats.rb +850 -0
  21. data/templates/skillsets/agent/test/test_agent1_policy_report.rb +475 -0
  22. data/templates/skillsets/agent/test/test_agent1_r1_words.rb +39 -39
  23. data/templates/skillsets/agent/test/test_agent1_r3_words.rb +11 -11
  24. data/templates/skillsets/agent/test/test_agent1_r3v_guardwords.rb +11 -11
  25. data/templates/skillsets/agent/test/test_agent1_r3v_lifecycle.rb +1 -1
  26. data/templates/skillsets/agent/test/test_agent1_stand_in_precedents.rb +5 -5
  27. data/templates/skillsets/agent/test/test_agent1_v06.rb +28 -3
  28. data/templates/skillsets/agent/tools/agent_advance.rb +1 -1
  29. data/templates/skillsets/llm_client/lib/llm_client/adapter.rb +7 -2
  30. data/templates/skillsets/llm_client/lib/llm_client/call_router.rb +1 -1
  31. data/templates/skillsets/llm_client/lib/llm_client/claude_code_adapter.rb +9 -3
  32. data/templates/skillsets/llm_client/lib/llm_client/cli_failure.rb +123 -0
  33. data/templates/skillsets/llm_client/lib/llm_client/codex_adapter.rb +6 -3
  34. data/templates/skillsets/llm_client/lib/llm_client/cursor_adapter.rb +5 -3
  35. data/templates/skillsets/llm_client/skillset.json +1 -1
  36. data/templates/skillsets/llm_client/test/test_cli_failure.rb +263 -0
  37. data/templates/skillsets/llm_client/tools/llm_call.rb +1 -1
  38. data/templates/skillsets/multi_llm_review/config/multi_llm_review.yml +19 -0
  39. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/build_review_bundle.rb +8 -1
  40. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/consensus.rb +20 -4
  41. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/dispatcher.rb +5 -1
  42. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/feedback_formatter.rb +119 -1
  43. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/observer_set.rb +7 -3
  44. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/persona_assembly.rb +26 -7
  45. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/roster_health.rb +127 -0
  46. data/templates/skillsets/multi_llm_review/skillset.json +3 -3
  47. data/templates/skillsets/multi_llm_review/test/test_feedback_formatter.rb +1 -1
  48. data/templates/skillsets/multi_llm_review/test/test_non_claude_host.rb +455 -0
  49. data/templates/skillsets/multi_llm_review/test/test_tool_wiring.rb +1 -1
  50. data/templates/skillsets/multi_llm_review/tools/multi_llm_review.rb +103 -34
  51. data/templates/skillsets/multi_llm_review/tools/multi_llm_review_collect.rb +16 -11
  52. data/templates/skillsets/multi_llm_review/tools/multi_llm_review_wait.rb +24 -4
  53. metadata +11 -2
  54. data/templates/skillsets/agent/config/policies/masa_2026_10_20.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bce3f299f0bb91ecbb6199e464a2ea24602ede6e9d4e972c1a7b5905ec447c5
4
- data.tar.gz: 4986b9e4f8c87ff233b67586791d8b3068aed4decaecb1319f5c0553b4a5445c
3
+ metadata.gz: faa4327412fbbe72c412e3e4cccd41173a346e488366b0d4963023cb389ce97e
4
+ data.tar.gz: 13767304ee185463ac1a1de1293873762c3658f81e8a5c6d007023ca29970377
5
5
  SHA512:
6
- metadata.gz: a4af517774c9e5e90299d4877190d83659932acf7851bf04275d5c3066298411ca628084a490cfef6348b327d550c05d5cc4f96cab086e5c297e2a169e1f72b3
7
- data.tar.gz: ba67dc90461e4350615a4ba9e232702efc27b241fa853a2934a80714bb5753c2aa1ebba06921ebe58e4db7145d8f3fb5d747be4ab37f8ad5da25150ab8c7ce8d
6
+ metadata.gz: 657b3094d640bd4876964d3ffd88f47fd57fda12147c77d882293c68662d66a791c306d8eaae4fd4238041f641c318dc7825bb0ff6c314b2c963086146a7eb17
7
+ data.tar.gz: 2f765af6b6122a2a3627678f3481a410be0bc0f359bb7b479a6e726fe6f1891264c023d42007840d1fd75e03d175109b78a164647d6402f771322fff8a3783d6
data/CHANGELOG.md CHANGED
@@ -6,6 +6,125 @@ This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.96.1] - 2026-10-22
10
+
11
+ ### Fixed — agent runs convene the persona seat their reviews declared none for (agent 1.0.2)
12
+
13
+ A run review dispatched multi_llm_review with `persona_count_declared: 0` and collected with no persona reviews,
14
+ so every round counted four seats where the operator's roster has five, and the report said so in one line.
15
+
16
+ - Each review round declares three personas (design: architect, security, operability; implementation:
17
+ correctness, performance, api-design; document: ontologist, skeptic, integration) and stores their prompts —
18
+ multi_llm_review's own canonical prompt for the same bundle, under a persona header — in run storage.
19
+ - The actor launches each seat with a one-line marker that the PreToolUse hook replaces with the seat's prompt.
20
+ From then on the subagent is a seat for its whole life, recognised by the host's meta file naming that launch;
21
+ it may read only its prompt file and hand back. Messages and stops aimed at a seat are refused.
22
+ - Each seat is settled at its SubagentStop from the hand-back the hooks kept, before the hazard and question
23
+ readers; agent_advance settles launches the host never started or never stopped. A seat whose transcript
24
+ shows another prompt is not submitted.
25
+ - agent_advance waits about 540 s per call for running seats, submits each settled reply with the verdict and
26
+ findings multi_llm_review's own parser reads from it, one per line the seat wrote, so a finding's severity
27
+ and consequence come from the same line, and gives the stand-in each persona's own reply. A finding whose
28
+ consequence clause (or location) lies past the point where multi_llm_review cuts a persona finding is
29
+ rebuilt with the clause and its location after a shortened body, so the cut does not record a P0 as one
30
+ that stated no consequence. A seat never launched holds the round only until the first reminder; missing
31
+ seats become a shortfall named in the report, and seats launched late or never are named on the review's
32
+ closure item. Until the round collects or its token expires the Stop hook sends the actor back to
33
+ agent_advance (three times without an advance between, and once more after a turn in which a seat started or
34
+ ended, then the run rests), so the round collects before its token expires. From ten minutes before the
35
+ token's end no seat is launched or asked for. Collect closes the round's seats under the lock that admits
36
+ launches and settles its remaining launches, so no launch outlives the round and the seat refusals end with
37
+ it; agent_stop closes the seats of a round that never collected. A close that fails because the seat lock
38
+ cannot be taken is journaled as such (`seats_close_failed`) and the settled replies are still submitted. A settled seat may be stopped; it is
39
+ never messaged.
40
+ - The seats run on the session's own plan; no policy spend counter counts them.
41
+ - `depends_on` pins multi_llm_review >= 0.12.0. L1 multi_llm_review_workflow 3.17.1.
42
+ - Design: `log/agent_persona_seats_design_v0.3_20261022.md` (two design review rounds, four implementation
43
+ review rounds and one falsification check; the P1s of each fixed). Probed live on one host: three seats
44
+ launched through the rewrite, all three submitted, five seats counted.
45
+
46
+ ## [3.96.0] - 2026-10-21
47
+
48
+ ### Changed — multi_llm_review says what the roster was when a result is read (multi_llm_review 0.12.0, llm_client 0.4.0)
49
+
50
+ A seat whose reviewer CLI was missing, logged out or refused by codex used to leave the count as `transport`, and
51
+ an APPROVE carried no feedback at all, so a review decided by two Anthropic seats read like one decided by four
52
+ seats from three makers. A Codex host's persona team was recorded as Claude's.
53
+
54
+ - A failed seat's reason is the cause its CLI adapter established: `cli_missing` (the binary is not on the PATH the
55
+ server searched), `cli_unauthenticated` (the CLI, asked after the failure with its own status command, says it
56
+ holds no credential), `workspace_refused` (codex refused a working directory outside a git repository) or
57
+ `cli_timeout`. Anything else stays `transport`, which now means an error with no established cause. Nothing the
58
+ CLI printed is read for this: codex prints the prompt and the files it read.
59
+ - `vote_tally.roster_health` states the seats, how many counted, each seat that did not count with its reason, and
60
+ each counted seat's maker with where it comes from (observed, configured, or declared by the caller). When a seat
61
+ did not count or maker diversity is not established, `feedback_text` starts with one line, on APPROVE too:
62
+ `Roster: 2 of 4 seats counted (1 caller-declared) — not counted: cli_missing: codex_gpt6-astra, cursor_composer2.5; maker diversity not established.`
63
+ - INSUFFICIENT says how many seats counted and how many were needed, that a seat can be added in config, and the
64
+ action that restores each lost seat where one exists. The tool advises no strategy.
65
+ - Every seat is dispatched with `no_fallback`: an API-key seat whose key is unset fails on its own provider instead
66
+ of being re-run on claude_code under its own name.
67
+ - New optional argument `orchestrator_host` (`claude_code`, `codex_cli`, `cursor`, `other`). `claude_code` or none
68
+ keeps `claude_team_<model>`; `codex_cli` records the persona seat as `codex_team_<model>` with provider
69
+ `codex_cli_host`. Records carry `orchestrator_host` and the server's own `host_detected`.
70
+ - `multi_llm_review_wait` reports answered and failed seats separately.
71
+ - The verdict and the quorum are unchanged. VERDICT_SCHEMA_VERSION 3, feedback_text_schema_version 2;
72
+ multi_llm_review's min_core_version is 3.24.9.
73
+ - config gains a commented second codex seat for a machine with only the codex CLI. Upgrades never rewrite an
74
+ instance's config; add it by hand.
75
+ - llm_client 0.4.0: `ApiError` carries the `code`, and `CallRouter` and `llm_call` return it as `error['code']`.
76
+ After a failed CLI call one status command runs (never when the dispatcher ended the call; at most about 19 s).
77
+ The error message and its ErrorTaxonomy type are unchanged, so every other llm_client caller sees only the added
78
+ key and that pause.
79
+
80
+ Design: `log/mlr_non_claude_host_design_v0.3.3_20261021.md`, frozen after four review rounds; implementation
81
+ reviewed in two (records `log/mlr_non_claude_host_*`).
82
+
83
+ ### Changed — L1 `multi_llm_review_workflow` 3.17.0
84
+
85
+ § Auto Mode vs Manual Mode sent a missing CLI to a "Manual mode" the runbook never described. It is replaced by
86
+ § Execution Environment / Reduced rosters and non-Claude hosts: what each failure reason means and what restores
87
+ the seat, the roster line, what a Claude-only, a non-Claude-host and a codex-only setup count under each strategy,
88
+ and how a host's per-call time limit meets a long review call.
89
+
90
+ ### Fixed — `capability_status` reported installed reviewer CLIs as missing
91
+
92
+ It searched PATH for files named `claude_cli`, `codex_cli` and `cursor_cli`. It now probes the binaries the
93
+ adapters spawn (`claude`, `codex`, `agent`), runs `--version` without a shell, and names the binary it searched for.
94
+
95
+ ## [3.95.1] - 2026-10-21
96
+
97
+ ### Changed — the agent SkillSet ships a sample policy, `default_2026_10_20`, instead of `masa_2026_10_20` (agent 1.0.1)
98
+
99
+ `masa_2026_10_20.rb` named its author and cited a record that exists only in the author's instance.
100
+ `default_2026_10_20.rb` carries the same rules (the stand-in may answer from the operator's recorded words, from
101
+ the instruction mode, and reversible questions no recorded word covers; review consent; no project exempt from the
102
+ data check; 10 rounds per review; 300 stand-in calls), with comments that say what each rule does. The stand-in
103
+ reads the policy file, comments included. Adopt it with `adopt policy default_2026_10_20 ac4ae89b`; adopting it
104
+ consents to sending the run's artifacts to the reviewers configured in multi_llm_review.
105
+
106
+ `masa_2026_10_20.rb` is no longer shipped and is not listed in `removed_files`, so upgrade leaves an installed copy
107
+ and a forced reinstall keeps the installed copy: an instance that has it keeps it, and an adoption of it stays valid. It is another operator's sample with the same
108
+ rules: an instance that never adopted it may delete it, and one that did may adopt `default_2026_10_20` instead. A
109
+ shipped policy is never changed in place; a changed rule ships under a new policy name in a new file. Design:
110
+ `log/agent_policy_default_and_proposal_design_v0.7.2_20261021.md`.
111
+
112
+ ### Changed — personal material out of the shipped agent tree
113
+
114
+ Home paths, a person's project and course names, answers typed in a real course and a third party's name are
115
+ replaced by synthetic ones in the agent SkillSet's tests and one code comment. The published 3.95.0 gem and the
116
+ repository history keep them.
117
+
118
+ ### Added — `bin/agent_policy_report.rb`
119
+
120
+ An operator-run script that reports, for each rule of the adopted policy, what the runs the chain records as ended
121
+ hold against it: stand-in answers by class and their corrections, review rounds and cap hits, stand-in calls and
122
+ grants, data checks, with counts, denominators and the operator's words. It moves no rule, evaluates no file
123
+ from a run directory, and writes only its report, under `storage/agent/policy_reports/` (and
124
+ `storage/agent/.gitignore` when absent; no report is written unless that file is a regular file holding exactly the line `*`). Every act it counts is recorded on the actor's reading of the
125
+ operator's words, and the report says so. A policy changes only by the operator's own copy, edit and typed
126
+ adoption.
127
+
9
128
  ## [3.95.0] - 2026-10-21
10
129
 
11
130
  ### Changed — the `agent` SkillSet is rebuilt (1.0): long runs in the host session, a stand-in instead of terminal approvals
@@ -98,11 +98,25 @@ module KairosMcp
98
98
  declaration_errors: errors }
99
99
  end
100
100
 
101
+ # The binary each declared external names: the one the llm_client
102
+ # adapter spawns for it (claude_code_adapter, codex_adapter,
103
+ # cursor_adapter). Probing the symbol itself searched PATH for a file
104
+ # called "codex_cli" and reported every installed CLI as missing.
105
+ EXTERNAL_BINARIES = {
106
+ claude_cli: 'claude',
107
+ codex_cli: 'codex',
108
+ cursor_cli: 'agent'
109
+ }.freeze
110
+
111
+ def binary_for(name)
112
+ EXTERNAL_BINARIES.fetch(name.to_s.to_sym, name.to_s)
113
+ end
114
+
101
115
  # which-style PATH check using only filesystem (no subprocess).
102
116
  # Returns true/false.
103
117
  def cli_in_path?(name)
104
118
  return false unless name.is_a?(Symbol) || name.is_a?(String)
105
- bin = name.to_s
119
+ bin = binary_for(name)
106
120
  ENV.fetch('PATH', '').split(File::PATH_SEPARATOR).any? do |dir|
107
121
  full = File.join(dir, bin)
108
122
  File.executable?(full) && !File.directory?(full)
@@ -110,11 +124,13 @@ module KairosMcp
110
124
  end
111
125
 
112
126
  # Get version of a CLI by spawning subprocess (only when probe_versions: true).
113
- # Returns nil on any failure (Honest unknown).
127
+ # Returns nil on any failure (Honest unknown). Spawned as an argv, not
128
+ # through a shell.
114
129
  def cli_version(name)
115
130
  return nil unless cli_in_path?(name)
116
- out = `#{name} --version 2>&1`.strip
117
- $?.success? ? out.lines.first&.strip : nil
131
+ require 'open3'
132
+ out, status = Open3.capture2e(binary_for(name), '--version')
133
+ status.success? ? out.strip.lines.first&.strip : nil
118
134
  rescue StandardError
119
135
  nil
120
136
  end
@@ -152,7 +152,9 @@ module KairosMcp
152
152
 
153
153
  externals.each do |ext|
154
154
  present = Capability.cli_in_path?(ext)
155
- entry = { available: present }
155
+ # The binary searched for, so a reader can tell which file was
156
+ # missing (claude_cli is the `claude` binary, and so on).
157
+ entry = { available: present, binary: Capability.binary_for(ext) }
156
158
  entry[:reason] = 'not found in PATH' unless present
157
159
  if present && probe_versions
158
160
  ver = Capability.cli_version(ext)
@@ -1,4 +1,4 @@
1
1
  module KairosMcp
2
- VERSION = "3.95.0"
2
+ VERSION = "3.96.1"
3
3
  CHANGELOG_URL = "https://github.com/masaomi/KairosChain_2026/blob/main/CHANGELOG.md"
4
4
  end
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: multi_llm_review_workflow
3
3
  description: "Multi-LLM review methodology and execution — workflow pattern, CLI tooling, consensus analysis, Persona Assembly. Applicable to design, implementation, documentation, or any artifact."
4
- version: "3.16.0"
4
+ version: "3.17.1"
5
5
  tags:
6
6
  - workflow
7
7
  - review
@@ -24,7 +24,7 @@ and integrated. The user (or primary LLM) acts as orchestrator.
24
24
 
25
25
  This skill covers:
26
26
  - **WHAT/WHEN**: When to use multi-LLM review, review types, convergence criteria
27
- - **HOW**: CLI commands, prompt generation, auto/manual execution, consensus analysis
27
+ - **HOW**: CLI commands, prompt generation, Path A (manual) and Path B (MCP) execution, consensus analysis
28
28
 
29
29
  For **WHO** (which LLM is good at what), see: `multi_llm_reviewer_evaluation`
30
30
  For **development lifecycle** (design → implement → verify), see: `design_to_implementation_workflow`
@@ -861,20 +861,89 @@ Save to L2 context at these moments:
861
861
 
862
862
  # Execution
863
863
 
864
- ## Auto Mode vs Manual Mode
864
+ ## Execution Environment
865
865
 
866
- ### Mode Detection
866
+ ### Reduced rosters and non-Claude hosts
867
867
 
868
- ```bash
869
- which codex 2>/dev/null && echo "codex: available" || echo "codex: NOT FOUND"
870
- which agent 2>/dev/null && echo "agent: available" || echo "agent: NOT FOUND"
871
- which claude 2>/dev/null && echo "claude: available" || echo "claude: NOT FOUND"
868
+ The roster is whatever `config/multi_llm_review.yml` names (Path B), and the tool
869
+ never drops a seat because its CLI is missing. Every seat runs only on its own
870
+ provider (no fallback to another). A seat that cannot run fails, leaves the count,
871
+ and is recorded with the cause its transport established — never with a cause read
872
+ out of text the CLI printed, because codex prints the prompt and the files it read:
873
+
874
+ | Reason | What happened | What restores the seat |
875
+ |---|---|---|
876
+ | `cli_missing` | the CLI's binary is not on the PATH the server searched | install it, or put its directory on that PATH (the result shows it) |
877
+ | `cli_unauthenticated` | the CLI, asked after the failure, said it is not logged in | log in with that CLI (`codex login`, `agent login`, `claude` then `/login`); the seat reads the login under HOME |
878
+ | `workspace_refused` | codex refused the server's working directory (no git repository, not trusted) | make that directory (named in the result) lie inside a git repository; how a host sets the server's directory is the host's |
879
+ | `cli_timeout` | the CLI call's own timer (llm_client `timeout_seconds`) fired | raise llm_client's and multi_llm_review's `timeout_seconds` together |
880
+ | `dispatch_timeout` | the dispatch window (multi_llm_review `timeout_seconds`) closed with the seat still running or still queued; with both at 600 s this fires first | as for `cli_timeout`; `collect_deadline_seconds` (1800 shipped) bounds how far that helps |
881
+ | `transport` | anything else; the seat's error message says what was seen | read the seat's row (an API-key seat whose key is unset lands here) |
882
+
883
+ Asking a failed CLI whether it is logged in costs one status command after the
884
+ failure (its own 10 s timer; up to about 19 s with the kill grace and reader joins),
885
+ and every other llm_client caller sees the same pause after a failed CLI call. It is
886
+ never run when the dispatcher itself ended the call.
887
+
888
+ Whenever a seat did not count, or the counted seats are not known to come from two
889
+ different makers, the result carries one roster line, on APPROVE too:
890
+
891
+ ```
892
+ Roster: 2 of 4 seats counted (1 caller-declared) — not counted: cli_missing: codex_gpt6-astra, cursor_composer2.5; maker diversity not established.
872
893
  ```
873
894
 
874
- - All three available → Auto mode (the configured roster, currently 5 reviewers)
875
- - Codex + Agent only → Auto mode (legacy, reduced roster — apply "Legacy 3-reviewer mode: 2/3 APPROVE" from Convergence Rules)
876
- - Any of codex/agent missing → Manual mode
877
- - User override: `mode: manual` or `mode: auto`
895
+ A counted seat's maker is observed (the seat reported its model), configured (the
896
+ roster pins the model and the seat ran on its own provider — this holds while the
897
+ CLI's own configuration does not route that name to another maker), or
898
+ caller-declared (a persona seat that was not observed). Only the first two
899
+ establish diversity. One kind of round always carries the line: an `exclude` round
900
+ whose caller names a slot (that slot does not count). An agent SkillSet round no
901
+ longer always carries it: agent 1.0.2 convenes three personas on the host and
902
+ submits the replies the host handed back, where 1.0.1 submitted none, so its line
903
+ follows the same rule as any other round. None of this changes the verdict or the quorum
904
+ (`min_quorum`, 2 shipped). An INSUFFICIENT result also says how many seats counted
905
+ and how many were needed, that a seat can be added in config, and the restoring
906
+ action for each reason in the table above.
907
+
908
+ **Claude Code without codex or cursor.** Nothing to configure. The persona team and
909
+ the Sonnet seat count, APPROVE is reachable, and every result says "2 of 4 seats
910
+ counted … maker diversity not established".
911
+
912
+ **A host other than Claude Code.** Pass `orchestrator_host` (`codex_cli`, `cursor`
913
+ or `other`; `claude_code` or nothing keeps `claude_team_<model>`), and the persona
914
+ seat is recorded as `codex_team_<model>` and so on, beside the server's own
915
+ detection of its host. Run the personas as separate sub-agents of your host (Codex:
916
+ multi-agent). Nothing in the system can observe that, so the persona seat is always
917
+ recorded as your declaration. A Codex session can still run the `claude` seats:
918
+ Codex's sandbox does not confine kairos-chain's MCP server.
919
+
920
+ **A machine with only the codex CLI.** One seat can answer, below the quorum, so
921
+ every review is INSUFFICIENT until a second codex seat is added on another model —
922
+ the commented recipe in `config/multi_llm_review.yml`. Upgrades never rewrite an
923
+ instance's config, so an existing instance adds it by hand: a slot naming
924
+ `provider`, `model` and `role_label`, on a model the roster does not already name.
925
+ With orchestrator_model `gpt-6-astra` and a `gpt-6-sol` seat:
926
+
927
+ | Strategy | Counted seats | What it costs |
928
+ |---|---|---|
929
+ | `delegate` (default) | 2: `gpt-6-sol` and your persona team | the persona seat rests on your declaration |
930
+ | `subprocess`, no `persona_model` | 2: `gpt-6-astra` and `gpt-6-sol`, both fresh processes | one call that returns only when every seat has finished; your own slot runs only if your model names one |
931
+ | `exclude` | 1: your slot leaves (`exclude_orchestrator_model: true`, shipped) | below the quorum |
932
+
933
+ **A host with a per-call time limit** (Codex: `tool_timeout_sec` per MCP server;
934
+ documented default 60 s, not verified here). A `subprocess` review is one call that
935
+ lasts as long as the slowest seat, so first raise the limit for kairos-chain above
936
+ both configured `timeout_seconds`, with a margin. A cut single-phase call leaves its
937
+ record only in the run's `completed.json`. On the delegate path the first call
938
+ returns at once, but waiting in short calls is no substitute: three consecutive
939
+ `still_pending` replies from `multi_llm_review_wait` end in `crashed` /
940
+ `wait_exhausted` while the worker is still healthy. Raise the host's limit instead.
941
+ `multi_llm_review_collect` waits at most `collect_max_wait_seconds` (420 shipped)
942
+ before reaping a live worker, so call collect after wait has said `ready`.
943
+
944
+ **Path A (manual Bash).** Run `which codex`, `which agent`, `which claude`; leave
945
+ out the line of a CLI that is not found, and read the result by the same rules: the
946
+ quorum stays 2, and the report says which seats did not count and why.
878
947
 
879
948
  ### CLI Tool Matrix (tested 2026-03-28; model flags made mandatory 2026-07-27)
880
949
 
@@ -1069,7 +1138,7 @@ multi_llm_review(
1069
1138
  `orchestrator_strategy: "subprocess"`.
1070
1139
  - If `orchestrator_model` is `null` or unmatched, full roster runs (back-compat).
1071
1140
 
1072
- **Manual-mode equivalent**: When orchestrating by hand, do not assign yourself
1141
+ **Path A equivalent**: When orchestrating by hand, do not assign yourself
1073
1142
  as a subprocess reviewer. Run the Claude CLI subprocess reviewers (Sonnet 5.5, plus
1074
1143
  any frontier roster slot you are not); if your own model matches one of them,
1075
1144
  skip that entry and use the after-exclusion convergence rule.
@@ -1094,19 +1163,21 @@ cross-model subprocess reviewers give epistemic diversity. The two are complemen
1094
1163
 
1095
1164
  **Call 1**: `multi_llm_review(orchestrator_strategy: "delegate", orchestrator_model: "...")`
1096
1165
  - SkillSet drops the orchestrator-matching reviewer from dispatch
1097
- - Subprocess reviewers run synchronously (no background threads)
1098
- - Subprocess results persisted to `.kairos/multi_llm_review/pending/<uuid>.json`
1166
+ - Subprocess reviewers run in a detached worker (default `parallel: true`), or
1167
+ synchronously with `parallel: false`
1168
+ - Subprocess results persisted under `.kairos/multi_llm_review/pending/<token>/`
1099
1169
  - Returns `status: "delegation_pending"`, `collect_token`, `persona_count_min/max`
1100
1170
 
1101
1171
  **Orchestrator's obligation** (between calls):
1102
1172
  - Recognize the `delegation_pending` status
1103
- - Spawn 2-4 parallel `Agent` tool calls with self-chosen personas appropriate to
1173
+ - Run 2-4 personas as separate sub-agents of your host (Claude Code: parallel
1174
+ `Agent` tool calls; Codex: multi-agent), self-chosen and appropriate to
1104
1175
  the artifact (e.g. design → architect/security/operability; code → correctness/
1105
1176
  performance/api-design; doc → ontologist/skeptic/integration)
1106
1177
  - Collect persona results: each as `{persona, verdict (APPROVE|REVISE|REJECT),
1107
1178
  reasoning, findings: [{severity, issue}, ...]}`
1108
- - Bind each persona to its subagent: add `agent_id` — the id the Agent tool
1109
- returned for that persona's subagent — to its entry. With the model_provenance
1179
+ - Bind each persona to its subagent (Claude Code): add `agent_id` — the id the
1180
+ Agent tool returned for that persona's subagent — to its entry. With the model_provenance
1110
1181
  SkillSet installed, the seat then records the model the harness observed
1111
1182
  answering, not only the declared one: a safety-classifier fallback inside a
1112
1183
  persona (Opus 5.5 → Opus 5 on biology, → Opus 4.8 on cyber) otherwise leaves
@@ -1120,7 +1191,8 @@ cross-model subprocess reviewers give epistemic diversity. The two are complemen
1120
1191
 
1121
1192
  **Call 2**: `multi_llm_review_collect(collect_token, orchestrator_reviews: [...])`
1122
1193
  - Persona Assembly: any REJECT → REJECT; else any REVISE → REVISE; else APPROVE
1123
- - Assembled into one synthetic reviewer entry `claude_team_<orchestrator_model>`
1194
+ - Assembled into one synthetic reviewer entry `<host>_team_<model>`
1195
+ (`claude_team_` for `orchestrator_host` claude_code or none; § Reduced rosters)
1124
1196
  - Combined with persisted subprocess results, run Consensus, return final verdict
1125
1197
  - Idempotent: repeated calls with the same token return the cached result
1126
1198
 
@@ -1128,9 +1200,12 @@ cross-model subprocess reviewers give epistemic diversity. The two are complemen
1128
1200
  - `expired_or_unknown_token`: orchestrator missed `must_collect_by` deadline
1129
1201
  (default 1800s since v3.23.2; was 600s), or token never existed. The pending
1130
1202
  review is gone; call `multi_llm_review` again from scratch.
1131
- - `error: invalid orchestrator_reviews`: persona count outside 2-4 or missing
1132
- required fields. Fix and retry collect with the same token.
1133
- - All-subprocess-failed at Call 1: returns error immediately; no token issued.
1203
+ - `error: invalid orchestrator_reviews`: more than 4 personas, or missing
1204
+ required fields. Fix and retry collect with the same token. 0–4 are accepted;
1205
+ fewer than convened is recorded as a shortfall.
1206
+ - All subprocess seats failed at Call 1: with `parallel: false` it returns an
1207
+ error at once and issues no token; on the default parallel path the failures
1208
+ surface at collect, as INSUFFICIENT with each seat's reason.
1134
1209
 
1135
1210
  **Default**: `orchestrator_strategy` defaults to `"delegate"` (config key
1136
1211
  `default_orchestrator_strategy`). `"exclude"` remains available as the legacy
@@ -1554,7 +1629,8 @@ Step 3: Execute the configured roster in parallel (currently 4 slots, one of
1554
1629
  Step 4: Collect and validate
1555
1630
  - Wait for all to complete (background task notifications)
1556
1631
  - Verify each output file exists and contains structured review
1557
- - Failed tool → offer manual fallback
1632
+ - Failed tool → record it as not counted, with its cause (§ Reduced rosters
1633
+ and non-Claude hosts)
1558
1634
 
1559
1635
  Step 5: Consensus analysis
1560
1636
  - Read all review files
@@ -1571,10 +1647,11 @@ Step 6: Report to user
1571
1647
 
1572
1648
  | Error | Detection | Recovery |
1573
1649
  |-------|-----------|----------|
1574
- | CLI not found | `which` non-zero | Manual mode fallback |
1575
- | Auth expired | Non-zero exit, auth error | Prompt re-login |
1576
- | Timeout (>5 min) | Background task timeout | Kill, report partial, retry |
1577
- | Empty output | Missing verdict | Report failure, manual retry |
1650
+ | CLI not found | `cli_missing` (Path A: `which` non-zero) | Install, or fix the server's PATH |
1651
+ | Not logged in | `cli_unauthenticated` | Log in with that CLI |
1652
+ | codex refuses the directory | `workspace_refused` | Run from inside a git repository |
1653
+ | Timeout | `cli_timeout` / `dispatch_timeout` | Raise both `timeout_seconds`; mind `collect_deadline_seconds` |
1654
+ | Empty output | `no_verdict` / `insubstantial` | Report failure, retry |
1578
1655
  | Trust prompt | Agent hangs | `--trust` flag |
1579
1656
  | Usage limit | "usage limit" in output | Alternate tool fallback |
1580
1657
 
@@ -2028,6 +2105,27 @@ Compression ratio: parallel agent raw → Assembly ≈ 2:1
2028
2105
  Step 0.25 guard-track sentence and § Convergence Rules. Source: design
2029
2106
  `log/agent_skillset_rebuild_design_v0.5.1_20261020.md` §2 and its delta v0.6.6.
2030
2107
 
2108
+ - Reduced rosters and non-Claude hosts (v3.17.0, 2026-10-21, operator request:
2109
+ 「MLRのdefaultがclaude codeでない場合の処理について…修正しようと思います」,
2110
+ rulings 1–9 in L2 `decision_mlr_non_claude_host_four_rulings_20261021`).
2111
+ § Auto Mode vs Manual Mode, which sent a missing CLI to a "Manual mode" it never
2112
+ described and counted 5 reviewers, is replaced by § Execution Environment /
2113
+ Reduced rosters and non-Claude hosts: what each failure cause means and what
2114
+ restores the seat, the roster line results now carry, what a Claude-only,
2115
+ non-Claude-host or codex-only setup counts under each strategy, and a host's
2116
+ per-call limit. The delegation protocol now names sub-agents of any host,
2117
+ `<host>_team_<model>`, the 0–4 persona range and where an all-failed Call 1
2118
+ surfaces; the Error Handling table maps the new reason tokens. Ships with
2119
+ multi_llm_review 0.12.0 and llm_client 0.4.0. Design
2120
+ `log/mlr_non_claude_host_design_v0.3.3_20261021.md`, frozen after four rounds.
2121
+
2122
+ - Agent runs convene persona seats (v3.17.1, 2026-10-22, operator request:
2123
+ 「Agent SkillSet1.0.1でreview時にpersona数が0に決め打ちされてるそうですが、MLRの設定と異なるので
2124
+ 修正して下さい」). § Reduced rosters no longer says an agent SkillSet round always
2125
+ carries the roster line: agent 1.0.2 declares and convenes three personas, launched
2126
+ by the run's actor through a marker the SkillSet's hook rewrites, and submits the
2127
+ replies the host handed back. Design `log/agent_persona_seats_design_v0.3_20261022.md`.
2128
+
2031
2129
  **Key insight**: Design reviews and implementation reviews find
2032
2130
  **categorically different bugs**. Both phases are necessary. The corollary that
2033
2131
  cost eight rounds to learn: **which of the two you are in is readable from the
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The policy report (design v0.7.2 INV-8): for each rule of the adopted
4
+ # policy, what the runs the chain records as ended hold against it — counts
5
+ # with their denominators and the operator's words of each act. The operator
6
+ # runs it outside runs. It reads the data directory, calls no model,
7
+ # evaluates no file from a run directory, writes one file under
8
+ # storage/agent/policy_reports (and storage/agent/.gitignore when absent), and
9
+ # changes no policy.
10
+ #
11
+ # ruby .kairos/skillsets/agent/bin/agent_policy_report.rb [--data-dir DIR]
12
+
13
+ require_relative '../lib/agent/policy_report'
14
+
15
+ def arg(name)
16
+ i = ARGV.index(name)
17
+ i && ARGV[i + 1]
18
+ end
19
+
20
+ data_dir = arg('--data-dir') || ENV['KAIROS_DATA_DIR'] || File.join(ENV['CLAUDE_PROJECT_DIR'] || Dir.pwd, '.kairos')
21
+ paths = KairosMcp::SkillSets::Agent::Paths.new(data_dir)
22
+ begin
23
+ puts KairosMcp::SkillSets::Agent::PolicyReport.new(paths).write
24
+ rescue ArgumentError, IOError, SystemCallError => e
25
+ abort e.message
26
+ end
@@ -0,0 +1,34 @@
1
+ # A sample policy for agent runs: an operator's mandate, shipped with the agent
2
+ # SkillSet. It binds no one until an operator adopts it by typing
3
+ # "adopt policy default_2026_10_20 <first 8 hex digits of its digest>"; any
4
+ # edit changes the digest and needs a new adoption. A changed policy takes a
5
+ # new name in its policy line. The stand-in reads this whole file, comments
6
+ # included, as part of its instructions.
7
+ #
8
+ # stand_in may: the decision points the stand-in answers instead of the
9
+ # operator (questions, plan approval and parameters, pinned-test changes).
10
+ # :precedent answers from the operator's own recorded words;
11
+ # :instruction_mode answers from the active instruction mode;
12
+ # :novel_reversible answers a reversible question no recorded word covers,
13
+ # by the model's own judgment (with an empty precedent store, that is most
14
+ # questions). Leaving out :precedent or :instruction_mode while keeping
15
+ # :novel_reversible answers the same questions, labelled novel; leaving out
16
+ # all three sends those decision points to the operator. These classes do
17
+ # not govern the stand-in's readings: it still checks review bundles for
18
+ # personal data, labels review findings and rules on hazards.
19
+ # consent review: a run may send its artifacts to the reviewers configured in
20
+ # multi_llm_review. The value and scope are recorded, not enforced.
21
+ # free_of_personal_data: projects whose review bundles skip the stand-in's
22
+ # check for personal or third-party data, unless a bundle carries findings
23
+ # from an earlier round. None here.
24
+ # spend: review_rounds caps each review, counted apart; at the cap the review
25
+ # waits for the operator. stand_in_calls caps the stand-in's model calls in a
26
+ # run; past it decision points and readings go to the operator, and a hazard
27
+ # cannot be ruled, which ends the run.
28
+
29
+ policy "default_2026_10_20" do
30
+ stand_in may: [:precedent, :instruction_mode, :novel_reversible]
31
+ consent review: :configured_providers, of: :project_artifacts
32
+ free_of_personal_data projects: []
33
+ spend default: { review_rounds: 10, stand_in_calls: 300 }
34
+ end