Tests and Linters
By the Syncfusion DevTutorials team · Last updated
Why an agent says "done" while a team rule is broken, how a definition of done makes it run the checks first, and how a lint message that names the fix lets the agent repair its own mistake. Includes sensors for testing, UI, planning, APIs and CI.
What Tests and Linters Do for an Agent
A sensor is a check that runs after the agent acts. It looks at the result and says if something is wrong.
In this lesson, you will learn how to make the agent run its sensors.
You will also learn how to make their messages useful.
Tests are sensors. So are lint, type checks and builds.
Lint = an automatic check of code style and patterns. A linter is the tool that runs it, such as ESLint.
For example, the team has a rule for dates:
- React: components must use
formatDate(), so every user sees the same date. - ASP.NET Core: code must not read the clock with
DateTime.Now, so tests can control the time.
The agent is asked to show a date. It takes the quick way, which breaks the rule.
The tests still pass. So it says "Done".
A Real-World Example
Think about a car's dashboard.
A warning light that only says "!" is not much help.
You know something is wrong. You do not know what to do.
A light that says "Tyre pressure low, front left. Add air." tells you what to fix.
And a light only helps if it works before you drive. A light that wakes up after the trip is too late.
Agent sensors work the same way:
- They must run before the agent says it is done.
- Their message must say what to do, not just "wrong".
"Done" with a broken rule
Click the button and watch the run in the Harness Lab.
- The edit: the agent uses a quick date call.
- The tests: they pass, so it says "Done".
- Then: open the Terminal tab and type
pnpm lint(ordotnet build -warnaserror). The check fails. The agent never ran it.
Simple lesson: green tests do not mean every team rule holds.
What You Will Learn
In this lesson, you will learn:
- What a sensor is.
- How to write a definition of done.
- Why a vague check message leaves the agent stuck.
- How to write a lint message that teaches the fix.
- Where CI fits.
Sensors Run Before "Done"
Guides and Sensors
Guide = something that tells the agent what to do before it acts.
Sensor = something that checks the result after it acts.
The rules file can hold both. "Use formatDate()" is a guide.
"Run pnpm lint before done" turns the lint into a sensor the agent always uses.
The Definition of Done
Definition of done = the list of checks that must all pass before the agent may say it is finished.
Without one, the agent decides by itself when it is done. It usually stops at the first green test run.
Watch the same job twice. First without the lint in "done", then with it:
Step through all five frames.
- Frame 1: the rules list only
pnpm testbefore done. - Frame 2: the agent's transcript. A red line breaks the rule. Then it says "Done".
- Frame 3: the lint, run after "done". It fails.
- Frames 4 and 5: a definition of done with both commands. Now the agent runs the lint and does not claim done.
How to Write It
Write it in the rules file, in plain words, with exact commands in backticks:
- Definition of done: `pnpm test` and `pnpm lint` both pass. Run them before you say you are done.
- Definition of done: `dotnet test` and `dotnet build -warnaserror` both pass. Run them before you say you are done.
The -warnaserror flag matters.
Without it, a banned API is only a warning. The build still says "Build succeeded".
Simple lesson: list every check by its exact command, and say "before you say you are done".
A Sensor That Does Not Teach
Stuck on "Not allowed."
Now the lint is part of "done". The agent runs it and sees that it fails.
But the message only says "Not allowed."
A sensor that does not teach
Click the button and read the end of the run.
- The lint line: it says "Not allowed." and nothing more.
- The last thought: the agent knows something is wrong.
- The finish: it does not know what to use instead, so it gives up.
A sensor helps when it runs before done, and its message says what to do instead. Then the agent can fix its own mistake.
Messages That Teach the Fix
OpenAI's team writes lint rules whose error text tells the agent how to fix the problem. The message is written for the agent, too.
A teaching message has three parts:
- What is wrong: "Do not format dates in components."
- What to use instead: "Use
formatDate()fromsrc/lib/dates.ts." - Why: "So every user sees the same date."
Watch the same agent with each message:
Step through all five frames.
- Frame 1: two lint files. Only the message is different.
- Frame 2: the exact error line the agent reads.
- Frame 3: what it does next. Vague: it gives up. Teaching: it edits the import.
- Frame 4: the full runs. Only the teaching side ends with the lint passing.
- Frame 5: the same thing in .NET, with
BannedSymbols.txt.
A Real Lint Rule
Here is a real rule in each format. Each bans one call, and its message names the fix.
// eslint.config.js
export default [
{
files: ["src/components/**/*.tsx"],
rules: {
"no-restricted-syntax": ["error",
{ selector: "CallExpression[callee.property.name='toLocaleDateString']",
message: "Do not format dates in components. Use formatDate() from src/lib/dates.ts, so every user sees the same date." },
],
},
},
];
The banned-API analyzer reads this file. It reports rule RS0030:
# Pricing.Api/BannedSymbols.txt
P:System.DateTime.Now;Do not read the clock directly. Use TimeProvider.System.GetUtcNow(), so tests can control the time.
Lab Exercise: Wire the Sensors Into Done
Make two changes in the lab:
- In the rules file, add a definition of done with the lint (
pnpm lintordotnet build -warnaserror). - In the lint file (
eslint.config.jsorPricing.Api/BannedSymbols.txt), rewrite the message so it names the fix.
Wire the sensors into done
Click the button, make both edits, then press Check my harness.
- First try: the agent still makes the quick mistake.
- Then: the lint fails, and the agent reads your message.
- The check: it must fix its own code on all 3 versions.
Here is what both edits do, on every job and both stacks:
Step through all four frames.
- Frames 1 and 3: the starting harness. Every job says "Done" with the rule broken.
- Frames 2 and 4: the two edits. Every job ends with lint and tests passing.
The quick first try is not a bug in the lab.
Real agents take shortcuts too.
A good harness does not hope the agent gets it right the first time. It makes sure the agent finds out, and knows how to fix it.
Simple lesson: run the sensor before done, and make its message say the fix.
Sensors for Each Part of the Team
The same idea fits any check a tool can run: coverage, colour tokens, accessibility, API contract tests and plan checks.
The lab runs unit tests, lint and end-to-end checks. It has no CI server and no contract tests. Set those up in your own project.
CI (continuous integration) = the full set of checks, run on every change, on a clean machine.
Keep "done" fast. A slow or flaky check gets skipped. Put fast checks in the definition of done, and the slow ones in CI.
Simple lesson: fast checks before done, slow checks in CI.
TL;DR
- Sensor = a check that runs after the agent acts, such as tests, lint, type checks and builds.
- Definition of done = the exact commands that must pass before the agent says done.
- Red build claimed as done = the agent said done, but a check it never ran fails.
- Teaching message = what is wrong, what to use instead, and why.
- ESLint
no-restricted-syntax= the React way to ban a call, with a message. BannedSymbols.txt= the .NET way to ban an API. With-warnaserror, RS0030 fails the build.- Lint = an automatic check of code style and patterns.
- CI = every check, run on each change, on a clean machine.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| No definition of done | "It will run the checks it needs." | List every check in the rules file. | It stops at the first green test run. |
| Lint not in "done" | "The lint runs in CI anyway." | Run it before done, too. | The agent says done with a broken rule. |
| Vague messages | "Not allowed." | "Use formatDate() from src/lib/dates.ts." | The agent sees the error but cannot fix it. |
Plain dotnet build | "The build will catch banned APIs." | Use dotnet build -warnaserror. | RS0030 is only a warning, and the build passes. |
| Only unit tests | "Tests pass, so it works." | Add lint, contract and CI checks. | Rules and contracts break without anyone noticing. |
| Slow checks in "done" | "Run everything every time." | Fast checks in "done", slow ones in CI. | The checks get skipped. |
Check Your Understanding
Exercises
These exercises practise the two sensor habits from this lesson.
Press Check when you are ready. Use Show Hint if you get stuck.
What to Remember
- A sensor checks the result after the agent acts.
- A sensor must run before "done". Write a definition of done with exact commands.
- In .NET, use
dotnet build -warnaserror, so a banned API fails the build. - A sensor must teach: what is wrong, what to use instead, and why.
- Real formats work: ESLint
no-restricted-syntaxwith a message, or .NETBannedSymbols.txt. - Keep the checks in "done" fast. Slow ones go in CI.
Further Reading
- Harness engineering: leveraging Codex in an agent-first world, by OpenAI: custom lints whose error messages tell the agent how to fix the problem.
- Harness engineering for coding agent users, on martinfowler.com: sensors as feedback that the agent can act on.
- awesome-harness-engineering, by walkinglabs: evals, checks and guardrails.
Next: Hooks and Permissions. You will turn "never" rules into walls the agent cannot get past.