Donavyn Haley

Software engineer in Portland. Co-founder and CTO of FITREPS, where I've spent three years building a creator platform on AWS. Currently at Capital One through TEKsystems.

I tend to build the whole thing: the services, the infrastructure they run on, the tests that gate them, and whatever tooling was missing.

Architecture through delivery

I owned the architecture for FITREPS, a fitness creator platform, including infrastructure, CI, and the test platform. I built billing end to end while my co-founder Alan focused primarily on the frontend and content creation.

fr creator dashboard
img/fr-creator-dashboard
Creator dashboard.

Choosing a database that supported iteration

FITREPS started on DynamoDB while we were still discovering how the application needed to query its data. Workout programs connected to workouts, exercises, and reusable exercise templates. Comments, likes, and bookmarks added relationships between users and content.

As those requirements evolved, the data layer became increasingly difficult to reason about. I moved the relational data to Aurora PostgreSQL so we could adapt queries more easily and iterate faster. I made the transition before launch, migrating the existing development users and their data.

Building billing around failure and recovery

I built the Stripe integration, creator onboarding through Stripe Connect, subscriptions, and the surrounding refund and payout flows. The hardest part was handling failed payments, delayed events, and repeated webhook deliveries correctly.

Subscription processing protects against duplicate events and supports retries. Successful checkout also updates subscription state directly, so access does not depend solely on a webhook arriving. Refund and payout handling includes explicit ledger adjustments and state transitions.

I tested billing end to end using Stripe test mode, with additional webhook and data-layer tests covering repeated events, refunds, and payout failures.

Making releases repeatable and recoverable

I built delivery checks alongside the application. Pull requests run lint, type checks, unit tests, application builds, infrastructure synthesis, and local platform integration tests. The local API runs the same Lambda handlers as AWS.

Development deployments update the backend before building the frontends, then run smoke tests followed by regression tests. Parallel test runs use separate users and server ports to avoid interfering with one another.

Production releases require a deliberate trigger and take a database snapshot before migrations. After deployment, read-only smoke checks verify the live system without creating test users or payment activity.

fr playwright
img/fr-playwright
A smoke pass of the suite, run locally against the dockerised stack.
fr training builder
img/fr-training-builder
Training program builder — multi-step product engineering over a complex domain.
Capuchin run dashboard
img/mc-runs
Starting a run: coding, PR review, or fix findings.

The pipeline

Linked-intent planning

A plan breaks into tasks that stay linked to the requirement that produced them, so a coder working one slice can see why it exists.

Parallel coders, isolated worktrees

Every coder gets its own git worktree, so several can work the same repo at once without stepping on each other.

Specs on disk, not in context

Requirements are EARS statements with semantic IDs. The spec tree carries the design across a run, not any one agent's context window.

The reviewer looks at the app, not the diff

It boots the application and drives Chrome over the DevTools Protocol, capturing the same routes at three breakpoints every round.

A critic before, a reviewer after

A planning critic reviews the plan before anyone writes code. An integration reviewer checks the merged result, because per-task reviewers structurally cannot see the seams between tasks.

TDD mode

Writes the failing test first and treats going green as the gate.

Capuchin agent pipeline
img/mc-pipeline
A cross-lab PR review: six gates, every reviewer timed and costed — $25.94 and 35.9M tokens, accounted for.

Running it

One engine, two frontends

A CLI and a desktop cockpit share a backend, so a run started in the terminal is still watchable in the UI.

Provider-neutral routing

Two vendor CLIs behind one interface, failing over on typed session, quota and rate-limit errors instead of string-matching an exit code.

Deny-by-default sandboxing

Delegated to the providers' own hardened sandboxes. I didn't want harness code pretending to be a security boundary.

Replay

Every stage hand-off is written to disk as JSON, so a run can be replayed and a resumed run starts from the longest unchanged prefix instead of the beginning.

Eight role cards

Planner, developer, reviewer, tester, curator, finalizer, pr-reviewer, improver — each a prompt contract rather than hardcoded behavior.

The loop closes on itself

Friction from every run — bounced reviews, failed gates, retried tool calls — feeds an improver that proposes changes to the harness and to its own role prompts.

Capuchin agent roles
img/mc-roles
Role cards.
Capuchin provider usage
img/mc-usage
Two providers, one meter.

One loop, not three tools

Its knowledge lives in a vault that renders as a navigable 3D graph, and work comes in from Grimoire, further down this page. A daily brief reads what's happening across the ecosystem and marks each item adopt, watch or ignore against the principles the project already committed to.

I wanted something that told me how it failed, not just what it produced.

img/mc-vault-graph
The vault as a 3D graph — orbit it, click a node, and the note opens.
What was actually hard

Not prompting. It was context-window economics, meaning what goes in, when to summarize, and what survives across sessions. Tool-call reliability and all the ways a call fails partway through. And getting a nondeterministic worker to behave the same way twice inside a pipeline that has to be repeatable. None of those are new problems. They just show up somewhere people don't expect to find them.

Less bookkeeping, more building

I built Grimoire after using Notion to manage development through a sprint board. I wanted less effort spent organizing documents and maintaining the system around the work. The goal was a small, focused board that reflected where each project actually stood.

img/gr-board
The board - dragging work into in progress.

Markdown first

Pages and ideas are ordinary Markdown files on disk. Read them outside the app, keep them in an Obsidian vault, or track them in Git. Accounts, discussions and project settings live in SQLite; backing up the data directory preserves both.

Ideas sit in a separate garden until someone commits to one, so a maybe doesn't quietly turn into committed work.

Keeping current work visible and accurate

I separated possible ideas, accepted backlog, and active work so they would not all compete for attention on the same board. Each project uses only the categories, fields, and optional chapters it needs.

Keeping that view accurate takes both a straightforward interface and integration with the work itself. People can update status directly, agents can report progress through project-scoped tools, and linked GitHub pull requests move pages into Review when opened and Done when merged.

Those paths reduce the separate bookkeeping needed to keep the board useful. Whether I move a page myself or an integration updates it, the goal is the same: return to a project and understand where it stands.

Making it easier to return to a project

I use Grimoire across four projects. Keeping each project's thoughts, work, and discussions together reduces the effort of switching between them.

The board gives me the current state, while individual pages hold the context behind the work. Discussions and activity history help preserve decisions across handoffs, and the away digest shows what changed while I was elsewhere.

Letting agents contribute without taking over

Agents can read and update work through project-scoped credentials. Their changes remain attributed to the person who delegated them, and their access can be revoked.

I kept destructive actions and project restructuring under human control. Agents can report progress and raise questions, but a person decides when a discussion is settled. That keeps the board useful as a shared record without giving an agent authority over how the project is organized.

Project agent credentials and their permitted actions
img/gr-agent-access
Agent tokens, and what a token can never do.
Chapter closing dialog with choices for unfinished work
img/gr-chapter-close
Closing a chapter.
Activity digest showing changes since the last visit
img/gr-digest
Back after a day away: the digest, every write attributed - including the agent's.

Shipping it

The app is open source under AGPL-3.0 and runs on your own infrastructure with Docker Compose. The MCP client is published separately under MIT.

Try the editable demo without an account, or follow the self-hosting guide to run your own board.

Grimoire project pages stored as Markdown files
img/gr-markdown-proof
The same project as the board draws it, and as it sits on disk.