Skip to content

Commit e1d62b0

Browse files
authored
Merge pull request #218 from YingqiDuan/feat/opencode-integration
feat(sleep): add OpenCode CLI backend for plain replay
2 parents a2a3a1f + 3f4b087 commit e1d62b0

12 files changed

Lines changed: 1315 additions & 14 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ All notable changes to SkillOpt are documented here. This project adheres to
77
## [Unreleased]
88

99
### Added
10+
- **OpenCode CLI backend** (`--backend opencode`) for SkillOpt-Sleep model calls,
11+
including plain task replay, using an installed OpenCode CLI with the user's
12+
existing login and file-based global configuration. Calls parse OpenCode's
13+
JSONL output and disable project configuration, tool use, external plugins,
14+
and configured MCP servers. Transcript harvesting and tool-aware replay
15+
remain follow-up work.
1016
- **GitHub Copilot CLI backend**, in two forms: `copilot_chat` (usable as both
1117
optimizer and target) and `copilot_exec` (target-only execution harness).
1218
Because the Copilot CLI carries its own sign-in, `--backend copilot` selects
@@ -86,6 +92,8 @@ All notable changes to SkillOpt are documented here. This project adheres to
8692
@Alphaxalchemy's #129).
8793

8894
### Tests
95+
- Add focused OpenCode backend coverage and opt-in real-CLI smoke tests for a
96+
plain call and a seeded cycle-level run.
8997
- Strengthen SkillOpt-Sleep verifier-discipline assertions, including recorded
9098
scores and gate actions (thanks @Tanmay9223, #96).
9199
- Add focused coverage for the validation-gate decision core and edit-budget

‎docs/reference/cli.md‎

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
> include the generic research `openai_compatible` backend, Sleep handoff,
55
> Sleep support for non-Azure OpenAI-compatible endpoints, the Sleep
66
> `--preferences` flag, the research `cursor_exec` target harness, or Cursor
7-
> source/backend/plugin support, Pi source/backend support, or VS Code Copilot
8-
> transcript harvesting; use a source install from `main` for those features
9-
> until the next release.
7+
> source/backend/plugin support, Pi source/backend support, the OpenCode Sleep
8+
> backend, or VS Code Copilot transcript harvesting; use a source install from
9+
> `main` for those features until the next release.
1010
1111
## Training
1212

@@ -130,13 +130,14 @@ Actions are `run`, `dry-run`, `status`, `adopt`, `harvest`, `schedule`, and
130130
| `--project PATH` | Project used for transcript scope, targets, state, and staging (default: current directory) |
131131
| `--scope invoked\|all` | Harvest this project or all projects |
132132
| `--source claude\|codex\|copilot\|cursor\|pi\|auto` | Transcript source; `auto` keeps Codex-then-Claude precedence and does not select Copilot, Cursor, or Pi |
133-
| `--backend mock\|claude\|codex\|copilot\|cursor\|pi\|handoff\|azure_openai` | Replay/optimizer backend |
133+
| `--backend mock\|claude\|codex\|copilot\|cursor\|pi\|opencode\|handoff\|azure_openai` | Replay/optimizer backend |
134134
| `--model NAME` | Backend-specific model override |
135135
| `--cursor-home PATH` | Override `~/.cursor` for Cursor transcript harvesting |
136136
| `--pi-home PATH` | Parent directory containing Pi's `agent/sessions` tree (default: `~/.pi`) |
137137
| `--vscode-workspace-storage PATH` | Override VS Code's `User/workspaceStorage` root for Copilot transcript harvesting |
138138
| `--cursor-path PATH` | Path to the installed Cursor Agent CLI |
139139
| `--pi-path PATH` | Path to the installed Pi coding-agent CLI |
140+
| `--opencode-path PATH` | Path to the installed OpenCode CLI |
140141
| `--preferences TEXT` | House rules supplied to reflection |
141142
| `--lookback-hours N` | Initial transcript lookback; `0` scans all history |
142143
| `--max-sessions N` / `--max-tasks N` | Bound the harvested workload |
@@ -213,6 +214,54 @@ The managed `schedule` command preserves the backend but not `--source`,
213214
`~/.skillopt-sleep/config.json`; use an absolute `pi_path` and verify
214215
authentication for the scheduled account.
215216

217+
### OpenCode backend
218+
219+
Install and configure OpenCode using its
220+
[official documentation](https://opencode.ai/docs/), then confirm the CLI is
221+
available with `opencode --version`.
222+
223+
`--backend opencode` runs SkillOpt's model calls for mining, plain task replay,
224+
judging, and reflection through an installed OpenCode CLI. It uses the user's
225+
existing OpenCode login, provider environment variables, and file-based global
226+
configuration; SkillOpt does not manage OpenCode accounts or provider
227+
credentials. Transcript sources remain independent, and there is not yet a
228+
`--source opencode` harvester.
229+
230+
If OpenCode is on `PATH`, no path option is needed. Otherwise use
231+
`--opencode-path`, the `opencode_path` config key, or
232+
`SKILLOPT_SLEEP_OPENCODE_PATH`. Use `--model`, the `model` config key, or
233+
`SKILLOPT_SLEEP_OPENCODE_MODEL` to override OpenCode's configured model:
234+
235+
```bash
236+
skillopt-sleep run --project "$(pwd)" \
237+
--source codex --backend opencode \
238+
--opencode-path /absolute/path/to/opencode \
239+
--model provider/model --max-sessions 5 --max-tasks 3 --progress
240+
```
241+
242+
Plain calls run from a temporary directory with project configuration, tool
243+
use, and external plugins disabled. Before contacting the model, SkillOpt
244+
discovers the resolved MCP configuration, disables every
245+
configured MCP server for the call, and verifies that none remains enabled. If
246+
that check fails, the model call is not made. Tool-aware replay is not yet
247+
supported.
248+
249+
The child process keeps normal OpenCode file-based global configuration and
250+
data directories. SkillOpt sets `OPENCODE_CONFIG_CONTENT` for the child process
251+
to define the temporary agent and disable configured MCP servers. This replaces
252+
the user's existing value in that child process, so settings supplied only
253+
through that value are unavailable. Because `--pure` skips external plugins,
254+
authentication or provider setup that depends on one of those plugins is also
255+
unavailable. Calls may appear in the user's normal OpenCode session history;
256+
these controls are invocation settings, not complete account or process
257+
isolation.
258+
259+
The managed scheduler stores the backend but not `--opencode-path`, `--model`,
260+
or the transcript source. Before scheduling OpenCode, put `opencode_path`,
261+
`model`, and `transcript_source` in `~/.skillopt-sleep/config.json` as needed.
262+
Prefer an absolute executable path and verify OpenCode access for the account
263+
that runs the scheduled job.
264+
216265
### Cursor source and backend
217266

218267
`--source cursor` reads local Cursor JSONL transcripts from

‎docs/sleep/README.md‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ skillopt-sleep schedule # install a nightly cron entry for this project
9090
> **Version note.** This page tracks `main`. PyPI 0.2.0 provides the base
9191
> commands above. Cursor source/backend/plugin support, VS Code Copilot
9292
> transcript harvesting, Pi source/backend support, Sleep handoff, non-Azure
93-
> OpenAI-compatible endpoints, and `--preferences` landed later and require a
94-
> source install from `main` until the next release.
93+
> OpenAI-compatible endpoints, the OpenCode Sleep backend, and `--preferences`
94+
> landed later and require a source install from `main` until the next release.
9595
9696
The per-agent integrations below still come from the repo; the CLI above is the
9797
standalone, pip-only way to run a cycle. Claude Code, Codex, Cursor, Copilot, and
@@ -170,6 +170,40 @@ The managed scheduler records the backend but does not preserve `--source`,
170170
`~/.skillopt-sleep/config.json`. Use an absolute `pi_path` and verify the
171171
scheduled account's Pi authentication.
172172

173+
### OpenCode
174+
175+
Install and configure OpenCode using its
176+
[official documentation](https://opencode.ai/docs/), then confirm the CLI is
177+
available with `opencode --version`.
178+
179+
`--backend opencode` sends SkillOpt's model calls for mining, plain task replay,
180+
judging, and reflection through an installed OpenCode CLI, using the user's
181+
existing login, provider environment variables, and file-based global
182+
configuration. Select a binary and model only when the OpenCode defaults are
183+
not suitable:
184+
185+
```bash
186+
skillopt-sleep run --project "$(pwd)" \
187+
--source codex --backend opencode \
188+
--opencode-path /absolute/path/to/opencode --model provider/model
189+
```
190+
191+
For plain calls, SkillOpt disables project configuration, tool use, external
192+
plugins, and configured MCP servers. It stops before the model call if it cannot
193+
confirm that every resolved MCP server is disabled. The subprocess keeps
194+
OpenCode's normal data directory, so calls may appear in the user's OpenCode
195+
session history. SkillOpt sets `OPENCODE_CONFIG_CONTENT` for the child process
196+
to define the temporary agent and disable configured MCP servers. This replaces
197+
the user's existing value in that child process, so settings supplied only
198+
through that value are unavailable; use file-based global configuration or
199+
provider environment variables instead.
200+
201+
OpenCode transcript harvesting and tool-aware replay are not implemented yet.
202+
For scheduling, put `opencode_path`, `model`, and the desired
203+
`transcript_source` in `~/.skillopt-sleep/config.json` as needed, and verify the
204+
scheduled account can run OpenCode. See the
205+
[CLI reference](../reference/cli.md#opencode-backend) for full details.
206+
173207
### Cursor
174208

175209
Cursor transcript harvesting and model execution are independent. Use

‎plugins/README.md‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ an importable `skillopt_sleep` module. Install with `uv tool install skillopt` o
4848
> **Version note.** This integration reference tracks `main`. PyPI 0.2.0
4949
> supports the base Sleep CLI, while Cursor source/backend/plugin support,
5050
> Pi source/backend support, handoff, Sleep support for non-Azure
51-
> OpenAI-compatible endpoints, and `--preferences` require a source checkout
52-
> from `main` until the next release.
51+
> OpenAI-compatible endpoints, the OpenCode Sleep backend, and `--preferences`
52+
> require a source checkout from `main` until the next release.
5353
5454
## One sleep cycle
5555

@@ -93,6 +93,12 @@ optimization.
9393
retained for scope filtering and may appear in miner prompts sent to a real
9494
backend and its provider. Known secret-shaped strings in retained message text
9595
are redacted only as defense in depth.
96+
- The core `opencode` backend uses the installed OpenCode CLI for plain model
97+
calls. It keeps the user's login and file-based global configuration
98+
while disabling project configuration, tool use, external plugins, and
99+
configured MCP servers for those calls. OpenCode transcript harvesting,
100+
tool-aware replay, and a native OpenCode plugin or command are not included
101+
yet.
96102
- Outbound prompts are not currently guaranteed to be free of secrets. Do not
97103
use a third-party provider on sensitive transcripts without reviewing the data
98104
source and the provider's retention policy.
@@ -128,13 +134,14 @@ Common implemented flags include:
128134

129135
| Flag | Default | Purpose |
130136
|---|---|---|
131-
| `--backend mock\|claude\|codex\|cursor\|copilot\|pi\|handoff\|azure_openai` | `mock` | select who performs model calls |
137+
| `--backend mock\|claude\|codex\|cursor\|copilot\|pi\|opencode\|handoff\|azure_openai` | `mock` | select who performs model calls |
132138
| `--model NAME` | backend default | select a backend-specific model |
133139
| `--source claude\|codex\|copilot\|cursor\|pi\|auto` | `claude` | select the transcript source; `auto` retains Codex-then-Claude precedence and does not select Copilot, Cursor, or Pi |
134140
| `--cursor-home PATH` | `~/.cursor` | override the Cursor transcript home |
135141
| `--cursor-path PATH` | auto-detect `cursor-agent` | select the Cursor Agent CLI executable |
136142
| `--pi-home PATH` | `~/.pi` | select the parent directory containing `agent/sessions` |
137143
| `--pi-path PATH` | auto-detect `pi` | select the Pi coding-agent CLI executable |
144+
| `--opencode-path PATH` | `SKILLOPT_SLEEP_OPENCODE_PATH`, then `opencode` on `PATH`/`PATHEXT` | select the OpenCode CLI executable |
138145
| `--project PATH` | current directory | select the project and invoked harvest scope |
139146
| `--scope invoked\|all` | `invoked` | limit transcript harvesting |
140147
| `--target-skill-path PATH` | managed skill | select a specific `SKILL.md` to stage/adopt |

‎plugins/openclaw/run_sleep.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def get_backend(
4343
codex_path="",
4444
pi_path="",
4545
cursor_path="",
46+
opencode_path="",
4647
azure_endpoint="",
4748
project_dir="",
4849
):
@@ -55,6 +56,7 @@ def get_backend(
5556
codex_path=codex_path,
5657
pi_path=pi_path,
5758
cursor_path=cursor_path,
59+
opencode_path=opencode_path,
5860
azure_endpoint=azure_endpoint,
5961
project_dir=project_dir,
6062
)

‎skillopt_sleep/__main__.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
--max-tasks N cap mined tasks per run
1414
--target-skill-path PATH explicit live SKILL.md to stage/adopt
1515
--tasks-file PATH reviewed TaskRecord JSON file to replay instead of harvesting
16-
--backend mock|claude|codex|copilot|cursor|pi|handoff|azure_openai
16+
--backend mock|claude|codex|copilot|cursor|pi|opencode|handoff|azure_openai
1717
--source claude|codex|copilot|copilot_cli|cursor|pi|auto
1818
--vscode-workspace-storage PATH
1919
--copilot-cli-session-store PATH
@@ -74,11 +74,12 @@ def _add_common(p: argparse.ArgumentParser) -> None:
7474
p.add_argument("--scope", default="", choices=["", "all", "invoked"])
7575
p.add_argument("--backend", default="",
7676
choices=["", "mock", "claude", "codex", "copilot", "cursor", "pi",
77-
"handoff", "azure_openai"])
77+
"opencode", "handoff", "azure_openai"])
7878
p.add_argument("--model", default="")
7979
p.add_argument("--codex-path", default="", help="path to the real @openai/codex binary")
8080
p.add_argument("--cursor-path", default="", help="path to the Cursor Agent CLI")
8181
p.add_argument("--pi-path", default="", help="path to the Pi coding-agent CLI")
82+
p.add_argument("--opencode-path", default="", help="path to the OpenCode CLI")
8283
p.add_argument("--claude-home", default="", help="override ~/.claude (also isolates state)")
8384
p.add_argument("--codex-home", default="", help="override ~/.codex for archived session harvest")
8485
p.add_argument("--cursor-home", default="", help="override ~/.cursor for Cursor session harvest")
@@ -126,6 +127,8 @@ def _cfg_from_args(args, task_meta: Dict[str, Any] | None = None) -> Any:
126127
overrides["pi_path"] = os.path.abspath(os.path.expanduser(args.pi_path))
127128
if getattr(args, "cursor_path", ""):
128129
overrides["cursor_path"] = os.path.abspath(os.path.expanduser(args.cursor_path))
130+
if getattr(args, "opencode_path", ""):
131+
overrides["opencode_path"] = os.path.abspath(os.path.expanduser(args.opencode_path))
129132
if getattr(args, "claude_home", ""):
130133
overrides["claude_home"] = os.path.abspath(args.claude_home)
131134
if getattr(args, "codex_home", ""):

0 commit comments

Comments
 (0)