Jaskaran Bhatia
BlogXLinkedIn

© 2026 Jaskaran Bhatia

Jaskaran Bhatia
BlogXLinkedIn

Contents

  1. Introduction
  2. agents get stories too
  3. the stale deal
  4. eviction without gaps
  5. walk the trajectory before handoff
  6. evals sit one level below stories
  7. what an eval is made of
  8. dimensions
  9. graders
  10. flakiness is a spec problem
  11. a worked example
  12. what actually runs
  13. running the suite without lying to yourself
  14. the short version
Jaskaran BhatiaSeptember 202615 min read

your stories are your evals

practical guide for writing user and agent stories, and then evaluating them

if you've read the new user persona and designing for agents you don't control, you have the tool side already: package the outcome, make every response teach the next step, build for the weakest model. this post is the other half. once the tool exists, how do you write down what the agent should do, and how do you prove it does it?

short answer: the same way you always did for humans. you write stories, then you test them. the stories just need a second persona now, and the tests have to grade something that thinks.

the example throughout is a sales agent sitting next to a CRM. it's boring on purpose, because every team will end up building one.

agents get stories too

user stories still describe the user's job to be done. the agent is always acting for someone, so the outcome stays theirs. but on the way there the agent has constraints of its own, and those deserve stories written from its point of view.

writing "as the sales agent in the side panel, i want..." feels weird the first time. it's the same thing as a legal ops manager's goals sitting underneath a GC's goals. the agent's tactical steps sit underneath the user's outcome. if you don't write them down, an agent-level failure can hide inside a user story that passes.

the stale deal

the one that taught me this: a sales agent in a side panel next to a deal record. the rep asks "what stage is this deal at?" and gets "negotiation". they ask the agent to push the close date out a week. then they switch to the CRM and move the stage to closed-won by hand. then they come back and ask "ok so what's the forecast impact?"

the agent answers from the record it fetched two turns ago. negotiation. wrong.

that's not a quirk of one model. almost every agent reuses what it fetched earlier in the conversation, which is sensible in a chat window where nothing moves. in a side panel next to a live record, the user edits between turns all the time.

the user story (as a rep, i want to ask about the deal in front of me and get the right answer) already covered this, and it already passed. the failure happened at the agent level, so it got agent stories:

as the sales agent in the side panel, i want to treat any record state i was handed as unverified on every turn, so that i refetch before answering.

as the sales agent in the side panel, i want stale record reads evicted from my transcript, so that i don't reason over two versions of the same deal.

if you've used the agent empathy canvas, this is zone 2 (context) meeting the "conflicting signals" pain. that's the practical use of the canvas i didn't cover the first time. every pain on it is a place to go looking for a missing agent story. dead-end errors, retry loops, context bloat, conflicting signals: whenever a trace shows one of them, there's usually a story nobody wrote.

eviction without gaps

you only find the second story if you think about what the agent is actually reading. refetching fixes the first failure and leaves "negotiation" near the top of the transcript with "closed-won" further down. at that point you're hoping the model knows the later read wins.

eviction has a catch of its own. delete the old tool result and the transcript now has an unexplained gap in it. an agent reading a history full of gaps is more likely to skip steps itself, because that history just taught it that steps get skipped. so you keep the tool call and replace its result with a note: fetched, now stale, removed so you don't get confused. that's the same thing you'd do for a person reading back through a thread.

walk the trajectory before handoff

a story states an outcome. before it goes to engineering, write down the steps an agent would take to reach it.

take "as a sales ops lead, i want to know why a lead was routed to a particular rep, so that i can trust the routing." the trajectory might be:

  1. list the routing rules for this lead's segment. what comes back: name, description, the rule itself?
  2. if the rule isn't in the list, fetch it.
  3. explain the rule in plain language, against this lead's fields.

two things come out of doing this. it's spec by example, so the story now says something concrete. and it shows you the tool shape before anyone builds it. this one needs a list_routing_rules tool, and whether that tool returns the rules inline is a question to settle with your EM now, not after the build.

it also tells you where the model should and shouldn't be. in skills are a sham i argued you use the model to get to the tool call and the tool to do the thing. the trajectory is the list of decisions the model has to get right on the way to those calls, and that list is exactly what you'll test.

a story isn't done until it has a trajectory (what to build) and acceptance criteria against that trajectory (how you'll know it works). those acceptance criteria are your evals. they just aren't code yet.

evals sit one level below stories

once the acceptance criteria are clear, writing evals is close to mechanical. coding agents write most of them now. give one your criteria and an existing eval file as the pattern and you get a decent suite back. the hard part is the thinking upstream, which is why the first two sections of this post exist.

in the stale deal case, two agent stories turned into twelve eval cases. that ratio is normal.

the part that trips PMs up is that evals depend on implementation and stories don't. take "earlier activity reads are stale, so asking about activities again refetches them." if the frontend later learns to flag which activities changed, the agent no longer needs to refetch everything, and the eval becomes "for every changed activity, fresh data is pulled in automatically." the user outcome is exactly the same and the eval is different.

that's why evals need a real PM and EM handshake. think of it like acceptance criteria and unit tests. you own the criteria, engineers own the tests. evals sit somewhere in between, because they encode agent experience, which is your job, and implementation, which mostly isn't. you don't need to understand every line of how an eval checks something. you do need to know what it's checking.

what an eval is made of

skills are a sham makes the case that tests are the contract for code. evals do the same job for the part you can't write as code, which is the model deciding what to do.

an eval is a test case. it holds everything needed to reproduce a run, plus the expected result. it never holds the actual output. a unit test for 1 + 1 holds the inputs and the 2, not whatever your code returned last time.

the task is the setup: which user, which date, which agent, which capabilities are switched on, the conversation history up to the turn under test, the new message, and mock data for every tool the agent might call.

the criteria are the checks. each one gets a dimension and a grader.

dimensions

i tag every criterion with one of five:

  • trajectory: right path, right tools, sensible order?
  • guardrails: did it avoid the things it must never do?
  • answer: is the substance right?
  • grounding: is it backed by the record or source it came from?
  • presentation: is it pitched well for the reader?

once everything's tagged, the report stops saying "the agent is at 77%" and starts saying where it breaks. in the suites i've been close to, guardrails and presentation sit near perfect almost from the start, and trajectory is nearly always the weak spot. grounding usually has too little coverage to say anything, which makes it unknown, not good. those aren't the same thing.

graders

  • deterministic: code checks a fact. was get_deal_activities called? do these test inputs produce these outputs?
  • judge: a model reads the output against a written criterion. is this summary fair? would a sales manager follow this explanation?

use deterministic wherever you can compute the answer. a judge is guessing, and code isn't.

flakiness is a spec problem

people treat evals as pass/fail. they don't have to be.

even a deterministic trajectory check can have levels. if the agent refetches every activity on the deal, the outcome is met, so 2 out of 3. if it fetches only the one activity it needed, 3 out of 3.

judges should grade on scales where every level is written down. back to the stale deal, for "doesn't repeat stale activity as current": 1 means it never reread, 2 means it read both old and new and got confused, 3 means it ignored the stale read and answered from fresh data.

same input, same model, different grade: that's what flakiness actually is, and almost every time it comes from a vague criterion. "rate this 0 to 5" gets a 3 on one run and a 2 on the next, because you can't really run models at zero temperature anymore. write down what each level means and the grades stop moving. a different model giving a different grade isn't flakiness. it's a different environment, and useful information.

an extreme example of how much the wording matters: back in 2023, running extraction evals on the models of that era, 1-to-4 scales bunched up at the ends. letters did the same thing. what fixed it was meaningless labels (q, j, l, v), each tied to a written condition, with the mapping back to scores done outside the model. current models don't need the trick. the lesson still holds.

a worked example

story: a sales ops lead wants to change a routing condition across 30 rules in five workflows, from region = APAC to region = APAC and segment = enterprise.

the trajectory is read the current condition, apply the update, confirm the result. here's the one level below thing again. if the update tool already returns the rule as it now reads, the confirmation read is redundant, and the eval shouldn't require it. check how the tool was built before you sign off on its eval.

one feature, four evals:

evalgradercatches
rule is syntactically validdeterministica rule that won't save
rule logic is correctdeterministic, run test leads through ita rule that saves but routes wrong
other rules untoucheddeterministiccollateral edits
explanation makes sense to sales opsjudgean explanation that's too technical, too thin, or doesn't match

the second row is the one that should keep you up. an existing rule has a nested and/or, and the agent breaks it while adding the new clause. it's syntactically fine and it gets through review. three months later someone asks why enterprise APAC leads keep landing in the SMB queue.

you could ask a judge whether the rule "matches the intent". don't. run leads through it and check where they land. save judges for what code can't compute: explanations, summaries, tone.

specific evals beat generic ones for the same reason. "updates any routing rule correctly" can only be graded on vibes. a concrete rule with concrete test leads can be graded by code. when a new failure shows up, first ask whether you already have an eval that represents it. if you don't, add one (a nested rule, say). if you do and it failed anyway, your criteria aren't tight enough.

what actually runs

people new to this assume an eval sends one message and grades the reply. for anything with more than one turn, it's more careful than that.

say the failure was on a follow-up. the rep asked for "deals over $50k closing this quarter", got some next-quarter deals mixed in, and replied "no, this quarter only." to test the fix:

  1. replay the whole history, so the agent sees that reply as a correction and not a fresh question.
  2. run the agent live, with every tool call returning mock data from the task, deterministically. nothing touches a real CRM.
  3. give the judge one criterion ("the answer lists only these two deals") and the final answer. not the full history. the history was there to reproduce the run, not to grade it.

get the replay wrong and you end up testing the wrong thing. replay only the first turn and you'll tell everyone it's fixed while the rep keeps seeing the bug.

running the suite without lying to yourself

the suite doesn't need to pass. it needs to reflect reality. "all evals green" isn't in my definition of done. some evals are must-pass before release. others can slip, because the last 5 to 10 percent of a behaviour can need a real redesign and shipping shouldn't wait on it. a failing eval that ships stays in the suite as a known failure. deleting it to get a green run is just lying with extra steps.

every customer failure becomes an eval. unblock the customer first. then add a synthetic eval that reproduces the failure, and leave it failing until it's fixed. synthetic matters: no customer data goes in the suite. an agent turning a support ticket into an eval will happily copy it verbatim, so make sure yours rewrites it.

when an eval fails, find the layer before you touch the prompt. i've watched a ticket-triage agent fail to escalate enterprise accounts. everyone's first instinct was to fix the prompt. the actual problem was that the tool never returned the account's tier field, so the agent was being asked to decide on data it never got. the failure can be in the prompt, the tool, the tool response, or the eval itself. figuring out which one is a joint call with your engineers.

read the prompt diff, not just the results. coding agents write most prompts now, and they add rules nobody asked for. a change meant to make stale activities get refetched can quietly turn into "treat all activities as unverified." that's wrong, because a logged call is a record of something that happened. when you catch one of these, add an eval for it. if you really can't right then, at least fix the prompt. that's the floor.

stop answering "does it work?" sales asks "does deal editing work?" and there's no yes or no. for any specific request there are three answers:

  • yes: a passing eval covers it
  • no: a failing eval covers it, and it's being worked on
  • unknown: nothing covers it, so it isn't promised

so give GTM the list of stories with passing evals. that's what the agent can do. it's a much more honest conversation than a demo.

model comparisons come almost for free. i argued in llm commoditization that evals are what make switching models possible. once the suite is tagged by dimension, you can see where a model is better, not just whether it is. keep a strong model as the reference and measure how close the cheaper ones get. sometimes the one you assumed was worse wins and nobody can explain why. go investigate that before switching to it.

the short version

  • agents get stories too. most of them come from seeing what the agent could actually see when it got something wrong. the canvas pains are where to look.
  • evict stale context, but leave a note where it was. gaps teach skipping.
  • walk the trajectory before handoff. it tells you what to build and what to test.
  • evals sit one level below stories. same outcome, different eval when the implementation changes.
  • tag every criterion with a dimension. grade with code when you can, and write down every level of every scale.
  • flaky grades mean a vague criterion.
  • the suite should match reality, not pass.

© 2026 Jaskaran Bhatia