VITALIY MATIYASH
Building a Skills Library / Momentum 2026

Your AI agent knows Spring Boot.It doesn't know your team.

The code compiles. The tests pass. You still leave the same review comment you left last week. My Momentum talk was about turning those repeat lessons into skills your coding agent can actually use.

Vitaliy MatiyashOctober 2026~9 min read
skills/spring-boot-api/SKILL.md

Your team's playbook, in the repo

The missing
context.

→Use ApiError, not Spring's default body.
→Leave X-Trace-Id to the filter.
→Keep controllers thin.
✓Keep these rules across sessions.
Reusable context, not another prompt
LESS REPEATING YOURSELF ↗
From my talk in Cincinnati · October 15, 2026
01 / The problem

The PR that passes every test. And still needs changes.

The most frustrating AI-generated code isn't always broken code. Sometimes it's perfectly reasonable code that doesn't belong in your codebase.

I’m a staff engineer working mostly with Java, Spring Boot, and Azure, and more of the code I review now involves a coding agent. Take a new endpoint in a Spring Boot API: it builds, the tests are green, and a quick manual check looks fine. Then you open the pull request.

The 404 returns Spring's default error instead of your team's ApiError. The X-Trace-Id header is missing. A test uses getOrderById_returns404, even though every other test in that class follows should<Outcome>When<Condition>.

None of those choices is universally wrong. They're just wrong for this team. An agent can know Java and Spring Boot inside out and still have no reason to know the conventions people here learned through years of reviews, production incidents, and "we tried that once" conversations.

The problem isn't that the agent can't write code. It's that it doesn't know how we write code.

02 / The repeated lesson

Every new session, the same conversation.

That knowledge has a name: tribal knowledge. It includes the unwritten rules that matter in your systems but not necessarily anywhere else. Which template a pull request needs. Why a service must deploy after another. The tiny header rule everyone eventually learns the hard way.

When a teammate learns one of those rules, they usually remember it. A coding agent can correct the code in the current session, but that correction won't reliably show up in a new one unless the guidance is saved somewhere the agent can find it.

One rule. Three moments.Choose a step ↓
“Can you return our ApiError body (code, message, traceId) for the 404 instead of Spring's default?”

The agent fixes it. The review is done.

That little shift—from a review comment to a file in the repo—is the idea behind a skills library. It doesn't magically teach the model your entire organization. It gives the agent a reusable, task-specific playbook where one would otherwise be missing.

03 / The format

So what's actually in a skill?

A skill is surprisingly boring, in the best way. It's a folder with a SKILL.md file. That file has two required YAML frontmatter fields—name and description—followed by regular Markdown instructions. You can add scripts, references, and templates when you need them. That's the core of the open Agent Skills specification.

spring-boot-api/ ├── SKILL.md ← required ├── scripts/ ← optional ├── references/ ← optional └── assets/ ← optional
Not a plugin. Not a model fine-tune.A small, reviewable package of instructions and supporting files. You can put it in version control, change it in a pull request, and give it an owner.

Here's the start of the skill from the synthetic Spring Boot Orders API I built for the talk. The details are intentional: what the skill covers, which conventions matter, and which requests shouldn't use it.

skills/spring-boot-api/SKILL.md
---
name: spring-boot-api
description: >-
  Add or change REST endpoints in the Orders API
  (Spring Boot, package dev.skillslibrary.orders)
  the way this team reviews them - ApiError error
  bodies with codes, X-Trace-Id handling, thin
  controllers over services, record DTOs,
  should<Outcome>When<Condition> tests with AssertJ.
  Use when adding an endpoint, an error case, or
  controller tests in this repo. Not for build,
  dependency, or database-schema work.
---

## Hard rules (MUST: a reviewer blocks the PR)

- Errors MUST be `ApiError` (`code`, `message`, `traceId`)
  from the one `@RestControllerAdvice`.
- Controllers MUST NOT read or set `X-Trace-Id`.
  `TraceIdFilter` owns it.
- Controllers MUST NOT import from `..domain..`.
  Entities never leave the service.

The description deserves more attention than its size suggests. It's a discovery hint. Supported clients can expose skill names and descriptions first, then load the body when a task calls for it. A vague description like “helps with APIs” makes it harder to pick the right skill—and easier to pick it when it doesn't belong.

How a skill loadsInteractive / 3 steps

First, the name and description.

The agent sees enough metadata to recognize that this skill may be relevant. It hasn't needed the full playbook yet.

MetadataConceptual context load · not to scale

This is the progressive-disclosure idea in the spec. Exact discovery and invocation behavior depend on the client. For example, Claude Code project skills can live under .claude/skills/<name>/SKILL.md. In the demo repo's skill, the frontmatter is about 111 tokens, the body about 458, and the two reference files about 530 and 452 (characters ÷ 4).

04 / Hands-on

Don't just read about it. Give the agent a task.

The demo repository has a small Spring Boot Orders API, team conventions, the skill above, ArchUnit checks for layering, and a script that reports which conventions a change follows. The rules are deliberately more specific than the defaults you'd get from a generic code-generation prompt.

  • Errors are ApiError objects with code, message, and traceId—not the default Spring error body.
  • X-Trace-Id is echoed on responses and included in errors.
  • Controllers stay thin, entities don't escape the service layer, and DTOs are records.
  • Controller tests use @WebMvcTest, AssertJ, and the team's naming convention.
Example task · same prompt in both runs
Add GET /api/orders/{id} with a 404 response
and controller tests.

Try it once with the skill available and once without. Start from the same commit, use a fresh session each time, and compare the diffs and validation results. If you want to be thorough, repeat each condition: an agent doesn't always make the same choices twice.

A useful caveat: the existing Orders API already follows these conventions. An agent can read the surrounding code and copy the patterns even without a skill. That's not a flaw in the exercise; it's reality. If both versions succeed, the skill may not be adding much for that task.

Open the Spring Boot demo repo ↗
05 / The stack

Skills aren't a replacement for everything else.

One of the questions I hear most is “Isn't this just a giant CLAUDE.md?” Not quite. I think about the pieces by the job each one does, rather than treating them as competing products.

Project instructions

CLAUDE.md or AGENTS.md: shared facts and always-relevant rules. Usually loaded as project context.

Skills

Task-specific playbooks. Available for discovery; detailed instructions loaded when relevant.

MCP tools

Connections and actions: read the issue tracker, query a system, call an API. Tool behavior varies by client.

Hooks & checks

Enforcement at defined points, such as linting or tests. Don't rely on an agent remembering to verify everything.

Specialized agents

Delegate a piece of work to a focused worker or workflow when the platform supports it.

Reusable prompts

Questions or commands you invoke yourself. Useful when there's no need for automatic discovery.

My simplest mental model from the talk: MCP gives an agent access. A skill gives it a procedure. You often want both. But if a rule can be checked deterministically by a test, put it in a test too.

06 / The cautionary part

A good skill can still go very wrong.

I wish the story ended with “write a SKILL.md and enjoy perfect pull requests.” It doesn't. A skill can help an agent make better choices, but it can also make the agent more confident about a bad choice.

A 2026 research paper I referenced in the talk, Demystifying Agent Skills: Why They Work—Until They Don't, looked at agent runs with and without skills. The part I found most interesting wasn't simply whether a run passed. It was what the skill changed.

65.7%
Procedural anchoring

Share of classified skill-use cases where the skill stabilized execution steps.

4.5%
Explicit new facts

Share of cases classified primarily as injecting missing knowledge.

29.6 → 3.3%
Retrieval precision

The share of actually used skills that were the right skill when the pool grew from 5 to 100.

These percentages describe specific analyses and experimental conditions in the paper—not an expected improvement percentage for your own repo. Read the study ↗

The same study counted runs where the agent misapplied or ignored the guidance it was given: 0.8% without skills, 10.0% with them. In other words, skills often work because they give an agent a sequence it can follow. But that also raises the stakes when the sequence is meant for the wrong situation.

01

The right procedure, wrong target

In a synthetic Kubernetes exercise for the talk, a runbook intended for a stateless service was applied to a stateful database. In my local tests, the older models I tried removed a volume claim in 9 of 9 runs. Later models stopped in 16 of 16; adding explicit disqualifying conditions to the skill helped older ones stop too (6 of 6). Those are small, setup-specific runs—not a ranking of models—but the lesson stuck: say when the procedure must not be used.

02

The skill nobody opens

If discovery misses the right skill, the instructions might as well not exist. Test descriptions with real task phrasing, including lookalike requests where the skill should not activate.

03

The stale rule that still sounds authoritative

Two slightly different copies of a skill create two competing sources of truth. Treat skills like code: ownership, review, version control, and a way to update consumers.

04

Instructions that sound good but say nothing

“Handle failures appropriately” leaves the risky decisions to the agent. A useful procedure says what to inspect, what success looks like, and when to stop. For hard guarantees, add programmatic checks.

I don't want an agent that blindly follows a runbook. I want one that knows when the runbook stops applying.

07 / Your first skill

Three things I'd try on Monday.

You don't need a platform team, a hundred-page strategy, or a library of fifty skills to find out whether this is useful. Start with one annoyance everyone recognizes.

The smallest useful experimentOne repo · One rule · A few runs
1

Find the comment you keep writing.

Look through recent pull requests. Pick a correction that's specific to your codebase, not a generic style preference. Write the rule, why it exists, and a concrete example in a skill.

2

Test whether the skill gets picked.

Write three requests that should invoke it and two that shouldn't. Use the words teammates actually type. Tighten the description until discovery makes sense.

3

Compare against doing nothing.

Same task, same starting commit, fresh sessions—with and without the skill. Check the convention that motivated you to write it. If the skill doesn't improve the outcome, revise it or move on.

That's a much better starting point than trying to capture everything your team knows. Build the library from real friction, one procedure at a time.

The takeaway

The best skill might be the review comment you never have to write again.

I built the starter kit so there's somewhere concrete to begin: a template, a simple linter, and before-and-after runbook examples. The Spring Boot demo gives you a task to test. And the slides are there if you'd rather see the talk version.

One question to leave with: what does your team keep explaining that your repository still doesn't say?