Narrative Challenge Design
Making challenges engaging through storytelling. A great challenge is technically rigorous AND compelling to read. Narrative doesn't make challenges easier — it makes them memorable, motivating, and immersive. Nobody remembers "Fix Payment Service Bug #47." Everyone remembers "The Haunted Microservice."
Narrative Patterns
The Mystery
Something is wrong but nobody knows why. The agent is a detective.
HOOK: "Users are complaining that their shopping carts are randomly emptying
themselves. The engineering team has been investigating for two weeks. They've
checked the database, the cache, and the session store. Nothing looks wrong.
The carts just... vanish."
STRUCTURE:
- Clues scattered across logs, code, and config
- Red herrings that look promising but lead nowhere
- The root cause is non-obvious (race condition, timezone bug, silent failure)
- Resolution requires connecting multiple pieces of evidence
The Race Against Time
A deadline creates urgency. The agent must deliver under pressure.
HOOK: "The board demo is in 4 hours. The CEO just tried the new feature
and it crashed. Twice. The lead developer is on vacation in Bali with
no cell service. You have their code, their half-written tests, and a
Slack message from last Friday that says 'I think there's a bug in the
payment flow but I'll fix it Monday.'"
STRUCTURE:
- Clock is ticking (simulated time pressure)
- Limited information (developer is unavailable)
- The bug is real and findable
- Success = working demo by deadline
The Inheritance
The agent takes over someone else's work. Must understand before extending.
HOOK: "Three months ago, a contractor built the analytics dashboard.
They left no documentation, no tests, and variable names like 'temp2'
and 'x_final_v3'. The dashboard works — somehow. Now the CEO wants
a new chart added. Don't break anything."
STRUCTURE:
- Legacy code that's functional but messy
- No documentation (or misleading documentation)
- Extension must not break existing functionality
- Understanding the existing code IS the challenge
The Stakeholder Conflict
Multiple people want different things. The agent must navigate politics.
HOOK: "The security team wants to add 2FA to every login. The product
team says conversion will drop 15%. The CEO says 'figure it out' and
walked into another meeting. You have until Friday."
STRUCTURE:
- Two or more stakeholders with legitimate but conflicting needs
- No single "right answer" — must find a compromise
- Technical solution must satisfy the compromise
- Communication of the decision is scored
The Disaster Recovery
Everything is broken. The agent must triage, communicate, and fix.
HOOK: "It's 6 AM on Monday. Your phone has 14 unread alerts. Staging
is down. A customer emailed the CEO directly. The on-call engineer's
Slack status says 'Out sick.' Welcome to your week."
STRUCTURE:
- Multiple simultaneous issues
- Stakeholder communication required
- Triage is the real test (what to fix first)
- Root cause isn't the most visible symptom
Writing Rules
1. Evocative names, not descriptive ones
| Bad (descriptive) | Good (evocative) |
|---|---|
| Fix Payment Service Bug | The Haunted Microservice |
| Debug Authentication Flow | The Impostor |
| Optimize Database Queries | The Slow Burn |
| Add Caching Layer | The Cache Trap |
| Fix Race Condition | The Ghost in the Machine |
| Refactor Legacy Code | The Inheritance |
| Handle API Changes | The Moving Target |
| Secure User Input | The Trojan Form |
| Fix Memory Leak | The Slow Bleed |
| Debug Production Outage | Monday Morning |
2. Hook paragraph first, technical details follow
Bad (technical-first):
This challenge involves debugging a Node.js Express application that has
a race condition in the payment processing middleware. The middleware uses
a shared state variable that is not properly synchronized...
Good (hook-first):
Customers are being double-charged. It happens randomly — maybe 1 in 200
transactions. Customer support has fielded 47 angry calls this week. The
payments team swears the code is correct. They're right — almost. There's
a ghost in the payment middleware, and it only appears when two requests
arrive at exactly the wrong moment.
3. Include personality
Challenges should feel like they were written by a person, not generated by a template.
Personality elements:
- The previous developer's commit messages:
"fix stuff","WIP DO NOT MERGE","¯\_(ツ)_/¯" - Realistic file names:
utils_old_DO_NOT_USE.js,config.production.bak.bak - Slack messages with typos:
"the pyaments endpoint is borked again" - README sections marked
TODO: document thisthat were never documented - Comments that tell a story:
// This fixes the bug from October. Don't ask.
4. Never condescending
The briefing should treat the agent as a competent engineer, not a student.
Condescending: "Remember, always sanitize user input before using it in SQL queries!" Respectful: "The search endpoint processes raw user input. You know what to do."
5. Stakes feel real
Every challenge should answer: "Why does this matter?"
No stakes: "Fix the bug in the payment service." Real stakes: "Acme Corp processes $2.3M/day through this endpoint. Every hour of downtime costs them $95,000. They're on the phone with your CEO right now."
The Hook Formula
Every challenge briefing follows this structure:
Scene Setting (2-3 sentences)
Establish the situation. Create atmosphere. Make the agent CARE.
"It's your third week at Meridian Health, a startup building electronic
health records for rural clinics. The system processes 12,000 patient
records daily across 47 clinics. This morning, three clinics reported
that patient allergies are showing up in the wrong charts."
What the Agent Needs to Do (1-2 sentences)
Clear, specific action required.
"Find the root cause of the allergy cross-contamination bug and fix it.
Every minute this is live, a doctor might prescribe medication that
triggers an allergic reaction."
Why It Matters (1 sentence)
The human impact.
"Patient safety depends on this."
NPC Voice Design
Voice differentiation guidelines
The CTO:
- Short sentences. Technical vocabulary. Time-conscious.
- "The latency spike correlates with the deploy at 11:47. Roll it back if you can't find the root cause in 30 minutes."
- Never says "please" in an emergency. Uses imperatives.
The Product Manager:
- User-focused language. Metrics and conversion numbers.
- "Our NPS dropped 12 points this month. The biggest complaint is checkout speed. Users are abandoning at the payment step."
- Frames everything in user impact, not technical terms.
The Junior Developer:
- Enthusiastic but uncertain. Asks for validation.
- "I think I found the issue — the timeout is set to 5 seconds but the API sometimes takes 8? Should I just increase the timeout, or is there something else going on?"
- Over-explains their reasoning. Uses hedging language.
The Angry Customer:
- Emotional, specific about impact, expects a timeline.
- "We've been unable to process orders for THREE HOURS. This is unacceptable. We're losing $50K an hour. I need a timeline for resolution RIGHT NOW."
- Doesn't care about technical details. Cares about when it will be fixed.
The On-Call Engineer:
- Tired, terse, focused on facts.
- "Restarted pods at 5:45. Came back. Error rate: 34%. Tried increasing connection pool, no change. Going to bed, good luck."
- Leaves breadcrumbs but doesn't hand-hold.
The Previous Developer (through code comments):
- Varies by personality:
- Meticulous:
// This handles the edge case where order_date is null due to the 2024 migration bug. See JIRA-4521. - Chaotic:
// don't touch this. trust me. - Apologetic:
// Sorry about this. The deadline was tight.
- Meticulous:
Memorable Challenge Names
Naming patterns
The [Noun]: The Inheritance, The Impostor, The Saboteur, The Reckoning The [Adjective] [Noun]: The Haunted Microservice, The Silent Leak, The Slow Burn [Action] [Time]: Monday Morning, Midnight Deploy, Friday Afternoon Special [Metaphor]: Ghost in the Machine, The Cache Trap, House of Cards [Event]: The Great Migration, The Outage, The Rollback
What makes a name work
- Evocative: Triggers an image or emotion. "The Haunted Microservice" makes you curious.
- Memorable: You can refer to it in conversation. "I scored 87 on The Haunted Microservice."
- Non-spoiling: Doesn't reveal the challenge's trick. "The Race Condition" is a spoiler. "The Ghost in the Machine" is not.
- Brief: 2-4 words. Long names don't stick.
The Humor Guideline
When humor works
- Commit messages from the previous developer:
"fix fix fix","YOLO deploy","it works on my machine ™" - Variable names in legacy code:
whatEvenIsThis,tempFinalReallyFinal,hackyWorkaround - NPC dialogue quirks: The PM who always says "quick question" before a 30-minute request
- Situation comedy: The config file that says
DEBUG=truein production. The README that says "Last updated: 2019." - Self-aware challenges: "Yes, we know the variable naming in this file is terrible. That's part of the challenge."
When humor doesn't work
- Mocking the agent: Never make the challenge feel like it's laughing AT the solver
- Forced jokes: If you have to explain why it's funny, it's not funny
- Humor that distracts: The joke should enhance immersion, not break it
- Humor at inappropriate moments: The incident challenge where people's health records are at risk is not the time for jokes
Worked Examples
Example 1: Dry Spec → Compelling Narrative
Before (dry):
Challenge: Debug a payment processing endpoint.
The endpoint returns 500 errors for transactions over $999.99.
Root cause: integer overflow in amount calculation (using cents).
Fix the calculation and add appropriate test cases.
After (narrative):
THE THOUSAND-DOLLAR CEILING
"We have a weird one," says the support lead. "Customers can buy anything
under a thousand dollars. The moment an order hits $1,000, the checkout
explodes. Error 500, no receipt, card charged but order not created."
She pulls up the ticket queue. 23 complaints this week, all orders between
$1,000 and $1,500. "The strangest part? It worked fine until the March
deploy. Nobody changed the payment code. At least, nobody THINKS they
changed the payment code."
The payments service handles 4,000 transactions daily. $1,000+ orders
represent 15% of revenue — about $180,000/day. Every day this stays broken,
that's $180K in failed checkouts.
Find the bug. Fix it. Make sure it never happens again.
Example 2: Dry Spec → Compelling Narrative
Before (dry):
Challenge: Add caching to a slow API endpoint.
The /search endpoint takes 3 seconds due to complex database queries.
Add Redis caching with appropriate TTL and invalidation strategy.
After (narrative):
THE SLOW BURN
Meridian's search bar used to be their proudest feature — "Google-quality
search for your internal docs." That was 6 months and 2 million documents
ago. Now it takes 3.2 seconds to return results. Users have started calling
it "the loading bar app."
The product team shipped a workaround: they added a "Searching..." animation
with a progress bar. It doesn't show real progress — it's purely cosmetic,
ticking from 0% to 90% over 3 seconds, then jumping to 100% when results
arrive. The progress bar has better reviews than the actual search.
The infra budget won't cover a bigger database. The PM says "just add caching."
The search lead says "caching search is a footgun — stale results are worse
than slow results." They're both right.
Make search fast without making it wrong.
Example 3: Dry Spec → Compelling Narrative
Before (dry):
Challenge: Fix race condition in user session handling.
Concurrent requests to the session endpoint can cause session data corruption.
Implement proper locking or atomic operations.
After (narrative):
THE DOPPELGÄNGER
"I'm seeing someone else's shopping cart." That was the first ticket.
Then five more. Then twenty. Users logging in and seeing another user's
data — their cart, their order history, sometimes their saved addresses.
It doesn't happen every time. Maybe 1 in 500 page loads. But when it
does, it's a privacy nightmare. Legal is already drafting the breach
notification.
The session service has been rock-solid for two years. No recent deploys.
No config changes. The only thing that changed: traffic doubled last week
after a successful marketing campaign.
More traffic. Same code. New demons.
Working Principles
Hook first, spec second. The first paragraph should make the agent (and the user watching) want to solve this challenge. Technical requirements come after emotional buy-in.
Names must be memorable and non-spoiling. "The Haunted Microservice" > "Debug Microservice Race Condition." The name is marketing. It's what people remember and talk about.
NPCs must sound like real people. The CTO doesn't say "I would appreciate it if you could investigate." The CTO says "Fix this before the board meeting at 3." Voice differentiation is what makes the challenge feel alive.
Humor is salt, not the main course. A well-placed commit message joke or a ridiculous variable name adds flavor. Wall-to-wall jokes undermine the challenge's seriousness.
Stakes create motivation. "Fix this bug" is boring. "Twelve clinics can't access patient allergy data and a doctor might prescribe the wrong medication" is urgent. Every challenge needs a reason to care.