Skip to content

feat: register bundled skills via config.skills.paths#244

Merged
marcusrbrown merged 1 commit intomainfrom
feat/skills-paths
Mar 27, 2026
Merged

feat: register bundled skills via config.skills.paths#244
marcusrbrown merged 1 commit intomainfrom
feat/skills-paths

Conversation

@marcusrbrown
Copy link
Owner

Summary

  • Register bundledSkillsDir in config.skills.paths during the config hook, enabling OpenCode's native skill tool to discover Systematic skills
  • Pattern adapted from Superpowers plugin
  • Skills are now discoverable both as slash commands (/systematic:brainstorming) AND via the native skill tool
  • Local ConfigWithSkills type bridges the v1→v2 SDK type gap until import upgrade

What changed

src/lib/config-handler.ts

  • Added registerSkillsPaths() — appends the bundled skills directory to config.skills.paths
  • Called at the end of createConfigHandler's config hook, after existing agent/command/skill merging
  • Uses ConfigWithSkills type extension since v1 SDK types don't include skills.paths (v2 does)

tests/integration/opencode.test.ts

  • registers bundled skills dir in config.skills.paths — verifies the path is added
  • preserves existing skills.paths entries — verifies existing paths aren't clobbered
  • does not duplicate skills.paths on repeated calls — verifies idempotency

Verification

Check Result
Build ✅ exit 0
Typecheck ✅ exit 0
Lint ✅ 54 files, no fixes
Unit tests ✅ 305/305
Integration tests ✅ 22/22 (3 new)

…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 fro-bot added the agent: working Agent is currently working on this label Mar 26, 2026
Copy link
Collaborator

@fro-bot fro-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: PASS

Blocking issues

None.

Non-blocking concerns

  • registerSkillsPaths mutates 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 on registerSkillsPaths says "Register a directory for OpenCode's native skill discovery (skill tool)" but doesn't document the mutation behavior. Consider adding @mutates config or similar annotation for clarity, or a brief note in the function doc.

  • SDK upgrade timeline: The ConfigWithSkills type 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.command is 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, .js extensions)
  • 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

@fro-bot fro-bot removed the agent: working Agent is currently working on this label Mar 27, 2026
@marcusrbrown marcusrbrown merged commit d0fcffa into main Mar 27, 2026
11 checks passed
@marcusrbrown marcusrbrown deleted the feat/skills-paths branch March 27, 2026 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants