samagotchi 0.157.0 → 0.159.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 +47 -1
- data/README.md +1 -1
- data/bin/chi +5 -1
- data/docs/architecture.md +14 -12
- data/docs/bundle-authoring.md +5 -5
- data/docs/bundles.md +2 -1
- data/docs/cli.md +76 -17
- data/docs/configuration.md +16 -5
- data/docs/context.md +12 -4
- data/docs/guardrails.md +11 -8
- data/docs/hooks.md +47 -80
- data/docs/internals/bridge.md +2 -1
- data/docs/internals/bundles.md +51 -36
- data/docs/internals/engine.md +7 -5
- data/docs/memory.md +43 -9
- data/docs/plugins.md +13 -9
- data/docs/releasing.md +6 -5
- data/docs/scheduling.md +228 -0
- data/docs/sessions.md +30 -6
- data/docs/testing.md +4 -4
- data/lib/samagotchi/bridge/card_places.rb +5 -13
- data/lib/samagotchi/bridge/turn_accumulator.rb +4 -1
- data/lib/samagotchi/bridge/turn_drawings.rb +7 -1
- data/lib/samagotchi/bridge.rb +26 -2
- data/lib/samagotchi/bundle_command/check.rb +23 -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.rb +53 -44
- 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 +6 -6
- data/lib/samagotchi/bundles/system/self_map.md +1 -1
- data/lib/samagotchi/client_id.rb +13 -3
- data/lib/samagotchi/config.rb +12 -0
- data/lib/samagotchi/context_command.rb +7 -5
- data/lib/samagotchi/context_move.rb +74 -0
- data/lib/samagotchi/context_sources.rb +4 -2
- data/lib/samagotchi/engine.rb +1 -6
- data/lib/samagotchi/extension_load.rb +20 -41
- data/lib/samagotchi/guardrails/load_failures.rb +3 -2
- data/lib/samagotchi/guardrails/pair_boundary.rb +1 -1
- data/lib/samagotchi/guardrails/path_resolve.rb +11 -0
- data/lib/samagotchi/guardrails/review_paths.rb +1 -5
- data/lib/samagotchi/hook_routes.rb +2 -2
- data/lib/samagotchi/hooks.rb +2 -3
- data/lib/samagotchi/memory_bundle/asset_installer.rb +112 -211
- data/lib/samagotchi/memory_bundle/asset_state.rb +81 -0
- data/lib/samagotchi/memory_bundle/builder.rb +10 -34
- data/lib/samagotchi/memory_bundle/bundle_hook.rb +6 -31
- data/lib/samagotchi/memory_bundle/file_actions.rb +51 -0
- data/lib/samagotchi/memory_bundle/installed_bundle.rb +1 -1
- data/lib/samagotchi/memory_bundle/installed_copy.rb +11 -18
- data/lib/samagotchi/memory_bundle/installed_manifest.rb +2 -16
- data/lib/samagotchi/memory_bundle/installer.rb +32 -14
- data/lib/samagotchi/memory_bundle/manifest.rb +37 -54
- data/lib/samagotchi/memory_bundle/provenance.rb +11 -51
- data/lib/samagotchi/memory_bundle/remerge.rb +7 -3
- data/lib/samagotchi/memory_bundle/shas.rb +5 -8
- data/lib/samagotchi/memory_bundle/shipped_update.rb +41 -41
- data/lib/samagotchi/memory_bundle/status.rb +30 -9
- data/lib/samagotchi/memory_bundle/system_bundle.rb +16 -5
- data/lib/samagotchi/memory_bundle/trash.rb +7 -12
- data/lib/samagotchi/memory_bundle/uninstaller.rb +10 -4
- data/lib/samagotchi/memory_orphans.rb +4 -4
- data/lib/samagotchi/memory_paths.rb +102 -13
- data/lib/samagotchi/plugin/api.rb +1 -4
- data/lib/samagotchi/plugin/loader.rb +42 -5
- 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/recap_place.rb +3 -4
- data/lib/samagotchi/run_options.rb +2 -0
- data/lib/samagotchi/schedule_command.rb +252 -0
- data/lib/samagotchi/schedules.rb +948 -0
- data/lib/samagotchi/session.rb +44 -18
- data/lib/samagotchi/session_access/contract.rb +1 -1
- data/lib/samagotchi/session_access/local.rb +20 -0
- data/lib/samagotchi/session_field.rb +5 -4
- data/lib/samagotchi/session_manager/spawn.rb +25 -11
- data/lib/samagotchi/session_manager/worker_command.rb +13 -13
- data/lib/samagotchi/steer.rb +10 -0
- data/lib/samagotchi/system_prompt.rb +20 -11
- data/lib/samagotchi/terminal_ui/formatting.rb +2 -0
- data/lib/samagotchi/terminal_ui/join_replay.rb +6 -1
- data/lib/samagotchi/testing/bundle.rb +5 -12
- data/lib/samagotchi/testing/install.rb +5 -5
- data/lib/samagotchi/testing/recorder.rb +1 -1
- data/lib/samagotchi/testing.rb +1 -1
- data/lib/samagotchi/tool_declarations.rb +44 -1
- data/lib/samagotchi/toolkit_binding.rb +1 -4
- data/lib/samagotchi/toolkit_command.rb +1 -4
- data/lib/samagotchi/tools/builtin_calls.rb +2 -0
- data/lib/samagotchi/tools/builtins.rb +17 -0
- data/lib/samagotchi/tools/cancel_schedule.rb +43 -0
- data/lib/samagotchi/tools/delegate.rb +12 -8
- data/lib/samagotchi/tools/list_schedules.rb +43 -0
- data/lib/samagotchi/tools/schedule_task.rb +39 -0
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +35 -0
- data/lib/samagotchi/web/project_list.rb +3 -2
- data/lib/samagotchi/web/public/chains.js +32 -8
- data/lib/samagotchi/web/public/index.html +10 -2
- data/lib/samagotchi/web/public/info_bar.js +4 -3
- data/lib/samagotchi/web/public/project_picker.js +86 -4
- data/lib/samagotchi/web/public/turn_events.js +4 -0
- data/lib/samagotchi/web/session_hub.rb +20 -0
- data/lib/samagotchi/worker.rb +24 -6
- data/lib/samagotchi/worker_boot.rb +3 -4
- data/lib/samagotchi/worker_inbound.rb +23 -0
- data/lib/samagotchi/worker_link.rb +5 -0
- data/lib/samagotchi/worker_wakes.rb +9 -1
- metadata +10 -2
- data/lib/samagotchi/hooks/bundle_loader.rb +0 -191
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ab720ab347312f152fc99a03ca8cd423a640de2c9b4221ccc70803396a2d8c09
|
|
4
|
+
data.tar.gz: 313bbe5c7cce008df50c73de233557824723566db8449a8e3a04ff01e85343f9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c02cc469245adaa130c74b1e10978c11b51e85f7ff8c2fe9c27d0de68682d0452f07d9dec7f9100c032dac9cf7357bff81fc70586c9c6cb1e99ab0327c68d56
|
|
7
|
+
data.tar.gz: 7ffaacdca84dc1396e5f6edd1160b54e063daa38b71d9aa7c36d7619495d26271606efd277024f344e18043ed2112f3343ea127560438bea0f5480b98df617f3
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,50 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.159.0] - 2026-11-09
|
|
12
|
+
|
|
13
|
+
Update with `chi update`.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `chi schedule <add|list|show|tick|run-now|enable|disable|cancel>`: durable schedules that outlive every worker. Each entry is a prompt with a clock in `~/.local/state/samagotchi/schedules.json`, fired by a tick run by cron, systemd or (with `schedule.auto_tick: true`) chi web's hub, and each firing is either the next link of the session's chain (the default, with `--keep-links` pruning the older links and their delegates) or a turn queued in the session itself (`--mode same`). Recurrence is `--every 45m`, `--weekday 1 --time 09:00` or `--date 2026-11-20T09:00`; a busy target is skipped and retried at the next tick, and 12 consecutive skips or 3 consecutive failures disable it (any success resets both). The model registers its own with `schedule_task`, `list_schedules` and `cancel_schedule`. `register_reminder` is unchanged: a reminder lives in a live worker and holds it up; a schedule wakes one. See docs/scheduling.md.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `chi bundle status NAME` lists the bundle's guardrail rules and scripts, and says which you edited (an edited one is
|
|
22
|
+
replaced by the next install, its copy kept in the trash).
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- A peer's wake push now starts a session that went idle (never one you stopped).
|
|
27
|
+
- Continuing a session carries a peer's pushed text the old session hadn't absorbed or read yet, as a separate
|
|
28
|
+
third-party context note.
|
|
29
|
+
|
|
30
|
+
## [0.158.0] - 2026-11-08
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- 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`.
|
|
35
|
+
- 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).
|
|
36
|
+
|
|
37
|
+
### Removed
|
|
38
|
+
|
|
39
|
+
- 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.
|
|
40
|
+
- 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`.
|
|
41
|
+
- 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.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- `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.
|
|
46
|
+
- `chi update --dry-run` now shows the same memory checksum warnings as the update itself.
|
|
47
|
+
- 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.
|
|
48
|
+
- 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 `?`.
|
|
49
|
+
- 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.
|
|
50
|
+
- `chi bundle try --json` no longer crashes when the answer or the trace holds non-ASCII text.
|
|
51
|
+
- `chi bundle upgrade` (and `chi update`) list a plugin or script that the new version adds under Installed, not Updated.
|
|
52
|
+
|
|
53
|
+
Update with `chi update`.
|
|
54
|
+
|
|
11
55
|
## [0.157.0] - 2026-11-08
|
|
12
56
|
|
|
13
57
|
### Added
|
|
@@ -5840,7 +5884,9 @@ and long-lived sessions.
|
|
|
5840
5884
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
5841
5885
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
5842
5886
|
|
|
5843
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
5887
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.159.0...HEAD
|
|
5888
|
+
[0.159.0]: https://github.com/dm1try/samagotchi/compare/v0.158.0...v0.159.0
|
|
5889
|
+
[0.158.0]: https://github.com/dm1try/samagotchi/compare/v0.157.0...v0.158.0
|
|
5844
5890
|
[0.157.0]: https://github.com/dm1try/samagotchi/compare/v0.156.0...v0.157.0
|
|
5845
5891
|
[0.156.0]: https://github.com/dm1try/samagotchi/compare/v0.155.0...v0.156.0
|
|
5846
5892
|
[0.155.0]: https://github.com/dm1try/samagotchi/compare/v0.154.1...v0.155.0
|
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,11 @@ 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"],
|
|
108
|
+
# durable schedules that outlive every worker (add, list, show, tick, run-now, …)
|
|
109
|
+
"schedule" => ["samagotchi/schedule_command", "ScheduleCommand"]
|
|
106
110
|
}.freeze
|
|
107
111
|
# chi --remote NAME <command> (or CHI_REMOTE=NAME): the session commands
|
|
108
112
|
# against another machine's chi web; what runs here only is refused (exit 2).
|
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,8 +104,8 @@ 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
|
|
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
|
|
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
|
+
| 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 the boot string loads directly; SessionManager's `run_session_loop` forwarder stays for older spawners' strings. 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. |
|
|
111
111
|
|
|
@@ -162,9 +162,9 @@ Unchanged: `ContextProviders`' `{ruby}` (`RbConfig.ruby`: the home's ruby inside
|
|
|
162
162
|
project env below, so a `mise env` that sets GEM_HOME reaches it), `chi bundle
|
|
163
163
|
try/test/check` (`-I LIB_DIR`), hooks (in-process). The worker's boot string, `run_session_loop(id, state_dir:)` and
|
|
164
164
|
`SAMAGOTCHI_BOOT_FALLBACK` stay the cross-version contract (`spec/worker_contract_spec.rb`): the home only adds the
|
|
165
|
-
prelude in front. The string names `
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
prelude in front. The string names `WorkerBoot.run_session_loop`, the worker's main; the SessionManager forwarder
|
|
166
|
+
remains one more release for boot strings written by older spawners. An older chi that wakes a session doesn't read
|
|
167
|
+
home.json and starts its worker as before.
|
|
168
168
|
|
|
169
169
|
**The tools a worker runs** follow the project, not the boot, and only they do: a spawned worker
|
|
170
170
|
(`WORKER_PROCESS_ENV`; never an in-process loop) calls `ProjectEnv.compute` in `WorkerBoot.run_session_loop`, after the owner
|
|
@@ -194,7 +194,7 @@ log's last 4 MB). Rows: [configuration.md](configuration.md#checking-it-chi-home
|
|
|
194
194
|
|
|
195
195
|
## Session retention & ordering
|
|
196
196
|
|
|
197
|
-
- **Files:** `~/.local/state/samagotchi/sessions/<uuid>.json` + `<uuid>/input|output|owner.lock|bridge.json` (XDG-aware), and the `<uuid>/stopped` and `<uuid>/archived` marker files.
|
|
197
|
+
- **Files:** `~/.local/state/samagotchi/sessions/<uuid>.json` + `<uuid>/input|output|owner.lock|bridge.json` (XDG-aware), and the `<uuid>/stopped` and `<uuid>/archived` marker files. Durable schedules belong to the machine, not a session: `~/.local/state/samagotchi/schedules.json` and its `schedules.lock`, next to `sessions/` ([Scheduling](scheduling.md)).
|
|
198
198
|
- **Single owner:** the process running a session's Engine (its worker, or a `--non-interactive` one-shot) holds a flock on `owner.lock` (`OwnerLock`); a second owner backs off, and the web answers 409 for a session a one-shot owns.
|
|
199
199
|
- **Status:** `status` is turn state (`idle`/`running`); liveness is the lock. A stop is the `<uuid>/stopped` marker (`Session.mark_stopped`; a resume removes it), which `Session.load` and `.summary_from_file` read as status `stopped`, so no other process rewrites a worker's session file.
|
|
200
200
|
- **Retention:** 14 days / 500 cap (env `SAMAGOTCHI_SESSION_RETENTION_DAYS`/`MAX_COUNT`, optional `KEEP_STATUS`), live-owner guard, only when `*.json` present; lazy sweep at most once per `session.sweep_interval_hours` (default 24) from the session hub's full-probe tick (and on `GET /api/sessions`, which the page no longer calls), manual via `bin/chi sessions prune --dry-run`.
|
|
@@ -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
|
|
@@ -432,7 +432,7 @@ shared with `/api/sessions` and the session view; built on the session's `Sessio
|
|
|
432
432
|
reads, so the page, `chi sessions list` and `/children` agree on status, liveness and a waiting question) carries `owner`, `project_root` and
|
|
433
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
|
|
434
434
|
from that sidecar `worker_version` (the chi the worker runs) and `worker_features`
|
|
435
|
-
(`Bridge::FEATURES`, what a client may ask of it beyond the routes: `restart`, `task_stop`, `reparent`, `unqueue`,
|
|
435
|
+
(`Bridge::FEATURES`, what a client may ask of it beyond the routes: `restart`, `task_stop`, `reparent`, `unqueue`, `activity` (`GET /activity`, the busy check a schedule tick asks a live worker),
|
|
436
436
|
`delivery`, a worker that queues a message for after the turn; `SessionManager.deliver_turn` and
|
|
437
437
|
the attached TUI refuse a queue to a worker without it, which would steer; `turn_ids`, a worker whose running
|
|
438
438
|
turn's mark, continue turn and Stop carry the turn's `enqueued_id`, which `chi answer`, `chi send --wait` with no
|
|
@@ -459,7 +459,8 @@ model: [internals/remote-sessions.md](internals/remote-sessions.md).
|
|
|
459
459
|
|---|---|---|---|---|
|
|
460
460
|
| `GET /api/sessions/resolve?id=` | owner | an id or a unique prefix | 200 `{id}` | 404 `not_found`; 400 `ambiguous_id` with `ids` |
|
|
461
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) with counts, roots, default/current marks; no `dir`: no current project | 400 `invalid_dir`; 503 `no_hub` |
|
|
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` |
|
|
463
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` |
|
|
464
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` |
|
|
465
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`) |
|
|
@@ -618,9 +619,9 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
618
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. |
|
|
619
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`). |
|
|
620
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. |
|
|
621
|
-
| 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). |
|
|
622
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)). |
|
|
623
|
-
| 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`); `SessionSetup` the settings a fork and a continue carry, applied by member name. See [sessions.md](sessions.md#session-file). |
|
|
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). |
|
|
624
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). |
|
|
625
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)). |
|
|
626
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)). |
|
|
@@ -654,6 +655,7 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
654
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)). |
|
|
655
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)). |
|
|
656
657
|
| Stores | `reminder_store.rb` (`ReminderStore`), `recap_store.rb` (`RecapStore`) | A session's reminders, and its idle recap (`recap.json`). |
|
|
658
|
+
| Schedules | `schedules.rb` (`Schedules`, its `Entry`, `Tick`, `Index`), `schedule_command.rb` (`ScheduleCommand`) | Durable schedules that outlive every worker: `<state dir>/schedules.json` and its `schedules.lock`, the tick's busy check (a live worker asked over the Bridge's `GET /activity`, the files when there is none), the chain prune. `chi schedule` is this machine only. See [Scheduling](scheduling.md). |
|
|
657
659
|
| 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)). |
|
|
658
660
|
| 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. |
|
|
659
661
|
| 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). |
|
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
|
@@ -6,7 +6,8 @@ the plugin API ([plugins.md](plugins.md)); install, upgrade and the `chi bundle`
|
|
|
6
6
|
feature they belong to: **source-links** in [hooks.md](hooks.md#the-source-links-bundle) and **known-names** in
|
|
7
7
|
[guardrails.md](guardrails.md#the-known-names-bundle). Both hook events from their `plugin.rb` with `chi.on`
|
|
8
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
|
|
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).
|
|
10
11
|
|
|
11
12
|
## The btw bundle
|
|
12
13
|
|
data/docs/cli.md
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
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)
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
- `chi context report [--days N]` — the candidate judge's counts from `context_candidates.jsonl`: candidates proposed, mentioned, attached or declined by you; the judge's asks; what it would attach per threshold, and how that agrees with what you did (this machine only; see [The log and the report](context.md#the-log-and-the-report))
|
|
25
25
|
- `chi send [-m TEXT] [--image PATH]... [--cut | --queue] (ID|PREFIX)...` — send a message to sessions as if typed there: a turn starts (or a running one takes it at its next step; `--cut` asks it to cut long thinking for it; `--queue` runs it as a turn of its own after the running one, and `--queue --wait` waits for that turn's own answer); piped stdin goes above `-m` as quoted context, and `--image` attaches images (see [Sessions: Sending a message](sessions.md#sending-a-message)); `--new` starts a session with it instead (`--new --continues ID|last:ID` the next link of that session's chain, see [Session chains](sessions.md#session-chains)), and `--wait` prints the answer (`--wait ID` with no message waits for the next reply without sending — to an idle session whose last turn already ended, that ended turn's reply or end comes back; `--wait --turn T ID` with no message waits for exactly turn T, whether running, queued or last ended; `--format json` includes its `turn_id` when known, for waiting again after exit 3 or 4; exit 3 a question waits, its options on stderr; exit 4 `--timeout` passed with the turn still running; see [Starting a session](sessions.md#starting-a-session))
|
|
26
26
|
- `chi answer ID --question QID (--option N|LABEL)... [--text T] [--timeout S] [--format json]` (or `--dismiss`) — answer the question a session waits on (the one `chi send --wait` exited 3 with), then wait and print what comes next as `chi send --wait` does: the reply (0), the next question (3), still running after `--timeout` (4). `--option` is 1-based or the label, repeated on a multi-select question; `--text` is free text, or a Deny's reason; `--dismiss` leaves it unanswered and the model finishes its reply. A question no longer open (the web answered first) isn't answered again: it waits for that turn's reply. An option the question doesn't offer exits 2; a worker that is gone exits 1 (`send the task again: chi send --wait -m "…" ID`). What a parent may pick follows `guardrails.parent_answers`, or the session's own `parent_answers` when stricter (`soft`, the default: a deny, a plain answer, Continue and "Allow once"; `standard`: no allow; `hard`: no Continue either), never a wider scope or an allow on chi's own config; a refused pick exits 1 with what to answer instead (a convention, not a security boundary; see [Guardrails](guardrails.md#answers-from-a-parent-agent))
|
|
27
|
+
- `chi schedule <add|list|show|tick|run-now|enable|disable|cancel>` — durable schedules on this machine: a prompt with a clock that fires out of no worker (cron, systemd, or chi web's hub with `schedule.auto_tick`), as the next link of a session's chain or as a turn in the session itself (see [Scheduling](scheduling.md) and [Durable schedules](#durable-schedules-chi-schedule)). A usage error exits 2, an unknown session or schedule 1; `chi --remote X schedule list` exits 2
|
|
27
28
|
- `chi remote add NAME URL [--token-file F | --token-stdin]`, `chi remote ls`, `chi remote rm NAME` — the other machines whose chi web the session commands reach with `--remote NAME` (see [Remote sessions](#remote-sessions))
|
|
28
29
|
- `chi review FILE… [--dir DIR] [--model M]`, `chi review --from ID [FILE…]` — start a review session to invite participants to: for files of a project, or as a review of a working session that starts from its recap, not its transcript (see [Review sessions](#review-sessions))
|
|
29
30
|
- `chi share ID --name NAME [--identity EMAIL] [--agent] [--expires 3d] [--cap 2]`, `chi share ls [ID]`, `chi share cap ID P DOLLARS`, `chi share revoke ID [P] | --all` — invite a participant to a session through chi web on the LAN (read-only review turns in a review session, pair turns that act under your guardrails in a working session) (a link of their own, 7 days, a $2 spending cap), list them, change one's cap, revoke them (see [Participants](#participants))
|
|
@@ -35,7 +36,8 @@
|
|
|
35
36
|
- `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
37
|
- `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
38
|
- `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
|
|
39
|
+
- `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)
|
|
40
|
+
- `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)). `status NAME` lists the bundle's guardrail rules and scripts beside its plugin, each `[ok]`, `[missing]` or `[modified]` (edited: the next install replaces it, its copy kept in the trash; an edited rule doesn't load, so it counts in `issues=`), and `diff NAME` names an edited rule or script with its recorded and current sha256 (chi keeps no base text for them). 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
41
|
|
|
40
42
|
- `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
43
|
- `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 +134,11 @@ The loop for a bundle you're writing (the whole path: [bundle-authoring.md](bund
|
|
|
132
134
|
chi's Ruby (minitest is one of chi's gems; rspec is optional). The tests run the bundle's code as written, with
|
|
133
135
|
your environment (the kit sandboxes each test's HOME and XDG dirs, not the process).
|
|
134
136
|
- `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,
|
|
137
|
+
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
138
|
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
|
|
139
|
+
request; a new `scripts:` or `plugin:` entry needs `chi bundle install --dev PATH` again, since the record
|
|
140
|
+
has no entry for it), and no sha256 is checked for any of its files, including its memories, for this bundle only
|
|
141
|
+
(the record says `dev`; every other bundle is checked as before). Its memories are copied at install. `chi bundle
|
|
140
142
|
status` shows `NAME vX dev → /abs/path`. `chi bundle upgrade NAME` refuses it (it follows its source already; to
|
|
141
143
|
leave dev mode: `chi bundle uninstall NAME`, then `chi bundle install` without `--dev`), as does a plain install
|
|
142
144
|
over it, and `--dev` over a normal install. `uninstall` removes the links and the record, never `PATH`'s files.
|
|
@@ -144,10 +146,11 @@ The loop for a bundle you're writing (the whole path: [bundle-authoring.md](bund
|
|
|
144
146
|
- `chi bundle check [PATH] [--fix] [--set KEY=VALUE]` (PATH defaults to `.`) checks it as an install takes it, one
|
|
145
147
|
finding per line, `error|warn|info CODE file[:line]: message (fix: hint)`, then `ok|failed: N errors, N
|
|
146
148
|
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
|
|
149
|
+
(HOME, config and state), not in yours, but in chi's own process: the plugin's code runs as written,
|
|
148
150
|
so run it (and `test`) on code you'd install. The codes, in order: `manifest` (a parse error, verbatim; the run
|
|
149
|
-
stops), `
|
|
150
|
-
|
|
151
|
+
stops), `hooks-retired` (error: a manifest `hooks:` entry, or `hooks/*.rb` files: class-file hooks are retired,
|
|
152
|
+
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
|
|
153
|
+
isn't one), `sha` (a stale or placeholder sha, or a plugin / script entry with no sha line; `--fix`
|
|
151
154
|
rewrites the first two and prints `fixed sha FILE → sha256:…`), `unknown-key` (warn: a manifest key this chi's
|
|
152
155
|
parser never reads, so it ignores it, one row per key at its line; the install keeps the manifest, so a newer
|
|
153
156
|
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,7 +159,7 @@ The loop for a bundle you're writing (the whole path: [bundle-authoring.md](bund
|
|
|
156
159
|
`Manifest::SINCE`; an installed bundle gets the unknown-key row but never the floor, as it's the author's fix),
|
|
157
160
|
`trust` (warn: `trust_level: reviewed|trusted` on a
|
|
158
161
|
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
|
|
162
|
+
then forces), `install` (each Installer warning, a `needs` one as warn, and each plugin load failure at
|
|
160
163
|
the source `file:line`; skipped while a placeholder sha is unfilled), `registered` (info: each command, tool,
|
|
161
164
|
hook with its priority, init, toolkit, tool source, peer source and prompt section), `hook-event` (warn: a `chi.on` event chi
|
|
162
165
|
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
|
|
@@ -339,7 +342,8 @@ Also shipped, not installed: dev (mcp, skills, source-links) (chi bundle install
|
|
|
339
342
|
the merge itself, and `--force` replacing the file. A dry run and an automatic update
|
|
340
343
|
(`update.auto`) show it and leave it, and so does a failed row or one with no place
|
|
341
344
|
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.
|
|
345
|
+
newer version fails that bundle's row with the file's name. Rules, the plugin and scripts are replaced, and an
|
|
346
|
+
older install's class-file `hooks/` removed. One
|
|
343
347
|
whose bytes are neither what the install recorded (nothing recorded counts as edited) nor the new version's is
|
|
344
348
|
edited: the row says `replaced edited hooks/x (a copy goes to the trash first)` (`would replace` in the plan), and
|
|
345
349
|
a copy goes to the bundle trash first (`chi bundle trash`; `hooks/x`,
|
|
@@ -348,15 +352,16 @@ Also shipped, not installed: dev (mcp, skills, source-links) (chi bundle install
|
|
|
348
352
|
chi"), a newer installed one is left, one whose new version needs a newer
|
|
349
353
|
chi is skipped, and bundles you didn't install stay uninstalled.
|
|
350
354
|
- **Bundles not from chi** are never changed, but the chi the update leaves
|
|
351
|
-
checks what is installed of them (the plugin
|
|
355
|
+
checks what is installed of them (the plugin and rules as they are,
|
|
352
356
|
not their source, which may be gone) with `chi bundle check`'s own checks,
|
|
353
357
|
and each warning or error is a row under the bundle's name: `requires_chi`
|
|
354
|
-
ruling this chi out, a plugin
|
|
358
|
+
ruling this chi out, a plugin that no longer loads, a hook on an event
|
|
355
359
|
chi no longer fires, a `ctx`/`chi` call the API lacks, a reference to chi's
|
|
356
360
|
internals that this chi no longer has (`Samagotchi::OldInternal::Thing is gone from this chi, so this bundle may
|
|
357
361
|
fail` — a name that still resolves gets no row, so a bundle reaching `Samagotchi::Log` isn't warned about on every
|
|
358
|
-
update), a name chi now ships,
|
|
359
|
-
doesn't load)
|
|
362
|
+
update), a name chi now ships, a rule or plugin edited since it was installed (it
|
|
363
|
+
doesn't load), or class-file hooks an older chi installed (`hooks-retired`: they no longer load; `chi bundle upgrade
|
|
364
|
+
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
|
|
360
365
|
missing `requires_chi`, its floor, `trust_level`) is left out, and so are
|
|
361
366
|
profiles. A clean bundle gets no row beyond its `skipped (not from chi)`.
|
|
362
367
|
- **They fail nothing:** an error row too has `failed: false` and leaves the exit
|
|
@@ -432,6 +437,60 @@ bundle). After a gem update, the first interactive start of the new version
|
|
|
432
437
|
(`chi`, `chi web`; not `-p` or `--non-interactive`) says in one line when
|
|
433
438
|
bundles or the helper can be updated.
|
|
434
439
|
|
|
440
|
+
### Durable schedules (`chi schedule`)
|
|
441
|
+
|
|
442
|
+
A schedule is a prompt with a clock, kept in
|
|
443
|
+
`~/.local/state/samagotchi/schedules.json` and fired by a **tick** that needs no
|
|
444
|
+
worker: cron, systemd, `chi schedule tick`, or chi web's hub when
|
|
445
|
+
`schedule.auto_tick: true`. How it works, what "busy" means and the DST caveat:
|
|
446
|
+
[Scheduling](scheduling.md). This machine only — `chi --remote studio schedule
|
|
447
|
+
list` exits 2.
|
|
448
|
+
|
|
449
|
+
```
|
|
450
|
+
# the daily coordinator, every Monday 09:00 local, each run a fresh link of the chain
|
|
451
|
+
chi schedule add --session 3f9a1c2e --weekday 1 --time 09:00 -m "Audit the open PRs" --title "Monday audit"
|
|
452
|
+
|
|
453
|
+
# every 30 minutes, as a turn in the session itself
|
|
454
|
+
chi schedule add --continues 3f9a1c2e --every 30m --mode same -m "Check the build"
|
|
455
|
+
|
|
456
|
+
chi schedule list # id mode recurrence next due target [skips 3 of 12 (≈1 h at a 5 min tick)]
|
|
457
|
+
chi schedule list --all --format json # the disabled ones and the fired one-offs too
|
|
458
|
+
chi schedule show 4b7e9a # the entry in full: anchor, head, prompt, counters
|
|
459
|
+
chi schedule tick # fire everything due; quiet when nothing is
|
|
460
|
+
chi schedule tick --dry-run # print what would fire, change nothing
|
|
461
|
+
chi schedule run-now 4b7e9a # fire it now, whatever its next_due says
|
|
462
|
+
chi schedule disable 4b7e9a # stop it, keep it in the file
|
|
463
|
+
chi schedule enable 4b7e9a
|
|
464
|
+
chi schedule cancel 4b7e9a # delete it (by id, a unique prefix, or its title)
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
`add` needs a target (`--session ID`, or `--continues ID` for the same session)
|
|
468
|
+
and exactly one recurrence kind — `--every 45m|2h|1d`, `--weekday 1..7` with
|
|
469
|
+
`--time HH:MM` (local wall clock), or `--date 2026-11-20T09:00` — plus `-m|--message|--prompt TEXT`.
|
|
470
|
+
`--title` names it, `--mode chain|same` picks the mode (chain by default),
|
|
471
|
+
`--catch-up once|none` what an overdue entry does, `--keep-links N` how many chain
|
|
472
|
+
links stay behind the head (`0` keeps all), and `--max-failures` / `--max-skips`
|
|
473
|
+
how many consecutive failures or busy targets disable it. A blank or over-16-KiB
|
|
474
|
+
prompt, two recurrence kinds, a `scratch` target and a `--weekday` without
|
|
475
|
+
`--time` are all refused with exit 2.
|
|
476
|
+
|
|
477
|
+
`tick` prints one line per entry it touched (`fired`, `skipped`, `missed`,
|
|
478
|
+
`failed`, or `would fire` under `--dry-run`), with the reason; nothing due prints
|
|
479
|
+
`no schedules due`, and a tick that finds the lock held by another prints `no
|
|
480
|
+
schedules due (another tick holds the lock)` — both exit 0, so a crontab line
|
|
481
|
+
that runs every five minutes is quiet. `run-now`, `enable`, `disable` and `cancel`
|
|
482
|
+
take the id, a unique prefix of it, or the title; a missing one exits 1, an ambiguous one 2 naming the matches.
|
|
483
|
+
|
|
484
|
+
Point cron at it (see [Scheduling](scheduling.md#running-the-tick) for systemd
|
|
485
|
+
and launchd), or turn on `schedule.auto_tick` and let chi web's hub tick every
|
|
486
|
+
`schedule.tick_interval_minutes` minutes; the lock covers both, so they never
|
|
487
|
+
fire twice.
|
|
488
|
+
|
|
489
|
+
The model can register its own schedules with `schedule_task` (defaulting to the
|
|
490
|
+
session it is in), list them with `list_schedules` and stop them with
|
|
491
|
+
`cancel_schedule`; like `register_reminder`, these are owner-voiced tools, refused
|
|
492
|
+
in a participant's review or pair turn.
|
|
493
|
+
|
|
435
494
|
## Flags
|
|
436
495
|
|
|
437
496
|
Samagotchi exposes one flag that feeds a prompt (`-p`, `--prompt`) and one that
|
|
@@ -1427,7 +1486,7 @@ Scan the QR code with the phone's camera. The page trades the token in the
|
|
|
1427
1486
|
link for a cookie (kept 400 days) and drops it from the address, so a
|
|
1428
1487
|
bookmark or a home-screen icon keeps working across restarts. It opens on
|
|
1429
1488
|
the project chi web starts in (`--start-dir DIR` or `web.start_dir` picks
|
|
1430
|
-
another; outside a
|
|
1489
|
+
another; outside a project (no repository or marked folder) it shows every session); the header's `all` shows
|
|
1431
1490
|
every project's. A home-screen
|
|
1432
1491
|
web app on iOS has cookies of its own: if it opens on "needs chi web's
|
|
1433
1492
|
access token", paste the token there (the part of the link after
|
data/docs/configuration.md
CHANGED
|
@@ -174,6 +174,7 @@ or `chi web` restart.
|
|
|
174
174
|
| `recap.*` | Worker start | The engine builds its recap job at start, and again when it binds a session with its own `recap.enabled` or `recap.sentences` (`--set`, see "Per-session settings") and when `/recap on\|off\|default` changes the session's own value. |
|
|
175
175
|
| `session.idle_exit_minutes`, `session.project_env`, `session.carry_last_answer`, `session.keep_empty`, `session.max_children`, `session.delegate_reports`, `session.task_wakes`, `session.max_wakes` | Worker start or next matching lifecycle decision | Existing workers keep their idle-exit timer and project env; the other values are read for the next corresponding decision. |
|
|
176
176
|
| `session.retention_*`, `session.max_count`, `session.keep_status`, `session.sweep_interval_hours` | Next retention sweep | `chi web` sweeps on its configured schedule and on `GET /api/sessions`; `chi sessions prune` uses the values for that invocation. The sweep interval is checked on the next hub tick. |
|
|
177
|
+
| `schedule.*` | Next CLI run | `chi schedule add` and `chi schedule tick` read them for that run; with `schedule.auto_tick` on, `chi web`'s hub ticks on `schedule.tick_interval_minutes`. |
|
|
177
178
|
| `web.*` except `web.participants.*` | `chi web` start | Restart `chi web` to change its bind address, port or page settings. |
|
|
178
179
|
| `log.*` | Process start | Each process holds its configured log sink and level after first use; restart that process. |
|
|
179
180
|
| `history.file` | Next history access | The TUI and web composer resolve its path when they read or append history. |
|
|
@@ -1471,10 +1472,12 @@ test run (`SAMAGOTCHI_ENV`, `RACK_ENV`, `CI`). The day is stamped in `$XDG_STATE
|
|
|
1471
1472
|
If an AGENTS.md file is present in the project root, samagotchi injects its
|
|
1472
1473
|
contents into the system prompt under a "Project specific description:" section.
|
|
1473
1474
|
The project root is the top of the git work tree chi runs in (a linked
|
|
1474
|
-
worktree's own checkout), or the
|
|
1475
|
+
worktree's own checkout), or of the folder marked by `chi project init` it runs
|
|
1476
|
+
in (see [Projects without git](memory.md#projects-without-git)); outside both,
|
|
1477
|
+
the current directory.
|
|
1475
1478
|
|
|
1476
|
-
Started in a subdirectory, chi loads the chain: every AGENTS.md from the
|
|
1477
|
-
|
|
1479
|
+
Started in a subdirectory, chi loads the chain: every AGENTS.md from the
|
|
1480
|
+
project's top down to the current directory, outermost first. The first keeps the
|
|
1478
1481
|
plain header; each further one is headed with its directory, e.g. "Project
|
|
1479
1482
|
specific description for pkg/:". Outside a repository only the current
|
|
1480
1483
|
directory's AGENTS.md is read. Edits are picked up by a new process or a
|
|
@@ -2125,7 +2128,7 @@ are never sent to; `chi web push rm ID` removes them. From the Mac: `chi web pus
|
|
|
2125
2128
|
shows a recent delivery (Apple keeps accepting pushes for it): if one stops getting notifications, switch it off and on
|
|
2126
2129
|
there; the new subscription replaces the dead one.
|
|
2127
2130
|
|
|
2128
|
-
- **What a tap opens**: the session, in its own project's view (the all view for a session in no
|
|
2131
|
+
- **What a tap opens**: the session, in its own project's view (the all view for a session in no project: no repository or marked folder), whichever
|
|
2129
2132
|
project the app was showing; an open app window moves there.
|
|
2130
2133
|
- **What is sent**: the session's name and the reason ("needs approval", "needs an answer", "hit its step limit",
|
|
2131
2134
|
"needs you", "turn failed", "done in N s"), never the question or the command, as the tab's notification on the
|
|
@@ -2268,6 +2271,14 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2268
2271
|
| `session.max_count` | `500` | yes | Keep the newest N; `0` = uncapped. |
|
|
2269
2272
|
| `session.keep_status` | none | yes | Comma list of statuses never pruned (a session a worker or `chi` has open is never pruned anyway). |
|
|
2270
2273
|
| `session.sweep_interval_hours` | `24` | yes | How often the retention sweep runs. |
|
|
2274
|
+
| `schedule.auto_tick` | `false` | | `chi web`'s hub runs `chi schedule tick` too, sharing the schedule lock with cron. Off by default: cron or systemd is the documented driver. See [Scheduling](scheduling.md). |
|
|
2275
|
+
| `schedule.tick_interval_minutes` | `5` | | How often the hub ticks when `schedule.auto_tick` is on, and how late a `catch_up: none` schedule may be before it moves to its next occurrence. |
|
|
2276
|
+
| `schedule.default_keep_links` | `5` | | Chain links a schedule keeps behind its current one (`0` keeps all). Archived links are outside the retention sweep, so this is what bounds them. See [Scheduling](scheduling.md). |
|
|
2277
|
+
| `schedule.default_max_failures` | `3` | | Consecutive failures that disable a schedule. |
|
|
2278
|
+
| `schedule.default_max_skips` | `12` | | Consecutive busy targets that disable a schedule; `list` prints it as a time window. |
|
|
2279
|
+
| `schedule.default_catch_up` | `once` | | An overdue schedule fires once at the next tick (`once`) or moves to its next occurrence (`none`). |
|
|
2280
|
+
| `schedule.max_per_session` | `10` | | Enabled schedules one chain may hold. `schedule_task` (and `chi schedule add`) refuse past it, so a routine that re-schedules itself cannot pile up entries. |
|
|
2281
|
+
| `schedule.max_total` | `50` | | Enabled schedules this machine may hold, across every chain. |
|
|
2271
2282
|
| `image.max_side` | `1568` | | See "Images". |
|
|
2272
2283
|
| `image.max_bytes` | `3750000` | | See "Images". |
|
|
2273
2284
|
| `image.max_per_request` | `20` | | See "Images". |
|
|
@@ -2370,7 +2381,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2370
2381
|
| `web.reload_check` | `false` | yes | Opt-in: once each finished turn has moved into the history, the page reads the session again (one full read per turn end), draws that turn as a reload would and compares the two, strictly: a known divergence counts as a mismatch too. `chi web` logs one `reload_checked` line per check and a `reload_mismatch` line naming the kinds that differed, `excused` (the known divergences, `history_shape.js` `ACCEPTED`, that would explain them) and `explained` (all of them had one), with `turn_id`, `drawn` (the turn came back from its drawing, so a mismatch with `drawn: true` is a drawing bug) and the worker's version: counts only, never content. The count is `grep -c reload_mismatch` over `grep -c reload_checked` in chi web's log, split by `excused`. Cards are left out: a reload places them after the render, which the check doesn't run (the e2e reload checks compare them). Every open owner tab runs the check; `chi web` logs a turn's first report only, and starts over when it restarts. |
|
|
2371
2382
|
| `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). |
|
|
2372
2383
|
| `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). |
|
|
2373
|
-
| `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
|
|
2384
|
+
| `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 project (no repository or marked folder) 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). |
|
|
2374
2385
|
| `web.participants.expires` | `7d` | | How long a participant's link lasts unless `chi share --expires` says otherwise: `Nh` or `Nd`, 1h to 30d. See [participants](internals/participants.md). |
|
|
2375
2386
|
| `web.participants.cap` | `2.0` | | What a participant's turns, and the side calls they cause, may cost you in dollars unless `chi share --cap` says otherwise ($0 to $1000); at the cap their next comment is refused (429 `cap_reached`) and you get a notice. `chi share cap ID P DOLLARS` changes one grant's. |
|
|
2376
2387
|
| `web.participants.queue` | `3` | | How many of a participant's turns may wait behind their running one (0 to 20); one more is refused (429 `too_many_turns`). |
|
data/docs/context.md
CHANGED
|
@@ -71,10 +71,12 @@ A source belongs to one session, or to a project:
|
|
|
71
71
|
|
|
72
72
|
- A **session** source (`chi context add NAME … <id>`) is that session's
|
|
73
73
|
alone and runs in the session's folder (the worktree it started in).
|
|
74
|
-
- A **project** source (`--project`, inside a git repository
|
|
75
|
-
|
|
74
|
+
- A **project** source (`--project`, inside a git repository or a folder
|
|
75
|
+
marked by `chi project init`) has **one snapshot shared by every session of
|
|
76
|
+
the project**: all worktrees of a repo (or subfolders of a marked folder)
|
|
76
77
|
share the project, and the command runs in the project root (the main
|
|
77
|
-
checkout; the session's folder when the root is a bare
|
|
78
|
+
checkout, or the marked folder; the session's folder when the root is a bare
|
|
79
|
+
git dir). Whichever
|
|
78
80
|
worker is due runs it; the others read the snapshot.
|
|
79
81
|
|
|
80
82
|
So anything that depends on the branch or the checkout (a PR, `git status`,
|
|
@@ -248,7 +250,9 @@ you're away from the terminal. All of these must hold:
|
|
|
248
250
|
project source's first text may predate the session, so neither wakes;
|
|
249
251
|
- `context.wake` is on (default `true`);
|
|
250
252
|
- the session's worker is up and idle: no turn running, nothing queued, no
|
|
251
|
-
question or continue offer waiting, not just started
|
|
253
|
+
question or continue offer waiting, not just started. A changed push from a
|
|
254
|
+
session-scoped source can start an idle-exited worker; it never restarts an
|
|
255
|
+
explicitly stopped session;
|
|
252
256
|
- under `session.max_wakes` turns in a row with no message from you (the
|
|
253
257
|
budget delegate reports and finished background tasks use too; a turn that
|
|
254
258
|
failed, or was stopped before the model call, pauses wakes until you write);
|
|
@@ -341,6 +345,10 @@ the chain's, names what moved and what stayed:
|
|
|
341
345
|
|
|
342
346
|
> Context moved with this session: pr-412, ci. Left with 3f2a9c1e: notes (pushed).
|
|
343
347
|
|
|
348
|
+
On a continue, text from a pushed source that the old session had not absorbed
|
|
349
|
+
or read is also carried in a separate note, clearly framed as third-party
|
|
350
|
+
text. The source itself stays with its old link; forks do not carry this text.
|
|
351
|
+
|
|
344
352
|
`chi send --new --continues` and the web's Continue toast say the same in a
|
|
345
353
|
few words, and `chi context ls` marks a session's source that stays
|
|
346
354
|
(`· stays`; `--format json` has the derived `movable`). Project sources are
|