samagotchi 0.156.0 → 0.158.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 +70 -1
- data/README.md +1 -1
- data/bin/chi +4 -1
- data/docs/architecture.md +18 -12
- data/docs/bundle-authoring.md +5 -5
- data/docs/bundles.md +4 -1
- data/docs/cli.md +29 -24
- data/docs/configuration.md +43 -9
- data/docs/context.md +5 -3
- data/docs/guardrails.md +12 -7
- data/docs/hooks.md +53 -83
- data/docs/internals/bridge.md +84 -7
- data/docs/internals/bundles.md +69 -46
- data/docs/internals/context-telemetry.md +4 -3
- data/docs/internals/engine.md +23 -7
- data/docs/internals/participants.md +3 -2
- data/docs/internals/remote-sessions.md +5 -2
- data/docs/internals/web-frontend.md +3 -2
- data/docs/internals/working-set.md +1 -1
- data/docs/memory.md +51 -10
- data/docs/plugins.md +48 -11
- data/docs/releasing.md +6 -5
- data/docs/sessions.md +13 -13
- data/docs/sub-agent.md +17 -2
- data/docs/testing.md +56 -5
- data/lib/samagotchi/answer_command.rb +2 -1
- data/lib/samagotchi/archive_store.rb +4 -3
- data/lib/samagotchi/bootstrap_command.rb +3 -2
- data/lib/samagotchi/bridge/card_places.rb +5 -7
- data/lib/samagotchi/bridge/card_store.rb +3 -0
- data/lib/samagotchi/bridge/turn_accumulator.rb +113 -10
- data/lib/samagotchi/bridge/turn_drawings.rb +271 -0
- data/lib/samagotchi/bridge.rb +31 -6
- data/lib/samagotchi/broadcast/recipients.rb +8 -8
- data/lib/samagotchi/broadcast/triage_model.rb +1 -1
- data/lib/samagotchi/bundle_command/check.rb +41 -10
- data/lib/samagotchi/bundle_command/installed_check.rb +13 -2
- data/lib/samagotchi/bundle_command/try/run.rb +4 -1
- data/lib/samagotchi/bundle_command/try/sandbox.rb +1 -1
- data/lib/samagotchi/bundle_command/try/trace.rb +1 -1
- data/lib/samagotchi/bundle_command.rb +20 -45
- data/lib/samagotchi/bundles/known-names/manifest.yml +4 -7
- data/lib/samagotchi/bundles/known-names/{hooks/known_names.rb → plugin.rb} +17 -0
- data/lib/samagotchi/bundles/source-links/manifest.yml +4 -7
- data/lib/samagotchi/bundles/source-links/{hooks/source_links.rb → plugin.rb} +23 -4
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +1 -1
- data/lib/samagotchi/bundles/system/manifest.yml +4 -4
- data/lib/samagotchi/bundles/system/memory_guide.md +7 -7
- data/lib/samagotchi/bundles/system/self_map.md +1 -1
- data/lib/samagotchi/child_move.rb +6 -6
- data/lib/samagotchi/child_reports.rb +2 -2
- data/lib/samagotchi/children_status.rb +15 -21
- data/lib/samagotchi/cli/parent_wait.rb +8 -22
- data/lib/samagotchi/config.rb +3 -0
- data/lib/samagotchi/context_command.rb +7 -5
- data/lib/samagotchi/context_sources.rb +9 -6
- data/lib/samagotchi/context_window.rb +9 -12
- data/lib/samagotchi/effective_model.rb +57 -22
- data/lib/samagotchi/engine/plugins.rb +1 -1
- data/lib/samagotchi/engine/recap.rb +8 -4
- data/lib/samagotchi/engine.rb +30 -9
- data/lib/samagotchi/events.rb +3 -2
- data/lib/samagotchi/extension_load.rb +26 -44
- data/lib/samagotchi/guardrails/load_failures.rb +3 -2
- data/lib/samagotchi/guardrails/path_resolve.rb +11 -0
- data/lib/samagotchi/guardrails/review_paths.rb +1 -5
- data/lib/samagotchi/guardrails_command.rb +1 -1
- data/lib/samagotchi/hook_routes.rb +2 -2
- data/lib/samagotchi/hooks.rb +2 -3
- data/lib/samagotchi/host_address.rb +52 -0
- data/lib/samagotchi/host_registry.rb +57 -45
- data/lib/samagotchi/kernel_loop.rb +7 -3
- data/lib/samagotchi/llm/chat_loop.rb +6 -3
- data/lib/samagotchi/llm_context_strategy.rb +27 -63
- data/lib/samagotchi/memory_bundle/asset_installer.rb +92 -177
- data/lib/samagotchi/memory_bundle/builder.rb +12 -35
- data/lib/samagotchi/memory_bundle/bundle_hook.rb +6 -31
- data/lib/samagotchi/memory_bundle/file_actions.rb +193 -0
- data/lib/samagotchi/memory_bundle/file_digest.rb +13 -0
- data/lib/samagotchi/memory_bundle/file_state.rb +152 -0
- data/lib/samagotchi/memory_bundle/installed_bundle.rb +1 -1
- data/lib/samagotchi/memory_bundle/installed_copy.rb +13 -19
- data/lib/samagotchi/memory_bundle/installed_manifest.rb +10 -17
- data/lib/samagotchi/memory_bundle/installer.rb +212 -178
- data/lib/samagotchi/memory_bundle/manifest.rb +51 -58
- data/lib/samagotchi/memory_bundle/merger.rb +69 -65
- data/lib/samagotchi/memory_bundle/plugin_ref.rb +6 -5
- data/lib/samagotchi/memory_bundle/profile.rb +5 -5
- data/lib/samagotchi/memory_bundle/provenance.rb +26 -52
- data/lib/samagotchi/memory_bundle/remerge.rb +31 -14
- data/lib/samagotchi/memory_bundle/shas.rb +5 -8
- data/lib/samagotchi/memory_bundle/shipped_update.rb +51 -11
- data/lib/samagotchi/memory_bundle/status.rb +26 -30
- data/lib/samagotchi/memory_bundle/system_bundle.rb +39 -10
- data/lib/samagotchi/memory_bundle/trash.rb +28 -18
- data/lib/samagotchi/memory_bundle/uninstaller.rb +16 -11
- data/lib/samagotchi/memory_orphans.rb +4 -4
- data/lib/samagotchi/memory_paths.rb +102 -13
- data/lib/samagotchi/memory_usage.rb +1 -1
- data/lib/samagotchi/model_lookup.rb +75 -0
- data/lib/samagotchi/model_profile.rb +1 -0
- data/lib/samagotchi/models_command.rb +1 -1
- data/lib/samagotchi/note_command.rb +1 -1
- data/lib/samagotchi/participant_mode.rb +2 -1
- data/lib/samagotchi/plugin/api.rb +42 -10
- data/lib/samagotchi/plugin/loader.rb +75 -15
- data/lib/samagotchi/plugin/sessions.rb +1 -1
- data/lib/samagotchi/project_command.rb +167 -0
- data/lib/samagotchi/project_init.rb +69 -0
- data/lib/samagotchi/project_scope.rb +6 -4
- data/lib/samagotchi/prompt_files.rb +10 -7
- data/lib/samagotchi/reasoning_history.rb +14 -20
- data/lib/samagotchi/recap_place.rb +26 -0
- data/lib/samagotchi/reply_wait/liveness.rb +38 -0
- data/lib/samagotchi/reply_wait/poll.rb +44 -15
- data/lib/samagotchi/reply_wait/target.rb +113 -0
- data/lib/samagotchi/reply_wait.rb +22 -2
- data/lib/samagotchi/run_options.rb +1 -0
- data/lib/samagotchi/sampling_settings.rb +9 -16
- data/lib/samagotchi/self_report.rb +34 -35
- data/lib/samagotchi/send_command.rb +17 -23
- data/lib/samagotchi/session.rb +349 -441
- data/lib/samagotchi/session_access/contract.rb +1 -1
- data/lib/samagotchi/session_access/local.rb +5 -6
- data/lib/samagotchi/session_access/remote.rb +5 -3
- data/lib/samagotchi/session_field.rb +134 -0
- data/lib/samagotchi/session_inbox.rb +49 -1
- data/lib/samagotchi/session_manager/emptiness.rb +2 -1
- data/lib/samagotchi/session_manager/listing.rb +29 -100
- data/lib/samagotchi/session_manager.rb +2 -1
- data/lib/samagotchi/session_metrics.rb +7 -4
- data/lib/samagotchi/session_paths.rb +57 -0
- data/lib/samagotchi/session_retention.rb +2 -2
- data/lib/samagotchi/session_row.rb +200 -0
- data/lib/samagotchi/session_setup.rb +15 -12
- data/lib/samagotchi/sessions_command.rb +11 -129
- data/lib/samagotchi/steer.rb +10 -0
- data/lib/samagotchi/steer_cut_after.rb +7 -14
- data/lib/samagotchi/system_prompt.rb +20 -11
- data/lib/samagotchi/terminal_ui/attached_loop.rb +6 -26
- data/lib/samagotchi/terminal_ui/join_replay.rb +91 -8
- data/lib/samagotchi/terminal_ui/local_link.rb +2 -2
- data/lib/samagotchi/terminal_ui.rb +3 -1
- data/lib/samagotchi/testing/bundle.rb +5 -12
- data/lib/samagotchi/testing/install.rb +5 -4
- data/lib/samagotchi/testing/recorder.rb +1 -1
- data/lib/samagotchi/testing.rb +1 -1
- data/lib/samagotchi/thinking.rb +16 -21
- data/lib/samagotchi/tool_declarations.rb +1 -1
- data/lib/samagotchi/tool_response.rb +5 -3
- data/lib/samagotchi/tool_runner.rb +18 -1
- data/lib/samagotchi/toolkit_binding.rb +1 -4
- data/lib/samagotchi/toolkit_command.rb +1 -4
- data/lib/samagotchi/tools/delegate.rb +60 -51
- data/lib/samagotchi/tools/delegate_relay.rb +5 -5
- data/lib/samagotchi/tools/delegate_result.rb +1 -1
- data/lib/samagotchi/tools/delegate_wait.rb +41 -17
- data/lib/samagotchi/tools/list_sessions.rb +7 -7
- data/lib/samagotchi/update_command.rb +11 -7
- data/lib/samagotchi/verify_fresh.rb +7 -11
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/vision_support.rb +11 -14
- data/lib/samagotchi/web/app.rb +66 -21
- data/lib/samagotchi/web/message_display.rb +57 -7
- data/lib/samagotchi/web/participant_access.rb +1 -1
- data/lib/samagotchi/web/project_list.rb +3 -2
- data/lib/samagotchi/web/public/activity.js +16 -7
- data/lib/samagotchi/web/public/app.js +29 -8
- data/lib/samagotchi/web/public/bubbles.js +8 -3
- data/lib/samagotchi/web/public/cards_place.js +15 -0
- data/lib/samagotchi/web/public/commands.js +5 -1
- data/lib/samagotchi/web/public/data.js +4 -2
- data/lib/samagotchi/web/public/history_shape.js +220 -0
- data/lib/samagotchi/web/public/index.html +6 -1
- data/lib/samagotchi/web/public/project_picker.js +86 -4
- data/lib/samagotchi/web/public/recap_stamp.js +17 -0
- data/lib/samagotchi/web/public/reload_check.js +71 -0
- data/lib/samagotchi/web/public/stage_model.js +7 -5
- data/lib/samagotchi/web/public/stage_view.js +7 -3
- data/lib/samagotchi/web/public/stream_handlers.js +8 -2
- data/lib/samagotchi/web/public/timing.js +43 -2
- data/lib/samagotchi/web/public/turn_block.js +215 -30
- data/lib/samagotchi/web/public/turn_drawing.js +43 -0
- data/lib/samagotchi/web/public/turn_events.js +10 -1
- data/lib/samagotchi/web/public/turn_pieces.js +29 -0
- data/lib/samagotchi/web/reload_check_route.rb +95 -0
- data/lib/samagotchi/web/server.rb +4 -2
- data/lib/samagotchi/web/session_access_routes.rb +3 -3
- data/lib/samagotchi/web/session_control.rb +1 -1
- data/lib/samagotchi/web/session_hub.rb +9 -17
- data/lib/samagotchi/web/session_show.rb +64 -2
- data/lib/samagotchi/web/session_summary.rb +36 -24
- data/lib/samagotchi/worker.rb +28 -5
- data/lib/samagotchi/worker_link.rb +3 -0
- metadata +22 -5
- data/lib/samagotchi/hooks/bundle_loader.rb +0 -191
- data/lib/samagotchi/send_command/wait_target.rb +0 -85
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7be08e98d08c8d5fae428eee5ca7a1439c44cda4354693cc542e712cd4aa9ce2
|
|
4
|
+
data.tar.gz: '09a1d00545460e98a25a4076314b1202822ad7ab71377e17d5917d8a05634fa0'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0149b416ea8e87e57e95c1cbe32a313a18a9735c50655f74d59531c41ab3b7785c2d8a3a2a41b458fab6308e802496e381d9b2f2ad062105b683608c603c9b67'
|
|
7
|
+
data.tar.gz: d01cee2cdcfafdc1bb0f6f88e9b99ddbd85a72bda7c096b2e23ab67eeac68857836ab4bd557b4dc98397634be7b0495f17230e473ccd4695d1f189fd4da714df
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,73 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.158.0] - 2026-11-08
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- A folder in no git repository can be a chi project: `chi project init [DIR]` writes `DIR/.chi/project.yml`, and DIR and every subfolder share one project memories folder, group their sessions (`chi sessions list`, chi web's projects) and take `chi context --project`. `chi project` shows which project a folder is in. A git repository stays the project wherever there is one (init writes nothing there), and `$HOME` or a folder above it can't be marked. A folder chi already ran in at its top keeps its memories. A session in a subfolder of a marked project reads the AGENTS.md chain from the project's top, and `delegate`'s `cwd:` takes any folder of it (not a nested repository or marked project); sessions already running in a folder when it is marked keep the old project until `chi sessions restart`.
|
|
16
|
+
- chi web's project picker has a New project… row: type a folder path, and chi creates the folder if needed and marks it as a project, as `chi project init` does (a folder inside a git repository opens that repository's project).
|
|
17
|
+
|
|
18
|
+
### Removed
|
|
19
|
+
|
|
20
|
+
- Bundles can no longer ship class-file hooks (`hooks/*.rb` and the manifest's `hooks:`): a bundle hooks events from its `plugin.rb` with `chi.on` (docs/plugins.md). An installed bundle that still has them keeps its memories, rules, plugin and scripts, and chi says at the first turn that its hooks no longer load (`chi bundle status` and `chi update` say so too); installing or upgrading it is refused until they move. An older install's `on_error: fail_closed` class-file hook (chi-nah 0.1.x) stops guarding: move it to `chi.on(…, on_error: :fail_closed)` with `plugin: required: true` (docs/plugins.md). Your config's own `hooks:` are unchanged.
|
|
21
|
+
- The next install or upgrade of such a bundle from a source without hooks removes its old `hooks/` (an edited hook is copied to the trash first; `--dry-run` lists the hooks under "Would remove", and `chi update`'s plan names an edited one), and `chi bundle uninstall` still removes them. An external bundle whose source still ships hooks stays on the first-turn warning until its source moves them or you uninstall it. `chi bundle build` no longer copies an installed bundle's hooks, and `chi bundle check` reports a source's hooks as `hooks-retired`.
|
|
22
|
+
- The test kit's `Testing::Bundle#hooks_namespace` (the module a bundle's hook files were loaded in); `Testing::Install::Result#hook_failures` and `Registered#hooks` stay, filled from the plugin and config hooks.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- `chi bundle install --dev` no longer warns of a checksum mismatch for the bundle's memories (stale shas while you edit); `chi bundle check` still flags them.
|
|
27
|
+
- `chi update --dry-run` now shows the same memory checksum warnings as the update itself.
|
|
28
|
+
- A conflicted memory that chi retries at the same version (at start, or in `chi update`) now warns when the bundle's file doesn't match its manifest's sha256, as an install or an upgrade does.
|
|
29
|
+
- A session whose first message, last prompt or title held bytes that aren't valid UTF-8 (pasted binary, a broken terminal) no longer fails to save; the bad bytes are saved as `?`.
|
|
30
|
+
- A damaged turn-drawings file no longer stops a terminal from joining a session or chi web from showing it; the turn is drawn from the saved messages instead.
|
|
31
|
+
- `chi bundle try --json` no longer crashes when the answer or the trace holds non-ASCII text.
|
|
32
|
+
- `chi bundle upgrade` (and `chi update`) list a plugin or script that the new version adds under Installed, not Updated.
|
|
33
|
+
|
|
34
|
+
Update with `chi update`.
|
|
35
|
+
|
|
36
|
+
## [0.157.0] - 2026-11-08
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- `web.reload_check` (off by default): chi web checks each finished turn against a reload of it and logs `reload_mismatch` with the kinds that differed and the known divergences that explain them (no content).
|
|
41
|
+
- A bundle's plugin can guard tool calls fail-closed: `chi.on(:before_tool_call, on_error: :fail_closed)` denies the call its block raised on, and a plugin its manifest marks `required: true` (under `plugin:`) that fails to load (an edited file, an unmet `requires_chi`, a raise) makes chi deny every tool call until it is fixed, as a fail-closed bundle hook does. `chi bundle check` warns about a fail-closed hook whose plugin isn't marked required (docs/plugins.md).
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- `/llm-context`, `/stats` and the web's LLM context chip name where a value came from as the other settings do: `session` and `hosts.NAME` (were `the session` and `hosts entry 'NAME'`).
|
|
46
|
+
- `chi sessions list` prints one line wherever it runs: the `--live`, `--cwd` and `--format text` listings and `chi --remote NAME sessions list` show the plain list's state (`idle`, not `live`) and description (no folder prefix), and the plain list's footer. The plain list's `ctx N%` now rounds as the picker and chi web round it (it could read 1% apart).
|
|
47
|
+
- A delegating parent's wait says `worker_gone` 5 s after a child's worker dies (was 15 s); a child whose worker never starts is reported `worker_gone` ("its worker did not start") after the 30 s boot limit (or the wait's timeout, if shorter: then the child shows as `running`, as for any wait that timed out).
|
|
48
|
+
- In chi web, a long tool output's hover shows the same cut live as after a reload (the first 2000 characters of a file read, the start and end of other output).
|
|
49
|
+
- A turn nobody typed (a reminder, an attached context change, a finished task, a delegate report) has an id of its own, `wake-` and 16 hex digits: `chi send --wait --format json` names it as the `turn_id`, and the `--turn` hints carry it.
|
|
50
|
+
- `chi send --wait -m` to a session left running by a worker that died names the message's own id as the `turn_id` in `--format json`, where it named the running turn's.
|
|
51
|
+
- `chi bundle install` of a bundle already installed from a source that moved on now takes the new text of each memory you never edited, as `chi bundle upgrade` would, and records the new version; a memory you edited is still kept (`--force` or `chi bundle upgrade` brings the bundle's changes).
|
|
52
|
+
- The known-names and source-links bundles hook through their plugin (known-names 0.2.0, source-links 0.7.0); `chi update` installs them. Nothing changes in what they do.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- A `delegate` follow-up that the child's ending turn didn't take gets its own turn's reply, not the ended turn's.
|
|
57
|
+
- `chi send --wait` with no message on a wake turn (a reminder, a context change, a task's finish, a delegate report) names its `turn_id`, ends `canceled` (`worker_stopped`) when its worker dies in it, and `--turn` waits for it.
|
|
58
|
+
- A message or a delegate follow-up merged into a running turn as a steer waits for that turn's reply or end, which the worker now records, not for the session's next reply (a newer turn's could answer for it).
|
|
59
|
+
- `chi bundle uninstall` asks for `--force` before taking a memory you edited that has no base copy (chi compares it with the checksum its install recorded; with neither, it counts as edited), as it does for any edited file; it used to move it to the trash without asking.
|
|
60
|
+
- `chi bundle status` says `modified` for an edited memory that has no base copy; it said `ok` while the next upgrade left the file behind.
|
|
61
|
+
- `chi update`'s plan names every edited hook, rule, plugin file and script it replaces or removes, as its `Copied to the trash first` line does; it left out edited scripts and hooks installed with no recorded sha, and its row now says `a copy goes to the trash first` instead of `it wasn't loading`.
|
|
62
|
+
- `chi bundle install --dry-run` and `chi bundle upgrade --dry-run` report hooks, rules, the plugin and scripts as the real run does (`Would update`, `Would install`, `Up to date`); a changed hook showed as skipped, an unchanged rule or plugin as would install, and scripts not at all.
|
|
63
|
+
- `chi bundle install core --dry-run` (a profile's dry run) no longer names a hook it would replace as your own kept file.
|
|
64
|
+
- `chi bundle upgrade --dry-run` lists a memory that already has the bundle's text as up to date, as the upgrade itself does; it listed it as skipped.
|
|
65
|
+
- `chi bundle upgrade` (and `chi update`'s plan) leaves behind a memory that `chi bundle status` calls `modified` but whose base copy equals it, as it does any edit it can't merge; it replaced the file with the bundle's text and kept no copy.
|
|
66
|
+
- `chi bundle upgrade` (and `chi update`'s plan) takes the bundle's new text for a memory you never edited that has no base copy (chi compares it with the checksum its install recorded), as for any unedited memory; it left the file behind as a conflict while `chi bundle status` called it `ok`.
|
|
67
|
+
- A bundle memory whose bytes don't match the manifest's `files:` sha now warns `Checksum mismatch` when `chi bundle upgrade` (or a re-install from a source that moved on) brings its new text or merges it into your edit, as a first install does: a bad download warns on an upgrade too. A `--dry-run` checks the bundle's file it would write, a memory or a hook, so it warns as the real run does and no longer blames a memory you edited (`install --force --dry-run`) or the hook an upgrade would replace. `chi update` and `chi bootstrap` show these warnings on the bundle's row (a system bundle install, update or restore, and a shipped bundle's update); they dropped them.
|
|
68
|
+
- A system bundle memory chi puts back after you deleted it is checked against the manifest's `files:` sha too, and warns `Checksum mismatch` when its bytes differ, as an installed one does.
|
|
69
|
+
- A context window given with `--context-window-tokens` to a one-shot run (`-p … --non-interactive`) is named `cli`, not `config`, where its source shows: the debug log, and chi web's context tooltip for that session.
|
|
70
|
+
- A tool row's duration is the same live, after a reload and in the attached terminal (each timed the call with its own clock).
|
|
71
|
+
- chi web draws a finished turn after a reload or a reconnect exactly as it drew it live: the empty answer's "asking again" row stays in its step, a failed turn keeps its last step, a card the turn showed comes back where it was, and the reminders that went into a turn are shown. Turns from before this release, or run by a worker not yet restarted, show as before.
|
|
72
|
+
- `chi --attach` shows the last turn's tool rows as they ran (status, duration, retries).
|
|
73
|
+
- A saved recap is placed after the turn it covers, by that turn's id, where counting turns could put it a turn off (after a check-in, for one).
|
|
74
|
+
- In chi web, a turn that fails after its tool steps shows the same time on its timing line live as after a reload (the turn record's, as a canceled turn does).
|
|
75
|
+
|
|
76
|
+
Update with `chi update` (known-names 0.2.0, source-links 0.7.0).
|
|
77
|
+
|
|
11
78
|
## [0.156.0] - 2026-11-08
|
|
12
79
|
|
|
13
80
|
### Changed
|
|
@@ -5798,7 +5865,9 @@ and long-lived sessions.
|
|
|
5798
5865
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
5799
5866
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
5800
5867
|
|
|
5801
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
5868
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.158.0...HEAD
|
|
5869
|
+
[0.158.0]: https://github.com/dm1try/samagotchi/compare/v0.157.0...v0.158.0
|
|
5870
|
+
[0.157.0]: https://github.com/dm1try/samagotchi/compare/v0.156.0...v0.157.0
|
|
5802
5871
|
[0.156.0]: https://github.com/dm1try/samagotchi/compare/v0.155.0...v0.156.0
|
|
5803
5872
|
[0.155.0]: https://github.com/dm1try/samagotchi/compare/v0.154.1...v0.155.0
|
|
5804
5873
|
[0.154.1]: https://github.com/dm1try/samagotchi/compare/v0.154.0...v0.154.1
|
data/README.md
CHANGED
|
@@ -217,7 +217,7 @@ once, for the session, for the repo, or for the whole rule in the repo.
|
|
|
217
217
|
- [chi as a sub-agent](docs/sub-agent.md): `chi send --wait --format json`, `chi answer`, instructions for a parent agent
|
|
218
218
|
- [Desktop helper](docs/desktop.md): `chi desktop`, the macOS "Send to chi" Service and hotkey
|
|
219
219
|
- [Guardrails](docs/guardrails.md): allow / ask / deny for tool calls, rules, approvals
|
|
220
|
-
- [Hooks](docs/hooks.md):
|
|
220
|
+
- [Hooks](docs/hooks.md): config hooks and a bundle plugin's hooks
|
|
221
221
|
- [Plugins](docs/plugins.md): bundle plugins (commands, tools, hooks)
|
|
222
222
|
- [Bundles](docs/bundles.md): what each shipped bundle does (btw, mcp, cost-cap, claude-peer, skills…), its commands and settings
|
|
223
223
|
- [Writing a bundle](docs/bundle-authoring.md): `chi bundle new`, `test`, `check`, `try`, `install --dev`
|
data/bin/chi
CHANGED
|
@@ -102,7 +102,9 @@ SUBCOMMANDS = {
|
|
|
102
102
|
# other machines' chi web, for chi --remote NAME (add, ls, rm)
|
|
103
103
|
"remote" => ["samagotchi/remote_command", "RemoteCommand"],
|
|
104
104
|
# the chi home: the Ruby every chi launch boots (set, doctor)
|
|
105
|
-
"home" => ["samagotchi/home_command", "HomeCommand"]
|
|
105
|
+
"home" => ["samagotchi/home_command", "HomeCommand"],
|
|
106
|
+
# this folder's project; init marks a folder in no git repository (.chi/project.yml)
|
|
107
|
+
"project" => ["samagotchi/project_command", "ProjectCommand"]
|
|
106
108
|
}.freeze
|
|
107
109
|
# chi --remote NAME <command> (or CHI_REMOTE=NAME): the session commands
|
|
108
110
|
# against another machine's chi web; what runs here only is refused (exit 2).
|
|
@@ -263,6 +265,7 @@ if options[:web]
|
|
|
263
265
|
exit Samagotchi::Web::Server.launch(port: port, scope: options[:scope] || "project", open_browser: options[:web_open],
|
|
264
266
|
markdown: markdown, new_token: options[:new_token], tunnel: options[:tunnel],
|
|
265
267
|
working_set: Samagotchi::Config.get("web.working_set"),
|
|
268
|
+
reload_check: Samagotchi::Config.get("web.reload_check"),
|
|
266
269
|
annotate_presets: Samagotchi::Config.get("web.annotate_presets"),
|
|
267
270
|
editor: Samagotchi::Config.get("web.editor"),
|
|
268
271
|
start_dir: options[:start_dir] || Samagotchi::Config.get("web.start_dir"),
|
data/docs/architecture.md
CHANGED
|
@@ -51,7 +51,7 @@ A compact visual overview of the current architecture, then the core API in pros
|
|
|
51
51
|
▼
|
|
52
52
|
┌──────────────────────────────────────────────────────────────────────────────────┐
|
|
53
53
|
│ Persistence │
|
|
54
|
-
│ Project: ~/.config/samagotchi/memories/projects/<repo>_<hash>/ (per
|
|
54
|
+
│ Project: ~/.config/samagotchi/memories/projects/<repo>_<hash>/ (per project) │
|
|
55
55
|
│ System: ~/.config/samagotchi/memories/ │
|
|
56
56
|
└──────────────────────────────────────────────────────────────────────────────────┘
|
|
57
57
|
```
|
|
@@ -104,7 +104,7 @@ terminal renders the events it gets over the Bridge.
|
|
|
104
104
|
| Turn | `TurnContext`, `TurnState`, `Engine::Turn` | One turn's frozen `TurnContext` (id, session, origin, author, participant mode, controller, folders, git facts, settings, model key/name and the tool surface (`Tools::ToolSurface`) from `generate`): built by `Engine#begin_turn`, published with the running flag by `TurnState` (the only way another thread reads the running turn: `Engine#turn_context` / `#last_turn_context`), handed explicitly down the tool path (`ModelBackend#complete(context:)`, `ToolRunner#run`, `Guardrails::Gate#evaluate`, `KernelLoop#dispatch_tool_call`). `Engine::Turn` keeps only the lifecycle state ([internals/engine.md](internals/engine.md), "Turn and TurnContext"). The turn stages (`TurnStages::ToolkitSuggestion`, `TurnStages::ContextJudge`, `TurnStages::Objectives`, `TurnStages::Warmup`, `TurnStages::VerifyAnchors`, `lib/samagotchi/turn_stages/`): the steps that keep state across the turn, built from the Engine-lifetime objects and called by name from the turn's skeleton with the values of the call (a `SystemOne::Recorder`, the sessions dir), not callbacks into the Engine (internals/engine.md, "Turn stages"). |
|
|
105
105
|
| 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. |
|
|
106
106
|
| 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. |
|
|
107
|
-
| 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
|
|
107
|
+
| 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 guardrail and plugin loaders read ([internals/bundles.md](internals/bundles.md)). |
|
|
108
108
|
| Background | `Samagotchi::Worker`, `Samagotchi::SessionManager` | `SessionManager` (`session_manager.rb`, its parts in `session_manager/`: spawn · worker_command · listing · delivery · lifecycle · removal · emptiness) forks/spawns one worker process per session. The worker process's main (owner lock, detach, signals, project env, what it does as it leaves) is `WorkerBoot` (`worker_boot.rb`), which SessionManager loads only as a worker boots (its `run_session_loop` forwarder); 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. |
|
|
109
109
|
| 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`. |
|
|
110
110
|
| Sessions | `Samagotchi::Session`, `SessionManager` | File `sessions/<uuid>.json` + sidecar `input/`/`output/`; retention 14d/500, `updated_at desc`, lazy sweep. |
|
|
@@ -420,7 +420,7 @@ project (the list, the events stream and a new chat follow it), `?scope=all` eve
|
|
|
420
420
|
`data-scope-dir`, which the page reads when the URL has no `?dir`), else every session. The page never
|
|
421
421
|
redirects, so the `?token=` trade's 303, a link code's `#code=` and the Home Screen app's `start_url` `/`
|
|
422
422
|
all land on the start project; a push opens its session's own project (`/?dir=<root>#/s/<id>`, or
|
|
423
|
-
`/?scope=all#/s/<id>` outside a
|
|
423
|
+
`/?scope=all#/s/<id>` outside a project: no repository or marked folder). `?dir=` beats `?scope=all`. A session created
|
|
424
424
|
without a folder starts in the start folder.
|
|
425
425
|
Files stay the source of truth and workers don't know the hub. Its watcher is a 1 s tick that
|
|
426
426
|
stats the sessions dir (every session writer goes tmp + rename, which bumps the dir's mtime) and
|
|
@@ -428,14 +428,15 @@ each `<id>/` folder (recap.json, bridge.json, the stopped and archived markers),
|
|
|
428
428
|
moved through `Session.summary_from_file`. Liveness is probed, since a killed owner leaves no
|
|
429
429
|
file trace: the owner lock every tick for the sessions the projection believes owned, and every
|
|
430
430
|
session every 10 s, so a `kill -9` shows within a second. The summary (`Web::SessionSummary`,
|
|
431
|
-
shared with `/api/sessions` and the session view
|
|
431
|
+
shared with `/api/sessions` and the session view; built on the session's `SessionRow`, the one row every list
|
|
432
|
+
reads, so the page, `chi sessions list` and `/children` agree on status, liveness and a waiting question) carries `owner`, `project_root` and
|
|
432
433
|
`bridge_up` (`WorkerLink` answers Live: a worker holds the lock and its sidecar names its pid; the page attaches its stream on it), and
|
|
433
434
|
from that sidecar `worker_version` (the chi the worker runs) and `worker_features`
|
|
434
435
|
(`Bridge::FEATURES`, what a client may ask of it beyond the routes: `restart`, `task_stop`, `reparent`, `unqueue`,
|
|
435
436
|
`delivery`, a worker that queues a message for after the turn; `SessionManager.deliver_turn` and
|
|
436
437
|
the attached TUI refuse a queue to a worker without it, which would steer; `turn_ids`, a worker whose running
|
|
437
438
|
turn's mark, continue turn and Stop carry the turn's `enqueued_id`, which `chi answer`, `chi send --wait` with no
|
|
438
|
-
message and `delegate_result` rely on through `ReplyWait.own_turn`). A worker's Bridge snapshot
|
|
439
|
+
message and `delegate_result` rely on through `ReplyWait.own_turn` (a wake or reminder turn has one too, worker-minted `wake-…`; a steer's merge is recorded in `input/merged/`, read by `ReplyWait::Poll#follow_merge`); every wait's binding is one `ReplyWait::Target`, built by its caller's constructor). A worker's Bridge snapshot
|
|
439
440
|
names its `chi_version` too.
|
|
440
441
|
`POST/DELETE /api/sessions` and `/stop` rescan the session before answering (`SessionHub#touch`).
|
|
441
442
|
`GET /api/sessions` is the hub's projection too (its sort, paging and total). `Server` always builds
|
|
@@ -457,8 +458,9 @@ model: [internals/remote-sessions.md](internals/remote-sessions.md).
|
|
|
457
458
|
| Route | Permission | Body / params | Answer | Refusals |
|
|
458
459
|
|---|---|---|---|---|
|
|
459
460
|
| `GET /api/sessions/resolve?id=` | owner | an id or a unique prefix | 200 `{id}` | 404 `not_found`; 400 `ambiguous_id` with `ids` |
|
|
460
|
-
| `GET /api/sessions/summaries` | owner | `dir` (a folder: its project; none: every project), `cwd`, `live=1`, `archived=1`, `tests=0`, `sort`, `order`, `limit` | 200: the rows `chi sessions list` prints (`
|
|
461
|
-
| `GET /api/projects?dir=` | owner | optional page-scope folder | 200: project rows (`Web::ProjectList`: the hub's projects plus the start project) with counts, roots, default/current marks; no `dir`: no current project | 400 `invalid_dir`; 503 `no_hub` |
|
|
461
|
+
| `GET /api/sessions/summaries` | owner | `dir` (a folder: its project; none: every project), `cwd`, `live=1`, `archived=1`, `tests=0`, `sort`, `order`, `limit` | 200: the rows `chi sessions list` prints (`SessionRow#to_summary_h`, 28 keys in a fixed order: `status`, `live`, `busy`, `owner`, `recap`, `ctx_pct`, `waiting`, `waiting_id`, `title`, `preview`, …) | 400 `invalid_dir`, `invalid_cwd` |
|
|
462
|
+
| `GET /api/projects?dir=` | owner | optional page-scope folder | 200: project rows (`Web::ProjectList`: the hub's projects plus the start project and current project, even without sessions) with counts, roots, default/current marks; no `dir`: no current project | 400 `invalid_dir`; 503 `no_hub` |
|
|
463
|
+
| `POST /api/projects` | owner | `{dir}` (absolute folder; `~` and `~/` expand against the server's home) | 200 `{outcome, root, dir}` (`created`, `already_marked`, or `git`) | 400 `invalid_json`, `invalid_dir`; 422 `above_home`, `write_failed` |
|
|
462
464
|
| `POST /api/sessions` (more fields) | owner | `toolkit`, `tools`, `no_tools`, `parent_answers`; `client_id` (`cli:send`/`cli:answer`: the first line is checked as chi send checks it); `check_vision: true` (images follow) | 201 adds `model_warning`, `parent_answers_warning` (a level looser than config.yml's, capped) and `first_turn_id` (the id the prompt it starts with gets for its turn; null for an `idle` create) | 400 `invalid_toolkit`, `invalid_parent_answers`, `invalid_continues` (beside `continues`); 403 `parent_answers_refused`, `parent_continue_refused`; 422 `no_vision` |
|
|
463
465
|
| `POST /api/sessions/:id/turn` (more fields) | owner | `client_id` as above; `check_vision: true` with `images` | as before | 403 `parent_answers_refused`, `parent_continue_refused`; 422 `no_vision` |
|
|
464
466
|
| `POST /api/sessions/:id/wait/prepare` | owner | `question_id` (absent: the pending one; `null`: none), `turn`, `created`, `busy` (+ `queue`) | 200 `{session_id, cursor, baseline: {messages, question_id, last_turn}, own_turn, known_turn, running, live, settled, last_turn_id}` (`WaitStart`) | 409 `busy`, `waiting` (`SendCommand::Busy`'s words, and its fields: `question`, `parent_strategy`) |
|
|
@@ -509,8 +511,9 @@ every lookup goes through `Session.resolve!` (an id or a unique prefix), and eve
|
|
|
509
511
|
|
|
510
512
|
A model ref (`--model`, `/model`, `default.model`, an alias's target) is parsed
|
|
511
513
|
by one pure resolver, `ModelRef.parse` (host prefix, alias), given the configured
|
|
512
|
-
hosts and aliases; `HostRegistry`
|
|
513
|
-
|
|
514
|
+
hosts and aliases; `HostRegistry` (one per process for commands and chi web:
|
|
515
|
+
`HostRegistry.current`) routes a name that names no host (its model index after
|
|
516
|
+
`/models`) and builds the `ModelTarget`.
|
|
514
517
|
|
|
515
518
|
Engine picks the loop from the effective model's host: `EffectiveModel.of` resolves it (`HostRegistry#resolve`)
|
|
516
519
|
on every read, never kept, since config.yml and a model listing can move it without a `/model`
|
|
@@ -616,8 +619,9 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
616
619
|
| Worker | `worker.rb` (`worker_boot.rb`, `worker_idle_exit.rb`, `worker_inbound.rb`, `worker_signals.rb`, `worker_wakes.rb`, `worker_task_wakes.rb`, `task_watch.rb`) | A session's background process: builds the `Engine` and `Bridge`, runs queued turns and the wake turns nobody typed (delegate reports, a background task that finished unseen: [Finish wake](internals/background-tasks.md#finish-wake), attached context), exits when idle. A spawned one traps TERM, HUP and INT (`WorkerSignals`, installed by `WorkerBoot.run_session_loop` when `SAMAGOTCHI_WORKER_PROCESS=1`): the running turn stops as a Stop with reason `signal`, is saved, and the worker leaves (`:signal`, exit 0; a new worker only for input already queued). A running turn is checkpointed at its iteration boundaries (`TurnCheckpoint`, the `interrupted_turn` mark), and the next worker settles a turn its predecessor died in (`TurnCheckpoint.settle`). The session is saved from the turn's thread, Bridge threads and a signal's thread; `Session#save` takes a per-session lock around its snapshot and write, so an older snapshot never lands over a newer one. |
|
|
617
620
|
| Config | `config.rb`, `config/restart_watch.rb` | Every setting as an `Entry`: env, config.yml and CLI layers ([configuration.md](configuration.md)); the notice a worker or chi web gets when config.yml changes a setting it reads only at its start. With `log.rb` it is the bottom layer: nothing it references reaches back to it, so `hosts:` and `models:` entries parse next to their types (`HostConfig.all`, `ModelSettings.all`). |
|
|
618
621
|
| Paths | `paths.rb` (`Paths`) | The XDG base dirs chi's files live under, read from the env on every call: `Paths.state_home` (`$XDG_STATE_HOME`, else `~/.local/state`) and `Paths.config_home` (`$XDG_CONFIG_HOME`, else `~/.config`), both defaults under `Dir.home`; a blank variable counts as unset, a relative one is made absolute from the current directory. `Paths.tilde` shows a path with `~` for the home folder. `SessionManager` hands a spawned worker the spawner's `XDG_STATE_HOME` / `XDG_CONFIG_HOME`, when set, made absolute, so a relative one isn't read from the session's folder. |
|
|
619
|
-
| MemoryBundle | `memory_bundle.rb`, `memory_bundle/{installer,builder,installed_bundle,plugin_ref,bundle_hook}.rb` (`Installer`, `Builder`, `InstalledBundle`, `PluginRef`, `BundleHook`) | Installing, building and reading bundles of memories,
|
|
622
|
+
| MemoryBundle | `memory_bundle.rb`, `memory_bundle/{installer,builder,installed_bundle,plugin_ref,bundle_hook}.rb` (`Installer`, `Builder`, `InstalledBundle`, `PluginRef`, `BundleHook`) | Installing, building and reading bundles of memories, rules, plugins and scripts (`BundleHook`: an older record's retired class-file hook). |
|
|
620
623
|
| Bundle authoring | `bundle_command.rb` (`BundleCommand`), `bundle_command/{scaffold,check,test_run}.rb`, `bundle_command/try/{run,sandbox,trace}.rb`, `testing.rb` + `testing/` (the test kit) | `chi bundle new`, `check`, `test` and `try`, and the kit a bundle's tests load it with ([bundle-authoring.md](bundle-authoring.md), [internals/bundles.md](internals/bundles.md)). |
|
|
624
|
+
| Session file | `session.rb` (`Session`, `Session::FIELDS`), `session_field.rb` (`SessionField`), `session_paths.rb` (`SessionPaths`), `session_setup.rb` (`SessionSetup`) | A session's `<uuid>.json`: one `SessionField` row per key (default, cast, what the file gets; the codec on its type), from which `Session.new`, `.from_h` and `#to_h` are built; `SessionPaths` is where the file and the session's dir are and the id rule, a leaf `Session` extends (so `ArchiveStore`, `ContextSources` and `ParticipantMode` name no `Session` constant; the first two still require session.rb at load, `ParticipantMode` lazily); `SessionSetup` the settings a fork and a continue carry, applied by member name. See [sessions.md](sessions.md#session-file). |
|
|
621
625
|
| Session config (`--set`) | `session_config.rb` (`SessionConfig`, `SessionConfig::Settings`) | A session's own settings as one value (`Session#settings`, `SessionSetup#settings`): `core`, the `--set KEY=VALUE` values of the core keys marked `session: true` (`Config::Entry`), typed by `Config.coerce!` and read first through `Config.get(key, session:)` (`RecapSetup`; `Engine#session=` rebuilds the recap job, `IdleScheduler#replace_job`), file key `config_settings`; `bundles`, the `--set BUNDLE.KEY=VALUE` values, checked against the manifest's `session_settings:`, laid over `bundles: <name>:` in `ctx.settings` ([plugins.md](plugins.md)), file key `bundle_settings`. `SessionConfig.clash` refuses a bundle setting named like a core one (install, `chi bundle check`). See [configuration.md](configuration.md#per-session-settings). |
|
|
622
626
|
| Plugin API | `plugin/api.rb` (`Plugin::Api`), `plugin/tool_spec.rb` (`Plugin::ToolSpec`: a checked tool declaration, how it is registered), `plugin/loader.rb`, `plugin/context.rb` (`ctx`), `plugin/http.rb` + `plugin/http_transport.rb` (`ctx.http`), `plugin/card.rb` (`Plugin::Card`) | What a bundle's plugin registers: tools, commands, annotation actions, hooks, services, toolkits, peer sources; what its handlers get as `ctx` ([plugins.md](plugins.md)). |
|
|
623
627
|
| Peer bundles' base | `plugin/peer.rb` (`Plugin::Peer`) | What claude-peer and codex-peer share (the send tool, the command, the cards, payloads); each bundle's subclass sets its strings and transport ([bundles.md](bundles.md#the-claude-peer-bundle)). |
|
|
@@ -634,7 +638,7 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
634
638
|
| LLM context strategies | `llm_context_strategy.rb`, `llm_context_view.rb`, `llm_context_stale.rb`, `llm_context_forget.rb` | What a request sends of the history (none, stale, forget) ([internals/llm-context-forget.md](internals/llm-context-forget.md)). |
|
|
635
639
|
| Session chains | `session_continue.rb` (`SessionContinue`), `session_chain.rb` (`SessionChain`) | A session that continues an earlier one. `SessionChain.opener_for` gives the text web `continue →` prefills in the new link: the previous link's own first typed message when that link continues one itself, else nil (the 201's `opener`; not saved) ([sessions.md](sessions.md)). |
|
|
636
640
|
| Review sessions | `review_start.rb` (`ReviewStart`), `session_review.rb` (`SessionReview`, the session's `review` field), `review_command.rb` (`ReviewCommand`, `chi review`), `review_apply.rb` (`ReviewApply`) | A session made to be shared: idle, its subjects project files checked by `Guardrails::ReviewPaths`, a fork of a working session from its recap (`--from`); Apply quotes a participant's review turn into the owner's composer ([sessions.md](sessions.md#review-sessions), [internals/participants.md](internals/participants.md)). |
|
|
637
|
-
| chi web's routes | `web/app.rb` (`Web::App`: the gate, `ROUTES`, the shared helpers), `web/message_display.rb` (`Web::MessageDisplay`: saved messages and cards as display items, `POST /api/render`), `web/session_show.rb` (`Web::SessionShow`: `GET /api/sessions/:id` with its `cards`, `tail` and `timing` re-reads, `GET …/output`, the timing payload), `web/session_create.rb` (`Web::SessionCreate`: `POST /api/sessions`, a continue, a review fork), `web/session_control.rb` (`Web::SessionControl`: answer, command, turn and images, cancel, stop, restart, archive, delete), `web/push_routes.rb` (`Web::PushRoutes`: `/api/push`, its subscriptions, prefs, test and presence), `web/block_renderer_routes.rb` (`Web::BlockRendererRoutes`: `GET /api/block_renderers` and one renderer's file, [internals/block-renderers.md](internals/block-renderers.md)) | The handlers `App`'s `ROUTES` name, in the file that holds their kind; each mixin is included in `App` and reads its helpers and ivars, so `app.send(:handle_show, …)` and the specs that stub `App` methods work as before. |
|
|
641
|
+
| chi web's routes | `web/app.rb` (`Web::App`: the gate, `ROUTES`, the shared helpers), `web/message_display.rb` (`Web::MessageDisplay`: saved messages and cards as display items, `POST /api/render`), `web/session_show.rb` (`Web::SessionShow`: `GET /api/sessions/:id` with its `cards`, `tail` and `timing` re-reads, `GET …/output`, the timing payload), `web/session_create.rb` (`Web::SessionCreate`: `POST /api/sessions`, a continue, a review fork), `web/session_control.rb` (`Web::SessionControl`: answer, command, turn and images, cancel, stop, restart, archive, delete), `web/push_routes.rb` (`Web::PushRoutes`: `/api/push`, its subscriptions, prefs, test and presence), `web/block_renderer_routes.rb` (`Web::BlockRendererRoutes`: `GET /api/block_renderers` and one renderer's file, [internals/block-renderers.md](internals/block-renderers.md)), `web/reload_check_route.rb` (`Web::ReloadCheckRoute`: `POST /api/sessions/:id/reload_check`, the opt-in `web.reload_check`'s counts from the page's `reload_check.js`, 204 and one `reload_checked` log line, with `reload_mismatch`, its `kinds`, `excused` (ACCEPTED ids) and `explained` when the turn read otherwise after a reload; the worker's version is chi web's own view, its sidecar) | The handlers `App`'s `ROUTES` name, in the file that holds their kind; each mixin is included in `App` and reads its helpers and ivars, so `app.send(:handle_show, …)` and the specs that stub `App` methods work as before. |
|
|
638
642
|
| Web Push | `web/push.rb` (`Web::Push`: `Runtime`, `preflight!`, the `web.push.*` settings), `web/push/crypto.rb` (`Push::Crypto`: RFC 8291 aes128gcm, RFC 8292 VAPID), `web/push/store.rb` (`Push::Store`, `Store::Sub`: `web-push/vapid.pem`, `subscriptions.json`), `web/push/client.rb` (`Push::Client`, `Client::Result`), `web/push/attention.rb` (`Push::Attention`: notify.js's rules in Ruby, shared cases in `spec/fixtures/attention_cases.json`), `web/push/presence.rb` (`Push::Presence`: the pages' "in front" reports), `web/push/notifier.rb` (`Push::Notifier`, a hub subscriber with a sender thread), `web/push_routes.rb` (`Web::PushRoutes`), `private_files.rb` (`PrivateFiles`, shared with the grants), `public/sw.js`, `public/push.js`, `public/manifest.webmanifest` | chi web pushes what the tab notifies for (approvals, questions, step-limit questions, cards, failed turns; done turns to a device that asks) to the owner's Home Screen app over an https public URL: the Notifier turns the hub's new attentions into show pushes after a hold, unless a chi web page is in front, at most 30 an hour, with one retry and a restart catch-up (`sent.json`) (each carries the keys still open, and the badge; no close push: every push shows a notification); the bell (`notifications.js`) subscribes the device, and the service worker and the page close the answered ones. See [internals/web-push.md](internals/web-push.md). |
|
|
639
643
|
| chi web's updates | `web/update_check.rb` (`Web::UpdateCheck`), `web/update_ops.rb` (`Web::UpdateOps`), `web/auto_update.rb` (`Web::AutoUpdate`) | The RubyGems checker and its `update_check.json`; the install, worker-restart and chi-web-restart operations (one at a time) the owner's routes and AutoUpdate share; `update.auto: install`'s thread (install when no turn runs, then idle workers and chi web). See [configuration](configuration.md#unattended-updates-updateauto). |
|
|
640
644
|
| Behind an auth proxy | `web/public_url.rb` (`Web::PublicUrl`: `web.public_url`, `web.proxy.identity_header`, `web.proxy.owner`), `web/proxy_gate.rb` (`Web::ProxyGate`, mixed into App; `RawHeaderNames`, prepended to WEBrick's request by `Web::Server`), `web/link_codes.rb` (`Web::LinkCodes`: the links' one-time codes), `proxy_trace.rb` (`ProxyTrace`), `web/public/token_fragment.js`, `web/public/auth_lost.js`, `web/tunnel.rb` + `web/tunnel/tailscale.rb` (`Web::Tunnel`, `Web::Tunnel::Tailscale`: `chi web --tunnel tailscale`, Tailscale Serve set for one run and the PublicUrl it makes) | Experimental: chi web behind an auth proxy. Every request needs the token; a proxied one's owner also needs the identity header (one clean value under one name); the `__Host-` cookie, an absolute `Location` from the public URL, https links with a one-time code in the fragment; the page's lost-sign-in banner. Bridges refuse proxy traces ([configuration.md](configuration.md#behind-an-auth-proxy)). |
|
|
@@ -646,11 +650,13 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
646
650
|
| Tool output cut | `tool_output_cut.rb` (`ToolOutputCut`), `tool_output_files.rb` (`ToolOutputFiles`) | A tool's output over `max_tool_output_chars` (a `memory_read`'s: `memory.read_max_chars`, 0 = none, plus a guard at half a known window), cut by the tool's policy; an execute's whole output saved in the session's `tool_output/` folder ([internals/tool-output-limits.md](internals/tool-output-limits.md)). |
|
|
647
651
|
| Steer delivery | `steer.rb` (`Steer`), `delivery.rb` (`Delivery`), `steer_cut.rb` (`SteerCut`), `generation_phase.rb`, `waiting_steer.rb`, `steer_cut_after.rb` (`SteerCutAfter`), `cut_policy.rb` (`CutPolicy`) | A message for a running turn: at the next boundary, cutting a thinking-only generation, or queued for the turn's end ([internals/engine.md](internals/engine.md)). |
|
|
648
652
|
| Prompt files | `prompt_files.rb` (`PromptFiles`) | The AGENTS.md chain (root → cwd) and the appended files the system prompt carries. |
|
|
649
|
-
| Model settings | `effective_model.rb` (`EffectiveModel`, `ModelChoice`), `model_profile.rb` (`ModelProfile`), `model_settings.rb`, `sampling_settings.rb`, `model_catalog.rb` (`ModelCatalog`), `model_notes.rb` (`ModelNotes`) | The effective model's settings as one snapshot per read, a model's prompt format, its `models:` entry, its request parameters, the pickable model rows (`chi models`, `/api/models`), the notes its prompt loads. |
|
|
653
|
+
| Model settings | `effective_model.rb` (`EffectiveModel`, `ModelChoice`), `model_lookup.rb` (`ModelLookup`: every layer's input), `model_profile.rb` (`ModelProfile`), `model_settings.rb`, `sampling_settings.rb`, `model_catalog.rb` (`ModelCatalog`), `model_notes.rb` (`ModelNotes`) | The effective model's settings as one snapshot per read, a model's prompt format, its `models:` entry, its request parameters, the pickable model rows (`chi models`, `/api/models`), the notes its prompt loads. |
|
|
650
654
|
| Session settings | `session_setting.rb` (`SessionSetting`), `session_model_settings.rb` (`SessionModelSettings`), `level_setting_command.rb` (`/thinking`, `/reasoning-history`), `llm_context_command.rb`, `toolkit_command.rb`, `thinking_notices.rb` (`ThinkingNotices`) | A session's own llm_context, thinking, reasoning_history and toolkit: their chips (session state, `/stats`, `:command_ran`, the web), the commands that set them, the thinking level's notices. |
|
|
651
655
|
| Dialects | `llm/dialect.rb` (`LLM::Dialect`) | What an `api: anthropic` provider's `/v1/messages` does differently (`dialect: fireworks`) ([internals/anthropic.md](internals/anthropic.md)). |
|
|
652
656
|
| Logging | `log.rb` (`Log`), `log_subscriber.rb` (`LogSubscriber`), `log_path.rb` (`LogPath`), `log_line.rb` | The debug log: tagged records, a session's event trail, where the file goes ([configuration.md](configuration.md#debug-log-file)). |
|
|
653
657
|
| Stores | `reminder_store.rb` (`ReminderStore`), `recap_store.rb` (`RecapStore`) | A session's reminders, and its idle recap (`recap.json`). |
|
|
658
|
+
| Reply waits | `reply_wait.rb` (`ReplyWait`, `GONE_AFTER`: the one dead-worker rule), `reply_wait/poll.rb` (`ReplyWait::Poll`, one look per poll), `reply_wait/target.rb` (`ReplyWait::Target`: which turn a wait binds, cursor, baseline, `owner_grace`; `first_message`, `message`, `wait_only`, `answer`, `participant`, `from_cursor`), `reply_wait/liveness.rb` (`ReplyWait::Liveness`: one owner and link read per look; `#owner?` for gone, `#worker_owned?` for an open question) | `chi send --wait`, `chi answer`, a participant's wait, the delegate tools and delegate reports wait through `ReplyWait.call(id, **target.to_h, …)` ([sub-agent.md](sub-agent.md)). |
|
|
659
|
+
| Session rows | `session_row.rb` (`SessionRow`) | A session as the lists see it: scalar facts only, built by `SessionManager.session_rows` (one owner, link, recap and analytics read each), `#to_summary_h` the summaries route's body and `.from_summary_h` a remote's rows read back, `#cli_line` the one `chi sessions list` line, `.running_or_starting?` the delegates' and Verify fresh's "running" (a 15 s grace for a worker on its way). A leaf: never session_manager or web. |
|
|
654
660
|
| Setup and update | `bootstrap_command.rb`, `bootstrap/`, `update_command.rb`, `gem_update.rb` | `chi bootstrap` (first config.yml, system bundle, core profile) and `chi update` (the gem, shipped bundles, the macOS helper). |
|
|
655
661
|
| Process groups | `process_group.rb` (`ProcessGroup`) | A command in a process group of its own, stopped as a group (TERM, grace, KILL): execute, tasks, context fetches, the mcp bundle's servers. |
|
|
656
662
|
| Desktop | `desktop.rb`, `desktop/macos.rb`, `desktop_command.rb`, `desktop/macos/*.swift` | `chi desktop`, the macOS "Send to chi" helper ([desktop.md](desktop.md)). The helper's Swift side: the panel (`Panel.swift`), the chi CLI runner (`ChiRunner.swift`), the session rows and the chi calls a send makes (`Sessions.swift`: `SendPlan`; `ChiHelper --sessions` and `--send-plan` are their CLI seams), agent terminals behind `AgentTerminal` (`AgentTerminal.swift`, `Kitty.swift`, `Tmux.swift`; `ChiHelper --agents` is their CLI seam). |
|
data/docs/bundle-authoring.md
CHANGED
|
@@ -24,7 +24,7 @@ Dev-linked scripts aren't chmodded: chi warns with a `chmod +x PATH/scripts/x` h
|
|
|
24
24
|
|
|
25
25
|
`check` prints one finding per line (`error|warn|info CODE file[:line]: message (fix: hint)`), exits 1 on any error
|
|
26
26
|
and installs into a temp sandbox, not the user's config or state; run it after every edit. `check` and `test` run
|
|
27
|
-
the bundle's plugin
|
|
27
|
+
the bundle's plugin in their own process, as written: run them on code you'd install.
|
|
28
28
|
|
|
29
29
|
## Trying a bundle
|
|
30
30
|
|
|
@@ -51,8 +51,6 @@ plugin:
|
|
|
51
51
|
sha256: sha256:<hex> # `chi bundle check --fix` fills it; never compute it by hand
|
|
52
52
|
# files: # memories it installs (top-level *.md); without files: every *.md but README & co.
|
|
53
53
|
# my_notes.md: sha256:<hex>
|
|
54
|
-
# hooks: # hooks/*.rb files (a plugin's chi.on is usually simpler), each with event: NAME
|
|
55
|
-
# # or events: [a, b] (one instance for both; chi newer than 0.97.0)
|
|
56
54
|
# needs: [gh] # outside commands it relies on
|
|
57
55
|
```
|
|
58
56
|
|
|
@@ -90,7 +88,8 @@ empty), then `exit: N` (`exit: 0 (no output)` when both were empty); a non-zero
|
|
|
90
88
|
Act through `ctx`: `ctx.notify(text, level: :warn)`, `ctx.steer(text)` (a line the model reads before its next
|
|
91
89
|
step), `ctx.card(…)`, `ctx.stop_turn(reason)`, `ctx.ask_user(…)`, `ctx.data_dir` (the bundle's state folder),
|
|
92
90
|
`ctx.session_dir` (this session's, removed with it), `ctx.cwd`, `ctx.log`. In a test, each recorded notice, steer or stop names its hook as `"plugin.rb (bundle
|
|
93
|
-
my-bundle)"`, the plugin's label
|
|
91
|
+
my-bundle)"`, the plugin's label. A bundle hooks events from its plugin only: class-file hooks (`hooks/*.rb`, a
|
|
92
|
+
manifest `hooks:`) are retired, and chi refuses a source that has them ([hooks.md](hooks.md#class-file-hooks-are-retired)).
|
|
94
93
|
|
|
95
94
|
## Testing it
|
|
96
95
|
|
|
@@ -126,8 +125,9 @@ class, a hand-built `ctx`), that is a gap in the kit: say so to the user rather
|
|
|
126
125
|
|
|
127
126
|
## Pitfalls
|
|
128
127
|
|
|
128
|
+
- **Sandbox and ENV.** A standalone `Testing::Bundle` snapshots `ENV` when built and restores it at shutdown; see [Testing a bundle](plugins.md#testing-a-bundle-experimental).
|
|
129
129
|
- **Shas.** Every file the manifest names has a sha256 line, and an edit makes it stale: the install then warns
|
|
130
|
-
of a checksum mismatch, and a line with no sha installs unchecked. `chi bundle check --fix` rewrites them; run it
|
|
130
|
+
of a checksum mismatch (not for `install --dev`; `chi bundle check` does), and a line with no sha installs unchecked. `chi bundle check --fix` rewrites them; run it
|
|
131
131
|
after the last edit.
|
|
132
132
|
- **requires_chi.** Use the chi the user runs (`chi --version`): a bundle whose `requires_chi` that chi doesn't
|
|
133
133
|
meet is now **refused at install** (`--force` is the only way past it), not just unloaded. `check` warns when the plugin calls something newer than the floor (`ctx.http` 0.80.0, `ctx.cost` 0.83.0, `ctx.usage` 0.100.0, `ctx.sessions.children` 0.34.0),
|
data/docs/bundles.md
CHANGED
|
@@ -4,7 +4,10 @@ What each shipped bundle does for you, its commands, settings and files. A bundl
|
|
|
4
4
|
the plugin API ([plugins.md](plugins.md)); install, upgrade and the `chi bundle` commands are in
|
|
5
5
|
[plugins.md](plugins.md#the-bundle-commands) and [cli.md](cli.md). Two shipped bundles are documented with the
|
|
6
6
|
feature they belong to: **source-links** in [hooks.md](hooks.md#the-source-links-bundle) and **known-names** in
|
|
7
|
-
[guardrails.md](guardrails.md#the-known-names-bundle).
|
|
7
|
+
[guardrails.md](guardrails.md#the-known-names-bundle). Both hook events from their `plugin.rb` with `chi.on`
|
|
8
|
+
(known-names on `before_tool_call`, priority 50; source-links on `after_turn` and `question_asked`, priority 90), as
|
|
9
|
+
every shipped bundle with code does; before known-names 0.2.0 and source-links 0.7.0 they shipped a `hooks/*.rb` file
|
|
10
|
+
(chi no longer loads one: [hooks.md](hooks.md#class-file-hooks-are-retired); `chi update` removes the old file).
|
|
8
11
|
|
|
9
12
|
## The btw bundle
|
|
10
13
|
|
data/docs/cli.md
CHANGED
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
- `chi scratch [options]` — a one-time session in this folder, attached like plain `chi`, that leaves nothing behind (see [Scratch sessions](#scratch-sessions))
|
|
11
11
|
- `chi --attach <session-id>` — attach the terminal to a session's worker (e.g. one started from the Web UI), waking one if it has exited
|
|
12
12
|
- A session id can be shortened to any unique prefix (like git): `chi --attach 2ea8`. `--resume`, `--attach`, `sessions stop`, `sessions archive` and `sessions delete` take one; an ambiguous prefix lists the sessions it matches.
|
|
13
|
-
- `chi web [--port 4567] [--open] [--scope=all] [--start-dir DIR]` — start the Web UI (single localhost port session control plane) on this
|
|
13
|
+
- `chi web [--port 4567] [--open] [--scope=all] [--start-dir DIR]` — start the Web UI (single localhost port session control plane) on this project's sessions (a git repository or a `chi project init` folder; `--scope=all`, or a folder in neither: `/?scope=all`, every session); if a chi web already runs on the port, print (with `--open`, open) its page for this folder and exit. Something else on the port (an older chi web too) exits 1 with "port N is in use"
|
|
14
14
|
- `chi web --web-host lan` — the Web UI on your home network too, for your phone: a link with an access token and its QR code (see [chi web on your phone](#chi-web-on-your-phone)); `chi web --new-token` replaces the token
|
|
15
|
-
- `chi web --start-dir DIR` (config `web.start_dir`) — the folder chi web starts in, in place of the one you run it in (`~` and a relative path work; chi web never changes its own folder): its page opens on that folder's project (the printed link, a bare `/`, the LAN link and its QR code, the Home Screen app), and a new session from the all view starts there; the header's project chip switches projects. One that isn't a folder exits 1; `--start-dir` without `web` exits 2. A chi web already running in another folder keeps it (the second one says so: restart it to change it)
|
|
15
|
+
- `chi web --start-dir DIR` (config `web.start_dir`) — the folder chi web starts in, in place of the one you run it in (`~` and a relative path work; chi web never changes its own folder): its page opens on that folder's project (the printed link, a bare `/`, the LAN link and its QR code, the Home Screen app), and a new session from the all view starts there; the header's project chip switches projects, and its picker has a `New project…` row for creating a project folder (a path inside a git repository opens that repository's project and the folder is left as it is, nothing marked). One that isn't a folder exits 1; `--start-dir` without `web` exits 2. A chi web already running in another folder keeps it (the second one says so: restart it to change it)
|
|
16
16
|
- `chi web --tunnel tailscale` — the Web UI over https on your tailnet, for your phone anywhere: Tailscale Serve (never Funnel) on this machine's `<machine>.<tailnet>.ts.net` name for this run, the owner your Tailscale login, turned off on exit (see [Tailscale Serve](configuration.md#tailscale-serve-your-tailnet)); `--tunnel` without `web` exits 2
|
|
17
17
|
- `chi web push ls [--format json]`, `chi web push rm ID`, `chi web push test [ID]` — the phones chi web pushes to (see [Phone notifications](configuration.md#phone-notifications-web-push)): list them (short id, label, origin, added, last delivery, done turns, last error; `stale` for one made on another public URL than chi web's now: never sent to), remove one, or send a test notification to ID or to every device not stale. chi web need not run; nothing printed holds a device's push address or keys. A usage error exits 2; a store others can read, a corrupt one, an unknown device or a failed test push exit 1. This machine only: `chi --remote X web push` exits 2
|
|
18
18
|
- `chi web --web-markdown` / `--no-web-markdown` — opt in to, or opt out of, sanitized Markdown rendering for completed assistant messages, the stage's asking text and a resolved question card's reply (`web.markdown`, off by default; `--no-web-markdown` turns a config's `web.markdown: true` off for this run)
|
|
19
19
|
- `chi web --no-web-working-set` — turns the stage view's working set off (on by default; `--web-working-set` turns a config's `web.working_set: false` back on): what each turn brought into the model's context, in the stage and under each finished turn; `?working_set=1|0` on the page URL overrides it (see [The working set](#the-working-set))
|
|
20
|
-
- `chi sessions list|stop|restart|archive|unarchive|delete|prune|clean|stats` — manage persisted sessions; `list` shows this git project's, `list --scope=all` every one, a delegated session with `↳ <parent>`, `list --archived` the archived ones too (see [Sessions](sessions.md))
|
|
20
|
+
- `chi sessions list|stop|restart|archive|unarchive|delete|prune|clean|stats` — manage persisted sessions; `list` shows this git project's, `list --scope=all` every one, a delegated session with `↳ <parent>`, `list --archived` the archived ones too (see [Sessions](sessions.md)); one line per session (`<id> <state> <ctx> <updated_at> <text> [flags] ↳ … ↪ …`) and one footer (`N session(s) (sort=… order=…)`, or the project note) for the plain list, the `--live`/`--cwd` text and `--remote`. `stats ID` prints a session's cost, tokens and progress, and its own settings (`--set`; a `settings:` line), from a live worker's `GET stats`, else its saved `analytics.json` (`--format json` one object, with `settings`), without running a model turn. A usage error (an unknown subcommand or flag, a flag missing its value, `stop`, `restart` or `delete` with no ids, a bad `list --format` or `--scope`, a `--days`, `--keep` or `--limit` that isn't a whole number) exits 2; an unknown or refused session exits 1
|
|
21
21
|
- `chi note [--source NAME] [-m TEXT] (ID|PREFIX)... | --all` — add a context note (TEXT or stdin) to sessions: background the model sees on its next turn; it starts no turn (see [Sessions: Context notes](sessions.md#context-notes))
|
|
22
22
|
- `chi broadcast [-m TEXT] [--all] [--dry-run]`, `chi broadcast log [--last N] [--format json]`, `chi broadcast deliver BROADCAST_ID (ID|PREFIX)...` — share one piece of information (TEXT or stdin) with every session it may concern, as a context note from `broadcast` (see [Broadcast](broadcast.md))
|
|
23
23
|
- `chi context <add|push|ls|show|refresh|rm|mute|unmute> …` — attach live external text to sessions (a command chi runs every so often, or text pushed in); the model gets a short note when it changes and reads it with `context_read`; `chi context add <URL>` attaches a GitHub PR with the github-pr bundle; `chi context push NAME -m TEXT` (the long form is `--message TEXT`) gives a `--push` source its new text, read from stdin when no `-m` is given (see [Attached context](context.md))
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
- `chi self` — print version, source dir (checkout or installed gem), config/memory/session paths, model/host and bundles. Run by a session's `execute`, the `model` row (and host, loop, profile, thinking, served model) is **that session's** model, labelled `(this session <id8>; default …)`; elsewhere it is the default, `(default)`. `model key` is the memory overlay key (`<name>.<key>.md`), and `big memories` the memories over `memory.entry_warn_tokens` ([Memory](memory.md#a-memorys-size)), and `model notes` the model notes a prompt of that model loads (`model_notes_deepseek (system, 612 chars)`, `none`; inside a session its `--mute` list is left out). `chi self --model` prints only the model a new session starts on, an alias resolved to its target (the desktop helper's hint)
|
|
36
36
|
- `chi update [--dry-run] [--to VERSION] [--json] [--no-gem] [--no-bundles] [--no-desktop]` — update an installed chi: the gem, the system bundle, the shipped bundles you installed and the desktop helper, and check the bundles from elsewhere, in one table (see [Updating](#updating))
|
|
37
37
|
- `chi home`, `chi home set [--ruby PATH]`, `chi home doctor` — the chi home: the one Ruby (and its gem path) every chi launch boots, whoever launches it. `chi home` shows it (its Ruby, the newest chi in it, gem home and path, `mise`, when and by which chi it was set, and the chi you ran when that is another one; exit 1 with the problem when it can't boot chi), `set` records this chi's Ruby and gem path (or `--ruby PATH`'s own; it must have samagotchi), `doctor` checks it and what should follow it, one row each with `ok`, `warn` or `fail` and what to run (exit 1 on a `fail`; see [Checking it](configuration.md#checking-it-chi-home-doctor)). At a terminal, a chi on another Ruby than the home's says so in one dim line a day. This machine only (see [The chi home](configuration.md#the-chi-home))
|
|
38
|
-
- `chi
|
|
38
|
+
- `chi project`, `chi project init [DIR]` — this folder's project, and making a folder in no git repository one. `chi project` prints how its project was found (`kind` `git`, `marker` or `none`), its `root` (what memories are keyed on), its `top` (where the AGENTS.md chain starts) and its project `memories` folder, with a `note` for a marker a repository makes ignored, or a `$HOME` that is a git repository. `init` writes `DIR/.chi/project.yml` (DIR defaults to this folder and is created when missing), so DIR and every subfolder share one memories folder, group their sessions and take `chi context --project`; it writes nothing in a git repository (the repository already is the project, exit 0), says so for a folder already marked, refuses `$HOME`, a folder above it and `/` (exit 1), and marks a folder inside another marked project as its own, nested one. It prints the root and the memories folder (with the memories already there: a folder chi ran in at its top keeps them), the running sessions in DIR to restart (`chi sessions restart ID`: their prompt keeps the old project) and, when DIR has saved sessions, that a running chi web groups them after its restart. This machine only. See [Projects without git](memory.md#projects-without-git)
|
|
39
|
+
- `chi bundle install|upgrade|uninstall|status|diff|list|build|trash|new|test|check` — manage memory bundles (see [Plugins](plugins.md) and [Bundle hooks](hooks.md#bundle-hooks)); `list` shows the installed ones and the ones shipped with chi, which `install <name>` installs; `upgrade <name>` upgrades an installed bundle by name from the source it came from (its folder, archive or git URL), `upgrade <source>` from a new one; `core` and `dev` are profiles that install a set of them (see [Bundle profiles](memory.md#bundle-profiles-core-and-dev), [Guardrails](guardrails.md), [Bundles](bundles.md#the-btw-bundle), [the mcp bundle](bundles.md#the-mcp-bundle) [the loop-guard bundle](bundles.md#the-loop-guard-bundle), [the check-in bundle](bundles.md#the-check-in-bundle) and [the skills bundle](bundles.md#the-skills-bundle)). `trash` lists and empties the bundle trash (moved files from uninstalls/upgrades). `install`/`upgrade` `--force` overwrites existing entries and also installs a bundle whose `requires_chi` this chi doesn't meet; without it such a bundle is refused (exit 1), nothing written. A plain `install` of a bundle that is already installed from the same source rewrites its rules, plugin, scripts and record: the summary lists a file that already holds the bundle's bytes as `Up to date: …`, one you wrote as `Skipped: …`, and ends with `NAME was already installed from SOURCE: its rules, plugin and scripts now match it and its record was rewritten` (plus, when a memory was kept, `your own copies of its memories were kept (chi bundle upgrade NAME merges the bundle's changes into them)`). A source with class-file hooks (`hooks/*.rb` or a manifest `hooks:` entry) is refused, `--dry-run` too; an older install's hooks are removed by the next install or upgrade (`Removed (chi no longer loads class-file bundle hooks): …`, an edited one copied to the trash first; see [Class-file hooks are retired](hooks.md#class-file-hooks-are-retired)). A usage error (an unknown subcommand or flag, a missing argument, a bad `build --scope`) exits 2, as for the other subcommands. Plain `chi` and `chi web` exit 1 on an unknown flag, a flag missing its value or a stray argument. `new`, `test` and `check` are for writing one: see [Writing a bundle](#writing-a-bundle-new-test-check)
|
|
39
40
|
|
|
40
41
|
- `chi guardrails replay [--dry-run] [--threshold T] [--model M]` — seed System 1's record from the approvals this machine's sessions already answered: each ask is judged by the configured model and written to `guardrails/judgments.jsonl` with the answer the user gave, then a per-rule table prints (asks, allowed, denied, would-be auto-allows, false allows, asks with no judgment). A parent agent's answer is not the user's: only its deny is replayed, and only where the parent could have allowed. `--dry-run` judges without writing, `--threshold` overrides `guardrails.system_one.threshold` for the table, `--model` the configured model for this run. Exit 2 when `guardrails.system_one.mode` is off or no `host` is set; a usage error exits 2 (see [System 1](guardrails.md#system-1-experimental))
|
|
41
42
|
- `chi guardrails rule <id>` — print exactly `asks` when that rule is loaded, not disabled and votes `ask` in this `guardrails.mode` for every model; any other line says why not (no such rule, disabled, another mode, it denies, for some models only, rules that failed to load, `guardrails.enabled: false`). Exit 0 either way, 2 for a usage error. It reads config.yml and the installed bundles as a worker does (`GuardrailWiring#rules`) and takes the rule's id, never a command; the [coordinator skill](bundles.md#the-coordinator-bundle) reads it before it merges without asking
|
|
@@ -132,11 +133,11 @@ The loop for a bundle you're writing (the whole path: [bundle-authoring.md](bund
|
|
|
132
133
|
chi's Ruby (minitest is one of chi's gems; rspec is optional). The tests run the bundle's code as written, with
|
|
133
134
|
your environment (the kit sandboxes each test's HOME and XDG dirs, not the process).
|
|
134
135
|
- `chi bundle install --dev PATH` installs the bundle in the local directory `PATH` (not a git URL, archive or name:
|
|
135
|
-
exit 2) as a link to it: its plugin,
|
|
136
|
+
exit 2) as a link to it: its plugin, rules, scripts and `manifest.yml` are `PATH`'s own files, so an edit applies at the
|
|
136
137
|
next worker or `chi web` restart with no re-install (a manifest edit to `block_renderers:` shows in chi web's next
|
|
137
|
-
request; a new `scripts
|
|
138
|
-
has no entry for it), and
|
|
139
|
-
record says `dev`; every other bundle is checked as before). Its memories are copied at install. `chi bundle
|
|
138
|
+
request; a new `scripts:` or `plugin:` entry needs `chi bundle install --dev PATH` again, since the record
|
|
139
|
+
has no entry for it), and no sha256 is checked for any of its files, including its memories, for this bundle only
|
|
140
|
+
(the record says `dev`; every other bundle is checked as before). Its memories are copied at install. `chi bundle
|
|
140
141
|
status` shows `NAME vX dev → /abs/path`. `chi bundle upgrade NAME` refuses it (it follows its source already; to
|
|
141
142
|
leave dev mode: `chi bundle uninstall NAME`, then `chi bundle install` without `--dev`), as does a plain install
|
|
142
143
|
over it, and `--dev` over a normal install. `uninstall` removes the links and the record, never `PATH`'s files.
|
|
@@ -144,10 +145,11 @@ The loop for a bundle you're writing (the whole path: [bundle-authoring.md](bund
|
|
|
144
145
|
- `chi bundle check [PATH] [--fix] [--set KEY=VALUE]` (PATH defaults to `.`) checks it as an install takes it, one
|
|
145
146
|
finding per line, `error|warn|info CODE file[:line]: message (fix: hint)`, then `ok|failed: N errors, N
|
|
146
147
|
warnings`. Exit 1 on any error, 0 otherwise, 2 for usage. It installs and loads the bundle in a temp sandbox
|
|
147
|
-
(HOME, config and state), not in yours, but in chi's own process: the plugin's
|
|
148
|
+
(HOME, config and state), not in yours, but in chi's own process: the plugin's code runs as written,
|
|
148
149
|
so run it (and `test`) on code you'd install. The codes, in order: `manifest` (a parse error, verbatim; the run
|
|
149
|
-
stops), `
|
|
150
|
-
|
|
150
|
+
stops), `hooks-retired` (error: a manifest `hooks:` entry, or `hooks/*.rb` files: class-file hooks are retired,
|
|
151
|
+
hook events from `plugin.rb` with `chi.on`; the run stops), `missing-file`, `unlisted` (warn: a file an install leaves out, by `MemoryFiles`' rules, so a README
|
|
152
|
+
isn't one), `sha` (a stale or placeholder sha, or a plugin / script entry with no sha line; `--fix`
|
|
151
153
|
rewrites the first two and prints `fixed sha FILE → sha256:…`), `unknown-key` (warn: a manifest key this chi's
|
|
152
154
|
parser never reads, so it ignores it, one row per key at its line; the install keeps the manifest, so a newer
|
|
153
155
|
chi reads the key from it with no reinstall, and `chi update`'s re-check names it too), `requires-chi` (this chi doesn't satisfy it:
|
|
@@ -156,10 +158,10 @@ The loop for a bundle you're writing (the whole path: [bundle-authoring.md](bund
|
|
|
156
158
|
`Manifest::SINCE`; an installed bundle gets the unknown-key row but never the floor, as it's the author's fix),
|
|
157
159
|
`trust` (warn: `trust_level: reviewed|trusted` on a
|
|
158
160
|
bundle chi doesn't ship), `clash` (warn: a name chi ships, or one installed from elsewhere; the sandboxed install
|
|
159
|
-
then forces), `install` (each Installer warning, a `needs` one as warn, and each plugin
|
|
161
|
+
then forces), `install` (each Installer warning, a `needs` one as warn, and each plugin load failure at
|
|
160
162
|
the source `file:line`; skipped while a placeholder sha is unfilled), `registered` (info: each command, tool,
|
|
161
163
|
hook with its priority, init, toolkit, tool source, peer source and prompt section), `hook-event` (warn: a `chi.on` event chi
|
|
162
|
-
never fires), `settings` (warn: a `--set` the manifest's `settings:` rules out, as config.yml's `bundles:` is told), `api` (warn: a `ctx.*` / `chi.*` call or a keyword this chi's API lacks, read from the source with
|
|
164
|
+
never fires), `fail-closed` (warn: a `chi.on(..., on_error: :fail_closed)` in a plugin whose manifest `plugin:` lacks `required: true`, so a load failure would not deny tool calls; not on an installed bundle's re-check), `settings` (warn: a `--set` the manifest's `settings:` rules out, as config.yml's `bundles:` is told), `api` (warn: a `ctx.*` / `chi.*` call or a keyword this chi's API lacks, read from the source with
|
|
163
165
|
Prism against the API's own classes, on a path that never runs too; written on a local `ctx` / `chi` itself, so a
|
|
164
166
|
`s = ctx.sessions` variable isn't followed; a name the plugin guards with `respond_to?` is left), `boundary` (warn: a `Samagotchi::` name outside "Stable for bundles"; a shipped bundle's listed
|
|
165
167
|
exceptions aside. On an installed bundle (`chi update`) only a name this chi no longer has is a row: the constant
|
|
@@ -339,23 +341,26 @@ Also shipped, not installed: dev (mcp, skills, source-links) (chi bundle install
|
|
|
339
341
|
the merge itself, and `--force` replacing the file. A dry run and an automatic update
|
|
340
342
|
(`update.auto`) show it and leave it, and so does a failed row or one with no place
|
|
341
343
|
for it (a skipped system bundle). A memory that can't be read at a
|
|
342
|
-
newer version fails that bundle's row with the file's name.
|
|
343
|
-
|
|
344
|
+
newer version fails that bundle's row with the file's name. Rules, the plugin and scripts are replaced, and an
|
|
345
|
+
older install's class-file `hooks/` removed. One
|
|
346
|
+
whose bytes are neither what the install recorded (nothing recorded counts as edited) nor the new version's is
|
|
347
|
+
edited: the row says `replaced edited hooks/x (a copy goes to the trash first)` (`would replace` in the plan), and
|
|
344
348
|
a copy goes to the bundle trash first (`chi bundle trash`; `hooks/x`,
|
|
345
349
|
`guardrails/x`, `plugin/x`, `scripts/x` inside the dir).
|
|
346
350
|
A bundle of the same name from elsewhere (a zip, git) is skipped ("not from
|
|
347
351
|
chi"), a newer installed one is left, one whose new version needs a newer
|
|
348
352
|
chi is skipped, and bundles you didn't install stay uninstalled.
|
|
349
353
|
- **Bundles not from chi** are never changed, but the chi the update leaves
|
|
350
|
-
checks what is installed of them (the plugin
|
|
354
|
+
checks what is installed of them (the plugin and rules as they are,
|
|
351
355
|
not their source, which may be gone) with `chi bundle check`'s own checks,
|
|
352
356
|
and each warning or error is a row under the bundle's name: `requires_chi`
|
|
353
|
-
ruling this chi out, a plugin
|
|
357
|
+
ruling this chi out, a plugin that no longer loads, a hook on an event
|
|
354
358
|
chi no longer fires, a `ctx`/`chi` call the API lacks, a reference to chi's
|
|
355
359
|
internals that this chi no longer has (`Samagotchi::OldInternal::Thing is gone from this chi, so this bundle may
|
|
356
360
|
fail` — a name that still resolves gets no row, so a bundle reaching `Samagotchi::Log` isn't warned about on every
|
|
357
|
-
update), a name chi now ships,
|
|
358
|
-
doesn't load)
|
|
361
|
+
update), a name chi now ships, a rule or plugin edited since it was installed (it
|
|
362
|
+
doesn't load), or class-file hooks an older chi installed (`hooks-retired`: they no longer load; `chi bundle upgrade
|
|
363
|
+
NAME` once its source hooks from `plugin.rb`, or `chi bundle uninstall NAME`). What only an author can act on (shas, unlisted files, tests, a
|
|
359
364
|
missing `requires_chi`, its floor, `trust_level`) is left out, and so are
|
|
360
365
|
profiles. A clean bundle gets no row beyond its `skipped (not from chi)`.
|
|
361
366
|
- **They fail nothing:** an error row too has `failed: false` and leaves the exit
|
|
@@ -801,8 +806,8 @@ also offline (from the saved records). `/recap` is in
|
|
|
801
806
|
Switch](#runtime-model-switch-assist-mode).
|
|
802
807
|
|
|
803
808
|
`/llm-context` shows the LLM context strategy, apply rule and budget the next
|
|
804
|
-
turn runs under, each with where it came from (`
|
|
805
|
-
`hosts
|
|
809
|
+
turn runs under, each with where it came from (`session`, `models: <key>`,
|
|
810
|
+
`hosts.<name>`, `llm_context.*`), and the session's own values.
|
|
806
811
|
`/llm-context strategy <none|stale|stale,forget> apply <payoff|next_request|turn_end>
|
|
807
812
|
budget <tokens|64k|off>` sets the session's own (any of the three, in one line;
|
|
808
813
|
`default` unsets one), and `/llm-context reset` unsets them all. A change is
|
|
@@ -1426,7 +1431,7 @@ Scan the QR code with the phone's camera. The page trades the token in the
|
|
|
1426
1431
|
link for a cookie (kept 400 days) and drops it from the address, so a
|
|
1427
1432
|
bookmark or a home-screen icon keeps working across restarts. It opens on
|
|
1428
1433
|
the project chi web starts in (`--start-dir DIR` or `web.start_dir` picks
|
|
1429
|
-
another; outside a
|
|
1434
|
+
another; outside a project (no repository or marked folder) it shows every session); the header's `all` shows
|
|
1430
1435
|
every project's. A home-screen
|
|
1431
1436
|
web app on iOS has cookies of its own: if it opens on "needs chi web's
|
|
1432
1437
|
access token", paste the token there (the part of the link after
|
|
@@ -1527,8 +1532,8 @@ CHI_REMOTE=studio chi context push claude-outbox ab12 < answer.json
|
|
|
1527
1532
|
- `send --new` needs `--dir`, that machine's absolute path (no folder of this
|
|
1528
1533
|
one is guessed); `--toolkit`, `--set` and `--parent-answers` are checked
|
|
1529
1534
|
against that machine's config and bundles. `sessions list` lists every
|
|
1530
|
-
project's sessions there (`--scope=project --cwd DIR` one project's)
|
|
1531
|
-
|
|
1535
|
+
project's sessions there (`--scope=project --cwd DIR` one project's), each
|
|
1536
|
+
on the same line a list here prints. `context` takes the session ids (no default session),
|
|
1532
1537
|
and a URL resolves through that machine's bundles.
|
|
1533
1538
|
- That machine's config.yml decides what it checks for `send` and `answer`:
|
|
1534
1539
|
a parent agent's `/continue yes` and options (`guardrails.parent_answers`),
|