insika 0.8.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +312 -2
  3. data/README.md +10 -6
  4. data/bin/insika +4 -1
  5. data/bin/insika-router +0 -1
  6. data/docs/AGENTS.md +142 -18
  7. data/docs/API.md +73 -0
  8. data/docs/ARCHITECTURE.md +56 -50
  9. data/docs/ARTIFACTS.md +33 -3
  10. data/docs/BENCHMARK.md +50 -7
  11. data/docs/CHANNELS.md +19 -2
  12. data/docs/CONTEXT.md +96 -27
  13. data/docs/CROSS-HARNESS-BENCH.md +157 -0
  14. data/docs/DEPLOY.md +70 -13
  15. data/docs/EMBEDDING.md +10 -0
  16. data/docs/EVALS.md +129 -10
  17. data/docs/FACTS.md +12 -6
  18. data/docs/HARVEST.md +8 -3
  19. data/docs/KNOWLEDGE.md +14 -0
  20. data/docs/MEDIA.md +6 -2
  21. data/docs/OBSERVABILITY.md +164 -28
  22. data/docs/PERFORMANCE.md +110 -0
  23. data/docs/PLUGINS.md +4 -4
  24. data/docs/POLICY.md +26 -14
  25. data/docs/RELEASING.md +9 -0
  26. data/docs/ROUTER.md +7 -0
  27. data/docs/RUBYLLM_2_MIGRATION.md +307 -0
  28. data/docs/SECURITY.md +34 -1
  29. data/docs/SHARED-CONVERSATIONS.md +40 -0
  30. data/docs/SKILLS.md +5 -3
  31. data/docs/STUDIO.md +122 -0
  32. data/docs/TOOLS.md +238 -42
  33. data/docs/operate.md +3 -0
  34. data/docs/prompts/ADD-TOOL.md +12 -2
  35. data/docs/prompts/DIAGNOSE-TURN.md +3 -0
  36. data/docs/prompts/GO-LIVE.md +3 -1
  37. data/lib/insika/agent_defaults.rb +140 -0
  38. data/lib/insika/agent_file_store.rb +12 -0
  39. data/lib/insika/agent_profile.rb +99 -17
  40. data/lib/insika/artifact_signing.rb +11 -0
  41. data/lib/insika/channels/web/widget.js +33 -0
  42. data/lib/insika/channels/web.rb +5 -2
  43. data/lib/insika/chat_builder.rb +124 -28
  44. data/lib/insika/checkpoint.rb +6 -1
  45. data/lib/insika/checkpoint_store.rb +59 -7
  46. data/lib/insika/commands/agent_payload.rb +3 -3
  47. data/lib/insika/commands/delete_kit.rb +26 -0
  48. data/lib/insika/commands/gate_harvest.rb +3 -0
  49. data/lib/insika/commands/review_guardrail_flag.rb +38 -0
  50. data/lib/insika/commands/run_distillation.rb +5 -8
  51. data/lib/insika/commands/run_harvest.rb +17 -1
  52. data/lib/insika/commands/seed_session.rb +128 -0
  53. data/lib/insika/commands/send_message.rb +9 -3
  54. data/lib/insika/commands/update_settings.rb +23 -1
  55. data/lib/insika/commands/write_kit.rb +27 -0
  56. data/lib/insika/compaction.rb +33 -7
  57. data/lib/insika/config_store.rb +87 -7
  58. data/lib/insika/context/builder.rb +29 -9
  59. data/lib/insika/context/priority.rb +5 -0
  60. data/lib/insika/context/provider.rb +7 -2
  61. data/lib/insika/context/providers/briefing.rb +11 -8
  62. data/lib/insika/context/providers/fence_notice.rb +27 -0
  63. data/lib/insika/context/providers/knowledge.rb +32 -6
  64. data/lib/insika/context/providers/memory.rb +61 -8
  65. data/lib/insika/context/providers/pending_confirmation.rb +52 -0
  66. data/lib/insika/context/providers/prompt.rb +17 -4
  67. data/lib/insika/context/providers/session.rb +46 -6
  68. data/lib/insika/context/reranker.rb +75 -0
  69. data/lib/insika/distill.rb +22 -13
  70. data/lib/insika/doctor.rb +142 -4
  71. data/lib/insika/dsl/runtime.rb +37 -4
  72. data/lib/insika/dsl/server_boot.rb +4 -12
  73. data/lib/insika/dsl.rb +19 -5
  74. data/lib/insika/edge_limiter.rb +27 -16
  75. data/lib/insika/egress_guard.rb +11 -3
  76. data/lib/insika/env_schema.rb +33 -73
  77. data/lib/insika/errors.rb +1 -0
  78. data/lib/insika/evals/assertions.rb +259 -18
  79. data/lib/insika/evals/golden.rb +230 -4
  80. data/lib/insika/evals/judge.rb +19 -10
  81. data/lib/insika/evals/moderator_compare.rb +47 -0
  82. data/lib/insika/evals/report.rb +61 -9
  83. data/lib/insika/evals/runner.rb +64 -4
  84. data/lib/insika/evals/simulator.rb +21 -3
  85. data/lib/insika/evals/transport.rb +317 -15
  86. data/lib/insika/event_stream.rb +63 -7
  87. data/lib/insika/evidence.rb +105 -17
  88. data/lib/insika/executor.rb +698 -164
  89. data/lib/insika/fence.rb +96 -0
  90. data/lib/insika/golden_store.rb +3 -0
  91. data/lib/insika/harvest.rb +26 -14
  92. data/lib/insika/harvest_engine.rb +1 -0
  93. data/lib/insika/harvest_store.rb +12 -0
  94. data/lib/insika/http_client.rb +87 -4
  95. data/lib/insika/kits.rb +54 -0
  96. data/lib/insika/knowledge.rb +34 -20
  97. data/lib/insika/llm_configurator.rb +46 -4
  98. data/lib/insika/llm_provider_store.rb +1 -3
  99. data/lib/insika/llm_trace_store.rb +54 -0
  100. data/lib/insika/mcp_client.rb +27 -63
  101. data/lib/insika/mcp_live_tool.rb +55 -9
  102. data/lib/insika/mcp_store.rb +37 -3
  103. data/lib/insika/mcp_tool_registry.rb +76 -26
  104. data/lib/insika/media.rb +38 -25
  105. data/lib/insika/memory_store.rb +16 -3
  106. data/lib/insika/memory_trim.rb +60 -0
  107. data/lib/insika/middleware.rb +12 -3
  108. data/lib/insika/model_metrics_store.rb +285 -0
  109. data/lib/insika/model_registry.rb +110 -0
  110. data/lib/insika/model_resolver.rb +1 -1
  111. data/lib/insika/model_selection.rb +14 -21
  112. data/lib/insika/model_visible.rb +17 -6
  113. data/lib/insika/onboarding.rb +1 -0
  114. data/lib/insika/outcome_store.rb +1 -1
  115. data/lib/insika/overlay_tool_registry.rb +30 -2
  116. data/lib/insika/pack_importer.rb +54 -9
  117. data/lib/insika/packaging.rb +14 -5
  118. data/lib/insika/pending_action_store.rb +45 -18
  119. data/lib/insika/plugin/loader.rb +4 -2
  120. data/lib/insika/prefix_fingerprint.rb +32 -27
  121. data/lib/insika/profile_source.rb +5 -0
  122. data/lib/insika/provider_error_classifier.rb +18 -3
  123. data/lib/insika/queue_policy.rb +7 -2
  124. data/lib/insika/refinement/proposer.rb +42 -17
  125. data/lib/insika/reliability.rb +12 -3
  126. data/lib/insika/router/app.rb +14 -5
  127. data/lib/insika/router/session_key.rb +35 -5
  128. data/lib/insika/safety/config.rb +20 -3
  129. data/lib/insika/safety/corpus.rb +10 -3
  130. data/lib/insika/safety/factory.rb +39 -1
  131. data/lib/insika/safety/input_guardrail.rb +21 -1
  132. data/lib/insika/safety/judge_moderator.rb +70 -0
  133. data/lib/insika/safety/output_validator.rb +29 -5
  134. data/lib/insika/safety/prompt_echo.rb +89 -0
  135. data/lib/insika/schema_guard.rb +53 -76
  136. data/lib/insika/server/app.rb +58 -7
  137. data/lib/insika/server/rack_app.rb +2 -0
  138. data/lib/insika/server/responses.rb +50 -5
  139. data/lib/insika/session_actor.rb +58 -28
  140. data/lib/insika/session_store.rb +163 -11
  141. data/lib/insika/settings_store.rb +57 -2
  142. data/lib/insika/shared_conversations.rb +305 -0
  143. data/lib/insika/skill_catalog.rb +28 -2
  144. data/lib/insika/skill_store.rb +6 -0
  145. data/lib/insika/soak/runner.rb +1 -1
  146. data/lib/insika/spoken_transcript.rb +31 -0
  147. data/lib/insika/steer_injector.rb +7 -48
  148. data/lib/insika/store.rb +29 -1
  149. data/lib/insika/stores/json_value.rb +37 -0
  150. data/lib/insika/stores/memory.rb +22 -35
  151. data/lib/insika/stores/postgres.rb +295 -0
  152. data/lib/insika/stores/sqlite.rb +257 -43
  153. data/lib/insika/stores/turn_counter.rb +25 -0
  154. data/lib/insika/studio/app.rb +1459 -163
  155. data/lib/insika/studio/assets/dist/application.css +1 -1
  156. data/lib/insika/studio/assets/dist/application.js +25 -25
  157. data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  158. data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  159. data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  160. data/lib/insika/studio/assets/dist/fonts/ibm-plex-sans-latin-wght-normal.woff2 +0 -0
  161. data/lib/insika/studio/forms.rb +189 -12
  162. data/lib/insika/studio/nav_icons.rb +3 -0
  163. data/lib/insika/studio/views/_agent_config_retrieval.erb +73 -0
  164. data/lib/insika/studio/views/_agent_picker.erb +15 -0
  165. data/lib/insika/studio/views/_agent_tab_config.erb +83 -243
  166. data/lib/insika/studio/views/_agent_tab_history.erb +56 -1
  167. data/lib/insika/studio/views/_agent_tab_performance.erb +34 -0
  168. data/lib/insika/studio/views/_agent_tab_prompts.erb +7 -9
  169. data/lib/insika/studio/views/_agent_tab_skills.erb +16 -7
  170. data/lib/insika/studio/views/_agent_tab_tools.erb +90 -0
  171. data/lib/insika/studio/views/_agents_master.erb +8 -12
  172. data/lib/insika/studio/views/_cfg_alerts.erb +4 -0
  173. data/lib/insika/studio/views/_cfg_budget.erb +20 -0
  174. data/lib/insika/studio/views/_cfg_distill.erb +26 -0
  175. data/lib/insika/studio/views/_cfg_followup.erb +30 -0
  176. data/lib/insika/studio/views/_cfg_grounding.erb +21 -0
  177. data/lib/insika/studio/views/_cfg_guardrails.erb +47 -0
  178. data/lib/insika/studio/views/_cfg_harvest.erb +35 -0
  179. data/lib/insika/studio/views/_cfg_reliability.erb +32 -0
  180. data/lib/insika/studio/views/_chats_master.erb +66 -0
  181. data/lib/insika/studio/views/_customers_master.erb +37 -0
  182. data/lib/insika/studio/views/_empty.erb +15 -0
  183. data/lib/insika/studio/views/_facts_master.erb +42 -0
  184. data/lib/insika/studio/views/_harvest_candidate_detail.erb +14 -0
  185. data/lib/insika/studio/views/_identity.erb +16 -0
  186. data/lib/insika/studio/views/_kpi.erb +17 -0
  187. data/lib/insika/studio/views/_message.erb +40 -2
  188. data/lib/insika/studio/views/_model_chart.erb +82 -0
  189. data/lib/insika/studio/views/_refinement_master.erb +38 -0
  190. data/lib/insika/studio/views/{tool_edit.erb → _tool_edit.erb} +38 -11
  191. data/lib/insika/studio/views/_tool_users.erb +17 -0
  192. data/lib/insika/studio/views/_why.erb +53 -0
  193. data/lib/insika/studio/views/agent_detail.erb +17 -10
  194. data/lib/insika/studio/views/agents.erb +28 -16
  195. data/lib/insika/studio/views/approvals.erb +16 -11
  196. data/lib/insika/studio/views/artifact.erb +20 -7
  197. data/lib/insika/studio/views/artifacts.erb +19 -14
  198. data/lib/insika/studio/views/chats.erb +22 -29
  199. data/lib/insika/studio/views/customer.erb +88 -43
  200. data/lib/insika/studio/views/customers.erb +16 -26
  201. data/lib/insika/studio/views/evals.erb +49 -31
  202. data/lib/insika/studio/views/fact_detail.erb +114 -0
  203. data/lib/insika/studio/views/facts.erb +15 -116
  204. data/lib/insika/studio/views/followups.erb +63 -52
  205. data/lib/insika/studio/views/funnel.erb +104 -43
  206. data/lib/insika/studio/views/harvest.erb +85 -59
  207. data/lib/insika/studio/views/home.erb +138 -23
  208. data/lib/insika/studio/views/inbox.erb +36 -0
  209. data/lib/insika/studio/views/kits.erb +176 -0
  210. data/lib/insika/studio/views/knowledge.erb +92 -80
  211. data/lib/insika/studio/views/layout.erb +42 -11
  212. data/lib/insika/studio/views/live.erb +45 -0
  213. data/lib/insika/studio/views/mcp.erb +43 -13
  214. data/lib/insika/studio/views/models.erb +187 -0
  215. data/lib/insika/studio/views/parity.erb +38 -32
  216. data/lib/insika/studio/views/playground.erb +13 -9
  217. data/lib/insika/studio/views/refinement.erb +15 -224
  218. data/lib/insika/studio/views/refinement_detail.erb +243 -0
  219. data/lib/insika/studio/views/session.erb +153 -118
  220. data/lib/insika/studio/views/settings.erb +86 -22
  221. data/lib/insika/studio/views/skills.erb +53 -19
  222. data/lib/insika/studio/views/system_files.erb +7 -7
  223. data/lib/insika/studio/views/task.erb +45 -15
  224. data/lib/insika/studio/views/tasks.erb +35 -18
  225. data/lib/insika/studio/views/tools.erb +62 -73
  226. data/lib/insika/task_actor.rb +4 -1
  227. data/lib/insika/task_store.rb +67 -1
  228. data/lib/insika/telemetry/pricing.rb +16 -14
  229. data/lib/insika/telemetry/recorder.rb +115 -9
  230. data/lib/insika/telemetry/ruby_llm_instrumenter.rb +110 -0
  231. data/lib/insika/telemetry.rb +12 -2
  232. data/lib/insika/templates/daily-digest/README.md +13 -0
  233. data/lib/insika/templates/daily-digest/agent.rb +22 -11
  234. data/lib/insika/testing/store_contract.rb +65 -0
  235. data/lib/insika/text_tool_call.rb +66 -0
  236. data/lib/insika/tick.rb +7 -1
  237. data/lib/insika/token_store.rb +5 -0
  238. data/lib/insika/tool_assembly.rb +21 -13
  239. data/lib/insika/tool_batch.rb +1 -1
  240. data/lib/insika/tool_catalog.rb +12 -2
  241. data/lib/insika/tool_definition.rb +82 -13
  242. data/lib/insika/tool_envelope.rb +266 -29
  243. data/lib/insika/tool_manifest.rb +1 -0
  244. data/lib/insika/tool_store.rb +12 -4
  245. data/lib/insika/tool_trace_store.rb +15 -8
  246. data/lib/insika/tool_usage_report.rb +14 -4
  247. data/lib/insika/tools/a2a_remote.rb +1 -1
  248. data/lib/insika/tools/agent_enum.rb +1 -1
  249. data/lib/insika/tools/confirm_pending.rb +112 -0
  250. data/lib/insika/tools/data_defined_tool.rb +24 -15
  251. data/lib/insika/tools/generate_image.rb +2 -2
  252. data/lib/insika/tools/load_knowledge.rb +7 -3
  253. data/lib/insika/tools/load_skill.rb +3 -3
  254. data/lib/insika/tools/present.rb +115 -0
  255. data/lib/insika/tools/remember.rb +7 -2
  256. data/lib/insika/tools/run_persona_eval.rb +9 -6
  257. data/lib/insika/tools/save_artifact.rb +16 -6
  258. data/lib/insika/tools/schedule_followup.rb +3 -3
  259. data/lib/insika/tools/stuck_signal.rb +3 -3
  260. data/lib/insika/tools/subagent.rb +5 -5
  261. data/lib/insika/tools/subagents.rb +3 -3
  262. data/lib/insika/tools/tool_search.rb +11 -7
  263. data/lib/insika/tools/tts.rb +2 -2
  264. data/lib/insika/tools/update_briefing.rb +4 -4
  265. data/lib/insika/turn_output.rb +2 -2
  266. data/lib/insika/turn_state.rb +31 -1
  267. data/lib/insika/turn_timing.rb +51 -14
  268. data/lib/insika/version.rb +1 -1
  269. data/lib/insika/wiring/graph.rb +88 -16
  270. data/lib/insika/wiring/graph_chat.rb +4 -0
  271. data/lib/insika/workflow.rb +25 -64
  272. data/lib/insika.rb +23 -3
  273. metadata +74 -13
  274. data/lib/insika/commands/import_mcp_tools.rb +0 -48
  275. data/lib/insika/mcp_http_client.rb +0 -67
  276. data/lib/insika/mcp_tool_ingestor.rb +0 -165
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 345e57c18a277e8ecd49b2481300c1474c60b2e0c3c384a086740e0de5ec3a2e
4
- data.tar.gz: 800794431e279fec34f135e4e203a0488b04066b667bc691806ea5f575d81530
3
+ metadata.gz: b98a9d84df7cda373881cc11d0658bc3dd208ceb4bc52c23ed4fed4bd641fbb4
4
+ data.tar.gz: cecc0e4671a335efc5670f297aaf53ebafd5f1662f25a3121894825582494b30
5
5
  SHA512:
6
- metadata.gz: 199cc16b9ea651ec2da1d2e6f7ddea5020194882da00cf96981e8d5d44086233862873d14640d11cd1d445f9d202992ed46691210f9fb1699b1a3d56a99b3145
7
- data.tar.gz: 44d24bc53036da3803ee6eba6203d1addc8ccf0bd27c1aa15d1e9acfe763bca807ede55c2b7136ee2c245e5cd725541c719baa018c99e09638e964803bf688a9
6
+ metadata.gz: 332d1cea74cdbee9e3241dfefc73538824643fe3b65964fb2584ed57fb4d85c7b1cb547c7d2ccf3ff2acd4893d49063bed60fbf6e94ed6968e1c30bbd9671b30
7
+ data.tar.gz: d203a16b2954fb36829ed074a463ebac6dce26fea980e546debf5e908e4bf6bfb77c7d04b2e703816254022eaf3da9dbbce1a09c845525454dc6126996ce00b0
data/CHANGELOG.md CHANGED
@@ -3,11 +3,321 @@
3
3
  All notable changes to this project are documented here.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
6
- project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) once
7
- it is released. Entries land with the pull request that makes the change.
6
+ project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from 1.0.0 on. Entries land with the pull request that makes the change.
8
7
 
9
8
  ## [Unreleased]
10
9
 
10
+ ## [1.0.1] - 2026-10-23
11
+
12
+ ### Removed
13
+
14
+ - Internal planning notes (`docs/superpowers/`) are no longer in the repository or the
15
+ gem. 1.0.0 shipped them by mistake; the packaging now never ships that directory.
16
+
17
+ ## [1.0.0] - 2026-10-23
18
+
19
+ ### Added
20
+
21
+ - Harvest page: each pending or blocked candidate shows its skill text, rationale and origin conversation; a blocked one can be re-gated once the missing piece is fixed; the page says when the loop skips an agent (harvest off, or no grounding matcher).
22
+ - Studio screens for watching conversations and what waits on a person (see
23
+ [Studio](docs/STUDIO.md)):
24
+ - **Live** (`/studio/live`): one card per recent conversation, moved by the
25
+ event stream (tools in the running turn, "agent is writing…", guardrail
26
+ flags), with an event ticker. `?agent=` shows one agent's conversations.
27
+ - **Why this reply**: under each agent reply, its turn's context by category,
28
+ skills injected and why, tool calls with timing and guardrail flags, plus
29
+ Replay in Playground and Save as eval case.
30
+ - **Inbox** (`/studio/inbox`): approvals, fact proposals, mined skills,
31
+ refinement runs and guardrail false-positive reports in one list, oldest
32
+ first, with tabs per type.
33
+ - **Guardrail false positives**: a flag can be marked as a false positive,
34
+ then resolved or undone (`:review_guardrail_flag`). The verdict lives on the
35
+ flag inside the session.
36
+ - **Agent History**: outcomes per day over 30 days with a marker per change
37
+ to a prompt file or to the agent's own skills, and per change a short diff
38
+ and the outcomes 7 days after vs 7 days before.
39
+ - **Funnel drops**: the biggest loss between stages, and per loss the
40
+ conversations that stopped there, grouped by the last thing that happened.
41
+ - Chats tabs (All / Active now / Guardrail flagged), a customer card on the
42
+ session, a tool-call waterfall per turn, an Overview "Needs attention" row,
43
+ a `⌘K` palette, and a sidebar grouped as Operate / Review / Build /
44
+ Insights / Platform with a count badge on each Review page.
45
+ - Markup tags in message text (`<carrossel/>`, `<vitrine formato="lista">`)
46
+ show as highlighted tokens, escaped and never rendered.
47
+ - `Store#amend(scope, key, value)`: overwrites a key without moving it in
48
+ `#recent`. The default is `#set`; a backend whose `#recent` follows its own
49
+ write order overrides both (the contract suite checks it). Memory, SQLite and
50
+ Postgres implement it.
51
+ - Persisted turn messages and tool-call traces carry `task_id`, so the Studio
52
+ ties each message to its own turn.
53
+
54
+ - `scripts/migrate_openclaw.rb seed`: carries recent OpenClaw conversations into
55
+ Insika sessions (`POST /v1/conversations/:id/seed`) so a returning customer
56
+ keeps the context. Reads root and per-process SQLite transcripts, follows the
57
+ active branch from the last compaction, keeps only customer text and agent
58
+ replies, and skips conversations that already have messages. `--only`/`--as`
59
+ rehearse one conversation on a test chat.
60
+ Each session is stamped with `--agent`, so the Studio lists it under that
61
+ agent; re-running stamps sessions seeded before (they still answer 409).
62
+ - Platform agent defaults (Studio › Settings › Agent defaults, or
63
+ `update_settings` with `agent_defaults`): an agent with no value of its own
64
+ for reliability, knowledge, memory retrieval, budget, alerts, guardrails,
65
+ grounding, follow-ups, distillation or harvest runs with the platform's. The
66
+ agent's own value wins whole. Each of those sections in the agent config has
67
+ a "use the platform default" box; saving with it checked keeps the agent
68
+ inheriting. A default is validated on save, and one that stops building
69
+ later leaves agents on their own values instead of failing turns. Agents
70
+ saved in the Studio before this have their own knowledge, guardrails,
71
+ distillation and harvest values (the form always wrote them): check the box
72
+ to make them inherit.
73
+
74
+ - **Optional Postgres store** (`INSIKA_DATABASE_URL`, `INSIKA_DATABASE_POOL`). It passes the
75
+ same store contract as SQLite; `pg` is not a gem dependency and loads only when the
76
+ variable is set. `scripts/store_copy.rb` moves an existing store. See
77
+ [Postgres store](docs/DEPLOY.md#postgres-store-optional) for when it pays off.
78
+ - `Store#entries` and `Store#recent`: a whole scope, or its most recently written keys, in
79
+ one call. The default implementation keeps third-party backends working; SQLite and
80
+ Postgres answer each in one query. The Studio's session and task lists use them.
81
+ - `INSIKA_SLOW_STORE_MS` also logs each slow write batch: its size, bytes, scopes, and how
82
+ long it waited for the lock versus how long its commit took.
83
+
84
+ ### Changed
85
+ - Session stats are versioned (`"v" => 2`, adds the guardrail flagged and
86
+ reported counts). `scripts/backfill_session_stats.rb` now also rewrites stats
87
+ older than the current version, not only missing ones.
88
+ - Reviewing a guardrail flag no longer moves the session to the top of the
89
+ recent lists.
90
+ - **MCP tools are named after their instance**: `<instance>__<tool>` (e.g.
91
+ `shop_staging__list_products`). Two instances offering the same tool used to share
92
+ one name, and every call went to whichever instance came first. Agents that allowed
93
+ MCP tools by name must select them again; per-tool overrides keep the server's name.
94
+ - `INSIKA_EGRESS_HOSTS` pins an MCP server only when its host resolves to a private
95
+ address. The operator registers the URL and the model cannot change it, so adding a
96
+ public server needs no redeploy. HTTPS still applies, and a private server still needs
97
+ `INSIKA_EGRESS_ALLOW_PRIVATE` and a listed host.
98
+
99
+ - An input guardrail injection hit no longer replaces the turn with the canned
100
+ refusal by default. The message reaches the model with a per-turn
101
+ `<security_notice>` (never persisted) and an audit `guardrail_flagged` with
102
+ `action: "flag"`, so a legitimate request in the same message is still served.
103
+ Sexual and abuse hits still block, now also when the message carries an
104
+ injection too. `guardrails.injection: "block"` (Studio › Guardrails › on
105
+ injection) restores the old behavior.
106
+ - `Store#recent` takes an optional fourth argument, `offset`, to read the next page; a
107
+ backend that implements the three-argument form keeps working (the stores pass
108
+ `offset` only when paging). SQLite reads a page's keys from the index and then only
109
+ their values, instead of reading every value in the range to sort it.
110
+ - Studio: the tasks list shows 50 tasks per page, newest first, instead of every task.
111
+ The home reads only the sessions of the last 14 days; its messages card counts that
112
+ window (and says so), and the conversations total comes from the keys alone.
113
+ - Every session write also writes a small stats record (last update, message count,
114
+ agent) in the `session_stats` scope, and the Studio home reads those instead of whole
115
+ sessions (every stat, filtered by date, so the order they were written in does not
116
+ matter). Sessions stored before this change have no stats until
117
+ `scripts/backfill_session_stats.rb` runs once (idempotent, safe with the app running;
118
+ it also removes stats whose session is gone).
119
+ - RubyLLM is pinned to a newer `2.0.0` commit: streamed responses are priced once when
120
+ read instead of on every chunk, and HTTP connections are shared per process and
121
+ settings. Specs stub LLM HTTP with `stub_llm_http`, because swapping the adapter on an
122
+ already-built connection no longer takes effect.
123
+
124
+ - Studio tools are grouped by origin and MCP server, with name/server filtering,
125
+ collapsible sections and per-section select/deselect actions. Selection keeps
126
+ denied tools blocked and requires saving before permissions change.
127
+
128
+ - Workflow and tool argument validation now use JSONSchemer. Explicit nulls and
129
+ declared constraints are enforced; existing tool scalar leniency remains.
130
+ - Distillation, harvest, knowledge and refinement use native structured responses.
131
+ Retired MCP import delegates to live discovery instead of generating HTTP snapshots.
132
+
133
+ - RubyLLM 2 migration: native loop control, tool schemas, cache markers, and usage
134
+ readers. MCP now uses the native RubyLLM client, replacing `ruby_llm-mcp` and the
135
+ Origin-header patch. Legacy SSE requires migration to Streamable HTTP. See
136
+ [migration results](docs/RUBYLLM_2_MIGRATION.md).
137
+ - Requires RubyLLM `~> 2.1` from RubyGems; the Git pin is gone. A provider's 400
138
+ quota message ("quota exceeded", "wait before trying again") now arrives as
139
+ `RubyLLM::RateLimitError` and is retried and rotated instead of failing the turn.
140
+
141
+ - SQLite writes from concurrent turns share one transaction and one commit (group commit),
142
+ so N worker processes take the file's write lock far less often. A turn opens and
143
+ closes its task record in one write each, and skips an empty evidence write.
144
+ - Litestream 0.5 with its blocking checkpoint disabled (`truncate-page-n: 0`); it restores
145
+ backups made by 0.3.
146
+ - Less CPU per turn: the prompt reads an agent's files once per build, the prompt-echo
147
+ check caches each squeezed prompt, and streamed events are matched only against their
148
+ own session's subscriptions.
149
+
150
+ ### Removed
151
+
152
+ - **The `HARNESS_*` environment variables (breaking).** Only the `INSIKA_*` names are
153
+ read. A leftover `HARNESS_*` key is no longer honored: it is reported as an error
154
+ naming its `INSIKA_*` replacement (a warning at boot, fatal under
155
+ `INSIKA_CONFIG_STRICT`, and an error in `insika doctor`), so a stale `HARNESS_DB`
156
+ cannot silently boot the engine on the memory backend. `EnvSchema.reconcile_legacy!`
157
+ is gone, and the bundled `insika-code` plugin and example read `INSIKA_CODE_*`.
158
+ - **The `plugin.yml` manifest name (breaking).** Only `insika.plugin.yml` loads. A
159
+ leftover `plugin.yml` is not loaded and warns to rename it.
160
+ - `Insika::LLMHTTPAdapter` (`faraday_adapter = :insika_net_http`). RubyLLM 2.1 shares
161
+ one connection per process and settings, so the stock `:net_http` no longer builds a
162
+ CA store per chat. A deployment that set `:insika_net_http` drops that line.
163
+
164
+ ### Fixed
165
+
166
+ - Skills written in one worker (pack import, Studio edit, `write_skill`) now reach the other workers within 2 s. The catalog only reloaded in the worker that handled the write, so the others kept the skills they booted with until a restart — in the Studio and in customer turns.
167
+ - Harvest no longer mines simulator/eval sessions (`sim-…`, `eval-…`), and the miner sees the candidates still open so it stops re-proposing the same idea under new names.
168
+ - Harvest: a bare `miner.model` ref (no `provider/`) now uses the agent's provider; it used to fail every run with `Provider must be specified`.
169
+ - Studio: `/studio` without a trailing slash answered 404; it now opens the
170
+ Overview.
171
+ - Studio: the agent History chart and arm conversions counted outcome kinds
172
+ against the primary stage name, so they read 0 whenever the kind and stage
173
+ names differ; they now map kinds through `advance_on`.
174
+ - Studio: a negative message or flag index on a guardrail review counted from
175
+ the end and reviewed the wrong flag; it is now not found.
176
+ - An error that is fatal only for one model or account no longer kills the turn:
177
+ no balance (402), a bad key or missing access (401/403) and a model the provider
178
+ does not have (404) move straight to the next fallback node — no retry on that
179
+ node, no backoff, and no circuit-breaker count (an open primary circuit fails
180
+ fast without rotating). On the last node it still raises; a 400 still never
181
+ rotates.
182
+ - Studio model fields are type-to-search pickers over the configured providers'
183
+ `provider/model` refs (their declared models, plus the chat models of key-only
184
+ providers): the agent model, a new agent, the playground pin and Settings'
185
+ default, fallback (one slot per position) and utility models. The server
186
+ refuses a ref outside the list — a typed `openai/gpt-x` under provider `openai`
187
+ used to reach the API as `openai/openai/gpt-x`. A stored value outside the list
188
+ is shown marked "not configured" and may be saved back unchanged. The plain
189
+ `model`/`provider` fields still pass as given for API clients.
190
+ The same pickers cover the reliability fallback chain (agent and Agent
191
+ defaults) and the refinement proposers, one slot per position, and the
192
+ knowledge, distill, harvest-miner and compaction models.
193
+ - Data-tools imported or edited in one worker now reach the others: the tool
194
+ registry checks the config version token (at most every 2 s) and rebuilds when
195
+ it moved, and the tool catalog follows. Before, the other workers kept the
196
+ catalog they booted with until a restart.
197
+ - LLM providers authored at runtime reach every worker process, and survive a
198
+ restart: each chat re-applies the stored providers when they changed. Before,
199
+ only the worker that served the edit had the key, so a fallback on that
200
+ provider failed as unconfigured. A cleared key stops being used; a key from
201
+ the environment is never cleared by it.
202
+ - Deleting an LLM provider authored at runtime puts back the key and base the
203
+ process started with (for example from the environment) instead of leaving
204
+ the provider without credentials; a worker that never applied the provider
205
+ leaves its config alone. Delete no longer disables a provider that also has a
206
+ key from the environment.
207
+ - Native chat usage includes tool rounds and retries, and failed turns expose
208
+ recorded usage. Responses projects cache-inclusive totals; negotiated pricing
209
+ no longer subtracts cache reads from already non-cached input.
210
+ - Reliability honors session model pins and model allowlists without multiplying
211
+ its attempt budget by RubyLLM transport retries.
212
+ - Speech response reads stop at the byte limit before buffering the entire body.
213
+ - Workflow schemas accept valid `false` values.
214
+
215
+ - **A merged fragment is framed by `steer_join`, like a steered one already was.** The
216
+ two burst doors disagreed on what the model sees: a steered message becomes its OWN
217
+ `user` message in the transcript (framed by `steer_join`), while a merged one was
218
+ concatenated into the queued turn's single payload by a bare `\n`. A burst therefore
219
+ reached the model as one run-on paragraph with no boundary between the asks, and a
220
+ trailing constraint could be answered by nothing (staging, Acme Beauty,
221
+ 2026-09-18: five messages merged 4/4, and the answer never mentioned the fifth).
222
+ `steer_join` now applies to both doors; the default `nil` returns the text untouched,
223
+ so a wiring that never set it is unchanged.
224
+
225
+ - **The door is open for as long as a turn is queued, not only during a debounce
226
+ window.** `collect`/`steer` merged a fragment only while a turn sat in a
227
+ `debounce_ms` window; a message that arrived while a turn waited behind the one in
228
+ flight joined nothing and became a turn of its own, third in line. A
229
+ `POST /v1/messages?stream=false` caller then held its connection through TWO turns
230
+ and timed out — on the WhatsApp integration that surfaced as a technical apology
231
+ to the customer, once per excess message of a burst. A queued turn is now mergeable
232
+ with or without a window, so every burst message answers immediately with `merged`
233
+ or `steered`. `followup` (the default) is untouched.
234
+ - **Re-importing a pack no longer erases the knobs it did not send.** `limits` and
235
+ `params` now MERGE per key on an update (`PackImporter::KNOB_BAGS`); everything
236
+ else keeps replacing. A provisioning client that publishes
237
+ `limits: {turn_timeout:, context_budget:}` used to drop every other knob on the
238
+ agent — `queue_mode`, `debounce_ms`, `chat_rate_limit` — so an unrelated playbook
239
+ publish silently reset the queue policy an operator had set in the Studio. The
240
+ authoritative allowlists (`prompt_files`/`skills`/`tools_allow`) are unchanged: a
241
+ name that left the pack still leaves the agent.
242
+ - One door per queued turn: with two turns waiting, the second used to take over the
243
+ first's fragment count, and the first then ran from a message snapshot the store had
244
+ already grown past.
245
+
246
+ ## [0.9.0] - 2026-09-07
247
+
248
+ The commerce-agent wave: the engine now enforces what the prompt used to ask for —
249
+ a write names only IDs a lookup returned, the model picks which cards to show and
250
+ the engine shows them, third-party text can be fenced before the model reads it,
251
+ and an eval case can start from a seeded snapshot. Additive on the wire: `/v1`
252
+ gains frames and keys, none change meaning.
253
+
254
+ ### Added
255
+
256
+ - **Write provenance** — `requires_evidence` on HTTP data tools checks declared
257
+ ID parameters against the session evidence ledger before approval or execution.
258
+ Unknown IDs and an unavailable ledger return `blocked` with gate `provenance`.
259
+ Studio editing, Doctor diagnostics, session traces, `tool_blocked`, the
260
+ `insika.tool.blocked` counter and `insika tools:report` expose the gate.
261
+ See [Tools](docs/TOOLS.md#provenance-checking-ids-before-a-write).
262
+ - **Snapshot evals** — cases can seed evidence IDs, memory, user/assistant history
263
+ and briefing before the first turn. The authenticated seed endpoint is disabled
264
+ by default (`evals.seeding`); Doctor warns when enabled. New assertions cover
265
+ forbidden/alternative/first calls, call limits, reply text and blocked gates.
266
+ Responses SSE now carries tool arguments, completion status and the provider's
267
+ `call_id` on both item frames, so a consumer pairs `added` with `done`.
268
+ See [Evals](docs/EVALS.md#state--a-case-starts-from-a-snapshot).
269
+ - **Presentation tools** — data tools with `presentation` instead of `request`
270
+ select evidence cards by known ID — this turn's, or the last 64 the session
271
+ ledger kept (snapshots seed them as `evidence.cards`). They report shown/dropped IDs,
272
+ emit `insika.ui` (web channel: `ui`) and select the outbox attachments. Evidence
273
+ cards carry IDs; empty selections suppress automatic card delivery. Includes
274
+ `ui_components` / `no_ui` eval assertions and Doctor diagnostics.
275
+ See [Tools](docs/TOOLS.md#presentation-tools-the-model-picks-ids-the-engine-shows-the-cards).
276
+ - **Fencing** — opt-in per agent through the DSL, payload or Studio. Sanitizes
277
+ ordinary tool result strings, memory text and injected knowledge summaries, and adds a fixed
278
+ identity-layer notice. The tool-string cap `fencing.max_chars` defaults to 12,000; the agent flag
279
+ defaults to off — and stays off in this release: flipping the default waits for the
280
+ golden-case comparison with fencing on ([Releasing](docs/RELEASING.md), gate 4).
281
+ Doctor warns for unfenced agents exposed by relay/widget env configuration.
282
+ See [Agents](docs/AGENTS.md#fencing--third-party-text-is-data-never-instructions).
283
+
284
+ ### Changed
285
+
286
+ - **Cache boundary** — explicit Anthropic cache control ends at the identity layer;
287
+ volatile system text follows in a separate block. Prefix fingerprints cover
288
+ identity and tool schemas; memory/knowledge/request changes retain separate
289
+ diagnostic digests without reporting identity-prefix invalidation.
290
+ See [Context](docs/CONTEXT.md#the-provider-prefix-cache).
291
+ - **Serial writes in parallel batches** — tools marked `side_effect` acquire a
292
+ per-session serial gate before the shared concurrency slot. Independent reads
293
+ can overlap writes; queued writes do not consume that shared slot. MCP tools
294
+ annotated `readOnlyHint` are reads.
295
+ - Memory and knowledge extraction read only nonblank user/assistant text, preserving
296
+ original transcript indexes. Direct tool messages are excluded; assistant
297
+ paraphrases can still reach extraction. This applies regardless of `fencing`.
298
+ - A tool's own `{"status":"blocked"}` answer is a call that ran: only the engine's
299
+ gate refusal reports `blocked` on `:tool_result`, the trace and `tools:report`.
300
+ - A Studio save that changes a tool's HTTP method re-derives `side_effect`.
301
+
302
+ ### Fixed
303
+
304
+ - Data tools declaring `evidence` no longer fail when the envelope parses an
305
+ already-parsed `Evidence::Spec`.
306
+ - Studio tool saves preserve `evidence` and `presentation` declarations.
307
+ - `scripts/serve_real.rb` passes channel and settings stores to the edge, enabling
308
+ configured relay/widget routes and the eval seeding setting in the demo server.
309
+ - Fencing: the notice ships with the flag regardless of the `context_providers`
310
+ allowlist; briefing values and the compaction summary are sanitized too; evidence
311
+ item ids stay byte-exact for the model (only the line is sanitized).
312
+ - Provenance: a schema-optional parameter the model omits is not checked; a blocked
313
+ call on a one-shot turn no longer fails emitting `tool_blocked`.
314
+ - `POST /v1/conversations/:id/seed` decodes a percent-encoded conversation id.
315
+ - Widget `ui` cards link only `http(s)` urls.
316
+ - The evidence ledger reads the session row once per turn, not once per gated call.
317
+ - Studio reads its templates as UTF-8 regardless of the process locale: a host with
318
+ no `LANG` answered 500 on the login page (found by the release install proof).
319
+
320
+
11
321
  ## [0.8.0] - 2026-08-31
12
322
 
13
323
  The post-consolidation hardening wave: the last two OpenClaw-era names are gone
data/README.md CHANGED
@@ -16,9 +16,11 @@ web control UI. Point an existing Responses client at it and serve many agents f
16
16
  deployment.
17
17
 
18
18
  - **Drop-in `/v1/responses`** — SSE streaming and usage, the shape existing clients already speak.
19
- - **Durable & resumable** — every turn checkpoints; a crash resumes without repeating side-effects.
19
+ - **Durable & resumable** — every turn checkpoints; recorded side-effect calls are deduplicated on replay. External writes still need idempotency.
20
20
  - **Agents as data** — agents, prompts, skills and tools are editable at runtime (UI or API), no redeploy.
21
- - **Tools & skills** — code tools, data-defined tools, MCP import; skills load on demand.
21
+ - **Tools & skills** — code, HTTP data and live MCP tools; skills load on demand.
22
+ - **Evidence-backed actions** — ID checks before writes, serial side effects per session, and selected evidence cards ([Tools](docs/TOOLS.md)).
23
+ - **Snapshot evals** — seed a case's starting state and check calls, refusals, replies and cards ([Evals](docs/EVALS.md)).
22
24
  - **Safe by default** — content-safety guardrails, an egress guard, confined execution, approvals, edge limits.
23
25
  - **Observable** — an event stream, per-session tool-call traces, optional OpenTelemetry.
24
26
  - **~0.4 ms of engine per turn** — p50 overhead on a neutral, key-free benchmark you can rerun yourself ([methodology](docs/BENCHMARK.md)).
@@ -106,7 +108,7 @@ navigates by.
106
108
 
107
109
  - [Agents](docs/AGENTS.md) — the AgentProfile and every key on it; create and edit at runtime.
108
110
  - [Limits and policy](docs/POLICY.md) — the five layers: allowed tools, approvals, guardrails, edge limits, reasoning.
109
- - [Tools](docs/TOOLS.md) — code vs data vs MCP tools, manifests, egress troubleshooting.
111
+ - [Tools](docs/TOOLS.md) — code, HTTP, MCP and presentation tools; evidence gates and serial writes.
110
112
  - [Skills](docs/SKILLS.md) — the SKILL.md format and progressive loading.
111
113
  - [Context](docs/CONTEXT.md) — what fills a turn's prompt; budget, eviction, memory.
112
114
  - [Workflows](docs/WORKFLOWS.md) — deterministic orchestration of several agents: the five patterns, and when to let the model choose instead.
@@ -137,10 +139,11 @@ navigates by.
137
139
  - [Load test](docs/LOADTEST.md) — load-testing and data topology.
138
140
  - [Soak](docs/SOAK.md) — the long run that finds what a short one cannot.
139
141
  - [Benchmark](docs/BENCHMARK.md) — the neutral, reproducible, provider-free engine benchmark.
142
+ - [Performance](docs/PERFORMANCE.md) — what keeps a turn cheap (fibers, SQLite group commit, memory trim) and what was tried and left out.
140
143
 
141
144
  **Improve**
142
145
 
143
- - [Evals](docs/EVALS.md) — the cases that grade an agent: rubrics, the judge panel, and the pre-merge gate.
146
+ - [Evals](docs/EVALS.md) — snapshot cases, tool/UI assertions, rubrics, the judge panel and the pre-merge gate.
144
147
  - [Refinement](docs/REFINEMENT.md) — read an agent's own traffic back as a ranked report of what broke.
145
148
  - [Outcomes and follow-ups](docs/OUTCOMES.md) — what the traffic was worth in business terms, and the tool that comes back on a promise.
146
149
  - [Knowledge](docs/KNOWLEDGE.md) — extract durable concepts from finished conversations into a per-agent knowledge base; provenance-stamped, PII-redacted, best-effort with a re-scan recovery path.
@@ -176,6 +179,7 @@ and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Vulnerabilities go through
176
179
 
177
180
  ## Status
178
181
 
179
- Pre-1.0 — published on [RubyGems](https://rubygems.org/gems/insika); APIs may
180
- still change between minor versions ([CHANGELOG.md](CHANGELOG.md)). Licensed
182
+ Published on [RubyGems](https://rubygems.org/gems/insika) and follows
183
+ [Semantic Versioning](https://semver.org/) from 1.0.0: a breaking change only lands in
184
+ a new major version ([CHANGELOG.md](CHANGELOG.md)). Licensed
181
185
  **MIT** ([LICENSE](LICENSE)).
data/bin/insika CHANGED
@@ -390,7 +390,7 @@ def evals_simulate(argv)
390
390
  # paired comparison, which it silently invalidates.
391
391
  require "securerandom"
392
392
  conv = opts[:conv] || "sim-#{golden.id}-#{SecureRandom.hex(4)}"
393
- run = simulator.run(persona: golden.persona, agent: target_agent, conv: conv)
393
+ run = simulator.run(persona: golden.persona, agent: target_agent, conv: conv, state: golden.state)
394
394
 
395
395
  verdict = judge && judge.score_conversation(
396
396
  rubric: golden.rubric, transcript: run.transcript, policy: golden.policy,
@@ -505,6 +505,9 @@ def local_side_effect_tools(agent)
505
505
  profile = Insika::StoredProfileSource.new(config_store: config_store).fetch(agent)
506
506
  return nil if profile.nil?
507
507
 
508
+ # Kits add reachable tools at turn time; the swap list must count them too.
509
+ profile = Insika::Kits.apply(profile, Insika::SettingsStore.new(config_store: config_store).kits)
510
+
508
511
  registry = Insika::OverlayToolRegistry.new(
509
512
  base: Insika::ToolRegistry.new, tool_store: Insika::ToolStore.new(config_store: config_store),
510
513
  http: Insika::HttpClient.new
data/bin/insika-router CHANGED
@@ -34,7 +34,6 @@ module Insika
34
34
  module_function
35
35
 
36
36
  def main
37
- Insika::EnvSchema.reconcile_legacy!
38
37
  pool = build_pool
39
38
  app = Insika::Router::App.new(
40
39
  pool: pool,