feat: add --skills support to opencode integration#2494
Open
tinesoft wants to merge 1 commit intogithub:mainfrom
Open
feat: add --skills support to opencode integration#2494tinesoft wants to merge 1 commit intogithub:mainfrom
--skills support to opencode integration#2494tinesoft wants to merge 1 commit intogithub:mainfrom
Conversation
--skills support to opencode integration
5b3b00c to
ac6514e
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an opt-in --skills mode to the opencode integration so scaffolding can produce agentskills.io-style SKILL.md files under .opencode/skills/<skill>/SKILL.md, with accompanying tests.
Changes:
- Added a
--skillsintegration option toOpencodeIntegrationand asetup()branch to scaffold skills-format outputs. - Added Opencode skills-mode tests validating SKILL.md creation, frontmatter shape, and that default markdown mode remains unchanged.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/specify_cli/integrations/opencode/__init__.py |
Adds --skills option and delegates setup to SkillsIntegration when enabled. |
tests/integrations/test_integration_opencode.py |
Adds a new test class covering skills-mode scaffolding behavior and SKILL.md frontmatter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+40
to
+59
| def setup( | ||
| self, | ||
| project_root: Path, | ||
| manifest: IntegrationManifest, | ||
| parsed_options: dict[str, Any] | None = None, | ||
| **opts: Any, | ||
| ) -> list[Path]: | ||
| if (parsed_options or {}).get("skills"): | ||
| helper = SkillsIntegration() | ||
| helper.key = self.key | ||
| helper.config = {**self.config, "commands_subdir": "skills"} | ||
| helper.registrar_config = { | ||
| "dir": ".opencode/skills", | ||
| "format": "markdown", | ||
| "args": "$ARGUMENTS", | ||
| "extension": "/SKILL.md", | ||
| } | ||
| helper.context_file = self.context_file | ||
| return helper.setup(project_root, manifest, parsed_options, **opts) | ||
| return super().setup(project_root, manifest, parsed_options, **opts) |
Comment on lines
+65
to
+125
| class TestOpencodeSkillsMode: | ||
| KEY = "opencode" | ||
|
|
||
| def test_skills_option_declared(self): | ||
| integration = get_integration(self.KEY) | ||
| opts = integration.options() | ||
| names = [o.name for o in opts] | ||
| assert "--skills" in names | ||
| skills_opt = next(o for o in opts if o.name == "--skills") | ||
| assert skills_opt.is_flag is True | ||
| assert skills_opt.default is False | ||
|
|
||
| def test_skills_mode_creates_skill_md_files(self, tmp_path): | ||
| integration = get_integration(self.KEY) | ||
| manifest = IntegrationManifest(self.KEY, tmp_path) | ||
| created = integration.setup(tmp_path, manifest, parsed_options={"skills": True}, script_type="sh") | ||
|
|
||
| skill_files = [p for p in created if p.name == "SKILL.md"] | ||
| assert skill_files | ||
|
|
||
| skills_dir = tmp_path / ".opencode" / "skills" | ||
| assert skills_dir.is_dir() | ||
|
|
||
| specify_skill = skills_dir / "speckit-specify" / "SKILL.md" | ||
| assert specify_skill.exists() | ||
|
|
||
| def test_skills_mode_does_not_create_md_command_files(self, tmp_path): | ||
| integration = get_integration(self.KEY) | ||
| manifest = IntegrationManifest(self.KEY, tmp_path) | ||
| integration.setup(tmp_path, manifest, parsed_options={"skills": True}, script_type="sh") | ||
|
|
||
| command_dir = tmp_path / ".opencode" / "command" | ||
| md_files = list(command_dir.glob("*.md")) if command_dir.exists() else [] | ||
| assert md_files == [] | ||
|
|
||
| def test_skills_mode_frontmatter(self, tmp_path): | ||
| integration = get_integration(self.KEY) | ||
| manifest = IntegrationManifest(self.KEY, tmp_path) | ||
| integration.setup(tmp_path, manifest, parsed_options={"skills": True}, script_type="sh") | ||
|
|
||
| skill_path = tmp_path / ".opencode" / "skills" / "speckit-plan" / "SKILL.md" | ||
| assert skill_path.exists() | ||
|
|
||
| content = skill_path.read_text(encoding="utf-8") | ||
| parts = content.split("---", 2) | ||
| parsed = yaml.safe_load(parts[1]) | ||
|
|
||
| assert parsed["name"] == "speckit-plan" | ||
| assert "description" in parsed | ||
| assert "compatibility" in parsed | ||
| assert parsed["metadata"]["author"] == "github-spec-kit" | ||
|
|
||
| def test_default_mode_unchanged(self, tmp_path): | ||
| integration = get_integration(self.KEY) | ||
| manifest = IntegrationManifest(self.KEY, tmp_path) | ||
| integration.setup(tmp_path, manifest, script_type="sh") | ||
|
|
||
| command_dir = tmp_path / ".opencode" / "command" | ||
| assert command_dir.is_dir() | ||
| md_files = list(command_dir.glob("*.md")) | ||
| assert md_files |
Adds opt-in `--skills` support to OpencodeIntegration, producing `speckit-<name>/SKILL.md` files under `.opencode/skills/` instead of flat `.md` files. Opencode natively supports this format (https://opencode.ai/docs/skills/). Activate via: `specify init --integration opencode --integration-options="--skills"`
ac6514e to
da2958b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds opt-in
--skillssupport toOpencodeIntegration, mirroring the pattern used byClaudeIntegration. When the flagis passed, commands are scaffolded as
speckit-<name>/SKILL.mdfiles under.opencode/skills/instead of flat.mdfiles under
.opencode/command/.Opencode natively supports the agentskills.io SKILL.md format at
.opencode/skills/<name>/SKILL.md(seehttps://opencode.ai/docs/skills/), with the same frontmatter (
name,description,compatibility,metadata) thatCommandRegistrar.build_skill_frontmatter()already produces — so no custom post-processing was needed.Activate via:
specify init --integration opencode --integration-options="--skills"Testing
uv run specify --helpuv sync --extra test && uv run pytestAll 28 opencode integration tests pass, including 5 new tests in
TestOpencodeSkillsModecovering:--skillsoption declaration (is_flag=True,default=False).opencode/skills/.mdcommand files created in skills modename,description,compatibility,metadata.author)Agent config consistency check (
tests/test_agent_config_consistency.py) also passes (26/26).Manual smoke test:
AI Disclosure
This PR was written with Claude Code (claude-sonnet-4-6). The implementation approach, code, and tests were generated
with AI assistance and reviewed and validated by the author.