Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ All notable changes to SkillOpt are documented here. This project adheres to
- **OpenCode transcript source** (`--source opencode`) for SkillOpt-Sleep. It
reads visible user/assistant text and tool names from OpenCode's local SQLite
history without requiring its CLI, login, or a provider connection.
- **OpenCode CLI backend** (`--backend opencode`) for SkillOpt-Sleep model calls,
including plain task replay, using an installed OpenCode CLI with the user's
existing login and file-based global configuration. Calls parse OpenCode's
JSONL output and disable project configuration, tool use, external plugins,
and configured MCP servers. Tool-aware replay remains follow-up work.
- **OpenCode CLI backend** (`--backend opencode`) for SkillOpt-Sleep model calls.
It uses an installed OpenCode CLI with the user's existing login and
file-based global configuration, and supports plain task replay plus opt-in
tool-aware replay. Plain calls disable project configuration,
model-initiated tool invocation, external plugins, and configured MCP servers.
Tool-aware replay exposes only temporary synthetic tools with randomized names
and fixed results, verifies which tools OpenCode actually invokes, and never
retains or replays historical tool arguments or results.
- **GitHub Copilot CLI backend**, in two forms: `copilot_chat` (usable as both
optimizer and target) and `copilot_exec` (target-only execution harness).
Because the Copilot CLI carries its own sign-in, `--backend copilot` selects
Expand Down Expand Up @@ -106,8 +109,8 @@ All notable changes to SkillOpt are documented here. This project adheres to
@Alphaxalchemy's #129).

### Tests
- Add focused OpenCode backend coverage and opt-in real-CLI smoke tests for a
plain call and a seeded cycle-level run.
- Add focused OpenCode backend coverage and opt-in real-CLI smoke tests for
tool-aware replay and a seeded plain cycle.
- Strengthen SkillOpt-Sleep verifier-discipline assertions, including recorded
scores and gate actions (thanks @Tanmay9223, #96).
- Add focused coverage for the validation-gate decision core and edit-budget
Expand Down
55 changes: 36 additions & 19 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ Actions are `run`, `dry-run`, `status`, `adopt`, `harvest`, `schedule`, and
| `--pi-path PATH` | Path to the installed Pi coding-agent CLI |
| `--opencode-path PATH` | Path to the installed OpenCode CLI |
| `--opencode-db PATH` | Path to the OpenCode SQLite history database |
| `--opencode-tool-replay` | Enable OpenCode tool-aware replay for `tool_called` checks in rule judges |
| `--preferences TEXT` | House rules supplied to reflection |
| `--lookback-hours N` | Initial transcript lookback; `0` scans all history |
| `--max-sessions N` / `--max-tasks N` | Bound the harvested workload |
Expand Down Expand Up @@ -256,6 +257,9 @@ Install and configure OpenCode using its
[official documentation](https://opencode.ai/docs/), then confirm the CLI is
available with `opencode --version`.

SkillOpt's OpenCode backend, including tool-aware replay, has been tested with
OpenCode CLI `1.18.15`. Other versions may work but have not been validated.

If OpenCode is on `PATH`, no path option is needed. Otherwise use
`--opencode-path`, the `opencode_path` config key, or
`SKILLOPT_SLEEP_OPENCODE_PATH`. Use `--model`, the `model` config key, or
Expand All @@ -268,28 +272,41 @@ skillopt-sleep run --project "$(pwd)" \
--model provider/model --max-sessions 5 --max-tasks 3 --progress
```

Plain calls run from a temporary directory with project configuration, tool
use, and external plugins disabled. Before contacting the model, SkillOpt
discovers the resolved MCP configuration, disables every
configured MCP server for the call, and verifies that none remains enabled. If
that check fails, the model call is not made. Tool-aware replay is not yet
supported.

The child process keeps normal OpenCode file-based global configuration and
data directories. SkillOpt sets `OPENCODE_CONFIG_CONTENT` for the child process
to define the temporary agent and disable configured MCP servers. This replaces
the user's existing value in that child process, so settings supplied only
through that value are unavailable. Because `--pure` skips external plugins,
Plain calls run from a temporary directory with project configuration and
model-initiated tool invocation disabled. Before contacting the model, SkillOpt
discovers the resolved MCP configuration, disables every configured MCP server
for the call, and verifies that none remains enabled. If that check fails, the
model call is not made.

OpenCode tool-aware replay is disabled by default. Enable it explicitly with
`--opencode-tool-replay` or `"opencode_tool_replay": true` in
`~/.skillopt-sleep/config.json`. It applies only to tasks whose rule judge
contains a non-empty `tool_called` check. In a fresh temporary workspace,
SkillOpt creates synthetic tools with randomized names and fixed results, then
verifies which tools OpenCode actually invoked. Historical tool arguments and
results are neither retained nor replayed. Configured MCP servers remain
disabled, and the invocation allowlist includes only these temporary tools.

Both modes continue to use OpenCode's normal data directory and file-based
global configuration. OpenCode may discover or initialize custom JS/TS tools
from its global configuration directories, although SkillOpt does not allow the
model to invoke them. SkillOpt replaces `OPENCODE_CONFIG_CONTENT` in the child
process to define the temporary agent and disable configured MCP servers, so
settings present only in the user's original value are unavailable. Because
`--pure` skips external plugins,
authentication or provider setup that depends on one of those plugins is also
unavailable. Calls may appear in the user's normal OpenCode session history;
these controls are invocation settings, not complete account or process
isolation.
unavailable. Calls may appear in the user's OpenCode session history. During
tool-aware replay, the fixed input (`synthetic`), fixed result, and temporary
project metadata may remain there as well. These controls are invocation
settings, not complete account or process isolation.

The managed scheduler stores the backend but not `--source`, `--opencode-db`,
`--opencode-path`, or `--model`. Put `transcript_source`, `opencode_db`,
`opencode_path`, and `model` in `~/.skillopt-sleep/config.json` as needed. Use
absolute database and executable paths, and verify OpenCode access when the
scheduled run uses the backend.
`--opencode-path`, `--opencode-tool-replay`, or `--model`. Put
`transcript_source`, `opencode_db`, `opencode_path`, and `model` in
`~/.skillopt-sleep/config.json` as needed. Add
`"opencode_tool_replay": true` only when the scheduled run should enable
tool-aware replay. Use absolute database and executable paths, and verify
OpenCode access when the scheduled run uses the backend.

### Cursor source and backend

Expand Down
36 changes: 21 additions & 15 deletions docs/sleep/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,21 +212,27 @@ skillopt-sleep run --project "$(pwd)" \
--opencode-path /absolute/path/to/opencode --model provider/model
```

For plain calls, SkillOpt disables project configuration, tool use, external
plugins, and configured MCP servers. It stops before the model call if it cannot
confirm that every resolved MCP server is disabled. The subprocess keeps
OpenCode's normal data directory, so calls may appear in the user's OpenCode
session history. SkillOpt sets `OPENCODE_CONFIG_CONTENT` for the child process
to define the temporary agent and disable configured MCP servers. This replaces
the user's existing value in that child process, so settings supplied only
through that value are unavailable; use file-based global configuration or
provider environment variables instead.

Tool-aware replay and a native OpenCode plugin or command are not implemented
yet. For scheduled runs, configure the source, database, executable, and model
in `~/.skillopt-sleep/config.json` as needed; the
[CLI reference](../reference/cli.md#opencode-source-and-backend) has the full
scheduler details.
Plain calls disable project configuration, model-initiated tool invocation,
external plugins, and configured MCP servers. SkillOpt stops before the model
call if it cannot confirm that every resolved MCP server is disabled.

Tool-aware replay is disabled by default. Enable it with
`--opencode-tool-replay` or `"opencode_tool_replay": true` for tasks whose rule
judge contains a `tool_called` check. It exposes temporary synthetic tools with
randomized names and fixed results, verifies which tools OpenCode actually
invokes, and denies all other tools. Historical tool arguments and results are
not retained or replayed.

Both modes continue to use OpenCode's normal data directory and file-based
global configuration. Calls may therefore appear in session history, and global
custom JS/TS tools may initialize, although SkillOpt does not allow the model to
invoke them. See the
[CLI reference](../reference/cli.md#opencode-source-and-backend) for complete
configuration, history, and isolation details.

For scheduled runs, configure the source, database, executable, and model in
`~/.skillopt-sleep/config.json` as needed. Set `opencode_tool_replay` to `true`
there to opt in to tool-aware replay.

### Cursor

Expand Down
14 changes: 9 additions & 5 deletions plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,14 @@ optimization.
CLI, authentication, or provider access. See
[the CLI reference](../docs/reference/cli.md#opencode-source-and-backend) for
its retained-data boundary.
- The core `opencode` backend uses the installed OpenCode CLI for plain model
calls. It keeps the user's login and file-based global configuration
while disabling project configuration, tool use, external plugins, and
configured MCP servers for those calls. Tool-aware replay and a native
OpenCode plugin or command are not included yet.
- The core `opencode` backend uses the installed OpenCode CLI. Plain calls
disable project configuration, model-initiated tool invocation, external
plugins, and configured MCP servers. Tool-aware replay requires explicit
opt-in. It exposes only temporary synthetic tools with randomized names and
fixed results, then verifies which tools OpenCode actually invoked. See the
[CLI reference](../docs/reference/cli.md#opencode-source-and-backend) for
history and isolation details. A native OpenCode plugin or command is not
included.
- Outbound prompts are not currently guaranteed to be free of secrets. Do not
use a third-party provider on sensitive transcripts without reviewing the data
source and the provider's retention policy.
Expand Down Expand Up @@ -146,6 +149,7 @@ Common implemented flags include:
| `--pi-path PATH` | auto-detect `pi` | select the Pi coding-agent CLI executable |
| `--opencode-path PATH` | `SKILLOPT_SLEEP_OPENCODE_PATH`, then `opencode` on `PATH`/`PATHEXT` | select the OpenCode CLI executable |
| `--opencode-db PATH` | `OPENCODE_DB`, `%LOCALAPPDATA%`/`%APPDATA%` (Windows), or `${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db` | select the OpenCode SQLite history database |
| `--opencode-tool-replay` | off | enable OpenCode tool-aware replay for `tool_called` checks in rule judges |
| `--project PATH` | current directory | select the project and invoked harvest scope |
| `--scope invoked\|all` | `invoked` | limit transcript harvesting |
| `--target-skill-path PATH` | managed skill | select a specific `SKILL.md` to stage/adopt |
Expand Down
2 changes: 2 additions & 0 deletions plugins/openclaw/run_sleep.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def get_backend(
pi_path="",
cursor_path="",
opencode_path="",
opencode_tool_replay=False,
azure_endpoint="",
project_dir="",
):
Expand All @@ -57,6 +58,7 @@ def get_backend(
pi_path=pi_path,
cursor_path=cursor_path,
opencode_path=opencode_path,
opencode_tool_replay=opencode_tool_replay,
azure_endpoint=azure_endpoint,
project_dir=project_dir,
)
Expand Down
7 changes: 7 additions & 0 deletions skillopt_sleep/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ def _add_common(p: argparse.ArgumentParser) -> None:
p.add_argument("--cursor-path", default="", help="path to the Cursor Agent CLI")
p.add_argument("--pi-path", default="", help="path to the Pi coding-agent CLI")
p.add_argument("--opencode-path", default="", help="path to the OpenCode CLI")
p.add_argument(
"--opencode-tool-replay",
action="store_true",
help="allow controlled synthetic tools for OpenCode tool-aware replay",
)
p.add_argument("--claude-home", default="", help="override ~/.claude (also isolates state)")
p.add_argument("--codex-home", default="", help="override ~/.codex for archived session harvest")
p.add_argument("--cursor-home", default="", help="override ~/.cursor for Cursor session harvest")
Expand Down Expand Up @@ -134,6 +139,8 @@ def _cfg_from_args(args, task_meta: Dict[str, Any] | None = None) -> Any:
overrides["cursor_path"] = os.path.abspath(os.path.expanduser(args.cursor_path))
if getattr(args, "opencode_path", ""):
overrides["opencode_path"] = os.path.abspath(os.path.expanduser(args.opencode_path))
if getattr(args, "opencode_tool_replay", False):
overrides["opencode_tool_replay"] = True
if getattr(args, "claude_home", ""):
overrides["claude_home"] = os.path.abspath(args.claude_home)
if getattr(args, "codex_home", ""):
Expand Down
Loading