kairos-chain 3.94.0 → 3.95.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +71 -0
  3. data/bin/kairos-chain +2 -0
  4. data/lib/kairos_mcp/skillset.rb +21 -0
  5. data/lib/kairos_mcp/skillset_manager.rb +58 -13
  6. data/lib/kairos_mcp/tools/system_upgrade.rb +2 -0
  7. data/lib/kairos_mcp/version.rb +1 -1
  8. data/templates/knowledge/design_to_implementation_workflow/design_to_implementation_workflow.md +4 -1
  9. data/templates/knowledge/multi_llm_review_workflow/multi_llm_review_workflow.md +40 -5
  10. data/templates/skillsets/agent/bin/agent_harvest.rb +28 -0
  11. data/templates/skillsets/agent/config/policies/masa_2026_10_20.rb +17 -0
  12. data/templates/skillsets/agent/hooks/agent_hook.rb +139 -0
  13. data/templates/skillsets/agent/lib/agent/confinement.rb +107 -239
  14. data/templates/skillsets/agent/lib/agent/dsl.rb +219 -0
  15. data/templates/skillsets/agent/lib/agent/guard.rb +799 -0
  16. data/templates/skillsets/agent/lib/agent/harvest.rb +145 -0
  17. data/templates/skillsets/agent/lib/agent/hooks.rb +785 -0
  18. data/templates/skillsets/agent/lib/agent/journal.rb +118 -0
  19. data/templates/skillsets/agent/lib/agent/policies.rb +153 -0
  20. data/templates/skillsets/agent/lib/agent/precedents.rb +151 -0
  21. data/templates/skillsets/agent/lib/agent/review.rb +507 -0
  22. data/templates/skillsets/agent/lib/agent/run.rb +497 -0
  23. data/templates/skillsets/agent/lib/agent/service.rb +1661 -0
  24. data/templates/skillsets/agent/lib/agent/stand_in.rb +274 -0
  25. data/templates/skillsets/agent/lib/agent/templates.rb +131 -0
  26. data/templates/skillsets/agent/lib/agent/transcript.rb +134 -0
  27. data/templates/skillsets/agent/lib/agent.rb +34 -22
  28. data/templates/skillsets/agent/plugin/SKILL.md +138 -171
  29. data/templates/skillsets/agent/plugin/hooks.json +94 -0
  30. data/templates/skillsets/agent/report_kit/KIT_SHA256.txt +5 -0
  31. data/templates/skillsets/agent/report_kit/check.py +23 -0
  32. data/templates/skillsets/agent/report_kit/kit.py +364 -0
  33. data/templates/skillsets/agent/report_kit/make_report_deck.py +159 -0
  34. data/templates/skillsets/agent/report_kit/render.py +19 -0
  35. data/templates/skillsets/agent/report_kit/viz.py +203 -0
  36. data/templates/skillsets/agent/skillset.json +99 -14
  37. data/templates/skillsets/agent/test/test_agent1_dsl.rb +89 -0
  38. data/templates/skillsets/agent/test/test_agent1_guard.rb +127 -0
  39. data/templates/skillsets/agent/test/test_agent1_hooks_service.rb +401 -0
  40. data/templates/skillsets/agent/test/test_agent1_journal_run.rb +93 -0
  41. data/templates/skillsets/agent/test/test_agent1_r1_check.rb +571 -0
  42. data/templates/skillsets/agent/test/test_agent1_r1_guard.rb +475 -0
  43. data/templates/skillsets/agent/test/test_agent1_r1_hookscript.rb +410 -0
  44. data/templates/skillsets/agent/test/test_agent1_r1_lifecycle.rb +556 -0
  45. data/templates/skillsets/agent/test/test_agent1_r1_report.rb +588 -0
  46. data/templates/skillsets/agent/test/test_agent1_r1_review.rb +689 -0
  47. data/templates/skillsets/agent/test/test_agent1_r1_words.rb +614 -0
  48. data/templates/skillsets/agent/test/test_agent1_r1b_fixes.rb +258 -0
  49. data/templates/skillsets/agent/test/test_agent1_r2_guard.rb +565 -0
  50. data/templates/skillsets/agent/test/test_agent1_r2_words.rb +349 -0
  51. data/templates/skillsets/agent/test/test_agent1_r2v_checkreview.rb +725 -0
  52. data/templates/skillsets/agent/test/test_agent1_r2v_decisions.rb +756 -0
  53. data/templates/skillsets/agent/test/test_agent1_r2v_progress.rb +539 -0
  54. data/templates/skillsets/agent/test/test_agent1_r2v_sessions.rb +770 -0
  55. data/templates/skillsets/agent/test/test_agent1_r3_guard.rb +354 -0
  56. data/templates/skillsets/agent/test/test_agent1_r3_words.rb +367 -0
  57. data/templates/skillsets/agent/test/test_agent1_r3v_checkreview.rb +854 -0
  58. data/templates/skillsets/agent/test/test_agent1_r3v_guardwords.rb +730 -0
  59. data/templates/skillsets/agent/test/test_agent1_r3v_lifecycle.rb +1096 -0
  60. data/templates/skillsets/agent/test/test_agent1_selfreview_fixes.rb +75 -0
  61. data/templates/skillsets/agent/test/test_agent1_stand_in_precedents.rb +113 -0
  62. data/templates/skillsets/agent/test/test_agent1_v06.rb +1129 -0
  63. data/templates/skillsets/agent/tools/agent_advance.rb +51 -0
  64. data/templates/skillsets/agent/tools/agent_finish.rb +50 -0
  65. data/templates/skillsets/agent/tools/agent_items.rb +56 -0
  66. data/templates/skillsets/agent/tools/agent_start.rb +17 -224
  67. data/templates/skillsets/agent/tools/agent_status.rb +9 -89
  68. data/templates/skillsets/agent/tools/agent_stop.rb +8 -122
  69. data/templates/skillsets/introspection/lib/introspection/safety_inspector.rb +28 -14
  70. data/templates/skillsets/llm_client/lib/llm_client/call_router.rb +7 -1
  71. data/templates/skillsets/llm_client/lib/llm_client/claude_code_adapter.rb +21 -2
  72. data/templates/skillsets/llm_client/skillset.json +1 -1
  73. data/templates/skillsets/llm_client/test/test_no_fallback_and_isolation.rb +113 -0
  74. data/templates/skillsets/llm_client/tools/llm_call.rb +20 -2
  75. metadata +54 -62
  76. data/templates/skillsets/agent/bin/agent_distill.rb +0 -124
  77. data/templates/skillsets/agent/bin/agent_rule.rb +0 -215
  78. data/templates/skillsets/agent/bin/agent_shadow_judge.rb +0 -70
  79. data/templates/skillsets/agent/bin/agent_step_worker.rb +0 -321
  80. data/templates/skillsets/agent/config/agent.yml +0 -171
  81. data/templates/skillsets/agent/lib/agent/act_classification.rb +0 -336
  82. data/templates/skillsets/agent/lib/agent/act_classification.yml +0 -54
  83. data/templates/skillsets/agent/lib/agent/admission.rb +0 -384
  84. data/templates/skillsets/agent/lib/agent/adoption.rb +0 -340
  85. data/templates/skillsets/agent/lib/agent/advance_gate.rb +0 -357
  86. data/templates/skillsets/agent/lib/agent/answer_ruling.rb +0 -491
  87. data/templates/skillsets/agent/lib/agent/cognitive_loop.rb +0 -452
  88. data/templates/skillsets/agent/lib/agent/delegation.rb +0 -372
  89. data/templates/skillsets/agent/lib/agent/delegation_table.yml +0 -44
  90. data/templates/skillsets/agent/lib/agent/distill_run.rb +0 -197
  91. data/templates/skillsets/agent/lib/agent/distiller.rb +0 -313
  92. data/templates/skillsets/agent/lib/agent/distiller_prompt.rb +0 -130
  93. data/templates/skillsets/agent/lib/agent/mandate_adapter.rb +0 -69
  94. data/templates/skillsets/agent/lib/agent/mediator.rb +0 -211
  95. data/templates/skillsets/agent/lib/agent/message_format.rb +0 -33
  96. data/templates/skillsets/agent/lib/agent/native_body/main.rb +0 -166
  97. data/templates/skillsets/agent/lib/agent/native_body/model_client.rb +0 -135
  98. data/templates/skillsets/agent/lib/agent/native_body/spend_meter.rb +0 -131
  99. data/templates/skillsets/agent/lib/agent/native_body/tool_layer.rb +0 -195
  100. data/templates/skillsets/agent/lib/agent/point_facts.rb +0 -231
  101. data/templates/skillsets/agent/lib/agent/review_hint.rb +0 -84
  102. data/templates/skillsets/agent/lib/agent/session.rb +0 -282
  103. data/templates/skillsets/agent/lib/agent/shadow_judge.rb +0 -564
  104. data/templates/skillsets/agent/lib/agent/staging.rb +0 -267
  105. data/templates/skillsets/agent/lib/agent/step_delegation.rb +0 -450
  106. data/templates/skillsets/agent/lib/agent/trigger_validator.rb +0 -69
  107. data/templates/skillsets/agent/lib/agent/verdict.rb +0 -177
  108. data/templates/skillsets/agent/plugin/agents/monitor.md +0 -24
  109. data/templates/skillsets/agent/test/test_agent_act_hardening.rb +0 -488
  110. data/templates/skillsets/agent/test/test_agent_admission.rb +0 -112
  111. data/templates/skillsets/agent/test/test_agent_allowlist.rb +0 -724
  112. data/templates/skillsets/agent/test/test_agent_answer_rulings.rb +0 -949
  113. data/templates/skillsets/agent/test/test_agent_capability_discovery.rb +0 -307
  114. data/templates/skillsets/agent/test/test_agent_complexity_review.rb +0 -852
  115. data/templates/skillsets/agent/test/test_agent_confinement.rb +0 -184
  116. data/templates/skillsets/agent/test/test_agent_distillation.rb +0 -539
  117. data/templates/skillsets/agent/test/test_agent_guard_integration.rb +0 -218
  118. data/templates/skillsets/agent/test/test_agent_guard_verdict_record.rb +0 -446
  119. data/templates/skillsets/agent/test/test_agent_halt_semantics.rb +0 -370
  120. data/templates/skillsets/agent/test/test_agent_human_mark_gate.rb +0 -486
  121. data/templates/skillsets/agent/test/test_agent_interruption_resilience.rb +0 -729
  122. data/templates/skillsets/agent/test/test_agent_m1.rb +0 -329
  123. data/templates/skillsets/agent/test/test_agent_m2.rb +0 -625
  124. data/templates/skillsets/agent/test/test_agent_m3.rb +0 -719
  125. data/templates/skillsets/agent/test/test_agent_m4.rb +0 -545
  126. data/templates/skillsets/agent/test/test_agent_native_body.rb +0 -788
  127. data/templates/skillsets/agent/test/test_agent_shadow_judge.rb +0 -1233
  128. data/templates/skillsets/agent/test/test_agent_verdict.rb +0 -119
  129. data/templates/skillsets/agent/test/test_agent_worker_exit_and_review_parse.rb +0 -622
  130. data/templates/skillsets/agent/test/test_agent_worker_process.rb +0 -386
  131. data/templates/skillsets/agent/test/test_decide_prompt_contract.rb +0 -158
  132. data/templates/skillsets/agent/test/test_review_hint.rb +0 -168
  133. data/templates/skillsets/agent/tools/agent_execute.rb +0 -627
  134. data/templates/skillsets/agent/tools/agent_step.rb +0 -3909
  135. data/templates/skillsets/agent/tools/agent_wait.rb +0 -195
  136. data/templates/skillsets/agent/tools/operator_report.rb +0 -130
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05055bfa3f7c4377e2e88011754c85d8d87c690e07f19837c4dca5a0c1cd033c
4
- data.tar.gz: 48b9c8a70d27304e21293440f121ec069cb0c7ec47ed41b01573cdd2e3c80505
3
+ metadata.gz: 3bce3f299f0bb91ecbb6199e464a2ea24602ede6e9d4e972c1a7b5905ec447c5
4
+ data.tar.gz: 4986b9e4f8c87ff233b67586791d8b3068aed4decaecb1319f5c0553b4a5445c
5
5
  SHA512:
6
- metadata.gz: '08ee4ff5f61407bdcc390eb8c4cda6c286472672a6549ded81d5d0b1c7cf29f8203a472f9cfa5d4cfc811b1b8d923d4ee77ee6746decad1893a33c01187ecc1e'
7
- data.tar.gz: 0b94dde53ddce2444defb9933515dda0d4e754bb0e6053129927d82032bdb9b73383b5d67234a9b57f3e003e82e1b004c17c94f6e551a45ba2fc5dca412bd340
6
+ metadata.gz: a4af517774c9e5e90299d4877190d83659932acf7851bf04275d5c3066298411ca628084a490cfef6348b327d550c05d5cc4f96cab086e5c297e2a169e1f72b3
7
+ data.tar.gz: ba67dc90461e4350615a4ba9e232702efc27b241fa853a2934a80714bb5753c2aa1ebba06921ebe58e4db7145d8f3fb5d747be4ab37f8ad5da25150ab8c7ce8d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,77 @@ This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.95.0] - 2026-10-21
10
+
11
+ ### Changed — the `agent` SkillSet is rebuilt (1.0): long runs in the host session, a stand-in instead of terminal approvals
12
+
13
+ The 0.x agent could not carry the operator's ordinary request (design → design review → implement →
14
+ implementation review): its act route wrote only `docs/drafts/draft_*`, could not reach multi-LLM review or
15
+ tests, and counted only terminal-attested answers (0 counted pairs). Design:
16
+ `log/agent_skillset_rebuild_design_v0.5.1_20261020.md` (five review rounds, frozen as the author's proposal)
17
+ and its delta `log/agent_skillset_rebuild_design_v0.6.3_20261020.md`.
18
+
19
+ - The host session (Claude Code) is the only body. The SkillSet supplies a plan from a Ruby-DSL template, a
20
+ stand-in (isolated `claude -p --safe-mode --tools ""`, Opus 5.5) that answers decision points from the
21
+ operator's own words and the instruction mode, a guard (host hooks: `PreToolUse` on every tool, fail-closed)
22
+ that lets through only what the run created or its worktree and branch hold, a hash-chained journal, and a
23
+ report check. Six tools: `agent_start`, `agent_status`, `agent_advance`, `agent_items`, `agent_finish`,
24
+ `agent_stop`.
25
+ - Runs need an adopted policy (the operator's mandate, `config/policies/*.rb`), adopted by the operator's own
26
+ typed words naming its digest; the adoption is recorded on the chain.
27
+ - Templates: `dev_cycle`, `impl_cycle`, `design_only`, `doc_cycle` (a document kept in git, revised in place,
28
+ optional build check), `survey` (versioned survey files from local sources), `general`.
29
+ - A review closes only when no (a)/(b) P0 is open. Each review may take the policy's `review_rounds`
30
+ (10), counted for that review alone; at the cap it waits for the operator, who grants more rounds or
31
+ freezes it. Revisions follow L1 multi_llm_review_workflow § Revision
32
+ Discipline: each round says which new P0s the actor's last addition drew, and the next step is to undo it.
33
+ Design reviews stay at the design level; implementation-only findings are deferred to the implementation
34
+ review and are operator items at once.
35
+ - Every run ends with a layered-deck report (`report_kit/`, the kit of L1 `layered_visual_pitch_deck`).
36
+ - `bin/agent_harvest.rb` harvests the operator's own answers from host transcripts (hook output, peer
37
+ messages and pasted host output excluded).
38
+ - Removed: the in-server OODA loop, act-route table and terminal rulings, shadow judge, distillation,
39
+ native body, `agent_execute`, `agent_step`, `agent_wait`, `operator_report`, the `agent-monitor` subagent.
40
+ - `agent` is no longer installed automatically in new instances (it needs a policy and projects hooks).
41
+ An installed 0.x agent becomes 1.0 on upgrade. 1.0 needs `multi_llm_review` and `llm_client` >= 0.3.0 in
42
+ the same instance; upgrade does not install a missing one (`kairos-chain skillset install multi_llm_review`).
43
+
44
+ ### Added — `removed_files` in `skillset.json`; `system_upgrade` archives them
45
+
46
+ `upgrade_apply` copied changed files and never deleted one, so a SkillSet that dropped files left them to be
47
+ loaded. A template may now list `removed_files`; upgrade moves each from the installed copy to
48
+ `storage/skillset_removed/<name>/<time>/`, and a forced reinstall no longer restores a retired config file.
49
+
50
+ ### Added — `llm_call` options `no_fallback` and `isolated`
51
+
52
+ `no_fallback` makes an authentication failure on the configured provider a failure instead of a silent switch
53
+ to `claude_code`. `isolated` (claude_code) runs `claude -p --safe-mode --tools ""` in an empty directory, so
54
+ no CLAUDE.md, skills, plugins, hooks, memory or MCP servers reach the call. An isolated call's payload carries
55
+ `isolation` (`safe_mode`, `tools`, `cwd`, as `claude -p` was spawned); llm_client is 0.3.0. The agent's
56
+ stand-in refuses any reply without that evidence (and refuses to call an llm_client too old to isolate), and the
57
+ agent SkillSet declares `llm_client >= 0.3.0`; upgrade both together.
58
+
59
+ ### Added — `user_level_conflicts` in `skillset.json`; install and upgrade report them
60
+
61
+ A SkillSet may list files an earlier version left at user level that it cannot remove itself (e.g. a personal
62
+ skill that shadows the project's). `install`, `upgrade_apply`, `system_upgrade` and `kairos-chain skillset
63
+ install/upgrade` print the ones present as warnings, with a command that moves them to a timestamped backup.
64
+ agent 1.0 lists the 0.x personal skill `~/.claude/skills/agent/SKILL.md` and `~/.claude/agents/agent-monitor.md`.
65
+
66
+ ### Changed — the shipped agent policy needs a new adoption
67
+
68
+ `masa_2026_10_20.rb` sets `review_rounds` to 10 rounds for each review (counted apart, no longer shared by a
69
+ run's reviews) and drops the lookup consent comment (runs never look things up on the web). Its digest
70
+ changed: adopt it with `adopt policy masa_2026_10_20 8846b67e`.
71
+
72
+ ### Changed — L1 `multi_llm_review_workflow` 3.16.0 and `design_to_implementation_workflow` 1.3
73
+
74
+ A new entry-level clause, § Provisional delegation under a mandate: under a pinned, journaled operator policy a
75
+ named delegate — never the context whose work is judged — answers reserved judgments provisionally, and nothing
76
+ resolves, closes, freezes or demotes beyond the run until the operator confirms it in their own words. Pointers
77
+ from INV-U2, INV-U4, INV-U5, Step 0.25 and § Convergence Rules, and from the merge criteria of
78
+ `design_to_implementation_workflow`. An instance's own L1 copy is not rewritten by upgrade.
79
+
9
80
  ## [3.94.0] - 2026-10-20
10
81
 
11
82
  ### Added — L0 changes proposed for later approval, L0 restores on the record, L1 body history
data/bin/kairos-chain CHANGED
@@ -102,6 +102,7 @@ when 'skillset'
102
102
  result = manager.install(source, layer_override: layer_override, force: force)
103
103
  puts "Installed SkillSet '#{result[:name]}' v#{result[:version]} [#{result[:layer]}]"
104
104
  puts "Path: #{result[:path]}"
105
+ manager.user_level_conflicts(KairosMcp::Skillset.new(result[:path])).each { |w| puts " [WARNING] #{w}" }
105
106
 
106
107
  when 'enable'
107
108
  name = ARGV.shift
@@ -162,6 +163,7 @@ when 'skillset'
162
163
  puts "## SkillSets"
163
164
  results.each do |r|
164
165
  puts " [UPGRADED] #{r[:name].ljust(22)} v#{r[:from]} -> v#{r[:to]} (#{r[:files_updated]} files)"
166
+ Array(r[:warnings]).each { |w| puts " [WARNING] #{w}" }
165
167
  end
166
168
  checkable.reject { |ss| upgraded_names.include?(ss.name) }.each do |ss|
167
169
  puts " [UNCHANGED] #{ss.name.ljust(22)} v#{ss.version}"
@@ -87,6 +87,27 @@ module KairosMcp
87
87
  @metadata['config_files'] || []
88
88
  end
89
89
 
90
+ # Files a release takes out of an installed copy (relative paths). An
91
+ # upgrade copies changed files and never deletes; a SkillSet that drops
92
+ # files names them here so system_upgrade archives them instead of
93
+ # leaving them to be loaded (Skillset#load requires every tools/*.rb).
94
+ def removed_files
95
+ Array(@metadata['removed_files']).select do |rel|
96
+ rel.is_a?(String) && !rel.empty? && !rel.start_with?('/') && !rel.split('/').include?('..')
97
+ end
98
+ end
99
+
100
+ # Files outside the instance that an earlier version left at user level
101
+ # and that this version cannot remove itself (e.g. a personal skill that
102
+ # shadows the project's): each { "path": "~/...", "pattern": "regex",
103
+ # "note": "..." }. Upgrade reports the ones present; the operator moves
104
+ # them.
105
+ def user_level_conflicts
106
+ Array(@metadata['user_level_conflicts']).select do |c|
107
+ c.is_a?(Hash) && c['path'].is_a?(String) && c['path'].start_with?('~/') && !c['path'].split('/').include?('..')
108
+ end
109
+ end
110
+
90
111
  # Optional fail-closed activation hook: a fully-qualified class name
91
112
  # whose `activate_on_load!` runs at skillset-load time, independent of
92
113
  # whether any of the SkillSet's tools are instantiated. Used by
@@ -89,12 +89,14 @@ module KairosMcp
89
89
  dest = File.join(@skillsets_dir, temp_skillset.name)
90
90
  if File.directory?(dest)
91
91
  if force
92
- # Preserve user config files before replacing
92
+ # Preserve user config files (subdirectories included) before replacing
93
93
  config_dir = File.join(dest, 'config')
94
94
  saved_configs = {}
95
95
  if File.directory?(config_dir)
96
- Dir.glob(File.join(config_dir, '*')).each do |f|
97
- saved_configs[File.basename(f)] = File.read(f)
96
+ Dir.glob(File.join(config_dir, '**', '*')).each do |f|
97
+ next unless File.file?(f)
98
+
99
+ saved_configs[f.sub("#{config_dir}/", '')] = File.read(f)
98
100
  end
99
101
  end
100
102
 
@@ -103,12 +105,13 @@ module KairosMcp
103
105
  # Copy new version
104
106
  FileUtils.cp_r(source_path, dest)
105
107
 
106
- # Restore user configs
107
- unless saved_configs.empty?
108
- FileUtils.mkdir_p(File.join(dest, 'config'))
109
- saved_configs.each do |name, content|
110
- File.write(File.join(dest, 'config', name), content)
111
- end
108
+ # Restore user configs, except those the new version retired
109
+ retired = temp_skillset.removed_files.select { |r| r.start_with?('config/') }.map { |r| r.sub('config/', '') }
110
+ saved_configs.reject! { |rel, _| retired.include?(rel) }
111
+ saved_configs.each do |rel, content|
112
+ path = File.join(dest, 'config', rel)
113
+ FileUtils.mkdir_p(File.dirname(path))
114
+ File.write(path, content)
112
115
  end
113
116
  else
114
117
  raise ArgumentError, "SkillSet '#{temp_skillset.name}' already installed at #{dest}. Use --force to reinstall."
@@ -154,14 +157,16 @@ module KairosMcp
154
157
  template_ver = Gem::Version.new(template_ss.version)
155
158
 
156
159
  changed_files = diff_files(template_path, installed.path)
160
+ removals = template_ss.removed_files.select { |rel| File.exist?(File.join(installed.path, rel)) }
157
161
 
158
- if template_ver > installed_ver || changed_files.any?
162
+ if template_ver > installed_ver || changed_files.any? || removals.any?
159
163
  results << {
160
164
  name: installed.name,
161
165
  installed_version: installed.version,
162
166
  available_version: template_ss.version,
163
167
  version_bump: template_ver > installed_ver,
164
168
  changed_files: changed_files,
169
+ removed_files: removals,
165
170
  new_skillset: false
166
171
  }
167
172
  end
@@ -194,7 +199,7 @@ module KairosMcp
194
199
  # Others (multiuser, service_grant, hestia, mmp, skillset_exchange, mcp_client)
195
200
  # require PostgreSQL or networking and must be installed explicitly.
196
201
  CORE_SKILLSETS = %w[
197
- plugin_projector agent llm_client autoexec autonomos
202
+ plugin_projector llm_client autoexec autonomos
198
203
  skillset_creator knowledge_creator introspection dream
199
204
  document_authoring synoptis
200
205
  ].freeze
@@ -223,7 +228,8 @@ module KairosMcp
223
228
  # Install new SkillSet from template
224
229
  result = install(template_path)
225
230
  results << { name: info[:name], from: nil, to: info[:available_version],
226
- action: 'installed', files_updated: 0 }
231
+ action: 'installed', files_updated: 0,
232
+ warnings: user_level_conflicts(Skillset.new(File.join(@skillsets_dir, info[:name]))) }.reject { |_, v| v == [] }
227
233
  else
228
234
  # Upgrade existing: copy changed files
229
235
  dest = File.join(@skillsets_dir, info[:name])
@@ -233,11 +239,13 @@ module KairosMcp
233
239
  FileUtils.mkdir_p(File.dirname(dst))
234
240
  FileUtils.cp(src, dst) if File.exist?(src)
235
241
  end
242
+ archived = archive_removed_files(info[:name], dest, Array(info[:removed_files]))
236
243
 
237
244
  installed = Skillset.new(dest)
238
245
  record_skillset_event(installed, 'upgrade')
239
246
  results << { name: info[:name], from: info[:installed_version], to: info[:available_version],
240
- action: 'upgraded', files_updated: info[:changed_files].size }
247
+ action: 'upgraded', files_updated: info[:changed_files].size, files_archived: archived.size,
248
+ warnings: user_level_conflicts(installed) }.reject { |_, v| v == [] }
241
249
  end
242
250
  end
243
251
 
@@ -445,8 +453,45 @@ module KairosMcp
445
453
  all_skillsets.find { |ss| ss.name == name.to_s }
446
454
  end
447
455
 
456
+ # The user-level leftovers a SkillSet declares that are present now, as
457
+ # warnings with the command that moves them aside (a timestamped backup,
458
+ # so a second move never overwrites the first).
459
+ def user_level_conflicts(skillset)
460
+ skillset.user_level_conflicts.filter_map do |c|
461
+ path = File.expand_path(c['path'])
462
+ next unless File.exist?(path)
463
+ next if c['pattern'] && !File.read(path, encoding: 'UTF-8').match?(Regexp.new(c['pattern']))
464
+
465
+ backup = File.expand_path("~/.claude/#{skillset.name}_previous_version_backup/#{Time.now.strftime('%Y%m%d_%H%M%S')}")
466
+ "#{path}: #{c['note'] || 'left by an earlier version'} (move it aside: mkdir -p #{backup} && mv #{path} #{backup}/)"
467
+ end
468
+ rescue StandardError
469
+ []
470
+ end
471
+
448
472
  private
449
473
 
474
+ # Move files a release dropped out of the installed copy, into
475
+ # storage/skillset_removed/<name>/<time>/ (kept, not deleted, so the
476
+ # operator can read back what the upgrade took out). Paths are checked to
477
+ # stay inside the installed SkillSet.
478
+ def archive_removed_files(name, dest, rels)
479
+ return [] if rels.empty?
480
+
481
+ root = File.realpath(dest)
482
+ stamp = Time.now.utc.strftime('%Y%m%dT%H%M%SZ')
483
+ archive = File.join(KairosMcp.storage_dir, 'skillset_removed', name.to_s, stamp)
484
+ rels.filter_map do |rel|
485
+ src = File.join(root, rel)
486
+ next unless File.exist?(src) && File.expand_path(src).start_with?("#{root}/")
487
+
488
+ to = File.join(archive, rel)
489
+ FileUtils.mkdir_p(File.dirname(to))
490
+ FileUtils.mv(src, to)
491
+ rel
492
+ end
493
+ end
494
+
450
495
  # Compare files between template and installed SkillSet
451
496
  def diff_files(template_path, installed_path)
452
497
  changed = []
@@ -361,6 +361,7 @@ module KairosMcp
361
361
  actions[:skillsets_upgraded] = (actions[:skillsets_upgraded] || []) << r[:name]
362
362
  output += " [UPGRADED] #{r[:name]} v#{r[:from]} → v#{r[:to]} (#{r[:files_updated]} files)\n"
363
363
  end
364
+ Array(r[:warnings]).each { |w| output += " [WARNING] #{w}\n" }
364
365
  end
365
366
  end
366
367
  rescue => e
@@ -487,6 +488,7 @@ module KairosMcp
487
488
  else
488
489
  output += " [UPGRADED] #{r[:name]} v#{r[:from]} → v#{r[:to]} (#{r[:files_updated]} files)\n"
489
490
  end
491
+ Array(r[:warnings]).each { |w| output += " [WARNING] #{w}\n" }
490
492
  end
491
493
  output += "\nNo L0 template changes needed.\n"
492
494
  output += "Restart the MCP server to load new SkillSet tools.\n"
@@ -1,4 +1,4 @@
1
1
  module KairosMcp
2
- VERSION = "3.94.0"
2
+ VERSION = "3.95.0"
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: design_to_implementation_workflow
3
3
  description: "Full-lifecycle workflow for complex features: design review, self-review, implementation review, and final merge gate. Derived from Service Grant + Attestation Nudge experiments."
4
- version: "1.2"
4
+ version: "1.3"
5
5
  tags:
6
6
  - workflow
7
7
  - implementation
@@ -157,6 +157,9 @@ Claude Persona Assembly (4 personas):
157
157
  - NOT for intermediate rounds (diminishing returns)
158
158
 
159
159
  **Merge criteria**: new (a)+(b) P0 = 0, with the freeze declared by the operator.
160
+ Inside an agent run a review closes provisionally (`multi_llm_review_workflow`
161
+ § Provisional delegation under a mandate) and only the operator freezes one; the
162
+ operator's word at merge settles the merge and confirms only the closures it names.
160
163
  A Codex APPROVE is the strongest *reference* signal (see
161
164
  `multi_llm_reviewer_evaluation`), and it is not a gate: Codex went 24 of 24
162
165
  reviews without reaching APPROVE on one design loop, so a merge waiting on it
@@ -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.15.1"
4
+ version: "3.16.0"
5
5
  tags:
6
6
  - workflow
7
7
  - review
@@ -29,6 +29,21 @@ This skill covers:
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`
31
31
 
32
+ ## Provisional delegation under a mandate
33
+
34
+ This clause reaches every judgment that a norm pointing here reserves to a human, or gives to the context
35
+ whose work it judges. Under a human-authored mandate — which may be a standing operator-owned policy,
36
+ pinned by digest and journaled per run — a named delegate, never the context whose work the judgment
37
+ concerns, may answer named classes of such judgments provisionally. Reversible work proceeds within the
38
+ run on such an answer; the answer resolves, closes, freezes and demotes nothing beyond the run until the
39
+ human confirms it in the human's own words. A review closed this way is provisionally closed and is
40
+ reported as such; it is closed in the sense of § Convergence only on that confirmation.
41
+
42
+ *Why:* runs of the agent SkillSet (1.0) are started by the operator and not answered during them; the
43
+ operator's standing ruling of 2026-10-20 delegates reversible judgment to a stand-in that reads the
44
+ operator's own words. Provisionality keeps what each pointing norm protects — the human's last word —
45
+ without stopping the run at every judgment.
46
+
32
47
  ## Step -1 — Pre-declared review spec (loop hygiene)
33
48
 
34
49
  > Validation scope: these rules were derived from one non-converging loop
@@ -271,6 +286,8 @@ still in its transient state blocks dispatch until re-triaged.
271
286
  orchestrator posing a question and answering it itself does not constitute
272
287
  resolution. (Same conceptual line as ACT-1 in L2 attestation — analogical,
273
288
  not a shared implementation: judgment-shaped decisions belong to the human.)
289
+ Inside a run under a mandate, a delegate's answer in the interview is a provisional
290
+ declaration, not a resolution (§ Provisional delegation under a mandate).
274
291
 
275
292
  **INV-U3 (constitutive recording).** The products of the pass — enumerated
276
293
  questions, human answers, declared Open Unknowns — are recorded to L2. A
@@ -300,7 +317,9 @@ advisory by default, subject to two bounds:
300
317
 
301
318
  Findings about the *integrity* of the design — internal contradiction,
302
319
  unrealizable invariant, an Open Unknown whose declared deferral is itself
303
- unsafe — remain (a)/(b) and block as before.
320
+ unsafe — remain (a)/(b) and block as before. A provisional declaration made
321
+ under a mandate carries no demotion power beyond its run until the human
322
+ confirms it (§ Provisional delegation under a mandate).
304
323
 
305
324
  **INV-U5 (classification authority).** The judgment-shaped /
306
325
  non-judgment-shaped classification of an unknown is a human prerogative.
@@ -309,7 +328,9 @@ declining, or judging a question draft-answerable). Unattended, every
309
328
  surfaced unknown is judgment-shaped by default; only a human-authored
310
329
  mandate may pre-classify named categories as non-judgment-shaped for a given
311
330
  run. An orchestrator's self-classification has no force. (Fail-closed:
312
- unclassified ⇒ judgment-shaped ⇒ stop.)
331
+ unclassified ⇒ judgment-shaped ⇒ stop.) A standing operator-owned policy,
332
+ pinned and journaled per run, is a human-authored mandate (§ Provisional
333
+ delegation under a mandate).
313
334
 
314
335
  ### Unattended execution (autonomous loops)
315
336
 
@@ -334,7 +355,9 @@ same pending question produce no new side effects and no forward motion —
334
355
  re-stopping is idempotent; forward motion requires a human answer. The
335
356
  mandate's expressive power, the ratification protocol, and the
336
357
  pending-question queue mechanism are owned by the Autonomous Growth Loop
337
- guard track (see the frozen design's §11 backlog).
358
+ guard track (see the frozen design's §11 backlog). Mandates for unattended
359
+ growth loops remain with the Autonomous Growth Loop guard track; operator-started
360
+ agent runs use the policy form of § Provisional delegation under a mandate.
338
361
 
339
362
  ### Acceptance observation (selective survival)
340
363
 
@@ -744,7 +767,9 @@ subtractive — see § Revision Discipline), is a freeze candidate for the
744
767
  operator regardless of the numerator. Neither of the two 2026-08 threads
745
768
  ever reached its APPROVE ratio; both closed by (a)+(b) exhaustion + operator
746
769
  freeze declaration — the intended close described above, now with a
747
- measurable trigger.
770
+ measurable trigger. Inside a run under a mandate, the labelling and the closure
771
+ declaration are the delegate's, provisionally, and never the orchestrating
772
+ context's when that context did the work (§ Provisional delegation under a mandate).
748
773
 
749
774
  **Escalating raises the bar.** The rule is a ratio over the observers that
750
775
  counted, so adding reserve observers with `escalate: true` raises the number of
@@ -1993,6 +2018,16 @@ Compression ratio: parallel agent raw → Assembly ≈ 2:1
1993
2018
  Upgrading does not rewrite an instance's own `config/multi_llm_review.yml`,
1994
2019
  so an existing instance keeps Opus 4.6 until that entry is edited by hand.
1995
2020
 
2021
+ - Provisional delegation under a mandate (v3.16.0, 2026-10-21, operator
2022
+ decision: 「基本1-9はそのように進めて下さい」, adopting the agent SkillSet
2023
+ 1.0 L1 clause drafts). A new entry-level clause after § Overview lets a
2024
+ named delegate — never the context whose work is judged — answer reserved
2025
+ judgments provisionally under a pinned, journaled operator policy; nothing
2026
+ resolves, closes, freezes or demotes beyond the run until the human confirms
2027
+ in their own words. Pointers were appended to INV-U2, INV-U4, INV-U5, the
2028
+ Step 0.25 guard-track sentence and § Convergence Rules. Source: design
2029
+ `log/agent_skillset_rebuild_design_v0.5.1_20261020.md` §2 and its delta v0.6.6.
2030
+
1996
2031
  **Key insight**: Design reviews and implementation reviews find
1997
2032
  **categorically different bugs**. Both phases are necessary. The corollary that
1998
2033
  cost eight rounds to learn: **which of the two you are in is readable from the
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Harvest the operator's own words from host transcripts into the agent's
4
+ # precedent store (design v0.5.1 INV-5). Run it apart from runs, regularly:
5
+ # the host deletes transcripts after 30 days. The operator runs it; the
6
+ # store governs runs, so no run writes it.
7
+ #
8
+ # ruby .kairos/skillsets/agent/bin/agent_harvest.rb [--data-dir DIR] [--since-days N]
9
+ # [--import-snapshot SNAPSHOT_DIR] [--no-transcripts]
10
+
11
+ require_relative '../lib/agent/harvest'
12
+ require_relative '../lib/agent/run'
13
+
14
+ def arg(name)
15
+ i = ARGV.index(name)
16
+ i && ARGV[i + 1]
17
+ end
18
+
19
+ data_dir = arg('--data-dir') || ENV['KAIROS_DATA_DIR'] || File.join(ENV['CLAUDE_PROJECT_DIR'] || Dir.pwd, '.kairos')
20
+ since = (d = arg('--since-days')) ? Time.now - Integer(d) * 86_400 : nil
21
+ paths = KairosMcp::SkillSets::Agent::Paths.new(data_dir)
22
+ harvest = KairosMcp::SkillSets::Agent::Harvest.new(paths)
23
+ if (snap = arg('--import-snapshot'))
24
+ puts "imported #{harvest.import_snapshot(File.expand_path(snap))} snapshot records"
25
+ end
26
+ puts "harvested #{harvest.run(since: since)} new records from transcripts" unless ARGV.include?('--no-transcripts')
27
+ total = KairosMcp::SkillSets::Agent::Precedents.new(paths.precedents_dir).all.size
28
+ puts "the store at #{paths.precedents_dir} holds #{total}"
@@ -0,0 +1,17 @@
1
+ # The operator's policy — the mandate for agent runs (design v0.5.1 §2).
2
+ # A transcription of the operator's ruling of 2026-10-20 (L2
3
+ # ruling_agent_skillset_rebuild_premise_20261020): reduce questions to the
4
+ # minimum by judging autonomously from past logs and the instruction mode;
5
+ # follow the operator's past decisions rather than default recommendations;
6
+ # occasional mistakes are acceptable; claude -p from a host session; never
7
+ # unattended. It binds only after the operator adopts this file's digest in
8
+ # their own typed words; any edit changes the digest and needs a new adoption.
9
+
10
+ policy "masa_2026_10_20" do
11
+ stand_in may: [:precedent, :instruction_mode, :novel_reversible]
12
+ consent review: :configured_providers, of: :project_artifacts
13
+ free_of_personal_data projects: []
14
+ # Review rounds for each review, counted apart: the only cap on a review,
15
+ # which closes only when no P0 is open; at the cap it waits for the operator.
16
+ spend default: { review_rounds: 10, stand_in_calls: 300 }
17
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Host hook entry for the agent SkillSet (design v0.5.1 §4). One script for
4
+ # every event; the event name comes from the hook input. In a session that is
5
+ # not bound to a run it only marks the guard as seen (PreToolUse,
6
+ # SessionStart), tells KairosChain's own agent tools which session calls them,
7
+ # and keeps the operator's words that may later adopt, confirm or correct
8
+ # something; otherwise it returns without output, so ordinary sessions pay one
9
+ # Ruby start and a file stat.
10
+
11
+ require 'json'
12
+ require 'fileutils'
13
+
14
+ # The host may start hooks without a UTF-8 locale; journals and transcripts
15
+ # hold the operator's words in UTF-8.
16
+ Encoding.default_external = Encoding::UTF_8
17
+
18
+ input = begin
19
+ JSON.parse($stdin.read)
20
+ rescue JSON::ParserError => e
21
+ # Unreadable input cannot be attributed to a session; on a failing exit
22
+ # the plugin's PreToolUse command line blocks the call only if the session
23
+ # id it finds in the input is bound here.
24
+ warn "agent hook: unreadable hook input (#{e.message[0, 100]})"
25
+ exit 1
26
+ end
27
+
28
+ event = input['hook_event_name'].to_s
29
+ sid = input['session_id'].to_s
30
+ data_dir = ENV['KAIROS_DATA_DIR'] || File.join(ENV['CLAUDE_PROJECT_DIR'] || Dir.pwd, '.kairos')
31
+ root = File.join(data_dir, 'storage', 'agent')
32
+ safe = sid.gsub(/[^A-Za-z0-9_.-]/, '_')
33
+
34
+ bound = !sid.empty? && File.exist?(File.join(root, 'bindings', safe))
35
+ begin
36
+ if %w[PreToolUse SessionStart].include?(event) && !sid.empty?
37
+ FileUtils.mkdir_p(File.join(root, 'guard_seen'))
38
+ FileUtils.touch(File.join(root, 'guard_seen', safe))
39
+ end
40
+ rescue SystemCallError
41
+ # The prelude never blocks an ordinary session; a bound one fails closed below.
42
+ exit 0 unless bound
43
+ end
44
+
45
+ # KairosChain's own agent tools (a server whose name says kairos, never
46
+ # another server's agent_*) learn the calling session and its project in
47
+ # every session (INV-6), without loading the library (Hooks.agent_tool?).
48
+ AGENT_TOOL = /\Amcp__(.+)__agent_(start|status|advance|items|finish|stop)\z/
49
+ agent_tool = (m = AGENT_TOOL.match(input['tool_name'].to_s)) && m[1].match?(/kairos/i) ? m[2] : nil
50
+ # A bound session goes through the library, which also releases an ended
51
+ # run's guard once the operator has spoken.
52
+ if event == 'PreToolUse' && agent_tool && !bound
53
+ extra = { '_session_id' => sid, '_project_dir' => ENV['CLAUDE_PROJECT_DIR'] || input['cwd'] }.compact
54
+ puts JSON.generate('hookSpecificOutput' => { 'hookEventName' => 'PreToolUse', 'permissionDecision' => 'allow',
55
+ 'updatedInput' => (input['tool_input'] || {}).merge(extra) })
56
+ exit 0
57
+ end
58
+
59
+ # Words that may adopt a policy, or name a decision or item to confirm,
60
+ # correct or resolve (Hooks::REFERENCE).
61
+ REFERENCE = /(?<![A-Za-z0-9])[DI]\d+(?![0-9A-Za-z])|(?i:adopt\s+policy)|採用|訂正|承認|確定(?!申告)|差し戻/
62
+ needs_full = bound ||
63
+ (event == 'PostToolUse' && agent_tool == 'start') ||
64
+ (event == 'SessionStart' && Dir.exist?(File.join(root, 'runs'))) ||
65
+ (event == 'UserPromptSubmit' && input['prompt'].to_s.match?(REFERENCE))
66
+ exit 0 unless needs_full
67
+
68
+ begin
69
+ $LOAD_PATH.unshift(ENV['KAIROS_MCP_LIB']) if ENV['KAIROS_MCP_LIB']
70
+ require_relative '../lib/agent/hooks'
71
+
72
+ project_root = ENV['CLAUDE_PROJECT_DIR'] || File.dirname(data_dir)
73
+ paths = KairosMcp::SkillSets::Agent::Paths.new(data_dir)
74
+
75
+ # The operator's own deny and ask rules (user and project). A guard allow
76
+ # does not suppress the host's prompt for an ask rule, and a run's operator
77
+ # is not answering, so both are refused and queued (design §8). Bash rules
78
+ # are matched against every command the original line runs, before it is
79
+ # wrapped for confinement.
80
+ deny = []
81
+ rules = []
82
+ [File.expand_path('~/.claude/settings.json'),
83
+ File.join(project_root, '.claude', 'settings.json'),
84
+ File.join(project_root, '.claude', 'settings.local.json')].each do |path|
85
+ next unless File.exist?(path)
86
+
87
+ perms = JSON.parse(File.read(path))['permissions'] || {}
88
+ %w[deny ask].each do |kind|
89
+ Array(perms[kind]).each do |rule|
90
+ rule = rule.to_s.strip
91
+ if (m = rule.match(/\ABash\((.+)\)\z/))
92
+ pat = m[1]
93
+ prefix = pat.end_with?(':*')
94
+ # The host's wildcard form: * spans any text, a multi-line command's
95
+ # newlines too, and a final ' *' also takes the bare command
96
+ # (Bash(git commit *) names `git commit`).
97
+ body = Regexp.escape(prefix ? pat[0..-3] : pat).gsub('\\*', '.*').sub(/\\ \.\*\z/) { '(?:\s.*)?' }
98
+ # A prefix ends at a word: Bash(mv:*) names mv, not mvn.
99
+ deny << if !prefix then /\A\s*#{body}\s*\z/m
100
+ elsif pat[0..-3].match?(/\w\z/) then /\A\s*#{body}(?=\s|\z)/m
101
+ else /\A\s*#{body}/m
102
+ end
103
+ elsif rule == 'Bash'
104
+ deny << /./
105
+ elsif (m = rule.match(/\A([A-Za-z0-9_*-]+)(?:\((.*)\))?\z/))
106
+ rules << { 'kind' => kind, 'tool' => m[1], 'spec' => m[2] }
107
+ end
108
+ end
109
+ end
110
+ rescue JSON::ParserError
111
+ next
112
+ end
113
+
114
+ stand_in_factory = lambda do |_run, policy|
115
+ llm_call = File.join(data_dir, 'skillsets', 'llm_client', 'tools', 'llm_call.rb')
116
+ require 'kairos_mcp/tools/base_tool'
117
+ require llm_call
118
+ KairosMcp::SkillSets::Agent::StandIn.new(
119
+ policy: policy,
120
+ instruction_mode: KairosMcp::SkillSets::Agent::InstructionMode.load(data_dir),
121
+ llm: KairosMcp::SkillSets::Agent::StandIn.default_llm(KairosMcp::SkillSets::LlmClient::Tools::LlmCall)
122
+ )
123
+ end
124
+
125
+ hooks = KairosMcp::SkillSets::Agent::Hooks.new(paths: paths, project_root: project_root,
126
+ stand_in_factory: stand_in_factory, settings_deny: deny,
127
+ settings_rules: rules)
128
+ out = hooks.handle(event, input)
129
+ puts JSON.generate(out) if out
130
+ exit 0
131
+ rescue StandardError, ScriptError => e
132
+ warn "agent hook (#{event}): #{e.class}: #{e.message[0, 300]}"
133
+ if event == 'PreToolUse' && bound
134
+ puts JSON.generate('hookSpecificOutput' => { 'hookEventName' => 'PreToolUse', 'permissionDecision' => 'deny',
135
+ 'permissionDecisionReason' => "agent guard failed: #{e.class}" })
136
+ exit 0
137
+ end
138
+ exit 1
139
+ end