Every team has a person who knows how things are done here.

How we name our endpoints. Which result type we return. Why we never throw from a handler. How a migration gets reviewed before it’s merged. None of it is written down. It lives in one or two people’s heads and spreads by osmosis — a code review comment here, a “no, we do it like this” there.

That person is a bottleneck. And if you’ve been using Claude Code, you’ve probably made it worse without noticing.

Because you taught Claude Code your conventions. In your CLAUDE.md, in the way you prompt it, in the corrections you make a hundred times a week. Your Claude Code writes code the way you like it. Your teammate’s Claude Code doesn’t. The new hire’s definitely doesn’t.

The knowledge is now in two places instead of one: your head, and your personal setup. Neither of them belongs to the team.

Skills fix that.


CLAUDE.md is personal. Skills are shareable.

A quick distinction, because the two overlap.

CLAUDE.md is always-on context for a repo. Claude reads it every session — it’s what makes a code review sound like your most experienced teammate instead of a generic linter. It’s the right place for facts that are always true: “this is an ASP.NET Core 9 API, we use EF Core, target framework net9.0.” But it’s a single growing wall of text, and in practice a lot of it is personal or local to how you work.

A skill is a folder with a SKILL.md that Claude loads on demand — only when the task matches its description. It’s a named, reusable capability. And crucially: it lives in the repo, in version control, so everyone who clones the repo gets it.

A rule of thumb:

  • CLAUDE.md — context Claude should always have. The stack, the target framework, the non-negotiables.
  • Skill — a specific way of doing a specific thing. “How we add an HTTP endpoint.” “How we write a migration.” “How we review a PR.”

The difference that matters for a team: a skill is discoverable and transferable. You don’t have to be in the room for it to work.


The convention that lives in your head

Let me make this concrete. On my team, a new API endpoint isn’t just a controller action. It has to:

  • validate its input and return a 400 with a problem-details body when it’s wrong,
  • return a Result<T> instead of throwing,
  • never touch the DbContext directly from the handler,
  • ship with an xUnit test.

None of that is written down anywhere. It’s just how we do it.

Now a new developer joins and asks their Claude Code:

“Add an endpoint to cancel a trip.”

They get a perfectly reasonable controller. It throws InvalidOperationException when the trip doesn’t exist. It returns the Trip entity straight from the DbContext. There’s no test. Nothing about it is wrong — it’s just not how we do it.

So the pull request comes in, and a reviewer writes the same three comments they write every week. The new developer fixes it. Everyone loses twenty minutes. And nothing was learned that the next new developer won’t have to learn again.


Turning it into a skill

The fix is to write the convention down once, in a form Claude can apply. Create a file at .claude/skills/add-endpoint/SKILL.md:

---
name: add-endpoint
description: >
  Use when adding or changing an HTTP endpoint in this API.
  Enforces our validation, result-type, and testing conventions.
---

# Adding an endpoint

Every endpoint in this project follows the same shape.

## Rules

1. Validate input first. On failure return `400` with a
   `ProblemDetails` body — never throw for bad input.
2. The handler returns `Result<T>`, never the EF entity, and
   never throws for expected failures (not-found, conflict).
3. The handler does not touch `DbContext` directly. It calls a
   repository or a domain service.
4. Every endpoint ships with an xUnit test covering the happy
   path and at least one failure path.

## Shape to follow

```csharp
public async Task<Result<TripDto>> CancelTrip(Guid tripId, CancellationToken ct)
{
    var trip = await _trips.Find(tripId, ct);
    if (trip is null)
        return Result.NotFound($"Trip {tripId} does not exist.");

    var outcome = trip.Cancel();          // decision lives in the domain
    if (outcome.IsFailure)
        return Result.Conflict(outcome.Error);

    await _trips.Save(trip, ct);
    return Result.Ok(trip.ToDto());
}
```

Now the new developer asks the exact same question — “add an endpoint to cancel a trip” — and Claude Code recognises the task, loads the skill, and produces the endpoint in our shape: validation up front, a Result<T>, no DbContext in the handler, and the xUnit test alongside it.

The reviewer doesn’t write those three comments. Because they never needed to.


Put it in version control

This is the part that turns a personal trick into a team asset.

.claude/skills/ is just files in your repo. Commit them. From that moment, every developer who clones the project gets the skill automatically — no setup, no “install my config”, no Slack message with a gist attached.

The effect on onboarding is the interesting bit. A new hire doesn’t need to know the convention to follow it. They ask Claude Code for an endpoint and get one that already fits. They learn the convention by reading the code it produced, not by getting it wrong in a PR first. The knowledge moved out of one person’s head and into the repository, where it belongs.

And because skills are code, they’re reviewed like code. A change to how you add endpoints is a pull request against add-endpoint/SKILL.md — visible, discussed, versioned. Your conventions get a changelog.


Where this gets thin

Two honest limitations, because a skill is not magic.

Skills go stale, and a stale skill is worse than none. A skill that describes last quarter’s convention will confidently apply the wrong thing, and it’ll do it fast and everywhere. So a skill needs an owner and it needs to be reviewed when the convention changes. Keep them small and specific. A giant “how we do everything” skill won’t be loaded at the right moment and won’t get maintained — it just rots.

A skill is guidance, not a guarantee. It shapes what Claude produces; it doesn’t enforce anything. Someone can still merge an endpoint that ignores it. Enforcement is a different layer — checks that run in your pipeline and review gates with a human at the end — and that’s where this series is going.


Try it this week

Pick the one convention you catch yourself explaining out loud to every new person. Just one. The endpoint shape, the migration ritual, the way you structure a handler — whatever you’re tired of repeating.

Write a SKILL.md for it: a name, a one-paragraph description, and a single before/after C# example. Commit it. The next time someone — or their Claude Code — does that task, watch whether they still need you in the room.

Which convention do you keep explaining by hand? Drop it in the comments — there’s a good chance it’s a skill waiting to be written, and I’m curious what everyone else’s “we do it like this” turns out to be.


This is part 1 of a short series on running Claude Code across a whole team, not just at your own desk.

Next — Part 2, on 27 July: once you have a skill worth sharing, how do you ship it — together with your subagents and hooks — as a single plugin your whole team installs with one command? Part 3 follows on 3 August.