kairos-chain 3.92.0 → 3.94.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 +99 -0
- data/bin/kairos-chain +3 -1
- data/lib/kairos_mcp/kairos_chain/landed_probe.rb +62 -0
- data/lib/kairos_mcp/knowledge_provider.rb +473 -15
- data/lib/kairos_mcp/l0_proposal_store.rb +82 -0
- data/lib/kairos_mcp/l1_history.rb +257 -0
- data/lib/kairos_mcp/plugin_projector.rb +60 -2
- data/lib/kairos_mcp/safe_evolver.rb +399 -126
- data/lib/kairos_mcp/storage/importer.rb +50 -0
- data/lib/kairos_mcp/tools/chain_import.rb +15 -3
- data/lib/kairos_mcp/tools/instructions_update.rb +27 -2
- data/lib/kairos_mcp/tools/knowledge_update.rb +37 -3
- data/lib/kairos_mcp/tools/skills_evolve.rb +34 -8
- data/lib/kairos_mcp/tools/skills_rollback.rb +94 -6
- data/lib/kairos_mcp/tools/system_upgrade.rb +4 -1
- data/lib/kairos_mcp/version.rb +1 -1
- data/lib/kairos_mcp/version_manager.rb +29 -14
- 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 +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 05055bfa3f7c4377e2e88011754c85d8d87c690e07f19837c4dca5a0c1cd033c
|
|
4
|
+
data.tar.gz: 48b9c8a70d27304e21293440f121ec069cb0c7ec47ed41b01573cdd2e3c80505
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '08ee4ff5f61407bdcc390eb8c4cda6c286472672a6549ded81d5d0b1c7cf29f8203a472f9cfa5d4cfc811b1b8d923d4ee77ee6746decad1893a33c01187ecc1e'
|
|
7
|
+
data.tar.gz: 0b94dde53ddce2444defb9933515dda0d4e754bb0e6053129927d82032bdb9b73383b5d67234a9b57f3e003e82e1b004c17c94f6e551a45ba2fc5dca412bd340
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,105 @@ 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.94.0] - 2026-10-20
|
|
10
|
+
|
|
11
|
+
### Added — L0 changes proposed for later approval, L0 restores on the record, L1 body history
|
|
12
|
+
|
|
13
|
+
- **L0 proposals.** `skills_evolve` keeps a pending L0 change as (base, result,
|
|
14
|
+
content) without evaluating it; `command: "pending"` lists the proposals and
|
|
15
|
+
`apply` takes a `proposal_id`. Applying writes exactly the stored bytes under
|
|
16
|
+
an exclusive lock, only while the base is still the L0 in force and the
|
|
17
|
+
content hashes to its result. A failed load, an interrupt or a killed thread
|
|
18
|
+
never leaves an unrecorded L0 on disk.
|
|
19
|
+
- **L0 restore on the record.** `skills_rollback` restores a snapshot only if
|
|
20
|
+
its hash appears in a transition recorded on the chain. Without
|
|
21
|
+
`approved: true` it writes nothing and returns a pending proposal; with
|
|
22
|
+
`proposal_id` the approval applies exactly the proposal that was shown.
|
|
23
|
+
- **L1 body history.** `knowledge_update` gains `history`, `restore` and
|
|
24
|
+
`erase_body` (the last is irreversible and needs `approved: true`). Bodies
|
|
25
|
+
are kept by content address from a recorded activation point, and restore and
|
|
26
|
+
erasure decide from the chain whether their record landed.
|
|
27
|
+
|
|
28
|
+
### Changed — read before upgrading
|
|
29
|
+
|
|
30
|
+
- `VersionManager.rollback` is removed; nothing shipped calls it. Code that
|
|
31
|
+
called it should use `skills_rollback` with a `proposal_id`.
|
|
32
|
+
- `chain_import` never overwrites an existing chain: it is refused when the
|
|
33
|
+
target already holds chain data. Import into a new data directory instead.
|
|
34
|
+
|
|
35
|
+
## [3.93.0] - 2026-10-19
|
|
36
|
+
|
|
37
|
+
### Added — `proactive_tutorial`, an opt-in mode that suggests KairosChain's own workflow
|
|
38
|
+
|
|
39
|
+
Claude Code passes only the head of an MCP server's instructions to the model
|
|
40
|
+
(4,096 characters by default, 2,048 in older builds). Until a mode is projected
|
|
41
|
+
into CLAUDE.md, the `tutorial` mode's "Proactive Tool Usage" section (line 82 of
|
|
42
|
+
309) never reaches the model.
|
|
43
|
+
|
|
44
|
+
- New shipped mode `proactive_tutorial`. Its first section, which fits inside
|
|
45
|
+
the 2,048-character cap after the first-run hint, has the model offer to save
|
|
46
|
+
L2 contexts, promote L1 knowledge, tidy up (`dream_scan`, `skills_audit`),
|
|
47
|
+
run multi-LLM review on hard-to-undo changes, point at installed skills, and
|
|
48
|
+
draft a project mode once L1 shows a theme (or, in the first session, the
|
|
49
|
+
project has docs). Writes happen only after the user says yes. Switch with
|
|
50
|
+
`instructions_update(command: "set_mode", mode_name: "proactive_tutorial")`;
|
|
51
|
+
the default stays `tutorial`. Existing instances receive the file on the next
|
|
52
|
+
`system_upgrade`.
|
|
53
|
+
- `instructions_update set_mode` now warns when CLAUDE.md still imports a mode
|
|
54
|
+
body projected for a different mode, and names the command that fixes it
|
|
55
|
+
(`kairos-chain mode project`, or `kairos-chain mode remove` for `none`).
|
|
56
|
+
|
|
57
|
+
### Fixed — projected hooks run against the data directory they were projected from
|
|
58
|
+
|
|
59
|
+
A project whose `.mcp.json` starts kairos-chain with another project's data
|
|
60
|
+
directory (`--data-dir /…/KairosChain_2026/.kairos` in GenomicsChain_2025; 16
|
|
61
|
+
projects on the reporting machine point at that one directory) got the shared
|
|
62
|
+
directory's SkillSet hooks projected into its own `.claude/settings.json`. Each
|
|
63
|
+
hook resolved its script as `${KAIROS_DATA_DIR:-$CLAUDE_PROJECT_DIR/.kairos}/…`
|
|
64
|
+
with `KAIROS_DATA_DIR` unset, so it looked in the wrong project:
|
|
65
|
+
model_provenance failed with `LoadError` on every Stop, SubagentStop and model
|
|
66
|
+
switch (46 times across two sessions, 2026-10-06 and 10-18) and observed
|
|
67
|
+
nothing; project_manager's session-start report failed the same way. A harness
|
|
68
|
+
tells a hook where the project is, never where the data directory is.
|
|
69
|
+
|
|
70
|
+
- When the data directory is not `<project root>/.kairos`, PluginProjector now
|
|
71
|
+
prefixes every projected hook command with the pair it projected from:
|
|
72
|
+
`export KAIROS_DATA_DIR=<dir> KAIROS_PROJECT_ROOT=<root>;`, shell-escaped.
|
|
73
|
+
The project root goes with it because `kairos-plugin-project` otherwise falls
|
|
74
|
+
back to the data dir's parent — the other project — when the hook's working
|
|
75
|
+
directory is not a plausible root. The two are always set together: the
|
|
76
|
+
agent SkillSet hands children both as a pair, and half a pair cross-wires a
|
|
77
|
+
re-projection. The default layout is projected exactly as before, and
|
|
78
|
+
hand-written hooks are never touched.
|
|
79
|
+
- Plugin mode is left as declared: `hooks/hooks.json` is distributable, and a
|
|
80
|
+
data directory on the projecting machine means nothing on the consumer's.
|
|
81
|
+
- `system_upgrade` and `kairos-chain upgrade` re-projected without `data_dir:`,
|
|
82
|
+
so in a project sharing a data directory they wrote the hooks as if it were
|
|
83
|
+
local and dropped the fix until the next server start; both now pass it.
|
|
84
|
+
- The Codex host's `--host` rewrite now applies only to what follows the pinned
|
|
85
|
+
prefix, so a data-directory or project path containing `kairos-plugin-project`
|
|
86
|
+
or `--host` is never rewritten.
|
|
87
|
+
- No SkillSet changes: model_provenance and project_manager keep their bare
|
|
88
|
+
`ruby` commands, which run under whatever Ruby the project selects. A gem
|
|
89
|
+
executable would not: under rbenv a project pinned to another Ruby (two of the
|
|
90
|
+
16 above run 3.3.7 / 3.3.10) cannot find it.
|
|
91
|
+
|
|
92
|
+
To pick this up, install this gem under the Ruby each project's MCP server runs
|
|
93
|
+
on — for most projects the usual one; for a project whose `.ruby-version` or
|
|
94
|
+
`.mcp.json` command selects another Ruby, that Ruby too — then restart the
|
|
95
|
+
project's session so projection runs again.
|
|
96
|
+
|
|
97
|
+
### Added — llm_client 0.2.2: `llm_call` reports the model ID it asked for
|
|
98
|
+
|
|
99
|
+
The success payload gains `requested_model` (the per-call `model` override, else
|
|
100
|
+
the configured `model`) beside `model` (what the provider answered with). On
|
|
101
|
+
Bedrock the two differ — `eu.anthropic.claude-sonnet-5-5` is sent and
|
|
102
|
+
`claude-sonnet-5-5` comes back — and only the first names the inference profile,
|
|
103
|
+
and with it the region. gc_tier1_assess records it in a report's
|
|
104
|
+
`assessor_stack.llm.model_requested`. Additive; no field changed or removed.
|
|
105
|
+
|
|
7
106
|
## [3.92.0] - 2026-10-13
|
|
8
107
|
|
|
9
108
|
### 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)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require_relative 'chain'
|
|
5
|
+
|
|
6
|
+
module KairosMcp
|
|
7
|
+
module KairosChain
|
|
8
|
+
# Answers "did this exact entry reach the ledger?" after an append did not
|
|
9
|
+
# return normally.
|
|
10
|
+
#
|
|
11
|
+
# Chain#add_block raises Storage::Error when it cannot tell whether the
|
|
12
|
+
# write landed, and a thread can be interrupted after the write but before
|
|
13
|
+
# add_block returns. Either way the caller holds a change it must keep
|
|
14
|
+
# (the record is on the chain) or undo (it is not). Looking only at the last
|
|
15
|
+
# block answers wrongly once anything else has been appended since, so the
|
|
16
|
+
# caller takes a mark before appending and the probe scans every block after
|
|
17
|
+
# that mark for an entry equal to the one the caller tried to append.
|
|
18
|
+
module LandedProbe
|
|
19
|
+
# The ledger length now, i.e. the index from which the caller's block can
|
|
20
|
+
# appear. nil when the ledger cannot be read; every later status is then
|
|
21
|
+
# :unknown.
|
|
22
|
+
def self.mark(storage_backend: nil)
|
|
23
|
+
chain = Chain.new(storage_backend: storage_backend)
|
|
24
|
+
case chain.load_state
|
|
25
|
+
when :readable then chain.chain.length
|
|
26
|
+
when :absent then 0
|
|
27
|
+
end
|
|
28
|
+
rescue StandardError
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# :landed -- a block after the mark carries an entry equal to entry_json
|
|
33
|
+
# :absent -- the ledger is readable (or absent) and no such entry is there
|
|
34
|
+
# :unknown -- the mark or the ledger could not be read
|
|
35
|
+
#
|
|
36
|
+
# Equality is on the parsed entry, so a backend that re-serialises the JSON
|
|
37
|
+
# still matches. Only StandardError is absorbed: an interrupt during the
|
|
38
|
+
# probe propagates, and callers run their undo in an ensure for that case.
|
|
39
|
+
def self.status(mark, entry_json, storage_backend: nil)
|
|
40
|
+
return :unknown if mark.nil?
|
|
41
|
+
|
|
42
|
+
expected = JSON.parse(entry_json)
|
|
43
|
+
chain = Chain.new(storage_backend: storage_backend)
|
|
44
|
+
return :absent if chain.load_state == :absent
|
|
45
|
+
return :unknown unless chain.load_state == :readable
|
|
46
|
+
|
|
47
|
+
found = chain.chain.drop(mark).any? do |block|
|
|
48
|
+
Array(block.data).any? do |raw|
|
|
49
|
+
begin
|
|
50
|
+
JSON.parse(raw.to_s) == expected
|
|
51
|
+
rescue JSON::ParserError
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
found ? :landed : :absent
|
|
57
|
+
rescue StandardError
|
|
58
|
+
:unknown
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|