You have written a useful Agent Skill. Its SKILL.md has a focused workflow, and a small Python script carries out the repetitive part. The script sits right beside the skill, exactly where a future maintainer expects to find it:
Then you tell GitHub Copilot to run it with what looks like the obvious command:
1python scripts/myscript.pySometimes that works. In fact, in the past it seemed to work fairly reliably, but AI is a fast-moving target and things change. Now, I’ve been seeing Copilot invoke the terminal from your active workspace root more frequently; the command fails because that root has no scripts/myscript.py, and the agent has to spend a turn reasoning about where the skill lives before trying again.
This is a small detail, but it matters when you use skills often. Every failed tool call adds latency, adds an error to the context, provides misleading path information, and asks the model to recover from a situation rather than focus on the task at hand. The fix is not to abandon relative references. The model just needs a better anchor for executable commands.
The documented guidance seems reasonable
The Agent Skills guide is clear about the intended convention:
Use relative paths from the skill directory root to reference bundled files. The agent resolves these paths automatically – no absolute paths needed.
It provides an example with a bundled script, scripts/validate.sh, and a SKILL.md that tells the agent to invoke bash scripts/validate.sh "$INPUT_FILE". The page also states that script paths in command blocks are relative to the skill directory root because the agent runs commands from there.
Visual Studio Code’s Agent Skills documentation gives closely related advice for files included with a skill. It recommends Markdown links using relative paths, such as [test template](./test-template.js), and says that you can reference files within the skill directory the same way.
In other words, the harness should handle the relative path correctly.
That is good guidance for portability and discovery. A relative link or path gives the skill loader a relationship it can understand: this script or example belongs to this SKILL.md. The problem happens when the harness is executing the script as a tool call – exactly the way the model provides it, not according to this convention. It’s not rewriting the request, it’s executing whatever the model emits verbatim.
The workspace-root surprise
Suppose the active workspace is located at /workspaces/myrepo and your skill is located in /workspaces/myrepo/.github/skills/my-skill/. Your skill contains a command to run either python ./scripts/myscript.py or python scripts/myscript.py.
Both commands mean the same thing to a shell: find scripts/myscript.py below the current working directory. In GitHub Copilot or Copilot in VS Code, the terminal commands are always run in the active workspace root, not the skill’s folder. Combine that with the fact that the model usually emits the command verbatim, and that means the tool call happens in the wrong folder. You’re now effectively executing:
1cd /workspaces/myrepo && python ./scripts/myscript.pyOf course, that file does not exist. The terminal returns an error, and only then does the model have evidence that it needs a different path. At that point, it either searches for the script or – more commonly – it reasons that it should attempt the call relative to the SKILL.md location.
The recovery is usually successful, but it is still a recovery. It also costs an additional full request-response cycle: Copilot issues the tool call, receives the failure, adds that result to its context, reasons about it, and emits the corrected call.
This is not a claim that relative paths are universally broken or that every agent host behaves identically. The important operational fact is narrower: when Copilot’s terminal command begins at the workspace root, a bare script path does not carry enough information to reach a bundled skill script reliably and consistently.
Give the model a path anchor
The simplest mitigation is an instruction near the top of SKILL.md that explicitly anchors the relative path:
In many cases, you can be even more succinct and just place this line near the top of the skill:
1Use absolute script paths rooted at this skill folder (`${SKILL_PATH}`).Then use the placeholder in the SKILL.md command block:
1Execute `python ${SKILL_PATH}/scripts/myscript.py` to validate and process the input.To be clear, ${SKILL_PATH} is not a shell environment variable. Do not expect Python, Bash, or PowerShell to expand it. It is an instruction-level placeholder for the model. Copilot already knows the active workspace path and, once the skill has loaded, the skill folder that supplied its instructions. The placeholder reminds it to combine those facts before it creates the terminal command. This helps it to reason about the correct path since it already has the SKILL.md location in its context and the workspace directory.
For the example above, the model now executes this command:
1python /workspaces/myrepo/.github/skills/my-skill/scripts/myscript.pyThat command remains rooted in a real location regardless of where the terminal tool starts.
The extra wording may seem redundant to a human who is already reading SKILL.md from the skill folder. It is useful to the model because it resolves an ambiguity that exists when it turns instructions into tool calls. You are replacing an implicit assumption about a terminal’s working directory with an explicit piece of execution context. You’re also no longer relying on the harness or model to resolve relative paths correctly.
Design for the failure you can avoid
Skills already benefit from scripts that are non-interactive, provide --help, and return useful error messages. The Agent Skills guidance recommends those practices because an agent needs clear feedback to decide what to do next. Resolving the path before execution belongs in the same category: it removes a failure mode rather than asking the model to recover gracefully from it.
This matters particularly for a small wrapper script. In Dynamic Instructions for Copilot, I showed how a skill can call a script to return only the instructions that apply to the current environment. That pattern keeps the skill concise and the model focused, but it only delivers those benefits after the wrapper script actually runs. A failed first attempt delays the useful output and adds irrelevant error context.
It also connects with the cost of model-driven loading. As Why Reusing AI Instructions Costs You More Tokens explains, an agent’s follow-up reads and tool calls require more reasoning turns and accumulate more context. An erroneous terminal call is not exactly the same as loading a reference file, but the effect is familiar: another turn, another tool result, and more text for the model to sort through.
Treat ${SKILL_PATH} as a convention, not a formal Agent Skills variable. Different agents may represent the known skill location differently, and future tooling may make the documented relative command behavior consistent everywhere. Test the convention with the models and hosts your team uses.
Tools like OpenTelemetry and VS Code Agent debug logs are especially useful here: inspect the command Copilot actually emitted and its terminal working directory instead of relying on what the skill text appears to imply. That’s how you learn about these kinds of failures and can test practices that can avoid them.
Make every call count
Relative paths are still the right way to describe files that belong to a skill. They keep the skill self-contained, portable, and easy to understand. It is a small change in a small file. When a skill runs repeatedly, that is exactly the kind of change worth making: fewer failed calls, less latency, and a workflow that behaves more like the instructions you wrote.
