samagotchi 0.18.1 → 0.20.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 +167 -1
- data/README.md +4 -3
- data/docs/architecture.md +21 -2
- data/docs/cli.md +48 -11
- data/docs/configuration.md +12 -5
- data/docs/guardrails.md +92 -14
- data/docs/memory.md +4 -0
- data/docs/plugins.md +5 -0
- data/docs/sessions.md +7 -5
- data/lib/samagotchi/bootstrap/config_writer.rb +14 -3
- data/lib/samagotchi/bootstrap_command.rb +26 -5
- data/lib/samagotchi/bridge.rb +25 -9
- data/lib/samagotchi/bridge_client/event_stream.rb +37 -1
- data/lib/samagotchi/bridge_client.rb +9 -5
- data/lib/samagotchi/bundle_command.rb +24 -5
- data/lib/samagotchi/bundles/check-in/manifest.yml +2 -2
- data/lib/samagotchi/bundles/check-in/plugin.rb +14 -5
- data/lib/samagotchi/bundles/guardrails/guardrails/rules.yml +24 -5
- data/lib/samagotchi/bundles/guardrails/manifest.yml +5 -4
- data/lib/samagotchi/bundles/mcp/manifest.yml +2 -2
- data/lib/samagotchi/bundles/mcp/plugin.rb +18 -4
- data/lib/samagotchi/bundles/source-links/hooks/source_links.rb +7 -4
- data/lib/samagotchi/bundles/source-links/manifest.yml +2 -2
- data/lib/samagotchi/bundles/system/manifest.yml +2 -2
- data/lib/samagotchi/bundles/system/memory_guide.md +2 -2
- data/lib/samagotchi/commands/registry.rb +4 -3
- data/lib/samagotchi/config.rb +3 -0
- data/lib/samagotchi/context_usage.rb +3 -3
- data/lib/samagotchi/engine.rb +25 -5
- data/lib/samagotchi/guardrail_wiring.rb +10 -3
- data/lib/samagotchi/guardrails/approval.rb +14 -7
- data/lib/samagotchi/guardrails/approvals.rb +69 -15
- data/lib/samagotchi/guardrails/context.rb +16 -9
- data/lib/samagotchi/guardrails/parent_approvals.rb +10 -4
- data/lib/samagotchi/guardrails/read_only_shell.rb +322 -0
- data/lib/samagotchi/guardrails/rm_targets.rb +86 -0
- data/lib/samagotchi/guardrails/rules.rb +69 -5
- data/lib/samagotchi/guardrails/shell_git_dirs.rb +5 -137
- data/lib/samagotchi/guardrails/shell_lex.rb +164 -0
- data/lib/samagotchi/guardrails/shell_paths.rb +145 -0
- data/lib/samagotchi/guardrails/targets.rb +65 -4
- data/lib/samagotchi/guardrails.rb +2 -0
- data/lib/samagotchi/hooks/registry.rb +6 -2
- data/lib/samagotchi/host_registry.rb +22 -4
- data/lib/samagotchi/idle_recap.rb +7 -2
- data/lib/samagotchi/idle_scheduler.rb +1 -1
- data/lib/samagotchi/installed_versions.rb +91 -0
- data/lib/samagotchi/live_versions.rb +5 -3
- data/lib/samagotchi/llm/usage.rb +1 -1
- data/lib/samagotchi/memory_bundle/builder.rb +25 -6
- data/lib/samagotchi/memory_bundle/index_sync.rb +1 -9
- data/lib/samagotchi/memory_bundle/installer.rb +79 -13
- data/lib/samagotchi/memory_bundle/shipped_update.rb +3 -1
- data/lib/samagotchi/memory_bundle/status.rb +17 -5
- data/lib/samagotchi/memory_bundle/uninstaller.rb +7 -7
- data/lib/samagotchi/memory_paths.rb +6 -0
- data/lib/samagotchi/model_overlay.rb +39 -0
- data/lib/samagotchi/model_profile.rb +4 -0
- data/lib/samagotchi/relay_desk.rb +9 -0
- data/lib/samagotchi/self_report.rb +38 -2
- data/lib/samagotchi/session.rb +35 -6
- data/lib/samagotchi/session_commands.rb +13 -2
- data/lib/samagotchi/session_manager.rb +166 -11
- data/lib/samagotchi/session_metrics.rb +260 -32
- data/lib/samagotchi/sessions_command.rb +43 -4
- data/lib/samagotchi/system_prompt.rb +10 -1
- data/lib/samagotchi/terminal_ui/attached_loop.rb +48 -3
- data/lib/samagotchi/terminal_ui/formatting.rb +52 -1
- data/lib/samagotchi/terminal_ui/image_input.rb +11 -4
- data/lib/samagotchi/terminal_ui/version_lines.rb +48 -0
- data/lib/samagotchi/token_usage.rb +57 -41
- data/lib/samagotchi/tool_runner.rb +21 -2
- data/lib/samagotchi/tools/builtins.rb +21 -5
- data/lib/samagotchi/tools/execute.rb +9 -8
- data/lib/samagotchi/turn_note.rb +3 -2
- data/lib/samagotchi/update_command.rb +33 -12
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +83 -11
- data/lib/samagotchi/web/public/app.js +135 -43
- data/lib/samagotchi/web/public/card.js +34 -2
- data/lib/samagotchi/web/public/ctx.js +59 -0
- data/lib/samagotchi/web/public/data.js +6 -0
- data/lib/samagotchi/web/public/format.js +15 -2
- data/lib/samagotchi/web/public/index.html +37 -2
- data/lib/samagotchi/web/public/model_pick.js +6 -2
- data/lib/samagotchi/web/public/model_picker.js +2 -1
- data/lib/samagotchi/web/public/question_card.js +14 -1
- data/lib/samagotchi/web/public/question_cards.js +17 -11
- data/lib/samagotchi/web/public/scope.js +15 -6
- data/lib/samagotchi/web/public/session_state.js +4 -0
- data/lib/samagotchi/web/public/timing.js +6 -2
- data/lib/samagotchi/web/public/turn_events.js +108 -4
- data/lib/samagotchi/web/public/update_notice.js +87 -14
- data/lib/samagotchi/web/server.rb +28 -1
- data/lib/samagotchi/web/session_hub.rb +30 -3
- data/lib/samagotchi/web/session_summary.rb +11 -2
- data/lib/samagotchi/worker.rb +25 -8
- data/lib/samagotchi/worker_idle_exit.rb +31 -2
- data/lib/samagotchi/worker_sidecar.rb +7 -5
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c3b1a6860a8c22ed75259438c755633283385c12ffbc28a8fcb4c817f59114c5
|
|
4
|
+
data.tar.gz: 24f7c45ebe336077bc2d9a1e670d3313b364c48d5b28aef3624593705236f29e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9f1d9dec24344b223170728f80629a76d1db18697f752b2ce7135cf3569428a902f1cc18589a928184f7809bcbe3a20289281cd4cae6324bdd3f5bb1192cf860
|
|
7
|
+
data.tar.gz: 8bf9a7cf6dbaac98a7583987be61d98e06ddd3ab6a0b6f36423ae41a6aa530ef42479fa28139ad89b8253e61edce1a57013dd27d0a9bcbf5b31c080cea6f8801
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,170 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.20.0] - 2026-10-03
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `guardrails.mode` (config.yml only): `auto`, the new default, or `strict`. Rules can be tagged `modes: [strict]`
|
|
16
|
+
to vote only in strict mode; a rule without `modes:` (every rule you wrote in config.yml) votes in both.
|
|
17
|
+
`/guardrails` shows the mode and marks the rules it leaves out `(strict only)`. See docs/guardrails.md#modes.
|
|
18
|
+
- New guardrail rule keys: `skip_read_only: true` (a shell command that only reads, such as `ls`, `cat`, `rg`,
|
|
19
|
+
`sed -n` or `git log`, doesn't match), `touches: chi_dirs` (a shell command names a path in chi's real config,
|
|
20
|
+
hooks, approvals or bundles dir, or a `.git/hooks`) and `rm: outside_tmp` (an `rm -rf` reaches outside the tmp
|
|
21
|
+
dirs). A config.yml rule that uses one fails closed on an older chi.
|
|
22
|
+
- Model speed and token stats. `/stats` has a speed line (the last generation's decode speed and the
|
|
23
|
+
session's average: exact from llama.cpp, estimated and marked `~` elsewhere), cached and reasoning
|
|
24
|
+
tokens, and the cost when the provider reports it (OpenRouter). The web's info bar shows the speed
|
|
25
|
+
next to `ctx`, updated after each generation, and the `ctx` tooltip there and on session cards lists
|
|
26
|
+
tokens in / cached / out (+ reasoning) and the cost, for that session only.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- [BEHAVIOUR] Guardrails ask less by default (auto mode). The guardrails bundle (0.5.0) no longer asks before
|
|
31
|
+
`git rebase`, writes outside the session's repo (`write-outside-repo`) or git in another checkout
|
|
32
|
+
(`git-outside-repo`); `guardrails: { mode: strict }` in config.yml brings those back. Everything else still asks
|
|
33
|
+
in both modes, as do the small-model rules and chi's own protected paths.
|
|
34
|
+
- [BEHAVIOUR] `shell-touches-chi` matches chi's real folders instead of text, and lets read-only commands through:
|
|
35
|
+
`ls ~/.config/samagotchi`, `rg samagotchi/hooks lib` and a scratch copy under `/tmp` no longer ask; `echo x >>
|
|
36
|
+
<config dir>/config.yml` and `cp hook .git/hooks/pre-commit` still do. A word it can't resolve falls back to the
|
|
37
|
+
old text match.
|
|
38
|
+
- [BEHAVIOUR] `rm-rf-wide` no longer asks when every `rm -rf` target is inside a tmp dir (`rm -rf /tmp/x`);
|
|
39
|
+
`/tmp` itself, `/tmp/*`, a `$VAR` and a link out of tmp still ask.
|
|
40
|
+
- [BEHAVIOUR] "Allow … in this repo" approvals hold for the whole repository, in every worktree of it, and the
|
|
41
|
+
ask names the repository (`in this repo (samagotchi)`) instead of the worktree folder. Approvals stored
|
|
42
|
+
before keep matching their exact folder.
|
|
43
|
+
- `chi bundle status` shows a bundle whose recorded scope this chi doesn't know (one a newer chi wrote, or a hand
|
|
44
|
+
edit) as `scope=team (unknown)`, counted as one issue, instead of checking its files in the system memories;
|
|
45
|
+
the shipped-bundle update skips it (upgrade chi or reinstall), and `chi bundle diff` refuses it with a one-line
|
|
46
|
+
error instead of a stack trace.
|
|
47
|
+
- The web model picker shows a model's configured sampling (`temperature=0.6 (hosts.work)`) as its row's tooltip;
|
|
48
|
+
`GET /api/models` has it as `sampling` on the models that have some.
|
|
49
|
+
- The web shows a plugin card that is only a notice (info level, no buttons, one short line, such as check-in's
|
|
50
|
+
"Nudged the model at 105 tool calls.") as a one-line row, `▸ check-in: Nudged …`, that opens on a click, like the
|
|
51
|
+
tool rows and resolved questions; warn cards, cards with buttons and longer ones stay framed cards.
|
|
52
|
+
- On a phone (a window under 900 px wide) the sessions strip's `hide` is in the top bar, where the `▾ N sessions`
|
|
53
|
+
pill comes back, with a finger-sized target, instead of the last column of the sideways-scrolling strip.
|
|
54
|
+
- On a phone the web info bar shows `mem N` (the memories the session used; their names in the tooltip) after the
|
|
55
|
+
session's status, since the `mem: …` line is hidden there.
|
|
56
|
+
- The web info bar's chips (model, ctx, speed, session time) are tinted over the card's glass instead of solid, and
|
|
57
|
+
the empty-history cover is see-through like the session panel.
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- An MCP server that exits without a wait status no longer raises `NoMethodError`; its waiting calls fail with
|
|
62
|
+
"the server exited" instead of hanging.
|
|
63
|
+
- A hook that raises is now logged (`hook_failed`) instead of being swallowed silently; the turn still goes on.
|
|
64
|
+
- A hook's card (check-in, skills) now prints under its tool call's row: `tool_call_completed` is emitted before
|
|
65
|
+
`after_tool_call` fires.
|
|
66
|
+
- When a hook corrects a tool call (known-names), the model is told what actually ran with a leading
|
|
67
|
+
`ran as: <tool> <args>` line.
|
|
68
|
+
- MCP image content is described with a neutral `[image N: …]` line instead of claiming it was attached, which
|
|
69
|
+
was wrong for a model that can't see images.
|
|
70
|
+
- An MCP `resource` block carrying an image `blob` is now attached like an `image` block instead of being
|
|
71
|
+
dropped to its URI text.
|
|
72
|
+
- check-in's `nudge` mode no longer says "nudged" when the steer was dropped later; it says "nudge not sent" at
|
|
73
|
+
the turn's end.
|
|
74
|
+
- A session started with an annotation (a web quote) is previewed by the note typed under the quote, not
|
|
75
|
+
`From your thinking: > …`; a quote with no note previews by its words.
|
|
76
|
+
- A session that has only context notes so far (`chi note`, `send_note`) is previewed on its card and in the
|
|
77
|
+
lists as `note: …` instead of `—`, until a message is typed.
|
|
78
|
+
- A web turn of images alone names each image once in the transcript a recap is written from, not twice.
|
|
79
|
+
- `chi bootstrap` no longer says "loading the model?" for a slow test on a remote provider (OpenRouter and the
|
|
80
|
+
like); the hint is for a local server, where a slow answer is a model loading.
|
|
81
|
+
- `chi bootstrap` says why it saved a host as `name-2` when the derived name is already taken (or a model id
|
|
82
|
+
starts with it), instead of silently picking another name.
|
|
83
|
+
- `chi bundle upgrade` reports a hook or plugin file that is byte-identical to the installed one as "already up
|
|
84
|
+
to date" instead of "Updated".
|
|
85
|
+
- `chi bundle upgrade --agent` from a git/zip/tar source no longer hands the agent an `incoming:` path that was
|
|
86
|
+
already deleted: the extracted source is kept until the agent step is done, then cleaned up.
|
|
87
|
+
- `chi self` now checks a local `api: openai` host's reachability (a `GET <base>/models` with the same short
|
|
88
|
+
probe timeouts) and reports up/down with the ids it serves, instead of always saying "reported per turn".
|
|
89
|
+
|
|
90
|
+
Update with `chi update`: guardrails moves to 0.5.0 (auto mode and the new rule keys; it needs chi 0.20.0), mcp to 0.4.1 (exit status, image lines, image blobs) and check-in to 0.2.1 (a dropped nudge says so). Restart `chi web` and running sessions afterwards (`chi sessions restart ID`).
|
|
91
|
+
|
|
92
|
+
## [0.19.0] - 2026-10-03
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
|
|
96
|
+
- A new or woken session worker runs the newest chi installed, whoever starts it: a `chi web`, `chi send` or
|
|
97
|
+
terminal left on an older chi no longer starts workers on its own version. A worker already running keeps its
|
|
98
|
+
version until it is restarted.
|
|
99
|
+
|
|
100
|
+
### Added
|
|
101
|
+
|
|
102
|
+
- `chi web` notices a newer chi installed (`chi update`, `gem update`, a `git pull` in a checkout) and says to
|
|
103
|
+
restart it, in its terminal and once in each open page.
|
|
104
|
+
- The web's info bar marks a session whose worker runs an older chi than the newest installed, with a Restart button
|
|
105
|
+
(or, for a worker from before restarts, the `chi sessions stop ID` to run); the page and the draft in the
|
|
106
|
+
composer stay as they are and follow the new worker.
|
|
107
|
+
- An attached terminal says in one line when the session's worker or the terminal itself runs an older chi than
|
|
108
|
+
the newest installed, and how to move each (`chi sessions restart ID`; `/detach`, then `chi --attach ID`). When
|
|
109
|
+
the worker restarts, the terminal stays attached and says so.
|
|
110
|
+
- `chi sessions restart ID...` moves a running session to a new worker on the newest chi installed, keeping its
|
|
111
|
+
attached terminal and web tabs on it; it is refused, with the reason, while a turn, a question, reminders or
|
|
112
|
+
background tasks would be lost.
|
|
113
|
+
- A bundle can ship per-model memory overlays (`tips.<model-key>.md` beside `tips.md`): they load only for that
|
|
114
|
+
model, as a `memory_write current_model_only` overlay does, and `chi bundle build tips.md` brings them along.
|
|
115
|
+
|
|
116
|
+
### Fixed
|
|
117
|
+
|
|
118
|
+
- `chi update` no longer says running sessions move to the new chi "at idle exit (30 min)": a worker keeps its chi
|
|
119
|
+
until restarted, and idles out only with nothing attached, after `session.idle_exit_minutes` (never with 0). The
|
|
120
|
+
workers row names `chi sessions restart ID` (or `stop` for a worker from before restarts).
|
|
121
|
+
- `chi web` no longer leaves exited session workers behind as zombie processes.
|
|
122
|
+
- The web's model picker lists a host added to (or changed in) `hosts:` while `chi web` runs, instead of the hosts
|
|
123
|
+
it started with.
|
|
124
|
+
- A bundle's model overlay no longer gets an `index.md` line of its own after `chi bundle install`, which showed it
|
|
125
|
+
to every model as a memory to read; `chi bundle status` reads it `ok (model overlay)`, uninstall no longer re-adds
|
|
126
|
+
its line, and an overlay whose base is nowhere, or only among your installed memories, installs with a warning. A
|
|
127
|
+
line an earlier install wrote goes with the bundle's next upgrade.
|
|
128
|
+
- source-links (0.3.2): a `case_insensitive: true` source no longer lists a ref in its `sources:` note when the ref
|
|
129
|
+
is a markdown link's label whose target names it in another case (`[jira-1](…/JIRA-1)`). Run `chi update` to get it.
|
|
130
|
+
- An `@path` image in a prompt takes backslash escapes, as a Finder drag into the terminal types them:
|
|
131
|
+
`@my\ shot.png` and `@a\ \(1\).png` attach the file instead of stopping at the first space.
|
|
132
|
+
- An `http` host named by a public name (`gpu.example.com`) counts as a remote provider (120-second first-token
|
|
133
|
+
limit, no llama.cpp `/props`), as a public IP address already did. Names without a dot and local suffixes
|
|
134
|
+
(`.local`, `.lan`, `.home.arpa`, `.internal`, `.ts.net`, `fritz.box`, …) stay local; `hosts.<name>.remote` decides
|
|
135
|
+
either way.
|
|
136
|
+
- `chi web` no longer logs `ERROR HTTPRequest#fixup: WEBrick::HTTPStatus::LengthRequired occurred.` after a POST
|
|
137
|
+
without a body.
|
|
138
|
+
- The web's delete confirm no longer promises a running worker from a stale list: it says the worker is stopped
|
|
139
|
+
first if it is still running.
|
|
140
|
+
- The web's scope links (`all`, `← project`) keep the page's `?view=stage|turn`.
|
|
141
|
+
- An approval card's verdict (`Allowed (scope)` / `Denied`) reads above the command it decided, so it no longer
|
|
142
|
+
looks like part of the tool call when the card's details are expanded.
|
|
143
|
+
- Answering or dismissing a question no longer says "Session is not running" when the worker is live but failed the
|
|
144
|
+
request: the server answers 502 with the worker's detail and the card shows it. 503 stays for a session with no
|
|
145
|
+
live worker.
|
|
146
|
+
- A turn that failed to send no longer leaves its prompt waiting to be restored into the composer later; and text
|
|
147
|
+
typed while a fast-failed turn's prompt was coming back is kept, with the restored prompt going under it.
|
|
148
|
+
- A worker that dies between a turn's end and its after-turn display no longer leaves the turn's answer bubble
|
|
149
|
+
waiting: the page stops waiting when the worker goes away, or after 20 s.
|
|
150
|
+
- A first web message the page answers itself (`/stats`, `/exit` …) or that is a typo of a command (`/modle`) no
|
|
151
|
+
longer leaves an empty session behind.
|
|
152
|
+
- A question card reopened after a reload shows its result once, in the collapsed summary, not twice.
|
|
153
|
+
- After a mid-turn reload, this tab's own prompt is still recognized as its own instead of being labelled `web`.
|
|
154
|
+
- A `chi scratch` session no longer offers `send_note`, so it leaves no note behind in another session.
|
|
155
|
+
- A `chi scratch` session's tool approvals offer only "Allow once" and "for the session", and keep a session
|
|
156
|
+
approval in memory: no "in this repo" or rule approval from it stays in the approvals store.
|
|
157
|
+
- A message sent (web, `chi send`, a delegate) to a session whose worker is slow to start no longer starts a second
|
|
158
|
+
worker beside it.
|
|
159
|
+
- The note a cancelled turn leaves for the model says "the reply above ends where it was cut off", not "the
|
|
160
|
+
answer", so narration cut off before a tool call isn't taken for an answer.
|
|
161
|
+
- A session worker that wakes again shows the model the server last said it served (`/stats`, the status row,
|
|
162
|
+
the web's info bar) right away, instead of none until its first generation.
|
|
163
|
+
- A tool call still running when its turn is cancelled (or fails) is saved in the session's analytics as
|
|
164
|
+
`canceled`, so the session's tool totals (`/stats`) count it as the turn did instead of dropping it.
|
|
165
|
+
- A session's `analytics.json` `session_duration_ms` runs from the session's `started_at`, not from when its current
|
|
166
|
+
worker started.
|
|
167
|
+
- A session started with `chi --model X` no longer hands X to the commands it runs as the default model: a `chi
|
|
168
|
+
self` (or other chi) run there reports and uses the configured default, with X as this session's model. A
|
|
169
|
+
`SAMAGOTCHI_DEFAULT_MODEL` you export yourself still passes.
|
|
170
|
+
- A preloaded memory that can't be loaded is warned about once, not again each time the prompt is rebuilt (another
|
|
171
|
+
thinking level, a `/model` switch).
|
|
172
|
+
|
|
173
|
+
Update with `chi update`: source-links moves to 0.3.2 (case-insensitive link targets). Restart `chi web` afterwards; from now on it tells you when a newer chi is installed.
|
|
174
|
+
|
|
11
175
|
## [0.18.1] - 2026-10-03
|
|
12
176
|
|
|
13
177
|
### Fixed
|
|
@@ -1035,7 +1199,9 @@ and long-lived sessions.
|
|
|
1035
1199
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
1036
1200
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
1037
1201
|
|
|
1038
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
1202
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.20.0...HEAD
|
|
1203
|
+
[0.20.0]: https://github.com/dm1try/samagotchi/compare/v0.19.0...v0.20.0
|
|
1204
|
+
[0.19.0]: https://github.com/dm1try/samagotchi/compare/v0.18.1...v0.19.0
|
|
1039
1205
|
[0.18.1]: https://github.com/dm1try/samagotchi/compare/v0.18.0...v0.18.1
|
|
1040
1206
|
[0.18.0]: https://github.com/dm1try/samagotchi/compare/v0.17.0...v0.18.0
|
|
1041
1207
|
[0.17.0]: https://github.com/dm1try/samagotchi/compare/v0.16.0...v0.17.0
|
data/README.md
CHANGED
|
@@ -54,9 +54,10 @@ chi update # the gem, then the bundles and the desktop helper
|
|
|
54
54
|
stay installed: running sessions still use them), then brings the rest up to
|
|
55
55
|
the new version: the system bundle, the bundles chi ships that you installed,
|
|
56
56
|
and the macOS helper (rebuilt only when its sources changed). Memory files you
|
|
57
|
-
edited are kept, and the table says which. Running sessions
|
|
58
|
-
|
|
59
|
-
running `chi web` needs a restart
|
|
57
|
+
edited are kept, and the table says which. Running sessions keep their chi
|
|
58
|
+
until restarted (`chi sessions restart ID`, or the Restart badge on the web);
|
|
59
|
+
new and woken ones start on the new chi. A running `chi web` needs a restart,
|
|
60
|
+
and its page says so. From a checkout, `git pull` instead. See
|
|
60
61
|
[CLI: Updating](docs/cli.md#updating).
|
|
61
62
|
|
|
62
63
|
## Set up
|
data/docs/architecture.md
CHANGED
|
@@ -213,6 +213,10 @@ process that already owns the `Engine`); every worker starts it, and it exposes:
|
|
|
213
213
|
too-old reconnects, and cursors from another worker's epoch, receive a `reset` marker carrying
|
|
214
214
|
`session_state_snapshot`. `?snapshot=1` joins with a snapshot frame instead of a replay;
|
|
215
215
|
`?client_id=` names whose stream it is (`Bridge#open_streams_except`, used by `POST /exit`).
|
|
216
|
+
An attached terminal's stream (`EventStream` with `rediscover:`) looks for the session's live
|
|
217
|
+
worker whenever it drops: a new one (a restart) is followed from its snapshot, and the terminal
|
|
218
|
+
sends its requests there (`worker_changed`); it gives up after ~12 s, or at once when the session
|
|
219
|
+
was stopped.
|
|
216
220
|
- `POST /session/:id/turn` — fire-and-forget turn creation; returns `202` with an `enqueued_id`
|
|
217
221
|
(delivery is at-least-once via the worker's file-IPC input path — it never calls `run_turn`
|
|
218
222
|
across the HTTP boundary). Only the bridge's own session: another id, in the path or the body's
|
|
@@ -270,6 +274,12 @@ The metrics in `/state`, `/snapshot`, `/stats` and the SSE `snapshot`/`reset` fr
|
|
|
270
274
|
newest turn the worker finished and any it hasn't saved yet (at most 20 turns), with their tool
|
|
271
275
|
calls and the running turn's finished ones. The full history is the session's `analytics.json`,
|
|
272
276
|
which `SessionMetrics#persist` rewrites after each turn; the web server merges the two by id.
|
|
277
|
+
The totals' `tokens` block adds the cached and reasoning sums, the cost, the decode time and tokens
|
|
278
|
+
behind the average speed (`avg_decode_tps`) and the last speeds (`last_decode_tps`,
|
|
279
|
+
`last_prefill_tps`, `tps_source`: `server` or `estimate`). Each `generation_completed` event
|
|
280
|
+
carries the generation's `speed` (`{decode_tps, source}`, null without one) and those running
|
|
281
|
+
`tokens`: the Engine closes the generation in `SessionMetrics#finish_generation` before relaying
|
|
282
|
+
it, so the web's info bar updates per generation without parsing chunk payloads.
|
|
273
283
|
|
|
274
284
|
The page's frequent reads of `GET /api/sessions/:id` stay light too:
|
|
275
285
|
- `?tail=1&recent=1` (each turn's end, a cancel, an answer display): `{tail, session: {id, status,
|
|
@@ -302,7 +312,13 @@ the server, no daemon) that keeps an in-memory projection of the session list an
|
|
|
302
312
|
changes to every open tab over `GET /api/events` (SSE: a `snapshot` frame on every connect,
|
|
303
313
|
then `session` for an upsert and `session_gone` for a removal, `: ping` while idle, no replay).
|
|
304
314
|
The snapshot names chi's version: a tab served by another one (its `<body data-version>`) offers a
|
|
305
|
-
reload in a toast, since an open tab keeps its old JS across a `chi web` upgrade.
|
|
315
|
+
reload in a toast, since an open tab keeps its old JS across a `chi web` upgrade. It also names
|
|
316
|
+
`installed`, the newest chi on this machine (`InstalledVersions`: the highest `samagotchi-<v>.gemspec`
|
|
317
|
+
in RubyGems' specification dirs, or a checkout's `version.rb` on disk; looked at again on each full
|
|
318
|
+
probe, every 10 s), and a change is a `chi` frame `{version, installed}`. A newer one than the
|
|
319
|
+
server runs is said in chi web's terminal and on the page: restart chi web (its workers already
|
|
320
|
+
run the newest chi, [Sessions](sessions.md)). `GET /api/info` carries `installed` too, and the
|
|
321
|
+
feature `newest_workers`.
|
|
306
322
|
Files stay the source of truth and workers don't know the hub. Its watcher is a 1 s tick that
|
|
307
323
|
stats the sessions dir (every session writer goes tmp + rename, which bumps the dir's mtime) and
|
|
308
324
|
each `<id>/` folder (recap.json, bridge.json, the stopped and archived markers), re-parsing only the files whose mtime or size
|
|
@@ -310,7 +326,10 @@ moved through `Session.summary_from_file`. Liveness is probed, since a killed ow
|
|
|
310
326
|
file trace: the owner lock every tick for the sessions the projection believes owned, and every
|
|
311
327
|
session every 10 s, so a `kill -9` shows within a second. The summary (`Web::SessionSummary`,
|
|
312
328
|
shared with `/api/sessions` and the session view) carries `owner`, `project_root` and
|
|
313
|
-
`bridge_up` (the sidecar is there *and* the lock is held: the page attaches its stream on it)
|
|
329
|
+
`bridge_up` (the sidecar is there *and* the lock is held: the page attaches its stream on it), and
|
|
330
|
+
from that sidecar `worker_version` (the chi the worker runs) and `worker_features`
|
|
331
|
+
(`Bridge::FEATURES`, what a client may ask of it beyond the routes). A worker's Bridge snapshot
|
|
332
|
+
names its `chi_version` too.
|
|
314
333
|
`POST/DELETE /api/sessions` and `/stop` rescan the session before answering (`SessionHub#touch`).
|
|
315
334
|
`GET /api/sessions` is the hub's projection too (its sort, paging and total). `Server` always builds
|
|
316
335
|
a hub; an `App.new` without one answers both routes `503 no_hub`.
|
data/docs/cli.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
- `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
|
|
16
16
|
- `chi web --web-markdown` — opt in to sanitized Markdown rendering for completed assistant messages
|
|
17
17
|
- `chi web --web-view turn` — draw turns with the turn view (each turn as one block of steps, the running one at the bottom of the history) instead of the default stage view (the running turn pinned above the composer); `?view=stage|turn` on the page URL overrides it (see [Web views](#web-views))
|
|
18
|
-
- `chi sessions list|stop|archive|unarchive|delete|prune|clean` — 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)). A usage error (an unknown subcommand or flag, a flag missing its value, `stop` or `delete` with no ids, a bad `list --format` or `--scope`) exits 2; an unknown or refused session exits 1
|
|
18
|
+
- `chi sessions list|stop|restart|archive|unarchive|delete|prune|clean` — 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)). 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`) exits 2; an unknown or refused session exits 1
|
|
19
19
|
- `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))
|
|
20
20
|
- `chi send [-m TEXT] [--image PATH]... (ID|PREFIX)...` — send a message to sessions as if typed there: a turn starts (or a running one picks it up); 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, and `--wait` prints the answer (`--wait ID` with no message waits for the next reply without sending; `--format json` prints one JSON object instead; 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))
|
|
21
21
|
- `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`). An approval can be denied, not allowed, unless `guardrails.parent_approvals: once` (a convention, not a security boundary; see [Guardrails](guardrails.md#approvals-from-a-parent-agent))
|
|
@@ -53,7 +53,9 @@ chi bootstrap # try localhost 8080, 11434, 1234, 8000
|
|
|
53
53
|
- **The file.** With no config.yml it writes a small commented one:
|
|
54
54
|
`default.model` as `<host>:<model>` and one `hosts:` entry named `local`
|
|
55
55
|
(localhost), `lan` (an IP) or after the domain (`openrouter`); `--name`
|
|
56
|
-
sets it.
|
|
56
|
+
sets it. When that name is taken (or a model id starts with it), chi picks
|
|
57
|
+
`name-2` and says why, with `--name` to choose another. An existing file is
|
|
58
|
+
left as it is apart from the new entry, added
|
|
57
59
|
at the end of its `hosts:` block (it gets a `hosts:` block, with a
|
|
58
60
|
`default` entry for its `server:` first, when it has none), after a backup
|
|
59
61
|
to `config.yml.bak-<time>`. `default.model` is set only when the file has
|
|
@@ -104,17 +106,19 @@ known-names 0.1.0 0.1.1 updated
|
|
|
104
106
|
core 0.1.0 0.2.0 updated (+ new-bundle)
|
|
105
107
|
infra_tools 1.0.0 skipped (not from chi)
|
|
106
108
|
Chi Helper 0.2.0 up to date (launch file refreshed)
|
|
107
|
-
workers 2 live on 0.2.0: they
|
|
109
|
+
workers 2 live on 0.2.0: they keep it until restarted (chi sessions restart 2ea8c1f0 91b0d2aa); or they idle out after 30 min with nothing attached
|
|
108
110
|
Also shipped, not installed: dev (mcp, skills, source-links) (chi bundle install NAME)
|
|
109
111
|
done
|
|
110
112
|
```
|
|
111
113
|
|
|
112
114
|
- **The gem.** It asks rubygems.org for the newest samagotchi (5 s timeout)
|
|
113
115
|
and, when that's newer, runs `gem install samagotchi` with the gem command
|
|
114
|
-
of the Ruby chi runs on (the real one, not a mise/rbenv/asdf shim
|
|
116
|
+
of the Ruby chi runs on (the real one, not a mise/rbenv/asdf shim; a chi
|
|
117
|
+
installed under another Ruby is a separate install it doesn't touch). Then it
|
|
115
118
|
hands over to the new chi, which does the rest and prints the table. Old
|
|
116
|
-
versions stay installed: running workers and an old `chi web` still
|
|
117
|
-
them
|
|
119
|
+
versions stay installed: running workers and an old `chi web` still load
|
|
120
|
+
files from them, so a `gem cleanup` while they run breaks them (a
|
|
121
|
+
`LoadError`, missing web assets); restart them first. Offline, the row says
|
|
118
122
|
"couldn't check" and the rest still runs; a failed install fails the row
|
|
119
123
|
and the rest runs on the current version. Under Bundler (`bundle exec`)
|
|
120
124
|
the row says `bundle update samagotchi` instead.
|
|
@@ -137,9 +141,15 @@ done
|
|
|
137
141
|
- **The desktop helper** (macOS) is rebuilt and restarted only when its Swift
|
|
138
142
|
sources changed (or the Ruby it runs moved); otherwise only its launch file
|
|
139
143
|
is refreshed. See [Desktop helper](desktop.md).
|
|
140
|
-
- **Running processes** are reported, never stopped
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
- **Running processes** are reported, never stopped. A live worker keeps its
|
|
145
|
+
chi until it is restarted: `chi sessions restart ID` (one from before
|
|
146
|
+
restarts: `chi sessions stop ID`, and the next prompt starts it on the new
|
|
147
|
+
chi); it exits on its own only when nothing is attached (no web tab, no
|
|
148
|
+
terminal, no reminder) and `session.idle_exit_minutes` pass (never with 0).
|
|
149
|
+
A new or woken worker always starts on the newest chi installed. A `chi web`
|
|
150
|
+
on `web.port` running an older chi needs a restart (Ctrl-C, then `chi web`):
|
|
151
|
+
its page says so too. One from before workers started on the newest chi
|
|
152
|
+
also starts its new sessions on its own version until then (the row says so).
|
|
143
153
|
|
|
144
154
|
`--dry-run` shows the table with "would update" and changes nothing. It is
|
|
145
155
|
this version's view: bundles that only a newer gem ships newer show up once
|
|
@@ -251,8 +261,12 @@ and `--shared` are refused. Its first line says it is a scratch session.
|
|
|
251
261
|
answers "scratch session: nothing is saved", and `write`/`edit` into the
|
|
252
262
|
memories folder are denied (a guardrail, rule `scratch-session`). `execute`
|
|
253
263
|
can still write files anywhere, memories included.
|
|
264
|
+
- An approval offers only "Allow once" and "for the session", and a session
|
|
265
|
+
approval is kept in memory, not in the approvals store; approvals stored
|
|
266
|
+
before still apply.
|
|
254
267
|
- No child sessions: the `delegate` tools are not offered, and a plugin's
|
|
255
268
|
`ctx.sessions.fork` (btw's side session) refuses, since they would outlive it.
|
|
269
|
+
Nor is `send_note`, whose note would stay in the other session.
|
|
256
270
|
|
|
257
271
|
### Sharing a session
|
|
258
272
|
|
|
@@ -320,6 +334,20 @@ a `chi --resume ID` after it starts a fresh one. A worker still running an
|
|
|
320
334
|
older chi (from before an upgrade) takes turns but not commands; the attached
|
|
321
335
|
terminal and the Web UI say so, with that restart line.
|
|
322
336
|
|
|
337
|
+
`chi sessions restart ID...` hands each session to a new worker on the newest
|
|
338
|
+
chi installed, without stopping it: an attached terminal and the web's tabs
|
|
339
|
+
move to the new worker. It is refused, with the reason, while something would
|
|
340
|
+
be lost: a turn running or queued, a question or approval waiting, reminders,
|
|
341
|
+
a `/btw` still running, an approval relayed from a delegate, or background
|
|
342
|
+
tasks the session started. A session with no running worker needs none (its
|
|
343
|
+
next prompt starts one on the newest chi), and a worker from before restarts
|
|
344
|
+
needs `chi sessions stop ID`. The Web UI's `POST /api/sessions/:id/restart`
|
|
345
|
+
does the same (409 with `reason` and `detail` when it can't). An attached
|
|
346
|
+
terminal says at the join, in one `chi>` line, when the worker or the terminal
|
|
347
|
+
runs an older chi than the newest installed (the worker moves with `chi
|
|
348
|
+
sessions restart ID`, the terminal with `/detach` and `chi --attach ID`), and
|
|
349
|
+
`chi> the session's worker restarted on chi X` when its worker was replaced.
|
|
350
|
+
|
|
323
351
|
`chi sessions archive ID...` hides sessions from every list (the terminal's,
|
|
324
352
|
the web's, `list_sessions`) and keeps them for good: the retention sweep never
|
|
325
353
|
deletes an archived session, nor counts it. Its delegates go with it. A live
|
|
@@ -387,8 +415,17 @@ file and index line stay as they are; only this session doesn't see it.
|
|
|
387
415
|
`/help` lists the commands this session takes, the installed bundles' too, each
|
|
388
416
|
with a line on what it does. `/stats` shows the session's numbers: turns, tool
|
|
389
417
|
calls (by tool, with errors), iterations, tokens in/out summed over every
|
|
390
|
-
request
|
|
391
|
-
the
|
|
418
|
+
request (with the cached and reasoning tokens when the server reports them),
|
|
419
|
+
the decode speed, generation latency, cancellations, retries, context used
|
|
420
|
+
and window, the prompt profile and the model the server says it ran, and the
|
|
421
|
+
cost when the provider reports one (OpenRouter's `usage.cost`; no prices are
|
|
422
|
+
guessed). The speed line is the last generation's and the session's average
|
|
423
|
+
(weighted by tokens): llama.cpp reports it exactly (`87 tok/s out, 1.9k tok/s
|
|
424
|
+
prompt (last, server)`); for other servers it is estimated from the first
|
|
425
|
+
streamed chunk to the end and marked `~` (`~64 tok/s out (last, estimate)`).
|
|
426
|
+
Generations under 8 tokens or 100 ms get no speed of their own, nor does a
|
|
427
|
+
reply without server token counts or a non-streamed one. A delegated child
|
|
428
|
+
keeps its own numbers: a parent's tokens and cost leave them out. `/recap` is in
|
|
392
429
|
[Session recap](#session-recap), `/model` and `/models` in [Runtime Model
|
|
393
430
|
Switch](#runtime-model-switch-assist-mode).
|
|
394
431
|
|
data/docs/configuration.md
CHANGED
|
@@ -94,8 +94,9 @@ Behavior:
|
|
|
94
94
|
- An edit to the file needs no restart of `chi web`: a new session's worker
|
|
95
95
|
reads the file when it starts, and a running chi takes a changed value the
|
|
96
96
|
next time it reads that setting (a worker keeps `hosts:` and what it set up
|
|
97
|
-
at its start until it is stopped
|
|
98
|
-
that started it
|
|
97
|
+
at its start until it is stopped; the web's model picker lists a `hosts:`
|
|
98
|
+
edit at once). A worker gets the CLI flags of the chi that started it
|
|
99
|
+
through its environment.
|
|
99
100
|
- Workers inherit hosts via `SAMAGOTCHI_HOSTS_JSON` propagated through `SessionManager.spawn_options`.
|
|
100
101
|
|
|
101
102
|
This lets you run `chi` without repeating common defaults such as model
|
|
@@ -235,11 +236,16 @@ hosts:
|
|
|
235
236
|
**Remote or local.** chi treats a host as a remote provider by its address, not
|
|
236
237
|
by its key: an `https` url, or an `http` IP address outside the loopback,
|
|
237
238
|
private (`10.*`, `172.16–31.*`, `192.168.*`, IPv6 `fc00::/7`), link-local and
|
|
238
|
-
CGNAT/Tailscale (`100.64.0.0/10`) nets
|
|
239
|
-
|
|
239
|
+
CGNAT/Tailscale (`100.64.0.0/10`) nets, or an `http` name with a dot that
|
|
240
|
+
doesn't end in a local suffix (`gpu.example.com`). A name without a dot (`box`)
|
|
241
|
+
or ending in `localhost`, `.local`, `.lan`, `.home`, `.home.arpa`, `.internal`,
|
|
242
|
+
`.intranet`, `.localdomain`, `.private`, `.corp`, `.test`, `.box` (`fritz.box`)
|
|
243
|
+
or `.ts.net` (Tailscale) is local: chi doesn't look names up. A remote
|
|
240
244
|
host keeps its model list for 10 minutes, gets a 120-second first-token limit,
|
|
241
245
|
and isn't asked for llama.cpp's `/props` (its context window and served model
|
|
242
|
-
come from its model list and each turn).
|
|
246
|
+
come from its model list and each turn). A local `api: openai` host has no
|
|
247
|
+
`/props`, so `chi self` GETs its `/models` with the same short probe timeouts
|
|
248
|
+
and reports up/down with the ids it serves. `remote: true` or `remote: false` on a
|
|
243
249
|
host decides it instead, e.g. for a llama.cpp behind an https proxy on the LAN:
|
|
244
250
|
|
|
245
251
|
```yaml
|
|
@@ -848,6 +854,7 @@ described in their own sections.
|
|
|
848
854
|
| `image.max_bytes` | `3750000` | | See "Images". |
|
|
849
855
|
| `image.max_per_request` | `20` | | See "Images". |
|
|
850
856
|
| `guardrails.enabled` | `true` | | `false`: no rules, and hooks' asks are dropped (a deny still applies). config.yml only: a worker unsets any `SAMAGOTCHI_GUARDRAILS_*` it inherits. See [Guardrails](guardrails.md). |
|
|
857
|
+
| `guardrails.mode` | `auto` | | Which rules vote: `auto` leaves out the rules tagged `modes: [strict]` (in the guardrails bundle: `git rebase`, writes and git outside the session's repo); `strict` runs them all. An unknown value warns and is `auto`. config.yml only. See [Guardrails](guardrails.md#modes). |
|
|
851
858
|
| `guardrails.small_models` | `auto` | | Which models get the `models: small` rules: `auto` (32B or less by the size in the name, an MoE's active size), a list of globs, or `[]`. config.yml only. See [Guardrails](guardrails.md#rules-for-some-models). |
|
|
852
859
|
| `guardrails.parent_approvals` | `off` | | What `chi answer` lets a parent agent allow on an approval: `off` (deny only) or `once` ("Allow once", never a wider scope). config.yml only: no environment variable (a parent can still pick the config dir with `XDG_CONFIG_HOME`). A convention for an honest parent, not a security boundary. See [Guardrails](guardrails.md#approvals-from-a-parent-agent). |
|
|
853
860
|
| `log.file` | state dir | yes | See "Debug Log File". |
|
data/docs/guardrails.md
CHANGED
|
@@ -81,6 +81,13 @@ Allowing beyond "once" is stored in `$XDG_STATE_HOME/samagotchi/guardrails/appro
|
|
|
81
81
|
| repo | this exact call in this repo (the cwd outside a repo), any session |
|
|
82
82
|
| rule | anything this rule asks about in this repo |
|
|
83
83
|
|
|
84
|
+
"This repo" is the git repository, not the folder: an approval given in one
|
|
85
|
+
worktree holds in the main checkout and every other worktree of it (it is
|
|
86
|
+
stored with the repository's common git dir as `repo`, and the worktree as
|
|
87
|
+
`repo_root`). The ask names the repository (`Allow this call in this repo
|
|
88
|
+
(samagotchi)`). An entry stored before chi 0.20 has no `repo` and still only
|
|
89
|
+
matches its exact folder.
|
|
90
|
+
|
|
84
91
|
A stored approval only relaxes an ask; a deny rule is never approvable.
|
|
85
92
|
A file that doesn't parse is moved aside to `approvals.json.corrupt-<UTC time>`
|
|
86
93
|
with one warning, and chi starts with no stored approvals (more asks, nothing lost).
|
|
@@ -137,7 +144,7 @@ grants no permission, so a parent may answer it either way by default.
|
|
|
137
144
|
`turn.parent_continue: false` (config.yml only, like `parent_approvals`)
|
|
138
145
|
makes parents stop-only. See [chi as a sub-agent](sub-agent.md#the-step-limit).
|
|
139
146
|
|
|
140
|
-
The guardrails settings (`enabled`, `small_models`, `parent_approvals`) are
|
|
147
|
+
The guardrails settings (`enabled`, `mode`, `small_models`, `parent_approvals`) are
|
|
141
148
|
read from config.yml only: they have no environment variable, and a worker
|
|
142
149
|
chi starts unsets every `SAMAGOTCHI_GUARDRAILS_*` it would inherit. What a
|
|
143
150
|
parent's environment does choose is the config dir: `XDG_CONFIG_HOME` picks
|
|
@@ -182,6 +189,7 @@ commands that name them.
|
|
|
182
189
|
```yaml
|
|
183
190
|
guardrails:
|
|
184
191
|
enabled: true # false: no rules, and hooks' asks are dropped (a deny still applies); config.yml only
|
|
192
|
+
mode: auto # or strict: also the rules tagged modes: [strict]; config.yml only
|
|
185
193
|
rules:
|
|
186
194
|
- id: git-push
|
|
187
195
|
tool: shell # execute + task_create; or a tool name, a glob, or a list
|
|
@@ -201,7 +209,41 @@ guardrails:
|
|
|
201
209
|
scopes: [once, session, rule]
|
|
202
210
|
```
|
|
203
211
|
|
|
204
|
-
A rule gives at least one of `tool`, `command`, `path` and `
|
|
212
|
+
A rule gives at least one of `tool`, `command`, `path`, `git`, `touches` and `rm`.
|
|
213
|
+
|
|
214
|
+
`rm: outside_tmp` (shell tools) matches a command whose `rm -r -f` reaches
|
|
215
|
+
outside the tmp folders (`$TMPDIR`, `/tmp`, `/var/tmp`): every such `rm` in a
|
|
216
|
+
chain must name only paths inside one, resolved like `touches` (so
|
|
217
|
+
`/tmp/../etc` and a link from `/tmp` to `/` are outside). The tmp folder
|
|
218
|
+
itself, a glob (`/tmp/*`), a `$VAR` other than `$HOME`/`$TMPDIR`, an `rm`
|
|
219
|
+
behind `sudo`/`xargs`/`sh -c` or in `$(…)`, and the tmp folder the session's
|
|
220
|
+
repo is in count as outside.
|
|
221
|
+
|
|
222
|
+
`touches: chi_dirs` (shell tools) matches a command that names a path in chi's
|
|
223
|
+
own folders: the config folder (`config.yml`, `memories/`), the hooks folder,
|
|
224
|
+
the approval store, installed bundles (`memories/.bundles`), the session repo's
|
|
225
|
+
git hooks (`core.hooksPath` honoured) or any `.git/hooks` outside a tmp folder.
|
|
226
|
+
Each word is read as a path against the folder the command is in by then
|
|
227
|
+
(`cd`, `pushd`/`popd` and `( … )` followed), with `~`, `$HOME` and
|
|
228
|
+
`$XDG_CONFIG_HOME`/`$XDG_STATE_HOME` expanded and symlinks resolved. So
|
|
229
|
+
`/tmp/x/config/samagotchi/config.yml` and chi's own source
|
|
230
|
+
(`lib/samagotchi/hooks/…`) don't match. A word it can't resolve (another
|
|
231
|
+
`$VAR`, `$(…)`, a glob, a relative path after `cd $X`) or one that reads as a
|
|
232
|
+
script (`sh -c '…'`, `ruby -e '…'`) is matched as text instead (`.config/samagotchi`,
|
|
233
|
+
`samagotchi/config.yml`, `samagotchi/hooks`, `samagotchi/guardrails`,
|
|
234
|
+
`memories/.bundles`, `.git/hooks`).
|
|
235
|
+
|
|
236
|
+
`skip_read_only: true` lets a shell command through when it only reads:
|
|
237
|
+
every command in it (split at `;`, `&&`, `||`, `|`) is `ls`, `cat`, `head`,
|
|
238
|
+
`tail`, `wc`, `stat`, `du`, `grep`, `rg`, `find`, `tree`, `file`, `sort`,
|
|
239
|
+
`uniq`, `cut`, `diff`, `echo`, `cd`, `sed`, `awk` or a reading `git`
|
|
240
|
+
(`log`, `show`, `diff`, `status`, `branch` listing, …), with no option that
|
|
241
|
+
writes or runs something (`sed -i`, `sed 's/a/b/w f'`, `find -delete`/`-exec`,
|
|
242
|
+
`rg --pre`, `sort -o`, `awk` with `>`/`|`/`system(`, `git -c`, `git diff
|
|
243
|
+
--ext-diff`, …) and no redirection other than to `/dev/null` or another fd.
|
|
244
|
+
`$(…)`, backticks, `$VAR` (other than `$HOME`, `$XDG_*`, `$TMPDIR` and `$PWD`
|
|
245
|
+
at a word's start), an env prefix, `sh -c`, `xargs`, `eval`, `sudo` and the
|
|
246
|
+
like make a command not read-only. It errs towards asking.
|
|
205
247
|
|
|
206
248
|
A tool name may be a glob, so one rule covers a plugin's tools (an MCP server's,
|
|
207
249
|
say): `tool: "mcp_*"` or `tool: ["mcp_{git,gh}_*", web_fetch]` (`*`, `?`, `[…]` and
|
|
@@ -303,6 +345,38 @@ once per bundle version to restart the session (`chi sessions stop ID`, then
|
|
|
303
345
|
older than the bundle) denies every tool call, as for a rule that doesn't
|
|
304
346
|
parse, until chi is updated or the bundle uninstalled.
|
|
305
347
|
|
|
348
|
+
### Modes
|
|
349
|
+
|
|
350
|
+
`guardrails.mode` (config.yml only) picks how much is asked:
|
|
351
|
+
|
|
352
|
+
- `auto`, the default: the rules tagged `modes: [strict]` don't vote. Asks
|
|
353
|
+
are kept for what is hard to undo or reaches chi itself.
|
|
354
|
+
- `strict`: every rule votes.
|
|
355
|
+
|
|
356
|
+
```yaml
|
|
357
|
+
guardrails:
|
|
358
|
+
mode: strict
|
|
359
|
+
rules:
|
|
360
|
+
- id: no-docker
|
|
361
|
+
tool: shell
|
|
362
|
+
command: '\bdocker\b'
|
|
363
|
+
modes: [strict] # or auto, or [auto, strict] (the same as leaving it out)
|
|
364
|
+
verdict: ask
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
A rule without `modes:` votes in every mode, so a rule you add to config.yml
|
|
368
|
+
always applies unless you tag it. The core checks (protected paths, hooks)
|
|
369
|
+
vote in both modes. In the guardrails bundle, `git-rebase`,
|
|
370
|
+
`write-outside-repo` and `git-outside-repo` are strict only; its small-model
|
|
371
|
+
rules (`models: small`) are untagged, so they ask a small model in both modes.
|
|
372
|
+
`/guardrails` shows the mode on its first lines and marks the rules this mode
|
|
373
|
+
leaves out `(strict only)`.
|
|
374
|
+
|
|
375
|
+
A rule in config.yml that uses a key this chi doesn't know yet (`modes:`,
|
|
376
|
+
`touches:`, `rm:`, `skip_read_only:` before 0.20) doesn't parse, and a rule
|
|
377
|
+
that doesn't parse denies every tool call (see Failing closed). Bundles say
|
|
378
|
+
which chi they need (`requires_chi`), so their rules don't hit this.
|
|
379
|
+
|
|
306
380
|
## The guardrails bundle
|
|
307
381
|
|
|
308
382
|
```sh
|
|
@@ -310,18 +384,22 @@ chi bundle install guardrails # chi bootstrap installs it, with the core prof
|
|
|
310
384
|
```
|
|
311
385
|
|
|
312
386
|
installs a default rule set plus a short memory telling the model not to
|
|
313
|
-
route around a deny.
|
|
314
|
-
`
|
|
315
|
-
`$HOME` or `..` paths
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
387
|
+
route around a deny. In both modes it asks before `git push`, `reset --hard`,
|
|
388
|
+
`clean -f`, `branch -D`, `filter-branch`/`filter-repo`; `rm -rf` on `/`, `~`,
|
|
389
|
+
`$HOME` or `..` paths, unless every target is inside a tmp folder; `curl … |
|
|
390
|
+
sh` and `base64 -d … | sh`; shell commands that name a path in chi's config,
|
|
391
|
+
hooks, approvals or bundles or a `.git/hooks` (`shell-touches-chi`, `touches:
|
|
392
|
+
chi_dirs`), unless they only read (`skip_read_only`); and answering chi's
|
|
393
|
+
questions around `chi answer`: `chi --attach` or `chi -p` with stdin from a
|
|
394
|
+
pipe, a here-string or a file (`chi-answer-piped`), and `curl`/`wget` to a
|
|
395
|
+
session's `/answer` route (`chi-answer-http`), both once or for the session.
|
|
396
|
+
`chi answer` itself isn't asked about. It denies writes into `.git/hooks`.
|
|
397
|
+
|
|
398
|
+
In strict mode (`guardrails: { mode: strict }`) it also asks before `git
|
|
399
|
+
rebase`, writes outside the session's repo (`write-outside-repo`) and git that
|
|
400
|
+
changes another checkout (`git-outside-repo`: `cd ../main && git commit`, `git
|
|
401
|
+
-C ../main add .`; it offers once, this session and "rule in this repo", the
|
|
402
|
+
last stored for later sessions in that repo). The rules are in
|
|
325
403
|
`lib/samagotchi/bundles/guardrails/guardrails/rules.yml`.
|
|
326
404
|
|
|
327
405
|
Small models (`models: small`, see above) get two more asks, in
|
data/docs/memory.md
CHANGED
|
@@ -27,6 +27,10 @@ Each memory entry may have a companion file named `<name>.<model-key>.md` in the
|
|
|
27
27
|
- **In the system prompt**: the identity memory and the preloaded memories (`--memory`, config `memories:`) get their overlays too, as `memory_read` gives them; after `/model` the rebuilt prompt carries the new model's.
|
|
28
28
|
- **Dormancy**: Overlays are only active under the matching model key; other models see the base entry only.
|
|
29
29
|
- **Invariant**: The base entry is the contract. Overlays only add model-specific guidance and never contradict the base protocol.
|
|
30
|
+
- **In a bundle**: ship `<name>.<key>.md` next to `<name>.md` (ship the base too; an overlay with no base anywhere installs with a warning and loads only once the base exists; one whose base is only among your installed memories is taken as an overlay of it, with a warning naming it). The overlay gets no `index.md` line, so other models don't see it, and `chi bundle status` reads it `ok (model overlay)`; `chi bundle build FILES...` brings a named memory's overlays along.
|
|
31
|
+
- The key is the `model key` row of `chi self` under that model. It follows the provider's model id: OpenRouter's `deepseek/deepseek-v4.1-flash` keys as `deepseek-deepseek-v4-1-flash`, while a local server names the same model differently, so one model may need one overlay per provider.
|
|
32
|
+
- Key an alias by its **target**, not the alias: the alias's own key is read only as a fallback, when the alias was typed and the target has no overlay.
|
|
33
|
+
- The overlay is read in the scope its base is found in: a project memory with the same name shadows a system-scope bundle's base and overlay.
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
At startup, the agent reads both scope indexes with blank-name memory reads
|
data/docs/plugins.md
CHANGED
|
@@ -524,6 +524,11 @@ ctx.card(id: id, title: "Build finished", body: "no warnings left") # replaces
|
|
|
524
524
|
its line; the web shows a bubble only when the command answers with
|
|
525
525
|
text or fails.
|
|
526
526
|
- `level:` is `:info` or `:warn` (the warning colour).
|
|
527
|
+
- An `:info` card with no actions and a body of one short line (up to 160
|
|
528
|
+
characters) is a notice: the web shows it as a one-line row,
|
|
529
|
+
`▸ check-in: Nudged the model at 105 tool calls.`, that opens on a click,
|
|
530
|
+
like a resolved question. A warn card, one with actions and one with more
|
|
531
|
+
to read stay framed cards.
|
|
527
532
|
- `id:` names an earlier card to replace. Without one a new id is made. The
|
|
528
533
|
web updates the card in place; the terminal prints it again, marked
|
|
529
534
|
`(updated)`. A card that waits for something (a model's answer) shows
|