samagotchi 0.93.0 → 0.95.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -1
  3. data/README.md +8 -8
  4. data/bin/chi +6 -2
  5. data/docs/architecture.md +4 -5
  6. data/docs/cli.md +4 -4
  7. data/docs/configuration.md +49 -86
  8. data/docs/hooks.md +2 -2
  9. data/docs/internals/bundles.md +1 -1
  10. data/docs/internals/context-telemetry.md +1 -1
  11. data/docs/internals/engine.md +7 -4
  12. data/docs/memory.md +26 -1
  13. data/docs/plugins.md +37 -0
  14. data/docs/releasing.md +2 -2
  15. data/docs/sessions.md +1 -1
  16. data/docs/testing.md +16 -11
  17. data/lib/samagotchi/bootstrap/config_writer.rb +1 -5
  18. data/lib/samagotchi/bootstrap_command.rb +1 -0
  19. data/lib/samagotchi/bundle_command/try/sandbox.rb +8 -2
  20. data/lib/samagotchi/bundle_command.rb +1 -0
  21. data/lib/samagotchi/bundles/dev/manifest.yml +2 -1
  22. data/lib/samagotchi/bundles/model-notes/manifest.yml +11 -0
  23. data/lib/samagotchi/bundles/model-notes/model_notes_deepseek.md +7 -0
  24. data/lib/samagotchi/bundles/model-notes/notes/README.md +37 -0
  25. data/lib/samagotchi/bundles/system/config_modification_protocol.md +6 -7
  26. data/lib/samagotchi/bundles/system/manifest.yml +3 -3
  27. data/lib/samagotchi/bundles/system/self_map.md +1 -1
  28. data/lib/samagotchi/client.rb +59 -196
  29. data/lib/samagotchi/config.rb +74 -15
  30. data/lib/samagotchi/engine.rb +7 -7
  31. data/lib/samagotchi/host_config.rb +20 -27
  32. data/lib/samagotchi/host_registry.rb +8 -8
  33. data/lib/samagotchi/kernel_loop.rb +46 -8
  34. data/lib/samagotchi/memory_bundle/profile.rb +22 -4
  35. data/lib/samagotchi/memory_bundle/shipped_update.rb +5 -1
  36. data/lib/samagotchi/model_profile.rb +2 -3
  37. data/lib/samagotchi/self_report.rb +0 -2
  38. data/lib/samagotchi/system_prompt.rb +7 -21
  39. data/lib/samagotchi/terminal_ui/thinking_line.rb +2 -4
  40. data/lib/samagotchi/testing/sandbox.rb +26 -0
  41. data/lib/samagotchi/thinking.rb +35 -2
  42. data/lib/samagotchi/thinking_notices.rb +11 -4
  43. data/lib/samagotchi/update_command.rb +1 -1
  44. data/lib/samagotchi/version.rb +1 -1
  45. data/lib/samagotchi/vision_support.rb +0 -3
  46. data/lib/samagotchi/web/public/app.js +15 -82
  47. data/lib/samagotchi/web/public/dock_reserve.js +103 -0
  48. data/lib/samagotchi/web/public/index.html +3 -3
  49. data/lib/samagotchi/web/public/toast_place.js +1 -1
  50. metadata +5 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fb0f158cad212e0caef1636e67b16290dd85d750a906a04e409adf9c29511ea
4
- data.tar.gz: e1ff65cd0228751f4adcd8601492a952070cc59d415d324e7908fdd3f998e61e
3
+ metadata.gz: a359a1fc0fd6f83c6676d21b651513596e6618652aa996087087fb4bdb432d03
4
+ data.tar.gz: 96a3421ca2dee43940f7591e32dd76764090b6ae1791cd5e91c13e6be575339a
5
5
  SHA512:
6
- metadata.gz: b58b31c103e24a12b880dbeeae67be626b85b8478c87a19ba9e36440d10e07b34b3f4d615d5f3fceb5518a76172643736efc66263646cc0f75c919186b597bda
7
- data.tar.gz: 05e2fc82913cafd6bc7a80fb0bc625b8f235b9008a78955b146a857e8f2b6c9e9b7c6c5a5717f31c2df32f14b17e4bc98781e68f8d160b95a657c1071dd85484
6
+ metadata.gz: 57f03d06345f6e2cd7f74411a6eca333cb08352eb1a2e48a39dfafe5ce5b7977b88d8b7fa327056f5aa6fc448b10ac7030661d149d61ce0823d66a104d5212fd
7
+ data.tar.gz: 2d0dae400a20ae0b023ccd613cb6dc871e34e86de7a6c3605d22eb21d5f1babbd3dc94d7f47a54ff31afcf36da4f71c9c667f80e5c6c90bb16e0a41c92892615
data/CHANGELOG.md CHANGED
@@ -8,6 +8,63 @@ and commands may change between minor versions. How releases are made:
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.95.0] - 2026-10-21
12
+
13
+ ### Removed
14
+
15
+ - chi's own `mlx` and `omlx` transports (`api:` / `transport:` on a host, `server.transport`,
16
+ `SAMAGOTCHI_SERVER_TRANSPORT`): mlx_lm.server and oMLX are chat hosts now, `url: http://HOST:PORT/v1, api: openai`
17
+ (on oMLX the chat endpoint matched or beat the native one, tool calls intact). llama.cpp is the only raw-prompt
18
+ server. A config that still names `mlx` or `omlx` stops chi at start with one line: `Error: config.yml
19
+ hosts.mac.api: omlx was removed; for mlx_lm.server or oMLX use url: http://HOST:PORT/v1, api: openai in a hosts:
20
+ entry`. Name the model as the server's `/v1/models` lists it (oMLX's prefixed `mlx-community--…` id); the short
21
+ selector oMLX's transport used to resolve now 404s. See
22
+ [docs/configuration.md](docs/configuration.md#model-server-api).
23
+ - The transport setting: `server.transport`, a host's `transport:`, `SAMAGOTCHI_SERVER_TRANSPORT` and
24
+ `--server-transport` (llama.cpp is the one raw-prompt server, and a host without `api:` talks it, as
25
+ `api: llama_cpp`). A config or environment still setting one to `llama_cpp` warns at start and runs on:
26
+ `Warning: config: 'server.transport' was removed: llama.cpp is chi's only raw-prompt transport (a hosts entry
27
+ without api: is api: llama_cpp); remove it`; `mlx` or `omlx` stops chi as above. The flag is an invalid option.
28
+ - The Qwen turn preamble: a native `qwen36` prompt no longer asks the model to open its thinking with a `TURN:` line,
29
+ and the `thinking.turn_preamble` setting goes with it (`--no-thinking-turn-preamble`,
30
+ `SAMAGOTCHI_THINKING_TURN_PREAMBLE`). A config.yml that still sets it gets `Warning: config: unknown key
31
+ 'thinking.turn_preamble'` at start and runs on; the flag is an invalid option.
32
+
33
+ ### Fixed
34
+
35
+ - Native Qwen3.6 on llama.cpp (`api: llama_cpp`, profile `qwen36`) thinks again: where the server's chat template
36
+ opens a thought after the assistant cue (Qwen3.5 and later, read from the model's `/props`), chi's prompt ends with
37
+ `<think>` and a newline as the template's does, at every level but `off`; before, the model wrote an empty thought
38
+ and answered at once. Its reasoning streams as thinking and stays out of the answer. Turns take longer; `thinking:
39
+ off` answers at once as before. An older Qwen3 or other template, or no template in `/props`, keeps the old prompt.
40
+ `low`, `medium` and `high` think the same there, which the notice now says. A tool call the model writes inside a
41
+ closed thought no longer runs. See [docs/configuration.md](docs/configuration.md#thinking).
42
+ - `chi bundle try` with a config chi stops at (e.g. a removed `api: omlx`) fails the install with that one line, not a
43
+ backtrace.
44
+
45
+ Update with `chi update` (the system bundle 0.95.0), then restart `chi web`.
46
+
47
+ ## [0.94.0] - 2026-10-20
48
+
49
+ ### Added
50
+
51
+ - Bundle test kit: `sandbox.model_notes_for(model_id, small:)` lists the model notes chi would load for a model id
52
+ (from the sandbox's memories, matched as chi matches them), and `sandbox.model_note_limits` the sizes chi warns
53
+ over, so a bundle that ships model notes can test which models its `models:` globs catch.
54
+ - The `model-notes` bundle (0.1.0, in the `dev` profile, now 0.7.0): reviewed model notes, for now
55
+ `model_notes_deepseek` for DeepSeek V4 / V4.1 (`models: *deepseek-v4*`). A same-name note you already have is
56
+ skipped and keeps loading; to take the bundle's, remove yours and install again. See
57
+ [docs/plugins.md](docs/plugins.md#the-model-notes-bundle).
58
+
59
+ ### Changed
60
+
61
+ - A profile's install (`chi bundle install|upgrade core|dev`, `chi update`, `chi bootstrap`) names each memory file
62
+ of a member it installs that you already had, which it leaves as yours: `model-notes: kept your own
63
+ model_notes_deepseek.md (not the bundle's; to take the bundle's, remove yours with memory_write remove: true, then
64
+ chi bundle install model-notes)`. Before, only `chi bundle install <member>` said so.
65
+
66
+ Update with `chi update` (the system bundle 0.94.0, dev 0.7.0 with the new model-notes 0.1.0), then restart `chi web`.
67
+
11
68
  ## [0.93.0] - 2026-10-20
12
69
 
13
70
  ### Changed
@@ -3634,7 +3691,9 @@ and long-lived sessions.
3634
3691
  - A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
3635
3692
  hotkey panel that send selected text or the clipboard to your sessions.
3636
3693
 
3637
- [Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.93.0...HEAD
3694
+ [Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.95.0...HEAD
3695
+ [0.95.0]: https://github.com/dm1try/samagotchi/compare/v0.94.0...v0.95.0
3696
+ [0.94.0]: https://github.com/dm1try/samagotchi/compare/v0.93.0...v0.94.0
3638
3697
  [0.93.0]: https://github.com/dm1try/samagotchi/compare/v0.92.0...v0.93.0
3639
3698
  [0.92.0]: https://github.com/dm1try/samagotchi/compare/v0.91.0...v0.92.0
3640
3699
  [0.91.0]: https://github.com/dm1try/samagotchi/compare/v0.90.0...v0.91.0
data/README.md CHANGED
@@ -19,11 +19,11 @@ command.
19
19
  its own API (the native path, and the default)
20
20
 
21
21
  Tested: llama.cpp native (Qwen, Gemma 4), [Splash](https://github.com/incoai/splash)
22
- over the OpenAI API, and [OpenRouter](https://openrouter.ai) (remote, OpenAI API
23
- with `api_key_env`). vLLM, LM Studio, Ollama, mlx-lm, oMLX and other
24
- OpenAI-compatible servers should work over the OpenAI API but are not tested;
25
- mlx-lm and oMLX also have native transports, see
26
- [Configuration](docs/configuration.md#model-server-transport).
22
+ and [oMLX](https://github.com/jundot/omlx) over the OpenAI API, and
23
+ [OpenRouter](https://openrouter.ai) (remote, OpenAI API with `api_key_env`).
24
+ vLLM, LM Studio, Ollama, mlx-lm and other OpenAI-compatible servers should work
25
+ over the OpenAI API but are not tested; see
26
+ [Configuration](docs/configuration.md#model-server-api).
27
27
 
28
28
  ## Install
29
29
 
@@ -80,7 +80,7 @@ the config. With a config already there, it adds a `hosts:` entry and keeps
80
80
  the rest of the file. Then it installs the `core` bundles (loop-guard,
81
81
  check-in, guardrails, slow-commands, agents-md, cost-cap: the safety set for a
82
82
  small local model, the cost cap inert until you set one) and, on a terminal, offers `dev` (known-names, mcp, btw, skills,
83
- source-links, github-pr, coordinator, claude-peer, codex-peer, ruby; see
83
+ source-links, github-pr, coordinator, claude-peer, codex-peer, ruby, model-notes; see
84
84
  [Bundle profiles](docs/memory.md#bundle-profiles-core-and-dev)). Edit the
85
85
  file later as in [Configure](#configure); `chi bootstrap --help` has the
86
86
  options.
@@ -110,7 +110,7 @@ hosts:
110
110
  api: openai
111
111
  ```
112
112
 
113
- `chi self` shows the model and host chi will use. Other settings (multiple hosts, transports, timeouts, the idle recap) are in
113
+ `chi self` shows the model and host chi will use. Other settings (multiple hosts, model server APIs, timeouts, the idle recap) are in
114
114
  [Configuration](docs/configuration.md).
115
115
 
116
116
  ## Use
@@ -207,7 +207,7 @@ once, for the session, for the repo, or for the whole rule in the repo.
207
207
  - [Releasing](docs/releasing.md): versions, the changelog, how a release is published
208
208
 
209
209
  - [CLI and REPL](docs/cli.md): flags, sharing a session, web UI, `/model`, status line
210
- - [Configuration](docs/configuration.md): `config.yml`, hosts, model server transports, timeouts, retries, logs
210
+ - [Configuration](docs/configuration.md): `config.yml`, hosts, model server APIs, timeouts, retries, logs
211
211
  - [Memory](docs/memory.md): scopes, model-specific overlays and model notes
212
212
  - [Sessions](docs/sessions.md): storage, retention, `chi sessions`
213
213
  - [Attached context](docs/context.md): `chi context`, sources, scopes, recipes (a file, a note, a stream), waking, the github-pr bundle, safety
data/bin/chi CHANGED
@@ -11,7 +11,12 @@ Samagotchi::Utf8Default.apply!
11
11
  require "optparse"
12
12
  require "samagotchi/config"
13
13
 
14
- Samagotchi::ConfigFile.load!
14
+ begin
15
+ Samagotchi::ConfigFile.load!
16
+ rescue Samagotchi::ConfigFile::RemovedApi => e
17
+ warn "Error: #{e.message}"
18
+ exit 1
19
+ end
15
20
  require "samagotchi"
16
21
 
17
22
  # `chi self`: print version, source dir, config/memory/session paths, model and
@@ -173,7 +178,6 @@ parser = OptionParser.new do |opts|
173
178
  desc += " (#{entry.enum_values.join("|")})" if entry.type == :enum
174
179
  desc += " (#{value_hints[entry.key]})" if value_hints.key?(entry.key)
175
180
  desc += "; only without a hosts: config" if %w[server.host server.port].include?(entry.key)
176
- desc += "; hosts: entries without a transport use it" if entry.key == "server.transport"
177
181
  if entry.type == :enum
178
182
  opts.on("#{entry.cli_flag} VALUE", entry.enum_values, desc) { |v| cli_overrides[entry.key] = v }
179
183
  else
data/docs/architecture.md CHANGED
@@ -489,7 +489,7 @@ on every read, never kept, since config.yml and a model listing can move it with
489
489
 
490
490
  | Loop | Class | Host | Talks through |
491
491
  |---|---|---|---|
492
- | Raw prompt | `KernelLoop`, wrapped by `LLM::NativeBackend` | no `api:`, or `llama_cpp`/`mlx`/`omlx` | `Client` (`/completion` or `/v1/completions`), chi's own Gemma/Qwen prompt and tool-call parsing |
492
+ | Raw prompt | `KernelLoop`, wrapped by `LLM::NativeBackend` | no `api:`, or `llama_cpp` | `Client` (llama.cpp `/completion`), chi's own Gemma/Qwen prompt and tool-call parsing |
493
493
  | Chat | `LLM::ChatLoop` | `api: openai` | `LLM::OpenAIChat` (`/v1/chat/completions`, streamed, native tool calls) |
494
494
  | Chat | `LLM::ChatLoop` | `api: anthropic` | `LLM::AnthropicMessages` (`/v1/messages`, streamed SSE, native `tool_use`) |
495
495
 
@@ -503,7 +503,7 @@ hooks and tools whichever model made it. Both loops' `generation_chunk` carries
503
503
  clients: `text`, `thinking`, `tool_call` and chi's `counts`, no `payload` or `content`; see the
504
504
  Bridge's stream above): the chat loop's thinking is the
505
505
  server's `reasoning_content`; the raw-prompt loop splits each generation's
506
- stream with a fresh `ThoughtStreamSplitter` (Qwen's `<think>` and Gemma's
506
+ stream with a fresh `ThoughtStreamSplitter`, seeded with the prompt's prefill (Qwen's `<think>` and Gemma's
507
507
  `<|channel>thought … <channel|>` are thinking, tool-call bodies are dropped
508
508
  from `text:`). The chat loop's model turns keep their `tool_calls` and tool results their `tool_call_id`,
509
509
  so later requests and resumed sessions pair them, and their reasoning (`thinking:`), which goes back as
@@ -521,10 +521,9 @@ as an empty answer and asks again.
521
521
  Both loops keep one `EmptyAnswerRetry` per turn (the `retry.empty_answer`
522
522
  budget, the hidden nudge, the retry's sampling), and both end each
523
523
  generation's `:generation_completed` with a `finish_reason`: the chat host's
524
- own, or for the raw-prompt loop what `Client::Transport#finish_reason_from`
524
+ own, or for the raw-prompt loop what `Client.finish_reason_from`
525
525
  reads from the stream's last payload (llama.cpp `/completion`'s `stop_type`:
526
- `limit` is `length`, `eos` and a stop word are `stop`; `/v1/completions` sends
527
- its own). An empty answer with a `length` stop and the context 90 % full or
526
+ `limit` is `length`, `eos` and a stop word are `stop`). An empty answer with a `length` stop and the context 90 % full or
528
527
  more is not asked again (a full window, not a thinking loop); with no finish
529
528
  reason it is. Both also keep one `ContextStatus` per turn: before each request
530
529
  it estimates how full the window is (the server's last count plus what the turn
data/docs/cli.md CHANGED
@@ -85,7 +85,7 @@ chi bootstrap # try localhost 8080, 11434, 1234, 8000
85
85
  - **The bundles.** Unless writing the config failed, it installs the system
86
86
  bundle and the `core` profile (loop-guard, check-in, guardrails, slow-commands, agents-md, cost-cap), one line
87
87
  each; on a terminal it then asks `Also install dev (known-names, mcp, btw,
88
- skills, source-links, github-pr, coordinator, claude-peer, codex-peer, ruby)? [y/N]`. Run again, it installs nothing new: a bundle
88
+ skills, source-links, github-pr, coordinator, claude-peer, codex-peer, ruby, model-notes)? [y/N]`. Run again, it installs nothing new: a bundle
89
89
  you uninstalled stays out ([Bundle profiles](memory.md#bundle-profiles-core-and-dev)).
90
90
  A bundle that fails to install makes the exit 1. `--dry-run` says what it
91
91
  would install.
@@ -812,7 +812,7 @@ like `[image shot.png 1280×800 not sent: an older image (chi sends up to the
812
812
  newest 20)]`.
813
813
 
814
814
  A model that can't see images (a text-only model, llama.cpp without
815
- `--mmproj`, an mlx host) refuses a turn with images before sending it:
815
+ `--mmproj`) refuses a turn with images before sending it:
816
816
  `host main can't take images: …; send text only, or pick a model that can see
817
817
  images (/model)`, and the typed text (and the web's chips) come back. When chi
818
818
  can't tell beforehand, the provider's refusal gives the same line. Images already
@@ -1175,8 +1175,8 @@ While a turn runs, one row above the prompt says what it is doing, the spinner f
1175
1175
  - `| thinking…` while the model starts, then `| thinking · <sentence>`: the newest complete
1176
1176
  sentence of its thinking, or of its answer (`writing ·`), like the web's thinking ticker: the
1177
1177
  same sentence rules (a list number such as `118.` is no sentence end; a newline is one), and the
1178
- row changes at most once every 1.5 s so it doesn't flicker. A long sentence is cut with `…`; a
1179
- Qwen `TURN:` prefix and inline markdown are left out.
1178
+ row changes at most once every 1.5 s so it doesn't flicker. A long sentence is cut with `…`, and
1179
+ inline markdown is left out.
1180
1180
  - `| waiting for the first token… 5s` after 2 s with nothing streamed.
1181
1181
  - `| running execute…` while a tool runs (its `tool>` line prints when it ends).
1182
1182
  - `| ↻ retrying (ECONNREFUSED) in 0.5s, 1/3` while a failed request is asked again: why (the HTTP status such as
@@ -32,13 +32,12 @@ thinking:
32
32
 
33
33
  # Multi-host (optional): aggregated /models and per-model routing.
34
34
  # A bare default.model uses the default host; host:model pins to a host.
35
- # transport: on a host overrides server.transport; api: openai makes a
36
- # host use the OpenAI chat API instead of chi's raw prompt.
35
+ # A host talks llama.cpp's own API (api: llama_cpp, the default); api: openai
36
+ # makes it use the OpenAI chat API instead of chi's raw prompt.
37
37
  hosts:
38
38
  main:
39
39
  host: localhost
40
40
  port: 8080
41
- transport: llama_cpp
42
41
  small-box:
43
42
  host: 192.0.2.20
44
43
  port: 8080
@@ -142,7 +141,7 @@ or `chi web` restart.
142
141
  | `default.model` | New session | Existing sessions keep their saved model; change one with `/model`. |
143
142
  | `default.input`, `no_default_input`, `no_interrupt` | Next CLI run | These set up that run's first prompt or turn limit. |
144
143
  | `default.max_tokens`, `max_tool_output_chars`, `read.*`, `execute.*` except `execute.description`, `image.*` | Next matching request or tool use | An operation already in progress keeps its resolved limits. |
145
- | `server.host`, `server.port`, `server.transport`, `hosts.*` | Worker start | Includes host addresses, APIs, declared models and host-level settings. The web model picker refreshes `hosts:` on file change; a running worker does not. |
144
+ | `server.host`, `server.port`, `hosts.*` | Worker start | Includes host addresses, APIs, declared models and host-level settings. The web model picker refreshes `hosts:` on file change; a running worker does not. |
146
145
  | `server.open_timeout`, `server.read_timeout`, `server.first_token_timeout` | Worker start | The worker's clients retain the timeouts set when they were built. |
147
146
  | `model_aliases` | Next model lookup | A session keeps its resolved model unless it is explicitly switched. |
148
147
  | `models.<key>.profile` | Session start or `/model` | It is resolved when that model is selected; editing it does not switch the current model's profile by itself. |
@@ -156,7 +155,7 @@ or `chi web` restart.
156
155
  | `append_system_prompt` | Worker start for the file list | The config list is not saved in the session file. File text is read when the prompt is built; `/model` rebuilds it, while an already-built prompt is cached. CLI `--append-system-prompt` files are saved in the session. |
157
156
  | `toolkit.default`, `toolkit.child` | Session creation | The chosen toolkit is saved; changing the defaults does not move existing sessions. |
158
157
  | `toolkit.kits`, `execute.description`, `llm_context.policy` | Worker start | These are held by the engine's toolkit or tool registry. |
159
- | `thinking.turn_preamble`, `skip_agents_md` | Prompt rebuild | A running engine caches its built prompt; a new worker or `/model` rebuild uses the changed value. |
158
+ | `skip_agents_md` | Prompt rebuild | A running engine caches its built prompt; a new worker or `/model` rebuild uses the changed value. |
160
159
  | `context.*` except `context.every_seconds`, `llm_context.*` except `llm_context.policy`, `steer.cut_after`, `memory.index_warn_tokens`, `status.line` | Next matching turn, display, poll or write | Readers resolve these settings when they perform that operation. Session-specific LLM context and thinking values remain saved in the session. |
161
160
  | `context.every_seconds` | Next context poll | The poller checks it for each source that has no explicit interval. |
162
161
  | `guardrails.*` | Next tool call or approval | Guardrail rules and disable lists are reloaded when the config file changes; rule settings take effect on that evaluation. `guardrails.parent_answers` is checked when a parent answers a question. |
@@ -188,64 +187,40 @@ An environment name used as a top-level key (`SAMAGOTCHI_DEFAULT_MODEL: my-model
188
187
  the old flat form) is not read: it warns as an unknown key with the nested one
189
188
  to use (`did you mean 'default.model'?`).
190
189
 
191
- ## Model Server Transport
190
+ ## Model Server API
192
191
 
193
- Chi talks to a model server over HTTP and supports three transports:
192
+ Chi talks to a model server over HTTP in one of two ways, set by the host's `api:`:
194
193
 
195
- - `llama_cpp` (default): llama.cpp's native `/completion` and `/models` endpoints.
196
- - `mlx`: [mlx-lm](https://github.com/ml-explore/mlx-lm)'s OpenAI-compatible
197
- `/v1/completions` and `/v1/models` endpoints (Apple Silicon-native models).
198
- - `omlx`: [oMLX](https://github.com/jundot/omlx) (the mlx-lm successor —
199
- continuous batching + tiered SSD KV cache) using the same `/v1/completions`
200
- and `/v1/models` endpoints as `mlx`.
194
+ - `llama_cpp` (the default): chi's own raw-prompt loop on llama.cpp's native `/completion`,
195
+ `/models` and `/props` endpoints;
196
+ - `openai`: the OpenAI chat API at `http://HOST:PORT/v1`, or at `url:` (see below);
197
+ - `anthropic`: the Messages API, see [Anthropic Messages hosts](#anthropic-messages-hosts).
201
198
 
202
- > **mlx and oMLX** are not verified with recent chi versions; llama.cpp and
203
- > OpenAI-compatible hosts (`api: openai`) are the tested paths.
204
-
205
- Select the transport with `server.transport` (`llama_cpp`, `mlx`, or `omlx`;
206
- env `SAMAGOTCHI_SERVER_TRANSPORT`). `server.host`/`server.port` are reused for all three —
207
- only the request/response shape differs. oMLX's default server port is `8000` (not
208
- `8080`), so point `server.port` at it. With `hosts:` each entry may set `transport: llama_cpp|mlx|omlx` to override the
209
- global transport per host (`lib/samagotchi/host_registry.rb`).
210
-
211
- Each host may also set `api:`, which says how chi talks to it:
212
-
213
- - `llama_cpp`, `mlx` or `omlx`: chi's own raw-prompt loop (the value is also the
214
- host's transport, so don't set a different `transport:` next to it);
215
- - `openai`: the OpenAI chat API at `http://HOST:PORT/v1`, or at `url:` (see below).
216
-
217
- Without `api:` a host uses the raw-prompt loop, as before. The loop follows the
199
+ Without `api:` a host (and the `server.host`/`server.port` one when there is no `hosts:` map)
200
+ uses the raw-prompt loop. There is no transport setting: `server.transport`, a host's
201
+ `transport:` and `SAMAGOTCHI_SERVER_TRANSPORT` were removed with the `mlx` and `omlx`
202
+ transports. Still set to `llama_cpp`, each warns at start and changes nothing (remove it);
203
+ set to `mlx` or `omlx`, chi stops with the line below. The loop follows the
218
204
  model's host, so `/model other-host:model` can move a session between the two.
219
205
  Workers started by plain `chi`, `chi web` or `--attach` get the same hosts, `api:` included.
220
206
 
221
- Example for mlx-lm (not verified with recent chi versions, like oMLX below):
222
-
223
- ```yaml
224
- server:
225
- transport: mlx
226
- host: 127.0.0.1
227
- port: 8080
228
- ```
229
-
230
- ```shell
231
- mlx_lm.server --model mlx-community/Qwen3-14B-Instruct-4bit
232
- ```
233
-
234
- Example for oMLX:
207
+ **mlx-lm and oMLX** ([mlx-lm](https://github.com/ml-explore/mlx-lm)'s `mlx_lm.server`,
208
+ [oMLX](https://github.com/jundot/omlx)) are chat hosts: give them `api: openai` with their `/v1` url.
209
+ chi's own `mlx` and `omlx` transports were removed (their chat endpoint matched or beat them); a config
210
+ still naming `api:`/`transport:` `mlx` or `omlx` stops chi at start with one line saying what to write.
211
+ oMLX's default port is `8000`; an oMLX started with an API key needs `api_key_env:`:
235
212
 
236
213
  ```yaml
237
- server:
238
- transport: omlx
239
- host: 192.0.2.10
240
- port: 8000
214
+ hosts:
215
+ omlx:
216
+ url: http://192.0.2.10:8000/v1
217
+ api: openai
218
+ api_key_env: OMLX_API_KEY
241
219
  ```
242
220
 
243
- Both the `mlx` and `omlx` transports still send chi's own raw formatted prompt
244
- (via `/v1/completions`) rather than a `messages` array, so the existing
245
- per-model prompt/tool-call formatting is unaffected — neither server reapplies its
246
- own chat template on this endpoint. Only the Gemma4 (`<|tool_call>…`) and Qwen3.6
247
- (`[[…]]`/`<|tool_call>`) tool-call formats are in scope; GLM/Mistral/Kimi/MiniMax
248
- formats are not parsed.
221
+ Name the model exactly as the server's `/v1/models` lists it (oMLX: e.g. `mlx-community--Qwen3.6-35B-A3B-4bit`;
222
+ a short name 404s): `chi models` and the `/model` picker show them. Tool calls come back as the chat API's own
223
+ `tool_calls`, and the model's reasoning as thinking.
249
224
 
250
225
  For an OpenAI Chat Completions server such as [Splash](https://github.com/incoai/splash)
251
226
  (a fast inference engine for Macs that works well for a local setup alongside
@@ -339,8 +314,7 @@ expose the OpenAI-compatible chat endpoint. In verbose mode (`-v`), chi prints t
339
314
  starting model uses (`[verbose] backend=chat` or `backend=native`); request
340
315
  bodies are not logged. The interactive REPL, `--prompt`,
341
316
  workers, and resumed sessions all use the loop of the model's host. Hosts without
342
- `api: openai` keep using the native `/completion`, `/v1/completions`, or oMLX
343
- transport path.
317
+ a chat `api:` keep using llama.cpp's native `/completion`.
344
318
 
345
319
  ### API keys from the Keychain
346
320
 
@@ -470,32 +444,14 @@ The same test works against a llama.cpp OpenAI-compatible server by changing
470
444
  the host, port, and model values. The test is skipped unless
471
445
  `SAMAGOTCHI_INTEGRATION=1` is set; see [Testing](testing.md).
472
446
 
473
- oMLX's known tool-call limitation (a stream filter that strips markup) only
474
- affects its `/v1/chat/completions` endpoint, not the `/v1/completions` endpoint
475
- chi uses, so raw `[[…]]`/`<|tool_call>` markers stream through untouched.
476
-
477
447
  `default.model` (config default) and `/model` (runtime effective) pick the model; the status line and `/model`
478
448
  output always render the runtime effective model (showing default when diverged). Which prompt format it gets is the
479
- prompt profile (see "Prompt profile" below). How the selector reaches the request differs by transport (mlx and oMLX: not verified with recent chi versions):
480
-
481
- - **mlx** (`mlx_lm.server`): the `model` field is omitted entirely — the server
482
- uses whatever was loaded via its own `--model` CLI flag.
483
- - **omlx**: the server *requires* a `model` field and returns `HTTP 400`
484
- (`model: Field required`) without it, so samagotchi forwards the selector
485
- resolved to the exact id listed in the server's `/v1/models` — matched by exact
486
- (case-insensitive) first, then substring, then passed through unchanged. That
487
- resolved id is usually prefixed (e.g. `mlx-community--gemma-4-e4b-it-4bit`), so a
488
- short selector such as `gemma-4-e4b-it-4bit` is what you set in
489
- `default.model`. An unknown selector passes through raw and oMLX 404s,
490
- listing its available models; if `/v1/models` is unreachable, samagotchi falls
491
- back to the raw selector and lets the server decide (its own 400/404). Either
492
- error fails the turn with the server's message (see "Server errors" below). Runtime
493
- model switch re-resolves each completion (the `/v1/models` id list is cached per
494
- client; the selector itself is re-resolved every time).
449
+ prompt profile (see "Prompt profile" below). The request's `model` field is the selector as written (host prefix
450
+ dropped).
495
451
 
496
452
  ## Prompt profile
497
453
 
498
- A native host (`llama_cpp`, `mlx`, `omlx`) gets a raw prompt in one model family's format: its turn markers, tool-call
454
+ A native host (`llama_cpp`) gets a raw prompt in one model family's format: its turn markers, tool-call
499
455
  syntax, thought tags and stop sequences. That is the prompt profile, `qwen36` or `gemma4`. A wrong one is not just
500
456
  worse output: a ChatML model under `gemma4` never hits a stop sequence, generates until its limit and then runs the
501
457
  tool calls it made up on the way. The first of these that says something wins:
@@ -517,16 +473,14 @@ tool calls it made up on the way. The first of these that says something wins:
517
473
 
518
474
  ```yaml
519
475
  hosts:
520
- mlx:
476
+ box:
521
477
  host: 192.0.2.10
522
478
  port: 8081
523
- transport: mlx
524
479
  profile: qwen36
525
480
  ```
526
481
 
527
482
  4. The server's chat template, on `llama_cpp` hosts: `/props` (asked with `?model=`, which a router needs) with
528
483
  `<|im_start|>` and `<function=` is `qwen36`, any other ChatML template too; `<|turn>` and `<|tool_call>` is `gemma4`.
529
- mlx_lm.server and oMLX publish no template, so config or the name decides there.
530
484
  5. The name: `qwen` → `qwen36`, `gemma` → `gemma4`.
531
485
  6. `qwen36`.
532
486
 
@@ -669,7 +623,7 @@ models:
669
623
 
670
624
  | Backend | A level change | Asks |
671
625
  |---|---|---|
672
- | native Qwen (`qwen36`) | only the prompt's tail (the empty thought after the cue) | no |
626
+ | native Qwen (`qwen36`) | only the prompt's tail (the thought after the cue) | no |
673
627
  | native Gemma 4 (`gemma4`) | the whole prompt is read again: `<\|think\|>` starts the system prompt | yes |
674
628
  | chat host, local (llama.cpp, Splash), a model name with `gemma` | the whole prompt: the template writes the same token | yes |
675
629
  | chat host, local, any other model | other request fields; the server keeps its cache, only the tail changes | no |
@@ -692,12 +646,24 @@ What each backend gets:
692
646
 
693
647
  | Backend | `off` | `low` / `medium` / `high` |
694
648
  |---|---|---|
695
- | native (`/completion`), `qwen36` | an empty thought after the assistant cue, and no turn preamble | no knob: thinking stays as the model has it, one notice |
649
+ | native (`/completion`), `qwen36` | an empty thought after the assistant cue | no knob: an open thought after the cue where the template has one (below), the same at each effort, one notice |
696
650
  | native, `gemma4` | no `<\|think\|>` token at the start of the system prompt | no knob, one notice |
697
651
  | chat host (`api: openai`) | `chat_template_kwargs: {enable_thinking: false}` and `reasoning_effort: "none"` | `reasoning_effort: <level>` |
698
652
  | Messages host (`api: anthropic`) | `thinking: {type: "disabled"}` | `thinking: {type: "adaptive", display: "summarized"}` and `output_config: {effort: <level>}` |
699
653
  | Messages host, `dialect: fireworks` | `thinking: {type: "disabled"}` | `thinking: {type: "adaptive"}` and `output_config: {effort: <level>}` (no `display`) |
700
654
 
655
+ Native `qwen36` at `default`, `low`, `medium` or `high` gets an open thought, `<think>` and a newline, after the
656
+ assistant cue when the llama.cpp server's chat template writes one there (Qwen3.5 and later: its generation prompt
657
+ ends `'<think>\n'` unless `enable_thinking` is false), read from the model's `/props` (`?model=`, which a llama.cpp
658
+ router answers from the model's own server): the model thinks, as the template would have it, and its reasoning shows
659
+ as thinking, not in the answer. Without it Qwen3.6 writes an empty thought at once and never thinks. A template whose
660
+ own default is no thinking (Qwen3.5's small models think only with `enable_thinking` true) gets the open thought
661
+ too: set `thinking: off` for such a model (`models:` or `hosts:`) to keep its answers immediate. A tool call written
662
+ inside a closed thought is not run. With no template
663
+ in `/props` (an older Qwen3 or other ChatML template, a router that can't load the model, a failed probe) the prompt
664
+ ends at the cue as before. `low`, `medium` and `high` think the same: native Qwen has no effort knob, and chi says
665
+ so once (`low isn't supported by native qwen36 on HOST; it thinks, with no effort control`).
666
+
701
667
  On a Messages host `default` sends nothing: the provider's own default, which differs by model (some Claude models
702
668
  think adaptively but show no thinking text, their blocks still going back; others, and Splash, don't think at all). A model that refuses `disabled` and names `between_tools` in the 400 (Claude 5.x) gets `thinking: {type:
703
669
  "between_tools"}` wherever `off` asked for `disabled`, from then on: the adapter keeps that per model for as long as it
@@ -737,8 +703,8 @@ hosts:
737
703
  sampling: { reasoning_effort: null } # sends only enable_thinking: false
738
704
  ```
739
705
 
740
- A different level changes a native model's system prompt (Gemma's token, Qwen's turn preamble), so the next turn
741
- reads the whole context again once; on a chat host only the end of the prompt changes.
706
+ A different level changes a native Gemma's system prompt (its token), so the next turn reads the whole context again
707
+ once; on native Qwen and a chat host only the end of the prompt changes.
742
708
 
743
709
  ## Reasoning history
744
710
 
@@ -1286,7 +1252,6 @@ Whether a model can see images is found out before a turn with images is sent:
1286
1252
  - a native llama.cpp host: `/props` must report `modalities.vision` (the server
1287
1253
  runs with `--mmproj`) and a media marker, and the prompt profile must know the
1288
1254
  chat template's image wrapping (qwen36 and gemma4 do);
1289
- - mlx and oMLX hosts: no (not verified with recent chi versions);
1290
1255
  - an OpenAI-API host: a local llama.cpp's `/props`, else the host's model list
1291
1256
  (OpenRouter's `architecture.input_modalities`); when it doesn't say, the image
1292
1257
  is sent and a refusal is reported.
@@ -1598,7 +1563,6 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
1598
1563
  | `default.input` | none | | Text pre-filled at the first prompt (a trailing space is kept); `--no-default-input` skips it. See [CLI](cli.md). |
1599
1564
  | `default.max_tokens` | server's | yes | Most tokens one generation may produce (`n_predict` on a native llama.cpp host; OpenRouter: 32768 when unset). |
1600
1565
  | `model.profile` | none | `--profile` | Prompt profile for every model (`qwen36`, `gemma4`); env and CLI only. See "Prompt profile". |
1601
- | `server.transport` | `llama_cpp` | yes | `llama_cpp`, `mlx` or `omlx`; see "Model Server Transport". |
1602
1566
  | `server.host` | `localhost` | yes | The model server when there is no `hosts:` map. |
1603
1567
  | `server.port` | `8080` | yes | Its port. |
1604
1568
  | `server.open_timeout` | `10` | yes | Connection timeout, seconds. |
@@ -1662,7 +1626,6 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
1662
1626
  | `context.peer_turns` | `3` | yes | Wake turns in a row a peer agent's answers may start (a peer bundle's outbox source, such as `codex-outbox`), with no message typed in the web or a TUI in between (`chi send` doesn't count); within `session.max_wakes`. Then answers wait as notes, and the UIs hear it once. An answer whose summary ends its verdicts with `VERDICT OK` wakes once to close the round, counted toward `session.max_wakes` only. `0`: a peer source wakes like any other. See [Waking](context.md#waking). |
1663
1627
  | `toolkit.default` | `full` | | The toolkit a new session is stored on: the tools its prompts declare (`full`, `lean`, `child`, one of `toolkit.kits` or a bundle's). `chi --toolkit` picks one per session. See "Toolkits". |
1664
1628
  | `toolkit.child` | `full` | | A delegate child's toolkit, unless its `delegate` call names one (`toolkit:`). See "Toolkits". |
1665
- | `thinking.turn_preamble` | `true` | yes | Ask a `qwen36` model to open its thinking with a short `TURN:` line (the step label). |
1666
1629
  | `reasoning_history` | `turn` | | Which of its reasoning a chat host's model gets back: `drop`, `turn`, `all`; environment only (`SAMAGOTCHI_REASONING_HISTORY`), below a session's own level (`/reasoning-history`), above the `models:`/`hosts:` entries. See "Reasoning history". |
1667
1630
  | `thinking.level` | `default` | `--thinking` | `off`, `low`, `medium`, `high` or `default` for every model; the flag and env outrank the `models:`/`hosts:` entries, the file's value doesn't; a session's own level outranks them all, and `--thinking` sets it on a session run (on `chi web` it sets this). See "Thinking". |
1668
1631
  | `models.<key>.thinking`, `hosts.<name>.thinking` | none | | A model's or host's level. See "Thinking". |
data/docs/hooks.md CHANGED
@@ -178,7 +178,7 @@ are also logged (`turn` tag, `hook_notice`).
178
178
 
179
179
  `:generation_progress` sees a model response **while it streams**: the
180
180
  thinking and the visible text, on both the raw-prompt path (llama.cpp
181
- `/completion`, `/v1/completions`) and the chat path (`api: openai`). It fires
181
+ `/completion`) and the chat path (`api: openai`). It fires
182
182
  for the turn's own generations only (not a plugin's `ctx.ask_model`, not a
183
183
  recap).
184
184
 
@@ -608,7 +608,7 @@ Notes:
608
608
  - Ordering: bundle hooks fire by `(priority, bundle_name, hook_name)` (lower priority first), then plain `config.yml` hooks in registration order.
609
609
  - Settings: a hook class with `initialize(settings = {})` gets the bundle's section of `config.yml` `bundles:` (see [Settings](#settings)).
610
610
  - A bundle can also ship a `plugin.rb` whose `chi.on(event)` blocks are bundle hooks too, next to commands and tools; see [Plugins](plugins.md). There `ctx.notify`, `ctx.steer` and the other `ctx` helpers act as this page's `event[:notify]`… do for the event the block runs for.
611
- - Shipped bundles (each in a profile: `core` or `dev`, see [Bundle profiles](memory.md#bundle-profiles-core-and-dev)): `chi bundle install guardrails` (rules, see [Guardrails](guardrails.md#the-guardrails-bundle)) and `chi bundle install known-names` (a hook, see [Guardrails](guardrails.md#the-known-names-bundle)), `chi bundle install source-links` (a hook: announces source refs, see [The source-links bundle](#the-source-links-bundle)), `chi bundle install btw` (a plugin: `/btw`, see [Plugins](plugins.md#the-btw-bundle)), `chi bundle install mcp` (a plugin: tools from MCP servers, see [Plugins](plugins.md#the-mcp-bundle)) `chi bundle install loop-guard` (a plugin: breaks tool-call loops, see [Plugins](plugins.md#the-loop-guard-bundle)), `chi bundle install check-in` (a plugin: checks on a long turn, see [Plugins](plugins.md#the-check-in-bundle)), `chi bundle install slow-commands` (a plugin: commands that ran past the execute limit are run as tasks next time, see [Plugins](plugins.md#the-slow-commands-bundle)), `chi bundle install agents-md` (a plugin: a nested AGENTS.md is steered into the conversation on the first touch under its directory, see [Plugins](plugins.md#the-agents-md-bundle)), `chi bundle install cost-cap` (a plugin: a per-session $ cap, `/cap`, see [Plugins](plugins.md#the-cost-cap-bundle)), `chi bundle install ruby` (a plugin: an RSpec run with no examples at all, a hint, see [Plugins](plugins.md#the-ruby-bundle)) `chi bundle install skills` (a plugin: `/skill`, versions of skills, see [Plugins](plugins.md#the-skills-bundle)), `chi bundle install github-pr` (attached context: the branch's open PR, see [Plugins](plugins.md#the-github-pr-bundle)), `chi bundle install coordinator` (a plugin: parallel work in worktrees and child sessions, see [Plugins](plugins.md#the-coordinator-bundle)) and `chi bundle install claude-peer` / `codex-peer` (a plugin: talk to a Claude Code or Codex session, see [Plugins](plugins.md#the-claude-peer-bundle)).
611
+ - Shipped bundles (each in a profile: `core` or `dev`, see [Bundle profiles](memory.md#bundle-profiles-core-and-dev)): `chi bundle install guardrails` (rules, see [Guardrails](guardrails.md#the-guardrails-bundle)) and `chi bundle install known-names` (a hook, see [Guardrails](guardrails.md#the-known-names-bundle)), `chi bundle install source-links` (a hook: announces source refs, see [The source-links bundle](#the-source-links-bundle)), `chi bundle install btw` (a plugin: `/btw`, see [Plugins](plugins.md#the-btw-bundle)), `chi bundle install mcp` (a plugin: tools from MCP servers, see [Plugins](plugins.md#the-mcp-bundle)) `chi bundle install loop-guard` (a plugin: breaks tool-call loops, see [Plugins](plugins.md#the-loop-guard-bundle)), `chi bundle install check-in` (a plugin: checks on a long turn, see [Plugins](plugins.md#the-check-in-bundle)), `chi bundle install slow-commands` (a plugin: commands that ran past the execute limit are run as tasks next time, see [Plugins](plugins.md#the-slow-commands-bundle)), `chi bundle install agents-md` (a plugin: a nested AGENTS.md is steered into the conversation on the first touch under its directory, see [Plugins](plugins.md#the-agents-md-bundle)), `chi bundle install cost-cap` (a plugin: a per-session $ cap, `/cap`, see [Plugins](plugins.md#the-cost-cap-bundle)), `chi bundle install ruby` (a plugin: an RSpec run with no examples at all, a hint, see [Plugins](plugins.md#the-ruby-bundle)) `chi bundle install skills` (a plugin: `/skill`, versions of skills, see [Plugins](plugins.md#the-skills-bundle)), `chi bundle install github-pr` (attached context: the branch's open PR, see [Plugins](plugins.md#the-github-pr-bundle)), `chi bundle install coordinator` (a plugin: parallel work in worktrees and child sessions, see [Plugins](plugins.md#the-coordinator-bundle)), `chi bundle install claude-peer` / `codex-peer` (a plugin: talk to a Claude Code or Codex session, see [Plugins](plugins.md#the-claude-peer-bundle)) and `chi bundle install model-notes` (memories: reviewed model notes, see [Plugins](plugins.md#the-model-notes-bundle)).
612
612
  - Installing a bundle executes its hook code at `Engine` startup. Only install bundles you trust, as you would a gem. Hooks are **not** executed at install time (copy-only); they are `module_eval`'d at `Engine.new` inside per-bundle `Samagotchi::Bundles::<name>` namespaces (no top-level `require` collisions). Keep hook files side-effect-free at load time; do work in `#call` — top-level side effects (require, IO, `at_exit`, global assignment) run once per `Engine.new` (class redefinition is idempotent).
613
613
 
614
614
  Lifecycle:
@@ -39,7 +39,7 @@ user-facing side (what a bundle owns, profiles, needs) is in [memory.md](../memo
39
39
  | `Provenance` | the `.bundles/<name>/` dir: `#write` the record + bases, `#record` → `InstalledBundle`, `.each_installed`, `.claimants` (which bundles own a file) |
40
40
  | `InstalledBundle`, `BundleHook`, `PluginRef` | value objects for the record; tolerant of older records (missing keys read as empty) |
41
41
  | `Builder` | `chi bundle build`: memories (+ the installed bundle's hooks, rules, plugin, scripts) → zip/tar/dir |
42
- | `Profile` | meta bundles (`includes:`): install the members, record which |
42
+ | `Profile` | meta bundles (`includes:`): install the members, record which; `InstallResult#kept_own` names a new member's memory files the user already had (`kept_own_line`, printed by `chi bundle`, `chi update` and `chi bootstrap`) |
43
43
  | `SystemBundle`, `ShippedUpdate` | the built-in system bundle (`ensure!` at Engine start, `sync` in `chi update`) and `chi update`'s upgrade of shipped bundles; both drive the Installer with `upgrade: true` |
44
44
  | `Uninstaller`, `Trash`, `Status`, `Listing` | remove, keep removed files, `chi bundle status`, `chi bundle list` |
45
45
  | `IndexUpdater`, `IndexSync` | the managed `index.md` lines (Installer; and the write/edit tools for memories) |
@@ -115,6 +115,6 @@ Context window lookup (`ContextWindow.resolve`, the first that answers wins; the
115
115
  4. `context.window_tokens`: CLI, `SAMAGOTCHI_CONTEXT_WINDOW_TOKENS` or the config file (`:config` or `:env`).
116
116
  5. `ContextWindow::DEFAULT_TOKENS`, 256000 (`:default`).
117
117
 
118
- Settings (3 and 4) only fill in when the server and its list report nothing (mlx, oMLX, a server that is down). A
118
+ Settings (3 and 4) only fill in when the server and its list report nothing (a server that is down, a chat host whose list has no window). A
119
119
  window the stream's `usage` reports itself (`n_ctx` / `context_window`) wins over all of these for that request
120
120
  (`window_src=server`). `chi self` shows the offline answer (steps 3 to 5) and which setting gave it.
@@ -165,8 +165,7 @@ whose tools, hooks, gate and dispatch it uses.
165
165
 
166
166
  ### KernelLoop (the native, raw-prompt loop)
167
167
 
168
- Runs models whose server takes a raw prompt (llama.cpp `/completion`, or `/v1/completions` on an
169
- OpenAI-compatible completions server). chi formats the prompt itself, per model profile (Gemma 4, Qwen 3.6), and
168
+ Runs models whose server takes a raw prompt (llama.cpp `/completion`). chi formats the prompt itself, per model profile (Gemma 4, Qwen 3.6), and
170
169
  parses tool calls out of the generated text.
171
170
 
172
171
  ```
@@ -684,8 +683,12 @@ Both loops:
684
683
 
685
684
  Native loop only: the Qwen open-block recovery, and the thinking prefill (`Thinking.native`: with thinking off, Qwen
686
685
  gets an empty thought after the cue, `QWEN_EMPTY_THOUGHT`, and Gemma 4 its empty thought channel,
687
- `GEMMA_EMPTY_THOUGHT`, with no `<|think|>` token before the system prompt; kept in the model message so the next
688
- prompt starts with what the server has cached).
686
+ `GEMMA_EMPTY_THOUGHT`, with no `<|think|>` token before the system prompt; at any other level Qwen gets an open
687
+ thought, `QWEN_OPEN_THOUGHT` (`<think>\n`), when the server's chat template writes one after its cue
688
+ (`Thinking.opens_thought?` on the model's `/props`, a Qwen3.5+ template; `KernelLoop#native_prefill`, once per turn).
689
+ The prefill is kept in the model message so the next prompt starts with what the server has cached; each
690
+ generation's `ThoughtStreamSplitter` is seeded with it (an open thought's reasoning streams as `thinking:`), and the
691
+ answer is stripped from prefill + response, so the reasoning never lands in it).
689
692
 
690
693
  ## Key design principles
691
694
 
data/docs/memory.md CHANGED
@@ -106,6 +106,31 @@ Working habits for this model:
106
106
  longest run without an edit and the Continues and steers each needed; run a
107
107
  note on and muted for the same kind of task. See
108
108
  [testing.md](testing.md) ("The model notes report").
109
+ - **Shipped notes: the model-notes bundle.** `chi bundle install model-notes`
110
+ (or the `dev` profile) installs reviewed notes into the system scope; for
111
+ now `model_notes_deepseek` (`models: *deepseek-v4*`). Each note's provenance
112
+ and evidence is in the bundle's `notes/README.md`, and its spec pins which
113
+ model ids load which note ([Plugins](plugins.md#the-model-notes-bundle)).
114
+ - **Your own note of the same name wins.** The install skips a
115
+ `model_notes_<name>.md` you already have and never owns it, so your note
116
+ is what loads, the two never stack, and upgrades leave it alone.
117
+ `chi bundle install model-notes` says `Skipped model_notes_deepseek.md
118
+ (already exists; use --force to overwrite)`; through the `dev` profile
119
+ (`chi bundle install dev`, `chi bundle upgrade dev`, `chi update`) it is
120
+ `model-notes: kept your own model_notes_deepseek.md (not the bundle's; to
121
+ take the bundle's, remove yours with memory_write remove: true, then chi
122
+ bundle install model-notes)`.
123
+ - **To take the bundle's version instead,** remove your note
124
+ (`memory_write` with `remove: true` moves it to the trash) and run
125
+ `chi bundle install model-notes` again: the install writes the missing
126
+ file and owns it from then on. Don't use `--force`: it overwrites every
127
+ file of the bundle with no trash copy.
128
+ - **Other notes stack.** A note of another name for the same models
129
+ (`model_notes_my_deepseek`), or a project-scope `model_notes_deepseek`,
130
+ loads beside the bundle's (notes are told apart by their file, not their
131
+ name), and the total may pass the 3,000-character warning.
132
+ - **Your edits to an installed note** are kept by an upgrade (a 3-way
133
+ merge), or come back as a conflict.
109
134
  - Without a model note the system prompt is what it was.
110
135
 
111
136
 
@@ -323,7 +348,7 @@ profiles, meta bundles that install a set of them:
323
348
  | profile | bundles |
324
349
  |---|---|
325
350
  | `core` | loop-guard, check-in, guardrails, slow-commands, agents-md, cost-cap: the recommended safety set |
326
- | `dev` | known-names, mcp, btw, skills, source-links, github-pr, coordinator, claude-peer, codex-peer, ruby |
351
+ | `dev` | known-names, mcp, btw, skills, source-links, github-pr, coordinator, claude-peer, codex-peer, ruby, model-notes |
327
352
 
328
353
  `chi bootstrap` installs `core` and, on a terminal, offers `dev`. An existing
329
354
  install gets neither by itself: `chi bundle install core` (or `dev`).