samagotchi 0.148.0 → 0.150.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -1
- data/README.md +4 -2
- data/docs/architecture.md +3 -3
- data/docs/bundles.md +38 -1
- data/docs/cli.md +76 -24
- data/docs/configuration.md +8 -6
- data/docs/guardrails.md +2 -1
- data/docs/hooks.md +2 -1
- data/docs/internals/background-tasks.md +1 -1
- data/docs/internals/bridge.md +8 -0
- data/docs/internals/bundles.md +42 -14
- data/docs/internals/objectives.md +269 -0
- data/docs/internals/web-frontend.md +4 -1
- data/docs/internals/web-push.md +2 -2
- data/docs/internals/working-set.md +5 -2
- data/docs/memory.md +47 -9
- data/docs/plugins.md +10 -2
- data/docs/releasing.md +1 -1
- data/docs/sessions.md +45 -2
- data/docs/system-one.md +17 -1
- data/docs/testing.md +5 -0
- data/lib/samagotchi/atomic_file.rb +3 -0
- data/lib/samagotchi/bootstrap_command.rb +5 -2
- data/lib/samagotchi/bridge/card_store.rb +52 -7
- data/lib/samagotchi/bridge.rb +1 -1
- data/lib/samagotchi/bundle_command.rb +91 -68
- data/lib/samagotchi/bundler_env.rb +24 -0
- data/lib/samagotchi/bundles/coordinator/manifest.yml +6 -4
- data/lib/samagotchi/bundles/coordinator/plugin.rb +3 -2
- data/lib/samagotchi/bundles/coordinator/skill_coordinator.md +9 -0
- data/lib/samagotchi/bundles/decision-card/manifest.yml +13 -0
- data/lib/samagotchi/bundles/decision-card/plugin.rb +280 -0
- data/lib/samagotchi/bundles/dev/manifest.yml +3 -2
- data/lib/samagotchi/bundles/github-pr/manifest.yml +3 -3
- data/lib/samagotchi/bundles/github-pr/plugin.rb +2 -1
- data/lib/samagotchi/bundles/known-names/hooks/known_names.rb +3 -1
- data/lib/samagotchi/bundles/known-names/manifest.yml +3 -2
- data/lib/samagotchi/bundles/source-links/hooks/source_links.rb +2 -2
- data/lib/samagotchi/bundles/source-links/manifest.yml +3 -3
- data/lib/samagotchi/bundles/system/manifest.yml +3 -3
- data/lib/samagotchi/bundles/system/memory_guide.md +5 -5
- data/lib/samagotchi/bundles/system/self_map.md +1 -1
- data/lib/samagotchi/chi_home.rb +4 -2
- data/lib/samagotchi/chi_shim.rb +2 -1
- data/lib/samagotchi/child_env.rb +10 -3
- data/lib/samagotchi/config.rb +7 -1
- data/lib/samagotchi/context_note.rb +17 -5
- data/lib/samagotchi/engine.rb +113 -6
- data/lib/samagotchi/engine_peers.rb +11 -0
- data/lib/samagotchi/git_env.rb +43 -0
- data/lib/samagotchi/guardrails/context.rb +2 -0
- data/lib/samagotchi/guardrails/pair_boundary.rb +3 -2
- data/lib/samagotchi/guardrails/targets.rb +4 -1
- data/lib/samagotchi/llm/chat_loop.rb +1 -1
- data/lib/samagotchi/memory_bundle/asset_installer.rb +16 -2
- data/lib/samagotchi/memory_bundle/file_standing.rb +167 -0
- data/lib/samagotchi/memory_bundle/installed_bundle.rb +62 -1
- data/lib/samagotchi/memory_bundle/installer.rb +161 -52
- data/lib/samagotchi/memory_bundle/listing.rb +4 -3
- data/lib/samagotchi/memory_bundle/merger.rb +209 -8
- data/lib/samagotchi/memory_bundle/placeholder.rb +2 -1
- data/lib/samagotchi/memory_bundle/profile.rb +7 -3
- data/lib/samagotchi/memory_bundle/provenance.rb +178 -20
- data/lib/samagotchi/memory_bundle/remerge.rb +167 -0
- data/lib/samagotchi/memory_bundle/shipped_history.rb +79 -0
- data/lib/samagotchi/memory_bundle/shipped_update.rb +89 -24
- data/lib/samagotchi/memory_bundle/source.rb +3 -3
- data/lib/samagotchi/memory_bundle/status.rb +21 -3
- data/lib/samagotchi/memory_bundle/system_bundle.rb +98 -33
- data/lib/samagotchi/memory_bundle/text_merge.rb +399 -0
- data/lib/samagotchi/memory_bundle/trash.rb +58 -2
- data/lib/samagotchi/memory_bundle/uninstaller.rb +26 -6
- data/lib/samagotchi/note_command.rb +1 -1
- data/lib/samagotchi/note_delivery.rb +6 -2
- data/lib/samagotchi/objectives.rb +395 -0
- data/lib/samagotchi/objectives_audit.rb +115 -0
- data/lib/samagotchi/objectives_check.rb +365 -0
- data/lib/samagotchi/objectives_command.rb +192 -0
- data/lib/samagotchi/plugin/api.rb +2 -1
- data/lib/samagotchi/plugin/context.rb +21 -1
- data/lib/samagotchi/project_env.rb +3 -2
- data/lib/samagotchi/self_report.rb +2 -0
- data/lib/samagotchi/session_commands.rb +15 -0
- data/lib/samagotchi/session_continue.rb +3 -0
- data/lib/samagotchi/session_inbox.rb +14 -6
- data/lib/samagotchi/session_manager.rb +1 -1
- data/lib/samagotchi/steer.rb +24 -4
- data/lib/samagotchi/testing/boundary.rb +2 -0
- data/lib/samagotchi/testing/host.rb +1 -0
- data/lib/samagotchi/testing/minitest.rb +3 -0
- data/lib/samagotchi/testing/rspec.rb +3 -0
- data/lib/samagotchi/testing/sandbox.rb +3 -1
- data/lib/samagotchi/tool_activity.rb +17 -0
- data/lib/samagotchi/tool_declarations.rb +34 -0
- data/lib/samagotchi/tools/builtin_calls.rb +2 -1
- data/lib/samagotchi/tools/builtins.rb +4 -1
- data/lib/samagotchi/tools/delegate.rb +2 -1
- data/lib/samagotchi/tools/objectives_tool.rb +75 -0
- data/lib/samagotchi/tools/peers.rb +3 -0
- data/lib/samagotchi/tools/task_runtime.rb +13 -10
- data/lib/samagotchi/turn_flow.rb +3 -1
- data/lib/samagotchi/update_command.rb +76 -28
- data/lib/samagotchi/update_hint.rb +4 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/auto_update.rb +8 -8
- data/lib/samagotchi/web/auto_update_record.rb +6 -4
- data/lib/samagotchi/web/message_display.rb +9 -0
- data/lib/samagotchi/web/participant_view.rb +2 -2
- data/lib/samagotchi/web/public/app.js +15 -3
- data/lib/samagotchi/web/public/block_open.js +13 -0
- data/lib/samagotchi/web/public/bubbles.js +4 -2
- data/lib/samagotchi/web/public/cards_place.js +30 -9
- data/lib/samagotchi/web/public/commands.js +4 -1
- data/lib/samagotchi/web/public/details_motion.js +2 -1
- data/lib/samagotchi/web/public/index.html +20 -14
- data/lib/samagotchi/web/public/objectives.css +80 -0
- data/lib/samagotchi/web/public/objectives_entry.js +22 -0
- data/lib/samagotchi/web/public/objectives_model.js +100 -0
- data/lib/samagotchi/web/public/objectives_moves.js +145 -0
- data/lib/samagotchi/web/public/objectives_strip.js +242 -0
- data/lib/samagotchi/web/public/objectives_wiring.js +62 -0
- data/lib/samagotchi/web/public/stage_model.js +5 -6
- data/lib/samagotchi/web/public/stage_view.js +8 -7
- data/lib/samagotchi/web/public/stream_handlers.js +6 -1
- data/lib/samagotchi/web/public/turn_block.js +34 -19
- data/lib/samagotchi/web/public/turn_html.js +4 -1
- data/lib/samagotchi/web/public/turn_model.js +1 -1
- data/lib/samagotchi/web/public/update_sheet.js +8 -3
- data/lib/samagotchi/web/public/working_set_view.js +10 -7
- data/lib/samagotchi/web/push/notifier.rb +7 -9
- data/lib/samagotchi/web/session_hub.rb +2 -1
- data/lib/samagotchi/web/session_show.rb +12 -1
- data/lib/samagotchi/web/update_ops.rb +2 -1
- data/lib/samagotchi/worker.rb +3 -0
- data/lib/samagotchi/worker_inbound.rb +16 -8
- metadata +22 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: caeb209690eb9b78ab3977c53ed4c7bbe7388b0a15e51b59b70da653ac9a9bdc
|
|
4
|
+
data.tar.gz: 43cd03b5039cc16b588323f82ca0e063053d4b78de83b9785e66dd7dbf8d4a71
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 84a48999dd02619caa8900b8e2897614c93089519fa5e87d05e5f743b7073546e61b2c4e49a768798f1e612ef29eb768a86c7e69197e1880348ab5b767291ec4
|
|
7
|
+
data.tar.gz: 65ff02a943a5d58615976d531b22114c40d015b24098d230b5b389abff7bdacd33cabcb9b5622a3b57d054d2e156878a945a6e83895547ffe6dba8c929e0ab5b
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,65 @@ and commands may change between minor versions. How releases are made:
|
|
|
7
7
|
[docs/releasing.md](docs/releasing.md).
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.150.0] - 2026-11-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- The web's steps block closes to its summary line after a turn and after a reload, whatever its steps said; opened, it shows the outline as before. A canceled or failed turn with a narrated step stays open. [docs/cli.md](docs/cli.md#how-the-page-draws-a-turn)
|
|
15
|
+
- The web's working-set footprint is now the steps block's summary line, in body colour, the steps' count at its right (a phone shows the footprint alone); there is no separate line under the block. A click on its words opens the turn's list, the chevron or the count opens the steps. [docs/cli.md](docs/cli.md#the-working-set)
|
|
16
|
+
- Check this also reads the agent's visible answers, never its thinking, so a claim about what the agent said or asked can be confirmed. They settle only that: a claim of work with nothing but the agent's words behind it isn't `confirmed`. With `objectives.check_model` they go to that host too. [docs/sessions.md](docs/sessions.md#objectives)
|
|
17
|
+
- An upgrade now merges a memory you edited with the bundle's new version instead of leaving it behind. `chi bundle upgrade`, `chi update` and the automatic system bundle update run a text merge (needs `git`): a clean merge replaces the file, with the old one in the bundle trash and the report saying `merged 0.8.0 into your x.md`, and `--dry-run` says `would merge`. When a chi start updates the system bundle, a terminal launch says so in one line. Entries both sides added under a `Changelog` heading are kept, yours first. A real conflict, no `git`, or no recorded base leaves your file untouched, as before, and a file marked by an older chi can stay behind too (see the next line).
|
|
18
|
+
- A memory left behind as a conflict gets another try without waiting for the bundle's next version: the system bundle retries its files marked conflict at every chi start and on `chi update`, the other bundles chi ships on `chi update`, and any other bundle on `chi bundle upgrade`. It touches memory files only, and a row reads `0.8.0 merged 0.8.0 into your x.md`. A file marked by an older chi merges normally when its recorded base is a version chi shipped, checked against the samagotchi gems still installed. Otherwise that base may be your own text, so the file merges only if the bundle takes out or rewords no line it still holds. If it does, it stays behind until resolved by hand, with `--agent` or with `--force`, and the retry can't fix that.
|
|
19
|
+
- Everything that reports an edited bundle file now says what happened in one wording: `merged 0.8.0 into your x.md`, or `x.md stays behind 0.8.0: missed ## Steps, ## Rules and 2 more` with the reason when there is one (`no merge possible (git not found)`). The record keeps why and what was missed, and the bundle's text is saved at `.bundles/<name>/incoming/<file>` until the file settles. `kept your edits` is gone from `chi update`, whose `--json` rows gain `merged` next to `kept`, and from `chi bundle upgrade`, `chi bootstrap` and the system bundle's line at a start.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `bundle exec chi home set --ruby X` no longer records the bundle's vendor folder as X's gems when the bundle has a `path` and holds samagotchi: the probe of X still took `BUNDLER_SETUP`. A home set that way keeps its wrong `gem_home` until you run `chi home set` again.
|
|
24
|
+
- Under a `bundle exec chi`, a tool's plain `ruby` no longer loads Bundler: `BUNDLER_SETUP` still reached it, so in a folder whose Gemfile needs a missing gem `ruby -e` exited 1, and with Bundler 4 (`BUNDLE_LOCKFILE`) a folder with any other Gemfile had its lock written over chi's own `Gemfile.lock`. `execute`, tasks, `!cmd`, context sources and MCP servers all run without them, and `task_create` refuses them in `env`, saying to write `KEY=value cmd` in the command instead.
|
|
25
|
+
- `chi bundle install <git url>` run from a git hook or `git rebase --exec` no longer takes the repo git's variables name for its own: `GIT_WORK_TREE` failed the clone, `GIT_OBJECT_DIRECTORY` wrote the bundle's objects into that repo, and `GIT_DIR` alone recorded that repo's HEAD as the bundle's `source_commit`. Settings given around chi (`git -c url.….insteadOf=…`, `GIT_CONFIG_COUNT`) still apply to the clone. `delegate`'s `cwd:` check also asks about the folder it was given, as do the known-names (the git name), github-pr (the branch, `gh pr view`) and source-links (the remote) bundles.
|
|
26
|
+
- The web no longer loses a reply you steered: a line sent while a text-only step streamed left that step's whole text hidden, with no row or summary to open, live and after a reload. The step is now a row of the steps block (`1 step`), like any other text step.
|
|
27
|
+
- A web card updated just as a finished turn slid into the history no longer stays stuck on its first text until a reload (`/short` could stay on "Short version: …").
|
|
28
|
+
- A web card no longer lands a turn too early for good after `!rollback` of a canceled or failed turn: the rollback takes the turn out of the count. A rolled-back or failed turn's own cards stay where the turn was, without their buttons, instead of being read as the next turn's.
|
|
29
|
+
- A web card no longer lands one turn late for good after a worker was killed in the next turn (`kill -9`, a pod that didn't wait): the turn is counted, since its prompt stays in the session.
|
|
30
|
+
- A web card keeps its place after a reload when the turn after it failed with nothing kept: above the failed prompt, as it showed live, not below it, and an older card no longer lands one turn too late. A failed prompt isn't counted as a turn any more.
|
|
31
|
+
- `chi bundle list` and `chi self` say when a bundle has a file behind (`1 file behind`), and `chi bundle status` says it per file. `issues=` now counts files that stay behind, are missing or can't be read: an edit alone is no issue. A file `chi bundle status` can't read no longer crashes it.
|
|
32
|
+
- Every merge now leaves a note on the file's record, since a worker's reaches only the log and an automatic update's rows no one reads: `chi bundle status` shows it (with the old copy's folder), `chi update` names an earlier one in its row, and a row printed to you, or `chi bundle upgrade`'s output, ends the note. An automatic update names it without clearing it.
|
|
33
|
+
- `chi update` no longer crashes on an edited memory it can't read at a newer version: that bundle's row fails and says which file, and the others go on.
|
|
34
|
+
- The start-up hint `… can be updated: chi update` counts a bundle whose file would now merge at the same version.
|
|
35
|
+
- The update sheet shows `chi update`'s own words for an edited file, and the phone's push after an automatic update counts both sides (`Merged the update into 1 file you edited. 2 files stay behind.`): a merge used to go unmentioned, and every kept file read as `Kept your edits`.
|
|
36
|
+
- `chi update` no longer reads `up to date` for a file that stays behind at the same version: a real conflict, no `git`, a timeout, a file it can't read, or one left for the bundle's next version now name the file and why, and the summary counts them.
|
|
37
|
+
- A file marked by an older chi whose base chi can't vouch for no longer claims to hold your edits: it says chi can't tell, and why.
|
|
38
|
+
- `chi update`'s table no longer carries the trash's long path: the row says `old copies: chi bundle trash`, and `--json`'s `trash_copy` has the full line.
|
|
39
|
+
- The `--force` suggestions say what happens to your file: it is copied to the trash first.
|
|
40
|
+
- `chi bundle install --force` and `chi bundle upgrade --force` no longer destroy what they overwrite: a memory that differs from the bundle's, your own same-name file too, is copied to the bundle trash first, and the output names it (`Copied to the trash first: …`; `chi bundle trash` lists it).
|
|
41
|
+
- An install, upgrade or `chi update` that replaces or removes a hook, rule, plugin or script you edited copies it to the bundle trash first, under its own subfolder (`hooks/x`, `scripts/sub/x`) at any depth, and says so. A `--dev` install's links are left out.
|
|
42
|
+
- `chi bundle uninstall`, with `--force` or without, copies a hook, rule, plugin or script you edited to the bundle trash before removing it, and names it. Only memories reached the trash before.
|
|
43
|
+
- An install, upgrade or uninstall that can't read a file or write the bundle trash fails with a message naming the file, not a backtrace, and running it again after fixing that picks up where it stopped.
|
|
44
|
+
- A memory whose conflict was resolved through `chi bundle upgrade --agent` keeps its description in the bundle's record.
|
|
45
|
+
- `chi bundle upgrade --agent` no longer calls a conflict resolved when nothing merged it. A file the session didn't change, or one still holding conflict markers, stays a conflict, the output says so (`Nothing changed in X: still behind.`), and the command exits 2. It used to mark the file resolved, so later upgrades kept it without a word and the bundle's change never arrived.
|
|
46
|
+
- An edited memory with no recorded base keeps surviving upgrades as a conflict. Its own text used to become the base, so the following upgrade overwrote it with nothing in the trash. A record an older chi already left that way (marked conflict, the base being your text) stays behind when the update would take out a line it holds. Otherwise it takes the update, with your text copied to the bundle trash first and a line saying so.
|
|
47
|
+
- A plain `chi bundle install` keeps the conflict mark on a file it skipped, so `chi bundle status` still shows the file missed an update.
|
|
48
|
+
- `chi bundle upgrade --dry-run` no longer prints a false `Checksum mismatch` for a memory you edited, and its `Kept` line now names those files. This only changes a dry run's output.
|
|
49
|
+
- `chi bundle upgrade --agent` no longer takes your file as the new base when the bundle's copy disappears during the session. The next upgrade used to overwrite the edit with nothing in the trash; the file now stays a conflict and the command says so.
|
|
50
|
+
- An install or upgrade no longer fails at its last step on a memory that isn't valid UTF-8.
|
|
51
|
+
- A Changelog merge compares whole entries, nested items included: your `- a` / ` - note` beside the bundle's `- b` / ` - note` no longer loses the bundle's ` - note`.
|
|
52
|
+
- Putting back a deleted system memory at the same version now restores that file alone. It used to run a whole upgrade, replacing hooks, rules and the plugin under live sessions.
|
|
53
|
+
|
|
54
|
+
Update with `chi update` (github-pr 0.6.3, known-names 0.1.9, source-links 0.6.3: their git calls ask about the session's folder, and they need this chi; dev profile 0.7.6).
|
|
55
|
+
|
|
56
|
+
## [0.149.0] - 2026-11-04
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- `/objectives` gives a session a short list of what it is to achieve (`set A | B`, `add`, `done`, `drop`), kept in the conversation as a note; a continue carries it, and a session with no list gets no note and no prompt line. A first version to try. [docs/sessions.md](docs/sessions.md#objectives)
|
|
61
|
+
- The `objectives` tool lets the model record a move on an objective (a line, optional evidence): information only, it never changes the list, and `/objectives` shows each objective's latest. Declared on `full` and the coordinator toolkit, so a `full` request carries its schema with or without a list; other kits name it in the not-loaded line. The coordinator bundle's skill says a move or a `done` is never approval to merge. [docs/sessions.md](docs/sessions.md#objectives)
|
|
62
|
+
- The `decision-card` bundle (in the `dev` profile): in a session with objectives, a long answer ending in a question gets a card with a short summary and the question, which you answer in the composer. One side request per such answer; a session with no list makes none, and nothing enters the conversation. `chi bundle uninstall decision-card` takes it away. Plugins get `ctx.objectives`. [docs/bundles.md](docs/bundles.md#the-decision-card-bundle)
|
|
63
|
+
- The web shows a session's objectives in the conversation: a strip above it with the current list, each list note drawn as pills or a line of what you changed, and the model's moves as chips above an answer. A tap edits the list with no message or turn (`/objectives edit ID TEXT` is new, and the terminals keep the command), Not yet tells the agent in a message, and on a phone it is one line and a bottom sheet. The `objectives` tool gains `propose`: the model suggests a change and you apply it from a card; it never changes the list by itself. `decision-card`'s `/short` gives a long answer's short version on demand. A session with no list shows nothing new. The tool's schema changed, so the prompt cache misses once. [docs/sessions.md](docs/sessions.md#objectives)
|
|
64
|
+
- Check this (`/objectives check O2`, or the button in the web's list): on request, one side request reads an objective's latest move against what the session's tools returned and people said, and reports a verdict with reasons in a card. Information only: no status changes and nothing enters the conversation. `objectives.check_model` picks a cheaper model, whose host then gets up to 24,000 characters of tool output, known secret shapes redacted.
|
|
65
|
+
- `objectives.system_one: audit` (off by default) saves a System 1 yes/no per active objective on incoming messages and finished answers, for `chi judgments`; nothing acts on it. Its text goes to the System 1 host.
|
|
66
|
+
|
|
67
|
+
Update with `chi update` (coordinator 0.8.0, decision-card 0.2.0, dev profile 0.7.5). `chi update` installs decision-card for anyone on the dev profile; it does nothing in a session with no objectives.
|
|
68
|
+
|
|
10
69
|
## [0.148.0] - 2026-11-04
|
|
11
70
|
|
|
12
71
|
### Added
|
|
@@ -5611,7 +5670,9 @@ and long-lived sessions.
|
|
|
5611
5670
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
5612
5671
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
5613
5672
|
|
|
5614
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
5673
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.150.0...HEAD
|
|
5674
|
+
[0.150.0]: https://github.com/dm1try/samagotchi/compare/v0.149.0...v0.150.0
|
|
5675
|
+
[0.149.0]: https://github.com/dm1try/samagotchi/compare/v0.148.0...v0.149.0
|
|
5615
5676
|
[0.148.0]: https://github.com/dm1try/samagotchi/compare/v0.147.0...v0.148.0
|
|
5616
5677
|
[0.147.0]: https://github.com/dm1try/samagotchi/compare/v0.146.0...v0.147.0
|
|
5617
5678
|
[0.146.0]: https://github.com/dm1try/samagotchi/compare/v0.145.0...v0.146.0
|
data/README.md
CHANGED
|
@@ -53,8 +53,10 @@ chi update # the gem, then the bundles and the desktop helper
|
|
|
53
53
|
`chi update` installs the newest samagotchi from rubygems.org (old versions
|
|
54
54
|
stay installed: running sessions still use them), then brings the rest up to
|
|
55
55
|
the new version: the system bundle, the bundles chi ships that you installed,
|
|
56
|
-
and the macOS helper (rebuilt only when its sources changed).
|
|
57
|
-
edited
|
|
56
|
+
and the macOS helper (rebuilt only when its sources changed). A memory file you
|
|
57
|
+
edited takes the update in a text merge (the old file goes to the bundle trash),
|
|
58
|
+
or stays behind as it is when no merge is possible, and the table says which
|
|
59
|
+
and why. Running sessions keep their chi
|
|
58
60
|
until restarted (`chi sessions restart ID`, or the Restart badge on the web);
|
|
59
61
|
new and woken ones start on the new chi. A running `chi web` needs a restart,
|
|
60
62
|
and its page says so. From a checkout, `git pull` instead. See
|
data/docs/architecture.md
CHANGED
|
@@ -101,8 +101,8 @@ terminal renders the events it gets over the Bridge.
|
|
|
101
101
|
| UI | `Samagotchi::TerminalUI` | REPL (Reline), rendering, REPL commands. Delegates all core work to an `Engine`. |
|
|
102
102
|
| Model loops | `KernelLoop` (via `LLM::NativeBackend`), `LLM::ChatLoop` | The model↔tool loop: raw prompt, or a chat API (OpenAI chat, Anthropic Messages), chosen per host (see below). |
|
|
103
103
|
| Adapters | `Samagotchi::Client`, `LLM::OpenAIChat`, `LLM::AnthropicMessages`, `LLM::HTTP` | Raw-prompt servers, the OpenAI chat API, Anthropic's Messages API, and the HTTP they share. |
|
|
104
|
-
| Tools | `lib/samagotchi/tools/*` | Execute, read, edit, write, memory, task_*, web_fetch, delegate/delegate_result, ask_user_question, reminders, send_note, list_sessions, context_read, forget_outputs, find_tools/call_tool (the tool index), plus runtime/output-guardrails. |
|
|
105
|
-
| Bundles | `lib/samagotchi/memory_bundle/*`, `BundleCommand` | `chi bundle`: install/upgrade (3-way merge), build, uninstall; the install record under `.bundles/<name>/` that the hook, guardrail and plugin loaders read ([internals/bundles.md](internals/bundles.md)). |
|
|
104
|
+
| Tools | `lib/samagotchi/tools/*` | Execute, read, edit, write, memory, task_*, web_fetch, delegate/delegate_result, ask_user_question, reminders, send_note, list_sessions, context_read, objectives, forget_outputs, find_tools/call_tool (the tool index), plus runtime/output-guardrails. |
|
|
105
|
+
| Bundles | `lib/samagotchi/memory_bundle/*`, `BundleCommand` | `chi bundle`: install/upgrade (3-way, with a text merge of edited memories), build, uninstall; the install record under `.bundles/<name>/` that the hook, guardrail and plugin loaders read ([internals/bundles.md](internals/bundles.md)). |
|
|
106
106
|
| Background | `Samagotchi::Worker`, `Samagotchi::SessionManager` | `SessionManager` forks/spawns one worker process per session; its `Worker` builds the `Engine` and `Bridge` (no terminal rendering) and runs queued turns. The spawned process (own process group) forks the worker, which `setsid`s and is reparented to init once its starter exits (it waits until the worker holds `owner.lock`, so the spawner's `Process.detach` waiter tells a starting worker): nothing that walks the spawner's process tree reaches it (`SAMAGOTCHI_WORKER_DETACH=1`, `detach_from_spawner`). The lock's pid is the worker's; `spawn`'s `child_pid` is its starter's. |
|
|
107
107
|
| Web | `Samagotchi::Web::App`, `Samagotchi::Web::Server`, `Samagotchi::Web::SessionHub` | Rack+WEBrick on one port, `127.0.0.1:4567` (index.html + `/api/*` + SSE); with `web.host: lan` also on this machine's LAN address, behind an access token (`Web::Lan`, `Web::Token`). The hub is chi web's projection of the session list, pushed to every tab over `GET /api/events`. |
|
|
108
108
|
| Sessions | `Samagotchi::Session`, `SessionManager` | File `sessions/<uuid>.json` + sidecar `input/`/`output/`; retention 14d/500, `updated_at desc`, lazy sweep. |
|
|
@@ -394,7 +394,7 @@ record starts at `phase: installed` and the run goes on as below. Ahead of every
|
|
|
394
394
|
`SessionHub#auto_offer_restart` (`auto_offers`, in memory) when a run on record for the newest installed chi is closed with
|
|
395
395
|
this chi web still older, or that chi has waited `HELD_FOR` (1 h): the trying goes on, and the page has its buttons back;
|
|
396
396
|
`restart_failed` and a failed install call it at once. Its record is `update_check.json`'s `auto`:
|
|
397
|
-
`{version, from, at, kept, phase: installed|workers|web|retrying|done|failed, workers: {restarted, left}, detail, pushed}`,
|
|
397
|
+
`{version, from, at, kept, merged, phase: installed|workers|web|retrying|done|failed, workers: {restarted, left}, detail, pushed}`,
|
|
398
398
|
in Ruby the value object `Web::AutoUpdateRecord`, which owns that shape (`from_h`, `to_store`).
|
|
399
399
|
With `update.restart: never` the run ends at the install (`chi_notice` `installed`). With `idle` it goes on
|
|
400
400
|
(`phase` `installed` → `workers` → `web` → `retrying` → `done`): `UpdateOps#restart_workers(select:)` over the stale workers whose
|
data/docs/bundles.md
CHANGED
|
@@ -858,7 +858,7 @@ by themselves there.
|
|
|
858
858
|
session: the coordinator session picks the change up from the handoff,
|
|
859
859
|
and merges as it always does. Experimental: it may go if it doesn't earn its place.
|
|
860
860
|
- **The coordinator toolkit.** The bundle declares `coordinator`: `lean`
|
|
861
|
-
plus `delegate`, `delegate_result` and `
|
|
861
|
+
plus `delegate`, `delegate_result`, `list_sessions` and `objectives` (the skill records moves with it)
|
|
862
862
|
([Toolkits](configuration.md#toolkits)). `/coordinate` puts a fresh session
|
|
863
863
|
on it before it asks the model (`ctx.use_toolkit`). When chi refuses (a reply
|
|
864
864
|
or a turn already there) and the session's toolkit has no `delegate`, the
|
|
@@ -1240,3 +1240,40 @@ for one model family, loaded into the prompt only for the models a note's
|
|
|
1240
1240
|
through upgrades; other notes stack with the bundle's
|
|
1241
1241
|
([Model notes](memory.md#model-notes)).
|
|
1242
1242
|
|
|
1243
|
+
## The decision-card bundle
|
|
1244
|
+
|
|
1245
|
+
`chi bundle install decision-card` (or the `dev` profile) installs the bundle shipped with chi. It is a try-out, written
|
|
1246
|
+
only against this API (`lib/samagotchi/bundles/decision-card/plugin.rb`). It does nothing in a session with no
|
|
1247
|
+
[objectives](sessions.md#objectives): no request, no card.
|
|
1248
|
+
|
|
1249
|
+
In a session with an active objective, an answer that is long and ends in a question gets a card when the turn is over:
|
|
1250
|
+
a short summary, the question, and the objective it concerns when the model names one. You answer in the composer.
|
|
1251
|
+
The card has no buttons, so it invents no options, and it is no "needs you": no push, no waiting mark.
|
|
1252
|
+
|
|
1253
|
+
- **The gate**: a completed owner's turn (not a stopped one, a participant's or a `--non-interactive` one), at least
|
|
1254
|
+
`min_chars` characters, a question mark that ends a word in the last `tail_chars` of the prose (code is left out). All of
|
|
1255
|
+
it is read before any request.
|
|
1256
|
+
- **The request**: one side answer (`ctx.ask_model`) about the turn's prompt and answer, with the list in its prompt. It
|
|
1257
|
+
counts in `/stats`' side requests under `decision-card`. If the model says the answer asks nothing, or leaves out the
|
|
1258
|
+
summary or the question, there is no card.
|
|
1259
|
+
- **It may be late.** It runs on a thread, so the turn's end doesn't wait, and a one-slot local server answers it after
|
|
1260
|
+
the running request. A new turn cancels it, which frees that slot, and a card still to come is dropped.
|
|
1261
|
+
- **A shown card folds** to a line (`Asked: …`) when your next turn starts (a reminder's, a child's report's or a participant's turn leaves it open): in the web a row in the same place; the terminals
|
|
1262
|
+
print it as an update.
|
|
1263
|
+
- **A failed request** is only logged (`no_card` in the debug log): no card, no notice, no push.
|
|
1264
|
+
- **`/short`**: the last answer's short version on demand, in a card, by the same side request. The web's objectives offer it
|
|
1265
|
+
under the newest long answer of a session with a list (Short version), between turns. Typed, it works in any session; during
|
|
1266
|
+
a turn it refuses, since that turn's answer isn't there yet.
|
|
1267
|
+
- **Nothing else changes**: nothing enters the conversation, so the next request is byte for byte what it would be
|
|
1268
|
+
without the bundle. The card lives in the session's `cards.json`, as any card. `chi bundle uninstall decision-card` takes
|
|
1269
|
+
it all away (a member of a profile you uninstall stays out); a session you have open needs `chi sessions restart ID`.
|
|
1270
|
+
|
|
1271
|
+
```yaml
|
|
1272
|
+
bundles:
|
|
1273
|
+
decision-card:
|
|
1274
|
+
min_chars: 1200 # how long an answer is long
|
|
1275
|
+
tail_chars: 300 # how far from the end the question may be
|
|
1276
|
+
model: null # a cheap configured model ("host:id" or an alias); null is the session's own
|
|
1277
|
+
timeout: 120 # seconds the side request may take (a number)
|
|
1278
|
+
max_tokens: 300 # the side answer's limit
|
|
1279
|
+
```
|
data/docs/cli.md
CHANGED
|
@@ -228,9 +228,11 @@ $ chi models qwen # only the names containing "qwen" (any case)
|
|
|
228
228
|
```
|
|
229
229
|
component from to status
|
|
230
230
|
chi (gem) 0.2.0 0.3.0 updated
|
|
231
|
-
system bundle 0.2.0 0.3.0 updated (
|
|
231
|
+
system bundle 0.2.0 0.3.0 updated (identity.md stays behind 0.3.0: missed ## Who you are (chi bundle diff samagotchi-system identity.md))
|
|
232
232
|
btw 0.1.1 up to date
|
|
233
|
-
known-names 0.1.0 0.1.1 updated
|
|
233
|
+
known-names 0.1.0 0.1.1 updated (merged 0.1.1 into your known_names.md; old copies: chi bundle trash)
|
|
234
|
+
coordinator 0.8.0 merged 0.8.0 into your skill_coordinator.md; old copies: chi bundle trash
|
|
235
|
+
loop-guard 0.2.0 notes.md stays behind 0.2.0: no merge possible (git not found) (chi bundle diff loop-guard notes.md)
|
|
234
236
|
core 0.1.0 0.2.0 updated (+ new-bundle)
|
|
235
237
|
infra_tools 1.0.0 skipped (not from chi)
|
|
236
238
|
infra_tools warn api plugin.rb:3: ctx.old_name isn't in chi 0.3.0's plugin API (fix: docs/plugins.md has the API)
|
|
@@ -238,15 +240,17 @@ Chi Helper 0.2.0 up to date (launch file refreshed)
|
|
|
238
240
|
workers 2 live on 0.2.0: they keep it until restarted (chi sessions restart 2ea8c1f0 91b0d2aa); or they idle out after 30 min with nothing attached
|
|
239
241
|
Bundles not from chi are left as they are: their author's next version, or chi bundle upgrade NAME, is what changes them
|
|
240
242
|
Also shipped, not installed: dev (mcp, skills, source-links) (chi bundle install NAME)
|
|
241
|
-
|
|
243
|
+
2 files stay behind (see above)
|
|
242
244
|
```
|
|
243
245
|
|
|
244
246
|
- `--to VERSION` installs exactly that gem version instead of checking for the
|
|
245
247
|
newest release. It must be newer than the running chi; an equal or older
|
|
246
248
|
version is refused.
|
|
247
249
|
- `--json` writes the component rows as one JSON array on stdout. Each row has
|
|
248
|
-
`component`, `from`, `to`, `status`, `failed`, `kept` and `level` fields;
|
|
249
|
-
`kept` is an array of edited filenames
|
|
250
|
+
`component`, `from`, `to`, `status`, `failed`, `kept`, `merged`, `earlier`, `trash_copy` and `level` fields;
|
|
251
|
+
`kept` is an array of edited filenames left behind, `merged` of those this run
|
|
252
|
+
merged, `earlier` of those an earlier merge's note names, `trash_copy` the full line
|
|
253
|
+
saying where the old copies went (the table says `chi bundle trash`), and `level` is `warn` or `error` on a
|
|
250
254
|
re-check's row (below), `null` on the others. Install progress is written to
|
|
251
255
|
stderr.
|
|
252
256
|
|
|
@@ -304,11 +308,36 @@ done
|
|
|
304
308
|
the row says what it did.
|
|
305
309
|
- **Shipped bundles**: each one you installed from chi (`chi bundle install
|
|
306
310
|
NAME`) is upgraded when chi ships a newer version. Memory files get the
|
|
307
|
-
3-way merge of `chi bundle upgrade`: an unedited file is updated, an
|
|
308
|
-
one that the new version also changes
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
311
|
+
3-way merge of `chi bundle upgrade`: an unedited file is updated, and an
|
|
312
|
+
edited one that the new version also changes takes a text merge, with the old
|
|
313
|
+
file in the bundle trash and `merged 0.8.0 into your FILE` in the row. A real
|
|
314
|
+
conflict, no `git`, or no recorded base keeps your file untouched, and the row
|
|
315
|
+
says `FILE stays behind 0.8.0:` with why and what it missed (up to three headings
|
|
316
|
+
and a count, or `2 places`). `chi bundle diff NAME FILE` shows it; `chi bundle
|
|
317
|
+
upgrade NAME --force` takes the bundle's, with a copy of yours in the bundle
|
|
318
|
+
trash first. A later run retries such a file at the same version: its row reads
|
|
319
|
+
`0.8.0 merged 0.8.0 into your FILE` when it merges, and names it as behind when
|
|
320
|
+
it doesn't. So does a file left for the bundle's next version (it matches its old
|
|
321
|
+
base), or one the retry can't read, and the row never says `up to date` while a file
|
|
322
|
+
stays behind. Once a file has the bundle's bytes it isn't behind, however it got
|
|
323
|
+
them. A file marked by an older chi
|
|
324
|
+
merges normally when its recorded base is a version chi shipped (an installed
|
|
325
|
+
samagotchi gem still has it). Otherwise that base may be your own text, so it merges only if the bundle takes out or
|
|
326
|
+
rewords no line it still holds. If it does, chi can't tell whether the file holds
|
|
327
|
+
edits of yours, says so, and the file stays behind until resolved by
|
|
328
|
+
hand, with `--agent` or with `--force`; the retry can't fix that. Every merge
|
|
329
|
+
leaves a note on the file's record, since a worker's reaches only the log and an
|
|
330
|
+
automatic update's rows may be read by no one. `chi bundle status` shows it while it
|
|
331
|
+
exists. A `chi update` row names an earlier one (`up to date (merged 0.8.0 into your
|
|
332
|
+
FILE on 2026-11-05 14:03; …)`), and a row printed to you ends the note for what it
|
|
333
|
+
printed, that run's own merges included; so does `chi bundle upgrade`, which prints
|
|
334
|
+
the merge itself, and `--force` replacing the file. A dry run and an automatic update
|
|
335
|
+
(`update.auto`) show it and leave it, and so does a failed row or one with no place
|
|
336
|
+
for it (a skipped system bundle). A memory that can't be read at a
|
|
337
|
+
newer version fails that bundle's row with the file's name. Hooks, rules and the plugin are replaced; an edited one didn't
|
|
338
|
+
load anyway (its sha no longer matched), the row says it was replaced, and
|
|
339
|
+
a copy goes to the bundle trash first (`chi bundle trash`; `hooks/x`,
|
|
340
|
+
`guardrails/x`, `plugin/x`, `scripts/x` inside the dir).
|
|
312
341
|
A bundle of the same name from elsewhere (a zip, git) is skipped ("not from
|
|
313
342
|
chi"), a newer installed one is left, one whose new version needs a newer
|
|
314
343
|
chi is skipped, and bundles you didn't install stay uninstalled.
|
|
@@ -367,9 +396,10 @@ this version's view: bundles that only a newer gem ships newer show up once
|
|
|
367
396
|
that gem is installed (the real run installs it first and hands over).
|
|
368
397
|
`--no-gem`, `--no-bundles` and `--no-desktop` leave a part alone for one run;
|
|
369
398
|
`update.gem`, `update.bundles` and `update.desktop: false` in config.yml turn
|
|
370
|
-
one off for good. It exits 0 when nothing failed (
|
|
399
|
+
one off for good. It exits 0 when nothing failed (merged edits, files that stay behind and skips are
|
|
371
400
|
fine), 1 when a part failed, 2 on a usage error. A second run changes nothing
|
|
372
|
-
and ends with "everything is up to date"
|
|
401
|
+
and ends with "everything is up to date", or with `N files stay behind (see above)`
|
|
402
|
+
when some do.
|
|
373
403
|
|
|
374
404
|
From a checkout it refuses (`git pull`, or `chi bundle upgrade NAME` for one
|
|
375
405
|
bundle). After a gem update, the first interactive start of the new version
|
|
@@ -867,6 +897,23 @@ mid-turn too, and the lists, cards, top bar and tab show it in place of the firs
|
|
|
867
897
|
message; a continue's next link keeps it. In the web, `✎` next to the session's
|
|
868
898
|
title (its strip card, or the top bar) does it. See [Session titles](sessions.md#session-titles).
|
|
869
899
|
|
|
900
|
+
<a id="session-objectives"></a>
|
|
901
|
+
`/objectives` shows what the session is to achieve, each objective's latest move under it (`last move: …`, recorded by
|
|
902
|
+
the model's `objectives` tool); [Objectives](sessions.md#objectives) has what that does.
|
|
903
|
+
- `/objectives set Two coffees | Stops before checkout (done when: no order is placed)`: a new list. Parts are split by
|
|
904
|
+
` | ` or by lines; a part may end `(done when: …)`. It replaces the list, and ids go on from the old one's.
|
|
905
|
+
- `/objectives add TEXT`: one more (several with ` | `).
|
|
906
|
+
- `/objectives edit O1 TEXT`: a new text, the rest of the line whole (it may end `(done when: …)`); id and status stay.
|
|
907
|
+
- `/objectives done O1 [O2…]`, `/objectives drop O1 [O2…]`: mark items. An id it doesn't have refuses the whole line, and
|
|
908
|
+
so does `done` on a dropped item. The model is shown a done item as `O1 [done] …` and no dropped one.
|
|
909
|
+
- `/objectives undo O1 [O2…]`: back to active, after a mistaken `done` or `drop`.
|
|
910
|
+
|
|
911
|
+
- `/objectives check O1`: an independent read of O1's latest move, one side request; the verdict comes as a card and as
|
|
912
|
+
`check: …` under the move. Information only: it edits nothing, and it is refused for an objective with no move or a dropped one, and during a participant's turn. See [Objectives](sessions.md#objectives).
|
|
913
|
+
|
|
914
|
+
All of them run mid-turn too. An edit answers with the new list at once and goes into the conversation between turns.
|
|
915
|
+
Refused in a chi REPL's session (`--no-shared`), as `chi note` is; `/objectives` alone still answers there.
|
|
916
|
+
|
|
870
917
|
A `/model`, `/llm-context`, `/thinking`, `/reasoning-history` or `/toolkit` change that restarts the prompt cache
|
|
871
918
|
asks first: the reply says what it costs, changes nothing, and names the line
|
|
872
919
|
that applies it (`/thinking low --yes`, `/model qwen --default --yes`). `--yes` (or `-y`) applies it at once.
|
|
@@ -1172,14 +1219,17 @@ again). When a step ends its thinking closes to a plain `thinking` line
|
|
|
1172
1219
|
(unless you opened it); a step that only thought shows that line alone. The
|
|
1173
1220
|
live narration is a box of about three lines that fills sentence by
|
|
1174
1221
|
sentence (a sentence shows once it is complete) and scrolls to the newest
|
|
1175
|
-
when full. When the turn ends the block
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1222
|
+
when full. When the turn ends the block closes to its summary (`3 steps
|
|
1223
|
+
· 8 tool calls · execute ×7 · read ×1`, after the turn's
|
|
1224
|
+
[footprint](#the-working-set) when it has one). Opened, it shows its outline when any of
|
|
1225
|
+
its steps said something: one line per step that wrote text (that text's first
|
|
1226
|
+
line), and each run of steps that only called tools or thought sits behind one
|
|
1227
|
+
`· N steps` line that shows them. That includes a reply a line was steered into: its
|
|
1228
|
+
step is a row like any other, and the answer that follows is the bubble. A canceled or failed turn with such a step
|
|
1229
|
+
stays open, as its last narrated step is the only text you get. A reload draws
|
|
1230
|
+
the same from what was saved: a failed turn whose stream dropped mid-narration
|
|
1231
|
+
saved no such step, so it reloads closed. Either way the answer is a normal bubble under the block (Markdown,
|
|
1232
|
+
annotate). A plain answer
|
|
1183
1233
|
without tools ends exactly as it does today. Rows the code collapses stay
|
|
1184
1234
|
as you toggled them. A reloaded session shows the same block
|
|
1185
1235
|
from the saved messages (each step's thinking, narration, tool parameters
|
|
@@ -1222,12 +1272,14 @@ session bar shows the `mem N` chip again.
|
|
|
1222
1272
|
folds it to one line (`SET 17 + ◆ name`), kept per browser; a click opens the
|
|
1223
1273
|
list. In a stage narrower than 760 px it is one line under the last calls;
|
|
1224
1274
|
on a phone it isn't shown.
|
|
1225
|
-
- **The footprint**,
|
|
1275
|
+
- **The footprint**, each finished turn's block's summary line, live and after
|
|
1226
1276
|
a reload: `touched …/web/public/ · 4 files · ◆ 2 memories s2–10 · +1 url ·
|
|
1227
1277
|
edited 1`, then `n stale`, `n forgotten` or `n dropped` while some are (a file
|
|
1228
|
-
changed after the turn read it, even at its very end, says so here)
|
|
1229
|
-
tag (`s2`) goes to that call's row; the rest
|
|
1230
|
-
|
|
1278
|
+
changed after the turn read it, even at its very end, says so here), with the
|
|
1279
|
+
steps' count at the right. A step tag (`s2`) goes to that call's row; the rest
|
|
1280
|
+
of its words opens the turn's list; the chevron or the count opens the steps.
|
|
1281
|
+
A phone shows the footprint alone, no count. A turn that touched nothing has
|
|
1282
|
+
none: its summary is the count.
|
|
1231
1283
|
- **The `set N` chip** in the session bar, in place of the `mem N` chip (whose
|
|
1232
1284
|
tooltip goes too): the session's whole set, preloaded (`--memory`) and muted
|
|
1233
1285
|
(`--mute`) memories included; its dot lights when the set changed since you
|
data/docs/configuration.md
CHANGED
|
@@ -166,7 +166,7 @@ or `chi web` restart.
|
|
|
166
166
|
| `toolkit.kits`, `execute.description`, `llm_context.policy` | Worker start | These are held by the engine's toolkit or tool registry. |
|
|
167
167
|
| `toolkit.suggest.mode`, `toolkit.suggest.threshold`, `toolkit.suggest.defer_turns`, `toolkit.suggest.defer_tokens` | Worker start | Suggestion settings are config-only and are resolved when the worker runs its audit or on-mode ask. |
|
|
168
168
|
| `skip_agents_md` | Prompt rebuild | A running engine caches its built prompt; a new worker or `/model` rebuild uses the changed value. |
|
|
169
|
-
| `context.*` except `context.every_seconds`, `llm_context.*` except `llm_context.policy`, `steer.cut_after`, `memory.index_warn_tokens`, `memory.entry_warn_tokens`, `status.line`, `web.participants.*` | 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. A participant's grant keeps the expiry and cap it was issued with; `web.participants.*` is what the next invite gets, and the cap and queue of a grant from before caps. |
|
|
169
|
+
| `context.*` except `context.every_seconds`, `objectives.*`, `llm_context.*` except `llm_context.policy`, `steer.cut_after`, `memory.index_warn_tokens`, `memory.entry_warn_tokens`, `status.line`, `web.participants.*` | 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. A participant's grant keeps the expiry and cap it was issued with; `web.participants.*` is what the next invite gets, and the cap and queue of a grant from before caps. |
|
|
170
170
|
| `context.every_seconds` | Next context poll | The poller checks it for each source that has no explicit interval. |
|
|
171
171
|
| `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. |
|
|
172
172
|
| `system_one.host`, `system_one.model`, `system_one.timeout_ms`, `system_one.runs`, `system_one.judgments` | Next tool call or approval | Each ask reads them. |
|
|
@@ -1504,7 +1504,7 @@ toolkit:
|
|
|
1504
1504
|
| `full` | every built-in; the default |
|
|
1505
1505
|
| `lean` | `execute`, `read`, `write`, `edit`, `memory_read`, `memory_write`, `task_create`, `task_wait`, `task_get`, `task_list`, `task_stop`, `ask_user_question`, `web_fetch`, `context_read` |
|
|
1506
1506
|
| `child` | `lean` plus `send_note`, without `memory_write`, `delegate`, `delegate_result` |
|
|
1507
|
-
| `coordinator` | `lean` plus `delegate`, `delegate_result`, `list_sessions` (declared by the coordinator bundle) |
|
|
1507
|
+
| `coordinator` | `lean` plus `delegate`, `delegate_result`, `list_sessions`, `objectives` (declared by the coordinator bundle) |
|
|
1508
1508
|
| `coding` | `child`, with the prompt text `- Be concise in your responses` / `- Show file paths clearly when working with files` (declared by the coordinator bundle, for build and fix children) |
|
|
1509
1509
|
| `review` | `read`, `memory_read` (not `forget_outputs`, even under the `forget` layer): what a [participant's](internals/participants.md#turns) turn may call, whatever the session declares (the review boundary, [guardrails](guardrails.md#a-participants-review-boundary)). Reserved: `toolkit.kits.review` is refused ("review is reserved for participants' turns"), and a bundle can't declare it. A session may run on it too, as any kit |
|
|
1510
1510
|
|
|
@@ -2141,7 +2141,7 @@ Both are read when chi web starts (restart it to apply a change). What it does,
|
|
|
2141
2141
|
install isn't blocked (a source checkout, Bundler, a RubyGems directory chi can't write: those stay a notice, with
|
|
2142
2142
|
the command to run). `chi update` also merges the shipped bundles that live sessions read, hence "no turn anywhere".
|
|
2143
2143
|
2. **Installs** exactly the release the notice named, as the **Update** button does (the system bundle and shipped
|
|
2144
|
-
bundles are merged three ways;
|
|
2144
|
+
bundles are merged three ways; a file you edited takes a text merge, one with a real conflict stays behind, and the push counts both). The page's sticky toast says
|
|
2145
2145
|
"Automatic chi update in progress" and its sheet shows the rows; with `update.restart: idle` no "installed"
|
|
2146
2146
|
toast with **Restart** buttons follows (the run restarts by itself). A failed install is tried **once per version**:
|
|
2147
2147
|
it pushes the failed row's reason and stays quiet until a newer release (or you, with the button) tries again.
|
|
@@ -2158,7 +2158,7 @@ Both are read when chi web starts (restart it to apply a change). What it does,
|
|
|
2158
2158
|
the install; after that they wait for their own idle exit or the session's **Restart**. A newer release in that day
|
|
2159
2159
|
installs as usual and takes them over.
|
|
2160
2160
|
4. **Says so.** The restarted chi web pushes "chi updated to X" ("chi web and 3 sessions restarted; 1 restarts when
|
|
2161
|
-
idle.
|
|
2161
|
+
idle. Merged the update into 1 file you edited. 2 files stay behind."); the later restarts of those sessions push nothing more. With
|
|
2162
2162
|
`update.restart: never` the push is "chi X is installed" and chi web and the workers move over when you restart them (the page's toast offers it). The push needs the phone set up
|
|
2163
2163
|
([Phone notifications](#phone-notifications-web-push)); without it the page's toasts and
|
|
2164
2164
|
`$XDG_STATE_HOME/samagotchi/update_check.json` (`auto`) are the record.
|
|
@@ -2273,6 +2273,8 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2273
2273
|
| `context.candidates.threshold` | `0.8` | | The probability at which the judge attaches a candidate in on mode (a judged line's `would: attach`). config.yml only. |
|
|
2274
2274
|
| `context.candidates.offer_threshold` | `0.6` | | The probability from which on mode shows the candidate's card, once (`would: offer`, below `threshold`). config.yml only. |
|
|
2275
2275
|
| `context.candidates.reask_after_turns` | `3` | | Owner prompts after a judged ask before the judge's one re-ask of that candidate. config.yml only. |
|
|
2276
|
+
| `objectives.check_model` | none | | The model [Check this](sessions.md#objectives) asks, its one side request (a host:id, an alias, a host's model id); none: the session's own. **Each Check this sends that model's host up to 24,000 characters of the session's tool output, messages and the agent's visible answers, off the machine with a hosted model even from a local session;** known key shapes and `token=`-style values are redacted first, by pattern only. config.yml only. |
|
|
2277
|
+
| `objectives.system_one` | `off` | | `audit`: System 1 answers a yes/no per active objective on what comes in and goes out, saved as runs and acted on by nothing; see [System 1's saved runs](system-one.md#objectives-in-audit). `off` (the default): no conversation text goes to a System 1 host for this. Its host and model are `system_one.host` / `.model`. config.yml only. |
|
|
2276
2278
|
| `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". |
|
|
2277
2279
|
| `toolkit.child` | `full` | | A delegate child's toolkit, unless its `delegate` call names one (`toolkit:`). See "Toolkits". |
|
|
2278
2280
|
| `toolkit.suggest.mode` | `off` | | `audit` asks System 1 for a toolkit suggestion without changing the session; `on` waits for it (up to `system_one.timeout_ms`) on an eligible turn and starts the session on a confidently suggested kit (Toolkits, On mode). The System 1 host, model and timeout come from `system_one.*`. config.yml only. |
|
|
@@ -2303,7 +2305,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2303
2305
|
| `update.bundles` | `true` | | `false`: `chi update` leaves the shipped bundles to `chi bundle upgrade` (`--no-bundles`). |
|
|
2304
2306
|
| `update.desktop` | `true` | | `false`: `chi update` leaves the desktop helper alone (`--no-desktop`). |
|
|
2305
2307
|
| `update.notify` | `on` | | `on`: chi web checks RubyGems once a day and shows aged stable releases newer than both this chi and the newest installed chi; `off`: no thread or network check. |
|
|
2306
|
-
| `update.auto` | `off` | | `install`: chi web installs the release its checker found (aged by `update.min_age_hours`) once no turn runs and no question waits in any session, as the **Update** button would (shipped bundles merged,
|
|
2308
|
+
| `update.auto` | `off` | | `install`: chi web installs the release its checker found (aged by `update.min_age_hours`) once no turn runs and no question waits in any session, as the **Update** button would (shipped bundles merged, a file that can't merge left behind, both reported), then pushes how it went; `update.restart` says what follows, also for a chi installed some other way (`chi update` in a terminal). An install that fails is tried once per version (a newer release, or the **Update** button, tries again). The check runs even with `update.notify: off` (which then only silences the page's and the phone's "available"). An install that can't run here (a checkout, Bundler, an unwritable gem dir) stays a notice. `off`: notice only. See [Unattended updates](#unattended-updates-updateauto). |
|
|
2307
2309
|
| `update.restart` | `idle` | | With `update.auto: install`: `idle` restarts the stale workers whose session is idle and untouched for 10 minutes, then chi web itself, once no turn runs anywhere and the newest chi has answered `chi --version`; it pushes "chi updated to X". `never`: the install only (the page's toast offers the restarts, workers also exit on their own when idle). |
|
|
2308
2310
|
| `update.check_hours` | `24` | | Hours between RubyGems checks (at least 1). The first check starts about 30 seconds after chi web starts. |
|
|
2309
2311
|
| `update.min_age_hours` | `24` | | A release must be this old before chi web offers it; `0` disables the age delay. |
|
|
@@ -2327,7 +2329,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2327
2329
|
| `web.port` | `4567` | `--port` | `chi web`'s port. See [CLI](cli.md). |
|
|
2328
2330
|
| `web.host` | `127.0.0.1` | yes | `127.0.0.1`, `::1` or `localhost`; `lan` (this machine's private IPv4 address) or one of its IPv4 addresses also opens `chi web` to the network, with an access token, asked of this machine's 127.0.0.1 too (its `Local:` link carries a one-time code; `chi web --new-token` replaces the token). Anything else binds `127.0.0.1` with a warning. See [CLI: chi web on your phone](cli.md#chi-web-on-your-phone). |
|
|
2329
2331
|
| `web.markdown` | `false` | yes | Render answers as Markdown in `chi web`. |
|
|
2330
|
-
| `web.working_set` | `true` | yes | The stage view's working set: the files, memories and URLs a turn brought into the model's context, in a rail in the stage, a footprint
|
|
2332
|
+
| `web.working_set` | `true` | yes | The stage view's working set: the files, memories and URLs a turn brought into the model's context, in a rail in the stage, a footprint as each finished turn's block summary and a `set N` chip in place of the mem chip; `false` brings the mem chip back. `?working_set=1` or `?working_set=0` on the page URL overrides it for that page load. See [CLI: the working set](cli.md#the-working-set). |
|
|
2331
2333
|
| `web.annotate_presets` | `Agreed\|Could you please elaborate?` | yes | Quick replies next to Annotate in `chi web`, `\|`-separated (a YAML list works too); `""` in the file or on the CLI leaves only Annotate (an empty env value means the default). See [CLI](cli.md#web-annotate-presets). |
|
|
2332
2334
|
| `web.editor` | `vscode` | yes | What a file ref in `chi web` (a file tool row's title, a diff line) opens, for a viewer on this machine: a preset (`vscode`, `vscode-insiders`, `cursor`, `zed`) or a URL template with `{path}` and an optional `{line}`; `none` turns refs off. See [Opening files from chi web](#opening-files-from-chi-web). |
|
|
2333
2335
|
| `web.start_dir` | the folder `chi web` runs in | | The folder `chi web` starts in (`chi web --start-dir DIR` for one run): its page (the printed link, a bare `/`, the LAN link and QR code, the Home Screen app) opens on that folder's project, outside a repo on every session, and a new session from the all view starts there; the header's project picker switches projects. `~` and a relative path (resolved from your home folder) work; one that isn't a folder stops `chi web` from starting. `chi web` never changes its own folder. See [CLI](cli.md). |
|
data/docs/guardrails.md
CHANGED
|
@@ -529,7 +529,8 @@ message:
|
|
|
529
529
|
- owner-voiced tools, which act in the owner's name beyond the turn:
|
|
530
530
|
`delegate` and any `delegate_*` tool, `register_reminder`,
|
|
531
531
|
`cancel_reminder`, `send_note`, `forget_outputs`, `task_create`,
|
|
532
|
-
`task_stop`, `find_tools` (it loads tools into the session),
|
|
532
|
+
`task_stop`, `find_tools` (it loads tools into the session), `objectives`
|
|
533
|
+
(a move on the owner's list), and
|
|
533
534
|
`memory_write` (a memory reaches the owner's later sessions); and the tools
|
|
534
535
|
that read the owner's background tasks and their output, `task_wait`,
|
|
535
536
|
`task_get`, `task_list` (a pair turn starts none);
|
data/docs/hooks.md
CHANGED
|
@@ -56,7 +56,7 @@ The plugin class must respond to `#call(event)` — duck-typed, no base class re
|
|
|
56
56
|
|-------|--------------|---------------|
|
|
57
57
|
| `:session_start` | The first turn this chi process runs for the session (so again after `--resume`, a worker that idle-exited and woke, or a restart) | `{ type: :session_start, session_id: "..." }` |
|
|
58
58
|
| `:before_turn` | Before each turn starts | `{ type: :before_turn, session_id: "...", prompt: "..." (nil on a continue), resumed: true \| false (true on a step-limit Continue, which resumes the run before it; false on every other turn, a reminder's or a wake's too), messages: [...] (the history before this turn) }` |
|
|
59
|
-
| `:after_turn` | After a turn completed or was stopped once the model was asked (not after one that failed, was cut short by an interrupt signal (SIGINT), or was stopped before its `:before_turn` hooks) | `{ type: :after_turn, status: "completed" \| "canceled", present: (see [Presenting the answer](#presenting-the-answer-display-only)), refs: (see [Refs on the answer](#refs-on-the-answer-display-only)), messages: [...] (the conversation the turn stored; a cancelled or empty turn ends it with a `kind: turn_note` system message, and a context line is `kind: context`, see [sessions.md](sessions.md#notes-a-turn-leaves-for-the-model)) }` |
|
|
59
|
+
| `:after_turn` | After a turn completed or was stopped once the model was asked (not after one that failed, was cut short by an interrupt signal (SIGINT), or was stopped before its `:before_turn` hooks) | `{ type: :after_turn, status: "completed" \| "canceled", present: (see [Presenting the answer](#presenting-the-answer-display-only)), refs: (see [Refs on the answer](#refs-on-the-answer-display-only)), messages: [...] (the conversation the turn stored; a cancelled or empty turn ends it with a `kind: turn_note` system message, and a context line is `kind: context`, see [sessions.md](sessions.md#notes-a-turn-leaves-for-the-model); on the native loop the last model message still holds its thought block until the next turn), answer: "..." (the answer's text with no thought block; nil for a stopped turn or one that ran out of steps; needs chi newer than 0.148.0) }` |
|
|
60
60
|
| `:before_generation` | Before each LLM API call (both loops), before its `:generation_started`: the hook's time (a question it waits on) isn't the generation's | `{ type: :before_generation, iteration: N }` |
|
|
61
61
|
| `:after_generation` | After LLM returns (both loops); not after a generation a hook cut (`stop_generation`) | `{ type: :after_generation, iteration: N, response: "...", messages: [...] (the conversation as sent) }` |
|
|
62
62
|
| `:generation_progress` | While the response streams, in batches (see [Watching the stream](#watching-the-stream)) | `{ type: :generation_progress, iteration: N, thinking: "..." (new since the last fire), text: "..." (new visible text), thinking_chars: N, text_chars: N (this generation so far), elapsed_ms: N, restarted: true (only on the first fire after a dropped stream was asked again) }` |
|
|
@@ -636,6 +636,7 @@ stripped of surrounding whitespace, except file text, an edit's
|
|
|
636
636
|
| `delegate` | `task` | — | `model`, `session`, `cwd`, `toolkit`, `wait`, `timeout` |
|
|
637
637
|
| `delegate_result` | — | — | `session`, `timeout` |
|
|
638
638
|
| `ask_user_question` | `question` | — | `question`, `options`, `header`, `multi_select`, `allow_freeform` |
|
|
639
|
+
| `objectives` | `note` | — | `action`, `id`, `note`, `evidence`, `change`, `text` |
|
|
639
640
|
| `forget_outputs` | `note` | — | `ids`, `note`, `keep`, `restore` |
|
|
640
641
|
|
|
641
642
|
A `write`'s `content:` is the file text; an `edit` carries `old_text:` and
|
|
@@ -42,7 +42,7 @@ Behavior:
|
|
|
42
42
|
again or stop it (`TaskWait::MESSAGE_WAITING_NOTE`), and `waited: Ns`; the task keeps running and stays watched
|
|
43
43
|
(below). A task that finished meanwhile gives its finished result, as after a Stop. A `chi -p` turn has no probe. The same probe ends a blocking `delegate_result` (and `delegate`'s wait) early; see [Sessions: Delegating](../sessions.md).
|
|
44
44
|
- `task_create` accepts `env` as a JSON object string for deterministic overrides such as `PATH`; use an absolute interpreter path when that is simpler. Ruby/Bundler isolation variables remain protected.
|
|
45
|
-
- `execute` and `task_create` both spawn with chi's own Ruby/Bundler setup scrubbed (`TaskRuntime.sanitized_spawn_env`): `RUBYOPT` loses its `-r…bundler/setup` flags (others stay) and `RUBYLIB
|
|
45
|
+
- `execute` and `task_create` both spawn with chi's own Ruby/Bundler setup scrubbed (`TaskRuntime.sanitized_spawn_env`): `RUBYOPT` loses its `-r…bundler/setup` flags (others stay) and `RUBYLIB` and what `bundle exec` sets (`BundlerEnv::VARS`: `BUNDLE_GEMFILE`, `BUNDLE_LOCKFILE`, `BUNDLE_BIN_PATH`, `BUNDLER_VERSION`, `BUNDLER_SETUP`) are unset, so a project's `ruby -e` or `bundle exec` uses its own Gemfile, or none, when chi runs under `bundle exec`. RubyGems requires what `BUNDLER_SETUP` names at boot, whatever `RUBYOPT` says. A project's own settings (`BUNDLE_PATH`, `BUNDLE_WITHOUT`) stay. `task_create` refuses those keys in the model's `env`, its error saying to write `KEY=value cmd` in the command instead; `execute`'s `env` comes from chi's callers (`Builtins`, `!cmd`), not the model, and is set over the scrub. An `execute` handed over at its limit keeps the process it spawned, so the task runs with the same env.
|
|
46
46
|
- `execute` and `task_create` export chi's own markers into the command, set over the model's `env` (which can't set them: `Error: env key is reserved`): `SAMAGOTCHI_PARENT_SESSION` (the session's id, `chi` without one; a chi started there answers as a parent agent), `SAMAGOTCHI_SESSION_MODEL` (the resolved ref the session runs on, read at each call so it follows `/model`; unset when unknown) `SAMAGOTCHI_SESSION_THINKING` (the session's own thinking level; unset when it has none) and `SAMAGOTCHI_SESSION_REASONING_HISTORY` (its own reasoning_history level, the same way). `chi self` reads the last three for its model, thinking level and reasoning history. The four are `ChildEnv::SESSION_MARKERS` (`TaskRuntime::MARKER_ENV_KEYS`), which a spawned worker unsets (`ChildEnv.unset`, merged into its spawn env). A session's worker never inherits them from whoever started it (a `chi send` run by another session's `execute`): its other commands (a user's `!cmd`, an MCP server, a context command) have none.
|
|
47
47
|
- They also pass on a set `XDG_STATE_HOME` / `XDG_CONFIG_HOME` made absolute (`Builtins.xdg_absolute`, via `Paths`), so a chi the command runs in another `cwd` (`chi send`) reads this chi's state and config. These aren't reserved: an XDG dir the model sets in `task_create`'s `env` stays its own.
|
|
48
48
|
- Every runner starts from the session's project env, `ProjectEnv.tools_env`: the overlay a spawned worker computed once at boot (`SessionManager.apply_project_env` → `ProjectEnv.compute` → `ProjectEnv.install!`; its folder's `mise env`, and the chi shim's dir first on PATH so `chi` is the chi home's), less `ProjectEnv::TOOLS_DROP` (`RUBYOPT`, `RUBYLIB`, Bundler's: the scrub above sets those). Outside a worker (`ProjectEnv::NONE`) it is `{}`. The sites: `execute` and `task_create` (`Tools::Builtins#project_env`, under the markers and the model's `env`; a participant's turn gets `{}`), the user's `!cmd` (`SessionCommands#shell`), and through `ProjectEnv.spawn_env` (the scrub above, then `tools_env`: what `execute` spawns with, for the runners that don't go through it) a context source's command (`ContextFetch#env_for`) and an MCP server, under the server's own keys (`bundles/mcp/plugin.rb` `server_env`, from mcp 0.7.4; no participant rule: the server is the session's). chi's own process env is never changed, and the project env never enters the prompt. User docs: [Project env](../sessions.md#project-env); the launch side: [How chi launches itself](../architecture.md#how-chi-launches-itself).
|
data/docs/internals/bridge.md
CHANGED
|
@@ -52,6 +52,9 @@ the "asking again" and steer-cut rows, ✂ rows and questions (with how they wer
|
|
|
52
52
|
- **Placement is relative.** An entry carries `turns` and lists with `turns_since` (turns completed after it) and
|
|
53
53
|
`current` (a card of the running turn). A card that comes mid-turn but isn't the turn's (an anytime command's, such as
|
|
54
54
|
`/btw`) goes after that turn (`during`). A card with an earlier card's id replaces it in place.
|
|
55
|
+
- **A turn that leaves nothing.** `!rollback` (`TurnFlow#rollback!`, `:turn_rolled_back`) takes a kept turn's count
|
|
56
|
+
back. Of a rolled-back turn, and a failed one with nothing kept, the cards and hook notices become between-turns entries
|
|
57
|
+
at its place (the cards lose their actions); its other rows go, having no step to sit in.
|
|
55
58
|
- **Caps.** `CAPACITY` (20) each for notices, ✂ rows (`LLM_CONTEXT_TYPES`) and cards, so one burst cannot push out
|
|
56
59
|
another kind. An open question (an approval too) is never pushed out.
|
|
57
60
|
- **Saved.** With a `path` (`cards.json` in the session's folder) the store rewrites the file after each event in
|
|
@@ -60,6 +63,11 @@ the "asking again" and steer-cut rows, ✂ rows and questions (with how they wer
|
|
|
60
63
|
and an unanswered question waits for no one: neither is saved or seeded. An entry from an earlier worker lists with
|
|
61
64
|
`earlier: true`; one shown during a turn comes back **without its actions** (their turn no longer runs), while a
|
|
62
65
|
between-turns card keeps its buttons.
|
|
66
|
+
- **A killed turn counts.** A worker killed mid-turn never saw the turn end, but `TurnCheckpoint` keeps its prompt (the
|
|
67
|
+
next worker settles it as canceled). The Bridge's store (`killed_turn_stays:`) saves `"running": true` at
|
|
68
|
+
`:turn_started`, and a store started from that adds the one turn. An ordered end clears it, so a graceful stop's
|
|
69
|
+
cancel counts once; a file without the field counts none. A REPL's store never saves it: it keeps no running turn in
|
|
70
|
+
the session, so a kill takes the prompt too.
|
|
63
71
|
|
|
64
72
|
## SSEWriter
|
|
65
73
|
|