# Specialists and skills An agent launched at a repository needs two different things: what it should know, and what it should do. Specialists answer the first, skills the second. The point of both is that a session gets the small relevant set instead of everything the project has ever touched. This is the fourth layer of the model in [the context budget](context-budget.md), and it's priced the same way: what loads on every launch costs on every launch. ## Specialist or skill A **specialist** is expertise. It says what to care about, what to avoid, what to look at, and when to hand over to somebody else. `database.postgresql` knows that a big estimate-versus-actual gap in a plan usually means stale statistics. A **skill** is a procedure — a numbered list you can follow and know when you've finished. `skill.query-optimisation` is ten steps ending in "confirm the result set is unchanged". The difference matters when you write one. A skill that reads like a description of a subject is a specialist in the wrong folder. ## Layers Guidance composes general to specific, so where two sources disagree, the narrower one is read last. | Layer | What it is | Example | |---|---|---| | Foundation | Always on, deliberately small | `foundation.change-safety` | | Mode | Posture for this piece of work | `mode.investigate` | | Language | What the code is written in | `language.csharp` | | Framework | What it is built on | `framework.ef-core` | | Database | Which engine | `database.postgresql` | | Platform | Where it runs | `platform.docker` | | Cloud | Whose cloud | `cloud.azure` | | Function | A cross-cutting specialty | `function.performance` | | Style | How you write code | `style.personal` | | Skill | A procedure to follow | `skill.query-optimisation` | | Project | The project's own instructions | `projects//context/` | Composition is by dependency, not inheritance. `framework.aspnet-core` requires `framework.dotnet`, which requires `language.csharp`; nothing subclasses anything, and the chain is three deep at most. ## Modes Five postures. They change what to do, not what to know. | Mode | Posture | |---|---| | `advise` | Answer the question. Don't change the repository. | | `investigate` | Find out what's happening. The fix is a separate step. | | `implement` | Make the change and verify it. The default. | | `review` | Judge the change as written. Report, don't rewrite. | | `coordinate` | Have the work done; do none of it. Judge what comes back by its evidence. For the lead of a team run. | Modes combine with specialists rather than duplicating them. `performance` with `investigate` means measure and isolate before editing. `performance` with `implement` means apply an optimisation somebody has already justified. ### A mode lasts the whole session A mode is a directive for the session, not for a message. You set it at launch with `--mode`, and it holds until something changes it. It's never guessed from what you typed, so a session started in `implement` stays there even if your next message is a question. That's deliberate: a posture that flipped on the wording of one message wouldn't be a posture. ### Changing it part way through Work changes shape. You ask an agent to look into a bug, it finds the cause, and now you want the fix — that's `investigate` becoming `implement`. The agent can make that switch itself: ```text loadout_mode(mode: "implement", task: "add the retry to the upload step") ``` or, without the launcher's own tools: ```bash loadout instructions explain --mode implement --project starstats "add the retry" ``` Either gives back the posture to adopt and what now applies. `skill.mode-switch` tells the agent when this is worth doing and when it isn't — one question inside a piece of implementation work is not a mode change. An unrecognised mode is refused rather than quietly treated as the default, because an agent told nothing would carry on believing it had switched. ### What a mode change doesn't touch Only two things move: the posture, and which skills are on offer. A reviewing skill is available in `investigate`, `advise` and `review` and withheld from `implement`. Everything else keeps working. Language, framework, database and platform specialists come from what's actually in the repository, so they apply whatever the mode is. Specialists triggered by task phrases keep triggering on the words in the new task. Nothing already in the context is taken away. ## How a specialist gets loaded Four ways, in descending order of authority. **You asked for it.** `--specialist function.security` loads it whatever the evidence says, and it's never dropped for budget. Asking for something and silently not getting it is the worst outcome going, so naming a specialist that doesn't exist stops the command instead of carrying on without it. **The task says so.** The strongest automatic signal, because it's the only one that reflects what you're actually doing. Phrases match on whole words: `api` doesn't match "capital". **A dependency declares it.** `Npgsql` in a project file is a deliberate choice, and worth more than a file extension. **The repository looks like it.** The weakest signal, and deliberately fenced in. Files and dependencies activate **languages and frameworks only** — the layers that describe what the code *is*. Databases, platforms, clouds and functional specialists describe what you're *doing*, and a repository holds all of those whatever today's task is. This is the rule that stops somebody fixing a null reference from being handed PostgreSQL, Kubernetes and Azure. A language also has to clear a threshold of three files. One stray `.sql` file doesn't make a project a database project. ## Project preferences A project or profile can say which specialists it expects to be relevant: ```yaml # projects//project.yaml specialists: preferred: - language.csharp - framework.dotnet - database.postgresql excluded: - cloud.aws mode: implement ``` **Preferred doesn't mean always loaded.** For a language or framework, a preference plus supporting evidence is enough. For anything else a preference raises the specialist's standing — so it isn't first out when the budget gets tight — but the task still has to point at it. A project that lists four technologies uses all four. That's no reason to put all four in front of every session. **Excluded is honoured.** It beats every kind of inference, including a requirement from another specialist. The only thing that overrides it is naming the specialist yourself on the command line. A profile's preferences replace the project's rather than adding to them, so a profile can narrow. ## Coding styles A style is how somebody writes code, as opposed to what they know about a language: early returns or a single exit, a result type or exceptions, what a repository class looks like. It lives in the same library as every other specialist, under the `style` kind, so it is loaded, budgeted and explained the same way. A style has up to four parts, and each costs something only when it is relevant: | Part | Id | Loads | |---|---|---| | Core | `style.work` | On every launch the style is in force | | Voice | `style.work.voice` | With the core. Rendered from a learned voice, never written by hand | | Language file | `style.work.csharp` | Only when the language it accompanies does | | Pattern | `style.work.pattern.repository` | Only when the task mentions it | A language file says what it follows with `accompanies`, and goes when that language goes, whether it was excluded or dropped for budget. A pattern is a rule plus example code, found by its `task_phrases`, so the examples cost nothing on a task that has nothing to do with them. ### Which styles are in force Three layers, read in this order, so the later one wins where two disagree: 1. **Personal** — `style.personal`, in force everywhere. 2. **Named** — one style chosen for a kind of work, such as `work` for the day job and `loose` for throwaway projects. 3. **Codebase** — `style.codebase` under one project's specialists, for that codebase's own conventions. The order is by layer, not by where a file came from. A named style you chose overrides your personal defaults, in the same way a project overrides the workspace, even when both sit in the workspace. A style that isn't in force never loads from evidence: another style's repository pattern doesn't turn up because a task said "repository". Naming one of its parts with `--specialist` still works. Choose the named style for a project, or for one of its profiles: ```bash loadout style use work loadout style use loose --profile spike loadout style use none ``` This writes `style:` under `specialists:` in the project manifest. Unlike the rest of a profile's preferences, a profile that doesn't name a style keeps the project's: a profile narrows what a session knows about, not whose code it's writing. If you write the same way across most of your work, set a default instead of choosing it project by project: ```bash loadout config set default-style work ``` The default is the named style wherever a project or profile hasn't chosen one, and outside a project. A project's own choice still wins. One limit: `style use none` clears the project's choice, so that project falls back to the default rather than to no named style at all. ### Writing one ```bash loadout instructions new style.personal loadout instructions new style.personal.csharp loadout instructions new style.work.pattern.repository loadout instructions new style.codebase --project starstats ``` Each part lands in `style//` and is valid as drafted: a language file already accompanies `language.`, and a pattern already has a task phrase, an example block and a "When not to use this" section to fill in. A codebase style drafted with `--project` starts from what the repository can be seen to do. `loadout style list` shows every style, which are in force here, and what each core costs. `loadout style show ` prints the core and says when each language file and pattern loads. ### A learned voice `loadout voice learn` builds a voice from your own writing, rule by rule, and renders the rules you accepted as the style's voice part: `style.personal.voice`, `style..voice` or `style.codebase.voice`. It loads wherever its style is in force, so a named style's voice goes where the style does. The profile is the source and the rendered file is made from it. Each rendered file carries a hash of what was rendered, and a file changed by hand is left alone on the next render rather than overwritten, with a message saying so. Put the change in the profile, or replace the file with `loadout voice render --force`. Only the rules are rendered. The writing they were learned from stays in the profile, because the rendered file travels with the workspace. The voice tells a session to check a commit message, pull request description or changed page with `loadout voice check`, fix what it finds once, and then carry on. Anything still reported goes in the session's reply, never in the commit or the pull request, because a rule learned last week shouldn't hold up today's work. `loadout docs audit` runs the same check over the documentation and lists what it finds as warnings. A learned rule never fails the audit. Every voice is learned against a guide: a fixed definition of where evidence comes from, which checks a rule may carry, and every threshold a run is judged by. `prose/1` ships. `loadout voice guide draft --about "..."` asks an agent to draft another, shows it to you, and saves it only if you say so. A saved version is never changed, so a profile learned against it keeps its meaning, and drafting the same id again proposes the next version. A draft can only use the checks Loadout can run. It may name sources Loadout can't read yet, such as code, and `voice guide list` says which, because a guide that needs them can't be learned from until they exist. `prose/1` learns from your squash merges and anything you mark with `loadout voice mark`, on the grounds that a squash message is usually written by hand when a pull request is merged. Usually is not always: if an agent writes your commits, learning from them would learn its voice and call it yours. So a squash merge whose message names an assistant as a co-author, or carries the "Generated with Claude Code" footer, is left out, and so is its pull request when edit pairs are read. Anything you've marked is kept whatever its trailer says. A squash merge with no trailer is still read, and when that's all a run found it says so before asking for a cap, so you can decline and spend nothing, then mark what you did write instead. A drafted guide is learned with `loadout voice learn --guide `, and reads only the sources it lists. Its rules go into the same voice part as the prose rules, and `voice check` and the docs audit check against every guide's rules unless `--guide` names one. One source is for word choice only. `--transcripts` reads what you typed to Claude Code, for your personal voice, and only a guide that lists `transcript` can use it. Prompts to an agent are short and often unpunctuated, so they show which words you reach for and how you spell them, not how you build a sentence. A guide that reads them may carry only the `avoid-phrase` and `prefer-spelling` checks. Only prompts Claude records as typed by a person are read, never one sent by Loadout or another program, and pasted text and code are taken out. So are screenshots: the image is never read, and the `[Image #1]` placeholder or file path left beside it is removed. A short error pasted in is often not marked as pasted, so it's known by how its lines look instead: a shell prompt, an `error:` or `warning:` line, a stack trace, a compiler error. Those lines go and the rest of the prompt stays. A line of yours that happens to look like terminal output goes too, which costs a line rather than teaching a tool's output as your voice. Two more things are left out on purpose: - A session's opening prompt. Loadout starts some sessions with one, and the transcript records it exactly as if you had typed it. - Prompts typed in the Claude desktop app, which are recorded the same way as prompts a program sends. Other text pasted without Claude marking it as pasted, and not shaped like terminal output, is still read as yours. Validation warns about a style that works but costs more than it should: - a core or voice over about 1,000 tokens, since both load on every launch and are never dropped for budget - a language file that accompanies nothing, so nothing will load it - a pattern with no example code, which is a rule and belongs in the core or a language file - a codebase style outside a project, which would apply to every project The launcher ships no styles. Shipping one would hand everybody somebody else's habits. ## Seeing what an agent will be told ```bash loadout instructions explain "Why is this EF Core PostgreSQL query taking 12 seconds?" \ --mode investigate ``` ```text Effective agent instructions foundation + Change safety always applies + Engineering core always applies + Evidence first always applies + Forward motion always applies + Verification always applies mode + Investigate investigate mode language + C# required by framework.dotnet framework + .NET required by framework.ef-core + Entity Framework Core task mentions "ef core" database + PostgreSQL task mentions "postgresql" function + Database task mentions "query" + Performance task mentions "taking" skill + Database query optimisation task mentions "query taking" Context Estimated instruction tokens: 2,853 Budget: 12,000 Usage: 24% ``` Every line carries the reason it's there, and `--json` gives you the same thing as a document. The explanation runs through the same service the launch path uses, so it describes what would actually get composed. ## Reading one `explain` says which specialists a task would load. To read what one of them actually says: ```bash loadout instructions show language.rust ``` ```text Rust language.rust built-in, about 214 tokens Loads when task mentions: rust, cargo, borrow checker files match: **/*.rs, **/Cargo.toml ## Cares about Lifetimes and ownership, and what the code does when something fails. ... ``` The whole text, what triggers it, and what it costs. Worth reading before you write your own version of one. The shipped specialists are deliberately short, and a project specialist with the same id replaces the one it shadows rather than adding to it. To see what there is at all: ```bash loadout instructions list # everything available to this project loadout instructions list --kind language ``` The library ships 104 specialists — 5 foundations, 5 modes, 10 languages, 8 frameworks, 4 databases, 5 platforms, 3 clouds, 22 functions, 17 skills and 25 roles. They are embedded in the binary rather than kept on disk, so the command is the way to read them; there is no directory to browse. A role is one agent's job in a team run: what it may do, what it hands back and how it is judged. Roles never load from evidence. They have no globs, no dependencies and no task phrases, so the only way one reaches a session is by name, which is how a team run gives a node its role. Every role composes on top of `role.member`, which carries the contract a node reports against. ## The context budget More guidance is not better. The ceiling is in estimated tokens: ```bash loadout config set instruction-max-tokens 12000 loadout config set instruction-warn-percent 80 ``` Bytes are the exact measure and tokens are an estimate — no tokeniser here matches the providers' — so both are reported and the token figure is always labelled as approximate. When the candidates exceed the budget, whole specialists are dropped, weakest evidence first. Nothing is ever cut in half: half a specialist reads as complete guidance while missing the caveat that made it safe. Foundation, the mode and anything you named explicitly are never dropped, and everything omitted is reported with both the reason it was reached and the reason it went. ## Turning it off ```bash loadout config set specialists false ``` Launches then compile exactly the context they did before this existed. Offered because this changes what every existing session is told, and somebody who has tuned their own instructions for a year is entitled to decline. ## Where specialists live Three layers, later overriding earlier by id: 1. **Built in.** Shipped inside the launcher. Not on disk, so they cannot be edited in place, go missing from an install, or be made to point elsewhere. 2. **Workspace** — `global/specialists/` in the central workspace, shared across every machine that clones it. 3. **Project** — `projects//specialists/`, for one project only. To disagree with a built-in specialist, write one with the same id in your workspace. There is no need to change the launcher, and no registry to keep in step. ## Writing one Start with a draft rather than a blank file: ```bash loadout instructions new skill.deploy-checklist loadout instructions new language.rust --project starstats ``` It writes into the workspace library, or into one project's with `--project`, under the directory its layer keeps. The draft is valid when it lands, and only carries the activation its layer can use: a language is found by what is in the repository, a skill by the words of a task, and a foundation applies always and has nothing to decide. `--dry-run` prints it instead of writing it. The library is read back immediately afterwards, so a draft that does not load says so at the moment you made it rather than the next time something needed it. With `--project`, the draft arrives with what the repository can be *seen* to do already filled in: ```text ## What this repository already does Counted from the code, not decided. Check anything that looks wrong, and delete what is true but not worth a session's attention. - **Test framework:** xUnit *(from 9 file(s))* - **Nullable reference types:** enabled *(from 9 file(s))* - **Errors:** returns a result type 15.4 times as often as it throws (494 against 32) *(from 381 file(s))* - **Comments:** 100% of files carry doc comments, so explanation goes above the member *(from 381 file(s))* ``` Only what can be counted, and every line says what it was counted from, so a reader who disagrees can go and check. Failure is reported as the ratio it is rather than as a rule — "never throws" is a claim counting cannot support, and somebody would have to disprove it later. A subject nothing could be found for is left out rather than written as "none found": a draft listing what it failed to detect reads as a list of problems, and the author deletes lines instead of writing them. Everything under those lines is a prompt. `skill.write-project-specialist` activates on a task like "write the conventions" and tells an agent how to fill them in — read a dozen files before writing anything, check the counted lines rather than trusting them, write instructions rather than description, and leave out whatever the language specialist already says. One markdown file that describes itself. There is no manifest: the library is what is on disk, which removes the possibility of a registry naming a file that is not there. ```markdown --- id: database.postgresql kind: database title: PostgreSQL summary: Planner behaviour, indexing, MVCC and locking. dependencies: - 'Npgsql' - 'psycopg' task_phrases: - 'postgres' - 'postgresql' globs: - '**/*.sql' requires: - 'function.database' --- ## Cares about What the planner chose and why, and what a statement locks. ## Working rules - Read `EXPLAIN (ANALYZE, BUFFERS)`, not `EXPLAIN`. ... ``` | Field | Meaning | |---|---| | `id` | Dotted identifier. Its first segment must match `kind`. | | `kind` | One of the layers above. An unknown kind fails to load. | | `always` | Foundation only. Loads whatever the task. | | `task_phrases` | Words in the task that suggest it. The strongest signal. | | `dependencies` | Substrings of a declared dependency. | | `globs` | Repository paths that suggest it. | | `requires` | Other specialists needed for this one to make sense. | | `accompanies` | Specialists this one follows in. It loads when any of them does, and never otherwise. | | `modes` | Restrict to particular postures. Empty means all. | | `capabilities` | Agent capabilities needed before it is worth loading. | Content should answer seven questions: what it cares about, what mistakes to avoid, what to inspect, what evidence to gather, which trade-offs matter, how to verify, and when to defer to another specialist. Keep it short enough that composing four of them is still practical. Do not write a persona. "You are the world's greatest PostgreSQL guru" tells an agent nothing; "a large gap between estimated and actual rows usually means stale statistics" tells it something. Check your work: ```bash loadout instructions validate --strict ``` This is also folded into `loadout doctor`, so a broken specialist shows up wherever every other problem does. ## Trust Specialist files are instructions to an agent that can edit code and run commands, so whoever controls the file controls the agent. Accordingly: - Files are read only from inside the library directories. A link resolving outside one is refused and reported. - Ids are addresses and are never resolved against the filesystem. - Content is used verbatim. There is no template substitution of any kind, so a shared workspace cannot make the launcher interpolate an environment variable into text bound for an agent. - A skill that names a script does not cause it to run. Loading a specialist executes nothing, however the file is phrased. - Provenance is visible: `loadout instructions list` marks anything that came from your workspace or project rather than the launcher. ## Providers Loadout composes provider-neutral guidance and each adapter delivers it the way its agent expects. Provider formats — `AGENTS.md`, `CLAUDE.md`, `.cursor/rules` — are outputs, never the source of truth. Where an agent lacks a capability a specialist needs, the specialist is left out with a reason rather than loaded into something that cannot use it. Capabilities are probed against the installed CLI, not inferred from a version number.