Skip to content

feat(init): add OpenCode tool support#1

Closed
retran wants to merge 2 commits intomainfrom
feat/opencode-tool-support
Closed

feat(init): add OpenCode tool support#1
retran wants to merge 2 commits intomainfrom
feat/opencode-tool-support

Conversation

@retran
Copy link
Copy Markdown
Owner

@retran retran commented Mar 27, 2026

Summary

  • Adds --tool opencode to mxcli init and mxcli add-tool with full support on par with the other tools
  • OpenCode gets dedicated skills (.opencode/skills/<name>/SKILL.md with YAML frontmatter), slash commands (.opencode/commands/), opencode.json, and Starlark lint rules written to .claude/lint-rules/ (shared path used by mxcli lint)
  • VS Code extension is installed for the opencode tool the same way it is for claude

Commits

  • feat(init): add OpenCode tool support with skills, commands, and lint rules — code changes in cmd/mxcli/ (tool_templates.go, init.go, cmd_add_tool.go) + 13 new tests in init_test.go
  • docs: add OpenCode integration documentation — new docs-site/src/tutorial/opencode.md page, SUMMARY.md nav entry, and updates to ai-assistants.md, other-ai-tools.md, mxcli-init.md, README.md

Notes

  • Claude Code remains the default tool; OpenCode is listed second
  • Lint rules go to .claude/lint-rules/ regardless of tool selection so mxcli lint works the same way for both
  • The pre-existing TUI Unix socket test failures (TestAgentListenerAcceptsConnection etc.) are unrelated to this PR — they fail on unmodified main due to a macOS socket path length limit

retran added 2 commits March 27, 2026 17:17
… rules

- Add 'opencode' to SupportedTools map in tool_templates.go with generateOpenCodeConfig()
- Write skills to .opencode/skills/<name>/SKILL.md with YAML frontmatter
- Write commands to .opencode/commands/
- Write lint rules to .claude/lint-rules/ (shared path used by mxcli lint)
- Write opencode.json pointing to AGENTS.md and .ai-context/skills/
- Install VS Code extension for opencode tool same as claude
- Add wrapSkillContent() and extractSkillDescription() helpers
- Update cmd_add_tool.go Long description to list opencode
- Add 13 tests (unit + integration) in init_test.go
- New dedicated tutorial page (docs-site/src/tutorial/opencode.md)
- Add OpenCode to SUMMARY.md nav after claude-code.md
- Update ai-assistants.md: count five -> six, add OpenCode row
- Update other-ai-tools.md: add OpenCode section with link to dedicated page
- Update mxcli-init.md Supported AI Tools table with OpenCode row
- Update README.md intro sentence and Supported AI Tools table
Copilot AI review requested due to automatic review settings March 27, 2026 16:18
@retran
Copy link
Copy Markdown
Owner Author

retran commented Mar 27, 2026

Superseded by upstream PR mendixlabs#47

@retran retran closed this Mar 27, 2026
Copy link
Copy Markdown

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 OpenCode as a first-class mxcli init / documentation integration alongside existing AI tool integrations, including dedicated OpenCode config files and generated project scaffolding.

Changes:

  • Adds --tool opencode support and generates opencode.json plus .opencode/{commands,skills} and shared lint rules output.
  • Adds unit/integration tests covering OpenCode init output (structure, frontmatter, commands, lint rules).
  • Expands docs site + README to document OpenCode usage and navigation.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
docs-site/src/tutorial/other-ai-tools.md Documents OpenCode as a supported tool and shows init usage.
docs-site/src/tutorial/opencode.md New OpenCode walkthrough page.
docs-site/src/tutorial/ai-assistants.md Updates supported tool list to include OpenCode.
docs-site/src/ide/mxcli-init.md Adds OpenCode row to mxcli init tool table.
docs-site/src/SUMMARY.md Adds OpenCode page to docs navigation.
cmd/mxcli/tool_templates.go Registers OpenCode tool and adds opencode.json template generator.
cmd/mxcli/init_test.go New tests validating OpenCode init output and skill wrapping behavior.
cmd/mxcli/init.go Implements OpenCode-specific directory creation, skill wrapping, command copying, lint rule copying, and VS Code extension install trigger.
cmd/mxcli/cmd_add_tool.go Adds OpenCode to the add-tool help text.
README.md Mentions OpenCode in supported assistants list and tool table.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +13 to +15
// cobra Run closure against dir, then restores the original value. The
// function panics if initListTools or initAllTools are left non-default from a
// previous test.
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The runInit comment says the helper panics if initListTools or initAllTools were modified by a previous test, but the function doesn’t actually check those globals. Either add the asserted checks/panic, or update the comment to reflect what the helper really does.

Suggested change
// cobra Run closure against dir, then restores the original value. The
// function panics if initListTools or initAllTools are left non-default from a
// previous test.
// cobra Run closure against dir, then restores the original value via
// t.Cleanup.
//

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +54
The `opencode.json` file is OpenCode's primary configuration. It points to `AGENTS.md` for instructions and to the skill files in `.opencode/skills/`:

```json
{
"instructions": ["AGENTS.md", ".ai-context/skills/*.md"],
"model": "anthropic/claude-sonnet-4-5"
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The opencode.json section is internally inconsistent with the JSON snippet and with what mxcli actually generates: it claims the file points to .opencode/skills/, but the snippet references .ai-context/skills/*.md; it also shows a model field, while the generator writes a $schema field and no model. Please align this page with the real opencode.json output/behavior so users don’t configure OpenCode incorrectly.

Suggested change
The `opencode.json` file is OpenCode's primary configuration. It points to `AGENTS.md` for instructions and to the skill files in `.opencode/skills/`:
```json
{
"instructions": ["AGENTS.md", ".ai-context/skills/*.md"],
"model": "anthropic/claude-sonnet-4-5"
The `opencode.json` file is OpenCode's primary configuration. It points to `AGENTS.md` for instructions and to the shared skill files in `.ai-context/skills/`, matching what `mxcli init` generates:
```json
{
"$schema": "https://schemas.mxapps.io/mxcli/opencode.schema.json",
"instructions": ["AGENTS.md", ".ai-context/skills/*.md"]

Copilot uses AI. Check for mistakes.
Comment on lines +81 to +90
"opencode": {
Name: "OpenCode",
Description: "OpenCode AI agent with MDL commands and skills",
Files: []ToolFile{
{
Path: "opencode.json",
Content: generateOpenCodeConfig,
},
},
},
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

mxcli add-tool opencode will only create opencode.json because OpenCode’s ToolConfig.Files doesn’t include any of the .opencode/commands, .opencode/skills, or .claude/lint-rules scaffolding that init creates. Either extend add-tool to generate the same OpenCode directories/content, or adjust the docs/PR description to match what add-tool actually does.

Copilot uses AI. Check for mistakes.
"$schema": "https://opencode.ai/config.json",
"instructions": [
"AGENTS.md",
".ai-context/skills/*.md"
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

generateOpenCodeConfig only references AGENTS.md and .ai-context/skills/*.md, but init also creates OpenCode-specific skills under .opencode/skills/<name>/SKILL.md. If OpenCode is expected to load those dedicated skill files, the generated opencode.json should include the .opencode/skills/**/SKILL.md paths (and possibly commands) or the OpenCode skill generation in init will be unused.

Suggested change
".ai-context/skills/*.md"
".ai-context/skills/*.md",
".opencode/skills/**/SKILL.md"

Copilot uses AI. Check for mistakes.
Comment on lines +315 to +337
lintRuleCount := 0
err = fs.WalkDir(lintRulesFS, "lint-rules", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
content, err := lintRulesFS.ReadFile(path)
if err != nil {
return err
}
targetPath := filepath.Join(lintRulesDir, d.Name())
if err := os.WriteFile(targetPath, content, 0644); err != nil {
return err
}
lintRuleCount++
return nil
})
if err != nil {
fmt.Fprintf(os.Stderr, " Error writing lint rules: %v\n", err)
} else {
fmt.Printf(" Created %d lint rule files in .claude/lint-rules/\n", lintRuleCount)
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

When both claude and opencode are selected, lint rules are written once in the Claude block and again in the OpenCode block (same destination lintRulesDir). This duplicates work and results in duplicate "Created X lint rule files" output; consider writing lint rules once when either tool requires them (outside the per-tool branches) or guarding the OpenCode lint rule walk when Claude already handled it.

Suggested change
lintRuleCount := 0
err = fs.WalkDir(lintRulesFS, "lint-rules", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
content, err := lintRulesFS.ReadFile(path)
if err != nil {
return err
}
targetPath := filepath.Join(lintRulesDir, d.Name())
if err := os.WriteFile(targetPath, content, 0644); err != nil {
return err
}
lintRuleCount++
return nil
})
if err != nil {
fmt.Fprintf(os.Stderr, " Error writing lint rules: %v\n", err)
} else {
fmt.Printf(" Created %d lint rule files in .claude/lint-rules/\n", lintRuleCount)
lintRulesPopulated := false
if entries, dirErr := os.ReadDir(lintRulesDir); dirErr == nil {
for _, entry := range entries {
if !entry.IsDir() {
lintRulesPopulated = true
break
}
}
}
if !lintRulesPopulated {
lintRuleCount := 0
err = fs.WalkDir(lintRulesFS, "lint-rules", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
content, err := lintRulesFS.ReadFile(path)
if err != nil {
return err
}
targetPath := filepath.Join(lintRulesDir, d.Name())
if err := os.WriteFile(targetPath, content, 0644); err != nil {
return err
}
lintRuleCount++
return nil
})
if err != nil {
fmt.Fprintf(os.Stderr, " Error writing lint rules: %v\n", err)
} else {
fmt.Printf(" Created %d lint rule files in .claude/lint-rules/\n", lintRuleCount)
}

Copilot uses AI. Check for mistakes.
Comment on lines +474 to +487
// extractSkillDescription returns a one-line description for the skill by
// finding the first top-level markdown heading (# ...) and stripping a leading
// "Skill: " prefix if present. Falls back to the skill name if no heading is
// found.
func extractSkillDescription(content []byte) string {
for _, line := range strings.Split(string(content), "\n") {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "# ") {
desc := strings.TrimPrefix(line, "# ")
desc = strings.TrimPrefix(desc, "Skill: ")
return strings.TrimSpace(desc)
}
}
return "MDL skill"
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The doc comment says the description “Falls back to the skill name if no heading is found”, but the implementation actually returns the constant "MDL skill". Update the comment or change the fallback to match the documented behavior.

Copilot uses AI. Check for mistakes.
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