DEV Community

Cover image for I made my coding agent explain every change to the customer. Here is the skill.
Efe Genç
Efe Genç

Posted on

I made my coding agent explain every change to the customer. Here is the skill.

The diff is never the expensive part. The expensive part comes after: explaining to the person who asked for the change what they actually got, and discovering that "done" meant "tests pass".

I spent four years as a founding engineer on a hospitality platform and then alone on a proactive assistant, and the habits that saved me the most time had nothing to do with code. Restate the request as a customer outcome before building. End every commit with a plain-language block. Do not call anything done until you have watched it behave. Write down what you deliberately did not build, next to the code. Never print a number you did not count.

Coding agents have none of these habits by default. So I wrote them down as a skill. It has since become a pack of four: product-engineer carries the seven rules, customer-block and done-means-observed carry one habit each for people who want only that, and release-notes is for an agent that writes about software instead of writing it. One installer places whatever you pick.

npx skills add Bubblegunn/product-engineer
Enter fullscreen mode Exit fullscreen mode

That places the skills for the agents in your project: Claude Code, Codex, Cursor, Copilot, Gemini CLI and the rest. Claude Code can also take it as a plugin: /plugin marketplace add Bubblegunn/product-engineer then /plugin install product-engineer@bubblegunn. Agents that read instruction files rather than skills (Cursor rules, Copilot instructions, Gemini, Cline, Kiro, Windsurf) get the same seven rules from files generated out of SKILL.md, and CI refuses a commit where the generated copies differ from the source. Source: github.com/Bubblegunn/product-engineer.

What changes

Before:

fix(notifications): classify IsSystem events as idempotent and skip the badge increment
Enter fullscreen mode Exit fullscreen mode

After:

fix(notifications): classify IsSystem events as idempotent and skip the badge increment

For the customer:
What changed: Things the system handles on its own no longer light up the phone or the menu badge; only items that need a person do.
Why it matters: The badge count means "something needs you" again, so people stop ignoring it.
Automation effect: Automatic housekeeping events are now fully handled without anyone looking at them.
Enter fullscreen mode Exit fullscreen mode

The agent used to report:

Done. All 42 tests pass.
Enter fullscreen mode Exit fullscreen mode

Now it reports:

Watched it in staging logs: 3 of 3 webhook retries logged, final failure recorded with the booking id.
Could not check: production, no deploy yet.
Not shipped:
- Dead-letter queue: three retries cover every failure in 90 days of logs.
Enter fullscreen mode Exit fullscreen mode

The seven rules

  1. Restate before building. One sentence of customer outcome, in the customer's words, or one question. One, not five.
  2. For the customer, every time. What changed, why it matters, automation effect only when a manual step really disappeared. Never an invented effect.
  3. Done means observed. Logs, data, or a real device. Or say exactly what you could not check.
  4. Build what was asked; name what you did not. A Not shipped: list with reasons, in the PR, so the decision lives where the code lives.
  5. No number without a count. Every figure has a command behind it, and its scope.
  6. Speak the stakeholder's language. A jargon-to-plain table ships with the skill, in English, Turkish, Japanese and Chinese: "idempotent" becomes "doing it twice has the same result as doing it once".
  7. Smallest change that moves the metric. One ledger line before any design: cost against customer value.

The full text is one file, SKILL.md, 89 lines. The reference files hold the template, the five questions to answer before building, the definition-of-done checklist, the four plain-language tables, the not-shipped format, and three short notes on the press-release restatement, ship-show-ask and appetite.

The hook

If you want the rule enforced rather than suggested:

sh scripts/install-hook.sh
Enter fullscreen mode Exit fullscreen mode

That installs a commit-msg hook. A commit without the block is refused with a two-line explanation. Merges, fixups and reverts pass, and [no-customer] anywhere in the message opts one commit out. The skill's own repository runs it, so every commit there is a demo.

The same check runs on its own, on a file, on stdin, or on a pull request body through gh. On a message without the block and then with it:

$ npx product-engineer check test/fixtures/without-block.txt
error no "For the customer:" block
1 error, 0 warnings

$ npx product-engineer check test/fixtures/with-block.txt
ok    "For the customer:" block with "What changed:"
ok    "Why it matters:" present
ok    "Automation effect:" present
info  readability of the block: Flesch 75 (easy), LIX 30
ok    "Not shipped:" lists 1 item with reasons
no errors, 0 warnings
Enter fullscreen mode Exit fullscreen mode

It also ships as a commitlint plugin with a shareable config, a pre-commit hook, and snippets for lefthook and husky, so a team that already has one of those adds a line rather than a tool. In CI it reads the pull request body and leaves one comment that it updates on every push, rather than a new one each time. npx product-engineer doctor reports which agents on the machine have the skill and whether their copies are current.

Measured, once

Before posting this I ran eight small coding tasks in Claude Code, each once with the skill and once without, and scored the agent's own words and git diff with five yes/no heuristics. The customer block went from 0/8 to 8/8, an observation or an honest "could not check" before "done" from 1/8 to 7/8, naming what was deliberately not built from 2/8 to 7/8. Two metrics did not move: a number with a method next to it scored 1/8 in both conditions, and every change in both conditions stayed within the requested files. The skill runs took about 60% more turns and cost about 45% more, because they verified more and wrote more. One run per task, so it is a smoke test, not a study; the harness, every transcript and the misses are in evals/RESULTS.md.

One thing that table does not say, and the repository now does: those runs installed the core skill and nothing else. The pack also ships customer-block and done-means-observed, each carrying one rule on its own, and neither extraction has been measured separately; release-notes has no task at all, because none of the eight writes release notes. Each skill file states its own gap. The alternative was to move three of four skills out of the pack and call it discipline, which would have said I shipped four things and believed in one.

One real defect, with the skill and without

The evaluation above uses small tasks. Afterwards I ran a real one twice: the same model, the same starting commit, and a defect I had actually shipped. The only source file in one of my packages held a literal NUL byte inside a string, so git classified the file as binary and no diff on it was readable, on GitHub or locally. An outside contributor could not see their own change.

Both runs produced a byte-identical fix, both spotted that the fix commit still shows as binary against its binary parent, and both declined to add a .gitattributes override for a reasoned cause. The skill did not make the model a better engineer, and I would not trust an article that claimed otherwise.

What differed is what survived the session. Only the skill run's commit message carried the customer block, the observation it had actually made (edit a line, run git diff, see a text hunk, revert), a Not shipped: line, and a plain-language paragraph. The bare run said those things in the chat window, where they die with the session. The whole transcript of both is in docs/case-study.md.

In that pair the skill run was also cheaper, 18 turns against 29, which is the opposite direction to the 45% above. One pair proves nothing either way; I am recording it because leaving it out would be picking the flattering number, which is rule five.

The block does not have to be in English

An audit today found the check rejecting a commit whose block was written as Müşteri için:, in a repository that ships its plain-language tables in Turkish, Japanese and Chinese. Inviting a team to work in their language and then failing their commit is worse than not inviting them.

The headings are data now, one row per language, read by the check, the hook and the pull request comment from the same file, with a test that fails if those three drift apart. English, Turkish, Japanese and Chinese are accepted with no configuration, a fullwidth colon reads as a colon, and a repository can name a heading for a language the table does not ship yet.

The same audit caught the readability helper returning Flesch 0, hard for Japanese. Flesch counts vowel runs as syllables, which is not what a syllable is in Japanese, Chinese, Korean, Arabic or Hebrew. It now refuses to score those scripts and says why, because rule five of this skill is that a number comes from a count, and a tool breaking its own rule on its own README's languages is the worst kind of wrong.

What it does not do

It runs no process and owns no workflow; it composes with whatever spec, TDD or review skill you already use. It does not write product strategy. It enforces nothing unless you install the hook.

Which of the seven would you throw out, and what would you add? I would rather hear the disagreement than the agreement.

Top comments (1)

Collapse
 
raju_dandigam profile image
Raju Dandigam

@efe_genc, the distinction between “tests pass” and “done means observed” is strong. The customer block also creates a useful review boundary: outcome, evidence, and intentional omissions are harder for a coding agent to blur together. Have you tried making the observed evidence machine-checkable in CI—perhaps linking each claim to a test, screenshot, or trace artifact—without turning the block into boilerplate?