samagotchi 0.33.0 → 0.35.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 +91 -1
- data/README.md +6 -1
- data/bin/chi +3 -0
- data/docs/broadcast.md +129 -0
- data/docs/cli.md +8 -0
- data/docs/configuration.md +2 -0
- data/docs/context.md +5 -0
- data/docs/guardrails.md +35 -3
- data/docs/hooks.md +25 -4
- data/docs/memory.md +17 -1
- data/docs/plugins.md +78 -3
- data/docs/releasing.md +1 -1
- data/docs/sessions.md +15 -9
- data/lib/samagotchi/bridge/card_store.rb +1 -1
- data/lib/samagotchi/bridge/turn_notice.rb +1 -1
- data/lib/samagotchi/broadcast/recipients.rb +63 -0
- data/lib/samagotchi/broadcast/scope_card.rb +94 -0
- data/lib/samagotchi/broadcast/tags.rb +154 -0
- data/lib/samagotchi/broadcast_command.rb +228 -0
- data/lib/samagotchi/bundles/coordinator/manifest.yml +14 -0
- data/lib/samagotchi/bundles/coordinator/plugin.rb +114 -0
- data/lib/samagotchi/bundles/coordinator/skill_coordinator.md +60 -0
- data/lib/samagotchi/bundles/dev/manifest.yml +3 -2
- data/lib/samagotchi/bundles/guardrails/guardrails/rules.yml +11 -0
- data/lib/samagotchi/bundles/guardrails/manifest.yml +2 -2
- data/lib/samagotchi/bundles/mcp/manifest.yml +3 -3
- data/lib/samagotchi/bundles/mcp/plugin.rb +10 -11
- data/lib/samagotchi/bundles/source-links/hooks/source_links.rb +32 -12
- data/lib/samagotchi/bundles/source-links/manifest.yml +4 -3
- data/lib/samagotchi/bundles/source-links/source_links.md +1 -1
- data/lib/samagotchi/bundles/system/delegated.md +1 -1
- data/lib/samagotchi/bundles/system/manifest.yml +4 -4
- data/lib/samagotchi/bundles/system/memory_guide.md +1 -1
- data/lib/samagotchi/bundles/system/self_map.md +8 -2
- data/lib/samagotchi/children_status.rb +143 -0
- data/lib/samagotchi/config.rb +6 -0
- data/lib/samagotchi/cut_policy.rb +58 -0
- data/lib/samagotchi/engine.rb +45 -108
- data/lib/samagotchi/engine_peers.rb +30 -0
- data/lib/samagotchi/git_head.rb +24 -0
- data/lib/samagotchi/guardrail_wiring.rb +27 -2
- data/lib/samagotchi/guardrails/approvals.rb +7 -0
- data/lib/samagotchi/guardrails/child_boundary.rb +103 -0
- data/lib/samagotchi/guardrails/context.rb +32 -0
- data/lib/samagotchi/guardrails/shared_git.rb +124 -0
- data/lib/samagotchi/guardrails/verdict.rb +4 -3
- data/lib/samagotchi/guardrails.rb +1 -0
- data/lib/samagotchi/hooks/registry.rb +11 -5
- data/lib/samagotchi/kernel_loop.rb +9 -22
- data/lib/samagotchi/llm/chat_loop.rb +11 -22
- data/lib/samagotchi/log_subscriber.rb +1 -1
- data/lib/samagotchi/memory_bundle/builder.rb +14 -1
- data/lib/samagotchi/memory_bundle/installer.rb +6 -2
- data/lib/samagotchi/memory_bundle/manifest.rb +26 -5
- data/lib/samagotchi/memory_bundle/provenance.rb +2 -1
- data/lib/samagotchi/memory_paths.rb +10 -0
- data/lib/samagotchi/note_command.rb +13 -13
- data/lib/samagotchi/note_delivery.rb +42 -0
- data/lib/samagotchi/plugin/api.rb +2 -2
- data/lib/samagotchi/plugin/context.rb +4 -4
- data/lib/samagotchi/plugin/sessions.rb +45 -1
- data/lib/samagotchi/process_group.rb +2 -5
- data/lib/samagotchi/session_manager.rb +4 -3
- data/lib/samagotchi/sessions_command.rb +3 -2
- data/lib/samagotchi/steer_cut.rb +125 -0
- data/lib/samagotchi/system_prompt.rb +21 -8
- data/lib/samagotchi/terminal_ui/attached_loop.rb +25 -2
- data/lib/samagotchi/terminal_ui/status_row.rb +23 -2
- data/lib/samagotchi/terminal_ui.rb +14 -0
- data/lib/samagotchi/tool_declarations.rb +9 -5
- data/lib/samagotchi/tools/builtins.rb +2 -2
- data/lib/samagotchi/tools/delegate.rb +103 -14
- data/lib/samagotchi/tools/delegate_wait.rb +55 -13
- data/lib/samagotchi/tools/send_note.rb +5 -11
- data/lib/samagotchi/turn_note.rb +9 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +3 -0
- data/lib/samagotchi/web/capabilities.rb +19 -0
- data/lib/samagotchi/web/public/activity.js +26 -6
- data/lib/samagotchi/web/public/app.js +515 -288
- data/lib/samagotchi/web/public/card.js +12 -3
- data/lib/samagotchi/web/public/command_view.js +2 -3
- data/lib/samagotchi/web/public/families_view.js +171 -0
- data/lib/samagotchi/web/public/format.js +52 -0
- data/lib/samagotchi/web/public/index.html +94 -21
- data/lib/samagotchi/web/public/live_timing.js +154 -0
- data/lib/samagotchi/web/public/live_turn.js +44 -0
- data/lib/samagotchi/web/public/sessions_list.js +228 -32
- data/lib/samagotchi/web/public/strip.js +5 -2
- data/lib/samagotchi/web/public/turn_html.js +107 -0
- data/lib/samagotchi/web/public/turn_model.js +5 -4
- data/lib/samagotchi/web/public/turn_view.js +43 -129
- data/lib/samagotchi/web/session_summary.rb +4 -0
- data/lib/samagotchi/worker.rb +173 -309
- data/lib/samagotchi/worker_inbound.rb +251 -0
- data/lib/samagotchi/worker_wakes.rb +120 -0
- metadata +24 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b598dac8dadadd4dd37861ed690d09d09926520c2295bc998def4d75c3716ea7
|
|
4
|
+
data.tar.gz: 9d30ebb820024929bbb2dc1267011af7eb5710b33a4ba9625489a74d111edfbd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f40ed32d227d1017bc7abcba8ef40f5e38f2f7dd7876aa5f78a9290e5443489b8109183655a151a1345fef1fa3f3f49e5deafbac38059cdba3bec70b0585d71
|
|
7
|
+
data.tar.gz: 55aca343a9dc45e78791863286768c356e815dc1b9783993f2c4477edb991883a3c88ae208dd642137cab4c6ead58fc1d49228f201fefcd6878dd421c719af70
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,94 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.35.0] - 2026-10-06
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `chi broadcast -m TEXT` (or stdin) shares a note with every session it may concern, without picking them: your
|
|
16
|
+
own sessions a worker or a chi REPL runs, or that ended a turn in the last 8 hours (`broadcast.active_hours`),
|
|
17
|
+
delegate children and scratch sessions left out. One gets it when the note shares a tag with it: a ticket id
|
|
18
|
+
(`broadcast.ticket_pattern`) in its branch or your prompts there, a pull request attached to it, a link. The rest
|
|
19
|
+
are listed as skipped; `--all` reaches every one, `--dry-run` shows who would get it and why. The model mentions a
|
|
20
|
+
broadcast briefly when it affects its current work and doesn't act on it unless asked. For you, not for an agent:
|
|
21
|
+
refused inside a session, and the guardrails bundle's `chi-broadcast` rule asks. See
|
|
22
|
+
[docs/broadcast.md](docs/broadcast.md).
|
|
23
|
+
- `chi sessions list --format json` has `delegate`: true for a child the `delegate` tool started, false for a fork.
|
|
24
|
+
- A parent session shows its delegate children at a glance: a `⑂ 3` chip in its web info bar (how many run, wait,
|
|
25
|
+
are done or failed in the tooltip; the waiting ones in the attention colour; a click opens all sessions), and
|
|
26
|
+
`⑂ 2 running · 1 waiting` in the terminal's status row.
|
|
27
|
+
- A hook's `event[:notify]` and a plugin's `ctx.notify` take `fallback_for: :display`: the line repeats what the
|
|
28
|
+
answer's display (`event[:present]`) shows, so a UI that renders the display leaves it out. The web with markdown
|
|
29
|
+
on does; the REPL, the attached TUI, `chi -p` and the web with markdown off still show it. See
|
|
30
|
+
[docs/hooks.md](docs/hooks.md#what-a-hook-can-do-the-runtime).
|
|
31
|
+
- Web, all sessions: each card has an archive button (unarchive on an archived one), and Select picks many cards
|
|
32
|
+
(click, Shift-click a range, "Select all shown") for Archive N / Unarchive M. A session with a running turn is
|
|
33
|
+
skipped with the reason on its card; one toast at the end has Undo.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- source-links 0.4.0 (needs chi 0.35.0; run `chi update`): with markdown on, the web no longer shows the
|
|
38
|
+
`sources:` line under an answer that links every ref it names; it still shows when a ref is only in code or
|
|
39
|
+
markdown is off, and the terminals print it as before.
|
|
40
|
+
- `chi note --source broadcast` is refused: that source is `chi broadcast`'s.
|
|
41
|
+
- Web: a parent's delegates fold into its card, on the strip and in all sessions, instead of being cards of their
|
|
42
|
+
own. A `▸ 3 delegates · 1 live · 1 waiting` chip opens their list (in the card in all sessions, a popover on the
|
|
43
|
+
strip); it opens by itself while one of them waits on you, and the card then wears the warning colour. A family
|
|
44
|
+
takes one strip slot, a search finds a parent by its delegates, and select mode picks cards. A fork and a delegate
|
|
45
|
+
whose parent isn't listed stay cards of their own.
|
|
46
|
+
- guardrails 0.7.0: the `chi-broadcast` rule asks before an agent runs `chi broadcast`.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- Web: a tool row shows how long the call took while you watch the turn, as it does after a reload.
|
|
51
|
+
|
|
52
|
+
Update with `chi update` (guardrails 0.7.0, source-links 0.4.0).
|
|
53
|
+
|
|
54
|
+
## [0.34.0] - 2026-10-06
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- `delegate cwd:` starts a child in another folder of the session's repository: a worktree the model made with
|
|
59
|
+
`git worktree add`, or a subfolder. Another repository is refused.
|
|
60
|
+
- Plugins: `ctx.sessions.children` lists the session's children (state, branch, last reply and whether the parent
|
|
61
|
+
was given it), and `ctx.sessions.stop(id)` stops one of its own children.
|
|
62
|
+
- Bundles: a `files:` entry in `manifest.yml` may carry a `description:`, which the install writes into the
|
|
63
|
+
memory's `index.md` line.
|
|
64
|
+
- The `coordinator` bundle: chi coordinates parallel work. `/coordinate <goal>` (or asking for it) has chi split
|
|
65
|
+
the work into tasks, each in a child session in its own git worktree, check each report and ask you before each
|
|
66
|
+
merge. `/children` shows the session's children: state, branch, last reply and whether it was reported, with a
|
|
67
|
+
Stop button each.
|
|
68
|
+
- Guardrails: a delegate child asks before it changes anything outside its folder (its worktree): a write there,
|
|
69
|
+
git that changes the main checkout or a sibling worktree, a command run from or naming one of them. It's built in,
|
|
70
|
+
in every mode and without the guardrails bundle, and answered once or for the child's session.
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- The `delegate` and `delegate_result` tools tell the model to start a child with `wait: false` unless its turn
|
|
75
|
+
can't go on without the reply, then end its turn or keep talking with you: the reply comes back by itself as a
|
|
76
|
+
delegate report. `delegate_result` is only for a reply the turn needs now.
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- A wake turn (a context source's change, a delegate's report) that fails no longer tells the model the user's
|
|
81
|
+
message went unanswered: it says the wake wasn't answered, and that no other wake turn starts until you write.
|
|
82
|
+
For a delegate's report it adds that the report comes again with your next message.
|
|
83
|
+
- A delegate wait that timed out or was canceled says the child's reply still comes as a delegate report, instead
|
|
84
|
+
of steering the model into waiting again with `delegate_result`; so does a question's result.
|
|
85
|
+
- `delegate` with `wait: false` in a session that gets no delegate reports (a `--no-shared` REPL, `-p`) says
|
|
86
|
+
`delegate_result` waits for the reply, instead of promising a report that never comes.
|
|
87
|
+
- In a linked git worktree the system prompt no longer names the repository's main checkout ("Project root"), which
|
|
88
|
+
led a model to work and commit there: it names this checkout's top and says to work only in it. Project memories
|
|
89
|
+
and session lists still follow the repository.
|
|
90
|
+
- `delegate` refused for too many running children tells a session that gets delegate reports to end its turn (a
|
|
91
|
+
report frees a slot), instead of to wait with `delegate_result`.
|
|
92
|
+
- At a repository's root the system prompt names the checkout the project's commands run in, and calls the project
|
|
93
|
+
memories folder your notes about the project, not its files: a model no longer goes looking for the repository
|
|
94
|
+
in the memories folder.
|
|
95
|
+
|
|
96
|
+
Update with `chi update`: it installs the new `coordinator` bundle for the `dev` profile (dev 0.3.0) and updates mcp
|
|
97
|
+
(0.4.5: stops an MCP server through chi's own process-group handling).
|
|
98
|
+
|
|
11
99
|
## [0.33.0] - 2026-10-06
|
|
12
100
|
|
|
13
101
|
### Changed
|
|
@@ -1663,7 +1751,9 @@ and long-lived sessions.
|
|
|
1663
1751
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
1664
1752
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
1665
1753
|
|
|
1666
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
1754
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.35.0...HEAD
|
|
1755
|
+
[0.35.0]: https://github.com/dm1try/samagotchi/compare/v0.34.0...v0.35.0
|
|
1756
|
+
[0.34.0]: https://github.com/dm1try/samagotchi/compare/v0.33.0...v0.34.0
|
|
1667
1757
|
[0.33.0]: https://github.com/dm1try/samagotchi/compare/v0.32.0...v0.33.0
|
|
1668
1758
|
[0.32.0]: https://github.com/dm1try/samagotchi/compare/v0.31.0...v0.32.0
|
|
1669
1759
|
[0.31.0]: https://github.com/dm1try/samagotchi/compare/v0.30.0...v0.31.0
|
data/README.md
CHANGED
|
@@ -120,6 +120,7 @@ chi web --open # web UI: this project's sessions (--s
|
|
|
120
120
|
chi web --web-host lan # the web UI on your phone too: scan the QR code it prints
|
|
121
121
|
chi sessions list # this project's saved sessions (--scope=all: every one)
|
|
122
122
|
pbpaste | chi note --source slack <id> # background context for a session (no turn)
|
|
123
|
+
chi broadcast -m "payments API is down" # the same for every session it concerns (a shared ticket, PR or link)
|
|
123
124
|
chi context add <PR URL> <id> # attached context: chi keeps it fresh, the agent hears when it changes
|
|
124
125
|
pbpaste | chi send -m "same bug?" <id> # a message to a session, the clipboard quoted above it
|
|
125
126
|
chi send --new --wait -m "review feat/x" # a new session you can watch in the web; prints the answer
|
|
@@ -145,7 +146,10 @@ never takes orders from. The web and the attached terminal show it as a dim
|
|
|
145
146
|
a note reaches (`id<TAB>description`). Agents can do the same: `list_sessions`
|
|
146
147
|
finds another session, `send_note` tells it something, and `delegate` hands a
|
|
147
148
|
task to a child session that runs in parallel and reports back only its final
|
|
148
|
-
reply (a normal session: `chi --attach <id>` steers it).
|
|
149
|
+
reply (a normal session: `chi --attach <id>` steers it). With the `coordinator`
|
|
150
|
+
bundle (in `dev`), `/coordinate <goal>` has chi split the work into tasks, each
|
|
151
|
+
in a child session in its own git worktree, check each report and ask you
|
|
152
|
+
before each merge; `/children` shows the children and their state.
|
|
149
153
|
|
|
150
154
|
`chi send` is the other half: the text goes in as your message, the same as
|
|
151
155
|
typing it in the attached terminal or the web composer, and a turn runs. Piped
|
|
@@ -199,6 +203,7 @@ once, for the session, for the repo, or for the whole rule in the repo.
|
|
|
199
203
|
- [Memory](docs/memory.md): scopes and model-specific overlays
|
|
200
204
|
- [Sessions](docs/sessions.md): storage, retention, `chi sessions`
|
|
201
205
|
- [Attached context](docs/context.md): `chi context`, sources, scopes, waking, the github-pr bundle, safety
|
|
206
|
+
- [Broadcast](docs/broadcast.md): `chi broadcast`, who a note reaches, tags, what a session gets
|
|
202
207
|
- [chi as a sub-agent](docs/sub-agent.md): `chi send --wait --format json`, `chi answer`, instructions for a parent agent
|
|
203
208
|
- [Desktop helper](docs/desktop.md): `chi desktop`, the macOS "Send to chi" Service and hotkey
|
|
204
209
|
- [Guardrails](docs/guardrails.md): allow / ask / deny for tool calls, rules, approvals
|
data/bin/chi
CHANGED
|
@@ -40,6 +40,8 @@ SUBCOMMANDS = {
|
|
|
40
40
|
"sessions" => ["samagotchi/sessions_command", "SessionsCommand"],
|
|
41
41
|
# a context note for sessions (-m, --source, --all)
|
|
42
42
|
"note" => ["samagotchi/note_command", "NoteCommand"],
|
|
43
|
+
# a note for every session it may concern (-m, --all, --dry-run)
|
|
44
|
+
"broadcast" => ["samagotchi/broadcast_command", "BroadcastCommand"],
|
|
43
45
|
# live external text attached to sessions (add, push, ls, show, rm, mute)
|
|
44
46
|
"context" => ["samagotchi/context_command", "ContextCommand"],
|
|
45
47
|
# a message into sessions as the user's (-m)
|
|
@@ -95,6 +97,7 @@ parser = OptionParser.new do |opts|
|
|
|
95
97
|
chi web [--port PORT] [--open] [--scope=all] the web UI
|
|
96
98
|
chi sessions <list|stop|archive|unarchive|delete|prune|clean>
|
|
97
99
|
chi note [--source NAME] [-m TEXT] ID...|--all background context for sessions
|
|
100
|
+
chi broadcast [-m TEXT] [--all] [--dry-run] a note for every session it may concern
|
|
98
101
|
chi context <add|push|ls|show|refresh|rm|mute|unmute> live external text attached to sessions
|
|
99
102
|
chi send [-m TEXT] ID...|--new a message into sessions, as if typed there
|
|
100
103
|
chi answer ID --question QID --option N answer a question a session waits on
|
data/docs/broadcast.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Broadcast
|
|
2
|
+
|
|
3
|
+
`chi broadcast` shares one piece of information with every session it may
|
|
4
|
+
concern, without picking them: "payments API returns 500 since 14:00 (PAY-123)",
|
|
5
|
+
"the PRD for checkout v2 changed: no guest checkout". Each session it reaches
|
|
6
|
+
gets it as a [context note](sessions.md#context-notes) from `broadcast`, and
|
|
7
|
+
that session's agent decides whether it affects its work. Sessions it doesn't
|
|
8
|
+
concern never see it.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
chi broadcast -m "payments API returns 500 since 14:00 (PAY-123)"
|
|
12
|
+
pbpaste | chi broadcast # the note from stdin
|
|
13
|
+
chi broadcast --dry-run -m "…" # who would get it and why; nothing is delivered
|
|
14
|
+
chi broadcast --all -m "deploy freeze until 18:00" # every recipient, tag or not
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
To tell one session or a few you picked, use `chi note ID...` instead.
|
|
18
|
+
|
|
19
|
+
## Who it reaches
|
|
20
|
+
|
|
21
|
+
The recipients are your own sessions, in every project:
|
|
22
|
+
|
|
23
|
+
- a worker or a chi REPL runs them now, or their last turn ended within
|
|
24
|
+
`broadcast.active_hours` (default 8). A session with no turn yet counts
|
|
25
|
+
by its last save;
|
|
26
|
+
- not a delegate child: its parent relays what concerns it (the
|
|
27
|
+
`coordinator`'s builders included). A fork is your session and counts;
|
|
28
|
+
- not a `chi scratch` session, not an archived one, and not a test run
|
|
29
|
+
(unless `chi broadcast` itself runs as one, `SAMAGOTCHI_ENV=test`).
|
|
30
|
+
|
|
31
|
+
A session open in a plain chi REPL (`--no-shared`) can't take notes: it is
|
|
32
|
+
listed as skipped, "open in a chi REPL".
|
|
33
|
+
|
|
34
|
+
## Tags: which sessions it concerns
|
|
35
|
+
|
|
36
|
+
A recipient gets the note when the note and the session share a tag:
|
|
37
|
+
|
|
38
|
+
| Tag | In the note | About the session |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| ticket | an id like `PAY-123` (`broadcast.ticket_pattern`) | its branch (any case: `feat/pay-123-retry`), your prompts there |
|
|
41
|
+
| pr | `PR #42`, a GitHub pull request URL | an attached `pr-42` source (the github-pr bundle), a PR URL in your prompts there |
|
|
42
|
+
| link | a URL, by host and path | a URL in your prompts there or in an attached context source's hint |
|
|
43
|
+
|
|
44
|
+
A link is compared without its scheme, `www.`, query, fragment or trailing
|
|
45
|
+
slash; a bare host (`https://github.com/`) is no tag. A PR URL names its repo,
|
|
46
|
+
so `acme/shop#42` doesn't match `acme/other#42`; `PR #42` with no repo matches
|
|
47
|
+
pull request 42 of any repo. Words the default ticket pattern would take that
|
|
48
|
+
are no ticket (`UTF-8`, `SHA-256`, `ISO-8601`, `GPT-4`, …) are left out.
|
|
49
|
+
|
|
50
|
+
A session that shares no tag is skipped for now, listed as "no tag match (not
|
|
51
|
+
checked: no triage yet)": a small triage model that reads the note and each
|
|
52
|
+
session's scope card is the next step. Until then, `--all` reaches them all.
|
|
53
|
+
|
|
54
|
+
## What it prints
|
|
55
|
+
|
|
56
|
+
One line per recipient, the ones that got it first, then a summary:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
broadcast "payments API returns 500 since 14:00 (PAY-123)"
|
|
60
|
+
3f2a1c9e delivered ticket PAY-123 matches (branch)
|
|
61
|
+
91ab02c4 delivered link notion.so/team/checkout-v2 matches (messages); waits for its next start
|
|
62
|
+
c0ffee12 skipped no tag match (not checked: no triage yet)
|
|
63
|
+
d00dad00 skipped open in a chi REPL
|
|
64
|
+
delivered 2 · skipped 2
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
A session a worker runs adds the note within a few seconds (after a running
|
|
68
|
+
turn); one with no worker gets it at its next start ("waits for its next
|
|
69
|
+
start"). Nothing starts a turn anywhere.
|
|
70
|
+
|
|
71
|
+
`--dry-run` prints the note's tags, each recipient's verdict ("would get it" or
|
|
72
|
+
"skipped") and its scope card: what chi knows about it from local state, and
|
|
73
|
+
what a triage model will read.
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
3f2a1c9e would get it ticket PAY-123 matches (branch)
|
|
77
|
+
project: shop (folder ../shop-pay, branch feat/pay-123-retry)
|
|
78
|
+
title: shop-pay · now the retry spec
|
|
79
|
+
tags: ticket PAY-123 · pr acme/shop#42
|
|
80
|
+
started: Fix the payments retry …
|
|
81
|
+
recap: Fixing the payments retry. Specs next.
|
|
82
|
+
recent: now the retry spec
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Exit status: 0 when it ran (skipped sessions included), 1 when it was refused,
|
|
86
|
+
no session is active or a delivery failed, 2 for a usage error.
|
|
87
|
+
|
|
88
|
+
## What a session gets
|
|
89
|
+
|
|
90
|
+
The note is your text, then one line chi adds:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
[CONTEXT NOTE from broadcast, 14:20]
|
|
94
|
+
payments API returns 500 since 14:00 (PAY-123)
|
|
95
|
+
(Shared by your user on 2026-10-06 14:20 with the sessions it may concern; it reached you because ticket PAY-123 matches your branch.)
|
|
96
|
+
[END NOTE]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
With `--all` the line says "with every active session". The date is there
|
|
100
|
+
because a session with no worker may read it days later. The system prompt
|
|
101
|
+
tells the model what a note from `broadcast` is: if it affects its current
|
|
102
|
+
work, it says so briefly in its next answer, otherwise it ignores it, and it
|
|
103
|
+
doesn't act on it unless you ask. Other notes keep their rule (background,
|
|
104
|
+
not mentioned on their own). `chi note --source broadcast` is refused, so a
|
|
105
|
+
plain note can't pass for a broadcast.
|
|
106
|
+
|
|
107
|
+
The note and its line together are capped at 16 KiB like any note; the text
|
|
108
|
+
may take up to 15872 bytes.
|
|
109
|
+
|
|
110
|
+
## For you, not for an agent
|
|
111
|
+
|
|
112
|
+
`chi broadcast` refuses to run inside a chi session (where
|
|
113
|
+
`SAMAGOTCHI_PARENT_SESSION` is set): "chi broadcast is for your user, not an
|
|
114
|
+
agent". With the guardrails bundle, the `chi-broadcast` rule also asks before
|
|
115
|
+
any shell command that runs it, once at a time, and only you may allow it
|
|
116
|
+
(a parent agent's `chi answer` can't). See [Guardrails](guardrails.md).
|
|
117
|
+
|
|
118
|
+
## Settings
|
|
119
|
+
|
|
120
|
+
| Setting | Default | What it does |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `broadcast.active_hours` | `8` | A session with no worker or REPL counts when its last turn ended within this many hours. |
|
|
123
|
+
| `broadcast.ticket_pattern` | `\b[A-Z][A-Z0-9]+-\d+\b` | A Ruby regex for ticket ids; an invalid one warns and the default is used. |
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
broadcast:
|
|
127
|
+
active_hours: 12
|
|
128
|
+
ticket_pattern: '\b(?:PAY|OPS)-\d+\b'
|
|
129
|
+
```
|
data/docs/cli.md
CHANGED
|
@@ -790,11 +790,19 @@ changes:
|
|
|
790
790
|
|
|
791
791
|
```
|
|
792
792
|
status> model=Qwen3.6-35B | ↳ 3f2a1c9e | ctx=12.3% (under20) | mem: notes, cli_usage | muted: gh-helper
|
|
793
|
+
status> model=Qwen3.6-35B | ⑂ 2 running · 1 waiting | ctx=8.1% (under20) | mem: skill_coordinator
|
|
793
794
|
```
|
|
794
795
|
|
|
795
796
|
- `model=`: the model in use, `(default: …)` beside it when it isn't the config's default, and
|
|
796
797
|
`model=<served> (served; asked <name>)` when the server said it served another model.
|
|
797
798
|
- `↳ <id>`: the session that delegated this one.
|
|
799
|
+
- `⑂ …`: this session's delegate children (forks aren't counted): how many run and how many wait
|
|
800
|
+
for an answer; only the counts there are, nothing when none does (`/children` has the rest:
|
|
801
|
+
done, failed, whether a reply was reported). The terminal reads them from the children's files
|
|
802
|
+
(the delegates in the session's `delegates.json`): an attached one when it joins, when a turn
|
|
803
|
+
ends and when a delegate's report merges into a turn, the REPL whenever it draws the row. A
|
|
804
|
+
child that starts waiting on an approval (which doesn't wake the parent) shows at the next of
|
|
805
|
+
those.
|
|
798
806
|
- `ctx=`: the kernel's context estimate and its bucket, updated during a turn (on hosts that
|
|
799
807
|
report none, `api: openai`, at the turn's end).
|
|
800
808
|
- `mem:`: the memories the session read, with its `--memory` list; `muted:` its `--mute` list.
|
data/docs/configuration.md
CHANGED
|
@@ -882,6 +882,8 @@ described in their own sections.
|
|
|
882
882
|
| `recap.timeout` | `30` | yes | Seconds a recap request may take. |
|
|
883
883
|
| `recap.min_user_turns` | `2` | yes | Prompts a session needs before it gets a recap. |
|
|
884
884
|
| `recap.sentences` | `2-4` | yes | Recap length, `N` or `N-M` (1–10). |
|
|
885
|
+
| `broadcast.active_hours` | `8` | | `chi broadcast` reaches a session a worker or a chi REPL runs, or whose last turn ended within this many hours. See [Broadcast](broadcast.md). |
|
|
886
|
+
| `broadcast.ticket_pattern` | `\b[A-Z][A-Z0-9]+-\d+\b` | | A Ruby regex for ticket ids; one in the note and in a session's branch (any case) or prompts delivers the broadcast there. See [Broadcast](broadcast.md). |
|
|
885
887
|
| `session.shared` | `true` | | Plain `chi` runs its session in a worker and attaches; `--no-shared` per run. |
|
|
886
888
|
| `session.idle_exit_minutes` | `30` | yes | An unused worker exits after this; `0` = never. |
|
|
887
889
|
| `session.keep_empty` | `false` | | Keep sessions nothing happened in. |
|
data/docs/context.md
CHANGED
|
@@ -154,6 +154,11 @@ update note, whose last line becomes:
|
|
|
154
154
|
Every UI labels the turn `context <name> changed`, and the web's
|
|
155
155
|
notifications count it as a finished turn however short.
|
|
156
156
|
|
|
157
|
+
A wake turn that fails goes back to before it and keeps the update as a
|
|
158
|
+
plain note; the model reads `[SYSTEM: the previous turn failed before any
|
|
159
|
+
answer: … The wake turn for the change in attached context <name> was not
|
|
160
|
+
answered; chi starts no other wake turn until the user writes.]`.
|
|
161
|
+
|
|
157
162
|
## GitHub PRs: the github-pr bundle
|
|
158
163
|
|
|
159
164
|
```sh
|
data/docs/guardrails.md
CHANGED
|
@@ -5,13 +5,14 @@ loops (native and chat hosts). The verdict is **allow**, **ask** or
|
|
|
5
5
|
**deny**; the strictest vote wins, and a deny can't be undone by a later
|
|
6
6
|
voter. Of two asks the first one names the rule, except a rule only the
|
|
7
7
|
user may allow (`chi-config`, `chi-hooks`, `shell-touches-chi`,
|
|
8
|
-
`chi-context-cmd`): it takes over, and only the scopes both asks offer
|
|
8
|
+
`chi-context-cmd`, `chi-broadcast`): it takes over, and only the scopes both asks offer
|
|
9
9
|
are offered.
|
|
10
10
|
|
|
11
11
|
Who votes, in order:
|
|
12
12
|
|
|
13
13
|
1. `before_tool_call` hooks (Ruby; see [Hooks](hooks.md#guardrails-from-a-hook)).
|
|
14
|
-
2. Core checks: a required guardrail that failed to load, then protected paths
|
|
14
|
+
2. Core checks: a required guardrail that failed to load, then protected paths, then (a delegate child only)
|
|
15
|
+
[the child boundary](#a-delegate-childs-boundary).
|
|
15
16
|
3. YAML rules: `config.yml`'s `guardrails:` section, then installed bundles' rule files (by bundle name).
|
|
16
17
|
|
|
17
18
|
The UI shows the tool line first, then the approval under it.
|
|
@@ -189,6 +190,35 @@ Built in, for `write`, `edit` and `memory_write` (symlinks resolved):
|
|
|
189
190
|
`execute` can still reach them; the guardrails bundle asks about shell
|
|
190
191
|
commands that name them.
|
|
191
192
|
|
|
193
|
+
## A delegate child's boundary
|
|
194
|
+
|
|
195
|
+
Built in, for [delegate](sessions.md#delegating) children only, in every
|
|
196
|
+
mode (also with `guardrails.enabled: false`) and without the guardrails
|
|
197
|
+
bundle: a child asks before it changes anything outside its folder, the work
|
|
198
|
+
tree top of the folder it was started in (a worktree from `delegate cwd:`,
|
|
199
|
+
else the parent's checkout). Rule `child-boundary`, source `core`; it asks when
|
|
200
|
+
|
|
201
|
+
- `write` or `edit` names a path outside it (tmp dirs and memory files don't count);
|
|
202
|
+
- `execute` or `task_create` runs mutating git in another dir (`git -C`, `cd`,
|
|
203
|
+
`GIT_DIR`: what `git: outside_repo` matches), or a command that isn't
|
|
204
|
+
read-only starts outside it (its `cwd:`) or names a path in the repository's
|
|
205
|
+
other checkouts (the main one and sibling worktrees, read from
|
|
206
|
+
`<common git dir>/worktrees/*/gitdir`) or in its common git dir;
|
|
207
|
+
- `execute` or `task_create` runs git that changes what every checkout shares,
|
|
208
|
+
even from its own worktree: a `git config` write (not `--get`, `--list`,
|
|
209
|
+
`--worktree`), `update-ref`, `worktree add|remove|move|prune`, `stash
|
|
210
|
+
drop|clear|pop`, creating or deleting a tag, and deleting, forcing or
|
|
211
|
+
overwriting a branch other than its own.
|
|
212
|
+
|
|
213
|
+
Read-only commands (`git -C ../app log`, `cat ../app/x`) and paths elsewhere
|
|
214
|
+
(`/usr/bin`, `~/.gem`) never ask. The answer is once or for the child's
|
|
215
|
+
session only: a repo or rule answer would hold in every worktree, for every
|
|
216
|
+
child, so a stored repo or rule approval doesn't let it through either. Its
|
|
217
|
+
ask goes before the rules, so with the guardrails bundle in strict mode the
|
|
218
|
+
card still names `child-boundary`. The parent (never a delegate), forks and
|
|
219
|
+
ordinary sessions don't get it. Like the rules it reads command text: a
|
|
220
|
+
`sh -c` body, a script or `$(…)` isn't looked into.
|
|
221
|
+
|
|
192
222
|
## Rules in config.yml
|
|
193
223
|
|
|
194
224
|
```yaml
|
|
@@ -397,7 +427,9 @@ hooks, approvals, bundles or attached context sources, or a `.git/hooks`
|
|
|
397
427
|
(`shell-touches-chi`, `touches: chi_dirs`), unless they only read
|
|
398
428
|
(`skip_read_only`); `chi context add … --cmd` (`chi-context-cmd`, once at a
|
|
399
429
|
time: a command chi will run every few minutes outside the guardrails; see
|
|
400
|
-
[Attached context](context.md#safety));
|
|
430
|
+
[Attached context](context.md#safety)); `chi broadcast` (`chi-broadcast`,
|
|
431
|
+
once at a time and only by the user: it is the user's command, which also
|
|
432
|
+
refuses to run inside a session; see [Broadcast](broadcast.md)); and answering chi's
|
|
401
433
|
questions around `chi answer`: `chi --attach` or `chi -p` with stdin from a
|
|
402
434
|
pipe, a here-string or a file (`chi-answer-piped`), and `curl`/`wget` to a
|
|
403
435
|
session's `/answer` route (`chi-answer-http`), both once or for the session.
|
data/docs/hooks.md
CHANGED
|
@@ -82,6 +82,8 @@ class Watchful
|
|
|
82
82
|
when :after_generation
|
|
83
83
|
# One line in the REPL, the attached TUI and the web ("<bundle>> text",
|
|
84
84
|
# or "hook> text" for a config hook); level: :warn colours it.
|
|
85
|
+
# fallback_for: :display marks a line a UI that renders the answer's
|
|
86
|
+
# display may leave out (below).
|
|
85
87
|
event[:notify].call("the model repeated itself", level: :warn)
|
|
86
88
|
when :before_tool_call
|
|
87
89
|
# A single-select question through the question flow (REPL, attached
|
|
@@ -114,6 +116,21 @@ end
|
|
|
114
116
|
known-names)` for a bundle hook, `audit.rb (config)` for a config hook,
|
|
115
117
|
`turn hook` for one registered at runtime.
|
|
116
118
|
|
|
119
|
+
`event[:notify]` also takes `fallback_for:`, what the line stands in for, so
|
|
120
|
+
that a UI that already shows it can leave the line out. The one value is
|
|
121
|
+
`:display`: the line repeats what the hook's
|
|
122
|
+
[`event[:present]`](#presenting-the-answer-display-only) display shows (its
|
|
123
|
+
links), for a UI that doesn't render that display. The hook never names a UI;
|
|
124
|
+
each decides by what it renders. The web with markdown on (`web.markdown` and
|
|
125
|
+
the commonmarker gem) leaves such a line out, live and after a reload; with
|
|
126
|
+
markdown off it shows, as it does in the REPL, the attached TUI and
|
|
127
|
+
`chi -p`, which print the answer as text. The log keeps the line with
|
|
128
|
+
`fallback_for=display`. Another value, or none, shows the line everywhere.
|
|
129
|
+
Mark a line only when the display really shows all of it (source-links marks
|
|
130
|
+
its note only when the answer links every URL the note names). It needs chi
|
|
131
|
+
0.35.0: an older chi's `event[:notify]` raises `ArgumentError` on the keyword,
|
|
132
|
+
so a bundle that passes it sets `requires_chi: ">= 0.35.0"`.
|
|
133
|
+
|
|
117
134
|
A steer is saved in the session as `{role: "user", kind: "steer", source:
|
|
118
135
|
"<bundle>", content: "…"}`, its text raw. The model reads it as a user turn
|
|
119
136
|
led by one line naming the sender: `[Steer from the <bundle> plugin,
|
|
@@ -420,7 +437,7 @@ stripped of surrounding whitespace, except file text, an edit's
|
|
|
420
437
|
| `list_sessions` | — | — | `cwd` |
|
|
421
438
|
| `send_note` | `text` | — | `session` |
|
|
422
439
|
| `context_read` | `name` | — | `offset`, `limit` |
|
|
423
|
-
| `delegate` | `task` | — | `model`, `session`, `wait`, `timeout` |
|
|
440
|
+
| `delegate` | `task` | — | `model`, `session`, `cwd`, `wait`, `timeout` |
|
|
424
441
|
| `delegate_result` | — | — | `session`, `timeout` |
|
|
425
442
|
| `ask_user_question` | `question` | — | `question`, `options`, `header`, `multi_select`, `allow_freeform` |
|
|
426
443
|
|
|
@@ -504,8 +521,8 @@ sources: JIRA JIRA-123 → https://myjira.com/browse/JIRA-123, JIRA JIRA-10 →
|
|
|
504
521
|
```
|
|
505
522
|
|
|
506
523
|
The note is **not part of the conversation**: it is an event shown to the
|
|
507
|
-
user, never stored in the session file. A UI replays it
|
|
508
|
-
|
|
524
|
+
user, never stored in the session file. A UI replays it with the session's
|
|
525
|
+
cards (a page reload keeps it, after the worker stopped too). Only the
|
|
509
526
|
model's final answer is scanned (the last `role: "model"` message), and only
|
|
510
527
|
the first 20 000 characters of it. A ref that is already a link is skipped —
|
|
511
528
|
inside a bare URL (`https://x.com/JIRA-123`), in a markdown link's target, or
|
|
@@ -543,7 +560,11 @@ text stays as it was, and the links survive a reload and a stopped worker
|
|
|
543
560
|
apply, and a ref in code (a `` `span` `` or a fenced block) or anywhere in a
|
|
544
561
|
markdown link is left as it is; past the first 20 000 characters the answer
|
|
545
562
|
is unchanged. The terminals see only the line; `note: false` drops it and
|
|
546
|
-
keeps the web links.
|
|
563
|
+
keeps the web links. With markdown on, the web leaves the line out when the
|
|
564
|
+
answer links every URL it names, since it would only repeat them as plain
|
|
565
|
+
text ([`fallback_for: :display`](#what-a-hook-can-do-the-runtime)); it shows
|
|
566
|
+
when it names one the answer doesn't link (a ref only in code, two sources on
|
|
567
|
+
one ref) and whenever markdown is off. Bundle 0.4.0 needs chi 0.35.0 for that.
|
|
547
568
|
|
|
548
569
|
The `prefix:` form compiles to `\b<prefix>-(\d+)\b` and the URL is
|
|
549
570
|
`base_url` + the full ref text (`JIRA-123`). The `pattern:` form takes a
|
data/docs/memory.md
CHANGED
|
@@ -102,6 +102,22 @@ for a file another bundle installed.
|
|
|
102
102
|
`- **memory_guide** · system · 2026-10-03 · 5120 · from samagotchi-system —
|
|
103
103
|
…`. `memory_write`, `write` and `edit` keep it. A bundle installed by chi
|
|
104
104
|
0.16 or earlier gets it on its next install or upgrade.
|
|
105
|
+
- **A bundle can give a memory its index description.** A `files:` entry
|
|
106
|
+
may be a mapping instead of a sha line:
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
files:
|
|
110
|
+
identity.md: sha256:…
|
|
111
|
+
skill_coordinator.md:
|
|
112
|
+
sha256: sha256:…
|
|
113
|
+
description: "Coordinate parallel work: …"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The install writes that description into the memory's `index.md` line
|
|
117
|
+
(after `— `), so the model can tell what a shipped skill is for from the
|
|
118
|
+
index alone. The bundle's record keeps it, `chi bundle build` writes the
|
|
119
|
+
mapping back, and `rake bundles:sha` refreshes the nested sha. A file
|
|
120
|
+
with a plain sha line keeps the description its line already has.
|
|
105
121
|
- **Uninstall moves, it doesn't delete.** The bundle's memory files go to
|
|
106
122
|
`$XDG_CONFIG_HOME/samagotchi/memories/.bundles/.trash/<bundle>-<YYYYmmdd-HHMMSS>/`,
|
|
107
123
|
and the output names them and the dir:
|
|
@@ -133,7 +149,7 @@ profiles, meta bundles that install a set of them:
|
|
|
133
149
|
| profile | bundles |
|
|
134
150
|
|---|---|
|
|
135
151
|
| `core` | loop-guard, check-in, guardrails: the recommended safety set |
|
|
136
|
-
| `dev` | known-names, mcp, btw, skills, source-links |
|
|
152
|
+
| `dev` | known-names, mcp, btw, skills, source-links, github-pr, coordinator |
|
|
137
153
|
|
|
138
154
|
`chi bootstrap` installs `core` and, on a terminal, offers `dev`. An existing
|
|
139
155
|
install gets neither by itself: `chi bundle install core` (or `dev`).
|
data/docs/plugins.md
CHANGED
|
@@ -488,7 +488,7 @@ full label, `plugin.rb (bundle my-bundle)`.
|
|
|
488
488
|
| `ctx.log` | `ctx.log.info(:event, key: value)`: debug-log records tagged `plugins`, with `bundle=<bundle>` |
|
|
489
489
|
| `ctx.messages` | the conversation, as a frozen copy, without the system prompt. While a turn runs, a session worker's (attached, web) adds that turn so far: its prompt, the model's text and the lines merged into it (no tool calls or thinking); the REPL's is the conversation before that turn |
|
|
490
490
|
| `ctx.messages_partial?` | whether `ctx.messages` leaves out a running turn (the REPL mid-turn), so a plugin can say what its answer is about |
|
|
491
|
-
| `ctx.notify(text, level: :info)` | one line to the user, labelled by the bundle (`my-bundle> …`). Every UI shows it, during a turn (a tool, a hook) or between turns (a command) |
|
|
491
|
+
| `ctx.notify(text, level: :info, fallback_for: nil)` | one line to the user, labelled by the bundle (`my-bundle> …`). Every UI shows it, during a turn (a tool, a hook) or between turns (a command). `fallback_for: :display` marks a line that repeats the answer's display (`event[:present]`), which a UI that renders the display leaves out: see [Hooks](hooks.md#what-a-hook-can-do-the-runtime). The keyword needs chi 0.35.0 (it raises on an older chi) |
|
|
492
492
|
| `ctx.card(title:, body: "", actions: [], level: :info, id: nil)` | a card in every UI, returning its id: see [Cards](#cards) |
|
|
493
493
|
| `ctx.ask_user(question:, options:, header: nil, allow_freeform: false)` | a single-select question through the question flow: `{selected:, freeform:, selected_indices:}`, or nil (no one to ask, cancelled, bad options) |
|
|
494
494
|
| `ctx.cancelled?` | whether the running turn was cancelled (a long tool should stop) |
|
|
@@ -496,7 +496,7 @@ full label, `plugin.rb (bundle my-bundle)`.
|
|
|
496
496
|
| `ctx.stop_turn(reason)` | stop the running turn after a warn notice with the reason; true when it stopped one now. In a `:before_tool_call` block it also denies that call |
|
|
497
497
|
| `ctx.stop_generation(reason)` | cut the generation that is streaming: the turn goes on and the model is asked again ([hooks.md](hooks.md#watching-the-stream)). Shows nothing: post your own notice. True when it cut one now |
|
|
498
498
|
| `ctx.ask_model(messages:, prompt:, …)` | a side answer from the session's model: see [Side answers](#side-answers-ctxask_model) |
|
|
499
|
-
| `ctx.sessions` | fork, send to and
|
|
499
|
+
| `ctx.sessions` | fork, send to, read, list and stop other sessions: see [Other sessions](#other-sessions-ctxsessions) |
|
|
500
500
|
| `ctx.context` | attach outside text to this session and list it: see [Attached context](#attached-context-ctxcontext) |
|
|
501
501
|
|
|
502
502
|
The Engine itself is never handed to a plugin.
|
|
@@ -608,7 +608,9 @@ llama.cpp serves on a native host too.
|
|
|
608
608
|
id = ctx.sessions.fork(messages: ctx.messages + [{ role: "user", content: q }, { role: "model", content: a }],
|
|
609
609
|
title: "btw: #{q}")
|
|
610
610
|
ctx.sessions.send(id, "go on from here")
|
|
611
|
-
ctx.sessions.read(id)
|
|
611
|
+
ctx.sessions.read(id) # => {id:, title:, status:, parent_id:, running:, messages:}
|
|
612
|
+
ctx.sessions.children # => [{id:, short_id:, state:, branch:, last_reply:, reported:, ...}]
|
|
613
|
+
ctx.sessions.stop(id) # one of this session's own children
|
|
612
614
|
```
|
|
613
615
|
|
|
614
616
|
- `fork(messages:, title: nil, prompt: nil)` starts a child session in its
|
|
@@ -629,6 +631,23 @@ ctx.sessions.read(id) # => {id:, title:, status:, parent_id:, running:, message
|
|
|
629
631
|
- `read(id)` gives a session now: from its worker when one runs (with a
|
|
630
632
|
running turn so far, `running: true`), else as saved. `messages` has no
|
|
631
633
|
system prompt.
|
|
634
|
+
- `children(all: false)` lists this session's children, newest first, as
|
|
635
|
+
frozen Hashes: `{id:, short_id:, title:, state:, waiting:, live:,
|
|
636
|
+
delegate:, cwd:, branch:, last_reply:, last_reply_at:, reported:,
|
|
637
|
+
updated_at:, archived:}`.
|
|
638
|
+
- `state` is `waiting` (a question or approval is open; `waiting` says
|
|
639
|
+
which), `running`, `failed` (the last turn failed or the worker
|
|
640
|
+
crashed), `stopped`, `done` (the last turn ended with a reply) or `idle`.
|
|
641
|
+
- `delegate` is true for a `delegate` child, false for a fork. Archived
|
|
642
|
+
children are listed only with `all: true`.
|
|
643
|
+
- `branch` is the branch checked out in the child's folder (read from its
|
|
644
|
+
`HEAD`, a short sha when detached; nil outside git). `last_reply` is the
|
|
645
|
+
first line of its newest reply, and `reported` says whether this session
|
|
646
|
+
was already given that reply (a delegate report or a wait).
|
|
647
|
+
- It reads every session's file: call it on demand, not in a loop.
|
|
648
|
+
- `stop(id)` stops one of this session's own children, as
|
|
649
|
+
`chi sessions stop` does, and waits up to 2 s for its worker to let go. It
|
|
650
|
+
returns the child's id. Any other session raises.
|
|
632
651
|
- Each raises `Samagotchi::Plugin::Sessions::Error` with the reason.
|
|
633
652
|
|
|
634
653
|
## Attached context: `ctx.context`
|
|
@@ -1120,6 +1139,62 @@ and a summary of what changed in counts, authors and states only; it wakes
|
|
|
1120
1139
|
the session for a review requesting changes, checks turning red, or the PR
|
|
1121
1140
|
merged or closed. See [Attached context](context.md#github-prs-the-github-pr-bundle).
|
|
1122
1141
|
|
|
1142
|
+
## The coordinator bundle
|
|
1143
|
+
|
|
1144
|
+
```sh
|
|
1145
|
+
chi bundle install coordinator # in the dev profile
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
chi as a coordinator of parallel work, the way you would run several agents
|
|
1149
|
+
yourself: split the work, one git worktree and child session per task, keep
|
|
1150
|
+
talking while they run, check each report, and merge only with your OK. It
|
|
1151
|
+
works in a session with a worker (plain `chi`, the web). A `--no-shared` REPL
|
|
1152
|
+
or `-p` gets no delegate reports, so the children's replies wouldn't come back
|
|
1153
|
+
by themselves there.
|
|
1154
|
+
|
|
1155
|
+
- **The skill.** `skill_coordinator` (system scope; its index line says what
|
|
1156
|
+
it is for, from the manifest's `description:`) holds the steps. The model
|
|
1157
|
+
creates each worktree with `execute` (`git worktree add ../<repo>-<task> -b
|
|
1158
|
+
<branch>`), starts a child there with `delegate wait: false, cwd:`, tells
|
|
1159
|
+
you what started and ends its turn. When a child's report comes, it checks
|
|
1160
|
+
the branch (`git log`, `git diff --stat`, the tests the child names) before
|
|
1161
|
+
telling you. It asks before each merge (`ask_user_question`), checks that its
|
|
1162
|
+
own folder is on the default branch and that branch's log first (another
|
|
1163
|
+
agent may have merged the branch already), merges `--ff-only` and never
|
|
1164
|
+
pushes unless you ask. After a merge it stops the
|
|
1165
|
+
child and removes only the worktrees and branches it made.
|
|
1166
|
+
- **`/coordinate <goal>`** sends this session a turn asking the model to
|
|
1167
|
+
follow the skill for the goal (in a `--no-shared` REPL it shows the text to
|
|
1168
|
+
send yourself). Asking "do this in parallel" works too: the index line leads
|
|
1169
|
+
the model to the skill.
|
|
1170
|
+
- **`/children [all]`** shows the session's children as a card, newest first,
|
|
1171
|
+
one line each: `` `ab12cd34` · running · fix/flaky · "fix the flaky spec" ``,
|
|
1172
|
+
`` `9a8b7c6d` · done · feat/x · reported · "All 12 specs pass" `` (`not
|
|
1173
|
+
reported yet` when the parent wasn't given that reply), `` `77aa66bb` ·
|
|
1174
|
+
waiting (approval) · open it: chi --attach 77aa66bb ``. A fork is marked
|
|
1175
|
+
`fork`; `all` adds archived children. It runs during a turn too. The card
|
|
1176
|
+
has Refresh and a `Stop <id>` per running or waiting child (up to 5);
|
|
1177
|
+
`/children stop <id>` stops one of this session's own children (by session
|
|
1178
|
+
id, as `chi sessions stop` does) and shows the card again.
|
|
1179
|
+
- **Children stay in their worktree.** A child asks before it changes
|
|
1180
|
+
anything outside its worktree (your checkout, a sibling's), in every
|
|
1181
|
+
guardrails mode and without the guardrails bundle ([a delegate child's
|
|
1182
|
+
boundary](guardrails.md#a-delegate-childs-boundary)); you answer on its
|
|
1183
|
+
card, or on the parent's while it waits.
|
|
1184
|
+
- **Merges.** The parent's merge in its own checkout is a plain `git
|
|
1185
|
+
merge`; to be asked before every merge, add a rule ([Rules in
|
|
1186
|
+
config.yml](guardrails.md#rules-in-configyml)):
|
|
1187
|
+
|
|
1188
|
+
```yaml
|
|
1189
|
+
guardrails:
|
|
1190
|
+
rules:
|
|
1191
|
+
- id: git-merge
|
|
1192
|
+
tool: shell
|
|
1193
|
+
command: '\bgit\s+merge\b'
|
|
1194
|
+
verdict: ask
|
|
1195
|
+
reason: merging a child's branch
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1123
1198
|
## Shutdown
|
|
1124
1199
|
|
|
1125
1200
|
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, and the profiles core and dev) has its own semver in its
|
|
16
|
+
loop-guard, mcp, skills, source-links, github-pr, coordinator, 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:`
|