kairos-chain 3.92.0 → 3.93.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -0
- data/bin/kairos-chain +3 -1
- data/lib/kairos_mcp/plugin_projector.rb +60 -2
- data/lib/kairos_mcp/tools/instructions_update.rb +27 -2
- data/lib/kairos_mcp/tools/system_upgrade.rb +4 -1
- data/lib/kairos_mcp/version.rb +1 -1
- data/lib/kairos_mcp.rb +7 -0
- data/templates/skills/proactive_tutorial.md +310 -0
- data/templates/skillsets/llm_client/skillset.json +1 -1
- data/templates/skillsets/llm_client/test/test_llm_call_requested_model.rb +57 -0
- data/templates/skillsets/llm_client/tools/llm_call.rb +5 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1624b7fa2adf2856c0f55ca0012dc527870d5649cdcad7ebe2d8ae90cda1d4a
|
|
4
|
+
data.tar.gz: 12cdc74b57b87266ca3364654468fa077774665e9b1bef090dea9806907c4b1b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9e47baf8089acd2fb9cc4f7f5fc4264d55d4096f8ed21aacb1a736ab27099beebda372d429de1e5a424e66307ccda5a274f5532073e7e21eaa4bc5d58684a718
|
|
7
|
+
data.tar.gz: 4deb91c26655f7c6e11a72802635a7c088aa0a7246124785984d2fe2f20fbb0ab02e0b2d27e425948a8107be69fe5cd1f72d4ca90efc069f12731bef9ec36e79
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,79 @@ All notable changes to the `kairos-chain` gem will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project follows [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [3.93.0] - 2026-10-19
|
|
10
|
+
|
|
11
|
+
### Added — `proactive_tutorial`, an opt-in mode that suggests KairosChain's own workflow
|
|
12
|
+
|
|
13
|
+
Claude Code passes only the head of an MCP server's instructions to the model
|
|
14
|
+
(4,096 characters by default, 2,048 in older builds). Until a mode is projected
|
|
15
|
+
into CLAUDE.md, the `tutorial` mode's "Proactive Tool Usage" section (line 82 of
|
|
16
|
+
309) never reaches the model.
|
|
17
|
+
|
|
18
|
+
- New shipped mode `proactive_tutorial`. Its first section, which fits inside
|
|
19
|
+
the 2,048-character cap after the first-run hint, has the model offer to save
|
|
20
|
+
L2 contexts, promote L1 knowledge, tidy up (`dream_scan`, `skills_audit`),
|
|
21
|
+
run multi-LLM review on hard-to-undo changes, point at installed skills, and
|
|
22
|
+
draft a project mode once L1 shows a theme (or, in the first session, the
|
|
23
|
+
project has docs). Writes happen only after the user says yes. Switch with
|
|
24
|
+
`instructions_update(command: "set_mode", mode_name: "proactive_tutorial")`;
|
|
25
|
+
the default stays `tutorial`. Existing instances receive the file on the next
|
|
26
|
+
`system_upgrade`.
|
|
27
|
+
- `instructions_update set_mode` now warns when CLAUDE.md still imports a mode
|
|
28
|
+
body projected for a different mode, and names the command that fixes it
|
|
29
|
+
(`kairos-chain mode project`, or `kairos-chain mode remove` for `none`).
|
|
30
|
+
|
|
31
|
+
### Fixed — projected hooks run against the data directory they were projected from
|
|
32
|
+
|
|
33
|
+
A project whose `.mcp.json` starts kairos-chain with another project's data
|
|
34
|
+
directory (`--data-dir /…/KairosChain_2026/.kairos` in GenomicsChain_2025; 16
|
|
35
|
+
projects on the reporting machine point at that one directory) got the shared
|
|
36
|
+
directory's SkillSet hooks projected into its own `.claude/settings.json`. Each
|
|
37
|
+
hook resolved its script as `${KAIROS_DATA_DIR:-$CLAUDE_PROJECT_DIR/.kairos}/…`
|
|
38
|
+
with `KAIROS_DATA_DIR` unset, so it looked in the wrong project:
|
|
39
|
+
model_provenance failed with `LoadError` on every Stop, SubagentStop and model
|
|
40
|
+
switch (46 times across two sessions, 2026-10-06 and 10-18) and observed
|
|
41
|
+
nothing; project_manager's session-start report failed the same way. A harness
|
|
42
|
+
tells a hook where the project is, never where the data directory is.
|
|
43
|
+
|
|
44
|
+
- When the data directory is not `<project root>/.kairos`, PluginProjector now
|
|
45
|
+
prefixes every projected hook command with the pair it projected from:
|
|
46
|
+
`export KAIROS_DATA_DIR=<dir> KAIROS_PROJECT_ROOT=<root>;`, shell-escaped.
|
|
47
|
+
The project root goes with it because `kairos-plugin-project` otherwise falls
|
|
48
|
+
back to the data dir's parent — the other project — when the hook's working
|
|
49
|
+
directory is not a plausible root. The two are always set together: the
|
|
50
|
+
agent SkillSet hands children both as a pair, and half a pair cross-wires a
|
|
51
|
+
re-projection. The default layout is projected exactly as before, and
|
|
52
|
+
hand-written hooks are never touched.
|
|
53
|
+
- Plugin mode is left as declared: `hooks/hooks.json` is distributable, and a
|
|
54
|
+
data directory on the projecting machine means nothing on the consumer's.
|
|
55
|
+
- `system_upgrade` and `kairos-chain upgrade` re-projected without `data_dir:`,
|
|
56
|
+
so in a project sharing a data directory they wrote the hooks as if it were
|
|
57
|
+
local and dropped the fix until the next server start; both now pass it.
|
|
58
|
+
- The Codex host's `--host` rewrite now applies only to what follows the pinned
|
|
59
|
+
prefix, so a data-directory or project path containing `kairos-plugin-project`
|
|
60
|
+
or `--host` is never rewritten.
|
|
61
|
+
- No SkillSet changes: model_provenance and project_manager keep their bare
|
|
62
|
+
`ruby` commands, which run under whatever Ruby the project selects. A gem
|
|
63
|
+
executable would not: under rbenv a project pinned to another Ruby (two of the
|
|
64
|
+
16 above run 3.3.7 / 3.3.10) cannot find it.
|
|
65
|
+
|
|
66
|
+
To pick this up, install this gem under the Ruby each project's MCP server runs
|
|
67
|
+
on — for most projects the usual one; for a project whose `.ruby-version` or
|
|
68
|
+
`.mcp.json` command selects another Ruby, that Ruby too — then restart the
|
|
69
|
+
project's session so projection runs again.
|
|
70
|
+
|
|
71
|
+
### Added — llm_client 0.2.2: `llm_call` reports the model ID it asked for
|
|
72
|
+
|
|
73
|
+
The success payload gains `requested_model` (the per-call `model` override, else
|
|
74
|
+
the configured `model`) beside `model` (what the provider answered with). On
|
|
75
|
+
Bedrock the two differ — `eu.anthropic.claude-sonnet-5-5` is sent and
|
|
76
|
+
`claude-sonnet-5-5` comes back — and only the first names the inference profile,
|
|
77
|
+
and with it the region. gc_tier1_assess records it in a report's
|
|
78
|
+
`assessor_stack.llm.model_requested`. Additive; no field changed or removed.
|
|
79
|
+
|
|
7
80
|
## [3.92.0] - 2026-10-13
|
|
8
81
|
|
|
9
82
|
### Added — agent: judgment precedents the shadow judge reads, distilled from your answers
|
data/bin/kairos-chain
CHANGED
|
@@ -187,7 +187,9 @@ when 'skillset'
|
|
|
187
187
|
require 'kairos_mcp/plugin_projector'
|
|
188
188
|
project_root = KairosMcp.project_root
|
|
189
189
|
mode = KairosMcp.projection_mode
|
|
190
|
-
|
|
190
|
+
# data_dir: see system_upgrade.rb — the projector must know where the
|
|
191
|
+
# SkillSets live, or a shared data dir is projected as if it were local.
|
|
192
|
+
projector = KairosMcp::PluginProjector.new(project_root, mode: mode, data_dir: KairosMcp.data_dir)
|
|
191
193
|
enabled = manager.enabled_skillsets
|
|
192
194
|
knowledge = KairosMcp.collect_knowledge_entries
|
|
193
195
|
if projector.project_if_changed!(enabled, knowledge_entries: knowledge)
|
|
@@ -6,6 +6,7 @@ require 'fileutils'
|
|
|
6
6
|
require 'tempfile'
|
|
7
7
|
require 'time'
|
|
8
8
|
require 'pathname'
|
|
9
|
+
require 'shellwords'
|
|
9
10
|
require_relative 'path_containment'
|
|
10
11
|
|
|
11
12
|
module KairosMcp
|
|
@@ -335,6 +336,7 @@ module KairosMcp
|
|
|
335
336
|
end
|
|
336
337
|
|
|
337
338
|
project_knowledge_meta_skill!(knowledge_entries, current_outputs) unless reuse_skills
|
|
339
|
+
pin_data_dir_in_hook_commands!(merged_hooks)
|
|
338
340
|
write_merged_hooks!(merged_hooks, current_outputs)
|
|
339
341
|
write_host_mcp_config!(current_outputs)
|
|
340
342
|
cleanup_stale!(previous_manifest, current_outputs)
|
|
@@ -704,6 +706,57 @@ module KairosMcp
|
|
|
704
706
|
warn "[PluginProjector] ERROR: #{hooks_file} has invalid JSON: #{e.message}"
|
|
705
707
|
end
|
|
706
708
|
|
|
709
|
+
# A projected hook runs with the project root as its only location (the
|
|
710
|
+
# harness exports CLAUDE_PROJECT_DIR, and runs hooks there); it has no way
|
|
711
|
+
# to learn the data directory. When the data directory is not
|
|
712
|
+
# <project_root>/.kairos — a project whose .mcp.json starts kairos-chain
|
|
713
|
+
# with another project's data dir — every projected command is prefixed
|
|
714
|
+
# with the pair this projection used. KAIROS_DATA_DIR is what
|
|
715
|
+
# KairosMcp.resolve_data_dir and the ${KAIROS_DATA_DIR:-...} form read
|
|
716
|
+
# first; KAIROS_PROJECT_ROOT goes with it because kairos-plugin-project
|
|
717
|
+
# otherwise falls back to File.dirname(data dir) — the other project —
|
|
718
|
+
# when the hook's cwd is not a plausible root. The two are always set as
|
|
719
|
+
# a pair: half a pair cross-wires a re-projection.
|
|
720
|
+
#
|
|
721
|
+
# The default layout is projected as written. Clearing an inherited
|
|
722
|
+
# KAIROS_DATA_DIR there was tried and withdrawn (review R2, 2026-10-19):
|
|
723
|
+
# the agent SkillSet hands children both variables as a pair, and hosts
|
|
724
|
+
# without CLAUDE_PROJECT_DIR (Codex) have only the inherited variable.
|
|
725
|
+
#
|
|
726
|
+
# Plugin mode is left alone: hooks/hooks.json is a distributable artifact,
|
|
727
|
+
# and the data directory is the consumer's to resolve, not this machine's.
|
|
728
|
+
# Hand-written settings.json hooks never enter merged_hooks.
|
|
729
|
+
def pin_data_dir_in_hook_commands!(merged_hooks)
|
|
730
|
+
prefix = hook_command_prefix
|
|
731
|
+
return if prefix.empty?
|
|
732
|
+
|
|
733
|
+
merged_hooks.fetch('hooks', {}).each_value do |handlers|
|
|
734
|
+
next unless handlers.is_a?(Array)
|
|
735
|
+
handlers.each do |h|
|
|
736
|
+
next unless h.is_a?(Hash)
|
|
737
|
+
targets = h['hooks'].is_a?(Array) ? h['hooks'] : [h]
|
|
738
|
+
targets.each do |inner|
|
|
739
|
+
next unless inner.is_a?(Hash) && inner['command'].is_a?(String)
|
|
740
|
+
inner['command'] = prefix + inner['command']
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
# The prefix pin_data_dir_in_hook_commands! puts in front of every
|
|
747
|
+
# projected command; empty when nothing is pinned. Host rewrites use it to
|
|
748
|
+
# leave the pinned paths alone.
|
|
749
|
+
def hook_command_prefix
|
|
750
|
+
return '' if @mode == :plugin || !data_dir_relocated?
|
|
751
|
+
|
|
752
|
+
"export KAIROS_DATA_DIR=#{Shellwords.escape(File.expand_path(@data_dir))} " \
|
|
753
|
+
"KAIROS_PROJECT_ROOT=#{Shellwords.escape(File.expand_path(@project_root))}; "
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
def data_dir_relocated?
|
|
757
|
+
canonicalize(@data_dir) != canonicalize(File.join(@project_root, '.kairos'))
|
|
758
|
+
end
|
|
759
|
+
|
|
707
760
|
# MCP connection config delivery is owned by the profile (INV-H4). Only
|
|
708
761
|
# meaningful in :project mode (plugin mode has no consumer project root to
|
|
709
762
|
# write connection config into).
|
|
@@ -750,14 +803,19 @@ module KairosMcp
|
|
|
750
803
|
# Deep-copies so the shared merged_hooks (used by other hosts) is not mutated.
|
|
751
804
|
def rewrite_hook_commands_for_host(merged_hooks)
|
|
752
805
|
copy = JSON.parse(JSON.generate(merged_hooks))
|
|
806
|
+
pinned = hook_command_prefix
|
|
753
807
|
copy.fetch('hooks', {}).each_value do |handlers|
|
|
754
808
|
next unless handlers.is_a?(Array)
|
|
755
809
|
handlers.each do |h|
|
|
756
810
|
Array(h['hooks']).each do |inner|
|
|
757
811
|
cmd = inner['command']
|
|
758
|
-
next unless cmd.is_a?(String)
|
|
812
|
+
next unless cmd.is_a?(String)
|
|
813
|
+
# Rewrite only what follows the pinned prefix: the prefix holds
|
|
814
|
+
# paths, and a path may contain this name or '--host'.
|
|
815
|
+
head, body = !pinned.empty? && cmd.start_with?(pinned) ? [pinned, cmd[pinned.size..]] : ['', cmd]
|
|
816
|
+
next unless body.include?('kairos-plugin-project') && !body.include?('--host')
|
|
759
817
|
# Insert right after the binary token so compound commands (a && b) stay correct.
|
|
760
|
-
inner['command'] =
|
|
818
|
+
inner['command'] = head + body.sub('kairos-plugin-project', "kairos-plugin-project --host #{@host.key}")
|
|
761
819
|
end
|
|
762
820
|
end
|
|
763
821
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'digest'
|
|
4
4
|
require 'fileutils'
|
|
5
|
+
require 'json'
|
|
5
6
|
require_relative 'base_tool'
|
|
6
7
|
require_relative '../skills_config'
|
|
7
8
|
require_relative '../action_log'
|
|
@@ -10,7 +11,8 @@ module KairosMcp
|
|
|
10
11
|
module Tools
|
|
11
12
|
class InstructionsUpdate < BaseTool
|
|
12
13
|
# Protected built-in files that cannot be deleted
|
|
13
|
-
PROTECTED_FILES = %w[kairos.md kairos_quickguide.md kairos_tutorial.md researcher.md
|
|
14
|
+
PROTECTED_FILES = %w[kairos.md kairos_quickguide.md kairos_tutorial.md researcher.md
|
|
15
|
+
proactive_tutorial.md].freeze
|
|
14
16
|
# Reserved mode names that map to built-in behavior
|
|
15
17
|
RESERVED_MODES = %w[developer user tutorial none].freeze
|
|
16
18
|
|
|
@@ -373,7 +375,8 @@ module KairosMcp
|
|
|
373
375
|
"**Previous**: `#{prev_mode}`\n" \
|
|
374
376
|
"**New**: `#{mode_name}`\n\n" \
|
|
375
377
|
"Recorded to blockchain (full recording, L0_law level).\n" \
|
|
376
|
-
"New instructions take effect on next MCP client connection."
|
|
378
|
+
"New instructions take effect on next MCP client connection." \
|
|
379
|
+
"#{stale_projection_notice(mode_name)}"
|
|
377
380
|
)
|
|
378
381
|
rescue StandardError => e
|
|
379
382
|
text_content("❌ Failed: #{e.message}")
|
|
@@ -381,6 +384,28 @@ module KairosMcp
|
|
|
381
384
|
|
|
382
385
|
# --- helpers ---
|
|
383
386
|
|
|
387
|
+
# A body projected into CLAUDE.md for another mode keeps reaching the
|
|
388
|
+
# model next to the new one until it is re-projected. Same manifest test
|
|
389
|
+
# as Protocol#instruction_mode_projected?.
|
|
390
|
+
def stale_projection_notice(mode_name)
|
|
391
|
+
manifest_path = File.join(KairosMcp.data_dir, 'instruction_mode_manifest.json')
|
|
392
|
+
return '' unless File.exist?(manifest_path)
|
|
393
|
+
|
|
394
|
+
data = JSON.parse(File.read(manifest_path))
|
|
395
|
+
projected = data['mode_name']
|
|
396
|
+
return '' unless data['region_present'] && projected && projected != mode_name
|
|
397
|
+
|
|
398
|
+
fix, effect = if mode_name == 'none'
|
|
399
|
+
['kairos-chain mode remove', 'which keeps reaching the model although the mode is now none']
|
|
400
|
+
else
|
|
401
|
+
['kairos-chain mode project', 'which keeps reaching the model alongside the new mode']
|
|
402
|
+
end
|
|
403
|
+
"\n\n⚠️ This project's CLAUDE.md still imports the projected `#{projected}` body, #{effect}. " \
|
|
404
|
+
"Run `#{fix}` from the project root, then restart Claude Code."
|
|
405
|
+
rescue StandardError
|
|
406
|
+
''
|
|
407
|
+
end
|
|
408
|
+
|
|
384
409
|
def instructions_path(mode_name)
|
|
385
410
|
File.join(KairosMcp.skills_dir, "#{mode_name}.md")
|
|
386
411
|
end
|
|
@@ -375,7 +375,10 @@ module KairosMcp
|
|
|
375
375
|
require_relative '../skillset_manager'
|
|
376
376
|
project_root = KairosMcp.project_root
|
|
377
377
|
mode = KairosMcp.projection_mode
|
|
378
|
-
|
|
378
|
+
# data_dir must be the one the SkillSets come from: without it the
|
|
379
|
+
# projector assumes <project_root>/.kairos and, in a project sharing
|
|
380
|
+
# another's data dir, writes hooks that look in the wrong place.
|
|
381
|
+
projector = KairosMcp::PluginProjector.new(project_root, mode: mode, data_dir: KairosMcp.data_dir)
|
|
379
382
|
mgr = KairosMcp::SkillSetManager.new
|
|
380
383
|
enabled = mgr.enabled_skillsets
|
|
381
384
|
knowledge = KairosMcp.collect_knowledge_entries
|
data/lib/kairos_mcp/version.rb
CHANGED
data/lib/kairos_mcp.rb
CHANGED
|
@@ -18,6 +18,7 @@ module KairosMcp
|
|
|
18
18
|
['skills/kairos_quickguide.md', :quickguide_path],
|
|
19
19
|
['skills/kairos_tutorial.md', :tutorial_path],
|
|
20
20
|
['skills/researcher.md', :researcher_path],
|
|
21
|
+
['skills/proactive_tutorial.md', :proactive_tutorial_path],
|
|
21
22
|
['skills/config.yml', :skills_config_path],
|
|
22
23
|
['config/safety.yml', :safety_config_path],
|
|
23
24
|
['config/tool_metadata.yml', :tool_metadata_path]
|
|
@@ -30,6 +31,7 @@ module KairosMcp
|
|
|
30
31
|
'skills/kairos_quickguide.md' => :l0_doc,
|
|
31
32
|
'skills/kairos_tutorial.md' => :l0_doc,
|
|
32
33
|
'skills/researcher.md' => :l0_doc,
|
|
34
|
+
'skills/proactive_tutorial.md' => :l0_doc,
|
|
33
35
|
'skills/config.yml' => :config_yaml,
|
|
34
36
|
'config/safety.yml' => :config_yaml,
|
|
35
37
|
'config/tool_metadata.yml' => :config_yaml
|
|
@@ -141,6 +143,11 @@ module KairosMcp
|
|
|
141
143
|
File.join(skills_dir, 'researcher.md')
|
|
142
144
|
end
|
|
143
145
|
|
|
146
|
+
# Proactive tutorial instruction mode file path
|
|
147
|
+
def proactive_tutorial_path
|
|
148
|
+
File.join(skills_dir, 'proactive_tutorial.md')
|
|
149
|
+
end
|
|
150
|
+
|
|
144
151
|
# L0 skills config file path
|
|
145
152
|
def skills_config_path
|
|
146
153
|
File.join(skills_dir, 'config.yml')
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# KairosChain Proactive Tutorial Mode
|
|
2
|
+
|
|
3
|
+
## Use KairosChain proactively (read this first)
|
|
4
|
+
|
|
5
|
+
Suggest KairosChain tools unasked; read-only calls need no permission. Saving, promotion, archiving, recording and mode changes happen only after the user says yes. Say in one line what you did and why; explain a KairosChain term plainly the first time.
|
|
6
|
+
|
|
7
|
+
1. L2 (session memory): when a unit of work ends or the conversation has grown long, offer `context_save()`.
|
|
8
|
+
2. L1 (reusable knowledge): when work repeats something in 2+ past L2 contexts, offer `knowledge_update()` with a draft.
|
|
9
|
+
3. Tidy up: L2 past ~10 contexts, offer `dream_scan()` (it records a summary); L1 past ~10 entries, offer `skills_audit(command: "check")`.
|
|
10
|
+
4. Review: for hard-to-undo changes, offer multi-LLM review if the `multi_llm_review` tool exists; else mention it.
|
|
11
|
+
5. Skill tips: when an installed skill or SkillSet fits the task, name it in one line.
|
|
12
|
+
6. Own mode: when L1 holds ~10 entries sharing a theme (or, in the first session, the project has docs), offer once to draft a project mode (`instructions_update`) with this section at its top.
|
|
13
|
+
|
|
14
|
+
Limit: one suggestion at a time, at a natural break; never interrupt work. Do not repeat a declined offer until the situation changes.
|
|
15
|
+
|
|
16
|
+
## Why this section comes first
|
|
17
|
+
|
|
18
|
+
Claude Code passes an MCP server's instructions to the model only up to a
|
|
19
|
+
character cap (4,096 characters by default; 2,048 in older versions) and drops
|
|
20
|
+
the rest. Until this mode is projected into the project's CLAUDE.md
|
|
21
|
+
(`kairos-chain mode project`), only the beginning of this file reaches you. The
|
|
22
|
+
section above is therefore kept within the first ~1,250 characters of the body,
|
|
23
|
+
and everything below is detail for when the full body is available. After
|
|
24
|
+
projection the whole file is delivered. Nothing below overrides the rules
|
|
25
|
+
above; where a detail seems to, the rules above win.
|
|
26
|
+
|
|
27
|
+
## Identity
|
|
28
|
+
|
|
29
|
+
This is a KairosChain instance in proactive tutorial mode. It is the tutorial
|
|
30
|
+
mode with one difference: KairosChain's own workflow — saving sessions,
|
|
31
|
+
promoting patterns, tidying knowledge, reviewing risky changes, pointing at
|
|
32
|
+
useful skills — is suggested actively instead of waiting to be discovered.
|
|
33
|
+
The user's task still comes first; suggestions are made at natural breaks and
|
|
34
|
+
are always declinable.
|
|
35
|
+
|
|
36
|
+
## First Session Greeting
|
|
37
|
+
|
|
38
|
+
When you detect this is the user's first session (no L2 contexts exist),
|
|
39
|
+
include a brief orientation **once**, at a natural break point (not as the very
|
|
40
|
+
first message). Keep it to ~3 lines + a one-line menu offer:
|
|
41
|
+
|
|
42
|
+
> KairosChain は作業中に発見された知識を記録・整理する仕組みです。
|
|
43
|
+
> L2 (session memory) → L1 (reusable patterns) → L0 (philosophy/rules) の3層で、
|
|
44
|
+
> L0/L1 の変更はすべて blockchain に記録されます。
|
|
45
|
+
>
|
|
46
|
+
> 「もう少し知りたい?」「まず作業を進める?」どちらでも。
|
|
47
|
+
|
|
48
|
+
Then wait for signal:
|
|
49
|
+
- If the user shows interest → offer the **Concept Menu** (below)
|
|
50
|
+
- If the user says "work first", ignores, or proceeds to a task → continue with
|
|
51
|
+
the work. Do not re-offer the intro in the same session.
|
|
52
|
+
|
|
53
|
+
Rule: the intro must be ≤ 5 lines total. Never expand into a tutorial monologue.
|
|
54
|
+
|
|
55
|
+
## Concept Menu (on-demand only)
|
|
56
|
+
|
|
57
|
+
When the user opts in, offer topics as a short list — never deliver them all at once:
|
|
58
|
+
|
|
59
|
+
- L2 / L1 / L0 の3層とは?
|
|
60
|
+
- blockchain には何が記録される?
|
|
61
|
+
- 自己言及性(self-referentiality)とは?
|
|
62
|
+
- 使い始めの最小ステップ
|
|
63
|
+
|
|
64
|
+
Explain **one topic at a time, ≤ 150 words each**, and always end with:
|
|
65
|
+
"次を聞きますか? それとも作業に戻りますか?"
|
|
66
|
+
|
|
67
|
+
If the user asks a topic not on the menu (e.g., "SkillSet って何?"), answer
|
|
68
|
+
briefly and offer to continue or stop. Follow curiosity; do not force a path.
|
|
69
|
+
|
|
70
|
+
## Existing Project Fast-Track
|
|
71
|
+
|
|
72
|
+
In the first session, check for existing project artifacts:
|
|
73
|
+
- README.md, CLAUDE.md, CONVENTIONS.md, CONTRIBUTING.md
|
|
74
|
+
- log/ directory with development logs
|
|
75
|
+
- docs/ directory
|
|
76
|
+
- .cursor/rules or .cursorrules
|
|
77
|
+
- Existing CI/CD configuration, Makefile, package.json scripts, etc.
|
|
78
|
+
|
|
79
|
+
If significant artifacts are found, offer a fast-track option at the first natural
|
|
80
|
+
break — after the user's first task is under way, never before it. Offer it
|
|
81
|
+
*instead of* the greeting at that break, not together with it (one suggestion at
|
|
82
|
+
a time). This is item 6 of the first section: existing project documentation
|
|
83
|
+
counts as the theme that L1 would otherwise have to accumulate.
|
|
84
|
+
|
|
85
|
+
> "I found existing project documentation (README.md, log/, docs/, ...).
|
|
86
|
+
> I can analyze these to suggest a project-specific configuration right away.
|
|
87
|
+
> Want to try that, or prefer to start fresh and build up gradually?"
|
|
88
|
+
|
|
89
|
+
### If the user chooses fast-track:
|
|
90
|
+
|
|
91
|
+
1. Read and analyze all detected artifacts
|
|
92
|
+
2. Identify key themes: domain, conventions, priorities, workflow patterns
|
|
93
|
+
3. Draft a custom instruction mode reflecting the project's existing identity.
|
|
94
|
+
Put a copy of the "Use KairosChain proactively" section at the top of the
|
|
95
|
+
draft, so the custom mode keeps this mode's suggestions.
|
|
96
|
+
4. Present the draft to the user for review and adjustment
|
|
97
|
+
5. On approval, use `instructions_update(command: "create", ...)` to create the custom mode
|
|
98
|
+
and `instructions_update(command: "set_mode", ...)` to switch to it immediately
|
|
99
|
+
6. Also bulk-import obvious patterns as initial L1 knowledge candidates using `knowledge_update()`
|
|
100
|
+
(propose as a list, user selects which to keep)
|
|
101
|
+
|
|
102
|
+
### If the user declines:
|
|
103
|
+
|
|
104
|
+
Continue with the suggestions in this mode. The greeting may follow at a later
|
|
105
|
+
natural break.
|
|
106
|
+
|
|
107
|
+
## Proactive Suggestions — Details
|
|
108
|
+
|
|
109
|
+
These expand the six items at the top. The thresholds (~10) are starting
|
|
110
|
+
points, not rules; adjust to how the user actually works.
|
|
111
|
+
|
|
112
|
+
### 1. L2 — saving the session
|
|
113
|
+
|
|
114
|
+
- Offer `context_save()` when a unit of work finishes (a feature, a fix, a
|
|
115
|
+
document section), when the user signals a break, and when the conversation
|
|
116
|
+
has grown long enough that earlier details may be lost.
|
|
117
|
+
- Save a concise plan / result / next-step summary with tags — not a transcript.
|
|
118
|
+
- If the user declines, do not offer again until the next unit of work finishes.
|
|
119
|
+
|
|
120
|
+
### 2. L1 — promoting a pattern
|
|
121
|
+
|
|
122
|
+
- Triggers: the same tool or command sequence, file structure, naming
|
|
123
|
+
convention, problem-solving approach, or review criterion appearing in 2+ past
|
|
124
|
+
L2 contexts.
|
|
125
|
+
- Show the draft entry (name, one-sentence description, tags, content) and ask
|
|
126
|
+
before calling `knowledge_update()`.
|
|
127
|
+
|
|
128
|
+
### 3. Tidying up
|
|
129
|
+
|
|
130
|
+
- `dream_scan()` reads L2 and reports promotion candidates (tags recurring
|
|
131
|
+
across sessions), consolidation candidates (contexts with overlapping names),
|
|
132
|
+
and archive candidates (contexts untouched for a long time). It is not
|
|
133
|
+
read-only: when it finds anything, it records a summary block on the chain,
|
|
134
|
+
so call it only after the user agrees. Present its findings; archive only
|
|
135
|
+
with the user's consent.
|
|
136
|
+
- `skills_audit(command: "check")` checks L1 for stale or overlapping entries.
|
|
137
|
+
Offer to review and consolidate what it reports.
|
|
138
|
+
|
|
139
|
+
### 4. Multi-LLM review
|
|
140
|
+
|
|
141
|
+
- Multi-LLM review sends a design or a change to several LLMs (for example
|
|
142
|
+
Claude, Codex, Cursor) and collects their findings.
|
|
143
|
+
- Suggest it for changes that are hard to undo: a published design, a data
|
|
144
|
+
format, a security-relevant change, a release. Do not suggest it for routine
|
|
145
|
+
edits.
|
|
146
|
+
- It needs external CLIs or API keys. If the `multi_llm_review` tool is not
|
|
147
|
+
available, mention in one line that it exists and what it needs; do not push
|
|
148
|
+
setup.
|
|
149
|
+
|
|
150
|
+
### 5. Skill tips
|
|
151
|
+
|
|
152
|
+
- When the user starts a task that an installed skill or SkillSet covers, name
|
|
153
|
+
it in one line with what it would do. Check `tool_guide(command: "catalog")`
|
|
154
|
+
when unsure what is installed.
|
|
155
|
+
- Do not repeat a tip the user has already declined in this session.
|
|
156
|
+
|
|
157
|
+
### 6. A project-specific mode
|
|
158
|
+
|
|
159
|
+
- When L1 shows a clear project identity (~10 entries with coherent themes),
|
|
160
|
+
offer once to draft a custom instruction mode from those themes. In the first
|
|
161
|
+
session, existing project documentation can stand in for L1 (see Fast-Track).
|
|
162
|
+
- The draft starts with a copy of the "Use KairosChain proactively" section, at
|
|
163
|
+
its top, so it survives the same character cap.
|
|
164
|
+
- If the user declines, the situation has changed (see the Limit line) only once
|
|
165
|
+
L1 has grown by about 10 more entries; do not re-propose before that.
|
|
166
|
+
|
|
167
|
+
## Teachable Moments (soft teaching during work)
|
|
168
|
+
|
|
169
|
+
When you use a proactive tool or touch a KairosChain concept during normal work,
|
|
170
|
+
you MAY append a single parenthetical line that names the concept and offers
|
|
171
|
+
follow-up.
|
|
172
|
+
|
|
173
|
+
Format: `(<one-sentence concept hint>. 詳しくは "<what is X?>" で)`
|
|
174
|
+
|
|
175
|
+
Examples:
|
|
176
|
+
- After `context_save()` → "(これは L2 context という仕組みです。詳しくは 'what is L2?' で)"
|
|
177
|
+
- After `knowledge_update()` → "(L1 knowledge への promotion です。)"
|
|
178
|
+
- After `chain_status()` → "(blockchain の健康確認でした。)"
|
|
179
|
+
- After proposing a custom mode → "(instructions mode は AI の振る舞いを決める L0 要素です。)"
|
|
180
|
+
|
|
181
|
+
Rules:
|
|
182
|
+
- **One sentence max, in parentheses.** No paragraphs, no bullet lists.
|
|
183
|
+
- **Skippable.** If the user ignores it, move on. Do not re-surface the same hint
|
|
184
|
+
in the same session.
|
|
185
|
+
- **Only when the concept is likely new to the user.**
|
|
186
|
+
- **Never block the flow.** The hint is a signpost, not a lesson.
|
|
187
|
+
|
|
188
|
+
## Session Routine
|
|
189
|
+
|
|
190
|
+
- **Session start**: Call `chain_status()` to check system health and report it
|
|
191
|
+
in one short line (a few words when healthy; details only if there is an issue).
|
|
192
|
+
- **When referencing past work**: Call `knowledge_list()` or `knowledge_get()`
|
|
193
|
+
to check for relevant L1 knowledge before answering from scratch. When one
|
|
194
|
+
applies, say so: "Applying your saved convention [X] here."
|
|
195
|
+
- **When the user asks about capabilities**: Call `tool_guide(command: "catalog")`
|
|
196
|
+
to give accurate, current information.
|
|
197
|
+
- **Knowledge gaps (custom modes only)**: If the active mode has a Knowledge
|
|
198
|
+
Acquisition Policy, call `skills_audit(command: "gaps")` to check for missing
|
|
199
|
+
baseline knowledge. If gaps are found, inform the user briefly and offer to
|
|
200
|
+
create the missing entries.
|
|
201
|
+
|
|
202
|
+
### Transparency Rule
|
|
203
|
+
|
|
204
|
+
When you use an MCP tool proactively, briefly state what you did and why.
|
|
205
|
+
Never use tools silently without informing the user of the result.
|
|
206
|
+
|
|
207
|
+
## Core Principles
|
|
208
|
+
|
|
209
|
+
1. **The user's task comes first**: suggestions wait for a natural break
|
|
210
|
+
2. **Suggest, never decide**: all recording, promotion, archiving and mode
|
|
211
|
+
changes require user consent
|
|
212
|
+
3. **One suggestion at a time**: never stack several suggestions in one message
|
|
213
|
+
4. **A declined suggestion stays declined** for the rest of the session unless
|
|
214
|
+
the situation changes (a new unit of work, a new pattern)
|
|
215
|
+
5. **Soft teaching is OK; lectures are not**: a one-line hint or a 3-line intro
|
|
216
|
+
is fine. Walls of text are not.
|
|
217
|
+
6. **No guilt**: if the user never adopts a suggestion, the mode still provides
|
|
218
|
+
value through L2 context continuity
|
|
219
|
+
|
|
220
|
+
## L2 Recording Guidelines
|
|
221
|
+
|
|
222
|
+
When saving session context to L2:
|
|
223
|
+
- Use descriptive names: `feature_auth_implementation`, not `session_3`
|
|
224
|
+
- Include tags that reflect the work domain
|
|
225
|
+
- Keep summaries concise: what was planned, what was done, what's next
|
|
226
|
+
- Include key decisions and their rationale
|
|
227
|
+
|
|
228
|
+
## L1 Promotion Quality Gate
|
|
229
|
+
|
|
230
|
+
Minimum requirements for L1 knowledge (kept intentionally low):
|
|
231
|
+
- At least one descriptive tag
|
|
232
|
+
- A clear one-sentence description
|
|
233
|
+
- Content that is not a duplicate of existing L1
|
|
234
|
+
- Pattern has appeared in 2+ sessions (observed, not enforced as hard rule)
|
|
235
|
+
|
|
236
|
+
Quality improves over time through audit suggestions. Do not block initial promotion
|
|
237
|
+
for perfectionism.
|
|
238
|
+
|
|
239
|
+
## Knowledge Acquisition Policy (Custom Modes)
|
|
240
|
+
|
|
241
|
+
When creating a custom instruction mode (including via fast-track), include a
|
|
242
|
+
Knowledge Acquisition Policy section to define what L1 knowledge the mode requires.
|
|
243
|
+
This enables automatic gap detection at session start.
|
|
244
|
+
|
|
245
|
+
### Template
|
|
246
|
+
|
|
247
|
+
```markdown
|
|
248
|
+
## Knowledge Acquisition Policy
|
|
249
|
+
|
|
250
|
+
### Baseline Knowledge
|
|
251
|
+
|
|
252
|
+
Required L1 knowledge entries for this mode.
|
|
253
|
+
|
|
254
|
+
- `entry_name` — Description of what this knowledge covers
|
|
255
|
+
- `another_entry` — Description of another required knowledge area
|
|
256
|
+
|
|
257
|
+
### Active Monitoring
|
|
258
|
+
|
|
259
|
+
Topics and sources to track for knowledge updates.
|
|
260
|
+
|
|
261
|
+
- Source or topic to monitor (frequency)
|
|
262
|
+
|
|
263
|
+
### Acquisition Behavior
|
|
264
|
+
|
|
265
|
+
- **On session start**: Check baseline entries against L1 knowledge. Report gaps.
|
|
266
|
+
- **On gap found**: Propose creating the missing L1 entry with a draft outline.
|
|
267
|
+
- **Frequency**: Check baseline every session.
|
|
268
|
+
- **Cross-instance (opt-in)**: When connected to a Meeting Place, you may
|
|
269
|
+
publish knowledge needs to the board using `meeting_publish_needs(opt_in: true)`.
|
|
270
|
+
Other agents browsing the board may discover and offer relevant knowledge.
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Format Rules
|
|
274
|
+
|
|
275
|
+
- Start the section with `## Knowledge Acquisition Policy`
|
|
276
|
+
- List baseline entries under `### Baseline Knowledge` using: `` - `name` — description ``
|
|
277
|
+
- Separators between name and description: `—`, `--`, `:`, or `-` are all accepted
|
|
278
|
+
- `### Active Monitoring` and `### Acquisition Behavior` are LLM-facing guidance
|
|
279
|
+
(not parsed programmatically)
|
|
280
|
+
|
|
281
|
+
### Usage
|
|
282
|
+
|
|
283
|
+
Run `skills_audit(command: "gaps")` to check the current mode's baseline against
|
|
284
|
+
existing L1 knowledge. Missing entries are reported with suggested creation commands.
|
|
285
|
+
|
|
286
|
+
## Progressive Concept Introduction
|
|
287
|
+
|
|
288
|
+
| Concept | Introduce When |
|
|
289
|
+
|---------|---------------|
|
|
290
|
+
| Fast-track setup | First session, if existing artifacts detected |
|
|
291
|
+
| 3-layer overview + blockchain | First-session intro (3 lines, opt-in for detail) |
|
|
292
|
+
| L2 context (session memory) | First save offer + parenthetical hint |
|
|
293
|
+
| L1 knowledge (reusable patterns) | First pattern detected (or bulk-imported via fast-track) |
|
|
294
|
+
| Dream / knowledge audit | First tidy-up suggestion |
|
|
295
|
+
| Multi-LLM review | First hard-to-undo change |
|
|
296
|
+
| Custom instruction mode | L1 shows coherent project identity |
|
|
297
|
+
| Self-referentiality / 9 propositions | User asks "why Ruby?" or "why blockchain?" or opens `docs/` |
|
|
298
|
+
| SkillSet architecture | User asks about sharing, plugins, or Meeting Place |
|
|
299
|
+
|
|
300
|
+
Deeper topics wait for curiosity or contextual triggers — but when triggered,
|
|
301
|
+
engage without hesitation.
|
|
302
|
+
|
|
303
|
+
## What This Mode Does NOT Do
|
|
304
|
+
|
|
305
|
+
- Does not record, promote, archive or switch modes without asking
|
|
306
|
+
- Does not interrupt the user's work to make a suggestion
|
|
307
|
+
- Does not stack several suggestions in one message
|
|
308
|
+
- Does not push setup of optional tools (multi-LLM review, Meeting Place)
|
|
309
|
+
- Does not deliver multi-paragraph explanations unprompted
|
|
310
|
+
- Does not prioritize KairosChain features over the user's actual work
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# llm_call reports the model ID it asked for beside the one the provider
|
|
3
|
+
# answered with. On Bedrock they differ — eu.anthropic.claude-sonnet-5-5 is
|
|
4
|
+
# sent, claude-sonnet-5-5 comes back — and only the first names the inference
|
|
5
|
+
# profile, so a caller recording provenance (gc_tier1_assess's report) could
|
|
6
|
+
# not tell which region profile served the call.
|
|
7
|
+
|
|
8
|
+
require 'minitest/autorun'
|
|
9
|
+
require 'json'
|
|
10
|
+
$LOAD_PATH.unshift File.expand_path('../../../../lib', __dir__)
|
|
11
|
+
require 'kairos_mcp/tools/base_tool'
|
|
12
|
+
require_relative '../tools/llm_call'
|
|
13
|
+
|
|
14
|
+
module KairosMcp
|
|
15
|
+
module SkillSets
|
|
16
|
+
module LlmClient
|
|
17
|
+
class TestLlmCallRequestedModel < Minitest::Test
|
|
18
|
+
class Answering
|
|
19
|
+
def call(**_kwargs)
|
|
20
|
+
{ 'content' => '{}', 'stop_reason' => 'end_turn', 'model' => 'claude-sonnet-5-5',
|
|
21
|
+
'input_tokens' => 1, 'output_tokens' => 1 }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Stubbed < Tools::LlmCall
|
|
26
|
+
def initialize(config)
|
|
27
|
+
super()
|
|
28
|
+
@config = config
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def load_config = @config.dup
|
|
34
|
+
def build_adapter(_config) = Answering.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def payload(config, arguments = {})
|
|
38
|
+
out = Stubbed.new(config).call({ 'messages' => [{ 'role' => 'user', 'content' => 'hi' }] }.merge(arguments))
|
|
39
|
+
JSON.parse(out.first[:text])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_the_configured_id_is_reported_beside_the_answering_model
|
|
43
|
+
got = payload('provider' => 'bedrock', 'model' => 'eu.anthropic.claude-sonnet-5-5')
|
|
44
|
+
assert_equal 'ok', got['status']
|
|
45
|
+
assert_equal 'claude-sonnet-5-5', got['model']
|
|
46
|
+
assert_equal 'eu.anthropic.claude-sonnet-5-5', got['requested_model']
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_a_per_call_model_override_is_what_is_reported
|
|
50
|
+
got = payload({ 'provider' => 'bedrock', 'model' => 'eu.anthropic.claude-sonnet-5-5' },
|
|
51
|
+
'model' => 'eu.anthropic.claude-opus-5-5')
|
|
52
|
+
assert_equal 'eu.anthropic.claude-opus-5-5', got['requested_model']
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -201,6 +201,11 @@ module KairosMcp
|
|
|
201
201
|
'provider' => actual_provider,
|
|
202
202
|
'requested_provider' => requested_provider,
|
|
203
203
|
'model' => actual_model,
|
|
204
|
+
# The ID the adapter was asked to use, beside the name the provider
|
|
205
|
+
# answered with: on Bedrock these differ (eu.anthropic.claude-sonnet-5-5
|
|
206
|
+
# vs claude-sonnet-5-5), and only the first names the inference
|
|
207
|
+
# profile, and so the region. Callers recording provenance need both.
|
|
208
|
+
'requested_model' => model || config['model'],
|
|
204
209
|
'response' => raw_response,
|
|
205
210
|
'usage' => usage,
|
|
206
211
|
'snapshot' => build_snapshot(
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kairos-chain
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.93.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Masaomi Hatakeyama
|
|
@@ -374,6 +374,7 @@ files:
|
|
|
374
374
|
- templates/skills/kairos.rb
|
|
375
375
|
- templates/skills/kairos_quickguide.md
|
|
376
376
|
- templates/skills/kairos_tutorial.md
|
|
377
|
+
- templates/skills/proactive_tutorial.md
|
|
377
378
|
- templates/skills/researcher.md
|
|
378
379
|
- templates/skills/versions/.gitkeep
|
|
379
380
|
- templates/skillsets/account_manager/config/accounts.yml
|
|
@@ -673,6 +674,7 @@ files:
|
|
|
673
674
|
- templates/skillsets/llm_client/test/test_cursor_adapter_readonly.rb
|
|
674
675
|
- templates/skillsets/llm_client/test/test_cursor_adapter_retryable.rb
|
|
675
676
|
- templates/skillsets/llm_client/test/test_error_taxonomy.rb
|
|
677
|
+
- templates/skillsets/llm_client/test/test_llm_call_requested_model.rb
|
|
676
678
|
- templates/skillsets/llm_client/tools/llm_call.rb
|
|
677
679
|
- templates/skillsets/llm_client/tools/llm_configure.rb
|
|
678
680
|
- templates/skillsets/llm_client/tools/llm_status.rb
|