Narrative Development
Traditional “AI-assisted development” in 2025 looks like waterfall with extra steps: write a 50-page PRD, engineer the perfect context, pray the AI understands, debug when it doesn’t. We’re spending more time writing ABOUT code than writing code.
What if we flipped it? What if we wrote the STORY first, and let the contracts emerge from the narrative?
The Problem with Context Engineering
A lot of the Koru language design is driven by conversations with AI. Bouncing ideas off each other leads to better solutions - we explore ideas quickly and iterate on them, following the mantra of “fail often, fail loudly, and fast”.
But Koru is designed to be the antithesis of traditional AI development that relies heavily on “context engineering” - front-loading massive documentation into a pre-code phase, making the whole thing look more like traditional waterfall development than something that belongs in 2025.
In our discussions about this problem, we discovered something better: narrative-driven development.
Programming by Storytelling
Here’s what narrative development looks like in practice. Let’s build a simple image editor - not by writing specs, but by telling a story:
OH MY GOD YES! This is narrative-driven development - you write the STORY FIRST, then extract the contracts, then fill in the implementations!
Phase 1: Sketch the Happy Path
Events don’t even exist yet - just write the story:
~load_image(path: "photo.jpg")
| loaded img |> apply_brightness(image: img.data, amount: 1.5)
| adjusted a |> apply_blur(image: a.result, radius: 5)
| processed p |> save_image(data: p.result, path: "output.jpg")
| saved |> _ Compiler says: “3 undefined events. Generate stubs?”
The IDE visualization shows a flow graph with red nodes (missing events).
Phase 2: Define Event Shapes
The compiler KNOWS you used img.data, so it suggests:
~event load_image { path: []const u8 }
| loaded { data: ImageData } // ← Extracted from flow usage!
| not_found { } // ← Added for robustness
| corrupt { }
~event apply_brightness { image: ImageData, amount: f32 }
| adjusted { result: ImageData } // ← From 'a.result' in flow
| invalid_amount { }
~event apply_blur { image: ImageData, radius: u32 }
| processed { result: ImageData } // ← From 'p.result'
| invalid_radius { }
~event save_image { data: ImageData, path: []const u8 }
| saved { }
| write_error { message: []const u8 } Compiler now says:
- ⚠️ Flow doesn’t handle ‘not_found’ branch
- ⚠️ Flow doesn’t handle ‘corrupt’ branch
- ⚠️ … (6 more unhandled branches)
- ❌ No procs implemented
Phase 3: Handle All Branches
Add error flows:
~load_image(path: "photo.jpg")
| loaded img |> apply_brightness(image: img.data, amount: 1.5)
| adjusted a |> apply_blur(image: a.result, radius: 5)
| processed p |> save_image(data: p.result, path: "output.jpg")
| saved |> log("Success!")
| write_error e |> log(e.message)
| invalid_radius |> log("Invalid blur radius")
| invalid_amount |> log("Invalid brightness")
| not_found |> log("Image not found")
| corrupt |> log("Image corrupted") Now compiler says:
- ✅ All branches handled
- ❌ Missing proc implementations (5 procs needed)
Phase 4: Stub the Procs
Make it compile:
~proc load_image {
// TODO: Actually load image
return .{ .not_found = .{} }; // Stub with error
}
~proc apply_brightness {
// TODO: Implement brightness adjustment
return .{ .adjusted = .{ .result = image } }; // Passthrough stub
}
// ... etc Compiler says:
- ✅ Compiles!
- ⚠️ 5 procs are stubs
- 💡 AI: “Want me to implement load_image? I see you need PNG/JPEG decoding.”
Phase 5: Implement One Proc at a Time
~proc load_image {
const file = std.fs.cwd().openFile(path, .{}) catch {
return .{ .not_found = .{} };
};
defer file.close();
const data = file.readToEndAlloc(allocator, 10_000_000) catch {
return .{ .corrupt = .{} };
};
const image = ImageData.decode(data) catch {
return .{ .corrupt = .{} };
};
return .{ .loaded = .{ .data = image } };
} Compiler says:
- ✅ load_image implemented!
- ⚠️ 4 procs still stubbed
- 🎯 Run tests: load_image works, rest are stubs
The IDE Should Support This!
Koru Studio needs these views:
Flow Canvas (CENTER, 50%) - Where you sketch the narrative
- Type flows even with undefined events
- Red nodes = missing events
- Yellow nodes = missing procs
- Green nodes = fully implemented
Event Explorer (LEFT, 20%) - Generated from flow usage
- Shows which events are referenced
- Click to define/refine event shape
- Shows branch coverage status
Implementation Tracker (RIGHT, 30%)
- Lists missing procs/subflows
- Shows stub vs. real implementations
- AI can generate implementations here
AI Copilot (BOTTOM) - Guides through phases
- “I see you referenced apply_blur. Want me to define its event shape?”
- “You’re not handling the corrupt branch. Add error handling?”
- “The load_image proc is stubbed. Want me to implement PNG decoding?”
This changes EVERYTHING about the IDE!
The parser needs to:
- ✅ Parse incomplete programs (undefined events OK!)
- ✅ Extract event usage from flows (what fields are accessed?)
- ✅ Suggest event shapes based on usage
- ✅ Track implementation status (stub vs. real)
- ✅ Show branch coverage even with stubs
This is the killer feature - programming by narrative!
What Just Happened?
Notice something profound here? We never wrote a requirements document. We never “engineered context.” We just told a story, and the compiler helped us make it real.
The AI didn’t need perfect specifications - it needed to see the NARRATIVE. When you write img.data, the AI knows you need an ImageData type. When you handle | corrupt |>, it knows you’re thinking about error cases.
This isn’t prompt engineering. It’s storytelling.
Narrative Development in Practice
This philosophy isn’t theoretical - it’s how we build Koru itself.
For example, we recently added full-program profiling through a simple conversation: “What if importing the profiler automatically instrumented everything?” Two hours later, we had ~[profile]import "$std/profiler" - one line that profiles your entire program with nanosecond precision.
The feature emerged from dialogue, not from a 20-page RFC about “Profiling Infrastructure Requirements”.
The IDE as Narrative Guide
Traditional IDEs show you a file tree and a text editor. Koru Studio shows you the STORY.
The IDE needs to support this narrative workflow with purpose-built views:
Flow Canvas (CENTER) - Where you sketch the narrative
- Type flows even with undefined events
- Red nodes = missing events
- Yellow nodes = missing procs
- Green nodes = fully implemented
Event Explorer (LEFT) - Generated from flow usage
- Shows which events are referenced
- Click to define/refine event shape
- Shows branch coverage status
Implementation Tracker (RIGHT) - Tracks completion
- Lists missing procs/subflows
- Shows stub vs. real implementations
- AI can generate implementations here
AI Copilot (BOTTOM) - Guides through phases
- “I see you referenced apply_blur. Want me to define its event shape?”
- “You’re not handling the corrupt branch. Add error handling?”
- “The load_image proc is stubbed. Want me to implement PNG decoding?”
The compiler becomes your co-author, helping you transform narrative into runnable code.
From Waterfall to Watershed
We’ve spent years trying to make AI understand our documentation. What if the problem isn’t that AI doesn’t understand - it’s that documentation isn’t how humans actually think?
We think in stories. We dream in narratives. We explain ideas by painting pictures with words.
Narrative development isn’t about writing better prompts. It’s about building software the way humans naturally communicate - through stories that unfold, evolve, and come to life.
The future of development isn’t better context engineering. It’s better storytelling.