release: v0.10.0
Changelog for v0.10.0, plus the fixes the release review turned up. Carries none of the 16 commits already on main — this is the release entry and the review findings only.
Why the changelog is here
script/build.ts embeds CHANGELOG.md into the compiled binary and script/publish.ts copies it into every npm package, so tagging without the entry ships an artifact whose embedded changelog stops at the previous version.
Fixes
Skill listing injection (P0). Three sites render <available_skills> from skill name/description. Two were escaped when skill sync landed; tool/skill.ts was missed — and it is the Skill tool's own description, sent to the model every turn whether or not the tool is invoked, so it is a wider exposure than either site that was fixed. Skill frontmatter is now remote content, so a synced description ending </description></skill></available_skills> broke out and arrived as prompt text. neutralizeListingWrapper is now exported and both live sites route through it. Its tag list also covers system-reminder and auto_loaded_skill, which the harness uses as trust boundaries in the same message stream.
Emptied workspace never purged (#1219). parsePage rejected pages < 1 as malformed, but the server sends pages: 0 for an empty workspace, so zero skills was unobservable and the purge branch was unreachable. Now accepted only when the envelope agrees it is empty.
Duplicate listing renderer — and the bug it hid. skill/skill.ts carried a second, unreferenced renderer (the copy without the escaping), and test/skill/fmt.test.ts tested that dead copy while the live renderer had no coverage. Deleted rather than kept in sync: two renderers is how the escape came to be applied to one and not the other. Repointing those tests immediately failed, which is the point — built-in skills were rendering a location that does not exist. A builtin: URI is not a filesystem path, so pathToFileURL resolved it against the CWD and emitted file:///…/packages/opencode/builtin:my-skill/SKILL.md. The deleted duplicate had a guard; the live renderer never did. 21 built-in skills ship, so every session put 21 bogus paths in front of the model.
Orphaned source maps (#1218). 191MB → 171MB compressed. Confirmed by a real publish + global install in the Verdaccio suite.
Tracker keys on a public repo. This release added three; scrubbed. script/check-tracker-leaks.ts existed with its own tests but was wired into no workflow, which is why they landed — it now runs on every PR. The pre-existing backlog is #1230.
Changelog omissions. #1171 was credited with one narrow bullet but also shipped a credential-leak fix (the observation mask replayed on every later request bypassed the redactor for two fields) and a user-visible bug (interactive chat appended a literal DONE). A security fix with no release-note visibility breaks anyone auditing from release notes. Also recorded #1184's two intended behaviour changes, and split "opt-in workspace surface" from "default-on reliability changes".
Smaller: the duplicated 0.65 safety fraction now imports the single exported constant (they had already drifted once); printLine strips control characters before writing workspace-derived text to stderr, since the workspace name is server-set and ANSI escapes could hide the very "engine not usable" notice it exists to deliver; mcp status, --integrations and two env vars were shipped undocumented; and the opt-out instruction at 5 sites now says how to actually opt out.
Tests
test/skill/release-v0.10.0-adversarial.test.ts (7) pins the listing escape — break-out, opening-tag forgery, trust-tag forgery, case variants, an over-escaping guard, idempotence. Plus two cases for the real empty envelope and one for the previously-untested MAX_TOTAL_BYTES ceiling.
Every new assertion was mutation-tested. That caught one of my own: the first byte-ceiling test passed with the byte term deleted, because the integrity check refuses the bundle anyway — rewritten to assert the ceiling's real contract (refusal on the advertised inventory, so no file is ever requested) and re-mutated.
Gates
| Gate | Result |
|---|---|
| Clean install + full monorepo typecheck | pass (13 packages) |
altimate_change marker guard | pass |
| Tracker-leak guard | pass |
| Deterministic preflight | 9 PASS / 0 WARN / 0 FAIL |
| Pre-release binary sanity | pass |
| Package size | 171MB (threshold 190MB) |
| Full test suite | 12508 pass, 758 skip |
| Verdaccio sanity (linux/arm64) | ALL PHASES PASSED — install 13/0, extended resilience 14/0/1, security 16/0 |
Verdaccio was run locally by cross-building the linux dist on macOS, which the release doc says is impossible — see #1231.
run-process.test.ts fails intermittently under full-suite load: a different test each run, passing in isolation, with fully green runs on two independent machines. Local disk was at 99%, which has produced phantom failures before. Not treated as a regression.
Deferred
Release-infrastructure hardening found during this work is split out into #1234 (closes #1233), since it is unrelated to this release's content.
Filed rather than fixed: #1220 #1221 #1222 #1223 #1224 #1225 #1226 #1227 #1228 #1229 #1230 #1231. The two worth reading first are #1229 (skill sync failures are invisible — worth a known-limitation note in the beta announcement) and #1231.
🤖 Generated with Claude Code
Summary by cubic
Adds the v0.10.0 changelog before release so compiled binaries and npm packages include the release notes, and closes the final review findings. Previously, remote skill text could forge prompt boundaries and malformed pagination could purge valid synced skills; both paths now reject or neutralize unsafe input.
Bug Fixes
- Protects skill metadata, bodies, attributes, generated file paths, auto-loaded content, and tool examples at their live render sites while preserving ordinary markup and copyable names.
- Requires all workspace listing pages to agree on
pagesandtotaland include the requested page number, refusing inconsistent responses instead of deleting valid skills. - Handles
builtin:and<built-in>as non-filesystem locations without scanning the project or emitting bogusfile://paths. - Removes orphaned source maps from published packages, reducing the package size from 191 MB to 171 MB.
- Runs tracker-leak checks on every pull request with read-only, non-persisted credentials and the actual head branch.
- Single-sources the compaction safety fraction and strips control characters from workspace-derived stderr notices.
- Documents MCP diagnostics, integration settings, workspace opt-in, environment variables, and the restart requirement when opting out.
Release Notes
- Records the workspace pilot, model-picker and harness fixes, credential redaction, literal
DONEfix, and shell-installer telemetry changes. - Closes #1218 and #1219.
Summary by CodeRabbit
-
New Features
- Added MCP commands for viewing configured servers and connection status.
- Added options to use local integrations or opt into workspace-managed features.
- Workspace-managed environments now synchronize custom skills and route warehouse tools through their configured engine.
-
Bug Fixes
- Improved synchronization with empty workspaces and removal of stale skills.
- Strengthened protection against unsafe skill metadata and disruptive control characters.
- Clarified instructions for switching out of workspace-managed mode.
- Improved handling of oversized tool results and model context limits.
-
Documentation
- Updated CLI and release documentation for workspace and integration settings.