🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

feat: return workspace skill directory from read_skill - #26713

Merged
kylecarbs merged 5 commits into
mainfrom
feat/skill-dir-read-skill
Jun 25, 2026
Merged

feat: return workspace skill directory from read_skill#26713
kylecarbs merged 5 commits into
mainfrom
feat/skill-dir-read-skill

Conversation

@kylecarbs

Copy link
Copy Markdown
Member

Summary

Workspace skills live on the workspace filesystem, and the agent's read_file/execute tools already operate on that same filesystem. But a skill's absolute directory was never surfaced to the model:

  • the <available-skills> catalog lists only name + description,
  • read_skill returned {name, body, files} where files are relative names, and
  • read_skill_file is relative-path-scoped (it rejects absolute paths, .., and hidden files).

As a result, a bundled scripts/foo.sh could be read but never run, and the agent had no way to browse or glob the skill directory.

Change

read_skill now returns dir, the absolute skill directory, for workspace skills. The model can join dir with a supporting file's relative path and pass the result to read_file or execute (which share the same workspace connection), so bundled scripts are runnable and the directory is browsable. This matches how Agent Skills work in coder/mux and openai/codex.

  • Personal skills are database-backed with no supporting files, so dir is omitted for them.
  • read_skill_file is unchanged and remains a path-safe convenience for reading supporting files.
  • Progressive disclosure is preserved: the path is revealed only when a skill is activated via read_skill, not in the always-on catalog.

Why this is safe

No new capability or boundary is crossed. The agent already has unrestricted workspace filesystem access through read_file/execute; the relative-only restriction on read_skill_file is a guardrail for that one convenience tool, not a sandbox around the agent. ChatMessagePart.SkillDir remains typescript:"-" and is still stripped by StripInternal() from the API/SSE wire format sent to the frontend. This change only affects the model-facing read_skill tool response.

Testing

  • go test ./coderd/x/chatd/chattool/ (skill tool tests) and ./coderd/x/chatd/ (skill prompt/merge tests)
  • gofmt, go vet, golangci-lint (clean), markdownlint (0 errors)
Investigation & decision log

Root cause trace

  • Discovery records the absolute dir: agent/agentcontextconfig/api.go discoverSkills sets SkillDir on the skill context part.
  • Catalog hides it: coderd/x/chatd/chattool/skill.go renderSkillIndex emits only - <alias>: <description>.
  • read_skill omitted it: the SourceWorkspace branch returned only name, body, and relative files.
  • read_skill_file is dir-scoped: validateSkillFilePath rejects absolute/../hidden, LoadSkillFile joins path.Join(skill.Dir, relativePath) server-side.
  • Wire-format stripping is separate from the model view: codersdk/chats.go StripInternal() zeroes SkillDir for API/SSE responses (typescript:"-"), which is the frontend channel, not the LLM tool channel.

Key insight

In coderd/x/chatd/generation_preparer.go, read_file, execute, and the skill tools are all wired with the same GetWorkspaceConn. execute runs via conn.StartProcess and read_file via conn.ReadFileLines, both on the workspace filesystem where skills live. The agent was fully capable of reading/running bundled files; it just lacked the absolute path.

Alternatives considered

  • Put the dir in the catalog index — rejected: bloats the always-on prompt and leaks paths for never-used skills, breaking progressive disclosure.
  • Return per-file absolute paths (files: [{path, abs}]) — heavier wire change; the single dir is sufficient since the model can join.
  • Drop read_skill_file and hand over only the dir (pure Agent Skills model) — larger redesign; reasonable as a future simplification, out of scope here.

PR generated with Coder Agents on behalf of @kylecarbs.

Workspace skills live on the workspace filesystem, and the agent's
read_file and execute tools already operate on that same filesystem.
But the skill's absolute directory was never surfaced to the model, so
bundled supporting files (for example a scripts/ helper) could only be
read through the relative-path-scoped read_skill_file tool and could
never be run.

read_skill now returns "dir", the absolute skill directory, for
workspace skills. The model can join it with a supporting file's
relative path to read or run that file with read_file or execute.
Personal skills are database-backed with no files, so dir is omitted
for them.
@github-actions

Copy link
Copy Markdown

Docs preview

📖 View docs preview for docs/ai-coder/agents/extending-agents.md

Make the read_skill response field self-documenting. "dir" was terse, and
"workspace_directory" would collide with the existing notion of the
workspace working directory (ContextFileDirectory, execute's WorkDir); the
value is the skill's own subdirectory, so "skill_directory" is clearer and
unambiguous.

@mafredri mafredri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving. But think the description could use a re-think.

Comment thread coderd/x/chatd/chattool/skill.go Outdated
Comment thread coderd/x/chatd/chattool/skill.go Outdated
Address review feedback: trim the read_skill tool description to a
breadcrumb that just notes workspace skills also return "dir" (the
absolute skill directory), without prescribing read_file/execute usage
or implying read_skill_file should be avoided. Also condense the
in-function comment.
…ription

The model already sees the "dir" field in the read_skill response, so
calling it out in the tool description is redundant. Restore the original
description; the field and the explanatory code comment stay.
@kylecarbs
kylecarbs merged commit 48fd0ef into main Jun 25, 2026
29 of 30 checks passed
@kylecarbs
kylecarbs deleted the feat/skill-dir-read-skill branch June 25, 2026 18:05
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants