feat(opencode): monitor delivery via opencode-sentinel plugin - #547
feat(opencode): monitor delivery via opencode-sentinel plugin#547tsukimiya wants to merge 6 commits into
Conversation
… run --interactive opencode 1.17.15's `opencode run --interactive` exits as soon as the boot prompt's turn completes, so the spawned worker never stays resident and cannot receive further agmsg messages. `opencode --prompt "<text>"` (TUI mode) auto-sends the initial prompt and keeps the TUI resident, confirmed by live testing. Switch the manifest to the existing prompt_arg mechanism already used by copilot/antigravity instead of a fixed multi-word cli prefix.
Companion to the previous spawn --prompt switch: updates README.md, README.ja.md, and docs/opencode.md so they no longer claim spawn is unsupported for opencode. monitor/both stay listed as unsupported (real-time push is a separate concern, addressed in a follow-up).
There was a problem hiding this comment.
Pull request overview
Adds a new monitor delivery mode for the OpenCode agent type by generating an OpenCode rule that instructs use of the external opencode-sentinel plugin’s sentinel_monitor tool to run watch.sh, with a documented fallback to turn-based self-checks when the plugin/tools aren’t available.
Changes:
- Enable OpenCode
monitordelivery mode (delivery_modes=monitor turn off) and generate a corresponding rule file + status detection. - Update the OpenCode command template and documentation to describe monitor-mode setup and watcher management flows.
- Extend Bats coverage for OpenCode delivery and spawn command shape (
--prompt).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_spawn.bats | Updates spawn assertion to expect opencode --prompt form. |
| tests/test_delivery.bats | Adds monitor-mode tests (rule content, status, rewrite behavior). |
| scripts/drivers/types/opencode/type.conf | Enables monitor and switches spawn CLI to opencode + prompt_arg=--prompt. |
| scripts/drivers/types/opencode/template.md | Adds monitor to the mode picker and documents how to start/switch the watcher. |
| scripts/drivers/types/opencode/_delivery.sh | Implements monitor/turn/off rule writing and status derivation from rule content. |
| README.md | Updates OpenCode support statement (monitor via plugin; spawn via --prompt). |
| README.ja.md | Japanese README parity update for OpenCode support statement. |
| docs/opencode.md | Documents monitor mode via opencode-sentinel and spawn via --prompt. |
| docs/agent-types.md | Updates prompt_arg docs to include opencode’s --prompt. |
Comments suppressed due to low confidence (2)
scripts/drivers/types/opencode/template.md:128
- Same as the main monitor command: use "${SENTINEL_SESSION_ID:--}" so watch.sh receives a stable argv even if SENTINEL_SESSION_ID is empty/unset.
- command: `~/.agents/skills/__SKILL_NAME__/scripts/watch.sh "$SENTINEL_SESSION_ID" "$(pwd)" opencode <name>`
scripts/drivers/types/opencode/template.md:139
- Same as the main monitor command: use "${SENTINEL_SESSION_ID:--}" so watch.sh receives a stable argv even if SENTINEL_SESSION_ID is empty/unset.
- command: `~/.agents/skills/__SKILL_NAME__/scripts/watch.sh "$SENTINEL_SESSION_ID" "$(pwd)" opencode`
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 2. Run `~/.agents/skills/__SKILL_NAME__/scripts/reset.sh "$(pwd)" opencode <name>` to remove that role's registration. | ||
| 3. If the session's active FROM was `<name>`, clear that state. | ||
| 4. Tell the user: "Dropped role `<name>` from this project." | ||
| 4. **If delivery mode is `monitor`**: run `sentinel_list` to find a running monitor described `agmsg inbox stream`; if one is running in this session, stop it with `sentinel_stop` on its id, then relaunch it with the `sentinel_monitor` tool using the default (no 4th arg) subscription so receive covers the project's remaining roles: |
| 4. **If delivery mode is `monitor`**, switch the watcher to the new role so receive is restricted to it: | ||
| a. Run `sentinel_list` to find a running monitor described `agmsg inbox stream`; if one is running in this session, stop it with `sentinel_stop` on its id. | ||
| b. Launch a fresh watcher with the `sentinel_monitor` tool: |
| |---|---|---|---| | ||
| | **`monitor`** (default on Claude Code) | SessionStart hook → Monitor tool → blocking SQLite stream | ~5s | Claude Code users wanting real-time push | | ||
| | **`turn`** (default on Codex / Copilot CLI / OpenCode) | Stop hook fires `check-inbox.sh` between assistant turns | until your next interaction | Codex / Copilot CLI / OpenCode (no Monitor tool); Claude Code users on a quieter loop | | ||
| | **`turn`** (default on Codex / Copilot CLI / OpenCode) | Stop hook fires `check-inbox.sh` between assistant turns | until your next interaction | Codex / Copilot CLI / OpenCode users not running monitor; Claude Code users on a quieter loop | |
| |---|---|---|---| | ||
| | **`monitor`**(Claude Codeのデフォルト) | SessionStartフック → Monitorツール → ブロッキングSQLiteストリーム | 約5秒 | リアルタイムプッシュを望むClaude Codeユーザー | | ||
| | **`turn`**(Codex / Copilot CLI / OpenCodeのデフォルト) | アシスタントのターン間でStopフックが `check-inbox.sh` を発火 | 次のやり取りまで | Codex / Copilot CLI / OpenCode(Monitorツールなし)、より静かなループを好むClaude Codeユーザー | | ||
| | **`turn`**(Codex / Copilot CLI / OpenCodeのデフォルト) | アシスタントのターン間でStopフックが `check-inbox.sh` を発火 | 次のやり取りまで | monitorを実行していないCodex / Copilot CLI / OpenCodeユーザー、より静かなループを好むClaude Codeユーザー | |
Without cmd_prefix=$, agmsg_actas_prompt falls back to the default '/', producing '/agmsg actas <name>' in the boot script — which OpenCode's TUI does not recognize (it invokes skills via '$agmsg', like codex and gemini). The spawned worker would boot but never claim its role. Also tightens the opencode spawn test to assert the '$agmsg actas' pattern is present and '/<cmd> actas' is absent, mirroring the codex fujibee#283 test — the old assertion checked --prompt and actas independently, so a boot script with --prompt followed by a bare-positional '/agmsg actas' would still pass. Copilot review feedback on type.conf L7.
Route opencode's real-time delivery through the sentinel_monitor tool (same shape as Claude Code's Monitor), with a turn-mode fallback when the tool is unavailable.
Companion to the monitor-delivery implementation: updates README.md, README.ja.md, and docs/opencode.md so the delivery-modes table and the OpenCode section list monitor as supported (via the external opencode-sentinel plugin), describe the turn fallback when the plugin is absent, and drop the stale 'no Monitor tool' / 'not supported' claims about monitor and spawn.
- watch.sh command now passes "${SENTINEL_SESSION_ID:--}" (4 sites:
_delivery.sh + template.md x3) instead of "$SENTINEL_SESSION_ID", so
launcher shells that drop a quoted-but-empty first arg don't shift
later watch.sh parameters. watch.sh documents this hazard for
GROK_SESSION_ID and recommends the same "${VAR:--}" shape.
- template.md actas/drop steps in monitor mode now explicitly say to
skip the sentinel_* tool calls when the plugin is unavailable, instead
of assuming the tools exist whenever mode=monitor.
- README.md / README.ja.md delivery-modes table: monitor row notes
OpenCode requires the plugin; turn row scopes OpenCode to the
plugin-not-installed case (the template picker now defaults to
monitor when the plugin is present).
Copilot review feedback on fujibee#547.
410d8dd to
e03fe89
Compare
|
Thanks @copilot — all six comments addressed in e03fe89:
The |
- watch.sh command now passes "${SENTINEL_SESSION_ID:--}" (4 sites:
_delivery.sh + template.md x3) instead of "$SENTINEL_SESSION_ID", so
launcher shells that drop a quoted-but-empty first arg don't shift
later watch.sh parameters. watch.sh documents this hazard for
GROK_SESSION_ID and recommends the same "${VAR:--}" shape.
- template.md actas/drop steps in monitor mode now explicitly say to
skip the sentinel_* tool calls when the plugin is unavailable, instead
of assuming the tools exist whenever mode=monitor.
- README.md / README.ja.md delivery-modes table: monitor row notes
OpenCode requires the plugin; turn row scopes OpenCode to the
plugin-not-installed case (the template picker now defaults to
monitor when the plugin is present).
Copilot review feedback on #547.
(cherry picked from commit e03fe89)
- watch.sh command now passes "${SENTINEL_SESSION_ID:--}" (4 sites:
_delivery.sh + template.md x3) instead of "$SENTINEL_SESSION_ID", so
launcher shells that drop a quoted-but-empty first arg don't shift
later watch.sh parameters. watch.sh documents this hazard for
GROK_SESSION_ID and recommends the same "${VAR:--}" shape.
- template.md actas/drop steps in monitor mode now explicitly say to
skip the sentinel_* tool calls when the plugin is unavailable, instead
of assuming the tools exist whenever mode=monitor.
- README.md / README.ja.md delivery-modes table: monitor row notes
OpenCode requires the plugin; turn row scopes OpenCode to the
plugin-not-installed case (the template picker now defaults to
monitor when the plugin is present).
Copilot review feedback on #547.
(cherry picked from commit e03fe89)
|
Both of these are in. Thank you — between them opencode goes from "spawn does not stay up" to a type with a real-time delivery path, and the analysis in each PR made them quick to review. They landed from branches in this repository (#569 and #570) rather than by merging your PRs directly. That is mechanical, not a judgement: the bats suite was split into shards after your PRs last ran, which renamed the required status check, so the required context could never report on those heads and GitHub held them blocked regardless of content. The red macOS job you may have seen on #546 was not a real failure either — it was the Your commits were cherry-picked, not rewritten, so they land under your authorship — you can see your name on all six on Two commits on #570 are ours, and we want to be explicit about what they changed and why. Wording. The docs said Quoting. The generated commands wrapped the project path in literal single quotes. Also noting that the two points from the automated review — the missing Closing both in favour of #569 and #570. The work is yours; only the branches are ours. |
What
Adds
monitormode to the opencode agent type, routing real-time delivery through theopencode-sentinelplugin'ssentinel_monitortool (same shape as Claude Code's Monitor tool). Falls back to turn-mode self-checks when the plugin is absent.Why
opencode has no built-in Monitor-tool equivalent, so until now it could only use
turnoroff— messages wait until the next tool call to surface. With the external opencode-sentinel plugin installed, opencode sessions gain a resident command-runner whose stdout lines arrive as steer notifications even in idle sessions — exactly what agmsg'swatch.shneeds to stream incoming messages in real time.The rule instructs the agent to launch
watch.shundersentinel_monitorat session start (or on/agmsg), passing$SENTINEL_SESSION_IDso the watcher persists its watermark per session.watch.shis runtime-agnostic and tolerates an empty session-id arg, so the command is safe even when the variable is unset. A fallback (turn-mode self-poll) is included for whensentinel_monitoris unavailable.Scope
scripts/drivers/types/opencode/type.conf:monitor=yes,delivery_modes=monitor turn offscripts/drivers/types/opencode/_delivery.sh:monitorcase writes the sentinel_monitor rule;statusreports mode from rule contentscripts/drivers/types/opencode/template.md: monitor added to the mode picker, plus an "ensure monitor is running" step and the actas/drop watcher-switch flowtests/test_delivery.bats: monitor-mode coverage (rule content, status, turn→monitor rewrite,bothstill rejected)README.md/README.ja.md/docs/opencode.md: monitor listed as supported via the plugin, with the turn-fallback noteDepends on the companion spawn PR (#546) — the two commits below it are that PR's.
Tests
bats tests/test_delivery.bats -f opencode→ 9/9 pass.Related