samagotchi 0.24.0 → 0.26.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -1
  3. data/docs/architecture.md +16 -9
  4. data/docs/cli.md +4 -3
  5. data/docs/configuration.md +22 -13
  6. data/docs/hooks.md +1 -1
  7. data/docs/internals/background-tasks.md +1 -0
  8. data/docs/internals/engine.md +478 -0
  9. data/docs/internals/prompt-caching.md +120 -0
  10. data/docs/plugins.md +18 -3
  11. data/docs/testing.md +12 -0
  12. data/lib/samagotchi/bundles/loop-guard/manifest.yml +2 -2
  13. data/lib/samagotchi/bundles/loop-guard/plugin.rb +59 -11
  14. data/lib/samagotchi/bundles/system/manifest.yml +1 -1
  15. data/lib/samagotchi/cancellation_controller.rb +8 -0
  16. data/lib/samagotchi/client.rb +53 -3
  17. data/lib/samagotchi/command_steps.rb +233 -0
  18. data/lib/samagotchi/config.rb +14 -4
  19. data/lib/samagotchi/empty_answer_retry.rb +2 -2
  20. data/lib/samagotchi/engine.rb +73 -11
  21. data/lib/samagotchi/guardrails/shell_lex.rb +49 -5
  22. data/lib/samagotchi/idle_client.rb +14 -2
  23. data/lib/samagotchi/kernel_loop.rb +60 -6
  24. data/lib/samagotchi/llm/chat_loop.rb +18 -4
  25. data/lib/samagotchi/llm/errors.rb +26 -1
  26. data/lib/samagotchi/llm/http.rb +5 -4
  27. data/lib/samagotchi/llm/openai_chat.rb +5 -4
  28. data/lib/samagotchi/llm/prompt_cache.rb +34 -9
  29. data/lib/samagotchi/llm/usage.rb +18 -3
  30. data/lib/samagotchi/log_subscriber.rb +2 -1
  31. data/lib/samagotchi/plugin/api.rb +3 -2
  32. data/lib/samagotchi/prompt_warmup.rb +95 -0
  33. data/lib/samagotchi/session_metrics.rb +38 -4
  34. data/lib/samagotchi/system_prompt.rb +30 -9
  35. data/lib/samagotchi/terminal_ui/attached_loop.rb +5 -2
  36. data/lib/samagotchi/terminal_ui/attached_view.rb +6 -2
  37. data/lib/samagotchi/terminal_ui/event_renderer.rb +14 -2
  38. data/lib/samagotchi/terminal_ui/formatting.rb +31 -9
  39. data/lib/samagotchi/terminal_ui.rb +2 -0
  40. data/lib/samagotchi/thinking_tails.rb +104 -0
  41. data/lib/samagotchi/token_usage.rb +18 -6
  42. data/lib/samagotchi/tool_activity.rb +37 -3
  43. data/lib/samagotchi/tool_declarations.rb +14 -0
  44. data/lib/samagotchi/tool_view.rb +40 -4
  45. data/lib/samagotchi/tools/builtins.rb +4 -1
  46. data/lib/samagotchi/tools/execute.rb +2 -1
  47. data/lib/samagotchi/tools/registry.rb +11 -4
  48. data/lib/samagotchi/tools/shell.rb +32 -0
  49. data/lib/samagotchi/tools/task_runtime.rb +3 -3
  50. data/lib/samagotchi/turn_note.rb +26 -2
  51. data/lib/samagotchi/turn_state.rb +6 -0
  52. data/lib/samagotchi/turn_tally.rb +17 -6
  53. data/lib/samagotchi/version.rb +1 -1
  54. data/lib/samagotchi/web/public/command_view.js +74 -3
  55. data/lib/samagotchi/web/public/format.js +11 -1
  56. data/lib/samagotchi/web/public/index.html +45 -13
  57. data/lib/samagotchi/web/public/stage_model.js +5 -1
  58. data/lib/samagotchi/web/public/stage_view.js +1 -1
  59. data/lib/samagotchi/web/public/turn_view.js +3 -3
  60. data/lib/samagotchi/worker.rb +3 -0
  61. metadata +7 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d6348260d3f666ffbfc0b8c3f10a51a2c64c3a30ce9cbd5a5c1280fa0325306
4
- data.tar.gz: 0cad64155e27a000a49c82e89778d69804fc609526418c1e03846a32d2fb864c
3
+ metadata.gz: d9914119c74e2e2233fcd5931386afca4fbc95b84aa7603e2f4f14289651a12c
4
+ data.tar.gz: 5ba92c2703f202dffe2d4125eac11fd9d93c970a032cc56af1ce41c0827ab5ba
5
5
  SHA512:
6
- metadata.gz: b9a1f022f8a225c517e3160d0d512fbb5a97750c32a6df7769bbcb91ddff5534c5b12f540c4ef80871d8e4f2f80d460c71cd56107476435a69d54cef0ef78395
7
- data.tar.gz: 419a527ffca2330de67b42544f619db872c06388ded821d3bc5e7f17f07a488a7adf96ce56d55032a53c4bc21e6076d32af398c0b8aff15c48e651e6596e7873
6
+ metadata.gz: 881df5c769cb4d5ca994253bf7cccfbbd29d033f51e9f73533cf74926d8d6fe155c8e0e92a7a6226b770dceb4e4a816b1d78dd0ff0b1502938a6e8761a26c8d3
7
+ data.tar.gz: 0a6c687f219568001c688d385221b239a2f285c66f17895c2202bf77098c40236a42cd3ca6b824b493260acb698bf6345e715ecaaa8e53ce6368e938c0bb155f
data/CHANGELOG.md CHANGED
@@ -8,6 +8,83 @@ and commands may change between minor versions. How releases are made:
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.26.0] - 2026-10-04
12
+
13
+ ### Added
14
+
15
+ - The web has a light theme: with the system set to light it follows (`prefers-color-scheme`). There is no
16
+ in-page switch yet. Native radios, inputs and scrollbars now follow the theme, so they are dark in dark mode.
17
+ - On a local llama.cpp host, the next turn starts faster: when a turn ends, chi sends the next turn's prompt (up to
18
+ your next message) in the background, so the server has it ready while you read. `cache.warmup: off` turns it
19
+ off; remote and paid hosts never get it.
20
+
21
+ ### Changed
22
+
23
+ - `execute`'s `description` parameter now says it is shown to the user as the step's title and asks for it on
24
+ every call (still optional), so models, Sonnet in particular, now label execute steps.
25
+ - loop-guard (bundle 0.3.4) words a loop its short run or its window found by the different sentences it held,
26
+ `12 different sentences in 48`, instead of `12 sentences ×4`, which read as a cycle of 12.
27
+ - `sampling:` can't set llama.cpp's `id_slot` (pinning a session to a slot made the next turn re-read the whole
28
+ prompt).
29
+
30
+ ### Fixed
31
+
32
+ - `thinking_tails.jsonl` names the plugin that stopped a turn instead of "hook".
33
+
34
+ Update with `chi update` (loop-guard 0.3.4).
35
+
36
+ ## [0.25.0] - 2026-10-04
37
+
38
+ ### Added
39
+
40
+ - The web shows an `execute` command as the steps a person reads: `cd X &&` becomes an "in X" tag, `| head -20` a
41
+ chip, `echo "=== x ==="` a label, a heredoc a collapsed "EOF · N lines" chip; the collapsed row's title is the
42
+ first step `+N`. A `raw` toggle shows the whole command; anything the parser can't read shows as before.
43
+ - `execute` takes an optional `description` ("what the command does, in a few words"), written by the model; it
44
+ becomes the tool row's title in the web and replaces the cut command in the terminal's tool line. Turn it off
45
+ with `execute.description: false`.
46
+ - Every generation logs its prompt-cache counts (`prompt=`, `cached=`, `cache_write=`), and `/stats` shows cache
47
+ writes next to cached tokens.
48
+ - A generation cut mid-thinking (loop-guard, a plugin's stop, a steer) or ended at the provider's output cap keeps
49
+ the last 20k chars of its thinking in the session's folder, `thinking_tails.jsonl`, so an archived session holds
50
+ the loop it was archived for. The model never sees it.
51
+ - Turn records count `cuts` (generations a plugin cut) and `capped` (generations that hit the output cap), and
52
+ `/stats` shows them as "thinking cuts" and "output cap hits": `retries` counts network retries only.
53
+
54
+ ### Changed
55
+
56
+ - On macOS, `execute`, `task_create` and `!cmd` run commands in `/bin/zsh` emulating sh (with bash's `{1..3}`,
57
+ `[[ =~ ]]` groups and echo escapes kept) instead of `/bin/sh`, which is bash 3.2 there and failed on an apostrophe
58
+ in a heredoc inside `"$( )"`: `git commit -m "$(cat <<'EOF' … it's … EOF )"` now works. Linux keeps
59
+ `/bin/sh`; see [background tasks](docs/internals/background-tasks.md).
60
+ - loop-guard's cut notice (bundle 0.3.3) quotes the looping sentence: `thinking repeats itself ("Let me write the
61
+ tool call.", one sentence ×8, 33k chars, 63 s): cut`.
62
+ - The system prompt puts what every session shares first and the per-session lines (model, working directory,
63
+ session) last, and plugin tools come in a fixed order, so a new session reuses the server's prompt cache: on a
64
+ local llama.cpp or Splash server its first answer starts in about 0.5 s instead of 4–6 s, and on Claude via
65
+ OpenRouter a new session reads the shared part from the cache (about 7× cheaper to start).
66
+ - Chat hosts (`api: openai`) are no longer asked for `temperature: 0.0`: chi sends no temperature unless one is
67
+ configured, so each model runs at its provider's default (as native llama.cpp hosts already did). Greedy decoding
68
+ made DeepSeek v4.1-flash loop in its thinking. The idle recap and `/btw` follow suit. Set `sampling: {temperature:
69
+ …}` on a `hosts:` or `models:` entry to pin one; the empty-answer retry still runs at 0.6 unless one is set.
70
+
71
+ ### Fixed
72
+
73
+ - loop-guard (bundle 0.3.3) cuts thinking that loops in a cycle of 7 or 8 short sentences, or with a longer
74
+ sentence ("I'll write the spec file now.") in the cycle: 48 sentences in a row with 12 or fewer different ones are
75
+ a loop. New settings `thinking.window_sentences` (48) and `thinking.window_distinct` (12).
76
+ - A steer row names chi's senders in words: the web's row and trail flash and the terminal's nudged line say
77
+ `parent agent`, `chi send` and `plugin` instead of the raw `parent_agent` / `chi_send` / `plugin_send`.
78
+ - Thinking off on Gemma 4 no longer warns that off wasn't honoured: its empty thought (whitespace alone) is not
79
+ counted as thinking.
80
+ - An OpenRouter 402 whose `metadata.reason` is `weight_exceeds_budget` (the request alone is larger than the
81
+ key's credit budget) fails at once as `request too large for the credit budget on host <name>: …; lower
82
+ max_tokens (default.max_tokens) or raise the key's credit limit`, instead of being retried as credit held by
83
+ in-flight requests. Other 402s are unchanged.
84
+
85
+ Update with `chi update`: loop-guard moves to 0.3.3 (the window rule and the quoted cut notice). Restart `chi web`
86
+ and running sessions afterwards (`chi sessions restart ID`).
87
+
11
88
  ## [0.24.0] - 2026-10-04
12
89
 
13
90
  ### Added
@@ -1342,7 +1419,9 @@ and long-lived sessions.
1342
1419
  - A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
1343
1420
  hotkey panel that send selected text or the clipboard to your sessions.
1344
1421
 
1345
- [Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.24.0...HEAD
1422
+ [Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.26.0...HEAD
1423
+ [0.26.0]: https://github.com/dm1try/samagotchi/compare/v0.25.0...v0.26.0
1424
+ [0.25.0]: https://github.com/dm1try/samagotchi/compare/v0.24.0...v0.25.0
1346
1425
  [0.24.0]: https://github.com/dm1try/samagotchi/compare/v0.23.0...v0.24.0
1347
1426
  [0.23.0]: https://github.com/dm1try/samagotchi/compare/v0.22.0...v0.23.0
1348
1427
  [0.22.0]: https://github.com/dm1try/samagotchi/compare/v0.21.0...v0.22.0
data/docs/architecture.md CHANGED
@@ -184,12 +184,18 @@ engine.system_prompt # fully built system prompt string
184
184
  engine.session # current session (Engine owns create/resume)
185
185
  ```
186
186
 
187
- The system prompt (`SystemPrompt#build`) is the base prompt, then rg guidance,
188
- AGENT.md, the working directory, **the model** (`Model: this session runs on
189
- <ref> (host …; model key …)` and a line telling the model to answer "which model
190
- are you" from it, not from training), the session id and log, the memory indexes,
191
- the identity and the preloaded memories. It is built once per loop and rebuilt only
192
- by a model switch (or changed tools), so the model line costs no KV churn.
187
+ The system prompt (`SystemPrompt#build`) is the base prompt, then rg guidance, the
188
+ identity and the preloaded memories, AGENT.md, the memory indexes, and last **the
189
+ model** (`Model: this session runs on <ref> (host …; model key …)` and a line telling
190
+ the model to answer "which model are you" from it, not from training), the working
191
+ directory and the session id and log (Gemma's native tool declarations still follow).
192
+ The order is for the servers' prompt caches, which reuse only an exact token prefix:
193
+ what every session shares first, what changes least before what changes more, the
194
+ per-session lines last, so a new session reuses everything above them. It is built
195
+ once per loop and rebuilt only by a model switch (or changed tools), so the model
196
+ line costs no KV churn.
197
+ The full request layout, what breaks the cache and the rules for changes:
198
+ [internals/prompt-caching.md](internals/prompt-caching.md).
193
199
 
194
200
  #### Subscribing to the live stream (and the bridge)
195
201
 
@@ -275,11 +281,12 @@ The metrics in `/state`, `/snapshot`, `/stats` and the SSE `snapshot`/`reset` fr
275
281
  newest turn the worker finished and any it hasn't saved yet (at most 20 turns), with their tool
276
282
  calls and the running turn's finished ones. The full history is the session's `analytics.json`,
277
283
  which `SessionMetrics#persist` rewrites after each turn; the web server merges the two by id.
278
- The totals' `tokens` block adds the cached and reasoning sums, the cost, the decode time and tokens
284
+ The totals' `tokens` block adds the cached, cache-write and reasoning sums, the cost, the decode time and tokens
279
285
  behind the average speed (`avg_decode_tps`) and the last speeds (`last_decode_tps`,
280
286
  `last_prefill_tps`, `tps_source`: `server` or `estimate`). Each `generation_completed` event
281
- carries the generation's `speed` (`{decode_tps, source}`, null without one) and those running
282
- `tokens`: the Engine closes the generation in `SessionMetrics#finish_generation` before relaying
287
+ carries the generation's `speed` (`{decode_tps, source}`, null without one), its own prompt-cache
288
+ counts (`prompt_tokens`, `cached_tokens`, `cache_write_tokens`: null when the server reported no writes) and
289
+ those running `tokens`: the Engine closes the generation in `SessionMetrics#finish_generation` before relaying
283
290
  it, so the web's info bar updates per generation without parsing chunk payloads.
284
291
 
285
292
  The page's frequent reads of `GET /api/sessions/:id` stay light too:
data/docs/cli.md CHANGED
@@ -420,9 +420,10 @@ file and index line stay as they are; only this session doesn't see it.
420
420
  `/help` lists the commands this session takes, the installed bundles' too, each
421
421
  with a line on what it does. `/stats` shows the session's numbers: turns, tool
422
422
  calls (by tool, with errors), iterations, tokens in/out summed over every
423
- request (with the cached and reasoning tokens when the server reports them),
424
- the decode speed, generation latency, cancellations, retries, context used
425
- and window, the prompt profile and the model the server says it ran, and the
423
+ request (with the cached tokens, the cache writes and the reasoning tokens when the server reports them),
424
+ the decode speed, generation latency, cancellations, retries (the network's),
425
+ thinking cuts (generations a plugin such as loop-guard cut) and output cap hits
426
+ (generations that ended at the provider's cap), context used and window, the prompt profile and the model the server says it ran, and the
426
427
  cost when the provider reports one (OpenRouter's `usage.cost`; no prices are
427
428
  guessed). The speed line is the last generation's and the session's average
428
429
  (weighted by tokens): llama.cpp reports it exactly (`87 tok/s out, 1.9k tok/s
@@ -369,9 +369,9 @@ after an idle exit) gets that process's environment, so put a lasting choice in
369
369
 
370
370
  ## Sampling
371
371
 
372
- chi asks chat hosts (`api: openai`) for greedy decoding (`temperature: 0.0`) and sends native hosts no sampling
373
- fields, so their server's defaults apply (llama.cpp: temperature 0.8). `sampling:` on a `hosts:` entry or a `models:`
374
- entry sets request fields for the model's turns:
372
+ chi sends no sampling fields by default, to chat hosts (`api: openai`) or native ones, so each model runs at its
373
+ provider's defaults (llama.cpp: temperature 0.8; vLLM takes them from the model's `generation_config.json`).
374
+ `sampling:` on a `hosts:` entry or a `models:` entry sets request fields for the model's turns:
375
375
 
376
376
  ```yaml
377
377
  hosts:
@@ -394,15 +394,16 @@ models:
394
394
  - A `models:` entry's fields win over its host's, field by field (the host can set a penalty and the model move only
395
395
  the temperature). The entry is found the way `profile:` is (the name as typed, alias-resolved or without its host
396
396
  prefix).
397
- - `temperature: null` (or `~`) sends no temperature, so the provider's default applies (vLLM takes it from the
398
- model's `generation_config.json`).
397
+ - `temperature: null` (or `~`) in a model's entry takes back a host's temperature, so the provider's default applies;
398
+ it also keeps the empty-answer retry (below) at that default.
399
399
  - Fields chi sets itself are refused with a warning: `model`, `messages`, `prompt`, `stream`, `stream_options`,
400
400
  `tools`, `tool_choice`, `stop`, `n_predict`, `max_tokens`, `n`, `parallel_tool_calls`, `response_format`,
401
401
  `cache_prompt`. A `sampling:` that isn't a map warns and is skipped.
402
- - Greedy decoding can make a heavily quantized thinking model loop in its reasoning ("Let me write the reply…"
403
- for minutes) or end with an empty answer. Qwen's own advice for its thinking models is `temperature: 0.6,
404
- top_p: 0.95` (not greedy), with `presence_penalty` between 0 and 2 against endless repetition.
405
- - The idle recap and side questions keep their own short, deterministic settings.
402
+ - Greedy decoding (`temperature: 0`) can make a thinking model loop in its reasoning ("Let me write the reply…"
403
+ for minutes) or end with an empty answer; set it only for a model you have watched. Qwen's own advice for its
404
+ thinking models is `temperature: 0.6, top_p: 0.95`, with `presence_penalty` between 0 and 2 against endless
405
+ repetition.
406
+ - The idle recap and side questions don't use `sampling:`; they send their own short output cap and no temperature.
406
407
 
407
408
  `/model` shows what applies (`sampling: temperature=0.6 presence_penalty=1.5 (hosts.work)`), and each request's
408
409
  `stream` line in the debug log carries a `sampling=` field with what was sent. The fields are read every turn, so a
@@ -514,10 +515,14 @@ gateway that spreads requests over several providers can key on it to keep one c
514
515
  prompt caches hit and every turn is answered by the same model. Servers that don't know the header ignore it.
515
516
 
516
517
  Chat requests for a Claude model (an id containing `claude`, such as `anthropic/claude-sonnet-5.5`) on a remote
517
- OpenAI-compatible host get two prompt-cache breakpoints (`cache_control` on the system message and on the last
518
- message), so each step reads the earlier prompt from Anthropic's cache instead of paying for it again; the debug
518
+ OpenAI-compatible host get two prompt-cache breakpoints (`cache_control` on the system prompt and on the last
519
+ message), so each step reads the earlier prompt from Anthropic's cache instead of paying for it again. The system
520
+ prompt goes as two text parts, the breakpoint after the first: everything sessions share, then the model, working
521
+ directory and session lines, so a new session reads the shared part from the cache as well; the debug
519
522
  log's line shows `cache=on`. Nothing to configure. A provider behind a gateway may still not cache: check the
520
- cached tokens in `/stats`.
523
+ cached tokens in `/stats`. Each request's own counts are in the debug log's `generation_completed` line:
524
+ `prompt=` (its prompt tokens), `cached=` (read from the server's cache) and `cache_write=` (written to it, when the
525
+ server reports writes); recap and side requests log theirs as `recap request_usage`.
521
526
 
522
527
  ## Llama Model Routing
523
528
 
@@ -616,6 +621,8 @@ Transient network failures are retried automatically with exponential backoff.
616
621
  - An HTTP 402 about credit held by in-flight requests (OpenRouter reserves credit for each running request, so
617
622
  one session's long request can make another's fail) is retried like a 429, 20s apart unless `Retry-After`
618
623
  says otherwise: with the default `retry.max` that is about 100s. With `retry.max: 0` it fails at once.
624
+ Not when its `metadata.reason` is `weight_exceeds_budget`: that request alone is larger than the key's credit
625
+ budget, so it fails at once (lower `default.max_tokens` or raise the key's limit).
619
626
  - A refused connection (nothing listening) is not retried: the turn fails at once with `can't reach host <name> at
620
627
  <address> (connection refused) — is the server running?`.
621
628
  - A stream that has already produced output is never retried (the retry would repeat it); it fails the turn.
@@ -671,7 +678,7 @@ message (before, a failed llama.cpp `/completion` ended the turn as
671
678
  | connection | reset, timed out, dropped mid-stream; refused | yes (network retry), not mid-stream; refused: no |
672
679
  | rate limited | HTTP 429 | yes, honouring `Retry-After` |
673
680
  | credits held | HTTP 402 "… in-flight requests" | yes, after 20s (or `Retry-After`) |
674
- | credits | any other HTTP 402: out of credits | no |
681
+ | credits | any other HTTP 402: out of credits; one whose `metadata.reason` is `weight_exceeds_budget` (the request alone is over the key's budget: lower `default.max_tokens`) | no |
675
682
  | server | HTTP 5xx, llama.cpp's mid-stream `error:` event | 500/502/503/504/529 only |
676
683
  | auth | HTTP 401/403 | no |
677
684
  | bad request | other 4xx; a prompt larger than the context window, whatever the status | no |
@@ -891,6 +898,7 @@ described in their own sections.
891
898
  | `models.<key>.thinking`, `hosts.<name>.thinking` | none | | A model's or host's level. See "Thinking". |
892
899
  | `hosts.<name>.remote` | by address | | `true`/`false`: treat the host as a remote provider or a local server. See "Remote or local". |
893
900
  | `max_tool_output_chars` | `10000` | yes | Tool output kept in the conversation; a top-level key (see below). |
901
+ | `cache.warmup` | `auto` | | `auto`: after a turn, send the next turn's prompt (up to the next message) to a local llama.cpp host on the native loop, so the next turn prefills only its message; never a remote or `api: openai` host. `off`: never. See [prompt caching](internals/prompt-caching.md#the-turn-end-warm-up). |
894
902
  | `retry.max` | `5` | yes | See "Llama Network Retry Behavior". |
895
903
  | `retry.base_delay` | `0.5` | yes | |
896
904
  | `retry.max_delay` | `8.0` | yes | |
@@ -912,6 +920,7 @@ described in their own sections.
912
920
  | `execute.preview_bytes` | `12288` | yes | |
913
921
  | `execute.telemetry_threshold_pct` | `80` | yes | |
914
922
  | `execute.timeout_sec` | `120` | yes | Seconds one `execute` command may run before it is stopped. |
923
+ | `execute.description` | `true` | | `execute` offers the model an optional `description` (a few words on what the command does), shown as the tool row's title in `chi web` and in place of the command in the TUI's tool line. `false`: the parameter isn't declared, and rows show the command's first step. |
915
924
  | `web.port` | `4567` | `--port` | `chi web`'s port. See [CLI](cli.md). |
916
925
  | `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 (`chi web --new-token` replaces it). Anything else binds `127.0.0.1` with a warning. See [CLI: chi web on your phone](cli.md#chi-web-on-your-phone). |
917
926
  | `web.markdown` | `false` | yes | Render answers as Markdown in `chi web`. |
data/docs/hooks.md CHANGED
@@ -399,7 +399,7 @@ stripped of surrounding whitespace, except file text, an edit's
399
399
 
400
400
  | Tool | `content:` from | `path:` from | Own fields |
401
401
  |------|-----------------|--------------|------------|
402
- | `execute` | `command` | — | `cwd` |
402
+ | `execute` | `command` | — | `description`, `cwd` |
403
403
  | `read` | `path` | — | `start_line`, `end_line` |
404
404
  | `write` | — | `path` | `content` |
405
405
  | `edit` | — | `path` | `old_text`, `new_text`, `start_line`, `end_line` |
@@ -17,6 +17,7 @@ Recommended workflow:
17
17
 
18
18
  Behavior:
19
19
 
20
+ - `execute`, `task_create` and the `!cmd` shell bang run the command in a non-login shell: `/bin/sh -c` on Linux; on macOS, when `/bin/zsh` is there, `/bin/zsh --emulate sh +o ignore_braces +o sh_glob -o bash_rematch +o bsd_echo -c` (macOS's `/bin/sh` is bash 3.2, which can't parse an apostrophe in a heredoc inside `"$( )"`, the usual commit message shape). That mode reads no rc files and keeps POSIX word splitting, unmatched globs left as is, `{1..3}`, `[[ … =~ (…) ]]` with `BASH_REMATCH`, arrays, `$'…'`, `&>` and echo expanding `\t`. Bash-only builtins and variables (`shopt`, `BASH_VERSION`, `${!prefix*}`, `read -p`) are not there.
20
21
  - Task metadata and output are persisted under `tmp/tasks/`.
21
22
  - Task listing is workspace-scoped (current project only).
22
23
  - `task_get` returns metadata and `output_path`; use `read` for output contents.