GeezerVison is showing github.com — feat: add skill action and automatic-use settings by jaaydenh · Pull Request #30882 · coder/coder
Conversation
jaaydenh
commented
Oct 15, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Adds two per-skill settings that the project skills UI will expose next:
action marks a project skill to show as an action button above project chat composers. A skills_action_project_only check keeps it to project skills; the personal and organization routes reject action with 400.
model_invocable (default true, every stored source) controls automatic use. When it's false the skill is left out of <available-skills> and read_skill reports it as not found, but a structured skill invocation (a chip from the / menu or an action) still loads it, as long as the skill is enabled and the chat owner can read it. Workspace skills always count as model-invocable.
Migration 000625 adds both columns with defaults, so existing skills keep today's behavior. The list, get, insert and update queries, codersdk.SkillMetadata and the create/update requests carry both fields, and the audit table tracks them. coderd/x/chatd/ARCHITECTURE.md gets TODO notes for the author.
NOTE: the migration adds two columns with constant defaults and a CHECK constraint to skills.
Stack (merge top to bottom):
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
…g in the slash menu
Organization and project skills load through one hook, and the menu
renders its skill groups from one ordered list. Adds project loading and
error stories.
…lify skill group offsets
…nd resolve emptiness in the hook
Cover the project-only skill tool check in the integration test, the
project skill body loader's not-found mapping, and the chat-projects
experiment gate in the composer.
… request instead of menu markup
…ed skill helpers
Split the form body of SkillEditor into SkillEditorForm, settle saves
through a mutate callback so the editor stays locked until the request
finishes, move the read-only enabled indicator into SkillEnabledSwitch,
and share the empty and loaded form value helpers in utils/skills.ts.
Add API methods and query factories to read, create, update, and delete
chat project skills, a projectSkillsScope for the shared skill helpers,
and ProjectSkillsDialog, which lists a project's skills and edits them
with SkillEditorForm.
Add a Skills row to the project Details panel that opens
ProjectSkillsDialog, with stories for the dialog and the panel, and
document where project skills are managed.
Add a skill-invocation chat input and message part. chatd loads the
invoked skill body with the chat owner's permissions when a message is
created, sent, or edited, stores it on the part, and renders it into
the user's prompt inside <invoked-skill>. Unavailable skills reject the
request with a 400. The stored body is internal and never returned by
the API.
… focusable and cover submit settlement
…t-skills/project-skills-dialog
…ts through refetches and handle deleted skills
…oject-skills/project-skills-details
… and toggle tests to the Details row PR
…downloads, toggles, refetches and deleted skills
…roject-skills/invocation-api
…ll details after deletes and refresh after download 404s
…t-skills/project-skills-dialog
…oject-skills/project-skills-details
…permission check failures
…etail eviction and download 404 refreshes
…roject-skills/invocation-api
…after main's 000630 and 000631
…transcript' into rs-skill-chips-transcript
jaaydenh
added a commit
that referenced
this pull request
Oct 22, 2026
Choosing a skill from the `/` menu now inserts a skill chip into the
composer instead of `/alias` text, and the message sends it as a
structured `skill-invocation` part (#30861), so chatd loads that exact
skill's body into the prompt.
- A Lexical `SkillInvocationNode` renders the chip with a remove button;
`/clear` and `/compact` still insert as commands, and typed `/name` text
that wasn't picked from the menu still goes out as plain text (#31126
turns a typed full alias into a chip).
- `buildChatInputContent` emits text and skill parts in document order,
a chip-only message can be sent, drafts keep chips, and the new chat
form forwards them.
- `insertSkill(source, name)` on the composer handle inserts a chip at
the caret without duplicating one that's already there. The project
action bar later in this stack uses it.
- Arrow keys step over chips instead of selecting them. Selecting a chip
node dropped the browser selection, so the next keystroke landed at the
start of the message; file reference chips had the same bug and get the
same fix.
- Copy and paste keep chips: copied text includes `/source/name`,
pasting skips a chip that's already in the composer, and a chip for a
skill this chat can't use is pasted as plain text.
Rendering the parts in the transcript and edit flow is in the next PR.
Dogfood UAT passed on this stack: picking project, personal and
organization skills sends one skill part each and the agent answers from
the skill body without calling `read_skill`; the caret, paste and copy
cases above, drafts, `/clear`, `/compact` and the 400 for a disabled or
deleted skill all behaved as expected.
| Chip in the composer | Sent message in the transcript |
| --- | --- |
| <img alt="Skill chip in the project composer"
src="https://raw.githubusercontent.com/coder/coder/assets/pr-30880-skill-chips/pr/composer-chip.png"
width="600" /> | <img alt="Skill chip in the sent message with the
codeword reply"
src="https://raw.githubusercontent.com/coder/coder/assets/pr-30880-skill-chips/pr/transcript-chip.png"
width="600" /> |
Stack (merge top to bottom):
- #30826
- #30827
- #30838
- #30840
- #30854
- #30855
- #30856
- #30861
- #30880 👈
- #30881
- #30882
- #30884
- #31122
- #31126
---------
Co-authored-by: Cursor <[email protected]>
Comment on lines
+330
to
+332
|
|
Content: req.Content,
|
|
|
Action: nullBool(req.Action),
|
|
|
ModelInvocable: nullBool(req.ModelInvocable),
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intended that the server ignores disable-model-invocation in the SKILL.md frontmatter? Here, model_invocable comes only from the request field. Claude Code, Cursor and VS Code Copilot use disable-model-invocation: true in SKILL.md for the same setting (Claude Code, Cursor, VS Code). #30884 also reads this key on import and writes it on download, but only in the browser (skills.ts, ProjectSkillsDialog.tsx). The server parser reads only name and description (frontmatter.go). For example:
- Alice turns off automatic use on the project skill
deploy. Bob downloads it from the project dialog, and the file now has disable-model-invocation: true.
- Bob commits the file as
.claude/skills/deploy/SKILL.md in the repo, so that Claude Code users get it as a manual-only skill. Coder also discovers skills in .claude/skills (resolve.go).
- In a Coder Agents chat on that workspace, the workspace
deploy skill is in <available-skills>, because workspace skills always count as model-invocable (turn_environment.go, ARCHITECTURE.md). The agent can run deploy without being asked. Claude Code does not do this with the same file.
- Bob also uploads the same file as a personal skill with
POST /api/experimental/users/me/skills. The server stores it with model_invocable: true, so the agent can use it automatically. If he imports the file in the project dialog instead, the skill is manual-only.
So the same file is manual-only in Claude Code and in the project dialog, but automatic in a workspace and through the API.
Generated by an agent on behalf of the user
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, it wasn't intended. Two PRs on top of the stack fix the stored-skill half:
- feat: honor disable-model-invocation in uploaded skill content #31159 (server): when a create or update request leaves
model_invocable unset, disable-model-invocation: true in the SKILL.md frontmatter turns automatic use off. This applies to personal, organization, and project skills. An explicit model_invocable still wins, and new content without the key leaves the setting alone. The server also removes the key before storing the content, so the stored file can't disagree with the column; downloads add it back for manual-only skills. Your step 4 now gives a manual-only personal skill.
- feat: show automatic use for personal and organization skills #31160 (frontend): the personal and organization skill editors get the same Agents can use it automatically switch as project skills, the tables show a Manual only badge, and download and export mark manual-only skills too. An edit-mode import of a file with the key now turns the switch off instead of dropping the line.
Workspace skills (your step 3) still ignore the key: they come from a different parser in agent skill discovery and aren't stored rows, so I've left that as a follow-up. The docs in #31159 say so explicitly.
Generated by an agent on behalf of the user
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
|
|
TODO (project-skills): chats in a project now also get the project's enabled skills as a `project` skill source next to personal, organization, and workspace skills. They are read each turn as the chat owner, subagents use the root chat's project, and a failed read continues the turn without them. Describe this here.
|
|
|
|
|
|
TODO (project-skills): stored skills now have a `model_invocable` setting, true by default. Skills with it off are left out of `<available-skills>`, `read_skill` reports them as not found, and they do not count toward enabling the skill tools. Workspace skills are always model-invocable. Describe this here.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be deleted.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
jaaydenh reacted with thumbs up emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
coderagents
Bot
commented
Oct 22, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Documentation Check
Updates Needed
-
docs/ai-coder/agents/extending-agents.md (open) - This PR adds a settable model_invocable field to personal, organization, and project skills (default true) that controls whether agents discover and load the skill on their own, but the "How chats load stored skills" section does not mention it. A sentence such as "By default an agent can load any turned-on skill. When model_invocable is set to false for a skill, the agent does not load it on its own; the skill can still be invoked explicitly" would cover the behavior.
-
Chip, Commands-group, and project-skill doc additions in this section (reverted in cb8fd9c; those changes now ship in sibling PRs, so they are out of scope for this PR)
Automated review via Coder Agents
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
coderd/apidoc/.gen formats swagger.json with biome from site/node_modules, but only the downstream swagger.json rule depended on the site install. When make reached .gen through another target (offlinedocs), formatting was skipped and CI saw an unformatted swagger.json.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On disable-model-invocation, here is how I think the follow-ups should land:
- #31159 has the right shape for stored skills. The server reads the key on create and update, an explicit
model_invocable wins, and the server removes the key before it stores the file, so the file can't disagree with the column.
- #31147 (@ibetitsmike) also changes
createSkill for the same key, but it keeps the key in the stored content. On its own, a PATCH that sets model_invocable: true leaves disable-model-invocation: true in the file. A download then gives Claude Code a manual-only skill that Coder treats as automatic. Could #31147 drop its stored-skill change, rebase onto #31159, and keep only the workspace half (the skill index, read_skill, read_skill_file, and the skill directory on <invoked-skill>)? #31159 leaves that half as a follow-up, and it fixes step 3 from my earlier comment.
- Both PRs read the key with their own code (
workspacesdk.SkillDisablesModelInvocation and skills.RemoveDisableModelInvocation). Could we keep one, so stored skills and workspace skills can't drift apart?
- When the workspace half lands, the line in #31159's docs that says workspace skills ignore the key needs to go.
Generated by an agent on behalf of the user
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Reviewers
f0ssel
Awaiting requested review from f0ssel
Uh oh!
There was an error while loading. Please reload this page.
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|