Skip to content

feat: add --skills support to opencode integration#2494

Open
tinesoft wants to merge 1 commit intogithub:mainfrom
tinesoft:feat/opencode-skills
Open

feat: add --skills support to opencode integration#2494
tinesoft wants to merge 1 commit intogithub:mainfrom
tinesoft:feat/opencode-skills

Conversation

@tinesoft
Copy link
Copy Markdown
Contributor

@tinesoft tinesoft commented May 8, 2026

Description

Adds opt-in --skills support to OpencodeIntegration, mirroring the pattern used by ClaudeIntegration. When the flag
is passed, commands are scaffolded as speckit-<name>/SKILL.md files under .opencode/skills/ instead of flat .md
files under .opencode/command/.

Opencode natively supports the agentskills.io SKILL.md format at .opencode/skills/<name>/SKILL.md (see
https://opencode.ai/docs/skills/), with the same frontmatter (name, description, compatibility, metadata) that
CommandRegistrar.build_skill_frontmatter() already produces — so no custom post-processing was needed.

Activate via:

specify init --integration opencode --integration-options="--skills"

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync --extra test && uv run pytest
  • Tested with a sample project (if applicable)

All 28 opencode integration tests pass, including 5 new tests in TestOpencodeSkillsMode covering:

  • --skills option declaration (is_flag=True, default=False)
  • SKILL.md file creation under .opencode/skills/
  • No .md command files created in skills mode
  • Correct SKILL.md frontmatter (name, description, compatibility, metadata.author)
  • Regression guard confirming default markdown mode is unchanged

Agent config consistency check (tests/test_agent_config_consistency.py) also passes (26/26).

Manual smoke test:

specify init /tmp/speckit-test --integration opencode --integration-options="--skills"
# ✅ .opencode/skills/speckit-specify/SKILL.md created
specify init /tmp/speckit-test2 --integration opencode                                                                   
# ✅ .opencode/command/speckit.specify.md created (default mode unchanged)

AI Disclosure

  • I did use AI assistance (describe below)

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.

Copilot AI review requested due to automatic review settings May 8, 2026 05:19
@tinesoft tinesoft requested a review from mnriem as a code owner May 8, 2026 05:19
@tinesoft tinesoft changed the title feat: add --skills flag to scaffold commands as SKILL.md files feat: add --skills support to opencode integration May 8, 2026
@tinesoft tinesoft force-pushed the feat/opencode-skills branch from 5b3b00c to ac6514e Compare May 8, 2026 05:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 --skills integration option to OpencodeIntegration and a setup() 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"`
@tinesoft tinesoft force-pushed the feat/opencode-skills branch from ac6514e to da2958b Compare May 8, 2026 10:36
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