Products Consulting About Blog Contact Us Česky
arrow_back Back to blog

How We Use Claude Code Skills to Codify Our Development Patterns

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.

YAML
---
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:

GROOVY
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:

GROOVY
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:

Java
@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 @Valid on 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:

MARKDOWN
<!-- 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:

YAML
# 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 CategoryPrevents
Unit tests@MockBean context explosion, wrong test structure
Event handler testsMocks that don’t execute handler logic
Integration testsMissing config, wrong base class, parallel conflicts
API componentsModule boundary violations, wrong auth pattern
CQRS handlersNon-serializable event fields, blocking reactive calls
Frontend componentsWrong imports, inconsistent typography, broken interactive components
Operations guideWrong 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

  1. Create .claude/skills/<name>/SKILL.md in your repo
  2. Add YAML frontmatter with name and description
  3. Write the template code and rules in Markdown
  4. 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:


Cover photo by 5010 on Unsplash.

More from the Blog