samagotchi 0.62.0 → 0.64.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +78 -1
  3. data/README.md +4 -1
  4. data/bin/chi +3 -2
  5. data/docs/architecture.md +12 -2
  6. data/docs/cli.md +20 -9
  7. data/docs/configuration.md +16 -9
  8. data/docs/context.md +13 -3
  9. data/docs/hooks.md +6 -3
  10. data/docs/internals/engine.md +10 -3
  11. data/docs/memory.md +1 -1
  12. data/docs/plugins.md +96 -2
  13. data/docs/releasing.md +1 -1
  14. data/docs/sessions.md +11 -8
  15. data/docs/sub-agent.md +27 -4
  16. data/docs/testing.md +13 -4
  17. data/lib/samagotchi/answer_command.rb +5 -1
  18. data/lib/samagotchi/answer_refs.rb +18 -26
  19. data/lib/samagotchi/bridge/turn_accumulator.rb +1 -0
  20. data/lib/samagotchi/bridge.rb +41 -5
  21. data/lib/samagotchi/bundles/claude-peer/manifest.yml +22 -0
  22. data/lib/samagotchi/bundles/claude-peer/plugin.rb +406 -0
  23. data/lib/samagotchi/bundles/claude-peer/scripts/chi-peer-SKILL.md +104 -0
  24. data/lib/samagotchi/bundles/claude-peer/scripts/pair +66 -0
  25. data/lib/samagotchi/bundles/claude-peer/skill_claude_peer.md +60 -0
  26. data/lib/samagotchi/bundles/dev/manifest.yml +2 -1
  27. data/lib/samagotchi/bundles/loop-guard/manifest.yml +2 -2
  28. data/lib/samagotchi/bundles/loop-guard/plugin.rb +17 -6
  29. data/lib/samagotchi/bundles/slow-commands/manifest.yml +2 -2
  30. data/lib/samagotchi/bundles/slow-commands/plugin.rb +5 -3
  31. data/lib/samagotchi/bundles/system/config_modification_protocol.md +1 -1
  32. data/lib/samagotchi/bundles/system/manifest.yml +3 -3
  33. data/lib/samagotchi/bundles/system/memory_guide.md +1 -1
  34. data/lib/samagotchi/child_reports.rb +7 -2
  35. data/lib/samagotchi/cli/parent_wait.rb +9 -2
  36. data/lib/samagotchi/composer_route.rb +90 -0
  37. data/lib/samagotchi/config.rb +6 -3
  38. data/lib/samagotchi/context_absorber.rb +25 -6
  39. data/lib/samagotchi/continue_offer.rb +17 -3
  40. data/lib/samagotchi/delivery.rb +13 -8
  41. data/lib/samagotchi/engine.rb +2 -0
  42. data/lib/samagotchi/host_config.rb +6 -6
  43. data/lib/samagotchi/host_model.rb +2 -2
  44. data/lib/samagotchi/idle_recap.rb +2 -3
  45. data/lib/samagotchi/image_store.rb +8 -0
  46. data/lib/samagotchi/interrupted_turn.rb +7 -3
  47. data/lib/samagotchi/last_turn.rb +5 -2
  48. data/lib/samagotchi/pending_input_queue.rb +10 -3
  49. data/lib/samagotchi/plugin/attached_context.rb +7 -4
  50. data/lib/samagotchi/plugin/sessions.rb +27 -5
  51. data/lib/samagotchi/recap_setup.rb +3 -3
  52. data/lib/samagotchi/reply_wait.rb +171 -6
  53. data/lib/samagotchi/row_refs.rb +3 -4
  54. data/lib/samagotchi/send_command.rb +63 -19
  55. data/lib/samagotchi/session.rb +12 -0
  56. data/lib/samagotchi/session_commands.rb +1 -1
  57. data/lib/samagotchi/session_inbox.rb +63 -7
  58. data/lib/samagotchi/session_manager.rb +49 -20
  59. data/lib/samagotchi/terminal_ui/attach_launcher.rb +6 -3
  60. data/lib/samagotchi/terminal_ui/attached_loop.rb +73 -35
  61. data/lib/samagotchi/terminal_ui/formatting.rb +3 -19
  62. data/lib/samagotchi/terminal_ui.rb +103 -68
  63. data/lib/samagotchi/tool_activity.rb +5 -5
  64. data/lib/samagotchi/tools/delegate.rb +28 -1
  65. data/lib/samagotchi/tools/delegate_cursor.rb +9 -4
  66. data/lib/samagotchi/tools/delegate_wait.rb +17 -5
  67. data/lib/samagotchi/tools/execute.rb +33 -8
  68. data/lib/samagotchi/turn_checkpoint.rb +9 -3
  69. data/lib/samagotchi/version.rb +1 -1
  70. data/lib/samagotchi/web/app.rb +6 -4
  71. data/lib/samagotchi/web/public/activity.js +2 -2
  72. data/lib/samagotchi/web/public/app.js +53 -91
  73. data/lib/samagotchi/web/public/card.js +73 -23
  74. data/lib/samagotchi/web/public/chains.js +6 -4
  75. data/lib/samagotchi/web/public/command_view.js +39 -35
  76. data/lib/samagotchi/web/public/commands.js +8 -8
  77. data/lib/samagotchi/web/public/composer.js +3 -3
  78. data/lib/samagotchi/web/public/copy.js +7 -15
  79. data/lib/samagotchi/web/public/diff_view.js +20 -23
  80. data/lib/samagotchi/web/public/format.js +0 -48
  81. data/lib/samagotchi/web/public/images.js +12 -16
  82. data/lib/samagotchi/web/public/question_cards.js +3 -2
  83. data/lib/samagotchi/web/public/read_view.js +10 -9
  84. data/lib/samagotchi/web/public/scope.js +23 -0
  85. data/lib/samagotchi/web/public/timing.js +2 -8
  86. data/lib/samagotchi/web/public/turn_html.js +119 -59
  87. data/lib/samagotchi/web/public/turn_model.js +13 -3
  88. data/lib/samagotchi/web/public/turn_view.js +73 -116
  89. data/lib/samagotchi/web/public/vendor/directive.js +8 -0
  90. data/lib/samagotchi/web/public/vendor/directives/unsafe-html.js +8 -0
  91. data/lib/samagotchi/worker.rb +53 -35
  92. data/lib/samagotchi/worker_inbound.rb +12 -11
  93. metadata +9 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68aeb876a7c4c04d7f2f5de4290a1c6089df3acd181bce7380ccb6bde9ef9de8
4
- data.tar.gz: ed308c360b3942d9f3d08233762396493a018585103e50661dd17ea4bb0d123c
3
+ metadata.gz: 61245b8998baef2bbb4c29cabc648314b4cc124cf9233099948cb7cf66dc890e
4
+ data.tar.gz: ac4e8fa165b5cc59d683b1541a3758e03f60a1d14b7fd9cded087770fda162de
5
5
  SHA512:
6
- metadata.gz: 8a3ecca6a15d1c2d0e4acf5531491116139b3423ca0e6fe2b4ad558f5c99b332b50672a700437f9d37c1397d9ed92e527b843e6577b11198906ff75ab16b4ecd
7
- data.tar.gz: 949538fdd97549e09bd215353cbdf9dccbe42a21806b965ff828db5b708521791e939abd2d2cb93892c23660abbfabd3106bb492412eb505f52cc0cd742d6d99
6
+ metadata.gz: 717ca2421c97d4f93493891e4f695528a0b8495ab11a2b47c348b29c726004abb32e638ab21b3e6af62676acfc4cc31c45527bdb9dfe72a9a270b3f7bfda3e02
7
+ data.tar.gz: 4916e876cf70f3b1b03e8c7554a127019e08e3b6f2e991305c8fe63ce1f6cf399155c43167ff36382c09eb2774792a4783ccbe39109702df6bd4efbe67a1ff53
data/CHANGELOG.md CHANGED
@@ -8,6 +8,81 @@ and commands may change between minor versions. How releases are made:
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.64.0] - 2026-10-13
12
+
13
+ ### Added
14
+
15
+ - `/queue TEXT` during a running turn now works in an attached terminal and the web composer too, as it did in the
16
+ plain REPL: TEXT runs as a turn of its own after the running one, instead of merging into it (`(queued: runs after
17
+ this turn)`). A session whose worker is older than this says to restart it rather than steering the turn. See
18
+ docs/cli.md, "Typing during a turn".
19
+ - `chi send --queue`: the message runs as a turn of its own after the running turn instead of merging into it, and
20
+ `chi send --queue --wait` waits for that turn's own answer (a running turn no longer refuses it; the running turn's
21
+ reply, end and questions are not the answer). Each turn's reply file now carries its message's id. See
22
+ docs/sessions.md, "Sending a message", and docs/sub-agent.md.
23
+ - Plugins: `ctx.sessions.send(id, text, delivery: :queue)` runs the message as a turn of its own after the session's
24
+ running turn; `delivery: :cut` raises (plugins never cut). See docs/plugins.md.
25
+
26
+ ### Changed
27
+
28
+ - Plain REPL (`--no-shared`): the lines a turn left over (a steer it didn't merge, `/queue` lines, image lines, commands
29
+ that wait) run in the order you sent them; before, an unmerged steer ran ahead of a `/queue` line typed earlier.
30
+ - A message with images sent during a running turn no longer holds back the text lines sent after it: they go in at
31
+ the turn's next step as usual, and the image message still runs as a turn of its own after it.
32
+
33
+ ### Fixed
34
+
35
+ - Stopping a session mid-turn (`chi sessions stop`, the web's stop, a parent stopping its delegate) cancels the turn
36
+ with its own reason, `session_stopped`, instead of the user's Stop: the turn's line reads "canceled (session
37
+ stopped)", a command it was running "stopped as the session was stopped" (slow-commands 0.2.2 counts it as
38
+ stopped, not slow), and `chi send --wait --format json` reports `cancel_reason: session_stopped`.
39
+ - A delegate (and any worker a session's own commands start, such as `chi send --new`) reads `hosts:` from config.yml
40
+ as it starts, so it sees a host added or changed after its parent's worker started; before, it got the parent's
41
+ start-time hosts through `SAMAGOTCHI_HOSTS_JSON`, which workers no longer inherit (one set in your shell
42
+ applies to that chi process only; put hosts in config.yml).
43
+ - Web: a step that only called plugin tools with a verb label is titled by the label ("echoing"), not "working
44
+ with echoing"; among other tools such a call is named by its tool ("working with read, echo").
45
+ - Web: a send from a stale tab into a session deleted meanwhile goes back to the start page with a "was not
46
+ found" notice, the line kept in the composer, instead of an alert.
47
+ - `chi send`, the web composer and a plugin's `ctx.sessions.send` now report a message the session's worker refuses
48
+ (a 4xx answer such as a delivery it doesn't run) instead of writing it as an input file the worker would merge
49
+ anyway; a body over the worker's size limit still goes in as a file, as before.
50
+ - `chi answer`, `chi send --wait ID` (no message) and `delegate_result` wait for the reply of the turn they are about
51
+ (the answered turn, the running turn, the follow-up's turn), not a newer one queued behind it; a Continue of the
52
+ step-limit question gets the continued turn's reply, and a Stop ends the wait as `not_continued`. Workers older
53
+ than this keep the old behaviour.
54
+
55
+ ## [0.63.0] - 2026-10-13
56
+
57
+ ### Added
58
+
59
+ - The claude-peer bundle (in the dev profile): pair a chi session with a Claude Code session you work with, and
60
+ the `claude_send` tool sends Claude a part of the work (a plan step, a diff, a finding) to validate, as context or
61
+ with a question; Claude's answer comes back as the `claude-review` context. `/claude validate|context <text>` and
62
+ `/claude last` send without the model, `/claude` shows whether a Claude is paired, and `/claude install-skill`
63
+ installs Claude's `chi-peer` skill, which pairs ("pair with chi <id>"). See docs/plugins.md, "The claude-peer
64
+ bundle".
65
+ - Plugins: `ctx.context.list` gives each source's last `summary:` too. See docs/plugins.md, "Attached context".
66
+
67
+ ### Fixed
68
+
69
+ - Attached context: a source added with `chi context add NAME --push` now wakes an idle session when its first
70
+ push asks to (`"wake": true`); before, only later pushes could.
71
+ - Plugins: `ctx.context.list` returns `[]` for a new session whose file isn't saved yet (a plugin command before
72
+ the first turn) instead of raising "Session not found".
73
+ - An after_turn hook's file refs on the answer (`event[:refs]`) must be under the session's folder, as a plugin
74
+ tool row's are: a file elsewhere is refused (and logged), and a stored one is dropped when the answer is shown.
75
+ - loop-guard (0.3.8): the card for a turn it stopped prints under the blocked call's row in the terminal, not
76
+ before it.
77
+ - Attached TUI: joining a session whose last turn was images alone (sent from the web) names each image once, not
78
+ twice.
79
+ - Attached TUI: text you had typed when the step-limit question opened comes back at the prompt once you answer
80
+ it, instead of being lost.
81
+ - `chi -p … --non-interactive` says so on stderr and exits 1 when the iteration limit cuts the turn short, instead
82
+ of exiting 0 with the partial text as if it were the answer.
83
+ - `chi --no-shared --resume` drops a question the session's last worker saved and died with, as an attached resume
84
+ does, instead of keeping it in the session file.
85
+
11
86
  ## [0.62.0] - 2026-10-13
12
87
 
13
88
  ### Added
@@ -2719,7 +2794,9 @@ and long-lived sessions.
2719
2794
  - A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
2720
2795
  hotkey panel that send selected text or the clipboard to your sessions.
2721
2796
 
2722
- [Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.62.0...HEAD
2797
+ [Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.64.0...HEAD
2798
+ [0.64.0]: https://github.com/dm1try/samagotchi/compare/v0.63.0...v0.64.0
2799
+ [0.63.0]: https://github.com/dm1try/samagotchi/compare/v0.62.0...v0.63.0
2723
2800
  [0.62.0]: https://github.com/dm1try/samagotchi/compare/v0.61.0...v0.62.0
2724
2801
  [0.61.0]: https://github.com/dm1try/samagotchi/compare/v0.60.0...v0.61.0
2725
2802
  [0.60.0]: https://github.com/dm1try/samagotchi/compare/v0.59.0...v0.60.0
data/README.md CHANGED
@@ -150,7 +150,10 @@ task to a child session that runs in parallel and reports back only its final
150
150
  reply (a normal session: `chi --attach <id>` steers it). With the `coordinator`
151
151
  bundle (in `dev`), `/coordinate <goal>` has chi split the work into tasks, each
152
152
  in a child session in its own git worktree, check each report and ask you
153
- before each merge; `/children` shows the children and their state.
153
+ before each merge; `/children` shows the children and their state. With the
154
+ `claude-peer` bundle (in `dev`), chi sends a part of its work to a Claude Code
155
+ session you pair it with, to validate or as context, and Claude answers back
156
+ into chi (`/claude`).
154
157
 
155
158
  `chi send` is the other half: the text goes in as your message, the same as
156
159
  typing it in the attached terminal or the web composer, and a turn runs. Piped
data/bin/chi CHANGED
@@ -386,8 +386,9 @@ begin
386
386
  scratch: scratch
387
387
  ).run
388
388
  # `chi -p X </dev/null`: the turn failed (nothing was sent again); -p
389
- # --non-interactive: the turn ended with no answer, or Ctrl-C cancelled it.
390
- exit 1 if %i[turn_failed empty_answer].include?(ended)
389
+ # --non-interactive: the turn ended with no answer or at the iteration
390
+ # limit, or Ctrl-C cancelled it.
391
+ exit 1 if %i[turn_failed empty_answer iteration_limit].include?(ended)
391
392
  exit Samagotchi::CLI::Exit::INTERRUPTED if ended == :interrupted
392
393
  rescue Samagotchi::TerminalUI::SessionBusy, Samagotchi::TerminalUI::SessionNotFound, Samagotchi::ModelProfile::MissingModel => e
393
394
  warn "Error: #{e.message}"
data/docs/architecture.md CHANGED
@@ -73,6 +73,12 @@ TerminalUI ── delegates ──▶ Engine
73
73
  delegates all core work to an `Engine`.
74
74
  - The `on_event:` seam on `run_turn` exposes raw `KernelLoop` events plus the
75
75
  higher-level turn events, so any new UI can render without terminal coupling.
76
+ - **`ComposerRoute`** (`lib/samagotchi/composer_route.rb`) decides where a line typed at
77
+ either terminal's prompt goes (the REPL's `steer_line` / `run_input_line`, the attached
78
+ `AttachedLoop#submit`): `/cut TEXT` / `/queue TEXT`, a terminal's own word, a session
79
+ command, a typo, a prompt. Each UI keeps what it does with the route. The web's
80
+ `composer.js#routeComposerLine` decides the same; `spec/fixtures/composer_routes.json`
81
+ holds the cases both answer (see [testing.md](testing.md)).
76
82
 
77
83
  ## Request / turn flow
78
84
 
@@ -369,7 +375,11 @@ session every 10 s, so a `kill -9` shows within a second. The summary (`Web::Ses
369
375
  shared with `/api/sessions` and the session view) carries `owner`, `project_root` and
370
376
  `bridge_up` (the sidecar is there *and* the lock is held: the page attaches its stream on it), and
371
377
  from that sidecar `worker_version` (the chi the worker runs) and `worker_features`
372
- (`Bridge::FEATURES`, what a client may ask of it beyond the routes). A worker's Bridge snapshot
378
+ (`Bridge::FEATURES`, what a client may ask of it beyond the routes: `restart`, `task_stop`, `reparent`,
379
+ `delivery`, a worker that queues a message for after the turn; `SessionManager.deliver_turn` and
380
+ the attached TUI refuse a queue to a worker without it, which would steer; `turn_ids`, a worker whose running
381
+ turn's mark, continue turn and Stop carry the turn's `enqueued_id`, which `chi answer`, `chi send --wait` with no
382
+ message and `delegate_result` rely on through `ReplyWait.own_turn`). A worker's Bridge snapshot
373
383
  names its `chi_version` too.
374
384
  `POST/DELETE /api/sessions` and `/stop` rescan the session before answering (`SessionHub#touch`).
375
385
  `GET /api/sessions` is the hub's projection too (its sort, paging and total). `Server` always builds
@@ -448,7 +458,7 @@ stream events (server counts, else a chars/4 estimate). Model lists are `LLM::Mo
448
458
  server (`/props`), then the host's model list, then config.
449
459
 
450
460
  **Keys.** A host's API key comes only from the environment variable its
451
- `api_key_env:` names; it never reaches config.yml, `HOSTS_JSON`, `chi self`,
461
+ `api_key_env:` names; it never reaches config.yml, `SAMAGOTCHI_HOSTS_JSON`, `chi self`,
452
462
  logs or events.
453
463
 
454
464
  ## Other components
data/docs/cli.md CHANGED
@@ -18,7 +18,7 @@
18
18
  - `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 (a live worker's `GET stats`, else its saved `analytics.json`; `--format json` one object) 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`) exits 2; an unknown or refused session exits 1
19
19
  - `chi note [--source NAME] [-m TEXT] (ID|PREFIX)... | --all` — add a context note (TEXT or stdin) to sessions: background the model sees on its next turn; it starts no turn (see [Sessions: Context notes](sessions.md#context-notes))
20
20
  - `chi context <add|push|ls|show|refresh|rm|mute|unmute> …` — attach live external text to sessions (a command chi runs every so often, or text pushed in); the model gets a short note when it changes and reads it with `context_read`; `chi context add <URL>` attaches a GitHub PR with the github-pr bundle (see [Attached context](context.md))
21
- - `chi send [-m TEXT] [--image PATH]... [--cut] (ID|PREFIX)...` — send a message to sessions as if typed there: a turn starts (or a running one takes it at its next step; `--cut` asks it to cut long thinking for it); piped stdin goes above `-m` as quoted context, and `--image` attaches images (see [Sessions: Sending a message](sessions.md#sending-a-message)); `--new` starts a session with it instead (`--new --continues ID|last:ID` the next link of that session's chain, see [Session chains](sessions.md#session-chains)), and `--wait` prints the answer (`--wait ID` with no message waits for the next reply without sending; `--format json` prints one JSON object instead; exit 3 a question waits, its options on stderr; exit 4 `--timeout` passed with the turn still running; see [Starting a session](sessions.md#starting-a-session))
21
+ - `chi send [-m TEXT] [--image PATH]... [--cut | --queue] (ID|PREFIX)...` — send a message to sessions as if typed there: a turn starts (or a running one takes it at its next step; `--cut` asks it to cut long thinking for it; `--queue` runs it as a turn of its own after the running one, and `--queue --wait` waits for that turn's own answer); piped stdin goes above `-m` as quoted context, and `--image` attaches images (see [Sessions: Sending a message](sessions.md#sending-a-message)); `--new` starts a session with it instead (`--new --continues ID|last:ID` the next link of that session's chain, see [Session chains](sessions.md#session-chains)), and `--wait` prints the answer (`--wait ID` with no message waits for the next reply without sending; `--format json` prints one JSON object instead; exit 3 a question waits, its options on stderr; exit 4 `--timeout` passed with the turn still running; see [Starting a session](sessions.md#starting-a-session))
22
22
  - `chi answer ID --question QID (--option N|LABEL)... [--text T] [--timeout S] [--format json]` (or `--dismiss`) — answer the question a session waits on (the one `chi send --wait` exited 3 with), then wait and print what comes next as `chi send --wait` does: the reply (0), the next question (3), still running after `--timeout` (4). `--option` is 1-based or the label, repeated on a multi-select question; `--text` is free text, or a Deny's reason; `--dismiss` leaves it unanswered and the model finishes its reply. A question no longer open (the web answered first) isn't answered again: it waits for that turn's reply. An option the question doesn't offer exits 2; a worker that is gone exits 1 (`send the task again: chi send --wait -m "…" ID`). An approval can be denied, not allowed, unless `guardrails.parent_approvals: once` (a convention, not a security boundary; see [Guardrails](guardrails.md#approvals-from-a-parent-agent))
23
23
  - `chi desktop install|upgrade|uninstall|status` — the macOS "Send to chi" helper: a Service and a ⌃⌥⌘N hotkey that send text or images to a session (live, stopped or new) as a message (⏎, a turn runs) or a context note (⌘⏎) (see [Desktop helper](desktop.md))
24
24
  - `chi models [--format text|json] [--timeout S] [TEXT]` — list the models every configured host offers, as the names `--model` takes (see [Listing the models](#listing-the-models))
@@ -250,7 +250,10 @@ Notes:
250
250
  retry lines and hooks' notices as they come, the after_turn hooks' ones
251
251
  (source-links' `sources:`) after the answer; and the error of a failed turn,
252
252
  then `chi: the session is kept with your prompt; continue it with: chi
253
- --resume ID` (exit 1). Ctrl-C saves the session with the prompt and a
253
+ --resume ID` (exit 1). A turn the iteration limit (`turn.max_iterations`)
254
+ cut short prints what the model wrote so far, then `chi: the iteration limit
255
+ (N) was reached before the turn finished; continue it with: chi --resume ID`
256
+ on stderr (exit 1). Ctrl-C saves the session with the prompt and a
254
257
  cancel note and exits 130.
255
258
  Nobody can answer there: an approval is denied, and a question the model
256
259
  asks (`ask_user_question`) is dismissed at once (one line on stderr), never
@@ -295,8 +298,8 @@ and cuts nothing. `/cut TEXT` in a terminal or the web composer (or `chi send --
295
298
  once the model has streamed only thinking for `steer.cut_after` seconds (per host/model: `steer_cut_after`; default
296
299
  20), now or while your message waits, that generation is cut and the step starts again with your message, marked
297
300
  `↪ cut in for your message` (see
298
- [configuration.md](configuration.md#messages-during-a-running-turn-steer-and-cut)). The web
299
- composer has no `/queue` yet (it says so and sends nothing). The
301
+ [configuration.md](configuration.md#messages-during-a-running-turn-steer-and-cut)). `/queue TEXT`
302
+ (terminal or web composer, or `chi send --queue`) keeps TEXT for after the turn: it runs as a turn of its own once the running one ends. The
300
303
  first answer to an `ask_user_question` wins; the other UIs close their widget.
301
304
  An empty answer dismisses the question in every UI. The model is then told
302
305
  not to go ahead with what it asked about, or change anything else, and to wait.
@@ -538,10 +541,18 @@ REPL alike:
538
541
  20 s)` (it waits for the thinking; the step may end first) or `(cutting is
539
542
  off; goes in at the next step)` (`steer.cut_after` is 0, per host/model:
540
543
  `steer_cut_after`, or no generation to cut).
541
- - `/queue TEXT` (plain REPL only) runs TEXT as a turn of its own after this
542
- one: `(queued: runs after this turn)`. An attached terminal says
543
- `(/queue isn't available in an attached session yet)` and sends nothing (the web
544
- composer: `(/queue isn't available in the web yet; …)`).
544
+ - `/queue TEXT` runs TEXT as a turn of its own after this one, in an attached
545
+ terminal, the plain REPL and the web composer alike: `(queued: runs after this
546
+ turn)` (the web draws it as a queued bubble until its turn starts). It never
547
+ merges into the running turn, and a plain line sent after it still does.
548
+ Several queued lines run one turn each, in the order sent; they still run
549
+ after a Ctrl-C or a failed turn, and a queued line drops a continue offer as
550
+ any prompt does. Other terminals show someone else's queued line with the same
551
+ note. A session whose worker is older than queueing would steer it instead, so
552
+ it is not sent: `(/queue needs a newer worker: restart it with chi sessions
553
+ restart, then send again)` (the web shows the refusal under the line). A line
554
+ with images works the same way: it waits for the turn's end, and the lines
555
+ sent after it still go in at the next step.
545
556
  At the open prompt (no turn running) `/cut TEXT` and `/queue TEXT` run TEXT
546
557
  as a normal prompt.
547
558
  - Commands answer, wait or are refused, by what they do:
@@ -833,7 +844,7 @@ Notes:
833
844
  - Without `--default` the command is session-scoped and does not rewrite config files.
834
845
  - With `--default` the new default is written to `~/.config/samagotchi/config.yml` (honoring `XDG_CONFIG_HOME`) and takes effect for all new sessions; the current session's effective model is also updated immediately. Bare aliases and `host:model` are both valid.
835
846
  - `--default` and `--alias` change only their one key's line in `config.yml` (`default.model`, or the alias under `model_aliases:`): comments and the rest of the file stay as written, a symlinked file is written through and keeps its mode. When the edited text wouldn't read back as the expected settings (a flow-style section, anchors), chi writes the whole file out from the parsed data instead, which drops its comments.
836
- - Worker sessions inherit `hosts:` via `SAMAGOTCHI_HOSTS_JSON`.
847
+ - A worker reads `hosts:` from config.yml when it starts (not from the chi that started it).
837
848
  - The idle recap uses the session's current model (a switch counts from the next recap), unless `recap: {host_ref, model}` pins one.
838
849
 
839
850
  ## Session recap
@@ -106,7 +106,10 @@ Behavior:
106
106
  at its start until it is stopped; the web's model picker lists a `hosts:`
107
107
  edit at once). A worker gets the CLI flags of the chi that started it
108
108
  through its environment.
109
- - Workers inherit hosts via `SAMAGOTCHI_HOSTS_JSON` propagated through `SessionManager.spawn_options`.
109
+ - A worker reads `hosts:` from the file as it starts, as every other setting, so a delegate (or any session
110
+ started later) sees a host added after its parent started. `SAMAGOTCHI_HOSTS_JSON` (a JSON object in the shape
111
+ of `hosts:`) replaces the file's `hosts:` for the process it is set on, the way specs use it; no worker inherits
112
+ it (`SessionManager.spawn_options` unsets it).
110
113
 
111
114
  This lets you run `chi` without repeating common defaults such as model
112
115
  and llama host/port on every invocation.
@@ -372,7 +375,7 @@ system prompt stays the same; a server that swaps models between turns goes unno
372
375
  `server (chat_template)`, `name`, `default`); `chi self` shows what config says without asking the server. A chat
373
376
  host (`api: openai`) formats nothing itself: its profile comes from the name and only strips thought tags.
374
377
 
375
- Workers get `hosts:` (with `profile:`) through `SAMAGOTCHI_HOSTS_JSON` and read `models:` from the same config file.
378
+ Workers read `hosts:` (with `profile:`) and `models:` from the config file.
376
379
  `--profile` reaches the worker a chi starts, but a worker that another process wakes later (`chi web`, `--attach`
377
380
  after an idle exit) gets that process's environment, so put a lasting choice in config.
378
381
 
@@ -416,8 +419,8 @@ models:
416
419
 
417
420
  `/model` shows what applies (`sampling: temperature=0.6 presence_penalty=1.5 (hosts.work)`), and each request's
418
421
  `stream` line in the debug log carries a `sampling=` field with what was sent. The fields are read every turn, so a
419
- `/model` switch takes the new model's. A worker gets `hosts:` (with `sampling:`) when it starts, through
420
- `SAMAGOTCHI_HOSTS_JSON`, and reads `models:` from the config file each turn: after changing a host's `sampling:`,
422
+ `/model` switch takes the new model's. A worker reads `hosts:` (with `sampling:`) from the config file when it
423
+ starts, and `models:` each turn: after changing a host's `sampling:`,
421
424
  stop the session's worker (`chi sessions stop`) for it to take effect.
422
425
 
423
426
  ## Prices
@@ -907,7 +910,8 @@ that model's cut wait (`steer.cut_after` seconds, default `20`, `0` = never; cou
907
910
  so the wait for a busy server doesn't count) and still does, and the model starts the step again with the message
908
911
  (`↪ cut in for your message`). One that comes earlier cuts once the thinking passes it, unless the step ends first
909
912
  and the message goes in there. A plain message (from the web composer, `chi send` without `--cut`, a parent agent)
910
- never asks for a cut. Such a cut spends no `retry.empty_answer` attempt and sends no hidden note; only the cut
913
+ never asks for a cut, nor does a queued one (`/queue TEXT`, `chi send --queue`, `ctx.sessions.send(…, delivery:
914
+ :queue)`), which runs as a turn of its own after the running one. Such a cut spends no `retry.empty_answer` attempt and sends no hidden note; only the cut
911
915
  thinking is lost. A generation that has streamed visible text or a tool call is never cut, and a plugin's steer
912
916
  (`ctx.steer`, `ctx.sessions.send`) never cuts.
913
917
 
@@ -931,9 +935,12 @@ models:
931
935
 
932
936
  `/model` shows the resolved wait (`; steer cut: after 60 s (models: qwen)`, `; steer cut: never (hosts.splash)`).
933
937
 
934
- `/queue TEXT` in the plain REPL runs TEXT as a turn of its own after the running one; the attached terminal and the web
935
- don't queue yet, and a request that asks the Bridge or the web for `delivery: "queue"` is refused (400
936
- `delivery_unavailable`).
938
+ `/queue TEXT` (in a terminal or the web composer) runs TEXT as a turn of its own after the running one: the request
939
+ carries `delivery: "queue"`, the input file keeps it, and the worker's drain leaves the file for after the turn. The
940
+ Bridge acks `delivery: "queue"` while a turn runs (to an idle session the message is simply the next turn:
941
+ `next_step`). A worker whose sidecar doesn't name the `delivery` feature (older than queueing) would steer it, so the
942
+ sender refuses it (`409 delivery_unavailable`, "restart it"), and so does a worker that answers the request with a
943
+ 400 `delivery_unavailable`.
937
944
 
938
945
  ## Server errors
939
946
 
@@ -1350,7 +1357,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
1350
1357
  | `memory.index_warn_tokens` | `2500` | yes | The tokens one scope's memory index (project or system; sent with every prompt) may hold before a `memory_write`, `write` or `edit` that takes it over gets a note asking the model to tighten long index descriptions; `0`: no note. Estimated as characters / `context.chars_per_token`. `memory:` is its own section, not the `memories:` preload list. See [Memory](memory.md). |
1351
1358
  | `context.status_thresholds` | `20,40,60,80` | yes | Percentages that put the estimate into a bucket; the rise into a guidance bucket (from the second up) leaves the model its own `[CONTEXT: …]` line, and the bucket decides the guidance. |
1352
1359
  | `context.every_seconds` | `300` | | How often an attached context source's command runs when it has no `--every` (seconds, at least 30). See [Attached context](context.md). |
1353
- | `context.wake` | `true` | yes | A source whose update says `wake: true` may start a turn in a live, idle session (one per source per 10 minutes, within `session.max_wakes`); `false`: updates wait as notes for the next turn. See [Waking](context.md#waking). |
1360
+ | `context.wake` | `true` | yes | A source whose update says `wake: true` may start a turn in a live, idle session (one per source per 10 minutes, within `session.max_wakes`); so may a session's pushed source's first push. `false`: updates wait as notes for the next turn. See [Waking](context.md#waking). |
1354
1361
  | `thinking.turn_preamble` | `true` | yes | Ask a `qwen36` model to open its thinking with a short `TURN:` line (the step label). |
1355
1362
  | `reasoning_history` | `turn` | | Which of its reasoning a chat host's model gets back: `drop`, `turn`, `all`; environment only (`SAMAGOTCHI_REASONING_HISTORY`), below a session's own level (`/reasoning-history`), above the `models:`/`hosts:` entries. See "Reasoning history". |
1356
1363
  | `thinking.level` | `default` | `--thinking` | `off`, `low`, `medium`, `high` or `default` for every model; the flag and env outrank the `models:`/`hosts:` entries, the file's value doesn't; a session's own level outranks them all, and `--thinking` sets it on a session run (on `chi web` it sets this). See "Thinking". |
data/docs/context.md CHANGED
@@ -123,6 +123,11 @@ chi context add clip --push --project
123
123
  pbpaste | chi context push clip --project
124
124
  ```
125
125
 
126
+ A Claude Code session can be a pushed source too: the
127
+ [claude-peer bundle](plugins.md#the-claude-peer-bundle)'s `pair` script attaches
128
+ `claude-inbox` (Claude's inbox socket as the hint) and `claude-review`, where
129
+ Claude pushes its answers as JSON with `wake: true`.
130
+
126
131
  ### A stream: chat, a log, a feed
127
132
 
128
133
  A source's text is a snapshot, not a log: each run replaces it. For
@@ -233,6 +238,10 @@ you're away from the terminal. All of these must hold:
233
238
  - the source asked (`"wake": true`; a plain-text source never does), in
234
239
  any change since the session last heard of it: a later change that doesn't
235
240
  ask doesn't take the wake back;
241
+ - it's a change, not the source's first text, except for a session's pushed
242
+ source (`chi context add NAME --push`, attached empty): its first push can
243
+ wake too. A command or URL source's first fetch runs as you attach it, and a
244
+ project source's first text may predate the session, so neither wakes;
236
245
  - `context.wake` is on (default `true`);
237
246
  - the session's worker is up and idle: no turn running, nothing queued, no
238
247
  question or continue offer waiting, not just started;
@@ -242,15 +251,16 @@ you're away from the terminal. All of these must hold:
242
251
  - the source hasn't woken the session in the last 10 minutes.
243
252
 
244
253
  Otherwise the change arrives as a note, as above. The turn starts with the
245
- update note, whose last line becomes:
254
+ update note, or, for a session's pushed source, its attached note, whose last
255
+ line becomes:
246
256
 
247
257
  > chi started this turn because the source changed; your user didn't write anything. Tell your user in a sentence or two what changed and what it may mean for their work. Don't run commands, change files or reply on the source for it: wait for your user to ask.
248
258
 
249
259
  Every UI labels the turn `context <name> changed`, and the web's
250
260
  notifications count it as a finished turn however short.
251
261
 
252
- A wake turn that fails goes back to before it and keeps the update as a
253
- plain note; the model reads `[SYSTEM: the previous turn failed before any
262
+ A wake turn that fails goes back to before it and keeps its note as a
263
+ plain one; the model reads `[SYSTEM: the previous turn failed before any
254
264
  answer: … The wake turn for the change in attached context <name> was not
255
265
  answered; chi starts no other wake turn until the user writes.]`.
256
266
 
data/docs/hooks.md CHANGED
@@ -301,9 +301,12 @@ end
301
301
  keywords only (String or Symbol keys inside `target` and `actions`).
302
302
  - `match`: the text in the answer the ref stands for (at most 500 characters).
303
303
  - `kind`: a short lowercase word. `"file"` takes `target: {path:, line:, end_line:}`
304
- (the lines optional); a relative path is resolved against the session's
305
- folder, an absolute one is kept as given. Any other kind (`"issue"`,
306
- `"commit"`, …) takes `target: {id:}`.
304
+ (the lines optional); the path is absolute or relative to the session's
305
+ folder, and must be **under** it (its own spelling or its real path:
306
+ `/tmp/x` or `/private/tmp/x`), as a plugin tool row's file refs
307
+ ([plugins.md](plugins.md)): a file elsewhere is refused. It is kept under
308
+ the folder's real path. Any other kind (`"issue"`, `"commit"`, …) takes
309
+ `target: {id:}`.
307
310
  - `label`: what a UI shows for it (optional, at most 200 characters).
308
311
  - `actions`: links a UI offers on top of the kind's own, each
309
312
  `{id:, label:, url:}`; http(s) URLs only, without userinfo (`user:pass@`),
@@ -54,8 +54,10 @@ Engine#run_turn(session, prompt, on_event:, max_iterations:, cancel_controller:,
54
54
  │
55
55
  ├── complete_turn(turn, result)
56
56
  │ # end_turn(turn, "completed" | "canceled"): under the event lock the session gets the kept
57
- │ # messages, goes IDLE, records last_turn, and :turn_completed {result, turn_summary,
58
- │ # display_pending} or :turn_canceled {cancellation_reason, cancelled_by, duration_ms} is emitted
57
+ │ # messages, goes IDLE, records last_turn (enqueued_id: the turn's input, from its origin;
58
+ │ # a continue turn's origin carries its offer turn's, ContinueOffer#run_continue_turn),
59
+ │ # and :turn_completed {result, turn_summary, display_pending} or :turn_canceled
60
+ │ # {cancellation_reason, cancelled_by, duration_ms} is emitted
59
61
  │ # then the :after_turn hook (status, messages, present: the AnswerDisplay presenter,
60
62
  │ # refs: the AnswerRefs adder)
61
63
  │ # store_answer_display (one replace of the answer: `display` and/or `display_refs`;
@@ -521,7 +523,12 @@ Both loops:
521
523
  - **A cut generation** (`after_cut`): a generation a plugin cut (`stop_generation`) spends the same retry budget
522
524
  with its own nudge; when it is used up, the turn ends cancelled (`:hook`). A steer's cut asks again with the
523
525
  steer and spends nothing.
524
- - **Steering**: queued input goes in at iteration boundaries (`Steer.inject!`, `:pending_input_merged`).
526
+ - **Steering**: queued input goes in at iteration boundaries (`Steer.inject!`, `:pending_input_merged`). A
527
+ worker's drain (`Worker#pending_input_drain`) takes every input file in name order except the ones
528
+ `SessionInbox.waits_for_turn_end?` leaves for a turn of their own (`delivery: queue`, or images): those are
529
+ skipped, not a barrier, so a line sent after them still merges. Only the files it claims reach
530
+ `:input_merged`, the failure hand-back (`@merged_this_turn`) and the checkpoint; the skipped ones run after the
531
+ turn, one turn each, in name order (`Worker#run_input_files`).
525
532
  - **Context status**: an estimate of the window's fill before each request,
526
533
  emitted on every request (`:context_status`) so the UI always has a current
527
534
  number, with a guidance line on the tail only when it rises far enough.
data/docs/memory.md CHANGED
@@ -270,7 +270,7 @@ profiles, meta bundles that install a set of them:
270
270
  | profile | bundles |
271
271
  |---|---|
272
272
  | `core` | loop-guard, check-in, guardrails, slow-commands, agents-md: the recommended safety set |
273
- | `dev` | known-names, mcp, btw, skills, source-links, github-pr, coordinator |
273
+ | `dev` | known-names, mcp, btw, skills, source-links, github-pr, coordinator, claude-peer |
274
274
 
275
275
  `chi bootstrap` installs `core` and, on a terminal, offers `dev`. An existing
276
276
  install gets neither by itself: `chi bundle install core` (or `dev`).
data/docs/plugins.md CHANGED
@@ -675,6 +675,7 @@ llama.cpp serves on a native host too.
675
675
  id = ctx.sessions.fork(messages: ctx.messages + [{ role: "user", content: q }, { role: "model", content: a }],
676
676
  title: "btw: #{q}")
677
677
  ctx.sessions.send(id, "go on from here")
678
+ ctx.sessions.send(id, "then the docs", delivery: :queue) # after its running turn
678
679
  ctx.sessions.read(id) # => {id:, title:, status:, parent_id:, running:, messages:}
679
680
  ctx.sessions.children # => [{id:, short_id:, state:, branch:, last_reply:, reported:, ...}]
680
681
  ctx.sessions.stop(id) # one of this session's own children
@@ -695,6 +696,12 @@ ctx.sessions.stop(id) # one of this session's own children
695
696
  5 s for the session's worker, so call it from an anytime command or a
696
697
  thread of your own, never from a tool or hook of a running turn. A
697
698
  session open in a chi REPL can't take it.
699
+ - A running turn takes it at its next step. `delivery: :queue` runs it as
700
+ a turn of its own after that turn instead (as `/queue TEXT` does; to an
701
+ idle session it simply runs). A plugin never cuts the running turn's
702
+ thinking: `delivery: :cut` raises `Samagotchi::Plugin::Sessions::Error`,
703
+ as does an unknown value. A worker older than queueing refuses a queue
704
+ (it would steer): `Error` with its reason; nothing is sent.
698
705
  - `read(id)` gives a session now: from its worker when one runs (with a
699
706
  running turn so far, `running: true`), else as saved. `messages` has no
700
707
  system prompt.
@@ -722,7 +729,7 @@ ctx.sessions.stop(id) # one of this session's own children
722
729
  ```ruby
723
730
  ctx.context.attach(url: "https://github.com/acme/app/pull/42", why: "branch feat/x has open PR #42")
724
731
  ctx.context.attach(name: "ci", cmd: "bin/ci-status", why: "this branch's CI", every_seconds: 120)
725
- ctx.context.list # => [{name:, scope:, why:, hint:, fetched_at:, error:, provider:}]
732
+ ctx.context.list # => [{name:, scope:, why:, hint:, fetched_at:, error:, provider:, summary:}]
726
733
  ctx.context.decline(url: "https://github.com/acme/app/pull/42") # => "pr-42"
727
734
  ctx.context.mark_offered("pr-42", "https://github.com/acme/app/pull/42", why: "branch feat/x has open PR #42")
728
735
  ctx.context.offered("pr-42") # => #<data Offer name="pr-42", hint="https://…", why="branch…", at="2026-10-08T…Z">, or nil
@@ -756,7 +763,10 @@ gets a note when its text changes.
756
763
  - The source is the session's (not the project's), marked
757
764
  `added_by: plugin:<bundle>`. It is plugin code, so it isn't asked about as
758
765
  the agent's `chi context add --cmd` is.
759
- - `list` gives the session's sources, its own then its project's.
766
+ - `list` gives the session's sources, its own then its project's (`[]` before
767
+ the session has an id or its file is saved: a command before the first turn). `hint` is the
768
+ one the last text gave (else the source's), `summary` that text's summary
769
+ (nil before any text; chi 0.63.0).
760
770
  - Two attaches of one source at once (a double click) both return its
761
771
  name.
762
772
  - `attach`, `decline` and `mark_offered` raise
@@ -1504,6 +1514,90 @@ by themselves there.
1504
1514
  reason: merging a child's branch
1505
1515
  ```
1506
1516
 
1517
+ ## The claude-peer bundle
1518
+
1519
+ ```sh
1520
+ chi bundle install claude-peer # in the dev profile
1521
+ ```
1522
+
1523
+ A live link between a chi session and a Claude Code session you already work
1524
+ with: chi sends it a part of the work (a plan step, a diff, a finding) to
1525
+ validate or as context, and Claude's answer comes back into chi. This is
1526
+ Claude with the context it has, not a fresh review run. Nothing runs until a
1527
+ Claude pairs; without one the bundle costs one tool declaration.
1528
+
1529
+ - **Pairing is Claude's.** chi can't see Claude's inbox, so Claude attaches
1530
+ two pushed sources to the chi session: `claude-inbox`, whose hint is its
1531
+ per-session inbox socket (`CLAUDE_CODE_MESSAGING_SOCKET`, Claude Code
1532
+ 2.1.224 or later), and `claude-review`, where its answers come. You never
1533
+ run that yourself:
1534
+ 1. `/claude install-skill` (once) shows a card with the target,
1535
+ `$CLAUDE_CONFIG_DIR/skills/chi-peer/SKILL.md` (else `~/.claude/…`),
1536
+ whether one is there and, when it differs, a short diff; its Install (or
1537
+ Replace) button runs `/claude install-skill --yes`, which copies the
1538
+ bundle's `scripts/chi-peer-SKILL.md` there with the installed
1539
+ `scripts/pair` path written in. The copy happens inside chi, where no
1540
+ guardrail sees it: the button is your consent. The card also offers the
1541
+ Claude Code permission rule `Read(~/.local/state/samagotchi/plugins/claude-peer/**)`
1542
+ (your state folder), so Claude isn't asked before reading a long part's
1543
+ file; chi never writes Claude's settings.
1544
+ 2. In Claude Code you say "pair with chi <id or chi web URL>". The skill runs
1545
+ `sh <bundle>/scripts/pair <id or URL>`, which attaches `claude-inbox` (the
1546
+ socket as its hint, pushed as JSON so a re-pair after a Claude restart
1547
+ refreshes it) and `claude-review`, and lists the session's context. A
1548
+ re-pair keeps Claude's last answer.
1549
+ 3. Claude answers a validate or a question with a JSON push to
1550
+ `claude-review` (`text`, `summary`, `wake: true`), which wakes chi, the
1551
+ first answer too (on chi 0.62 the first one arrives as a note without
1552
+ waking); the model reads it with `context_read claude-review`.
1553
+ - **The tool `claude_send(kind, title, text)`**, `kind` being `validate`,
1554
+ `context` or `question`, writes one JSON line to that socket. The message
1555
+ starts with a header, `chi <id> · <kind> · <title>`. A text up to 4,000
1556
+ characters follows inline; a longer one goes to a file,
1557
+ `$XDG_STATE_HOME/samagotchi/plugins/claude-peer/sessions/<id>/<HHMMSS>-<slug>.md`
1558
+ (removed with the session), and the message names it (`payload: <path>`).
1559
+ The tool is declared whether or not a Claude is paired, so pairing doesn't
1560
+ change the prompt. Its errors say what to do: no `claude-inbox` (pair from
1561
+ Claude), the socket gone or refusing (that Claude session ended or
1562
+ restarted: pair again), a text over 200,000 characters.
1563
+ - **`/claude`** (an anytime command, so it works mid-turn) sends without
1564
+ the model:
1565
+ - `/claude` alone shows a card: paired or not, the socket and whether its
1566
+ file is there (it goes when that Claude session ends), the last send, and
1567
+ Claude's last answer (the `claude-review` summary).
1568
+ - `/claude validate <text>` and `/claude context <text>` send the text as it
1569
+ is, titled by its first line: paste a selection after them.
1570
+ - `/claude last` sends the model's last completed answer as context. Mid-turn
1571
+ it is the answer before the running turn, never the turn's partial text;
1572
+ a cancelled or failed turn has no answer, so the one before it goes.
1573
+ - **The skill.** `skill_claude_peer` (system scope) tells the model to send
1574
+ only when you ask, to pick the part rather than the session, not to wait
1575
+ or poll, and how to read the `claude-review` answer (a validate ends with
1576
+ `VERDICT: OK`, `CHANGES` or `UNSURE`).
1577
+ - **Asking first.** The tool has no `targets:`, so guardrails match it by name
1578
+ only: to be asked before each send, add a rule ([Rules in
1579
+ config.yml](guardrails.md#rules-in-configyml)):
1580
+
1581
+ ```yaml
1582
+ guardrails:
1583
+ rules:
1584
+ - id: claude-send
1585
+ tool: claude_send
1586
+ verdict: ask
1587
+ reason: sends session content to Claude Code
1588
+ ```
1589
+
1590
+ - **Limits.** The socket's format (`{"type":"user","message":{"role":"user","content":"…"}}`)
1591
+ is undocumented: it was found in, and checked on, Claude Code 2.1.296. A
1592
+ line Claude Code can't parse is dropped silently, so a Claude Code update
1593
+ could break this without an error. No auth line is sent: it is optional on
1594
+ macOS and Linux, and native Windows, which needs it, isn't supported.
1595
+ Claude's `crossSessionInbound` setting decides what it does with a peer
1596
+ message: an interactive auto-mode session delivers it; a session that
1597
+ bypasses permissions holds it for approval (in `-p` it expires after 5
1598
+ minutes). It is local only (a Unix socket), but it does hand session
1599
+ content to another agent: only what the model or you picked.
1600
+
1507
1601
  ## Shutdown
1508
1602
 
1509
1603
  When the REPL exits, or a session's worker exits (an idle exit, `/exit`, a
data/docs/releasing.md CHANGED
@@ -13,7 +13,7 @@ can run the whole release; the user approves the notes before the tag and the
13
13
  and `rake release:check` enforce it). The system bundle upgrades itself when
14
14
  chi starts.
15
15
  - **Every other shipped bundle** (btw, check-in, guardrails, known-names,
16
- loop-guard, mcp, skills, source-links, github-pr, coordinator, and the profiles core and dev) has its own semver in its
16
+ loop-guard, mcp, skills, source-links, github-pr, coordinator, claude-peer, and the profiles core and dev) has its own semver in its
17
17
  `manifest.yml` and, when it needs a newer chi, a `requires_chi:` line. They never upgrade by themselves: users run
18
18
  `chi update` (all of them, with the gem) or `chi bundle upgrade NAME`. So:
19
19
  - a change to a bundle's files bumps that bundle's `version:`