feat: register bundled skills via config.skills.paths#244
Conversation
…overy Add skills.paths registration in the config hook so OpenCode's built-in skill tool can discover Systematic skills natively, alongside the existing slash command registration. This follows the pattern established by the Superpowers plugin (obra/superpowers) and uses the skills.paths property from the OpenCode v2 SDK types. A local type extension bridges the gap until we upgrade from v1 imports. Changes: - config-handler.ts: add registerSkillsPaths() after command merging - opencode.test.ts: 3 new integration tests (path registered, existing paths preserved, no duplicates on repeated calls) Verification: - Build: exit 0 - Typecheck: exit 0 - Lint: 54 files, no fixes - Unit tests: 305/305 pass - Integration tests: 22/22 pass (3 new)
fro-bot
left a comment
There was a problem hiding this comment.
Verdict: PASS
Blocking issues
None.
Non-blocking concerns
-
registerSkillsPathsmutates config in-place: This is correct for the hook pattern (OpenCode's config hook mutates the live config singleton), and it matches the Superpowers plugin pattern. However, the JSDoc comment onregisterSkillsPathssays "Register a directory for OpenCode's native skill discovery (skilltool)" but doesn't document the mutation behavior. Consider adding@mutates configor similar annotation for clarity, or a brief note in the function doc. -
SDK upgrade timeline: The
ConfigWithSkillstype bridge comment says "bridge until import upgrade" — the plan document references this but there's no tracked issue or TODO. Low risk since the bridge is safe and the types align correctly, but worth tracking so it doesn't become permanent tech debt.
Missing tests
None.
Risk assessment (LOW) + rationale
The change is purely additive — it appends a directory path to config.skills.paths during the config hook, with idempotency guards already in place. No existing behavior is modified.
- Likelihood of regression: Very low. The change is isolated to the config hook, after all existing merge logic. It follows the exact pattern from the Superpowers plugin. The idempotency check (
includes) prevents duplicate entries on repeated hook invocations. - Security exposure: None. The path is derived from the plugin's own
bundledSkillsDir, not from user input. - Blast radius: Minimal. This only adds OpenCode's native skill discovery as an additional discovery mechanism. The existing slash-command registration via
config.commandis unchanged.
Additional notes
The implementation is clean and follows codebase conventions precisely:
- Type bridge (
ConfigWithSkills) is minimal and well-documented - No
any, no@ts-ignore, no non-null assertions - ESM conventions respected throughout (
node:protocol,.jsextensions) - Function-over-class, explicit return types on exports
- The Superpowers plugin adaptation is accurate (both mutate the live config singleton in the config hook)
Build, typecheck, lint, and all 305 unit tests pass. The 3 new integration tests cover the key scenarios (registration, preservation, idempotency).
Run Summary
| Field | Value |
|---|---|
| Event | pull_request |
| Repository | marcusrbrown/systematic |
| Run ID | 23623939763 |
| Cache | hit |
| Session | ses_2d36c561dffe7Lv2HUAsRmVwLp |
Summary
bundledSkillsDirinconfig.skills.pathsduring the config hook, enabling OpenCode's nativeskilltool to discover Systematic skills/systematic:brainstorming) AND via the nativeskilltoolConfigWithSkillstype bridges the v1→v2 SDK type gap until import upgradeWhat changed
src/lib/config-handler.tsregisterSkillsPaths()— appends the bundled skills directory toconfig.skills.pathscreateConfigHandler's config hook, after existing agent/command/skill mergingConfigWithSkillstype extension since v1 SDK types don't includeskills.paths(v2 does)tests/integration/opencode.test.tsregisters bundled skills dir in config.skills.paths— verifies the path is addedpreserves existing skills.paths entries— verifies existing paths aren't clobbereddoes not duplicate skills.paths on repeated calls— verifies idempotencyVerification