kairos-chain 2.4.0 → 2.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52819cfdb42eed0ec8b3c0789cd19b44458dfb5446f24beb25d2ef21df7d6d75
4
- data.tar.gz: 0bdfc0afa6c20c8a6b93fd348e0fbe99ccdfe81a950c158127ef526d28287c7a
3
+ metadata.gz: 4bb1a479485b0eeb8315806b9cb6b657aab0999da825b028c1bd164d29d7683a
4
+ data.tar.gz: f0c41de78a0b1a83bd0826b71e7847a80549f5f3ce91673acaefcafd322b9c23
5
5
  SHA512:
6
- metadata.gz: 5144b19067b3a7361581312ccb2d99c0b137c8b6d2291c40b762149232f3bf42fa8ae365c28ba3580b36acda43d9e914d7e0de14c1ca5c4231213c49d565a314
7
- data.tar.gz: 81d99fb9024bf56b4c3080a6c61def85d98ccb91169d14071a23aeee02cc080701077098be547a6aede583f554f4ccd3a6050b11d2927a32543cc5a14d0e8381
6
+ metadata.gz: 86afd61254c72f559565196bf3caa53f547b5f3483ae5562cbedac0ddaa9d56970ec19aa54eaed3278f338e2ca930ab5c7dcd9d6acbe681f61b0bc0d197ae706
7
+ data.tar.gz: d8de0bb6abda6c4e1837c3976a1e85a4b2784d8e8619afda40434c64b1365733ca69666b5de981c87ec3f296667192e9b7a3d573a0301108c2fd7c3408e55b7e
data/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ 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
+ ## [2.5.0] - 2026-03-03
8
+
9
+ ### Added
10
+
11
+ - **Cross-Instance Knowledge Discovery**: KairosChain instances connected to a Meeting Place can now publish knowledge gaps as "needs" to the SkillBoard. Other agents browsing the board can discover these needs and offer relevant knowledge.
12
+ - `skills_audit(command: "export_needs")`: New audit command to package knowledge gaps for cross-instance sharing
13
+ - `meeting_publish_needs`: New Hestia MCP tool to publish needs to the Meeting Place board (requires explicit `opt_in: true`)
14
+ - `SkillBoard#post_need` / `remove_needs`: In-memory need entries (session-only, no persistence — DEE compliant)
15
+ - `POST /place/v1/board/needs`: New HTTP endpoint to publish knowledge needs
16
+ - `DELETE /place/v1/board/needs`: New HTTP endpoint to remove published needs
17
+ - `browse(type: 'need')`: Filter board entries to show only knowledge needs
18
+ - Needs are automatically cleaned up on agent unregister
19
+
20
+ - **Knowledge Acquisition Policy — Cross-Instance Extension**: Tutorial template Acquisition Behavior now includes opt-in cross-instance knowledge needs publishing guidance
21
+
22
+ - **L1 Knowledge Updates**: Updated `hestiachain_meeting_place` (EN/JP), `kairoschain_usage` (EN/JP), `kairoschain_operations` (EN/JP), `persona_definitions` with cross-instance discovery, proactive tool usage, and dynamic persona suggestion documentation
23
+
24
+ ### Fixed
25
+
26
+ - **PlaceRouter query string parsing**: Added missing `require 'uri'` — `parse_query` was silently failing due to `NameError` on `URI.decode_www_form`, causing all browse query parameters (`type`, `search`, `limit`) to be ignored
27
+
28
+ ---
29
+
7
30
  ## [2.4.0] - 2026-03-03
8
31
 
9
32
  ### Added
@@ -284,6 +307,7 @@ This project follows [Semantic Versioning](https://semver.org/).
284
307
  - Skill promotion with Persona Assembly
285
308
  - Tool guide and metadata system
286
309
 
310
+ [2.5.0]: https://github.com/masaomi/KairosChain_2026/compare/v2.4.0...v2.5.0
287
311
  [2.4.0]: https://github.com/masaomi/KairosChain_2026/compare/v2.3.1...v2.4.0
288
312
  [2.3.1]: https://github.com/masaomi/KairosChain_2026/compare/v2.3.0...v2.3.1
289
313
  [2.3.0]: https://github.com/masaomi/KairosChain_2026/compare/v2.2.0...v2.3.0
@@ -4,6 +4,7 @@ require_relative 'base_tool'
4
4
  require_relative '../knowledge_provider'
5
5
  require_relative '../context_manager'
6
6
  require_relative '../dsl_skills_provider'
7
+ require_relative '../skills_config'
7
8
  require_relative '../kairos'
8
9
 
9
10
  module KairosMcp
@@ -38,7 +39,7 @@ module KairosMcp
38
39
  }
39
40
  }.freeze
40
41
 
41
- READONLY_COMMANDS = %w[check conflicts stale dangerous recommend].freeze
42
+ READONLY_COMMANDS = %w[check conflicts stale dangerous recommend gaps export_needs].freeze
42
43
  WRITE_COMMANDS = %w[archive unarchive].freeze
43
44
 
44
45
  def name
@@ -47,7 +48,8 @@ module KairosMcp
47
48
 
48
49
  def description
49
50
  'Audit knowledge health across L0/L1/L2 layers. Check for conflicts, staleness, ' \
50
- 'dangerous patterns, and get promotion/archive recommendations. ' \
51
+ 'dangerous patterns, get promotion/archive recommendations, and detect knowledge gaps ' \
52
+ 'defined by custom instruction mode policies. ' \
51
53
  'Archive operations require human approval (approved: true).'
52
54
  end
53
55
 
@@ -56,7 +58,7 @@ module KairosMcp
56
58
  end
57
59
 
58
60
  def usecase_tags
59
- %w[audit health check recommend archive stale dangerous L0 L1 L2]
61
+ %w[audit health check recommend archive stale dangerous gaps needs meeting knowledge-policy L0 L1 L2]
60
62
  end
61
63
 
62
64
  def examples
@@ -76,6 +78,18 @@ module KairosMcp
76
78
  {
77
79
  title: 'Archive stale knowledge',
78
80
  code: 'skills_audit(command: "archive", target: "old_guide", reason: "No longer relevant", approved: true)'
81
+ },
82
+ {
83
+ title: 'Check knowledge gaps for current mode',
84
+ code: 'skills_audit(command: "gaps")'
85
+ },
86
+ {
87
+ title: 'Check knowledge gaps for specific mode',
88
+ code: 'skills_audit(command: "gaps", mode_name: "genomics_expert")'
89
+ },
90
+ {
91
+ title: 'Export knowledge needs for Meeting Place sharing',
92
+ code: 'skills_audit(command: "export_needs")'
79
93
  }
80
94
  ]
81
95
  end
@@ -143,6 +157,10 @@ module KairosMcp
143
157
  include_archived: {
144
158
  type: 'boolean',
145
159
  description: 'Include archived items in results (default: false)'
160
+ },
161
+ mode_name: {
162
+ type: 'string',
163
+ description: 'Instruction mode name (for gaps command). Defaults to current active mode.'
146
164
  }
147
165
  },
148
166
  required: ['command']
@@ -192,6 +210,10 @@ module KairosMcp
192
210
  run_dangerous_check(layer, args)
193
211
  when 'recommend'
194
212
  run_recommendations(layer, args)
213
+ when 'gaps'
214
+ run_gaps_check(args)
215
+ when 'export_needs'
216
+ run_export_needs(args)
195
217
  end
196
218
 
197
219
  output << result
@@ -895,6 +917,214 @@ module KairosMcp
895
917
  end
896
918
  end
897
919
 
920
+ # =========================================================================
921
+ # Knowledge Gaps
922
+ # =========================================================================
923
+
924
+ def run_gaps_check(args)
925
+ mode = args['mode_name'] || current_mode_name
926
+ content = load_instruction_content(mode)
927
+
928
+ unless content
929
+ return "## Knowledge Gaps Report\n\n" \
930
+ "Could not load instruction file for mode `#{mode}`.\n" \
931
+ "Ensure the mode exists and has a corresponding `.md` file in the skills directory."
932
+ end
933
+
934
+ baseline = parse_baseline_knowledge(content)
935
+
936
+ unless baseline && !baseline.empty?
937
+ return "## Knowledge Gaps Report\n\n" \
938
+ "**Mode**: `#{mode}`\n\n" \
939
+ "No Knowledge Acquisition Policy found in this mode's instructions.\n\n" \
940
+ "To add one, include a `## Knowledge Acquisition Policy` section with a " \
941
+ "`### Baseline Knowledge` subsection listing required L1 entries:\n\n" \
942
+ "```markdown\n" \
943
+ "## Knowledge Acquisition Policy\n\n" \
944
+ "### Baseline Knowledge\n\n" \
945
+ "Required L1 knowledge entries for this mode.\n\n" \
946
+ "- `entry_name` — Description of what this knowledge covers\n" \
947
+ "```"
948
+ end
949
+
950
+ # Compare against existing L1 knowledge
951
+ provider = KnowledgeProvider.new
952
+ existing = provider.list.map { |item| item[:name] }
953
+
954
+ present = []
955
+ missing = []
956
+ baseline.each do |entry|
957
+ if existing.include?(entry[:name])
958
+ present << entry
959
+ else
960
+ missing << entry
961
+ end
962
+ end
963
+
964
+ output = ["## Knowledge Gaps Report\n"]
965
+ output << "**Mode**: `#{mode}`"
966
+ output << "**Baseline entries**: #{baseline.size}"
967
+ output << "**Present**: #{present.size}"
968
+ output << "**Missing**: #{missing.size}\n"
969
+
970
+ if missing.empty?
971
+ output << "### All Baseline Knowledge Present\n"
972
+ output << "All required L1 knowledge entries for this mode are available."
973
+ else
974
+ output << "### Missing Entries\n"
975
+ missing.each do |entry|
976
+ output << "- `#{entry[:name]}` — #{entry[:description]}"
977
+ end
978
+
979
+ output << "\n### Suggested Actions\n"
980
+ output << "Create the missing entries using `knowledge_update`:\n"
981
+ missing.each do |entry|
982
+ output << "```"
983
+ output << "knowledge_update(command: \"create\", name: \"#{entry[:name]}\", " \
984
+ "description: \"#{entry[:description]}\", " \
985
+ "content: \"# #{entry[:name]}\\n\\nTODO: Add content\", " \
986
+ "tags: [\"baseline\"])"
987
+ output << "```\n"
988
+ end
989
+ end
990
+
991
+ if present.any?
992
+ output << "### Present Entries\n"
993
+ present.each do |entry|
994
+ output << "- `#{entry[:name]}` — #{entry[:description]}"
995
+ end
996
+ end
997
+
998
+ output.join("\n")
999
+ end
1000
+
1001
+ def parse_baseline_knowledge(content)
1002
+ # Find the Knowledge Acquisition Policy section
1003
+ policy_match = content.match(/^##\s+Knowledge Acquisition Policy\s*$/i)
1004
+ return nil unless policy_match
1005
+
1006
+ # Extract from ### Baseline Knowledge subsection
1007
+ baseline_match = content.match(/^###\s+Baseline Knowledge\s*\n(.*?)(?=^###|\z)/im)
1008
+ return nil unless baseline_match
1009
+
1010
+ baseline_text = baseline_match[1]
1011
+ entries = []
1012
+
1013
+ # Parse lines matching: - `name` — description (supports —, --, :, -)
1014
+ baseline_text.scan(/^-\s+`([^`]+)`\s*(?:—|--|:|-)\s*(.+)$/) do |name, description|
1015
+ entries << { name: name.strip, description: description.strip }
1016
+ end
1017
+
1018
+ entries
1019
+ end
1020
+
1021
+ def current_mode_name
1022
+ SkillsConfig.load['instructions_mode'] || 'tutorial'
1023
+ end
1024
+
1025
+ def load_instruction_content(mode_name)
1026
+ path = case mode_name
1027
+ when 'developer'
1028
+ KairosMcp.md_path
1029
+ when 'user'
1030
+ KairosMcp.quickguide_path
1031
+ when 'tutorial'
1032
+ KairosMcp.tutorial_path
1033
+ when 'none'
1034
+ nil
1035
+ else
1036
+ File.join(KairosMcp.skills_dir, "#{mode_name}.md")
1037
+ end
1038
+
1039
+ return nil unless path && File.exist?(path)
1040
+
1041
+ File.read(path)
1042
+ end
1043
+
1044
+ # =========================================================================
1045
+ # Export Needs (Cross-Instance Knowledge Discovery)
1046
+ # =========================================================================
1047
+
1048
+ def run_export_needs(args)
1049
+ mode = args['mode_name'] || current_mode_name
1050
+ content = load_instruction_content(mode)
1051
+
1052
+ unless content
1053
+ return "## Export Needs Report\n\n" \
1054
+ "Could not load instruction file for mode `#{mode}`.\n" \
1055
+ "No knowledge needs to export."
1056
+ end
1057
+
1058
+ baseline = parse_baseline_knowledge(content)
1059
+
1060
+ unless baseline && !baseline.empty?
1061
+ return "## Export Needs Report\n\n" \
1062
+ "**Mode**: `#{mode}`\n\n" \
1063
+ "No Knowledge Acquisition Policy found — no needs to export."
1064
+ end
1065
+
1066
+ # Find missing entries (gaps)
1067
+ provider = KnowledgeProvider.new
1068
+ existing = provider.list.map { |item| item[:name] }
1069
+ missing = baseline.reject { |entry| existing.include?(entry[:name]) }
1070
+
1071
+ if missing.empty?
1072
+ return "## Export Needs Report\n\n" \
1073
+ "**Mode**: `#{mode}`\n\n" \
1074
+ "All baseline knowledge is present. No needs to export."
1075
+ end
1076
+
1077
+ # Build exportable needs structure
1078
+ needs_data = build_knowledge_needs(mode, missing)
1079
+
1080
+ # Check Meeting Place connection
1081
+ connection_file = File.join(KairosMcp.storage_dir, 'meeting_connection.json')
1082
+ connected = File.exist?(connection_file)
1083
+
1084
+ output = ["## Export Needs Report\n"]
1085
+ output << "**Mode**: `#{mode}`"
1086
+ output << "**Missing entries**: #{missing.size}"
1087
+ output << "**Meeting Place connected**: #{connected}\n"
1088
+
1089
+ output << "### Exportable Needs\n"
1090
+ needs_data[:needs].each do |need|
1091
+ output << "- `#{need[:name]}` — #{need[:description]}"
1092
+ end
1093
+
1094
+ if connected
1095
+ output << "\n### Next Step\n"
1096
+ output << "Publish these needs to the Meeting Place board:\n"
1097
+ output << "```"
1098
+ output << "meeting_publish_needs(opt_in: true)"
1099
+ output << "```"
1100
+ else
1101
+ output << "\n### Not Connected\n"
1102
+ output << "Connect to a Meeting Place first using `meeting_connect(url: \"...\")`, "
1103
+ output << "then use `meeting_publish_needs(opt_in: true)` to publish."
1104
+ end
1105
+
1106
+ output.join("\n")
1107
+ end
1108
+
1109
+ def build_knowledge_needs(mode_name, missing_entries = nil)
1110
+ if missing_entries.nil?
1111
+ content = load_instruction_content(mode_name)
1112
+ return { agent_mode: mode_name, needs: [], published_at: nil, session_only: true } unless content
1113
+
1114
+ baseline = parse_baseline_knowledge(content) || []
1115
+ provider = KnowledgeProvider.new
1116
+ existing = provider.list.map { |item| item[:name] }
1117
+ missing_entries = baseline.reject { |entry| existing.include?(entry[:name]) }
1118
+ end
1119
+
1120
+ {
1121
+ agent_mode: mode_name,
1122
+ needs: missing_entries.map { |entry| { name: entry[:name], description: entry[:description] } },
1123
+ published_at: Time.now.utc.iso8601,
1124
+ session_only: true
1125
+ }
1126
+ end
1127
+
898
1128
  # =========================================================================
899
1129
  # Helpers
900
1130
  # =========================================================================
@@ -1,4 +1,4 @@
1
1
  module KairosMcp
2
- VERSION = "2.4.0"
2
+ VERSION = "2.5.0"
3
3
  CHANGELOG_URL = "https://github.com/masaomi/KairosChain_2026/blob/main/CHANGELOG.md"
4
4
  end
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  name: hestiachain_meeting_place
3
3
  description: "HestiaChain Meeting Place — user guide for agent discovery, skill exchange, and trust anchoring"
4
- version: 2.0
4
+ version: 2.1
5
5
  layer: L1
6
6
  tags: [documentation, readme, hestia, meeting-place, p2p, deployment, trust-anchor]
7
7
  readme_order: 4.5
8
8
  readme_lang: en
9
9
  ---
10
10
 
11
- ## HestiaChain Meeting Place (v2.0.0)
11
+ ## HestiaChain Meeting Place (v2.5.0)
12
12
 
13
13
  ### What is HestiaChain?
14
14
 
@@ -29,9 +29,9 @@ KairosChain (MCP Server)
29
29
  ├── chain/ ← Trust anchor (self-contained, no external gem dependency)
30
30
  ├── PlaceRouter ← /place/v1/* HTTP endpoints
31
31
  ├── AgentRegistry ← Agent registration with JSON persistence
32
- ├── SkillBoard ← Skill discovery (random sampling, no ranking)
32
+ ├── SkillBoard ← Skill + knowledge needs discovery (random sampling, no ranking)
33
33
  ├── HeartbeatManager ← TTL-based liveness with fadeout recording
34
- └── tools/ ← 6 MCP tools
34
+ └── tools/ ← 7 MCP tools
35
35
  ```
36
36
 
37
37
  A KairosChain instance with the hestia SkillSet is simultaneously an MCP server, a P2P agent, a Meeting Place host, and a participant in other Meeting Places. This embodies the DEE principle of subject-object undifferentiation (主客未分).
@@ -85,6 +85,8 @@ curl -s -H "Authorization: Bearer $TOKEN" \
85
85
  | POST | `/place/v1/unregister` | Bearer | Unregister an agent |
86
86
  | GET | `/place/v1/agents` | Bearer | List registered agents |
87
87
  | GET | `/place/v1/board/browse` | Bearer | Browse skill board (random order) |
88
+ | POST | `/place/v1/board/needs` | Bearer | Publish knowledge needs to board |
89
+ | DELETE | `/place/v1/board/needs` | Bearer | Remove published knowledge needs |
88
90
  | GET | `/place/v1/keys/:id` | Bearer | Retrieve agent's public key |
89
91
 
90
92
  ### MCP Tools
@@ -97,6 +99,26 @@ curl -s -H "Authorization: Bearer $TOKEN" \
97
99
  | `record_observation` | Record subjective observation of interaction |
98
100
  | `meeting_place_start` | Start the Meeting Place, initialize components |
99
101
  | `meeting_place_status` | Show Meeting Place configuration and status |
102
+ | `meeting_publish_needs` | Publish knowledge gaps to board (explicit opt-in required) |
103
+
104
+ ### Cross-Instance Knowledge Discovery
105
+
106
+ Agents can publish their knowledge gaps (needs) to the Meeting Place board, enabling other agents to discover and offer relevant knowledge.
107
+
108
+ **Workflow:**
109
+
110
+ 1. Run `skills_audit(command: "gaps")` to detect missing baseline knowledge
111
+ 2. Run `skills_audit(command: "export_needs")` to preview exportable needs
112
+ 3. Run `meeting_publish_needs(opt_in: true)` to publish needs to the board
113
+ 4. Other agents browsing with `browse(type: 'need')` can discover these needs
114
+ 5. Agents decide locally whether to offer knowledge (no automated matching)
115
+
116
+ **DEE Compliance:**
117
+ - Needs are session-only (in-memory, no persistence)
118
+ - No aggregation, ranking, or popularity metrics
119
+ - Explicit opt-in required (`opt_in: true`)
120
+ - Random sampling for browse results (D3)
121
+ - Each agent decides independently whether to respond (D5)
100
122
 
101
123
  ### Trust Anchor: Chain Migration
102
124
 
@@ -118,7 +140,7 @@ HestiaChain implements the Decentralized Event Exchange (DEE) protocol:
118
140
  - **PhilosophyDeclaration**: Agents declare their exchange philosophy (observable, not enforceable). Only the hash is recorded on chain.
119
141
  - **ObservationLog**: Agents record subjective observations. Multiple agents can have different observations of the same interaction — "meaning coexists."
120
142
  - **Fadeout**: When an agent's heartbeat expires, this is recorded as a first-class event (not an error). Silent departure is a natural part of the protocol.
121
- - **Random Sampling**: The SkillBoard returns skills in random order. There is no ranking, no scoring, no popularity metric.
143
+ - **Random Sampling**: The SkillBoard returns skills and knowledge needs in random order. There is no ranking, no scoring, no popularity metric.
122
144
 
123
145
  ### EC2 Deployment
124
146
 
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  name: hestiachain_meeting_place_jp
3
3
  description: "HestiaChain Meeting Place — エージェント探索・スキル交換・信頼アンカーのユーザーガイド"
4
- version: 2.0
4
+ version: 2.1
5
5
  layer: L1
6
6
  tags: [documentation, readme, hestia, meeting-place, p2p, deployment, trust-anchor]
7
7
  readme_order: 4.5
8
8
  readme_lang: jp
9
9
  ---
10
10
 
11
- ## HestiaChain Meeting Place (v2.0.0)
11
+ ## HestiaChain Meeting Place (v2.5.0)
12
12
 
13
13
  ### HestiaChain とは
14
14
 
@@ -29,9 +29,9 @@ KairosChain (MCP Server)
29
29
  ├── chain/ ← 信頼アンカー(自己完結型、外部 gem 依存なし)
30
30
  ├── PlaceRouter ← /place/v1/* HTTP エンドポイント
31
31
  ├── AgentRegistry ← JSON 永続化によるエージェント登録
32
- ├── SkillBoard ← スキル発見(ランダムサンプリング、ランキングなし)
32
+ ├── SkillBoard ← スキル+知識ニーズ発見(ランダムサンプリング、ランキングなし)
33
33
  ├── HeartbeatManager ← TTL ベースの生存確認と退場記録
34
- └── tools/ ← 6 MCP ツール
34
+ └── tools/ ← 7 MCP ツール
35
35
  ```
36
36
 
37
37
  hestia SkillSet を持つ KairosChain インスタンスは、MCP サーバー、P2P エージェント、Meeting Place ホスト、他の Meeting Place の参加者を同時に兼ねます。これは DEE プロトコルの「主客未分」原則を体現しています。
@@ -85,6 +85,8 @@ curl -s -H "Authorization: Bearer $TOKEN" \
85
85
  | POST | `/place/v1/unregister` | Bearer | エージェント登録解除 |
86
86
  | GET | `/place/v1/agents` | Bearer | 登録エージェント一覧 |
87
87
  | GET | `/place/v1/board/browse` | Bearer | スキルボード閲覧(ランダム順) |
88
+ | POST | `/place/v1/board/needs` | Bearer | 知識ニーズをボードに公開 |
89
+ | DELETE | `/place/v1/board/needs` | Bearer | 公開した知識ニーズを削除 |
88
90
  | GET | `/place/v1/keys/:id` | Bearer | エージェントの公開鍵取得 |
89
91
 
90
92
  ### MCP ツール
@@ -97,6 +99,26 @@ curl -s -H "Authorization: Bearer $TOKEN" \
97
99
  | `record_observation` | インタラクションの主観的観察を記録 |
98
100
  | `meeting_place_start` | Meeting Place を起動、コンポーネント初期化 |
99
101
  | `meeting_place_status` | Meeting Place の設定とステータスを表示 |
102
+ | `meeting_publish_needs` | 知識ギャップをボードに公開(明示的 opt-in 必須) |
103
+
104
+ ### クロスインスタンス知識発見
105
+
106
+ エージェントは自身の知識ギャップ(ニーズ)を Meeting Place ボードに公開できます。他のエージェントがブラウズ中にニーズを発見し、関連知識を提供できます。
107
+
108
+ **ワークフロー:**
109
+
110
+ 1. `skills_audit(command: "gaps")` でベースライン知識の不足を検出
111
+ 2. `skills_audit(command: "export_needs")` でエクスポート可能なニーズをプレビュー
112
+ 3. `meeting_publish_needs(opt_in: true)` でニーズをボードに公開
113
+ 4. 他のエージェントが `browse(type: 'need')` でニーズを発見
114
+ 5. 各エージェントがローカルに知識提供の判断を行う(自動マッチングなし)
115
+
116
+ **DEE 準拠:**
117
+ - ニーズはセッション限り(インメモリ、永続化なし)
118
+ - 集計・ランキング・人気指標なし
119
+ - 明示的 opt-in 必須(`opt_in: true`)
120
+ - ブラウズ結果はランダムサンプリング(D3)
121
+ - 各エージェントが独立に判断(D5)
100
122
 
101
123
  ### 信頼アンカー:チェーン移行
102
124
 
@@ -118,7 +140,7 @@ HestiaChain は Decentralized Event Exchange(DEE)プロトコルを実装し
118
140
  - **PhilosophyDeclaration**: エージェントが交換哲学を宣言(観察可能、強制不可)。ハッシュのみチェーンに記録
119
141
  - **ObservationLog**: エージェントが主観的観察を記録。同じインタラクションに対して複数のエージェントが異なる観察を持てる —「意味は合意されない。意味は共存する」
120
142
  - **Fadeout**: エージェントの心拍が期限切れになると、これはエラーではなく第一級イベントとして記録される。静かな退場はプロトコルの自然な一部
121
- - **ランダムサンプリング**: SkillBoard はスキルをランダム順で返す。ランキング、スコアリング、人気指標は存在しない
143
+ - **ランダムサンプリング**: SkillBoard はスキルと知識ニーズをランダム順で返す。ランキング、スコアリング、人気指標は存在しない
122
144
 
123
145
  ### EC2 デプロイ
124
146
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: kairoschain_operations
3
3
  description: "Future roadmap, deployment, and operations guide"
4
- version: 1.1
4
+ version: 1.2
5
5
  layer: L1
6
6
  tags: [documentation, readme, operations, deployment, roadmap, backup]
7
7
  readme_order: 5
@@ -26,8 +26,11 @@ The following development phases have been completed on the `feature/skillset-pl
26
26
  | **Phase 4.pre** | Authentication + Hardening | Admin token rotation, session-based auth for P2P endpoints |
27
27
  | **Phase 4A** | HestiaChain Foundation | Self-contained trust anchor SkillSet, DEE protocol (PhilosophyDeclaration, ObservationLog), chain migration (4 stages), 4 MCP tools, 77 test assertions |
28
28
  | **Phase 4B** | Meeting Place Server | PlaceRouter, AgentRegistry, SkillBoard, HeartbeatManager, 6 HTTP endpoints, 2 MCP tools, 70 test assertions |
29
+ | **v2.3.0** | Tutorial Mode + Proactive Tools | Behavioral gradient instruction mode, existing project fast-track, Knowledge Acquisition Policy |
30
+ | **v2.4.0** | Dynamic Persona Suggestion | 2-step suggest→assembly workflow, custom persona names, improved unknown persona handling |
31
+ | **v2.5.0** | Cross-Instance Knowledge Discovery | SkillBoard knowledge needs, `meeting_publish_needs` tool, `export_needs` audit command, DEE-compliant session-only needs |
29
32
 
30
- Test results: 356 passed, 0 failed (v2.0.0).
33
+ Test results: 356+ passed, 0 failed (v2.5.0).
31
34
 
32
35
  ### Near-term
33
36
 
@@ -26,8 +26,11 @@ readme_lang: jp
26
26
  | **Phase 4.pre** | 認証 + 堅牢化 | Admin トークンローテーション、P2Pエンドポイントのセッションベース認証 |
27
27
  | **Phase 4A** | HestiaChain Foundation | 自己完結型信頼アンカーSkillSet、DEEプロトコル(PhilosophyDeclaration、ObservationLog)、チェーン移行(4ステージ)、4 MCPツール、77テストアサーション |
28
28
  | **Phase 4B** | Meeting Placeサーバー | PlaceRouter、AgentRegistry、SkillBoard、HeartbeatManager、6 HTTPエンドポイント、2 MCPツール、70テストアサーション |
29
+ | **v2.3.0** | チュートリアルモード + プロアクティブツール | 行動勾配インストラクションモード、既存プロジェクト高速トラック、Knowledge Acquisition Policy |
30
+ | **v2.4.0** | 動的ペルソナ提案 | 2ステップ suggest→assembly ワークフロー、カスタムペルソナ名、未知ペルソナハンドリング改善 |
31
+ | **v2.5.0** | クロスインスタンス知識発見 | SkillBoard知識ニーズ、`meeting_publish_needs`ツール、`export_needs`監査コマンド、DEE準拠セッション限りニーズ |
29
32
 
30
- テスト結果: 356テスト通過、0失敗(v2.0.0)。
33
+ テスト結果: 356+テスト通過、0失敗(v2.5.0)。
31
34
 
32
35
  ### 近期
33
36
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: kairoschain_usage
3
3
  description: "KairosChain tools reference, usage patterns, and evolution workflow"
4
- version: 1.1
4
+ version: 1.2
5
5
  layer: L1
6
6
  tags: [documentation, readme, usage, tools, workflow, examples]
7
7
  readme_order: 3
@@ -252,6 +252,8 @@ Commands:
252
252
  - `conflicts`: Detect potential contradictions between knowledge
253
253
  - `dangerous`: Detect patterns conflicting with L0 safety
254
254
  - `recommend`: Get promotion and archive recommendations
255
+ - `gaps`: Check knowledge gaps defined by Knowledge Acquisition Policy in instruction modes
256
+ - `export_needs`: Package knowledge gaps as shareable needs for cross-instance discovery via Meeting Place
255
257
  - `archive`: Archive L1 knowledge (human approval required)
256
258
  - `unarchive`: Restore from archive (human approval required)
257
259
 
@@ -252,6 +252,8 @@ cp -r skills/versions skills/backups/versions_$(date +%Y%m%d)
252
252
  - `conflicts`: 知識間の潜在的矛盾を検出
253
253
  - `dangerous`: L0安全性と矛盾するパターンを検出
254
254
  - `recommend`: 昇格とアーカイブの推奨を取得
255
+ - `gaps`: Knowledge Acquisition Policyで定義された知識ギャップを検出
256
+ - `export_needs`: 知識ギャップをMeeting Placeでの共有用にパッケージ化
255
257
  - `archive`: L1知識をアーカイブ(人間の承認が必要)
256
258
  - `unarchive`: アーカイブから復元(人間の承認が必要)
257
259
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: persona_definitions
3
3
  description: Default persona definitions for Persona Assembly during skill promotion and audit decisions
4
- version: "1.2"
4
+ version: "1.3"
5
5
  layer: L1
6
6
  tags: [meta, personas, assembly, promotion, audit, decision-making, facilitator]
7
7
  ---
@@ -242,6 +242,15 @@ The assembly produces a discussion summary with:
242
242
 
243
243
  **Important:** The assembly output is advisory only. Human judgment remains the final authority, especially for L0 promotions.
244
244
 
245
+ ### Dynamic Persona Suggestion (v2.4.0+)
246
+
247
+ Use `skills_promote(command: "suggest")` to have the LLM analyze source content and suggest optimal personas before running Persona Assembly. The 2-step workflow:
248
+
249
+ 1. **Suggest**: LLM analyzes the content and recommends persona types and count
250
+ 2. **Assembly**: Run the assembly with the suggested (or modified) persona set
251
+
252
+ Custom persona names are fully supported — the LLM infers the role from the name and context when no pre-defined definition exists.
253
+
245
254
  ### Customizing Personas
246
255
 
247
256
  Users can modify this knowledge to:
@@ -73,6 +73,10 @@ them as naturally as you would use a notebook.
73
73
  to check if relevant L1 knowledge exists before answering from scratch.
74
74
  - **When the user asks about capabilities**: Call `tool_guide(command: "catalog")`
75
75
  to give accurate, current information.
76
+ - **Knowledge gaps (custom modes only)**: If the active mode has a Knowledge
77
+ Acquisition Policy, call `skills_audit(command: "gaps")` silently to check
78
+ for missing baseline knowledge. If gaps are found, inform the user briefly
79
+ and offer to create the missing entries.
76
80
 
77
81
  ### When Few or No L2 Contexts Exist
78
82
 
@@ -183,6 +187,53 @@ Minimum requirements for L1 knowledge (kept intentionally low):
183
187
  Quality improves over time through audit suggestions. Do not block initial promotion
184
188
  for perfectionism.
185
189
 
190
+ ## Knowledge Acquisition Policy (Custom Modes)
191
+
192
+ When creating a custom instruction mode (including via fast-track), include a
193
+ Knowledge Acquisition Policy section to define what L1 knowledge the mode requires.
194
+ This enables automatic gap detection at session start.
195
+
196
+ ### Template
197
+
198
+ ```markdown
199
+ ## Knowledge Acquisition Policy
200
+
201
+ ### Baseline Knowledge
202
+
203
+ Required L1 knowledge entries for this mode.
204
+
205
+ - `entry_name` — Description of what this knowledge covers
206
+ - `another_entry` — Description of another required knowledge area
207
+
208
+ ### Active Monitoring
209
+
210
+ Topics and sources to track for knowledge updates.
211
+
212
+ - Source or topic to monitor (frequency)
213
+
214
+ ### Acquisition Behavior
215
+
216
+ - **On session start**: Check baseline entries against L1 knowledge. Report gaps.
217
+ - **On gap found**: Propose creating the missing L1 entry with a draft outline.
218
+ - **Frequency**: Check baseline every session.
219
+ - **Cross-instance (opt-in)**: When connected to a Meeting Place, you may
220
+ publish knowledge needs to the board using `meeting_publish_needs(opt_in: true)`.
221
+ Other agents browsing the board may discover and offer relevant knowledge.
222
+ ```
223
+
224
+ ### Format Rules
225
+
226
+ - Start the section with `## Knowledge Acquisition Policy`
227
+ - List baseline entries under `### Baseline Knowledge` using: `` - `name` — description ``
228
+ - Separators between name and description: `—`, `--`, `:`, or `-` are all accepted
229
+ - `### Active Monitoring` and `### Acquisition Behavior` are LLM-facing guidance
230
+ (not parsed programmatically)
231
+
232
+ ### Usage
233
+
234
+ Run `skills_audit(command: "gaps")` to check the current mode's baseline against
235
+ existing L1 knowledge. Missing entries are reported with suggested creation commands.
236
+
186
237
  ## Progressive Concept Introduction
187
238
 
188
239
  Introduce KairosChain concepts only when they become relevant:
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
+ require 'uri'
4
5
 
5
6
  module Hestia
6
7
  # PlaceRouter handles Meeting Place HTTP endpoints under /place/v1/*.
@@ -102,6 +103,10 @@ module Hestia
102
103
  handle_list_agents(env)
103
104
  when ['GET', '/place/v1/board/browse']
104
105
  handle_browse(env)
106
+ when ['POST', '/place/v1/board/needs']
107
+ handle_post_needs(env)
108
+ when ['DELETE', '/place/v1/board/needs']
109
+ handle_delete_needs(env)
105
110
  else
106
111
  # Check for /place/v1/keys/:id pattern
107
112
  if request_method == 'GET' && path.start_with?('/place/v1/keys/')
@@ -215,6 +220,9 @@ module Hestia
215
220
 
216
221
  result = @registry.unregister(agent_id)
217
222
 
223
+ # Clean up any posted needs for this agent
224
+ @skill_board.remove_needs(agent_id)
225
+
218
226
  # Record fade-out observation if trust anchor available
219
227
  # (agent explicitly leaving = graceful fadeout)
220
228
 
@@ -241,6 +249,49 @@ module Hestia
241
249
  json_response(200, result)
242
250
  end
243
251
 
252
+ # POST /place/v1/board/needs — Bearer token required
253
+ # Publish knowledge needs to the board (session-only, in-memory)
254
+ def handle_post_needs(env)
255
+ body = parse_body(env)
256
+ agent_id = body['agent_id']
257
+ agent_name = body['agent_name'] || 'Unknown Agent'
258
+ agent_mode = body['agent_mode'] || 'unknown'
259
+ needs = body['needs'] || []
260
+
261
+ unless agent_id
262
+ return json_response(400, { error: 'missing_agent_id', message: 'agent_id is required' })
263
+ end
264
+
265
+ @skill_board.post_need(
266
+ agent_id: agent_id,
267
+ agent_name: agent_name,
268
+ agent_mode: agent_mode,
269
+ needs: needs.map { |n| { name: n['name'], description: n['description'] } }
270
+ )
271
+
272
+ json_response(200, {
273
+ status: 'published',
274
+ agent_id: agent_id,
275
+ needs_count: needs.size,
276
+ session_only: true
277
+ })
278
+ end
279
+
280
+ # DELETE /place/v1/board/needs — Bearer token required
281
+ # Remove all needs posted by an agent
282
+ def handle_delete_needs(env)
283
+ body = parse_body(env)
284
+ agent_id = body['agent_id']
285
+
286
+ unless agent_id
287
+ return json_response(400, { error: 'missing_agent_id', message: 'agent_id is required' })
288
+ end
289
+
290
+ @skill_board.remove_needs(agent_id)
291
+
292
+ json_response(200, { status: 'removed', agent_id: agent_id })
293
+ end
294
+
244
295
  # GET /place/v1/keys/:id — Bearer token required
245
296
  def handle_get_key(path)
246
297
  agent_id = path.sub('/place/v1/keys/', '')
@@ -13,6 +13,32 @@ module Hestia
13
13
 
14
14
  def initialize(registry:)
15
15
  @registry = registry
16
+ @posted_needs = []
17
+ end
18
+
19
+ # Post knowledge needs for an agent (session-only, no persistence — DEE compliant).
20
+ # Overwrites existing needs for the same agent_id.
21
+ #
22
+ # @param agent_id [String] The agent's unique identifier
23
+ # @param agent_name [String] Human-readable agent name
24
+ # @param agent_mode [String] The agent's instruction mode
25
+ # @param needs [Array<Hash>] List of { name:, description: } hashes
26
+ def post_need(agent_id:, agent_name:, agent_mode:, needs:)
27
+ @posted_needs.reject! { |n| n[:agent_id] == agent_id }
28
+ @posted_needs << {
29
+ agent_id: agent_id,
30
+ agent_name: agent_name,
31
+ agent_mode: agent_mode,
32
+ needs: needs,
33
+ published_at: Time.now.utc.iso8601
34
+ }
35
+ end
36
+
37
+ # Remove all needs posted by an agent (called on unregister cleanup).
38
+ #
39
+ # @param agent_id [String] The agent's unique identifier
40
+ def remove_needs(agent_id)
41
+ @posted_needs.reject! { |n| n[:agent_id] == agent_id }
16
42
  end
17
43
 
18
44
  # Browse available skills across all registered agents.
@@ -79,6 +105,22 @@ module Hestia
79
105
  }
80
106
  end
81
107
 
108
+ # Add need entries from posted needs (session-only, in-memory)
109
+ @posted_needs.each do |posted|
110
+ posted[:needs].each do |need|
111
+ entries << {
112
+ agent_id: posted[:agent_id],
113
+ agent_name: posted[:agent_name],
114
+ name: need[:name],
115
+ format: 'need',
116
+ description: need[:description],
117
+ agent_mode: posted[:agent_mode],
118
+ tags: ['knowledge_need'],
119
+ published_at: posted[:published_at]
120
+ }
121
+ end
122
+ end
123
+
82
124
  entries
83
125
  end
84
126
  end
@@ -12,7 +12,8 @@
12
12
  "KairosMcp::SkillSets::Hestia::Tools::PhilosophyAnchor",
13
13
  "KairosMcp::SkillSets::Hestia::Tools::RecordObservation",
14
14
  "KairosMcp::SkillSets::Hestia::Tools::MeetingPlaceStart",
15
- "KairosMcp::SkillSets::Hestia::Tools::MeetingPlaceStatus"
15
+ "KairosMcp::SkillSets::Hestia::Tools::MeetingPlaceStatus",
16
+ "KairosMcp::SkillSets::Hestia::Tools::MeetingPublishNeeds"
16
17
  ],
17
18
  "config_files": ["config/hestia.yml"],
18
19
  "knowledge_dirs": ["knowledge/hestia_meeting_place"]
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'json'
6
+
7
+ module KairosMcp
8
+ module SkillSets
9
+ module Hestia
10
+ module Tools
11
+ # Publish knowledge needs to a Meeting Place board.
12
+ #
13
+ # DEE compliance:
14
+ # - Requires explicit opt_in: true (no silent publishing)
15
+ # - Needs are session-only (in-memory on the Place, no persistence)
16
+ # - No aggregation or ranking of needs (D3, D5)
17
+ class MeetingPublishNeeds < KairosMcp::Tools::BaseTool
18
+ def name
19
+ 'meeting_publish_needs'
20
+ end
21
+
22
+ def description
23
+ 'Publish knowledge needs (gaps) to a Meeting Place board. ' \
24
+ 'Other agents browsing the board can discover and offer relevant knowledge. ' \
25
+ 'Requires explicit opt-in and an active Meeting Place connection.'
26
+ end
27
+
28
+ def category
29
+ :meeting_place
30
+ end
31
+
32
+ def usecase_tags
33
+ %w[hestia meeting needs knowledge gaps cross-instance board publish]
34
+ end
35
+
36
+ def related_tools
37
+ %w[skills_audit meeting_connect meeting_place_status]
38
+ end
39
+
40
+ def input_schema
41
+ {
42
+ type: 'object',
43
+ properties: {
44
+ opt_in: {
45
+ type: 'boolean',
46
+ description: 'Explicit opt-in to publish knowledge needs. Must be true.'
47
+ },
48
+ mode_name: {
49
+ type: 'string',
50
+ description: 'Instruction mode name to check gaps for (defaults to current active mode)'
51
+ }
52
+ },
53
+ required: ['opt_in']
54
+ }
55
+ end
56
+
57
+ def call(arguments)
58
+ unless arguments['opt_in'] == true
59
+ return text_content(JSON.pretty_generate({
60
+ error: 'opt_in_required',
61
+ message: 'Publishing knowledge needs requires explicit opt-in. ' \
62
+ 'Call with opt_in: true to confirm.'
63
+ }))
64
+ end
65
+
66
+ # Load connection state
67
+ connection_file = File.join(KairosMcp.storage_dir, 'meeting_connection.json')
68
+ unless File.exist?(connection_file)
69
+ return text_content(JSON.pretty_generate({
70
+ error: 'not_connected',
71
+ message: 'No active Meeting Place connection. Use meeting_connect first.'
72
+ }))
73
+ end
74
+
75
+ connection = JSON.parse(File.read(connection_file), symbolize_names: true)
76
+ unless connection[:connected]
77
+ return text_content(JSON.pretty_generate({
78
+ error: 'not_connected',
79
+ message: 'Meeting Place connection is not active. Reconnect using meeting_connect.'
80
+ }))
81
+ end
82
+
83
+ place_url = connection[:url] || connection.dig(:meeting_place, :url)
84
+ agent_id = connection[:self_agent_id]
85
+
86
+ unless place_url && agent_id
87
+ return text_content(JSON.pretty_generate({
88
+ error: 'invalid_connection',
89
+ message: 'Connection state is missing url or agent_id. Reconnect using meeting_connect.'
90
+ }))
91
+ end
92
+
93
+ # Compute knowledge needs using skills_audit logic
94
+ audit_tool = KairosMcp::Tools::SkillsAudit.new
95
+ mode_name = arguments['mode_name'] || audit_tool.send(:current_mode_name)
96
+ needs_data = audit_tool.send(:build_knowledge_needs, mode_name)
97
+
98
+ if needs_data[:needs].empty?
99
+ return text_content(JSON.pretty_generate({
100
+ status: 'no_needs',
101
+ mode: mode_name,
102
+ message: 'All baseline knowledge is present. Nothing to publish.'
103
+ }))
104
+ end
105
+
106
+ # Read session token from connection state
107
+ session_token = connection[:session_token]
108
+
109
+ # POST needs to the Meeting Place board
110
+ mmp_config = ::MMP.load_config rescue {}
111
+ agent_name = mmp_config.dig('identity', 'name') || 'KairosChain Instance'
112
+
113
+ post_body = {
114
+ agent_id: agent_id,
115
+ agent_name: agent_name,
116
+ agent_mode: mode_name,
117
+ needs: needs_data[:needs]
118
+ }
119
+
120
+ result = http_post(
121
+ "#{place_url}/place/v1/board/needs",
122
+ post_body,
123
+ session_token
124
+ )
125
+
126
+ if result
127
+ text_content(JSON.pretty_generate({
128
+ status: 'published',
129
+ mode: mode_name,
130
+ needs_count: needs_data[:needs].size,
131
+ needs: needs_data[:needs],
132
+ place_url: place_url,
133
+ session_only: true,
134
+ hint: 'Needs are visible to other agents browsing the board. ' \
135
+ 'They will be removed when you disconnect.'
136
+ }))
137
+ else
138
+ text_content(JSON.pretty_generate({
139
+ error: 'publish_failed',
140
+ message: 'Failed to publish needs to Meeting Place. ' \
141
+ 'The Place may be unreachable or the session may have expired.',
142
+ place_url: place_url
143
+ }))
144
+ end
145
+ rescue StandardError => e
146
+ text_content(JSON.pretty_generate({
147
+ error: 'unexpected_error',
148
+ message: e.message
149
+ }))
150
+ end
151
+
152
+ private
153
+
154
+ def http_post(url, body, token = nil)
155
+ uri = URI.parse(url)
156
+ http = Net::HTTP.new(uri.host, uri.port)
157
+ http.use_ssl = uri.scheme == 'https'
158
+ req = Net::HTTP::Post.new(uri.path)
159
+ req['Content-Type'] = 'application/json'
160
+ req['Authorization'] = "Bearer #{token}" if token
161
+ req.body = JSON.generate(body)
162
+ response = http.request(req)
163
+ response.is_a?(Net::HTTPSuccess) ? JSON.parse(response.body, symbolize_names: true) : nil
164
+ rescue StandardError
165
+ nil
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
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: 2.4.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masa Hatakeyama
@@ -221,6 +221,7 @@ files:
221
221
  - templates/skillsets/hestia/tools/chain_migrate_status.rb
222
222
  - templates/skillsets/hestia/tools/meeting_place_start.rb
223
223
  - templates/skillsets/hestia/tools/meeting_place_status.rb
224
+ - templates/skillsets/hestia/tools/meeting_publish_needs.rb
224
225
  - templates/skillsets/hestia/tools/philosophy_anchor.rb
225
226
  - templates/skillsets/hestia/tools/record_observation.rb
226
227
  - templates/skillsets/mmp/config/meeting.yml
@@ -269,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
270
  - !ruby/object:Gem::Version
270
271
  version: '0'
271
272
  requirements: []
272
- rubygems_version: 3.3.26
273
+ rubygems_version: 3.5.22
273
274
  signing_key:
274
275
  specification_version: 4
275
276
  summary: KairosChain - Memory-driven agent framework with blockchain auditability