samagotchi 0.134.0 → 0.136.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 +78 -1
- data/bin/chi +2 -3
- data/docs/architecture.md +6 -3
- data/docs/cli.md +43 -38
- data/docs/configuration.md +11 -9
- data/docs/guardrails.md +53 -9
- data/docs/internals/engine.md +6 -3
- data/docs/internals/participants.md +1 -1
- data/docs/internals/prompt-caching.md +1 -1
- data/docs/internals/web-frontend.md +263 -0
- data/docs/internals/working-set.md +2 -2
- data/docs/sessions.md +5 -3
- data/docs/testing.md +36 -6
- data/lib/samagotchi/bridge.rb +11 -6
- data/lib/samagotchi/bridge_client.rb +8 -5
- data/lib/samagotchi/bundles/system/manifest.yml +1 -1
- data/lib/samagotchi/config.rb +0 -2
- data/lib/samagotchi/engine.rb +69 -12
- data/lib/samagotchi/guardrail_wiring.rb +8 -6
- data/lib/samagotchi/guardrails/approval.rb +41 -5
- data/lib/samagotchi/guardrails/implicit_writers.rb +19 -4
- data/lib/samagotchi/guardrails/pair_boundary.rb +5 -1
- data/lib/samagotchi/guardrails/pair_command.rb +387 -78
- data/lib/samagotchi/guardrails/parent_approvals.rb +12 -15
- data/lib/samagotchi/guardrails/read_only_shell.rb +24 -2
- data/lib/samagotchi/guardrails/shared_git.rb +1 -1
- data/lib/samagotchi/guardrails/shell_git_dirs.rb +1 -1
- data/lib/samagotchi/guardrails/shell_lex.rb +22 -0
- data/lib/samagotchi/guardrails_command.rb +13 -10
- data/lib/samagotchi/llm/chat_loop.rb +4 -3
- data/lib/samagotchi/message_parts.rb +1 -1
- data/lib/samagotchi/revise_anchor.rb +33 -0
- data/lib/samagotchi/session_inbox.rb +20 -12
- data/lib/samagotchi/session_manager.rb +13 -11
- data/lib/samagotchi/system_one/approval_question.rb +21 -16
- data/lib/samagotchi/system_one/self_protect.rb +13 -15
- data/lib/samagotchi/tools/delegate_relay.rb +6 -5
- data/lib/samagotchi/tools/delegate_wait.rb +5 -5
- data/lib/samagotchi/tools/execute.rb +6 -6
- data/lib/samagotchi/tools/output_guardrails.rb +9 -2
- data/lib/samagotchi/tools/read.rb +5 -5
- data/lib/samagotchi/turn_anchors.rb +49 -0
- data/lib/samagotchi/verify_anchor.rb +5 -5
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +6 -18
- data/lib/samagotchi/web/message_display.rb +33 -1
- data/lib/samagotchi/web/participant_access.rb +2 -2
- data/lib/samagotchi/web/participant_view.rb +8 -0
- data/lib/samagotchi/web/public/activity.js +1 -1
- data/lib/samagotchi/web/public/annotations.js +1 -1
- data/lib/samagotchi/web/public/answer_fold.js +100 -31
- data/lib/samagotchi/web/public/app.js +451 -367
- data/lib/samagotchi/web/public/bubbles.js +30 -10
- data/lib/samagotchi/web/public/cards_place.js +4 -2
- data/lib/samagotchi/web/public/chip_popover.js +2 -2
- data/lib/samagotchi/web/public/composer.css +8 -0
- data/lib/samagotchi/web/public/context_chips.js +9 -6
- data/lib/samagotchi/web/public/data.js +4 -2
- data/lib/samagotchi/web/public/dock_reserve.js +13 -15
- data/lib/samagotchi/web/public/feature_gates.js +33 -0
- data/lib/samagotchi/web/public/history_reveal.js +10 -6
- data/lib/samagotchi/web/public/index.html +105 -53
- data/lib/samagotchi/web/public/info_bar.js +11 -12
- data/lib/samagotchi/web/public/info_bar_model.js +8 -10
- data/lib/samagotchi/web/public/latest.js +46 -0
- data/lib/samagotchi/web/public/level_chip.js +33 -95
- data/lib/samagotchi/web/public/lists_view.js +15 -13
- data/lib/samagotchi/web/public/live_timing.js +2 -0
- data/lib/samagotchi/web/public/llm_context_chip.js +13 -144
- data/lib/samagotchi/web/public/markdown_place.js +1 -1
- data/lib/samagotchi/web/public/method_api.js +14 -0
- data/lib/samagotchi/web/public/notifications.js +4 -11
- data/lib/samagotchi/web/public/participant.js +11 -6
- data/lib/samagotchi/web/public/participant_names.js +1 -1
- data/lib/samagotchi/web/public/participants_panel.js +4 -2
- data/lib/samagotchi/web/public/project_picker.js +18 -22
- data/lib/samagotchi/web/public/question_cards.js +2 -2
- data/lib/samagotchi/web/public/reasoning_history_chip.js +8 -34
- data/lib/samagotchi/web/public/restore.js +2 -0
- data/lib/samagotchi/web/public/revise_stack.js +378 -0
- data/lib/samagotchi/web/public/scope.js +12 -20
- data/lib/samagotchi/web/public/send_turn.js +29 -16
- data/lib/samagotchi/web/public/session_actions.js +15 -14
- data/lib/samagotchi/web/public/session_fields.js +152 -0
- data/lib/samagotchi/web/public/session_payload.js +35 -0
- data/lib/samagotchi/web/public/session_state.js +9 -5
- data/lib/samagotchi/web/public/session_store.js +191 -0
- data/lib/samagotchi/web/public/settings_chip.js +212 -0
- data/lib/samagotchi/web/public/settings_panel.js +121 -0
- data/lib/samagotchi/web/public/shell_command.js +26 -0
- data/lib/samagotchi/web/public/stage_model.js +4 -4
- data/lib/samagotchi/web/public/stage_view.js +11 -16
- data/lib/samagotchi/web/public/start_settings.js +25 -88
- data/lib/samagotchi/web/public/stream_handlers.js +88 -90
- data/lib/samagotchi/web/public/task_stop.js +1 -1
- data/lib/samagotchi/web/public/thinking_chip.js +7 -45
- data/lib/samagotchi/web/public/time_gaps.js +5 -2
- data/lib/samagotchi/web/public/timing.js +15 -5
- data/lib/samagotchi/web/public/toolkit_chip.js +37 -21
- data/lib/samagotchi/web/public/{turn_view.js → turn_block.js} +33 -93
- data/lib/samagotchi/web/public/turn_events.js +3 -3
- data/lib/samagotchi/web/public/turn_html.js +20 -16
- data/lib/samagotchi/web/public/turn_model.js +6 -6
- data/lib/samagotchi/web/public/verdict_fresh.js +2 -0
- data/lib/samagotchi/web/public/working_set_view.js +3 -1
- data/lib/samagotchi/web/server.rb +4 -4
- data/lib/samagotchi/web/session_control.rb +2 -2
- data/lib/samagotchi/web/session_create.rb +1 -1
- data/lib/samagotchi/web/session_show.rb +6 -3
- data/lib/samagotchi/worker.rb +9 -9
- data/lib/samagotchi/worker_inbound.rb +6 -5
- metadata +15 -3
- data/lib/samagotchi/web/public/hold.js +0 -78
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 12638807efa522a91eb43ef7934f29aa0a4473d48da39897d6244b755eafdfdc
|
|
4
|
+
data.tar.gz: e4dbe2698ef9517d9ccbacbd6e216720d8f0ce8e75bef8974f05951b7e1d2bfd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 605c9b52f0d2b949e2f875ef939ba01401def71fb879ef78affe5e97b9f04ba2c761e48e17c801525617a87cfb4f7bed2d5b64045080f6408974e97a7e8f3f07
|
|
7
|
+
data.tar.gz: c8d922fa4080f5b098ad953859506cfded71dc2be9038f836e88f53c288abca31265df0acdda01d3b945e43107d5c41b6ab9d5e2c3fa9196d4be284654e9d8e9
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,81 @@ and commands may change between minor versions. How releases are made:
|
|
|
7
7
|
[docs/releasing.md](docs/releasing.md).
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.136.0] - 2026-10-30
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Web: an unfolded long answer's fold row is the answer's header: it keeps the first line and size, and its bar runs
|
|
15
|
+
on into the answer's. The recap's ▸/▾ matches the steps' and thinking's in place of the browser's triangle.
|
|
16
|
+
- Web: a long delegate report folds to one row, "delegate report · its first heading · N lines", where the report
|
|
17
|
+
sits; a click opens it and this browser remembers that. A report merged into a running turn gets its row on the
|
|
18
|
+
next reload.
|
|
19
|
+
- Web: a delegate report in a reloaded history renders as markdown (headings, lists, code), as answers do; Copy
|
|
20
|
+
still copies its text. A report that arrives live shows as plain text until the next reload.
|
|
21
|
+
- Web: the session bar's id copies itself on click; the copy chi --attach button is gone.
|
|
22
|
+
- Web: the session bar's think, reasoning and llm ctx chips are one ⚙ chip whose panel is the start page's:
|
|
23
|
+
segments, a pick applies at once; the chip names only what the session set.
|
|
24
|
+
- Web: the session bar's tools chip is a 🧰 chip after ⚙: 🧰 alone while the session is on the configured default
|
|
25
|
+
kit (its tooltip names it), "🧰 lean" on another.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Web: a `!cmd`'s output in a reloaded history is its command bubble alone: it no longer opens a turn that showed
|
|
30
|
+
the next turn's steps and "turn N" timing a second time.
|
|
31
|
+
- Web: on a phone, a labelled line in the history (a delegate report, a tui line, a participant's) puts its label
|
|
32
|
+
above the text instead of squeezing the text into a narrow column beside it.
|
|
33
|
+
- Web: a session's recap is the page's last line again: the last turn's check-in notice no longer lands under it.
|
|
34
|
+
|
|
35
|
+
Update with `chi update`, then restart `chi web` and the session workers (`chi sessions restart`). `chi home doctor`
|
|
36
|
+
says what else to do.
|
|
37
|
+
|
|
38
|
+
## [0.135.0] - 2026-10-30
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Web: Revise on a finished answer: your next message rewrites it, and once that turn completes the earlier version
|
|
43
|
+
folds in place to one stub row ("v1 · its first line · N lines — superseded by v2", a click unfolds it); the newest
|
|
44
|
+
answer's "v2 · 1 earlier ▾" chip lists the versions by their prompts. Stacks show on every owner's page, live and
|
|
45
|
+
after a reload.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- Guardrails: a file or string check (`test -f x`, `[ -d dir ]`, `[ "$a" = b ]`) counts as read-only, so
|
|
50
|
+
`test -f x && cat x` no longer asks where `cat x` alone wouldn't.
|
|
51
|
+
|
|
52
|
+
### Removed
|
|
53
|
+
|
|
54
|
+
- Web: the turn view (`web.view: turn`, `chi web --web-view`, `SAMAGOTCHI_WEB_VIEW`, `?view=`): the stage is the only
|
|
55
|
+
view; finished turns still show as blocks of steps in the history. A config.yml that still sets `web.view` warns
|
|
56
|
+
about an unknown key; a chi web started with `--web-view` doesn't come back from an Update restart (start it again
|
|
57
|
+
without the flag).
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- Web: opening another session clears the previous one's init row, markdown tip and card actions at once; they no
|
|
62
|
+
longer stayed when the open failed.
|
|
63
|
+
- Web: a canceled turn's timing shows in the info bar right away, not at the next unrelated redraw.
|
|
64
|
+
- Web: the info bar follows a terminal taking the open session (its Continue and Stop, the title's ✎) at once, not at
|
|
65
|
+
the hub's next event.
|
|
66
|
+
- Web: Verify fresh on a verdict's card says it's unavailable as soon as the open session's worker goes, not at the
|
|
67
|
+
hub's next event.
|
|
68
|
+
- Web: a turn's end no longer shows the session idle while the next queued turn already runs (its late re-read wrote
|
|
69
|
+
the stored "idle" over "running").
|
|
70
|
+
- Web: a sign-in that lapsed behind an auth proxy is reported (the sign-in prompt) by the notification bell and the
|
|
71
|
+
push devices list too.
|
|
72
|
+
- Pair turns: a program is judged by its name in any case, as macOS's disk runs it: `GIT config …`, `CHI share`,
|
|
73
|
+
`NOHUP`, `PRINTENV` or `Bash -c` are refused like their lower-case names (System 1's memories exemption reads
|
|
74
|
+
`MAKE` or `RUBY x.rb` the same way). More spellings that hid a command are caught: fish's `--command S` and
|
|
75
|
+
`-C`/`--init-command S`, `PROMPT_COMMAND` and a `$(…)` kept in a value bash expands later (`PS4='$(…)' bash -x`),
|
|
76
|
+
the program behind `xcrun`, `arch`, `script`, `builtin`, `uv run`, `pnpm exec`, `bunx` and a wrapper's value option
|
|
77
|
+
(`env -u X`, `sudo -u root`), the command lines `env -S`, `ssh -o ProxyCommand=`, `hyperfine` and `parallel` run,
|
|
78
|
+
`php -B/-R/-E`, `perl -de`, `jruby`/`raku`/`julia -e`. git or chi behind a program chi doesn't know
|
|
79
|
+
(`some-runner git config …`, `chronic chi share x`) and a `$(…)` kept in a value now ask you (refused when what it
|
|
80
|
+
runs reads as git config or chi). `git add maintenance start` no longer asks you; `git lfs update` does.
|
|
81
|
+
|
|
82
|
+
Update with `chi update`, then restart `chi web` (without `--web-view`) and the session workers (`chi sessions
|
|
83
|
+
restart`). `chi home doctor` says what else to do.
|
|
84
|
+
|
|
10
85
|
## [0.134.0] - 2026-10-30
|
|
11
86
|
|
|
12
87
|
### Added
|
|
@@ -5143,7 +5218,9 @@ and long-lived sessions.
|
|
|
5143
5218
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
5144
5219
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
5145
5220
|
|
|
5146
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
5221
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.136.0...HEAD
|
|
5222
|
+
[0.136.0]: https://github.com/dm1try/samagotchi/compare/v0.135.0...v0.136.0
|
|
5223
|
+
[0.135.0]: https://github.com/dm1try/samagotchi/compare/v0.134.0...v0.135.0
|
|
5147
5224
|
[0.134.0]: https://github.com/dm1try/samagotchi/compare/v0.133.0...v0.134.0
|
|
5148
5225
|
[0.133.0]: https://github.com/dm1try/samagotchi/compare/v0.132.0...v0.133.0
|
|
5149
5226
|
[0.132.0]: https://github.com/dm1try/samagotchi/compare/v0.131.0...v0.132.0
|
data/bin/chi
CHANGED
|
@@ -234,7 +234,7 @@ if options[:dir]
|
|
|
234
234
|
exit 2
|
|
235
235
|
end
|
|
236
236
|
|
|
237
|
-
# `chi web`: its flags (--port, --open
|
|
237
|
+
# `chi web`: its flags (--port, --open…) went through the parser above.
|
|
238
238
|
options[:web] = true if web
|
|
239
239
|
|
|
240
240
|
# The first interactive start of a new installed chi says what `chi update` would update.
|
|
@@ -253,9 +253,8 @@ if options[:web]
|
|
|
253
253
|
port = options[:web_port] || Samagotchi::Config.get("web.port")
|
|
254
254
|
markdown = options[:web_markdown]
|
|
255
255
|
markdown = Samagotchi::Config.get("web.markdown") if markdown.nil?
|
|
256
|
-
view = Samagotchi::Config.get("web.view")
|
|
257
256
|
exit Samagotchi::Web::Server.launch(port: port, scope: options[:scope] || "project", open_browser: options[:web_open],
|
|
258
|
-
markdown: markdown,
|
|
257
|
+
markdown: markdown, new_token: options[:new_token], tunnel: options[:tunnel],
|
|
259
258
|
working_set: Samagotchi::Config.get("web.working_set"),
|
|
260
259
|
annotate_presets: Samagotchi::Config.get("web.annotate_presets"),
|
|
261
260
|
editor: Samagotchi::Config.get("web.editor"),
|
data/docs/architecture.md
CHANGED
|
@@ -236,6 +236,9 @@ agent logic and can be used without any terminal rendering; the UI is a thin lay
|
|
|
236
236
|
run's own prompts until their turns end; `#run` distinguishes an empty answer from a
|
|
237
237
|
prompt this terminal removed before it ran (both exit 1), as well as chi's other outcomes.
|
|
238
238
|
Without a capable terminal it falls back to `PlainSurface` (append-only).
|
|
239
|
+
- The browser's page (`lib/samagotchi/web/public/`: `app.js` for the owner, `participant.js` for a participant) is a
|
|
240
|
+
client of chi web: where its state lives, which redraw follows which write, its render idioms, stale-answer guards,
|
|
241
|
+
storage keys and streams are in [internals/web-frontend.md](internals/web-frontend.md).
|
|
239
242
|
|
|
240
243
|
#### Using the core
|
|
241
244
|
|
|
@@ -532,16 +535,16 @@ The page's frequent reads of `GET /api/sessions/:id` stay light too:
|
|
|
532
535
|
(`turn_model.js` `questionRefs`) before the card draws, so the stage's asking slot (`stage_slots.js`
|
|
533
536
|
`drawAsking(text, refs)`) pairs them on its raw draw and again after its markdown swap; the card pairs its
|
|
534
537
|
question text and its kept reply (`question_cards.js`); the step's closed `.gen-text` takes them
|
|
535
|
-
(`
|
|
538
|
+
(`turn_block.js`; on a reload its `data-answer-at`, the message's `display_refs`) and `linkTextRefs` pairs it at
|
|
536
539
|
the turn's end and after a reload. A closed step's text is markdown too with `web.markdown` on: a reload's
|
|
537
|
-
from its message's `html` (`
|
|
540
|
+
from its message's `html` (`turn_block.js` `textTemplate`), a live turn's from `POST /api/render` on its step's
|
|
538
541
|
first open after the turn's end (`markdown_place.js` `renderStepTexts`, which pairs its refs again after the
|
|
539
542
|
swap); the text as written stays on it as `data-copy-source` (`stepText`, a reloaded card's kept reply). A file ref outside the
|
|
540
543
|
session's folder is dropped, as a reload drops it: the folder `/tail` names, else (an older worker) the hub's
|
|
541
544
|
session list entry's, else (refs to check, no hub entry) the session file's; with no folder known at all, every
|
|
542
545
|
file ref is dropped rather than shown unchecked.
|
|
543
546
|
A plugin tool's row refs (`refs`, `RowRefs`) ride its tool events and, on a reload, its part (saved as
|
|
544
|
-
`tool_refs`); `
|
|
547
|
+
`tool_refs`); `turn_block.js` binds them to the row's title (`refs.js bindRowRefs`: the first on the title,
|
|
545
548
|
the others in its menu).
|
|
546
549
|
- `?timing=1`: the whole timing (`analytics.json` merged with the worker's `/state`) and
|
|
547
550
|
`turn_count`, when the page's merge came up short.
|
data/docs/cli.md
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
- `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
|
|
18
18
|
- `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
|
|
19
19
|
- `chi web --web-markdown` — opt in to sanitized Markdown rendering for completed assistant messages, the stage's asking text and a resolved question card's reply
|
|
20
|
-
- `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))
|
|
21
20
|
- `chi web --no-web-working-set` — turns the stage view's working set off (on by default; `--web-working-set` turns a config's `web.working_set: false` back on): what each turn brought into the model's context, in the stage and under each finished turn; `?working_set=1|0` on the page URL overrides it (see [The working set](#the-working-set))
|
|
22
21
|
- `chi sessions list|stop|restart|archive|unarchive|delete|prune|clean|stats` — manage persisted sessions; `list` shows this git project's, `list --scope=all` every one, a delegated session with `↳ <parent>`, `list --archived` the archived ones too (see [Sessions](sessions.md)). `stats ID` prints a session's cost, tokens and progress, and its own settings (`--set`; a `settings:` line), from a live worker's `GET stats`, else its saved `analytics.json` (`--format json` one object, with `settings`), without running a model turn. A usage error (an unknown subcommand or flag, a flag missing its value, `stop`, `restart` or `delete` with no ids, a bad `list --format` or `--scope`, a `--days`, `--keep` or `--limit` that isn't a whole number) exits 2; an unknown or refused session exits 1
|
|
23
22
|
- `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))
|
|
@@ -708,9 +707,9 @@ back). Once the session has a model reply, the two that break the cache now
|
|
|
708
707
|
the `--yes` line that applies them; `/llm-context reset --yes` works too.
|
|
709
708
|
`/llm-context` alone answers mid-turn too; a change sent while a turn runs
|
|
710
709
|
waits for the turn's end (see *Typing during a turn*). `/stats` shows
|
|
711
|
-
the same values on its `llm context:` line. The web's
|
|
712
|
-
|
|
713
|
-
through `/llm-context … --yes
|
|
710
|
+
the same values on its `llm context:` line. The web's session bar names the
|
|
711
|
+
session's own in its ⚙ chip (`⚙ ctx stale,forget`), whose panel sets them
|
|
712
|
+
through `/llm-context … --yes`, one field a tap (its note says what a change costs). See "LLM context: a session's own strategy" in
|
|
714
713
|
[configuration.md](configuration.md).
|
|
715
714
|
|
|
716
715
|
`/working-set` lists the session's working set as the model has it (see [The
|
|
@@ -778,7 +777,7 @@ comes first; `/reasoning-history default` unsets it. It is saved and carried as
|
|
|
778
777
|
or from `all` once an earlier reply has thinking rewrites the earlier replies;
|
|
779
778
|
`drop` ↔ `turn` costs nothing. Under `turn` a step-limit Continue keeps the
|
|
780
779
|
reasoning of the turn it continues. `/stats` shows it on its `reasoning history:`
|
|
781
|
-
line, the web
|
|
780
|
+
line, the web in the session bar's ⚙ panel (`⚙ reasoning all` once the session set its own). See "Reasoning history" in
|
|
782
781
|
[configuration.md](configuration.md).
|
|
783
782
|
|
|
784
783
|
`/toolkit` lists the tools the next turn declares (each with its estimated
|
|
@@ -1037,29 +1036,31 @@ the keys of sessions gone from the list are dropped when the list loads);
|
|
|
1037
1036
|
other viewers and the participant page are not affected. A jump into a
|
|
1038
1037
|
folded answer (a claim link, say) unfolds it for that page load.
|
|
1039
1038
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1039
|
+
**Revise** rewrites an answer and stacks the versions. A finished turn's
|
|
1040
|
+
final answer has a Revise button on its bottom edge (on hover; always shown
|
|
1041
|
+
on a touch screen), unless it's a Verify turn's answer, a canceled or failed
|
|
1042
|
+
turn's partial answer, or an earlier version in a stack. Revise arms the
|
|
1043
|
+
composer with a chip, "Revising: ‹its first line› ✕"; your next message (say
|
|
1044
|
+
"cut it shorter") is sent as a Revise of that answer. ✕, emptying the box or
|
|
1045
|
+
opening another session lets go of it. When the Revise turn completes with an
|
|
1046
|
+
answer, the earlier version folds where it was into one stub row,
|
|
1047
|
+
"▸ v1 · “its first line” · 84 lines — superseded by v2": its prompt, its
|
|
1048
|
+
steps and its answer, all behind it (a warn card, a verdict card and the
|
|
1049
|
+
recap stay on view). Click the stub to unfold that version in place (kept per
|
|
1050
|
+
browser, with the folded answers); a time divider between two folded stubs
|
|
1051
|
+
moves into the later stub. The newest version has a chip, "v3 · 2 earlier ▾",
|
|
1052
|
+
listing every version by its prompt; pick one to jump to its stub. Revise
|
|
1053
|
+
again on the newest version adds to the stack. Stacks are session data (the
|
|
1054
|
+
stamp is on the Revise prompt, see [sessions.md](sessions.md), Revise
|
|
1055
|
+
stacks): every owner's page shows them, live and after a reload; the
|
|
1056
|
+
participant page doesn't draw them yet. A session whose worker predates
|
|
1057
|
+
Revise (started by an older chi) disables the button and shows the chip as
|
|
1058
|
+
"Revise: restart this session to use Revise"; a message sent then is a plain
|
|
1059
|
+
one. A Revise turn that fails comes back into the composer with its chip.
|
|
1060
|
+
|
|
1061
|
+
### How the page draws a turn
|
|
1062
|
+
|
|
1063
|
+
**The stage** pins the running turn above the composer, in its own
|
|
1063
1064
|
card, so it stays on screen without scrolling: a status row (what it is
|
|
1064
1065
|
doing, the step, the elapsed time), your prompt on one line, the newest
|
|
1065
1066
|
narration sentence (else the newest thinking one, in italics; click it for
|
|
@@ -1078,8 +1079,8 @@ stage's bottom edge takes you to it. Once answered, the model's
|
|
|
1078
1079
|
question or its own approval keeps that reply (a delegate's relayed
|
|
1079
1080
|
approval, a hook's question and the step limit don't): two muted lines
|
|
1080
1081
|
under its `question → answer` line, the whole text when you open the card,
|
|
1081
|
-
|
|
1082
|
-
calls` with one tick per call, opens the turn
|
|
1082
|
+
live and after a reload. The chip at the stage's bottom edge, `N steps · M tool
|
|
1083
|
+
calls` with one tick per call, opens the turn block right above it (newest step first
|
|
1083
1084
|
while it runs; a tick opens its step). Below the chip, past a dashed rule, wait the
|
|
1084
1085
|
messages queued for after the turn and the commands queued for its end; they go into
|
|
1085
1086
|
the history after the turn's answer. `▾` folds the stage to its status
|
|
@@ -1094,10 +1095,11 @@ message moves it at once. The history is never scrolled while a turn runs, and o
|
|
|
1094
1095
|
follows the hand-off if you were at its end. The `/` command list opens
|
|
1095
1096
|
over the stage's lower edge.
|
|
1096
1097
|
|
|
1097
|
-
**The turn
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1098
|
+
**The turn block** shows a turn's work as *one block*: in the stage's cloud
|
|
1099
|
+
while the turn runs (newest step first), in the history after the hand-off
|
|
1100
|
+
and on a reload. The running
|
|
1101
|
+
generation is the live part on top (its thinking, its narration, its
|
|
1102
|
+
tool rows), the earlier ones below it collapsed to one line each
|
|
1101
1103
|
(their narration's first line, else their first call's title such as
|
|
1102
1104
|
`edit lib/a.rb`, and a call count), expandable for inspection. A tool row
|
|
1103
1105
|
says what the call did: a file's path relative to the session's folder, a
|
|
@@ -1116,8 +1118,8 @@ first line, so a mid-turn note reads without a click), and each run of steps
|
|
|
1116
1118
|
that only called tools or thought sits behind one `· N steps` line that
|
|
1117
1119
|
shows them; old turns open the same way after a reload. A turn whose steps
|
|
1118
1120
|
said nothing collapses the block to its summary (`3 steps
|
|
1119
|
-
· 8 tool calls · execute ×7 · read ×1`). Either way the answer
|
|
1120
|
-
|
|
1121
|
+
· 8 tool calls · execute ×7 · read ×1`). Either way the answer is a normal
|
|
1122
|
+
bubble under the block (Markdown, annotate). A plain answer
|
|
1121
1123
|
without tools ends exactly as it does today. Rows the code collapses stay
|
|
1122
1124
|
as you toggled them. A reloaded session shows the same block
|
|
1123
1125
|
from the saved messages (each step's thinking, narration, tool parameters
|
|
@@ -1130,7 +1132,10 @@ steps saved before that have none, so they show no thinking. An `edit` or
|
|
|
1130
1132
|
made (up to 120 lines or 8 KB), live and after a reload (see
|
|
1131
1133
|
[Guardrails](guardrails.md#ask) for the diff an approval shows first).
|
|
1132
1134
|
|
|
1133
|
-
|
|
1135
|
+
`web.view`, `chi web --web-view`, `SAMAGOTCHI_WEB_VIEW` and `?view=` were removed with the turn view (the
|
|
1136
|
+
stage is the only view; a config.yml that still sets `web.view:` warns about an unknown key).
|
|
1137
|
+
|
|
1138
|
+
**When things happened**, on the owner's page and on a participant's review page: where 10 minutes or
|
|
1134
1139
|
more of quiet passed between the end of one activity and the start of the next (a turn, a context
|
|
1135
1140
|
note, a reminder), the history has one dim centred line, `── 14:32 · 47 min later ──`; the date is
|
|
1136
1141
|
added when the day changed or the turn wasn't today (`── Sat 24 Oct 09:10 · 13 h later ──`).
|
|
@@ -1147,7 +1152,7 @@ it read, edited or wrote, the memories it read or wrote and the URLs it
|
|
|
1147
1152
|
fetched. It is on by default; `web.working_set: false` (or `chi web
|
|
1148
1153
|
--no-web-working-set`, `SAMAGOTCHI_WEB_WORKING_SET=false`; `?working_set=0` on
|
|
1149
1154
|
the page URL for one page load, `?working_set=1` back on) turns it off, and the
|
|
1150
|
-
session bar shows the `mem N` chip again.
|
|
1155
|
+
session bar shows the `mem N` chip again.
|
|
1151
1156
|
|
|
1152
1157
|
- **The rail**, on the right of the stage's live slots: the running turn's set
|
|
1153
1158
|
in four lines, folded as it grows (files under one folder become
|
data/docs/configuration.md
CHANGED
|
@@ -656,7 +656,7 @@ models:
|
|
|
656
656
|
came from);
|
|
657
657
|
- `chi --thinking LEVEL` on a run that starts or resumes a session (the REPL, `-p`, `--resume`, an attached one);
|
|
658
658
|
- `chi send --new --thinking LEVEL`;
|
|
659
|
-
- the web's
|
|
659
|
+
- the web's ⚙ panel in the session bar (its Thinking row), and the start page's ⚙ panel (`POST /api/sessions` takes `"thinking": "low"`;
|
|
660
660
|
anything that isn't a level answers `400 invalid_thinking`).
|
|
661
661
|
- `chi web --thinking LEVEL` is the default for the sessions its workers run, below a session's own. A session started
|
|
662
662
|
with only the env (`SAMAGOTCHI_THINKING_LEVEL=low chi send --new …`) loses the level when a worker without that env
|
|
@@ -809,7 +809,7 @@ models:
|
|
|
809
809
|
(its file's `"reasoning_history"`), so a `--resume`, a respawned worker, a continue and `/model` keep it; a plugin's
|
|
810
810
|
fork copies it, a delegate child starts without it. Set it with `/reasoning-history LEVEL` in the session
|
|
811
811
|
(`/reasoning-history default` unsets it, `/reasoning-history` alone shows the level and where it came from) or the
|
|
812
|
-
web's
|
|
812
|
+
web's ⚙ panel in the session bar (its Reasoning row, shown on chat hosts only). There is no start flag: a fresh session runs
|
|
813
813
|
the command before its first turn at no cost. A change takes effect at the next turn's start; sent while a turn runs
|
|
814
814
|
it waits for its end.
|
|
815
815
|
- What a change costs the prompt cache (`/reasoning-history` says so, and asks first when it costs: "Changes that
|
|
@@ -849,8 +849,8 @@ first: an unknown host or a bad alias is an error at once, not a question.
|
|
|
849
849
|
- `Nothing changed yet: send /thinking low --yes to apply.` names the line that applies it.
|
|
850
850
|
- `--yes` (or `-y`, anywhere after the command) applies it at once.
|
|
851
851
|
- The terminal (the REPL and an attached TUI) puts the `--yes` line in the next input: Enter applies it.
|
|
852
|
-
- The web's reply bubble has an **Apply (restarts the cache)** button. The session bar's
|
|
853
|
-
choice:
|
|
852
|
+
- The web's reply bubble has an **Apply (restarts the cache)** button. The session bar's ⚙ panel is already an
|
|
853
|
+
explicit choice: a tap sends the `--yes` line, and its note says what a change costs. Command bubbles are page-only, so
|
|
854
854
|
the button is gone after a reload.
|
|
855
855
|
- Only a person at a web tab or a chi TUI is asked. `chi send ID "/thinking low"`,
|
|
856
856
|
`chi -p "/thinking low" --non-interactive`, lines piped into the REPL, a delegate, a plugin and a card's action
|
|
@@ -1570,12 +1570,15 @@ toolkit:
|
|
|
1570
1570
|
cache; `full` and every kit without a prompt send the bytes they sent before. Keep it to a line or two that
|
|
1571
1571
|
fits the kit's work (the coordinator bundle's `coding`: be concise): one that isn't text or is over 2000
|
|
1572
1572
|
characters is left out with a warning, and long text belongs in `append_system_prompt:`. `/toolkit` shows it
|
|
1573
|
-
(`prompt: …`), `/stats` its kit and size (`kit prompt:`), the web's
|
|
1573
|
+
(`prompt: …`), `/stats` its kit and size (`kit prompt:`), the web's 🧰 chip in its tooltip.
|
|
1574
1574
|
- **Saved at creation, definitions resolve at worker start.** A session stores its toolkit as named
|
|
1575
1575
|
(`"toolkit": {"name": "lean", "add": [], "remove": []}`) when it is created: `toolkit.default`, `toolkit.child`
|
|
1576
1576
|
for a delegate child (or the kit its `delegate` call names), or `chi --toolkit NAME` / `--tool` / `--no-tool` ([cli](cli.md)). Changing `toolkit.default`
|
|
1577
1577
|
doesn't move existing sessions, not even when their worker is woken again; a session from before toolkits is on
|
|
1578
|
-
`full`. A continue and a fork keep the toolkit name. `/toolkit` shows and changes it. The
|
|
1578
|
+
`full`. A continue and a fork keep the toolkit name. `/toolkit` shows and changes it. The web's session bar
|
|
1579
|
+
shows it as the 🧰 chip after ⚙: `🧰` alone while the session is on `toolkit.default` (its tooltip names the kit,
|
|
1580
|
+
"full (the default)"), `🧰 lean` on another kit (`GET /api/sessions/:id`'s `session.toolkit` against
|
|
1581
|
+
`session.toolkit_default`, the default as chi web reads it now); it has no picker, `/toolkit` changes it. The kit's tools, prompt
|
|
1579
1582
|
text and group selectors are part of its definition, not the session file: edits reach a saved name at its next
|
|
1580
1583
|
worker start.
|
|
1581
1584
|
- **A new web chat: 🧰.** The start page's 🧰 (beside ⚙; a bottom sheet on a phone) picks the new session's toolkit.
|
|
@@ -1708,7 +1711,7 @@ its own). The first target is a long session such as a day-long coordinator, whe
|
|
|
1708
1711
|
|
|
1709
1712
|
- **Set it** at start with `chi --llm-context stale,forget --llm-context-apply turn_end --llm-context-budget 64k`
|
|
1710
1713
|
(the same flags on `chi send --new`), in the session with `/llm-context strategy … apply … budget …`
|
|
1711
|
-
(docs/cli.md, "Session commands"), or from the web's
|
|
1714
|
+
(docs/cli.md, "Session commands"), or from the Context row of the web's ⚙ panel in the session bar.
|
|
1712
1715
|
- **A new web chat:** the start page's ⚙ panel (beside the model picker; a bottom sheet on a phone) holds the new
|
|
1713
1716
|
session's rarely used settings, each a row of segments that applies at once: **Thinking** and **Context** (the
|
|
1714
1717
|
strategy; **Apply and budget ▸** opens the other two fields, with their own Set), the first segment following the
|
|
@@ -2184,8 +2187,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2184
2187
|
| `web.port` | `4567` | `--port` | `chi web`'s port. See [CLI](cli.md). |
|
|
2185
2188
|
| `web.host` | `127.0.0.1` | yes | `127.0.0.1`, `::1` or `localhost`; `lan` (this machine's private IPv4 address) or one of its IPv4 addresses also opens `chi web` to the network, with an access token, asked of this machine's 127.0.0.1 too (its `Local:` link carries a one-time code; `chi web --new-token` replaces the token). Anything else binds `127.0.0.1` with a warning. See [CLI: chi web on your phone](cli.md#chi-web-on-your-phone). |
|
|
2186
2189
|
| `web.markdown` | `false` | yes | Render answers as Markdown in `chi web`. |
|
|
2187
|
-
| `web.
|
|
2188
|
-
| `web.working_set` | `true` | yes | The stage view's working set: the files, memories and URLs a turn brought into the model's context, in a rail in the stage, a footprint line under each finished turn and a `set N` chip in place of the mem chip; `false` brings the mem chip back. `?working_set=1` or `?working_set=0` on the page URL overrides it for that page load; the turn view ignores it. See [CLI: the working set](cli.md#the-working-set). |
|
|
2190
|
+
| `web.working_set` | `true` | yes | The stage view's working set: the files, memories and URLs a turn brought into the model's context, in a rail in the stage, a footprint line under each finished turn and a `set N` chip in place of the mem chip; `false` brings the mem chip back. `?working_set=1` or `?working_set=0` on the page URL overrides it for that page load. See [CLI: the working set](cli.md#the-working-set). |
|
|
2189
2191
|
| `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). |
|
|
2190
2192
|
| `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). |
|
|
2191
2193
|
| `web.start_dir` | the folder `chi web` runs in | | The folder `chi web` starts in (`chi web --start-dir DIR` for one run): its page (the printed link, a bare `/`, the LAN link and QR code, the Home Screen app) opens on that folder's project, outside a repo on every session, and a new session from the all view starts there; the header's project picker switches projects. `~` and a relative path (resolved from your home folder) work; one that isn't a folder stops `chi web` from starting. `chi web` never changes its own folder. See [CLI](cli.md). |
|
data/docs/guardrails.md
CHANGED
|
@@ -54,6 +54,11 @@ changed: `diff +3 −1` under the row on the web (closed, it survives a
|
|
|
54
54
|
reload) and ` +3 −1` at the end of the terminal's tool line. The model never
|
|
55
55
|
sees these diffs.
|
|
56
56
|
|
|
57
|
+
The card also carries the ask's facts as `approval:` (tool, command or paths, where, rule, scopes, preview…):
|
|
58
|
+
`Guardrails::Approval.payload` builds them as a `Guardrails::ApprovalFacts` value, which System 1 and the parent
|
|
59
|
+
checks read in the worker; the card and the session file get its `to_h`, the same hash every UI reads, and a saved
|
|
60
|
+
card comes back through `ApprovalFacts.from_h` (string or symbol keys, missing fields nil).
|
|
61
|
+
|
|
57
62
|
Who answers:
|
|
58
63
|
|
|
59
64
|
- REPL (`chi --no-shared`, with or without `-p`): at the `? ` prompt.
|
|
@@ -516,10 +521,36 @@ own, one another interpreter runs (`ruby -e`, `python - <<EOF`) by its text
|
|
|
516
521
|
variable a program runs through a shell (`PairCommand::COMMAND_ENV`:
|
|
517
522
|
`GIT_EDITOR`, `GIT_SEQUENCE_EDITOR`, `EDITOR`, `VISUAL`, `GIT_EXTERNAL_DIFF`,
|
|
518
523
|
`GIT_SSH_COMMAND`, `GIT_SSH`, `GIT_PROXY_COMMAND`, `GIT_PAGER`, `PAGER`,
|
|
519
|
-
`MANPAGER`, `GIT_ASKPASS`, `SSH_ASKPASS`), as a prefix,
|
|
520
|
-
read as `sh -c` would run it, for the refusals and for
|
|
524
|
+
`MANPAGER`, `GIT_ASKPASS`, `SSH_ASKPASS`, bash's `PROMPT_COMMAND`), as a prefix,
|
|
525
|
+
`env`'s or `export`'s: read as `sh -c` would run it, for the refusals and for
|
|
526
|
+
an outside write. An assigned value that keeps a `$(…)`, `${ …; }` or backticks
|
|
527
|
+
as text (`PS4='$(…)' bash -x`, `PS0`, `PS1`, `$'\x24(…)'`: the shell expands it
|
|
528
|
+
later), a prefix's, a bare assignment's or `export`'s (not `grep 'X=$(…)'`), is
|
|
529
|
+
refused for what its `$(…)` runs (`PS4='$(git config …)'`), and otherwise the
|
|
530
|
+
owner approves it (`PairBoundary::NET`: `CFLAGS='$(BASE)' make`).
|
|
531
|
+
The program is found behind the wrappers (`env`, `sudo`, `timeout`, `xargs`,
|
|
532
|
+
`nice`, `exec`, `command`, `builtin`, `xcrun`, `arch`, `script`'s file, `npx`,
|
|
533
|
+
`bunx`, `uvx`, and two-word ones: `uv`/`poetry`/`pdm`/`hatch`/`pipx run`,
|
|
534
|
+
`pnpm`/`yarn exec`/`dlx`, `npm exec`/`x`, `bun x`, `mise exec`/`x`) and their
|
|
535
|
+
value options (`env -u X`, `sudo -u root`, `timeout -s KILL 5`; `xcrun -r`,
|
|
536
|
+
`sudo -n` are flags). A command line a program takes as text is read as a
|
|
537
|
+
command: `env -S S` (`-vS S` too), `script -c S`, `npx`/`npm exec -c S`
|
|
538
|
+
(`--call`), `rsync -e S` (`--rsh`), ssh's (scp's, sftp's) `-o ProxyCommand=S`
|
|
539
|
+
(`LocalCommand`, `KnownHostsCommand`: they run here), `hyperfine`'s arguments,
|
|
540
|
+
`parallel`'s and `watch`'s. And as a net for a runner no list knows, any word
|
|
541
|
+
but the program's (a wrapper's option value too) that names git is read as git
|
|
542
|
+
from there, one naming chi before a chi command counts (`chronic chi share x`;
|
|
543
|
+
not `cp bin/chi /tmp/x`), and a command line starting with git or chi is read
|
|
544
|
+
as a command (`some-runner 'git config k v'`): a hit asks the owner
|
|
545
|
+
(`PairBoundary::NET`), it doesn't refuse, since chi can't tell whether that
|
|
546
|
+
word runs (`gh pr create --title 'git config fix'` asks too). A read stays a
|
|
547
|
+
read, and a command that only reads (`rg 'git config'`) isn't netted. A heredoc written as data (`cat`,
|
|
521
548
|
`tee`, `git commit -F -`) is not looked into: where it goes is checked. A
|
|
522
549
|
command the checks can't read is refused, never let through on a text match.
|
|
550
|
+
A program is told by its name in any case, on every disk (`GIT config`, `Chi
|
|
551
|
+
share`, `/bin/SH -c`, `NOHUP`: a disk that folds case, macOS's default, runs
|
|
552
|
+
them as git, chi, sh, nohup; `ShellLex.program_name`), and so is chi or git
|
|
553
|
+
config in a script's text.
|
|
523
554
|
|
|
524
555
|
And it **asks the owner** before a `write` or `edit` that may land outside the
|
|
525
556
|
session's project root, and before a command that may write there, every time:
|
|
@@ -552,7 +583,8 @@ rule lowers it), so it comes even in auto mode. A command fails closed
|
|
|
552
583
|
install -g`, `corepack enable`, `rustup`/`pyenv`/`rbenv`/`asdf`/`volta`/`nvm`
|
|
553
584
|
installs and globals, `code --install-extension`, `gh auth`/`config
|
|
554
585
|
set`/`extension install`, `launchctl` but its reading verbs, `git maintenance register`/`start`, `git
|
|
555
|
-
lfs install
|
|
586
|
+
lfs install`/`update` (git's words from its subcommand on: not `git add
|
|
587
|
+
maintenance start`), `scalar register`/`clone`; a project
|
|
556
588
|
install such as `npm install` or `bundle install` and build caches don't
|
|
557
589
|
count), and no shell or interpreter that reads its script from stdin: one
|
|
558
590
|
on the receiving end of a pipe whatever its options (`… | sh`, `| bash -x`,
|
|
@@ -560,8 +592,10 @@ rule lowers it), so it comes even in auto mode. A command fails closed
|
|
|
560
592
|
or with no script at all: chi can't see that script. A shell's `-e`, `-x`
|
|
561
593
|
and `-o …` are flags, only `-c` (or a cluster holding it, `-ec`, `-cx`)
|
|
562
594
|
hands it a script: the first word after its options (`sh -c -- S`, `bash -c
|
|
563
|
-
-x S`)
|
|
564
|
-
|
|
595
|
+
-x S`), and fish's `--command S` (`--command=S`) or `-C`/`--init-command S`,
|
|
596
|
+
a command it runs first (also attached, `-C'S'`, in a cluster, `-lC S`, and
|
|
597
|
+
by a prefix fish takes, `--comm`, `--init`); an interpreter's own code flag does (`python -c`, `ruby -e`,
|
|
598
|
+
`node -e`/`-p`/`--eval=`, `perl -e`/`-E`, `php -r`/`-B`/`-R`/`-E`, `jruby`/`raku`/`julia -e`), alone or in a cluster
|
|
565
599
|
(`ruby -we`, `perl -le`, `node -pe`, `python3 -Ic`, `python3 -c'…'`;
|
|
566
600
|
`PairCommand.cluster_code_at`: a letter that takes the rest of the word,
|
|
567
601
|
`ruby -rset`, holds no code). A script file it names (`sh
|
|
@@ -570,11 +604,15 @@ rule lowers it), so it comes even in auto mode. A command fails closed
|
|
|
570
604
|
Accepted gaps (an accident guard for a trusted team): a script file the turn
|
|
571
605
|
wrote and then runs; inline scripts read only by their text for paths
|
|
572
606
|
(`find … -exec sh -c '…'`, `flock … sh -c`, `awk 'BEGIN{system(…)}'`,
|
|
573
|
-
`deno eval`); a `GIT_CONFIG_*` set by `printf -v`
|
|
574
|
-
(
|
|
575
|
-
value a program runs (`LESSOPEN`,
|
|
607
|
+
`deno eval`); a `GIT_CONFIG_*` or a `COMMAND_ENV` variable set by `printf -v`
|
|
608
|
+
or `read` and exported (`printf -v GIT_PAGER …; export GIT_PAGER; git log`);
|
|
609
|
+
a variable outside `COMMAND_ENV` whose value a program runs (`LESSOPEN`,
|
|
610
|
+
`BROWSER`, a tool's own `*_EDITOR`; `GIT_EXEC_PATH` runs only a file the
|
|
611
|
+
turn wrote); an interpreter no list names (as `awk`); `npx -y`,
|
|
576
612
|
`npm exec`, `pnpm dlx`, `uvx`: they fetch into a cache, which doesn't count,
|
|
577
|
-
and run the package as in-project work
|
|
613
|
+
and run the package (judged as the program) as in-project work; a wrapper's
|
|
614
|
+
value option no list names (`uv run --with x git …` reads `x` as the program;
|
|
615
|
+
the net still reads the git or chi after it).
|
|
578
616
|
|
|
579
617
|
Anything else asks: `rm -rf ~/x`, `sed -i … ~/x`, `curl -o ~/x`, `dd of=~/x`,
|
|
580
618
|
`touch`/`mkdir` outside, `perl -pi … ~/x`, `cd .. && make`, `cd && make`, and
|
|
@@ -726,6 +764,11 @@ checked even after the database name, and only its read/display options are
|
|
|
726
764
|
allowed (unknown options and dot-command arguments are rejected). `gh` allows
|
|
727
765
|
only `run list|view`, `pr list|view|diff|checks`, `issue list|view` and
|
|
728
766
|
`repo view`; `--web`/`-w`, `gh api` and `pr checks --watch` are not read-only.
|
|
767
|
+
`test` and `[ … ]` (with its closing `]`) are read-only as one check, optionally after `!`: a file or string
|
|
768
|
+
test (`-e`, `-f`, `-d`, `-s`, `-r`, `-w`, `-x`, `-L`, `-h`, `-b`, `-c`, `-p`, `-S`, `-g`, `-u`, `-k`, `-O`, `-G`,
|
|
769
|
+
`-n`, `-z` with one operand) or a comparison (`=`, `==`, `!=`, `-eq`, `-ne`, `-lt`, `-le`, `-gt`, `-ge`), so
|
|
770
|
+
`test -f x && cat x` and `[ -d dir ] && ls dir` only read; `-a`/`-o`, `( … )`, any other operator or a missing
|
|
771
|
+
operand, and `[[ … ]]` are not.
|
|
729
772
|
`$(…)`, backticks, `$VAR` (other than `$HOME`, `$XDG_*`, `$TMPDIR` and `$PWD`
|
|
730
773
|
at a word's start), an env prefix, `sh -c`, `xargs`, `eval`, `sudo` and the
|
|
731
774
|
like make a command not read-only, as does a `task_create` `env:` that sets `BASH_ENV`, `ENV`, `CDPATH`, `IFS`,
|
|
@@ -873,6 +916,7 @@ every surface answers for the same paths):
|
|
|
873
916
|
| in a dir: `under?` (case-folded on a folding disk; `fold: false` exact), `strictly_under?`, `within?` (root resolved too) | `PathResolve` | `under?`: ShellPaths, ReviewPaths, PairCommand, ChildBoundary, SelfProtect's words; `Outside.within?` and RmTargets' `strictly_under?` fold only when the dir exists (a missing session root keeps the case it was typed in); `within?`: ProtectedPaths, ScratchWrites, ParentApprovals, SelfProtect's paths |
|
|
874
917
|
| tmp dirs and "not one the session is in" | `PathResolve.tmp_roots(session:)` (exact case) | Outside (`Outside.tmp_roots` is the list it and Targets read), RmTargets; `touches_chi?` takes all of them |
|
|
875
918
|
| a shell word's `~`, `$HOME`, XDG dirs, `$TMPDIR` | `PathResolve.expand_word` | ShellPaths::Walk, ShellGitDirs; PairCommand has its own `~`/`$HOME` (`expand_tilde`) |
|
|
919
|
+
| a program word's name: basename, case-folded on every disk (`GIT`, `/bin/SH`, `ſh`) | `ShellLex.program_name` / `.program?` | PairCommand, ImplicitWriters, SelfProtect's file runners, ShellGitDirs, SharedGit |
|
|
876
920
|
| chi's dirs | `ChiDirs.protected` / `.touches` / `.self_protect` / `.review` | ParentApprovals, Targets, SelfProtect, ReviewPaths (`ProtectedPaths` and `ScratchWrites` get theirs from the wiring) |
|
|
877
921
|
|
|
878
922
|
Left apart on purpose: `Targets.prompt_memory_path?` compares in any case on
|
data/docs/internals/engine.md
CHANGED
|
@@ -76,7 +76,10 @@ Engine#run_turn(session, prompt, on_event:, max_iterations:, cancel_controller:,
|
|
|
76
76
|
│ # messages, goes IDLE, records last_turn (enqueued_id: the turn's input, from its origin;
|
|
77
77
|
│ # a continue turn's origin carries its offer turn's, ContinueOffer#run_continue_turn),
|
|
78
78
|
│ # and :turn_completed {result, turn_summary, display_pending} or :turn_canceled
|
|
79
|
-
│ # {cancellation_reason, cancelled_by, duration_ms} is emitted
|
|
79
|
+
│ # {cancellation_reason, cancelled_by, duration_ms} is emitted; before the replace,
|
|
80
|
+
│ # stamp_opening puts a Verify turn's `verify` and a completed Revise turn's `revises`
|
|
81
|
+
│ # (re-targeted to its stack's top) on the opening message, metadata never sent, and
|
|
82
|
+
│ # :turn_completed carries `verdict` / `revises` when there are
|
|
80
83
|
│ # then the :after_turn hook (status, messages, present: the AnswerDisplay presenter,
|
|
81
84
|
│ # refs: the AnswerRefs adder)
|
|
82
85
|
│ # store_answer_display (one replace of the answer: `display` and/or `display_refs`;
|
|
@@ -330,7 +333,7 @@ One iteration with tool calls:
|
|
|
330
333
|
stored under the real path; at most `RowRefs::MAX_REFS` and `MAX_BYTES`). `ToolRowFields.for` can't build it (no plugins on a reload), so the run carries it
|
|
331
334
|
as `refs:`, saved with the result as `tool_refs` (`ToolResponse::SAVED_KEYS`, never sent), and
|
|
332
335
|
`MessageParts#tool_part` reads it back through `RowRefs.for_display` (checked again). The page binds them to the
|
|
333
|
-
row's title (`refs.js bindRowRefs`, from `
|
|
336
|
+
row's title (`refs.js bindRowRefs`, from `turn_block.js` live and on a reload): the first ref on it, the rest in its
|
|
334
337
|
menu.
|
|
335
338
|
- Settles an ask verdict after `:tool_call_started`, so a UI shows the tool line and then the approval.
|
|
336
339
|
- Dispatches through `KernelLoop#dispatch_tool_call`, or writes the denial text. Unknown tools are answered in
|
|
@@ -545,7 +548,7 @@ Turn events (the main ones; `Events` in `events.rb` keeps the shared sets):
|
|
|
545
548
|
| `:working_set_updated` | after `:generation_started` (the running turn's conversation, the turn's strategy) and once in `end_turn` before the end event (the kept messages), only when the set differs from the last one emitted for the session and is not empty, except one empty event when the last one had items (a rollback emptied the set): a tool-free turn emits none (`Engine#emit_working_set`); between turns `Engine#announce_working_set` announces it under the next turn's strategy (after a `/working-set` op, held behind the command's `command_ran`) | `{items: [{kind, key, state (live\|stale\|forgotten\|dropped), tokens, ops, count, first_id, pinned, has_drop}], at, adds?: [{kind, key, label}]}` (`WorkingSet`, internals/working-set.md; `adds` while the user's adds are pending) |
|
|
546
549
|
| `:hook_notice` | a hook's or plugin's notify during a turn | `{hook, text, level}` (announced with `between_turns: true` outside a turn) |
|
|
547
550
|
| `:guardrail_warning` | a guardrails line during a turn | `{message}` |
|
|
548
|
-
| `:turn_completed` | normal end | Engine event `{result, turn_summary, display_pending}
|
|
551
|
+
| `:turn_completed` | normal end | Engine event `{result, turn_summary, display_pending}`, plus `verdict` (a Verify turn's recorded verdict) and `revises` (a Revise turn's stamp, `{turn_id}`) when there are; the Bridge's SSE frame omits `result` (answer remains in `turn_summary.output`) |
|
|
549
552
|
| `:turn_canceled` | Stop, hook stop, Ctrl-C | `{cancellation_reason, cancelled_by?, duration_ms}` |
|
|
550
553
|
| `:turn_failed` | an error | `{error_class, message, duration_ms, error_kind?, retryable?, host?, summary?}` |
|
|
551
554
|
| `:answer_display` | after the after_turn hooks (observers only, not the sink) | `{display, refs?}` (display a string, or nil; refs the count of the answer's refs, only when a hook attached some) |
|
|
@@ -583,7 +583,7 @@ message's `author_name`, `turn_started`'s, or the panel's list (`participant_nam
|
|
|
583
583
|
A review turn proposes; the owner applies (D4, §3 Apply-as-quote). A pair turn acted itself: no Apply under it
|
|
584
584
|
(`ReviewApply.review_turn?`: a participant's opening message not stamped `pair`; the route answers it
|
|
585
585
|
`not_review_turn`, and its "latest" skips it). Under each participant's review turn that has a
|
|
586
|
-
reply, the owner's page shows **Apply** (`review_apply.js`; drawn by the history render, `
|
|
586
|
+
reply, the owner's page shows **Apply** (`review_apply.js`; drawn by the history render, `turn_block.js`, and at a live
|
|
587
587
|
turn's end from its `turn_started`'s turn id and author, in the stage while the stage holds the turn; a full-width
|
|
588
588
|
button on a phone). It reads `GET …/apply?turn=T` and puts the answer in the composer, after whatever is typed there,
|
|
589
589
|
never sent: the owner reads it, edits it, sends it or not. While the composer holds it (`deliveryControl.hold()`,
|
|
@@ -253,7 +253,7 @@ is prefilled once. The native and the chat loop use the same plan.
|
|
|
253
253
|
estimate when no count is known. On `api: anthropic`, a `:full` / `:provider` change also warns that preserved
|
|
254
254
|
thinking in replies is dropped from then on. A new setting with a cost adds its classifier and goes through
|
|
255
255
|
the same step. A launch flag (`chi --model`, `--llm-context`, `--thinking` on an attached or resumed session,
|
|
256
|
-
`LLMContextOverride.command_line`) and
|
|
256
|
+
`LLMContextOverride.command_line`) and the session bar's ⚙ panel, whose note states the cost (`settings_chip.js`)
|
|
257
257
|
send their line with `--yes`: typing the flag, or the Set, is the choice. A plugin command asks
|
|
258
258
|
through `ctx.cache_confirm(line, changed:)` (cost `:full`: its prompt section is in the stable part), with the
|
|
259
259
|
sender's flag `SessionCommands#run` gives it (`CacheConfirm.asking`), and returns `[text, confirm]`.
|