From 1a4106120d5263ae217692625ba761a667c22dd6 Mon Sep 17 00:00:00 2001 From: Jonas Herrmansdsoerfer Date: Wed, 21 Jan 2026 13:12:27 +0100 Subject: [PATCH] fix: use correct 'skills' directory path and respect OPENCODE_CONFIG_DIR - Change skill directory from 'skill' (singular) to 'skills' (plural) to match OpenCode standard - Use getOpenCodeConfigDir() to respect OPENCODE_CONFIG_DIR environment variable - Update documentation and tests to reflect correct paths Fixes #810 --- docs/features.md | 4 ++-- src/features/AGENTS.md | 2 +- .../opencode-skill-loader/async-loader.test.ts | 2 +- src/features/opencode-skill-loader/loader.test.ts | 2 +- src/features/opencode-skill-loader/loader.ts | 12 +++++++----- src/tools/skill/types.ts | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/features.md b/docs/features.md index 38dad891..f135780e 100644 --- a/docs/features.md +++ b/docs/features.md @@ -147,8 +147,8 @@ Three specializations in one: ### Custom Skills Load custom skills from: -- `.opencode/skill/*/SKILL.md` (project) -- `~/.config/opencode/skill/*/SKILL.md` (user) +- `.opencode/skills/*/SKILL.md` (project) +- `~/.config/opencode/skills/*/SKILL.md` (user) - `.claude/skills/*/SKILL.md` (Claude Code compat) - `~/.claude/skills/*/SKILL.md` (Claude Code user) diff --git a/src/features/AGENTS.md b/src/features/AGENTS.md index 2d7abe14..cda5564c 100644 --- a/src/features/AGENTS.md +++ b/src/features/AGENTS.md @@ -36,7 +36,7 @@ features/ | Type | Priority (highest first) | |------|--------------------------| | Commands | `.opencode/command/` > `~/.config/opencode/command/` > `.claude/commands/` > `~/.claude/commands/` | -| Skills | `.opencode/skill/` > `~/.config/opencode/skill/` > `.claude/skills/` > `~/.claude/skills/` | +| Skills | `.opencode/skills/` > `~/.config/opencode/skills/` > `.claude/skills/` > `~/.claude/skills/` | | Agents | `.claude/agents/` > `~/.claude/agents/` | | MCPs | `.claude/.mcp.json` > `.mcp.json` > `~/.claude/.mcp.json` | diff --git a/src/features/opencode-skill-loader/async-loader.test.ts b/src/features/opencode-skill-loader/async-loader.test.ts index 7e901760..4b0c5b19 100644 --- a/src/features/opencode-skill-loader/async-loader.test.ts +++ b/src/features/opencode-skill-loader/async-loader.test.ts @@ -5,7 +5,7 @@ import { tmpdir } from "os" import type { LoadedSkill } from "./types" const TEST_DIR = join(tmpdir(), "async-loader-test-" + Date.now()) -const SKILLS_DIR = join(TEST_DIR, ".opencode", "skill") +const SKILLS_DIR = join(TEST_DIR, ".opencode", "skills") function createTestSkill(name: string, content: string, mcpJson?: object): string { const skillDir = join(SKILLS_DIR, name) diff --git a/src/features/opencode-skill-loader/loader.test.ts b/src/features/opencode-skill-loader/loader.test.ts index 34b03beb..8e550b17 100644 --- a/src/features/opencode-skill-loader/loader.test.ts +++ b/src/features/opencode-skill-loader/loader.test.ts @@ -4,7 +4,7 @@ import { join } from "path" import { tmpdir } from "os" const TEST_DIR = join(tmpdir(), "skill-loader-test-" + Date.now()) -const SKILLS_DIR = join(TEST_DIR, ".opencode", "skill") +const SKILLS_DIR = join(TEST_DIR, ".opencode", "skills") function createTestSkill(name: string, content: string, mcpJson?: object): string { const skillDir = join(SKILLS_DIR, name) diff --git a/src/features/opencode-skill-loader/loader.ts b/src/features/opencode-skill-loader/loader.ts index 4bff1ca1..081eb339 100644 --- a/src/features/opencode-skill-loader/loader.ts +++ b/src/features/opencode-skill-loader/loader.ts @@ -1,11 +1,11 @@ import { promises as fs } from "fs" import { join, basename } from "path" -import { homedir } from "os" import yaml from "js-yaml" import { parseFrontmatter } from "../../shared/frontmatter" import { sanitizeModelField } from "../../shared/model-sanitizer" import { resolveSymlinkAsync, isMarkdownFile } from "../../shared/file-utils" import { getClaudeConfigDir } from "../../shared" +import { getOpenCodeConfigDir } from "../../shared/opencode-config-dir" import type { CommandDefinition } from "../claude-code-command-loader/types" import type { SkillScope, SkillMetadata, LoadedSkill, LazyContentLoader } from "./types" import type { SkillMcpConfig } from "../skill-mcp-manager/types" @@ -187,13 +187,14 @@ export async function loadProjectSkills(): Promise> { - const opencodeSkillsDir = join(homedir(), ".config", "opencode", "skill") + const configDir = getOpenCodeConfigDir({ binary: "opencode" }) + const opencodeSkillsDir = join(configDir, "skills") const skills = await loadSkillsFromDir(opencodeSkillsDir, "opencode") return skillsToRecord(skills) } export async function loadOpencodeProjectSkills(): Promise> { - const opencodeProjectDir = join(process.cwd(), ".opencode", "skill") + const opencodeProjectDir = join(process.cwd(), ".opencode", "skills") const skills = await loadSkillsFromDir(opencodeProjectDir, "opencode-project") return skillsToRecord(skills) } @@ -249,11 +250,12 @@ export async function discoverProjectClaudeSkills(): Promise { } export async function discoverOpencodeGlobalSkills(): Promise { - const opencodeSkillsDir = join(homedir(), ".config", "opencode", "skill") + const configDir = getOpenCodeConfigDir({ binary: "opencode" }) + const opencodeSkillsDir = join(configDir, "skills") return loadSkillsFromDir(opencodeSkillsDir, "opencode") } export async function discoverOpencodeProjectSkills(): Promise { - const opencodeProjectDir = join(process.cwd(), ".opencode", "skill") + const opencodeProjectDir = join(process.cwd(), ".opencode", "skills") return loadSkillsFromDir(opencodeProjectDir, "opencode-project") } diff --git a/src/tools/skill/types.ts b/src/tools/skill/types.ts index 3817158c..d22951e0 100644 --- a/src/tools/skill/types.ts +++ b/src/tools/skill/types.ts @@ -18,7 +18,7 @@ export interface SkillInfo { } export interface SkillLoadOptions { - /** When true, only load from OpenCode paths (.opencode/skill/, ~/.config/opencode/skill/) */ + /** When true, only load from OpenCode paths (.opencode/skills/, ~/.config/opencode/skills/) */ opencodeOnly?: boolean /** Pre-merged skills to use instead of discovering */ skills?: LoadedSkill[]