Skip to content

File path location error in skill #18370

Closed

Description

@util6

Description

Here is the directory structure of my skill:
skill-name/
├── SKILL.md
├── scripts/
├── references/

It's failing to resolve the paths correctly. Instead of looking inside the skill directory, it's treating the paths as relative to my workspace root, so it can't find anything in references/.

Plugins

No response

OpenCode version

No response

Steps to reproduce

No response

Screenshot and/or share link

No response

Operating System

No response

Terminal

No response

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 20, 2026
  2. github-actions commented on Mar 20, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Both issues have been closed. It may be worth checking if the fix was applied and if this is a regression, or if your setup differs in some way.

  3. util6 commented on Mar 20, 2026

    @util6
    Author
  4. zcutlip commented on Apr 8, 2026

    @zcutlip

    Many claude skills use ${CLAUDE_PLUGIN_ROOT}, as in:

    ${CLAUDE_PLUGIN_ROOT}/scripts/helper_script.sh.

    I don't think opencode supports this or something similar, but I don't know how to have a skill locate a script dynamicaly without it.

  5. zol9527 commented on Apr 14, 2026

    @zol9527

    Many claude skills use ${CLAUDE_PLUGIN_ROOT}, as in:

    ${CLAUDE_PLUGIN_ROOT}/scripts/helper_script.sh.

    I don't think opencode supports this or something similar, but I don't know how to have a skill locate a script dynamicaly without it.

    Hi friend, have you solve it? Recently I use claude code & opencode both rencetly, but opencode can't read rules, scripts path properly.

  6. zcutlip commented on Apr 15, 2026

    @zcutlip

    have you solve it?
    Sorry, no. This is a bug in opencode, and without a solution to dynamically resolve relative paths to skill resources, there's no solution.

    I will say the model is usually persistent enought to try a bunch of paths, and eventually finds the helper script, but it's annoying and is probably wasteful of tokens.

  7. removed
    bugSomething isn't working
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  8. micha149 commented on May 19, 2026

    @micha149

    I noticed that this issue only occurs when triggering the skill as a slash command like /my-skill. When doing so, the command is expanded to content of .agents/skills/my-skill/SKILL.md in my prompt. Maybe OpenCode loses the connection to the actual skill here.

    When the skill is triggered by the agent through its description, for example by saying „lets plan the next story“, paths can be resolved correctly. This can help as a workaround, too. But hopefully this will help fixing this bug.

  9. zcutlip commented on May 30, 2026

    @zcutlip

    I've been working on a project which I'll share publicly later that generates supplemental documentation for OpenCode. I won't go into details of that project here, but I've learned quite a bit about how skills work internally, and what the agent sees vs. what's presented to the user on the console.

    Here's an excerpt. Skip below for SKILL.md suggestions to help the agent locate bundled resources. (Note this is based on an older tag of the source code, so the source code reference may have changed). The excerpt below was fully automated, generated by a combination of scripts and LLM.


    The Agent's View: <skill_content>

    When the agent invokes the skill tool, it receives a structured XML block. Understanding this block is critical for writing effective skills. Here is exactly what the agent sees:

    <skill_content name="my-skill">
    
    # Skill: my-skill
    
    [the full body of your SKILL.md, minus the frontmatter]
    
    Base directory for this skill: file:///Users/you/.config/opencode/skills/my-skill/
    Relative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.
    Note: file list is sampled.
    
    <skill_files>
    <file>/Users/you/.config/opencode/skills/my-skill/scripts/helper.sh</file>
    <file>/Users/you/.config/opencode/skills/my-skill/reference/api-spec.yaml</file>
    </skill_files>
    
    </skill_content>

    Key observations for skill authors:

    1. Your content comes first, followed by metadata about the skill's directory and files. The agent may read your instructions before it gets to the path hints.
    2. The file list is sampled — only up to 10 files are shown, and SKILL.md itself is excluded. Large skills may not list all files. The agent will find unlisted files by searching.
    3. File paths are absolute, not relative. The agent can execute them directly via bash without resolving relative paths.
    4. Your SKILL.md content is emitted verbatim — no variable substitution, no macro expansion, no placeholder replacement of any kind (see next section).

    Source: packages/opencode/src/tool/skill.ts:23-72 (execute function), packages/opencode/src/tool/skill.txt (tool description)


    ...hi human here again.

    Take away: the agent doesn't have any sort of variable or macro expansion that resolves to the skill location. No special SKILL_LOCATION/scripts/script.py syntax. However, it does have more context to work with than you realize. It gets a skill_content XML block with a nested skill_files XML tag. It's also explicitly told the "Base directory" of the skill, e.g.: /Users/user/projects/ProjectName/.opencode/skills/my-fancy-skill/.

    You should be able to work with this information in your SKILL.md and the agent will know what you mean. Here's an example that's been working for me surprisingly well:

    ---
    name: dev-setup
    description: Set up development environment
    ---
    
    Run the development environment setup script.
    
    Step 1:
    
    > Note: BASE_DIRECTORY should be the "Base Directory" from your "<skill-content ... >" message.
    Execute: `{BASE_DIRECTORY}/scripts/dev-setup.sh`

    Of course rather than being preprocessed by the harness and expanded deterministically, this gets handled by the LLM probabilistically. So it's going to depend on your model and what else is in the conext window.

    But play around with it, and see if you get good results! Report back positive and negative findings so followers of this issue can take away lessons learned, until we get a proper, templated "skill location" macro.

  10. zcutlip commented on May 30, 2026

    @zcutlip

    Oh another thing I've learned: there's A LOT you can ask the agent about what it "saw" that you didn't see, and it'll help you diagnose when things went wrong. For example you can say:

    When I invoked "my-fancy-skill" you either couldn't find the helper script, or it took you several tries. I'd like to improve the skill. can you show me the "skill_content" XML block you received when I invoked it?

    This is especially effective if you switch back to a mode like Plan so the agent doesn't jump straight to fixing the problem, like "oh you're right. Now that I've found the script I'll run it..."

    Then you can back-and-forth with the agent on ideas that might improve the skill.

    Also, often when the agent tries something and fails, it gets error messages in the context window that you don't see. You can ask it to show you those, especially if you interrupted right when the error happened.

    Using the agent harness to improve the agent harness is an untapped superpower of these tools. Give it a try!

  11. zcutlip commented on May 30, 2026

    @zcutlip

    I noticed that this issue only occurs when triggering the skill as a slash command like /my-skill. When doing so, the command is expanded to content of .agents/skills/my-skill/SKILL.md in my prompt.

    @micha149 yes! This is right! One of the things I’ve been learning in my source code spelunking is commands and skills work very differently for opencode, and when you invoke a skill this way it essentially becomes a command. I.e., the skill description is dumped directly into your prompt as if it were a slash command. More importantly, it does not get the XML block described above, so it gets NONE of that context from the skill_content block. Worse, I believe it also doesn’t get the $ARGUMENTS expansion commands get, so this method is the worst of both worlds.

    DO NOT invoke skills as slash commands except for the simplest of skills.

    That said, even with the normal invocation I still have some trouble with the resolution of helper scripts, just not quite as much.

  12. shyuan commented on Jun 24, 2026

    @shyuan
    Contributor

    Identified the root cause: the skill tool emits the base directory as a file:// URL via pathToFileURL(dir).href (packages/opencode/src/tool/skill.ts). When the path contains characters that get URL-encoded — e.g. # from a git-tagged plugin cache dir (...git#v1.3.0 → ...git%23v1.3.0) — the LLM derives a read-tool path with %23 but the filesystem has #, so read returns "File not found" and references appear missing.

    The <file> entries right below already use path.resolve(dir, file.path) (plain paths), so the base directory should match them.

    Fix in #33580 — emits dir directly instead of pathToFileURL(dir).href. Also resolves the file:/// prefix issue from #23885.

  13. util6 commented on Jun 24, 2026

    @util6
    Author
  14. zcutlip commented on Jun 24, 2026

    @zcutlip

    @rekram1-node I do not believe PR #33580 addresses this issue. I think many people here, including me, are seeing file paths bundled with skills fail to resolve in variety of much broader circumstances.

    No doubht that PR addresses a bug, but I do not believe this issue is resolved.

  15. shyuan commented on Jun 25, 2026

    @shyuan
    Contributor

    @zcutlip You're right, and I want to make sure your work here isn't lost. Your comments in this thread were the most thorough tracing of this problem — the source-code spelunking into how skills work internally, the distinction between slash-command invocation vs. the skill tool, the observation about missing <skill_content> context in the command path, and the {CLAUDE_PLUGIN_ROOT} gap — all of that was essential to understanding why #33580 only fixed part of the problem.

    I've opened #33786 to capture the two remaining bug code paths you and @micha149 identified:

    1. The system prompt <available_skills> block still URL-encodes <location> (same pathToFileURL bug, second occurrence)
    2. Skills invoked as slash commands get no directory context at all — just raw SKILL.md content with no base directory or file list

    PR #33787 fixes both.

    The third issue you raised — the lack of a deterministic ${SKILL_ROOT} macro (or equivalent) for skill authors to reliably reference bundled files — is a design-level feature request. That one needs the OpenCode team to weigh in on the approach, so it belongs in a separate feature discussion rather than a bug fix PR. I'd encourage you to open that one if you haven't already, since you've clearly thought through the design tradeoffs already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions