Project · #06

Storymap

Backlog management made easy for both me and Claude.

ProductWorkspace opsStory mappingFull-stackCloudflare WorkersGitHub App
View live

A backlog tool for two readers

I wanted a backlog management tool optimised for both me and Claude Code. I had a .md backlog file for each project, but they were mostly for Claude’s benefit. They weren’t visual, or easy for me to navigate and find things in. What I needed was a tool that was easy for me to use, but that was also integrated into my Claude Code workflow.

A left-to-right flow. On the left, two writers: Me and Claude Code. Each feeds into a tool: Me through the storymap UI, Claude Code through a backlog skill. Both tools converge on a single highlighted schema-validation step, which then writes to one markdown source of truth on the right. Dashed return arrows along the top and bottom show both writers also read the same files.

Losing the thread

The trigger was starting to have more and more small projects, and forgetting where I was up to, what was done, and what wasn’t. I wanted to introduce a work tracking tool to keep track of what I’ve done, what I’m working on, and what I want to do in the future across all my projects.

I also love storymaps as a way of visualising work to be done, in a way that’s fundamentally structured around the customer experience, with clear goals for each release. So I decided to move to a storymap-first work management tool. It only had to work for me, so I didn’t need the complexity of other tools out there.

I looked at Jira. It has a free plan that would have worked for my usage, and a great MCP integration, but it doesn’t support storymaps out of the box. It’s focused on traditional list-based backlogs, and doesn’t support storymaps without paid third-party plugins. I looked at other storymap-first tools, but none of them had a product with strong LLM integration and a generous free tier.

What are story maps?

The structure of a story map. Across the top, a left-to-right user journey of activities: Capture, Organise, Plan, Review. Below each activity, columns of task cards. Three horizontal release slices stack top to bottom by priority: Release 1 (See all my work in one place), Release 2 (Plan releases by priority), and a dashed Release 3 (Edit from Claude Code).

User story maps are a two-dimensional product backlog, pioneered by Jeff Patton. The vertical slices of a story map break down the user journey into high-level activities, and more granular tasks within them. Horizontal slices in a story map are product goals, organised with the highest priority at the top. They’re a fantastic way to hone down the scope of an MVP by staying laser-focused on what’s truly required across the user journey to meet the goal. The visualness of the map also often helps highlight gaps early on, and builds understanding of the end-to-end product in a way that a traditional flat backlog doesn’t.

What I built

Live storymap grid (screenshot to add)
Capture from storymap.dylanmagorhampel.com

I use storymap several times a day now, for two main things. First, when I have an idea for something to change in one of my apps, I can quickly open it and add the new change to the backlog in 30 seconds. Second, when I get an hour or two to sit down and work on my projects, I open storymap to orient myself on what’s still in flight to finish, and what are the top things to start next.

Markdown as a backend

As I was thinking through the architecture of storymap, I explored different data models, including various databases. They would have been much better in some ways, such as load speed in the UI and strictly enforcing a schema at the DB layer. But using a traditional database would have meant a whole lot of extra overhead building an MCP server, or some other mechanism for Claude Code to read and modify the backlog. I decided to look at what I do now as an alternative approach: markdown files in a GitHub repo. It’s proven to work well with Claude Code, but due to the lack of schema enforcement, because they’re effectively just text files, it creates additional challenges integrating reliably into a human-usable UI.

---
id: GM0kBMSueU
title: Short reference ID
status: open
task: XEKP2D7Iau
slice: 1_tUzMWBkc
effort: S
---
Currently when I'm talking to Claude about backlog items I
have to explain what it is and Claude needs to hunt for it.
Add a short (just a few characters) reference ID to backlog
items so that I can just use the reference to match accurately

To solve the unstructured data problem, I added structure to it. I defined a schema for backlog items, and wrote a schema validation script to pick up any discrepancies. Then I implemented a backlog skill in Claude Code, used for all interactions with my storymap-based backlogs. The schema validation script runs as part of the backlog skill, and the same script runs when saving backlog changes from the storymap UI. I’ve captured all edit points, so the storymap schema stays reliably enforced. Yes, I could go and manually commit changes that go outside of the schema. But it’s just me using this repo, so I know not to do that. If it became a problem, I could also add the schema validation to the CI/CD pipelines so that it’s run on commits or merges. But it simply hasn’t been necessary yet.

Containing the blast radius

Using markdown files as my backend means any changes from the storymap UI need to get committed to my repo. The key question was: how do I make the level of repo access for storymap as fine-grained as possible, so that the blast radius of any issues or security gaps is capped at only the backlog files, and not everything else in the repo.

A vertical flowchart of the write path. A save from the storymap UI in the browser passes through Cloudflare Access at the edge (whitelisted emails, which issues a JWT), then into the Worker, labelled blast-radius containment. Inside the Worker, four stacked gates in sequence: JWT validation (verifies the signed token), a default-deny gate (writes are never public), a file whitelist (only storymap entity paths), and schema validation (frontmatter must match). The flow then reaches a scoped GitHub App (Contents-only, one repo) before the final highlighted step: commit to markdown in the repo.

I focused on three things. First, strong authentication for committing backlog edits. Second, a file whitelist in the Worker layer, to avoid any non-backlog files being written. Third, scoped GitHub App access, to limit what other actions are possible at all.

Making it feel right

The hardest thing to get right was to get the UI feeling right. While it looked OK at first, it took a lot of rounds of small improvements for it to feel how I wanted it to, especially for interactions like dragging a card to a different cell.

Dragging a card to a different cell (capture to add)

Worth building?

Storymap keeps the simplicity and LLM-readability of markdown files, while also putting them into a UI that helps me visualise the experience, think through opportunities, and make better decisions.

Building your own tool like this is worth it more and more often, as the effort to build functional software to solve specific tasks continues to decrease. I wouldn’t for anything mission-critical, but for productivity accelerators I use regularly, the benefits of building something exactly optimised for my personal workflow are compelling.