Repository navigation
Description
Describe the enhancement you want to request
A session-scoped way to deactivate/remove an already-activated skill — the missing counterpart to session.skill().
Problem
Activating a skill in a session is one-way. The v2.0.26 surface is add-only:
session.skill({ sessionID, id, resume })— injects the skill into the session (the syntheticskillmessage the model then sees)skill.list()— lists the catalogsession.skill.activated— event for UIs to refresh- Nothing removes it. Re-calling
session.skillwithresume:falseis a no-op; the only way out is deleting the session.
Concrete case from my own setup: a session has had the ads skill active since I first activated it while building a skill-picker UI. I cannot turn it off. Every turn since, that session has carried the ads instruction block in context, even for tasks that have nothing to do with ads.
Why this is worth having:
- Every other session-scoped action is reversible — skills are the exception. There is
session.revert,switchAgent,switchModel,fork… but one spacebar press in a skill picker permanently commits an instruction block to the rest of the session. - Real token cost that can never be reclaimed. Each activated skill injects its SKILL.md body (often 0.5–1.5 KB) into system context for every subsequent turn. Once a UI makes activation a single keystroke, users accumulate active skills quickly — one of my sessions sits at 8 — and there is no way to trim.
- Interactive UIs are half-built without it. The builtin
/skillspicker can only invoke. The in-flight sidebar work (feat(tui): show active skills in session sidebar #48461 / [FEATURE]: Show active session skills in the UI (sidebar, like MCP/TODO/LSP) and keep the model aware of them during the session #48355) can only display. A TUI plugin I've built (sidebar "active skills" widget + searchable picker that activates viasession.skill) cannot offer deactivation at all — and with activation being irreversible, every misclick is permanent for that session. A picker without an off switch is a trap. - The server already has a per-session "skill dropped" concept — it's just unreachable. Plugin reload during a turn fails the step retry and marks every skill as removed #51128 shows the harness emitting "the following skills are no longer available and must not be used" when a plugin reload rebuilds the catalog. That path is only reachable today as a side effect of a reload; users and UIs cannot trigger the equivalent deliberately.
What I'm explicitly not asking for
- Removing a skill from the catalog (globally). Plugins can already do that via
transform(SkillEditor.remove()at registration time) — but it is server-wide, not per-session, and requires owning a plugin. - Rewriting session history. The minimal ask: stop injecting the skill from the next turn on. (Making the synthetic activation message deletable would be a nice stretch goal, but plain "no longer injected" is enough to unblock UIs.)
Suggested shape (maintainers' call)
Mirror the activation path:
session.skill({ sessionID, id, remove: true })orDELETE /session/{id}/skill/{skillID}, and- a
session.skill.removed(or.deactivated) event so sidebar/picker UIs can refresh the same way they do onsession.skill.activated.
Semantics: subsequent turns don't see the skill in context; no model call is resumed (same as resume:false on activation); idempotent.
Related (checked before filing)
- [FEATURE]: Show active session skills in the UI (sidebar, like MCP/TODO/LSP) and keep the model aware of them during the session #48355 + PR feat(tui): show active skills in session sidebar #48461 — active-skills sidebar +
<loaded_skills>reminder. This makes the request more urgent, not redundant: once active skills are visible (and the model is reminded not to re-load them every turn), the lack of a removal path becomes more visible and more painful. I also searched open issues for "deactivate skill", "unload skill", "toggle skill", "remove session skill", "disable skill" — nothing requests this. - Plugin reload during a turn fails the step retry and marks every skill as removed #51128 — plugin-reload bug that marks skills removed via system instruction; shows the server can already do a per-session "drop these skills", it's just not exposed.
- [FEATURE]: Add /skills command to list and quick-invoke skills #7846 —
/skillspicker (invoke-only).
OpenCode v2.0.26, Linux. Happy to test early builds — I already have a working TUI picker plugin and would wire up the off switch the day the endpoint exists.
Activity
opencode-agent commentedon Oct 10, 2026
Thanks for the detailed write-up, @AmineAce!
In short, you're asking for a per-session way to turn off a skill that's already been activated: an endpoint or option that mirrors
session.skill(), plus a matching event so picker/sidebar UIs can refresh. From the next turn on, the model would no longer get that skill. The catalog and the session history would stay as they are.I checked the code: an activated skill is stored as a
skillmessage in the session history and is sent to the model on every later turn. Nothing removes it or skips it yet, so you're right that there's currently no way to turn it off.Related issues:
<loaded_skills>reminder/skillspicker (invoke-only)Maintainers will consider this. Thanks for offering to test builds and wire it into your picker plugin.