<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Diaz</title>
    <description>The latest articles on DEV Community by Daniel Diaz (@daniel_diaz).</description>
    <link>https://dev.to/daniel_diaz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2017360%2F8acddb2e-c499-46a0-8e95-80af9ff9f505.png</url>
      <title>DEV Community: Daniel Diaz</title>
      <link>https://dev.to/daniel_diaz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/daniel_diaz"/>
    <language>en</language>
    <item>
      <title>Your agent follows instructions. Until it doesn't.</title>
      <dc:creator>Daniel Diaz</dc:creator>
      <pubDate>Tue, 19 May 2026 19:08:52 +0000</pubDate>
      <link>https://dev.to/cloudx/your-agent-follows-instructions-until-it-doesnt-11m1</link>
      <guid>https://dev.to/cloudx/your-agent-follows-instructions-until-it-doesnt-11m1</guid>
      <description>&lt;h2&gt;
  
  
  Hooks over flowers
&lt;/h2&gt;

&lt;p&gt;Instructions suggest. Skills guide. Hooks &lt;strong&gt;enforce&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's the whole story, but it took me a while to understand why it matters.&lt;/p&gt;

&lt;p&gt;You've set up your agent well. Custom instructions for coding standards. Skills for your team's specific patterns. Copilot knows your stack, follows your conventions, generates code that looks like yours.&lt;/p&gt;

&lt;p&gt;Then one day it decides to run &lt;code&gt;rm -rf dist/&lt;/code&gt; before rebuilding. Or it edits a file and moves on without running the formatter. Or it completes a task without touching the test suite. All technically valid moves. All not what you wanted.&lt;/p&gt;

&lt;p&gt;The problem isn't instructions or skills failing. It's that they &lt;em&gt;guide&lt;/em&gt; the agent. They inform its decisions. But an agent that's informed can still decide differently. Instructions are context. They're not guarantees.&lt;/p&gt;

&lt;p&gt;Hooks are guarantees.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Agent Hooks?
&lt;/h2&gt;

&lt;p&gt;Agent Hooks are shell commands that VS Code runs at specific lifecycle points during an agent session. Not suggested. Not requested. Run.&lt;/p&gt;

&lt;p&gt;They live in your repo at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.github/
└── hooks/
    └── hooks.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The filename can be anything. VS Code loads all &lt;code&gt;*.json&lt;/code&gt; files inside &lt;code&gt;.github/hooks/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A hook that auto-formats every file the agent edits looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx prettier --write &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;$TOOL_INPUT_FILE_PATH&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file. VS Code picks it up automatically. The next time the agent edits any file, Prettier runs. No prompt needed, no skill invocation, no agent cooperation required.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;VS Code added agent-scoped hooks in &lt;a href="https://code.visualstudio.com/updates/v1_111" rel="noopener noreferrer"&gt;version 1.111&lt;/a&gt; (March 2026). Workspace hooks via &lt;code&gt;.github/hooks/&lt;/code&gt; were available earlier. Use &lt;code&gt;/create-hook&lt;/code&gt; in chat to scaffold a hook configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Meet the eight
&lt;/h2&gt;

&lt;p&gt;This is where hooks get interesting. VS Code exposes eight points in an agent session where your code can run:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;When it fires&lt;/th&gt;
&lt;th&gt;What you can do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SessionStart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User submits the first prompt&lt;/td&gt;
&lt;td&gt;Inject context, validate project state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UserPromptSubmit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User submits any prompt&lt;/td&gt;
&lt;td&gt;Audit requests, add system context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PreToolUse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Before the agent invokes any tool&lt;/td&gt;
&lt;td&gt;Block dangerous operations, require approval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PostToolUse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;After a tool completes&lt;/td&gt;
&lt;td&gt;Run formatters, trigger follow-up actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PreCompact&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Before conversation context is compacted&lt;/td&gt;
&lt;td&gt;Export state before it gets truncated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SubagentStart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A subagent is spawned&lt;/td&gt;
&lt;td&gt;Initialize subagent resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SubagentStop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A subagent completes&lt;/td&gt;
&lt;td&gt;Aggregate results, clean up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Agent session ends&lt;/td&gt;
&lt;td&gt;Run tests, generate reports, send notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most people, when they first hear about hooks, think &lt;code&gt;PostToolUse&lt;/code&gt;: run a formatter. That's valid and immediately useful.&lt;/p&gt;

&lt;p&gt;But look at &lt;code&gt;PreToolUse&lt;/code&gt;. That's where you can &lt;em&gt;stop&lt;/em&gt; the agent before it does something.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;SessionStart&lt;/code&gt;. That's where you can inject context that the agent doesn't have yet: current branch, environment, version, whether production deploys are frozen.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PreCompact&lt;/code&gt; is the one nobody talks about. When a long session gets too big for the context window, VS Code compacts it. You can hook into that moment to export state, save important context to a file, or log what's about to be truncated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop. Before anything happens
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;PreToolUse&lt;/code&gt; fires before every tool invocation. Your hook receives the tool name and its input via stdin as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hookEventName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PreToolUse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run_in_terminal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool_input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rm -rf dist/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your hook can return one of three &lt;code&gt;permissionDecision&lt;/code&gt; values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"allow"&lt;/code&gt;: proceed without asking the user&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"deny"&lt;/code&gt;: block the operation entirely&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"ask"&lt;/code&gt;: stop and require explicit user confirmation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple shell script that blocks destructive commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.tool_input.command // ""'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'(rm -rf|DROP TABLE|git push --force)'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Destructive command blocked by policy"}}'&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wire it up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PreToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./scripts/validate-command.sh"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent never sees the operation. It doesn't try to negotiate. The hook returns &lt;code&gt;deny&lt;/code&gt;, the tool call stops.&lt;/p&gt;

&lt;p&gt;There's also a simpler way to block without writing any JSON at all. Every script, when it finishes, returns a number to whoever called it. That's an exit code. &lt;code&gt;0&lt;/code&gt; means success. VS Code specifically watches for exit code &lt;code&gt;2&lt;/code&gt; as a "stop this right now" signal. You just write your reason to stderr and exit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Production deploys are frozen"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
&lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VS Code passes that message to the model as context and blocks the tool call. No JSON, no &lt;code&gt;hookSpecificOutput&lt;/code&gt;, no ceremony.&lt;/p&gt;

&lt;p&gt;One more thing worth knowing: &lt;code&gt;continue: false&lt;/code&gt; in the JSON output stops the entire agent session, not just one tool call. Think of exit code &lt;code&gt;2&lt;/code&gt; as hitting the brakes on a single operation. &lt;code&gt;continue: false&lt;/code&gt; is turning off the engine. Use the second one carefully.&lt;/p&gt;

&lt;p&gt;If you define more than one hook for the same event, VS Code runs all of them. When multiple &lt;code&gt;PreToolUse&lt;/code&gt; hooks return conflicting &lt;code&gt;permissionDecision&lt;/code&gt; values, the most restrictive wins: &lt;code&gt;deny&lt;/code&gt; beats &lt;code&gt;ask&lt;/code&gt;, and &lt;code&gt;ask&lt;/code&gt; beats &lt;code&gt;allow&lt;/code&gt;. You can stack a validation hook and a logging hook on the same event without worrying about one canceling the other.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full protocol reference: &lt;a href="https://code.visualstudio.com/docs/copilot/customization/hooks#_hook-input-and-output" rel="noopener noreferrer"&gt;Hook input and output, VS Code docs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The morning briefing
&lt;/h2&gt;

&lt;p&gt;Instructions are static. They were written at the time you created the file. But some context only exists at runtime: the current git branch, which environment is active, whether the CI pipeline is currently broken.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SessionStart&lt;/code&gt; fires before the agent does anything. Your hook can inject that information directly into the session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git branch &lt;span class="nt"&gt;--show-current&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;node_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;env_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;development&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

jq &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--arg&lt;/span&gt; branch &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$branch&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--arg&lt;/span&gt; node &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$node_version&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--arg&lt;/span&gt; &lt;span class="nb"&gt;env&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$env_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{
    hookSpecificOutput: {
      hookEventName: "SessionStart",
      additionalContext: ("Branch: " + $branch + " | Node: " + $node + " | Env: " + $env)
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every session the agent starts, it already knows what branch it's on and what environment it's working in. No need to tell it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not every hook is for everyone
&lt;/h2&gt;

&lt;p&gt;Workspace hooks apply to every agent interaction. But sometimes you want a hook that only runs for a specific agent.&lt;/p&gt;

&lt;p&gt;Since VS Code 1.111, you can define hooks directly in a custom agent's frontmatter. The &lt;code&gt;hooks&lt;/code&gt; field here uses YAML syntax because it lives inside the &lt;code&gt;.agent.md&lt;/code&gt; frontmatter, but the structure maps directly to what you'd write in a JSON config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PM&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Explainer"&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explains&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;PM&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;why&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;it's&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;taking&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;longer.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Also&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;formats&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;code."&lt;/span&gt;
&lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;PostToolUse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;command&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./scripts/format-and-lint.sh"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

You are a code editing agent. After making changes, files are formatted and linted automatically.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable &lt;code&gt;chat.useCustomAgentHooks&lt;/code&gt; to use this. The hook only runs when this specific agent is active, either selected by the user or invoked as a subagent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part everyone skips (don't)
&lt;/h2&gt;

&lt;p&gt;Hooks run shell commands with the same permissions as VS Code. That's the &lt;em&gt;power&lt;/em&gt; and the &lt;em&gt;responsibility&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Before enabling hooks from any source, read the scripts&lt;/em&gt;&lt;/strong&gt;. Hooks receive JSON input from the agent. Validate and sanitize that input before using it. Never hardcode secrets in hook scripts; use environment variables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;One specific risk&lt;/em&gt;&lt;/strong&gt;: if the agent has access to edit scripts that your hooks run, it can modify those scripts during a session and execute code it writes. Use &lt;a href="https://code.visualstudio.com/docs/copilot/customization/hooks#_safety" rel="noopener noreferrer"&gt;&lt;code&gt;chat.tools.edits.autoApprove&lt;/code&gt;&lt;/a&gt; to prevent the agent from editing hook scripts without manual approval.&lt;/p&gt;

&lt;h2&gt;
  
  
  When your hook does nothing
&lt;/h2&gt;

&lt;p&gt;If a hook runs but nothing seems to happen, check the &lt;strong&gt;GitHub Copilot Chat Hooks&lt;/strong&gt; output channel. Open the Output panel in VS Code, select that channel from the list, and you'll see which hooks were loaded, which fired, their exit codes, and any stdout or stderr output.&lt;/p&gt;

&lt;p&gt;Hook scripts that exit with code &lt;code&gt;1&lt;/code&gt; produce a non-blocking warning: the agent continues, but the issue shows up in the channel. Exit code &lt;code&gt;2&lt;/code&gt; is the one that blocks and surfaces the message to the model. If your hook is supposed to stop something and it isn't, check which exit code your script is returning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Already have Claude hooks? You're closer than you think
&lt;/h2&gt;

&lt;p&gt;If you're coming from Claude Code, VS Code reads hook configurations from &lt;code&gt;.claude/settings.json&lt;/code&gt; and &lt;code&gt;.claude/settings.local.json&lt;/code&gt; by default. The format is the same, with two differences to watch for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool input property names&lt;/strong&gt;: Claude Code uses &lt;code&gt;snake_case&lt;/code&gt; (e.g. &lt;code&gt;tool_input.file_path&lt;/code&gt;), VS Code uses &lt;code&gt;camelCase&lt;/code&gt; (e.g. &lt;code&gt;tool_input.filePath&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool names&lt;/strong&gt;: different. Claude uses &lt;code&gt;Write&lt;/code&gt;/&lt;code&gt;Edit&lt;/code&gt;, VS Code uses &lt;code&gt;create_file&lt;/code&gt;/&lt;code&gt;replace_string_in_file&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where Hooks Fit
&lt;/h2&gt;

&lt;p&gt;Hooks are the third piece of a larger customization system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instructions&lt;/strong&gt; (&lt;code&gt;copilot-instructions.md&lt;/code&gt; / &lt;code&gt;.github/instructions/&lt;/code&gt;): always-on context. Good for project-wide rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; (&lt;code&gt;.github/skills/&lt;/code&gt;): domain-specific, activated on demand. Good for encoding your conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt; &lt;em&gt;← you're here&lt;/em&gt;: &lt;strong&gt;&lt;em&gt;deterministic&lt;/em&gt;&lt;/strong&gt; automation at lifecycle points. Good for guarantees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Servers&lt;/strong&gt;: external tools: database access, browser automation, external APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugins&lt;/strong&gt;: installable bundles that package all of the above together.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7vmm4dvc6s848eic0vu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7vmm4dvc6s848eic0vu.png" alt="VS Code Agent Customization Stack" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instructions tell the agent &lt;strong&gt;&lt;em&gt;how&lt;/em&gt;&lt;/strong&gt; to work. Skills tell the agent &lt;strong&gt;&lt;em&gt;what patterns to follow&lt;/em&gt;&lt;/strong&gt;. Hooks make sure certain things happen regardless of what the agent decides.&lt;/p&gt;

&lt;p&gt;They're not interchangeable. They're complementary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The difference between guidance and guarantee matters.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instructions and skills are &lt;strong&gt;&lt;em&gt;probabilistic&lt;/em&gt;&lt;/strong&gt;. They shift the agent's behavior in the right direction. Hooks are &lt;strong&gt;&lt;em&gt;deterministic&lt;/em&gt;&lt;/strong&gt;. Your code runs, period. Both have their place. Knowing which to reach for is the skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with one hook.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One &lt;code&gt;PostToolUse&lt;/code&gt; Prettier hook that auto-formats on every file edit. Ship it, live with it for a week, see what else you want to automate. The scope expands naturally.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is the second post in a series on VS Code agent customizations: Skills, Hooks, MCP Servers, CLI, and Plugins.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Previous post: &lt;a href="https://dev.to/cloudx/stop-getting-generic-output-from-copilot-teach-it-your-patterns-1358"&gt;I stopped fighting Copilot's conventions. I taught it mine instead.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Official docs: &lt;a href="https://code.visualstudio.com/docs/copilot/customization/hooks" rel="noopener noreferrer"&gt;Agent Hooks (VS Code)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>githubcopilot</category>
      <category>agentskills</category>
      <category>ai</category>
    </item>
    <item>
      <title>Stop getting generic output from Copilot. Teach it your patterns.</title>
      <dc:creator>Daniel Diaz</dc:creator>
      <pubDate>Thu, 23 Apr 2026 13:11:44 +0000</pubDate>
      <link>https://dev.to/cloudx/stop-getting-generic-output-from-copilot-teach-it-your-patterns-1358</link>
      <guid>https://dev.to/cloudx/stop-getting-generic-output-from-copilot-teach-it-your-patterns-1358</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You use Copilot. You ask it to build something, and it does sort of. It follows your prompt, generates working code, and you ship it.&lt;/p&gt;

&lt;p&gt;Then you do it again the next day. And the day after.&lt;/p&gt;

&lt;p&gt;A month later, your codebase has class names in PascalCase next to camelCase functions, three different error handling styles, two ways to structure the same kind of module, and hooks that work differently from each other for no clear reason.&lt;/p&gt;

&lt;p&gt;All of it generated by Copilot. All of it reviewed and accepted by you.&lt;/p&gt;

&lt;p&gt;The problem isn't that Copilot generates bad code. It generates &lt;em&gt;generic&lt;/em&gt; code. It doesn't know your stack, your team's decisions, or the patterns you settled on six months ago. It works from its training data. And your codebase slowly starts to look like it was written by the internet.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are Agent Skills?
&lt;/h2&gt;

&lt;p&gt;Agent Skills are Markdown files that tell Copilot what &lt;em&gt;your&lt;/em&gt; conventions are, for a specific domain, task, or workflow. Persistent context the agent reads before generating anything in that area.&lt;/p&gt;

&lt;p&gt;They live in your repo at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.github/
└── skills/
    └── your-skill-name/
        └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire setup. No config files, no registration, no CLI step. The file being there is enough for VS Code to discover it.&lt;/p&gt;

&lt;p&gt;When you mention the skill in a chat prompt like &lt;code&gt;"Use the component-structure skill to create a new button"&lt;/code&gt;, Copilot reads that SKILL.md first, then generates code that follows your conventions.&lt;/p&gt;

&lt;p&gt;This is what separates skills from regular prompts: &lt;strong&gt;they're reusable, versioned, and shared through the repo.&lt;/strong&gt; Your conventions stop living in someone's head or a doc nobody reads; they live next to the code they govern.&lt;/p&gt;

&lt;p&gt;With a well-written &lt;code&gt;description&lt;/code&gt;, Copilot can automatically load the relevant skill based on your request without explicit mention. Explicitly referencing skills is more common with smaller models that need extra guidance to identify the right context.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;VS Code added native skill support and the &lt;code&gt;/create-skill&lt;/code&gt; command in &lt;a href="https://code.visualstudio.com/updates/v1_110" rel="noopener noreferrer"&gt;version 1.110&lt;/a&gt;. In &lt;a href="https://code.visualstudio.com/updates/v1_113" rel="noopener noreferrer"&gt;version 1.113&lt;/a&gt;, a dedicated Chat Customizations editor was added, providing a centralized UI to manage skills, instructions, and agents from a single place.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A minimal SKILL.md
&lt;/h2&gt;

&lt;p&gt;Here's the minimum a skill needs to actually work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.github/skills/component-structure/SKILL.md&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;component-structure&lt;/span&gt;
&lt;span class="na"&gt;description: Guidelines for creating React components following team conventions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;named exports, props interface, no inline JSX logic.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Component Structure Skill&lt;/span&gt;

&lt;span class="gu"&gt;## When to use&lt;/span&gt;
Creating new React components or reviewing component patterns.

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; One component per file
&lt;span class="p"&gt;-&lt;/span&gt; Props interface defined above the component
&lt;span class="p"&gt;-&lt;/span&gt; Named exports only (no default exports)
&lt;span class="p"&gt;-&lt;/span&gt; No inline logic in JSX, extract to handlers or custom hooks
&lt;span class="p"&gt;-&lt;/span&gt; Error boundaries at page level, not inside components

&lt;span class="gu"&gt;## Never do this&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Default exports
&lt;span class="p"&gt;-&lt;/span&gt; Logic directly in JSX
&lt;span class="p"&gt;-&lt;/span&gt; Props without an explicit interface
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pattern example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; field must match the directory name exactly. The &lt;code&gt;description&lt;/code&gt; is what Copilot reads to decide whether to load the skill, so be specific. Full frontmatter reference: &lt;a href="https://code.visualstudio.com/docs/copilot/customization/agent-skills#_skillmd-file-format" rel="noopener noreferrer"&gt;SKILL.md file format&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Four sections. One pattern. A few explicit don'ts.&lt;/p&gt;

&lt;p&gt;When Copilot reads this before generating a component, it follows the same structure every time not because it guessed right, but because you told it.&lt;/p&gt;

&lt;p&gt;The skill doesn't need to be exhaustive. &lt;strong&gt;It needs to be specific.&lt;/strong&gt; A skill that covers one thing well beats one that tries to cover everything and ends up covering nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a skill from a conversation
&lt;/h2&gt;

&lt;p&gt;One of the more useful additions in VS Code 1.110 is &lt;code&gt;/create-skill&lt;/code&gt;. After debugging a problem across several chat turns and landing on the right approach, you type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/create-skill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent extracts the pattern from your conversation and scaffolds a SKILL.md for you. You review, adjust, commit.&lt;/p&gt;

&lt;p&gt;This is how skills actually get created in practice. &lt;strong&gt;You don't design a skill from scratch.&lt;/strong&gt; You solve a problem, recognize you'll solve it the same way every time, and capture that. &lt;code&gt;/create-skill&lt;/code&gt; removes the friction of doing the capture manually.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Ecosystem
&lt;/h2&gt;

&lt;p&gt;Skills are one piece of a larger customization system. Here's a quick map:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2pg9dlm1xy0vre71373.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2pg9dlm1xy0vre71373.png" alt="How a general agent loads skills to become specialized" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instructions&lt;/strong&gt; (&lt;code&gt;copilot-instructions.md&lt;/code&gt; / &lt;code&gt;.github/instructions/&lt;/code&gt;): always-on context loaded in every session. Good for project-wide rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; ← you're here: domain-specific, activated on demand when mentioned in chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt;: scripts that run at specific points in the agent lifecycle: before a response, after a file write, on session start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Servers&lt;/strong&gt;: external tools that give the agent capabilities your codebase doesn't have natively, like database access, browser automation, or external APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugins&lt;/strong&gt;: installable bundles that package all of the above together.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these has its own post coming. Skills are the easiest starting point entirely local to your repo, zero infrastructure, and the effect on the agent is immediate.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The model doesn't know your stack. You have to teach it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copilot is trained on public code. Your team's specific decisions aren't in that data. Skills are the mechanism for closing that gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One good skill beats ten prompts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A well-written skill invoked consistently produces better results than re-explaining your conventions in each prompt. The repeatability is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The skill itself is documentation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing a SKILL.md forces you to articulate things that previously existed informally. Once it's committed, the team has a shared reference, not just for Copilot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The real value shows up at review time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When everyone uses the same skill, code review stops being about style. You argue about logic instead. That's the conversation worth having.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is the first post in a series on VS Code agent customizations: Skills, MCP Servers, CLI, Hooks, and Plugins.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Official docs: &lt;a href="https://code.visualstudio.com/docs/copilot/customization/agent-skills" rel="noopener noreferrer"&gt;Agent Skills VS Code&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>githubcopilot</category>
      <category>agentskills</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
