🇺🇸🇧🇷

I Tested Matt Pocock's Agent Skills — This Was the Result

I tried Matt Pocock's engineering skills harness on a Java CRUD refactor. First run skipped architecture; second run asked 17 questions—and this is what came out.

I tested Matt Pocock’s agent skills on a real refactor. This is what came out—not a polished demo, but a conversation with an LLM and the code it produced afterward.

The short version: first attempt, I asked for a CRUD and the agent skipped architecture. Second attempt, I said “ask everything again” and got 17 explicit decisions before a single line changed.

Why the repo is called faruk-base2

faruk-base (the first repo) was me picking skills one by one—install this, try that, wire my own workflow by hand. It worked well enough to learn the mechanics, but there was no coherent harness: no router, no grilling protocol, no spec/ticket chain when things got big.

faruk-base2 is the opposite bet. I cloned a template built around Matt Pocock’s engineering skills—someone with more experience than me curating which skills exist and how they chain. Install with npx skills add mattpocock/skills, restore from skills-lock.json, read HELP-SKILLS.md.

I renamed the entry router locally from /ask-matt to /ask-fmz. Same skill content, different invocation name in .agents/skills/, .claude/skills/, and agent/skills/. When you see /ask-fmz below, read mattpocock/skills.

The repo is a skills testbed. This session focused on examples/java-crud—a Product REST API on Java 21, Spring Boot 4.1, and PostgreSQL in Docker:

ItemValue
APIhttp://localhost:8090/api/products
StackJava 21, Spring Boot 4.1, PostgreSQL 17
SQL editor (host)localhost:5433

Each example has CONTEXT.md and ADRs under docs/adr/. The workspace rule: technical decisions only after my confirmation, one at a time.

Attempt one: “make a CRUD” — and the agent skipped architecture

Before the session documented here, I asked the agent—using Matt’s skills—to build a CRUD. It ran. Code appeared. Docker came up.

What it did not do: walk me through architecture. No layered design question. No schema strategy. No “where does the database live?” moment. It assumed defaults and moved on.

That is the failure mode I care about. An LLM with skills is still an LLM: if the prompt is vague and the skill chain does not force an interview, you get a CRUD, not your CRUD.

So I opened a new thread and attached /ask-fmz with a clearer instruction:

Rebuild the Java module and ask everything again.

Attempt two: the flow we actually used

flowchart LR
  A["/ask-fmz"] --> B["/grill-with-docs<br/>17 questions, one at a time"]
  B --> C["Shared understanding<br/>summary + my confirmation"]
  C --> D["/implement<br/>TDD + tests + commit"]

We did not use /to-spec, /to-tickets, /handoff, /prototype, or a formal /code-review with parallel sub-agents. Scope was already closed after grilling—same session, straight to /implement.

Matt’s full harness supports a longer path (/to-spec/to-tickets → per-ticket /implement). That is for multi-session builds. This was a revalidation of an existing example, not a greenfield feature.

The conversation, turn by turn

Below is the session arc—not every word, but the decisions as they happened.

Turns 1–4 — Stack baseline

Me: /ask-fmz rebuild the Java module and ask everything again

Agent: Read the current java-crud (Spring Boot 4.1, Java 21, PostgreSQL, H2 in tests, ddl-auto, Swagger always on). Started /grill-with-docs.

TurnQuestionMy answer
1Refactor goalA — same Product CRUD, revalidate stack and decisions
2Java versionA — Java 21
3Spring BootA — 4.x
4Runtime database(see turn 5)

Turn 5 — “Where will this database live?”

Question 4 was picking a runtime database. Before choosing, I interrupted:

Tell me where this database will live?

I did not want a checkbox labeled “PostgreSQL.” I wanted a picture of what lands on my machine when I run docker compose up.

Agent: Instead of assuming, it read docker-compose.yml and answered with a diagram—then re-asked question 4 with a table mapping each option to host ports and containers:

flowchart TB
  subgraph host["Your machine"]
    Editor["SQL editor"]
    Client["Browser / curl"]
  end

  subgraph docker["Docker Compose"]
    App["java-crud"]
    DB[("PostgreSQL<br/>container: db")]
    Vol[("volume<br/>product_pg_data")]
  end

  Editor -->|"localhost:5433"| DB
  Client -->|"localhost:8090/api/products"| App
  App -->|"jdbc:postgresql://db:5432/products"| DB
  DB --- Vol

That is the moment grilling clicked for me. The agent did not decide—I still picked PostgreSQL in Docker (option A). But I could see why: nothing installs Postgres natively on Windows; data survives restarts in a named volume; my editor hits 5433, the API hits 8090, and the app talks to db:5432 on the internal network.

Turn 6 — A requirement born in chat

Once I understood the layout, I answered—and added something the checklist never asked:

A, but I always need to know how to access this database from my SQL editor.

That sentence became a README section—“Database access (SQL editor)” (Acesso ao banco (editor SQL) in the repo; docs stay pt-BR) with copy-paste host, port, user, password. Not code. Still part of the deliverable.

TurnTopicMy answer
5Test databaseA — H2 in memory (test profile)
6Schema toolingCLiquibase (replacing ddl-auto: update)
7SwaggerB — dev profile only
8Host portsA — API 8090, Postgres 5433

Turns 11–17 — Architecture, tests, language

TurnTopicMy answer
9Validation rulesA — keep current (name max 120, price ≥ 0.01, etc.)
10LayersA — Controller → Service → Repository + DTOs + exception handler
11Docker buildAmvn test then mvn package in Dockerfile
12Default compose profileAdev (Swagger on at docker compose up)
13Liquibase in H2 testsA — same changelog as production
14HTTP error formatB{ "error": "..." } in English
15Integration test scopeB“always test more things so we don’t have bugs”
16List orderingBcreatedAt DESC
17Docs vs code languageDocs pt-BR; code, tests, HTTP messages, Swagger labels, commits English

After turn 17, the agent showed a consolidated table of all 17 decisions plus a before/after diagram. I replied with /implement.

What changed in the module

BeforeAfter
ddl-auto: updateLiquibase + ddl-auto: validate
Swagger always onSwagger only in dev; off in prod
Errors in Portuguese (Produto não encontrado)English (Product not found)
List order unspecifiedfindAllByOrderByCreatedAtDesc()
4 integration tests9 integration tests
README without SQL access blockDedicated SQL editor section

After /implement

The agent committed 90526d2refactor(java-crud): revalidate example with Liquibase and expanded tests. The diff matches the table above: schema tooling, Swagger profiles, English errors, list ordering, tests, and README.

Worth showing only one snippet—the Liquibase precondition for legacy Docker volumes. The old setup used ddl-auto: update; my volume still had a products table but no DATABASECHANGELOG row. First boot after the refactor failed with relation "products" already exists. This fixed it:

# db.changelog-master.yaml
preConditions:
  - onFail: MARK_RAN
  - not:
      tableExists:
        tableName: products

Everything else was structural: ProductRepository.findAllByOrderByCreatedAtDesc(), @Profile("dev") on OpenAPI, nine cases in ProductCrudIntegrationTest, and three new ADRs under docs/adr/.

How we checked it

cd examples/java-crud
docker compose --profile test run --rm test   # 9/9
docker compose up --build -d
curl http://localhost:8090/actuator/health
curl http://localhost:8090/api/products/9999  # {"error":"Product not found"}

Swagger UI returned 200 under the default dev profile. SQL editor: jdbc:postgresql://localhost:5433/products (user/pass products).

What I take from this

The prompt is the product. Same skills, two sessions, opposite outcomes. “Make a CRUD” let the agent skip architecture. “Ask everything again” forced /grill-with-docs to run as designed—17 questions, one per turn, each with options and a recommendation. Skills route behavior; they do not fix a vague ask.

Conversation is a requirements channel. The SQL editor requirement was not in any ADR until I typed it mid-grill. It became a README section with copy-paste JDBC settings. The best specs sometimes arrive as a side comment, not a ticket.

Facts and decisions stay separate. When I asked where the database would live, the agent read docker-compose.yml and explained containers, volumes, and ports. I still had to pick PostgreSQL over H2. That is the rhythm I want: the agent surfaces what is true in the repo; I own the choice.

Versioning exposes real debt. Moving from ddl-auto to Liquibase broke startup on an old Docker volume—a table existed without a DATABASECHANGELOG row. Demo-friendly defaults hide that until you commit to migrations. The precondition in the changelog was not theoretical; it unblocked the deploy.

One session was enough here. We skipped /to-spec and /to-tickets because grilling closed the scope. For a multi-day build with blocking edges between tickets, I would take the longer path. The harness gives you both; picking the short path is a decision too.


Repo: faruk-base2. Skills upstream: mattpocock/skills. Local router: /ask-fmz. Full session handoff: resumo.md in the repo.

Comments

Comments powered by GitHub — sign in to join the discussion.