# The skills layer

Tyler Youk · updated 2026-10-31 · https://tyleryouk.com/writing/skills-layer

A skill is a directory that holds one markdown file. The model reads the description in that file's
frontmatter to decide whether the skill applies. So the description is not documentation. It is the
routing key, and a skill with a vague description exists but never fires.

The fleet's process entry points live here. These are the skills that start a plan, continue one, or run a
feedback pass. If you deleted this layer, every agent would keep executing work, but there would be no way
left to start anything.

This page is about delivery: which machines get a skill, and how far it actually travels.

## The defining property is negative {#the-defining-property-is-negative}

A skill reaches exactly one machine.

The fleet ships a plugin to every box. The plugin carries hooks and scripts, is pinned to a commit, and is
gated on a version. One push really does reach every box, because every box pulls it. That is true of the
plugin and of nothing else. People who had read the plugin's documentation have more than once applied
the sentence *"one push, every machine gets it"* to skills.

The plugin does not carry skills, and it never has.

## Three delivery layers, three reaches {#three-delivery-layers-three-reaches}

```text
PLUGIN        one repository  →  EVERY box
              pinned to a commit, gated on a version
              carries: hooks, scripts

DOCTRINE      each box's own clone  →  EVERY box, live
              read through a symlink, so a rule change
              lands with no version bump
              🔴 but the SYMLINK is tracked in that box's own repo

SKILL         one box's own repository  →  exactly ONE box
              arrives at that box's next pull
```

People keep confusing two of these layers with each other. The middle one causes the most trouble,
because doctrine looks like it is delivered the way skills are.

Each machine reads doctrine through a symlink into its own clone, so a rule change reaches every box
without a release. But the symlink itself is a tracked file in that machine's own repository. On five
machines, someone repointed the links by hand and committed the change on none of them. After that, every
checkout restored nine symlinks into a directory that the rebuilt tree no longer had. The automatic pull
then skipped, because it refuses to run over uncommitted deletions. The result was five machines pinned
to a stale tree, with no warning.

A repoint is not delivered until someone commits it. A change made by hand on a live machine lasts until
the next checkout and no longer.

## What belongs in a skill, and what does not {#what-belongs-in-a-skill-and-what-does-not}

A skill belongs to the agent that owns the folder. A machine's agent directory belongs to that agent, and
a project's own skills, commands and rules never go there. That boundary stops one agent's behaviour from
leaking into another agent's because their files sit near each other.

The fleet holds its own skills to four conventions. Each one came from a past failure, not from a
preference.

* A skill that touches more than one file loads its context and shows a status table before it writes
  anything. The reader sees what is about to happen while it is still cheap to stop.
* A skill never asks an interactive question as its first step. A skill that opens with a question has not
  read anything yet, so it cannot ask an informed one.
* A skill with side effects opts out of automatic invocation. Matching on the description automatically is
  right for a skill that reads and wrong for one that writes.
* The set of verbs a skill name starts with is fixed. *audit* is read-only, *self-enhance* runs on its own,
  and *update* and *fix* are limited in scope. A skill whose name does not start with one of them claims a shape
  the fleet has no rules for.

### A door is thin; the process is a frame {#a-door-is-thin-the-process-is-a-frame}

The skills that start things work out *which* process you mean and then hand off to a frame document. The
process itself lives in the frame document, never in the entry-point skill.

This matters more than it sounds. If an entry point contains its process, a second entry point cannot
share it. As soon as two entry points need the same steps, someone copies the steps, and the two copies
diverge the way any two copies do.

### A fact a skill would assert becomes a command that reads it {#a-fact-a-skill-would-assert-becomes-a-command-that-reads-it}

In a skill file, an exclamation mark directly followed by a backticked command runs in a shell before the
content goes to the model, and the command's output replaces the placeholder. We verified this here both
with no tool allowlist and with automatic invocation turned off.

So a sentence that states a count, a path or a version goes out of date, and a command that reads the value
does not. The pages on this wiki follow the same discipline, state the probe, not the answer,
and this applies it one layer down, inside the instruction itself.

### The executing agents have no skills at all {#the-executing-agents-have-no-skills-at-all}

That is the current design, not a gap. An agent that executes a filed piece of work reads its
specification and its checklist. Anything it needs from a process is written into the issue body when the
issue is filed.

This is the opposite of the obvious approach. The machines that do the work carry the least process.
Process lives where work is *planned*, and it reaches the place where work is *done* as data in the issue,
not as installed behaviour. That means a process can change without deploying anything anywhere.

## Grade the population, never one machine {#grade-the-population-never-one-machine}

*"The fleet has skill X"* can only be true of each machine separately, and no single account can read most
of them. A verification here once read one machine and declared the whole layer sound.

Every fact about this layer lives outside the repository, so this page gives the commands that read each
fact instead of the answers:

| Question                                     | Command                                                                                |
| -------------------------------------------- | -------------------------------------------------------------------------------------- |
| What does *this* machine have                | `ls ~/.claude/skills/`                                                                 |
| What does a given machine's repository carry | `gh api repos/<org>/<repo>/contents/skills --jq '.[]\|select(.type=="dir").name'`      |
| What one skill actually does                 | `gh api repos/<org>/<repo>/contents/skills/<name>/SKILL.md --jq .content \| base64 -d` |
| Does the plugin carry skills (it does not)   | `gh api repos/<org>/<repo>/contents/plugins/<plugin> --jq '.[].name'`                  |
| Is a machine on the current plugin payload   | `bash _infra/scripts/plugin-deploy-check.sh`                                           |

That table has one trap, and it costs an hour the first time. `gh api` writes its 404 body to standard
output, so a bare fallback prints the error JSON *and* the fallback text on one line. Filter for the shape
of output you expect, not for whether the output is empty.

## Where this layer is currently weakest {#where-this-layer-is-currently-weakest}

* Only two of seven agent repositories have a skills directory. The rest return 404. So the layer really
  reaches two machines, and nobody else can reach the larger set, which holds most of the skills that exist
  here. Any plan that says "ship a skill to the fleet" describes a mechanism that does not exist.
* The two sets have diverged, and nothing measures the gap. One has twenty-four named skills and the other
  has fifty-one. There is no shared manifest, no linter and no index. No command answers *"which skills
  exist in the fleet"*. The table above needs one read per machine because that single command has never
  existed.
* A backup file sits inside the skills directory, the same directory the loader walks. It is not a skill
  and nothing removes it, which breaks this fleet's own standing rule that git history is the archive.
* Three of this component's own in-repository pointers point at files that nothing calls. The assertion
  checker reports them as present on disk and called by nobody. That is what an entry point looks like when
  someone replaced it but did not delete it.
