How We Use Claude Code Skills to Codify Our Development Patterns

Every codebase has patterns. The way you write tests, structure components, wire up APIs — these conventions live in your team’s collective memory, scattered across code reviews, onboarding docs, and tribal knowledge. When you bring an AI coding assistant into the mix, it doesn’t know any of this. It will write perfectly valid code that violates every convention you’ve established.
Claude Code Skills solve this by letting you encode your patterns as reusable templates that Claude automatically picks up when the context is right.
What Are Skills?
A skill is a Markdown file in .claude/skills/<name>/SKILL.md with YAML frontmatter that tells Claude when to activate and what patterns to follow. Think of them as contextual style guides that load on demand.
---
name: unit-test
description: "Generate unit tests for backend services. Use when writing
tests for query handlers, data fetchers, services, or domain logic."
---
# Unit Test Generator
...templates and rules...The description field is the trigger — Claude reads it to decide whether to load the skill for the current task. Be specific about when it should activate.
Skills We Built (and Why)
We run a Spring Boot + Vue.js monorepo with a CQRS/event-sourced backend and micro-frontend architecture. Here are the categories of skills we built and the problems each one solves.
1. Unit Test Skills
Our biggest pain point was AI-generated tests that used @MockBean (which creates a new Spring context per unique mock set, destroying test performance) or @SpringBootTest (which loads the entire application). Our convention is manual mocks with constructor injection:
class OrderServiceSpec extends Specification {
OrderRepository repository = Mock()
@Subject
OrderService service
def setup() {
service = new OrderService(repository)
}
def "should return order when found"() {
given:
def query = new FindOrderQuery("order-1")
when:
def result = service.findById(query).block()
then:
1 * repository.findById("order-1") >> Mono.just(mockOrder)
and:
result != null
result.id() == "order-1"
}
}The skill encodes this pattern plus framework-specific gotchas: Stub() defaults can’t be overridden in given: blocks, reactive methods need .block(), and interaction verification goes in then: before assertions in and:.
2. Event Handler / Projection Test Skills
Our event-sourced architecture wraps every event handler with a retry/dead-letter-queue service. Without the skill, Claude generates tests that mock the wrapper as a no-op — but the real wrapper executes the handler function. The skill teaches the correct mock pattern:
def setup() {
// The wrapper mock must actually execute the handler lambda
retryService.withRetry(_, _, _, _, _) >> { args ->
def event = args[0]
def handler = args[4]
handler.apply(event).onErrorResume { Mono.empty() }
}
projection = new OrderProjection(repository, retryService)
}This single pattern would take a developer 20 minutes to discover from existing code. The skill makes it instant.
3. Integration Test Skills
Integration tests against real databases (via Testcontainers) need a specific setup in our codebase: extend a shared base class, import the test configuration, declare repository scanning with the exact module package, and use resource locks to prevent parallel execution conflicts. Miss any step and you get cryptic Spring context errors.
The skill encodes the full boilerplate:
@SpringJUnitConfig(OrderIntegrationTest.TestConfig.class)
@ResourceLock("DB_ORDER_TESTS")
class OrderIntegrationTest extends AbstractDatabaseIntegrationTest {
@TestConfiguration
@Import(DatabaseTestConfig.class)
@EnableRepositories(basePackages = "com.example.order.infrastructure")
static class TestConfig { }
@Autowired
private OrderRepository repository;
// Tests run against real Testcontainer database
// Cleanup is automatic via inherited @AfterEach
}4. API Layer Skills (GraphQL / REST)
Our API layer has its own patterns for authentication, input validation, and type mapping. A key convention in our modulith architecture: mappers must stay within their module boundary. Adding module-specific types to a shared mapper breaches architectural boundaries and fails our modularity tests.
The skill encodes:
- How to wire up authentication (which supplier to use, which to avoid)
- Where input validation happens (schema-level, not annotation-level — the framework ignores
@Validon certain input types) - How to structure the request-command-query-response flow
- Which mapper belongs where
5. Frontend Component Skills
This is our most comprehensive skill. It covers three page archetypes we’ve standardized across our micro-frontends:
Management pages (CRUD tables): A list layout wrapper + search row + server-side data table with responsive column hiding + empty state component.
Explore pages (card grids): The same list layout + breadcrumb navigation + view mode toggle (grid/map) + responsive card grid.
Detail pages: A detail layout wrapper + hero image + tab navigation + contextual action bar.
The skill also encodes our typography scale (stat numbers use a specific heading size — not the larger ones that look overwhelming on mobile), import conventions (types from the centralized package, never local definitions), and component-specific quirks (certain Vuetify components must be imported directly, not through our shared wrapper, to preserve their interactive behavior).
6. Operations / Debugging Skills
A reference guide for accessing production databases through our Kubernetes bastion pod. This skill activates when someone asks about debugging production issues — it provides the exact commands, common diagnostic queries, and safety rules (always read before write, always scale down when done) without anyone needing to look up documentation.
How to Write Effective Skills
1. Start from real problems
Don’t write skills speculatively. Wait until Claude generates code that violates a convention, then encode the correction. Our best skills came from actual bugs:
- A test that passed locally but failed in CI because a mock didn’t execute the handler function
- An architectural test failure because a mapper was placed in the wrong module
- A mobile UI drawer that wouldn’t close because a component wrapper didn’t preserve interactive behavior
2. Include the “why”
A rule without context gets blindly followed or ignored at the wrong time. Compare:
<!-- Weak -->
Never use @MockBean in tests.
<!-- Strong -->
Never use @MockBean — each unique set of mock beans creates a new Spring
context, destroying test startup performance. Use manual mocks in setup()
with constructor injection instead.When Claude understands why a rule exists, it can make better judgment calls in edge cases.
3. Show the template, then the rules
Structure skills as: template code first, rules and gotchas second. Claude is better at following a concrete example than interpreting abstract guidelines.
4. Be specific in the description
The description field determines when Claude loads the skill. Generic descriptions waste context on irrelevant tasks:
# Too broad — loads on every backend task
description: "Backend development helper"
# Precise — loads only when writing event handler tests
description: "Generate tests for event handler projections. Use when writing
tests for event handlers that project events into read models. Handles
retry service mocking and reactive event processing."5. Keep skills focused
One skill per pattern. Don’t combine “write an API endpoint” with “write its test” — these are separate tasks that happen at different times. Smaller skills load faster and don’t pollute context with irrelevant templates.
The Compound Effect
Seven skills might not sound like much, but the compound effect is significant. Each skill prevents a class of mistakes:
| Skill Category | Prevents |
|---|---|
| Unit tests | @MockBean context explosion, wrong test structure |
| Event handler tests | Mocks that don’t execute handler logic |
| Integration tests | Missing config, wrong base class, parallel conflicts |
| API components | Module boundary violations, wrong auth pattern |
| CQRS handlers | Non-serializable event fields, blocking reactive calls |
| Frontend components | Wrong imports, inconsistent typography, broken interactive components |
| Operations guide | Wrong connection commands, missing safety steps |
After a few weeks of using skills, our code review feedback on AI-generated code dropped noticeably. The patterns that used to require “actually, we do it this way” comments now come correct on the first pass.
Getting Started
- Create
.claude/skills/<name>/SKILL.mdin your repo - Add YAML frontmatter with
nameanddescription - Write the template code and rules in Markdown
- Commit to your repo — skills are version-controlled with your code
Skills are loaded on demand based on the task context, so there’s no performance cost to having many of them. Start with the pattern that causes the most repeated corrections in your code reviews.
Further Reading:
- Claude Code Skills Documentation
- Claude Code Overview
- CLAUDE.md — Project Instructions
- Claude Code Hooks
- Claude Code on GitHub


