samagotchi 0.118.0 → 0.120.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 +76 -1
- data/bin/chi +6 -1
- data/docs/architecture.md +35 -5
- data/docs/cli.md +60 -6
- data/docs/configuration.md +47 -10
- data/docs/internals/participants.md +109 -12
- data/docs/internals/remote-sessions.md +6 -1
- data/docs/internals/web-push.md +4 -2
- data/docs/plugins.md +22 -0
- data/docs/sessions.md +4 -3
- data/docs/testing.md +10 -1
- data/lib/samagotchi/answer_command.rb +2 -0
- data/lib/samagotchi/bridge.rb +56 -13
- data/lib/samagotchi/bridge_client/event_stream.rb +34 -3
- data/lib/samagotchi/bridge_client.rb +58 -19
- data/lib/samagotchi/bridge_secret.rb +35 -0
- data/lib/samagotchi/bundles/claude-peer/manifest.yml +3 -3
- data/lib/samagotchi/bundles/claude-peer/scripts/chi-peer-SKILL.md +48 -0
- data/lib/samagotchi/bundles/claude-peer/scripts/pair +73 -16
- data/lib/samagotchi/bundles/system/manifest.yml +1 -1
- data/lib/samagotchi/config.rb +3 -0
- data/lib/samagotchi/participant_messages.rb +5 -0
- data/lib/samagotchi/participants.rb +16 -6
- data/lib/samagotchi/review_command.rb +3 -1
- data/lib/samagotchi/run_options.rb +3 -1
- data/lib/samagotchi/session_access/contract.rb +4 -1
- data/lib/samagotchi/session_access/local.rb +15 -4
- data/lib/samagotchi/session_access/remote.rb +43 -7
- data/lib/samagotchi/session_access.rb +11 -1
- data/lib/samagotchi/session_manager.rb +1 -1
- data/lib/samagotchi/sessions_command.rb +1 -2
- data/lib/samagotchi/share_command.rb +29 -8
- data/lib/samagotchi/terminal_ui/attached_loop.rb +3 -0
- data/lib/samagotchi/terminal_ui/local_link.rb +18 -3
- data/lib/samagotchi/tools/delegate_relay.rb +4 -0
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +117 -43
- data/lib/samagotchi/web/grants.rb +127 -16
- data/lib/samagotchi/web/link_codes.rb +24 -15
- data/lib/samagotchi/web/participant_access.rb +69 -13
- data/lib/samagotchi/web/participant_exposure.rb +44 -0
- data/lib/samagotchi/web/participant_review.rb +66 -8
- data/lib/samagotchi/web/participants_admin.rb +12 -6
- data/lib/samagotchi/web/proxy_gate.rb +18 -3
- data/lib/samagotchi/web/public/annotate_bar.css +18 -0
- data/lib/samagotchi/web/public/annotate_bar.js +10 -3
- data/lib/samagotchi/web/public/app.js +66 -155
- data/lib/samagotchi/web/public/composer.css +73 -0
- data/lib/samagotchi/web/public/composer_grip.js +21 -15
- data/lib/samagotchi/web/public/composer_mount.js +196 -0
- data/lib/samagotchi/web/public/index.html +7 -83
- data/lib/samagotchi/web/public/notifications.js +58 -8
- data/lib/samagotchi/web/public/participant.html +45 -10
- data/lib/samagotchi/web/public/participant.js +92 -18
- data/lib/samagotchi/web/public/participant_annotate.js +75 -0
- data/lib/samagotchi/web/public/participant_model.js +53 -1
- data/lib/samagotchi/web/public/participants_panel.js +34 -10
- data/lib/samagotchi/web/public/review_history.js +52 -0
- data/lib/samagotchi/web/public/scope.js +12 -8
- data/lib/samagotchi/web/public/stage_frame.js +9 -4
- data/lib/samagotchi/web/public/stage_view.js +4 -4
- data/lib/samagotchi/web/push/notifier.rb +17 -3
- data/lib/samagotchi/web/running.rb +7 -4
- data/lib/samagotchi/web/server.rb +34 -11
- data/lib/samagotchi/web/session_create.rb +7 -7
- data/lib/samagotchi/web/start_dir.rb +26 -0
- data/lib/samagotchi/worker_sidecar.rb +22 -11
- metadata +9 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b242fb85587a862bad996a05e189367e5a4e1b9d025df7a7d335d60b2184fe4
|
|
4
|
+
data.tar.gz: 85ababba9d74adb82a892cc96d8e2a9fc430a36caf55e9fa9bf549b0f502d136
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 179d89d141810eccc0038f7eac484775c17cc6b07b80504e4139a6ad0579ebb51fe344619bbb949ad9d5a183c5e82fff90915015915a12bdfac46a5b4589cde2
|
|
7
|
+
data.tar.gz: faeb2bde8eab54b4c286f596e9e3005678d1a6aeebc4758af00aa33da12e4ec5492627a6edc4b7f19c7343e361b0501e3ad92ef53edcf7684255241904e14006
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,79 @@ 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.120.0] - 2026-10-26
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `chi web --start-dir DIR` and `web.start_dir`: the folder chi web starts in, in place of the one you run it in
|
|
15
|
+
(`~` and a relative path work; one that isn't a folder stops it, exit 1). Its page opens on that folder's project,
|
|
16
|
+
and a new session from the all view starts there. A chi web already running in another folder keeps it and the
|
|
17
|
+
second one says so: restart it to change it.
|
|
18
|
+
- Annotate on the participant page: selecting text in the Plan (the review's files) or the thread offers your
|
|
19
|
+
`web.annotate_presets` and quotes the selection into the comment box (`From <path>:` / `From <name>'s comment:`),
|
|
20
|
+
as on your own page.
|
|
21
|
+
- The participant page's comment box is the owner's composer: it grows with the text, its grip resizes or folds it
|
|
22
|
+
(Annotate and typing open it again), it stays one row on a phone, and ↑/↓ recall the participant's own earlier
|
|
23
|
+
comments from that browser (kept per review link, never your prompt history). No `/` list, delivery choices or
|
|
24
|
+
images there yet; every comment is still a queued review turn. Your participant view has no comment box.
|
|
25
|
+
- The participant page shows the participant their own usage in one line under the comment box: what their
|
|
26
|
+
comments have cost you of their cap (a running turn's too), their queued comments of their queue limit, when their
|
|
27
|
+
link ends, and the session's model. Never another participant's spend, yours or the session's. It sits on a
|
|
28
|
+
per-link exposure level (`own`, the only one so far), so a later tier can show more.
|
|
29
|
+
- Review links bound to one account: `chi share ID --name NAME --identity EMAIL` (and the Invite dialog's email field,
|
|
30
|
+
behind an auth proxy that names the signed-in user: `web.public_url` with `web.proxy.identity_header`, or
|
|
31
|
+
`chi web --tunnel tailscale`) makes a link that opens only through that proxy, signed in as EMAIL. A forwarded
|
|
32
|
+
link opens for nobody else, and on the LAN or this machine for nobody. `--identity` without such a proxy is refused
|
|
33
|
+
(the link could never open), and `chi share` warns when a link could be bound and isn't. `chi share ls` shows
|
|
34
|
+
`alex@corp · bound`. Through `chi --remote`, `--identity` needs that chi web to be this version or newer (an older
|
|
35
|
+
one would ignore it and make a link anyone could open).
|
|
36
|
+
- chi web trusts proxy headers (`X-Forwarded-*`, the identity header, the public Host) only from this machine
|
|
37
|
+
(a loopback peer): the proxy must run where chi web runs. With `web.host: lan` and `web.public_url` together, a LAN
|
|
38
|
+
device sending those headers is a LAN request, never one through the proxy. An identity header that isn't ASCII is
|
|
39
|
+
refused.
|
|
40
|
+
- A bound link opened by another account, or not through the proxy, is refused with its own words (401
|
|
41
|
+
`token_bound`: "this review link is for another account …", on the page too), and the refusal goes into the
|
|
42
|
+
session's participants audit naming who tried. Its one-time code stays usable: the person it was sent to can still
|
|
43
|
+
open it. Behind a proxy the audit's new-peer lines are per signed-in identity (every peer there is 127.0.0.1).
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- chi web's bare page (`/`: the LAN link and its QR code, the Home Screen app) opens on the project chi web starts in,
|
|
48
|
+
as its printed link already did; outside a repo it shows every session as before. Every project's sessions are now
|
|
49
|
+
`/?scope=all` (the header's `all`), and `chi web --scope=all` (or a `chi web` run outside a repo) prints that link.
|
|
50
|
+
- A pushed notification opens its session in that session's own project (the all view for a session outside a repo),
|
|
51
|
+
not the project the app shows. The Home Screen app's notifications and badge still cover every project: on a
|
|
52
|
+
project's page it tidies them from every session's events, where before a project's page (`?dir=`) left them as
|
|
53
|
+
they were.
|
|
54
|
+
- The participants' grants store (`web-grants/grants.json`) carries a version: 2 once a grant is bound to an identity.
|
|
55
|
+
chi keeps a grant's fields it doesn't know when it rewrites the store, and never writes over a store a newer chi
|
|
56
|
+
wrote (its links still work; invite, cap and revoke say to update chi). A chi from before this one doesn't check.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- chi web's stage: on a phone its height follows the whole bottom dock (an info bar that wraps late after a reload
|
|
61
|
+
no longer leaves it too tall), and the keyboard opening during a smooth scroll no longer leaves a question card
|
|
62
|
+
out of sight.
|
|
63
|
+
|
|
64
|
+
### Security
|
|
65
|
+
|
|
66
|
+
- A session's worker answers only chi's own clients on its machine: its Bridge makes a random secret, written to the
|
|
67
|
+
session's `bridge.json` (readable by you only), and refuses every request that doesn't name it (403
|
|
68
|
+
`bridge_secret`). A proxy or tunnel that forwards every local port, or another account on the machine, reaches the
|
|
69
|
+
port but no longer a session. **After updating chi, restart chi web, re-attach terminals** (`chi --attach ID`) **and
|
|
70
|
+
restart older session workers** (`chi sessions restart ID...`): a chi web, attached terminal or session worker from
|
|
71
|
+
before the update sends no secret, and a worker the new chi starts (a delegate child too) refuses it with a message
|
|
72
|
+
saying so. Workers started before the update ask for no secret and answer both until they restart.
|
|
73
|
+
|
|
74
|
+
## [0.119.0] - 2026-10-26
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- claude-peer (0.4.3): `pair --inbox-socket PATH` pairs both ways with chi on
|
|
79
|
+
another machine through an `ssh -R` forward of Claude's socket
|
|
80
|
+
([docs/plugins.md](docs/plugins.md)); docs/cli.md: remote sessions through an
|
|
81
|
+
SSH tunnel. Update with `chi update`.
|
|
82
|
+
|
|
10
83
|
## [0.118.0] - 2026-10-26
|
|
11
84
|
|
|
12
85
|
### Changed
|
|
@@ -4445,7 +4518,9 @@ and long-lived sessions.
|
|
|
4445
4518
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
4446
4519
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
4447
4520
|
|
|
4448
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
4521
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.120.0...HEAD
|
|
4522
|
+
[0.120.0]: https://github.com/dm1try/samagotchi/compare/v0.119.0...v0.120.0
|
|
4523
|
+
[0.119.0]: https://github.com/dm1try/samagotchi/compare/v0.118.0...v0.119.0
|
|
4449
4524
|
[0.118.0]: https://github.com/dm1try/samagotchi/compare/v0.117.0...v0.118.0
|
|
4450
4525
|
[0.117.0]: https://github.com/dm1try/samagotchi/compare/v0.116.0...v0.117.0
|
|
4451
4526
|
[0.116.0]: https://github.com/dm1try/samagotchi/compare/v0.115.0...v0.116.0
|
data/bin/chi
CHANGED
|
@@ -134,6 +134,10 @@ if options[:tunnel] && !web
|
|
|
134
134
|
warn "Error: --tunnel goes with chi web (chi web --tunnel tailscale)"
|
|
135
135
|
exit 2
|
|
136
136
|
end
|
|
137
|
+
if options[:start_dir] && !web
|
|
138
|
+
warn "Error: --start-dir goes with chi web (chi web --start-dir DIR)"
|
|
139
|
+
exit 2
|
|
140
|
+
end
|
|
137
141
|
if options[:sets] && web
|
|
138
142
|
warn "Error: --set is a new session's (chi --set, chi send --new --set), not chi web's"
|
|
139
143
|
exit 2
|
|
@@ -225,7 +229,8 @@ if options[:web]
|
|
|
225
229
|
markdown: markdown, view: view, new_token: options[:new_token], tunnel: options[:tunnel],
|
|
226
230
|
working_set: Samagotchi::Config.get("web.working_set"),
|
|
227
231
|
annotate_presets: Samagotchi::Config.get("web.annotate_presets"),
|
|
228
|
-
editor: Samagotchi::Config.get("web.editor")
|
|
232
|
+
editor: Samagotchi::Config.get("web.editor"),
|
|
233
|
+
start_dir: options[:start_dir] || Samagotchi::Config.get("web.start_dir"))
|
|
229
234
|
end
|
|
230
235
|
|
|
231
236
|
# --resume and --attach take a unique id prefix too, like git.
|
data/docs/architecture.md
CHANGED
|
@@ -152,7 +152,7 @@ agent logic and can be used without any terminal rendering; the UI is a thin lay
|
|
|
152
152
|
| Core | `Samagotchi::Engine` | System prompt, memory injection, tool declarations, session lifecycle, the model↔tool loop (`run_turn`). No terminal coupling. |
|
|
153
153
|
| UI | `Samagotchi::TerminalUI` | Interactive REPL (Reline), rendering (ANSI, spinner, status line), REPL commands. Delegates all core work to an `Engine`. |
|
|
154
154
|
| Model loops and adapters | `KernelLoop`, `LLM::ChatLoop`, `Samagotchi::Client`, `LLM::OpenAIChat`, `LLM::AnthropicMessages`, `LLM::HTTP` | The model↔tool loops and the HTTP adapters they talk through (see "Model loops and adapters"). |
|
|
155
|
-
| Bridge (SSE/HTTP) | `Samagotchi::Bridge`, `SessionManager` | The **single live client transport**: an SSE read stream + HTTP POST turn/cancel/answer surface that attaches to a worker's existing `Engine` via `Engine#subscribe`. Every session worker starts it (bound `127.0.0.1`,
|
|
155
|
+
| Bridge (SSE/HTTP) | `Samagotchi::Bridge`, `SessionManager` | The **single live client transport**: an SSE read stream + HTTP POST turn/cancel/answer surface that attaches to a worker's existing `Engine` via `Engine#subscribe`. Every session worker starts it (bound `127.0.0.1`, localhost-only), and it answers only a request that names its secret (`X-Chi-Bridge`, from the worker's 0600 `bridge.json`). |
|
|
156
156
|
| Web (Rack) | `Samagotchi::Web::App`, `SessionManager` | Single-port `127.0.0.1:4567` control plane via `rack`+`webrick` (serve `index.html` + `/api/*`). With `web.host: lan` (or one of this machine's IPv4 addresses) the server also listens on that address, where every request but this machine's needs the access token (`App#token_gate`: the `chi_token` cookie or `Authorization: Bearer`; [CLI](cli.md#chi-web-on-your-phone)). Experimental: behind an auth proxy (`web.public_url`, `Web::ProxyGate`) every request needs the token, this machine's too, and one that came through the proxy also the configured identity header for the owner ([configuration.md](configuration.md#behind-an-auth-proxy)). A request goes through, in order: the Host check (`local_host_header?`: loopback names, the LAN address, the public host), the cross-site check (`cross_site?`: Origin this server's or the public origin, no `Sec-Fetch-Site` cross-site/same-site on a POST or `/api`), the frame check (`framed?`: a frame/embed/object load from another origin, 403 `framed`; every HTML answer carries `X-Frame-Options: DENY` and `frame-ancestors 'none'`), the token gate (`token_gate` → `principal_for`, `proxied_principal` for a proxied request; the `?token=` / `POST /api/token` trade sets the cookie, `__Host-chi_token` through the proxy; with `web.public_url` a direct request takes Bearer only, and chi's token-less `/api/info` probe gets `probe_info`), then the route's permission (`Principal#permits?`). It talks to each worker's Bridge (`App#relay`, `bridge_get`; `/stream` proxies it) and reads the session files; no `Engine` of its own. Markdown (`web.markdown`) is rendered here only (`Web::MarkdownRenderer`): the answers it serves, card bodies, and `POST /api/render` for a text the page already shows. `App` keeps the gate, `ROUTES` and the helpers the handlers share; its handlers live in mixins it includes, each a `Web::` module with private methods: `SessionAccessRoutes` (`web/session_access_routes.rb`), `ParticipantAccess` (`web/participant_access.rb`), `ParticipantsAdmin` (`web/participants_admin.rb`), `ParticipantReview` (`web/participant_review.rb`), `MessageDisplay` (`web/message_display.rb`), `SessionShow` (`web/session_show.rb`), `SessionCreate` (`web/session_create.rb`), `SessionControl` (`web/session_control.rb`), `PushRoutes` (`web/push_routes.rb`) and `ProxyGate` (`web/proxy_gate.rb`). Exact paths in `GATE_FREE_PATHS` are served before the token gate (the fragment trade's script, and the Home Screen app's manifest, service worker and icons). `bin/chi web` entrypoint. |
|
|
157
157
|
| Sessions | `Samagotchi::Session`, `SessionManager` | File-based `~/.local/state/samagotchi/sessions/<uuid>.json` + sidecar `input/`/`output/`; retention (14d/500) + ordering (`updated_at desc`). |
|
|
158
158
|
|
|
@@ -390,8 +390,27 @@ process that already owns the `Engine`); every worker starts it, and it exposes:
|
|
|
390
390
|
worker only through `chi web`. A request carrying any trace a proxy adds (`ProxyTrace`: `X-Forwarded-*`,
|
|
391
391
|
`Forwarded`, `X-Real-IP`, `X-Auth-Request-*`, `Cf-*`…, underscore twins too) is `403 proxied`
|
|
392
392
|
(`Bridge#proxied_request?`): an auth proxy that forwards every local port and adds such a header doesn't reach a
|
|
393
|
-
worker.
|
|
394
|
-
|
|
393
|
+
worker.
|
|
394
|
+
- **The secret.** Every request, on every route (the stream, the reads such as `state` and `stats`, the writes, and
|
|
395
|
+
an unknown path), names the Bridge's secret in `X-Chi-Bridge`; one without it, or with another one, is
|
|
396
|
+
`403 bridge_secret` with one message (`BridgeSecret::REFUSED`: restart chi web, re-attach terminals and restart
|
|
397
|
+
older session workers), after the browser and proxy checks and before any route (`Bridge#secret_ok?`,
|
|
398
|
+
`OpenSSL.secure_compare`). No route is left open: what the reads show is the session itself. Only a request that
|
|
399
|
+
got past it counts as client activity, so a refused one (an older chi web's polls) never holds the idle exit. Each Bridge makes its own (`SecureRandom.hex(32)`, 64 hex
|
|
400
|
+
characters) when it starts and writes it to `bridge.json`, which is 0600 from the moment it exists
|
|
401
|
+
(`AtomicFile` creates the temporary file with that mode, then renames it), so only this machine's user can read
|
|
402
|
+
it: a forward that adds no proxy header, or another local account, reaches the port but not a session. Clients get
|
|
403
|
+
it only from the sidecar: `BridgeClient.discover`/`.wait_for`/`.for_sidecar` take the port and the secret from the
|
|
404
|
+
same read (chi web makes its client from the sidecar for every request, the attached terminal again on a
|
|
405
|
+
`worker_changed`), so a respawned worker's new one is used and nothing passes a port by hand. A worker from before
|
|
406
|
+
the secret writes none and asks for none; a chi web or attached terminal from before it sends none, so a worker
|
|
407
|
+
the newer chi started refuses it until it is restarted. A client tells that refusal from a route's own 403
|
|
408
|
+
(`BridgeClient::Response#secret_refused?`) and shows the one message: chi web's relays answer 502 `bridge_secret`,
|
|
409
|
+
`chi answer` and a parent's approval relay say it instead of "refused", and an event stream ends with reason
|
|
410
|
+
`bridge_secret` once rediscovery finds no newer worker (the attached terminal's closing line), never retrying in
|
|
411
|
+
silence; chi web's stream proxy passes no refusal on as frames. The secret is never logged (a refusal logs
|
|
412
|
+
`secret_refused` with the path, at most once a minute), never in an event, a reply, `/api/info` or a session
|
|
413
|
+
file, and `WorkerSidecar`, `BridgeClient` and `Bridge` leave it out of `#inspect`.
|
|
395
414
|
|
|
396
415
|
The metrics in `/state`, `/snapshot`, `/stats` and the SSE `snapshot`/`reset` frames
|
|
397
416
|
(`SessionMetrics#snapshot`) carry the session's totals and only the recent timing records: the
|
|
@@ -472,7 +491,7 @@ Every route goes through `Bridge#dispatch`: an id other than the bridge's own se
|
|
|
472
491
|
`handler_failed`) rather than dropping the connection.
|
|
473
492
|
|
|
474
493
|
The per-session port is OS-assigned (bound to `0`) and published to a `bridge.json` sidecar
|
|
475
|
-
for client discovery. `chi web`'s `GET /api/sessions/:id/stream` proxies this bridge
|
|
494
|
+
for client discovery, with the Bridge's secret (see above). `chi web`'s `GET /api/sessions/:id/stream` proxies this bridge
|
|
476
495
|
(503 `not_live` when the worker is not running; full history of any session is served by
|
|
477
496
|
`GET /api/sessions/:id/output`), as a byte pipe for the owner: `App#proxy_stream_body` gives `ProxyStreamBody` the
|
|
478
497
|
request's frame filter (`App#stream_filter`: nil for the owner; for a participant, and the owner's participant view
|
|
@@ -493,7 +512,18 @@ in RubyGems' specification dirs, or a checkout's `version.rb` on disk; looked at
|
|
|
493
512
|
probe, every 10 s), and a change is a `chi` frame `{version, installed}`. A newer one than the
|
|
494
513
|
server runs is said in chi web's terminal and on the page: restart chi web (its workers already
|
|
495
514
|
run the newest chi, [Sessions](sessions.md)). `GET /api/info` carries `installed` too, and the
|
|
496
|
-
feature `newest_workers
|
|
515
|
+
feature `newest_workers`; next to `cwd` (the folder chi web runs in) it names `start_dir`, the folder it
|
|
516
|
+
starts in (`web.start_dir`, `--start-dir`; `Web::StartDir`), which a second `chi web` given another one
|
|
517
|
+
mentions.
|
|
518
|
+
|
|
519
|
+
The page's scope is in its URL, and the server picks the default: `?dir=<folder>` is that folder's
|
|
520
|
+
project (the list, the events stream and a new chat follow it), `?scope=all` every session, and a bare
|
|
521
|
+
`/` the start folder's project when that folder is in a repo (`App#index_data_attributes` writes
|
|
522
|
+
`data-scope-dir`, which the page reads when the URL has no `?dir`), else every session. The page never
|
|
523
|
+
redirects, so the `?token=` trade's 303, a link code's `#code=` and the Home Screen app's `start_url` `/`
|
|
524
|
+
all land on the start project; a push opens its session's own project (`/?dir=<root>#/s/<id>`, or
|
|
525
|
+
`/?scope=all#/s/<id>` outside a repo). `?dir=` beats `?scope=all`. A session created
|
|
526
|
+
without a folder starts in the start folder.
|
|
497
527
|
Files stay the source of truth and workers don't know the hub. Its watcher is a 1 s tick that
|
|
498
528
|
stats the sessions dir (every session writer goes tmp + rename, which bumps the dir's mtime) and
|
|
499
529
|
each `<id>/` folder (recap.json, bridge.json, the stopped and archived markers), re-parsing only the files whose mtime or size
|
data/docs/cli.md
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
- `chi scratch [options]` — a one-time session in the plain in-process REPL, in this folder, that leaves nothing behind (see [Scratch sessions](#scratch-sessions))
|
|
12
12
|
- `chi --attach <session-id>` — attach the terminal to a session's worker (e.g. one started from the Web UI), waking one if it has exited
|
|
13
13
|
- A session id can be shortened to any unique prefix (like git): `chi --attach 2ea8`. `--resume`, `--attach`, `sessions stop`, `sessions archive` and `sessions delete` take one; an ambiguous prefix lists the sessions it matches.
|
|
14
|
-
- `chi web [--port 4567] [--open] [--scope=all]` — start the Web UI (single localhost port session control plane) on this git project's sessions (`--scope=all`, or a folder in no repo: every session); if a chi web already runs on the port, print (with `--open`, open) its page for this folder and exit. Something else on the port (an older chi web too) exits 1 with "port N is in use"
|
|
14
|
+
- `chi web [--port 4567] [--open] [--scope=all] [--start-dir DIR]` — start the Web UI (single localhost port session control plane) on this git project's sessions (`--scope=all`, or a folder in no repo: `/?scope=all`, every session); if a chi web already runs on the port, print (with `--open`, open) its page for this folder and exit. Something else on the port (an older chi web too) exits 1 with "port N is in use"
|
|
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
|
+
- `chi web --start-dir DIR` (config `web.start_dir`) — the folder chi web starts in, in place of the one you run it in (`~` and a relative path work; chi web never changes its own folder): its page opens on that folder's project (the printed link, a bare `/`, the LAN link and its QR code, the Home Screen app), and a new session from the all view starts there; `/?scope=all` (the header's `all`) is every project. One that isn't a folder exits 1; `--start-dir` without `web` exits 2. A chi web already running in another folder keeps it (the second one says so: restart it to change it)
|
|
16
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
|
|
17
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
|
|
18
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
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
- `chi answer ID --question QID (--option N|LABEL)... [--text T] [--timeout S] [--format json]` (or `--dismiss`) — answer the question a session waits on (the one `chi send --wait` exited 3 with), then wait and print what comes next as `chi send --wait` does: the reply (0), the next question (3), still running after `--timeout` (4). `--option` is 1-based or the label, repeated on a multi-select question; `--text` is free text, or a Deny's reason; `--dismiss` leaves it unanswered and the model finishes its reply. A question no longer open (the web answered first) isn't answered again: it waits for that turn's reply. An option the question doesn't offer exits 2; a worker that is gone exits 1 (`send the task again: chi send --wait -m "…" ID`). What a parent may pick follows `guardrails.parent_answers`, or the session's own `parent_answers` when stricter (`soft`, the default: a deny, a plain answer, Continue and "Allow once"; `standard`: no allow; `hard`: no Continue either), never a wider scope or an allow on chi's own config; a refused pick exits 1 with what to answer instead (a convention, not a security boundary; see [Guardrails](guardrails.md#answers-from-a-parent-agent))
|
|
27
28
|
- `chi remote add NAME URL [--token-file F | --token-stdin]`, `chi remote ls`, `chi remote rm NAME` — the other machines whose chi web the session commands reach with `--remote NAME` (see [Remote sessions](#remote-sessions))
|
|
28
29
|
- `chi review FILE… [--dir DIR] [--model M]`, `chi review --from ID [FILE…]` — start a review session to invite participants to: for files of a project, or as a review of a working session that starts from its recap, not its transcript (see [Review sessions](#review-sessions))
|
|
29
|
-
- `chi share ID --name NAME [--agent] [--expires 3d] [--cap 2]`, `chi share ls [ID]`, `chi share cap ID P DOLLARS`, `chi share revoke ID [P] | --all` — invite a participant to review a session through chi web on the LAN (a link of their own, 7 days, a $2 spending cap), list them, change one's cap, revoke them (see [Participants](#participants))
|
|
30
|
+
- `chi share ID --name NAME [--identity EMAIL] [--agent] [--expires 3d] [--cap 2]`, `chi share ls [ID]`, `chi share cap ID P DOLLARS`, `chi share revoke ID [P] | --all` — invite a participant to review a session through chi web on the LAN (a link of their own, 7 days, a $2 spending cap), list them, change one's cap, revoke them (see [Participants](#participants))
|
|
30
31
|
- `chi --remote NAME send|answer|note|context|sessions|share|review …` (or `CHI_REMOTE=NAME`) — those commands on that machine's sessions, through its chi web (see [Remote sessions](#remote-sessions))
|
|
31
32
|
- `chi --remote NAME --attach ID` (`--resume ID`, `--dir DIR [-p TEXT]`) — the attached TUI on a session of that machine (see [Remote sessions](#remote-sessions))
|
|
32
33
|
- `chi memory ls [--scope project|system] [--format text|json]` — the memories of both scopes (this folder's project first), one row each: scope, name, size, date, `from <bundle>`, the index description and its model overlays; `chi memory rm NAME [--scope project|system]` removes one as `memory_write` with `remove: true` does: its file and model overlays go to the bundle trash (the line names the dir; `chi bundle trash` lists and empties it) and its index line is dropped. NAME in both scopes without `--scope` exits 2 naming both; a missing NAME or a bundle's memory (`chi bundle uninstall` removes it) exits 1 (see [Memory: Listing and removing from the shell](memory.md#listing-and-removing-from-the-shell))
|
|
@@ -238,7 +239,12 @@ done
|
|
|
238
239
|
hands over to the new chi, which does the rest and prints the table. Old
|
|
239
240
|
versions stay installed: running workers and an old `chi web` still load
|
|
240
241
|
files from them, so a `gem cleanup` while they run breaks them (a
|
|
241
|
-
`LoadError`, missing web assets); restart them first.
|
|
242
|
+
`LoadError`, missing web assets); restart them first. A chi web, an
|
|
243
|
+
attached terminal or a session worker started before the update may not
|
|
244
|
+
reach a worker the new chi starts (403 `bridge_secret`: its Bridge asks for
|
|
245
|
+
a secret they don't send; an older worker's delegate child is one): restart
|
|
246
|
+
chi web, re-attach, and restart the older workers (`chi sessions restart
|
|
247
|
+
ID...`, as the `workers` row says). Offline, the row says
|
|
242
248
|
"couldn't check" and the rest still runs; a failed install fails the row
|
|
243
249
|
and the rest runs on the current version. Under Bundler (`bundle exec`)
|
|
244
250
|
the row says `bundle update samagotchi` instead.
|
|
@@ -1164,6 +1170,12 @@ On a touch screen (a phone, a tablet) the bar sits just above the composer
|
|
|
1164
1170
|
instead of next to the selection, where the system's own Copy menu and the
|
|
1165
1171
|
selection handles would cover it; several pills wrap to a second row.
|
|
1166
1172
|
|
|
1173
|
+
A review's participants get the same on their page (a `chi share` / `chi
|
|
1174
|
+
review` link): selecting text in the Plan or the thread quotes it into
|
|
1175
|
+
their comment box, labelled `From docs/plan.md:` or `From Sam's comment:`,
|
|
1176
|
+
with the same presets. Not in the owner's participant view, and no plugin
|
|
1177
|
+
pills there (a review turn refuses `/` lines).
|
|
1178
|
+
|
|
1167
1179
|
The list is `web.annotate_presets`, `|`-separated (at most five; a preset
|
|
1168
1180
|
can't contain `|`; a YAML list works too):
|
|
1169
1181
|
|
|
@@ -1200,7 +1212,10 @@ Plain http: the link and your traffic can be read by anyone on this Wi-Fi.
|
|
|
1200
1212
|
|
|
1201
1213
|
Scan the QR code with the phone's camera. The page trades the token in the
|
|
1202
1214
|
link for a cookie (kept 400 days) and drops it from the address, so a
|
|
1203
|
-
bookmark or a home-screen icon keeps working across restarts.
|
|
1215
|
+
bookmark or a home-screen icon keeps working across restarts. It opens on
|
|
1216
|
+
the project chi web starts in (`--start-dir DIR` or `web.start_dir` picks
|
|
1217
|
+
another; outside a repo it shows every session); the header's `all` shows
|
|
1218
|
+
every project's. A home-screen
|
|
1204
1219
|
web app on iOS has cookies of its own: if it opens on "needs chi web's
|
|
1205
1220
|
access token", paste the token there (the part of the link after
|
|
1206
1221
|
`token=`), or open the link once in it.
|
|
@@ -1336,6 +1351,36 @@ chi --remote studio --dir /Users/me/app -p "hi" # a new session there (--
|
|
|
1336
1351
|
has installed (`chi --remote studio sessions restart ab12`), this terminal
|
|
1337
1352
|
older than studio (`chi update` here).
|
|
1338
1353
|
|
|
1354
|
+
#### Through an SSH tunnel
|
|
1355
|
+
|
|
1356
|
+
When that machine's chi web is only reachable over SSH — behind a sign-in proxy
|
|
1357
|
+
(`chi --remote` through one isn't supported yet), or bound to 127.0.0.1 —
|
|
1358
|
+
forward its port and add it as a remote like any other:
|
|
1359
|
+
|
|
1360
|
+
```sh
|
|
1361
|
+
ssh -N -L 14567:127.0.0.1:4567 studio # the host's web.port, 4567 by default
|
|
1362
|
+
chi remote add work http://127.0.0.1:14567 --token-file work-token
|
|
1363
|
+
# work-token: the host's $XDG_STATE_HOME/samagotchi/web-token
|
|
1364
|
+
chi --remote work sessions list
|
|
1365
|
+
```
|
|
1366
|
+
|
|
1367
|
+
- Pick a local port other than 14567 when this machine runs its own chi web.
|
|
1368
|
+
- Forward only chi web's port, never a worker's: a session's Bridge answers
|
|
1369
|
+
only chi's own clients on its machine (they read its secret from the
|
|
1370
|
+
session's folder), so a forwarded worker port is of no use.
|
|
1371
|
+
- Without `web.public_url` there, a request that arrives through the tunnel
|
|
1372
|
+
looks local and needs no token, so any process here reaching the forwarded
|
|
1373
|
+
port acts as you there. With it set, every request needs the token, which
|
|
1374
|
+
`chi --remote` sends as Bearer.
|
|
1375
|
+
- `-L` binds 127.0.0.1 unless you write `-g` or `0.0.0.0:`: don't.
|
|
1376
|
+
- Attaching works through the tunnel too (`chi --remote work --attach ab12`),
|
|
1377
|
+
plain http, no proxy.
|
|
1378
|
+
|
|
1379
|
+
SSH can forward a Unix socket as well, which is how claude-peer's pairing makes
|
|
1380
|
+
a Claude session on this laptop reachable from chi on that machine
|
|
1381
|
+
(`pair --inbox-socket <path>`): see [plugins.md](plugins.md), "chi on another
|
|
1382
|
+
machine".
|
|
1383
|
+
|
|
1339
1384
|
How it works inside (`SessionAccess`, chi web's routes, where each check runs):
|
|
1340
1385
|
[internals/remote-sessions.md](internals/remote-sessions.md).
|
|
1341
1386
|
|
|
@@ -1374,8 +1419,9 @@ chi share revoke --all # every link to every session
|
|
|
1374
1419
|
- **The participant page.** Their link opens a page of its own (never yours): the session's title and status, who
|
|
1375
1420
|
else takes part, and the conversation as a participant sees it: every prompt and reply with who wrote it, each
|
|
1376
1421
|
step's tools as one line (`read docs/plan.md`: the tool and a project file's path, never arguments or output), and
|
|
1377
|
-
the reply streaming in while a turn runs. A "Comment or ask" box sends their comment
|
|
1378
|
-
|
|
1422
|
+
the reply streaming in while a turn runs. A "Comment or ask" box sends their comment (your composer's box, with its
|
|
1423
|
+
grip to resize or fold it and ↑/↓ over their own earlier comments from that browser; no `/` list, no images yet);
|
|
1424
|
+
their queued comments show with **Take back**; "waiting for the owner" shows while you answer a question or an approval of the turn; a refused
|
|
1379
1425
|
comment (a `!` or `/` line, too many waiting, their cap reached) says why. On a phone it is the thread first with
|
|
1380
1426
|
the box pinned, tool lines folded. They never see tool output or arguments, thinking, approvals or questions,
|
|
1381
1427
|
memories, context notes, plugin and delegate input, cards, command output, the working set, cost, timing or host
|
|
@@ -1404,6 +1450,14 @@ chi share revoke --all # every link to every session
|
|
|
1404
1450
|
`https://<public url>/#code=…`; with `chi web --tunnel tailscale` too (its `ts.net` name, which web.json records
|
|
1405
1451
|
while that chi web answers on its port: a chi web on another port takes web.json over, and the link falls back to
|
|
1406
1452
|
127.0.0.1). A tunnel link opens only on a device on your tailnet; the grant still decides.
|
|
1453
|
+
- **A link for one account.** Behind an auth proxy that names the signed-in user (`web.public_url` with
|
|
1454
|
+
`web.proxy.identity_header`, or `chi web --tunnel tailscale`), `--identity EMAIL` binds the link to that account:
|
|
1455
|
+
it opens only through the proxy, signed in as EMAIL. A forwarded link opened by anyone else says "This review link
|
|
1456
|
+
is for another account …", and its one-time code still works for EMAIL. `chi share` says `· bound to EMAIL`, `chi
|
|
1457
|
+
share ls` `alex@corp · bound`, and the panel's Invite has an email field there. Without such a proxy `--identity`
|
|
1458
|
+
is refused (the link could never open); with one, an unbound invite gets a warning line. Through `chi --remote`
|
|
1459
|
+
it needs that chi web to have bound links (this version or newer), else it is refused before anything is issued.
|
|
1460
|
+
See [configuration.md](configuration.md#inviting-colleagues).
|
|
1407
1461
|
- The owner's own token and the `chi web --new-token` rotation are separate: rotating it ends no participant's link.
|
|
1408
1462
|
- **In the attached terminal.** A participant's message reads `Alex ▸ review> is step 3 right?`, the name in that
|
|
1409
1463
|
participant's own colour (queued, running, and the last exchange when you join); yours stay as they were. A line
|
data/docs/configuration.md
CHANGED
|
@@ -1608,7 +1608,11 @@ web:
|
|
|
1608
1608
|
|
|
1609
1609
|
Experimental. `chi web` binds 127.0.0.1 only; to use it from elsewhere over https, put it behind a proxy that does TLS
|
|
1610
1610
|
and, usually, a sign-in (oauth2-proxy, nginx `auth_request`, Caddy `forward_auth`, Cloudflare Access, Tailscale
|
|
1611
|
-
Serve; a work pod forwarding `https://<port>.<pod>.<domain>` through oauth2-proxy) and tell chi web its public URL
|
|
1611
|
+
Serve; a work pod forwarding `https://<port>.<pod>.<domain>` through oauth2-proxy) and tell chi web its public URL.
|
|
1612
|
+
The proxy must run **on the same machine** as chi web: only a request from a loopback peer (127.0.0.0/8, ::1) counts
|
|
1613
|
+
as one through the proxy, with its identity header. A proxy on another host, reaching chi web on its LAN address
|
|
1614
|
+
(`web.host: lan`), isn't supported: its requests are LAN requests (the LAN token; a link bound to an account refused),
|
|
1615
|
+
since any LAN device could send the same headers.
|
|
1612
1616
|
|
|
1613
1617
|
```yaml
|
|
1614
1618
|
web:
|
|
@@ -1649,20 +1653,20 @@ What changes once `web.public_url` is set:
|
|
|
1649
1653
|
to the proxy, but it outlives the sign-in's redirects: the sign-in page sits at that URL (its scripts can read it)
|
|
1650
1654
|
and it stays in the browser's history, which is why it holds a code that works once. The page trades the code for
|
|
1651
1655
|
the cookie (`POST /api/token`) and drops it from the URL; a page that already has a session asks first, since the
|
|
1652
|
-
trade replaces it.
|
|
1653
|
-
a link can spend it (`chi web` again, or a new invite, makes another)
|
|
1656
|
+
trade replaces it. An owner's code (or an unbound participant's) presented with the wrong identity is used up and
|
|
1657
|
+
gives nothing, so whoever already holds a link can spend it (`chi web` again, or a new invite, makes another); a
|
|
1658
|
+
link bound to one account ([Inviting colleagues](#inviting-colleagues)) is refused to anyone else and keeps its code. The 401 page's paste box posts the token in
|
|
1654
1659
|
the request's body, never in the URL.
|
|
1655
1660
|
- When the proxy's sign-in or chi's token ends, the page says so: it reloads once (the proxy's sign-in brings you
|
|
1656
1661
|
back), and within a minute of that shows "Signed out … Reload" instead of a list that quietly stopped updating. Its
|
|
1657
1662
|
API calls ask for JSON, so oauth2-proxy answers an ended sign-in with 401 instead of a redirect.
|
|
1658
|
-
- A session's Bridge (its worker's own port
|
|
1659
|
-
|
|
1660
|
-
|
|
1663
|
+
- A session's Bridge (its worker's own port) answers only a request that names its secret, which only chi's own
|
|
1664
|
+
clients on this machine read (from the worker's 0600 `bridge.json`): a proxy or tunnel that forwards every local
|
|
1665
|
+
port reaches the port but gets 403. It also refuses a request that carries a proxy header such as
|
|
1666
|
+
`X-Forwarded-For` or `Forwarded` (403 `proxied`).
|
|
1661
1667
|
- `chi --remote` to a chi web behind a sign-in proxy isn't supported yet.
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
> reach any local port, such as a pod forwarding every `https://<port>.<pod>…`, unless it adds `X-Forwarded-For` or
|
|
1665
|
-
> `Forwarded` to every request; and never one that also lets other people through its sign-in.
|
|
1668
|
+
SSH to that machine works instead: forward its port and add it as a remote
|
|
1669
|
+
([Through an SSH tunnel](cli.md#through-an-ssh-tunnel)).
|
|
1666
1670
|
|
|
1667
1671
|
Which header to trust: only one the proxy **sets** on every signed-in request **and replaces** when a client sends
|
|
1668
1672
|
it. Check before setting `identity_header`: run an echo on a free port behind the same proxy (`python3 -c` with
|
|
@@ -1683,6 +1687,33 @@ one.
|
|
|
1683
1687
|
|
|
1684
1688
|
Keep the state dir (`web-token`, the grants) out of any folder others can read, such as a team's shared folder.
|
|
1685
1689
|
|
|
1690
|
+
### Inviting colleagues
|
|
1691
|
+
|
|
1692
|
+
Behind a proxy whose sign-in lets colleagues in (a work pod behind Okta and oauth2-proxy, a tailnet you share), give
|
|
1693
|
+
each reviewer a link bound to their account:
|
|
1694
|
+
|
|
1695
|
+
```sh
|
|
1696
|
+
chi share 3f9a1c2e --name Alex --identity alex@corp.example
|
|
1697
|
+
# p_7c01d2aa Alex (human, reviewer) · session 3f9a1c2e · expires … · cap $2.00 · bound to alex@corp.example
|
|
1698
|
+
# https://4567.pod.example.com/#code=chc_…&s=3f9a1c2e-…
|
|
1699
|
+
```
|
|
1700
|
+
|
|
1701
|
+
- It needs `web.proxy.identity_header` (or `chi web --tunnel tailscale`): the link opens only through the proxy,
|
|
1702
|
+
signed in as that email (any case). Opened by someone else (forwarded, pasted in the wrong chat), on the LAN or on
|
|
1703
|
+
this machine, it says "This review link is for another account …", and its one-time code stays: Alex can still open
|
|
1704
|
+
it. The refusal is in the session's participants audit with the identity that tried. Without an identity header
|
|
1705
|
+
`--identity` is refused: the link could never open.
|
|
1706
|
+
- Run only chi 0.109 or newer on the same state dir: an older chi rewriting the grants store drops the binding and
|
|
1707
|
+
makes every bound link open for anyone the proxy lets in.
|
|
1708
|
+
- An unbound link there opens for anyone the proxy lets in who has it; `chi share` warns when you make one. The web's
|
|
1709
|
+
Invite has an email field behind such a proxy (the name defaults to the email's first part).
|
|
1710
|
+
- The identity is what the trusted header carries: the work email through Okta, the Tailscale login (`alex@github`)
|
|
1711
|
+
through Tailscale Serve. Bind to the one your proxy sends. A tagged Tailscale device has no user login, so a bound
|
|
1712
|
+
link refuses it.
|
|
1713
|
+
- The header is the proxy's word only for requests from this machine (the proxy is local; a LAN device's copy is
|
|
1714
|
+
ignored): any program on this machine that reaches chi web's port directly can send it too. On a machine or pod only you use, that is you already; on a host
|
|
1715
|
+
other users share, a bound link's identity isn't a boundary against them.
|
|
1716
|
+
|
|
1686
1717
|
### Tailscale Serve (your tailnet)
|
|
1687
1718
|
|
|
1688
1719
|
chi web on your phone away from the home Wi-Fi: [Tailscale](https://tailscale.com) Serve gives this Mac an https
|
|
@@ -1796,6 +1827,9 @@ What it needs:
|
|
|
1796
1827
|
|
|
1797
1828
|
Turning it on, on the phone: open the `Proxied:` link in Safari → Share → **Add to Home Screen** → open the **Chi**
|
|
1798
1829
|
app → tap the **bell** at the top → turn on **This device** in the sheet → Allow. A test notification arrives at once.
|
|
1830
|
+
The app opens on the project chi web starts in (`web.start_dir`; the header's `all` shows every project), but its
|
|
1831
|
+
notifications are every project's: opening it closes the ones whose question or card is no longer open and sets its
|
|
1832
|
+
badge for every project, whichever project the page shows.
|
|
1799
1833
|
In a browser tab the bell stays the tab's own notifications (while the tab is in the background), as before.
|
|
1800
1834
|
|
|
1801
1835
|
**The devices** (the bell's sheet in the app; a bottom sheet on the phone): this device first, with its switch (off
|
|
@@ -1807,6 +1841,8 @@ are never sent to; `chi web push rm ID` removes them. From the Mac: `chi web pus
|
|
|
1807
1841
|
shows a recent delivery (Apple keeps accepting pushes for it): if one stops getting notifications, switch it off and on
|
|
1808
1842
|
there; the new subscription replaces the dead one.
|
|
1809
1843
|
|
|
1844
|
+
- **What a tap opens**: the session, in its own project's view (the all view for a session in no repo), whichever
|
|
1845
|
+
project the app was showing; an open app window moves there.
|
|
1810
1846
|
- **What is sent**: the session's name and the reason ("needs approval", "needs an answer", "hit its step limit",
|
|
1811
1847
|
"needs you", "turn failed", "done in N s"), never the question or the command, as the tab's notification on the
|
|
1812
1848
|
Mac. The session's name shows on the lock screen and the Watch.
|
|
@@ -1968,6 +2004,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
1968
2004
|
| `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). |
|
|
1969
2005
|
| `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). |
|
|
1970
2006
|
| `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). |
|
|
2007
|
+
| `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; `/?scope=all` is every project. `~` and a relative path work; one that isn't a folder stops `chi web` from starting. `chi web` never changes its own folder. See [CLI](cli.md). |
|
|
1971
2008
|
| `web.participants.expires` | `7d` | | How long a participant's link lasts unless `chi share --expires` says otherwise: `Nh` or `Nd`, 1h to 30d. See [participants](internals/participants.md). |
|
|
1972
2009
|
| `web.participants.cap` | `2.0` | | What a participant's turns, and the side calls they cause, may cost you in dollars unless `chi share --cap` says otherwise ($0 to $1000); at the cap their next comment is refused (429 `cap_reached`) and you get a notice. `chi share cap ID P DOLLARS` changes one grant's. |
|
|
1973
2010
|
| `web.participants.queue` | `3` | | How many of a participant's turns may wait behind their running one (0 to 20); one more is refused (429 `too_many_turns`). |
|