Grimoire · Solo design + build · 2026
An AI-native deck builder for Magic: The Gathering. Shipped to production solo in 15 days.
A collection manager and deck coach that stands on parity with Moxfield and Archidekt, and wins on one wedge: an AI coach that builds a legal Commander deck from the cards you already own. Live at grimoirestudy.com.
The system
A coach with tools, not a chat window
The Deck Coach is not a prompt wrapped in a textarea. It's an agentic tool loop: the model interviews you about intent, then works through up to sixteen tool steps — searching real card data, checking format legality, reading your collection, pulling commander statistics from EDHREC, finding combo lines, searching the web for recent meta shifts — before a single card is committed. The save itself is a tool call: idempotent, legality-checked, and owned-aware.
Intent interview → tool loop (searchCards · checkLegality · lookupCollection · commanderResearch · findCombos · web search) → saveDeck (legal, idempotent, owned-aware) → readiness score + buy list
The detail that defines the product
When the Coach saves a deck, it doesn't save a generic card reference. resolveOwnedPrinting resolves each card to the most valuable printing you actually own — your foil, your special-art version — and falls back to a standard printing only for cards you still need. Every other builder saves an abstract list; Grimoire saves your deck, then hands you the buy list for the gap.
Cost is a design constraint
An AI feature that loses money per use isn't a feature, it's a countdown. The Coach runs on Sonnet (roughly $0.30–0.50 per full deck build); Opus is reserved for the heavy analysis surfaces where depth is the point. Credits are enforced atomically — a conditional UPDATE … WHERE balance ≥ cost, no check-then-spend race — under a hard cap of about $3 per user per month, and a build is only charged when it completes. A failed generation is free.
The hard part: a local copy of every card ever printed
Resolving imports against Scryfall's live API got rate-limited and silently dropped cards. The obvious fix — parse Scryfall's bulk data file — crashes Node outright: the JSON is ~530 MB, past V8's maximum string length. The fix that shipped streams the download to disk, then stream-parses the array one object at a time with a hand-written brace-depth scanner (memory stays flat regardless of file size) and batch-upserts 500 rows at a time, idempotently. A 2,700-card collection import went from per-card API resolution — where rate limits silently dropped cards — plus ~13,500 row-by-row database writes that stalled around row 900, to a handful of batched local queries. Imports now resolve entirely against Grimoire's own catalogue.
Transferable: the pattern — constrain the model with real-data tools and make the save a validated, idempotent operation — applies anywhere "plausible" isn't "correct": config generation, compliance tooling, catalog and pricing surfaces, agent builders.
The problem
Deck-first tools ignore the shoebox
Commander is Magic's most popular format: 100 unique cards, color-identity rules, a power-bracket system, and a secondary market where a single list can price out at four figures. The established tools serve players who already know what they're building. Nobody starts from the other end — the pile of cards you actually own.
Competitive gap
| Tool | Strength | Why it falls short |
|---|---|---|
| Moxfield | The default deck database; deep format support | Deck-first. Collection is an afterthought; nothing builds for you |
| Archidekt | Visual builder, rich categorization | Same deck-first assumption; steep for newer brewers |
| EDHREC | Meta statistics for every commander | Recommendations, not a finished legal deck; blind to your cards |
| TCGplayer / Card Kingdom | Pricing and purchase | No bridge from "what I own" to "what this deck needs" |
The scope call that made 15 days possible: match Moxfield's depth where it's table stakes; don't try to out-build it. Deck CRUD, collection tracking, pricing, sharing, and a playtest engine are parity features, built to be credible rather than superior. The innovation budget went entirely to the one job nobody does: collection → coached deck → buy list.
Four decisions that drove the design
The non-negotiables
Collection-first, not value-first
The tempting home screen is "your collection is worth $3,936" — a number that flatters and goes nowhere. I rejected the portfolio-tracker framing; value is a secondary lens. The home surface leads with what your cards can do: decks you can build, decks that are close, what's missing.
Your most valuable printing, not a generic one
The alternative every competitor ships — resolve saved cards to a default or cheapest printing — is simpler and wrong. The deck you sleeve is made of the cards you own. resolveOwnedPrinting was more work at save-time and it's the difference between a list and your list.
Sonnet by default, Opus where it earns it
Everything-on-Opus tested better on nuance and would have made every free build a loss. The Coach runs on Sonnet; Opus is reserved for deck analysis and collection insights, where users read the output slowly. Unit economics were designed with the feature, not retrofitted after launch.
Card images bypass the image optimizer — deliberately
Card art is the most-rendered asset in the product, and routing it through a metered optimization service means one viral day makes every card in production go blank when the quota exhausts. Images ship unoptimized, straight from Scryfall's CDN. Less elegant on paper; strictly fewer ways to fail.
One consequence worth stating plainly: the fastest path to value needs no account — the landing page renders featured decks at zero clicks, and a full read-only deck is one click away — but deck building itself is auth-gated. That's a deliberate trade: every Coach run costs real money, so the free tier is metered per-account rather than open to anonymous traffic.
Failure modes
What happens when the model — or the upstream — is wrong
A product built on someone else's card database and a probabilistic model needs explicit answers for the days both misbehave:
| Failure | What the system does | Why |
|---|---|---|
| Scryfall down or rate-limiting | Exponential backoff honoring Retry-After, per-chunk failure isolation, local-catalogue fallback | A 2,700-card import shouldn't die because request 1,900 hit a 429 |
| Coach saves a 99-card "Commander deck" | Legality engine names the exact issue; the Coach self-corrects to exactly 100 | One-card-short was the most common model failure in testing |
| Card image fails to load | Cascade: primary URI → Scryfall by-ID redirect → text box with the card name | A deck page never renders blank |
| Search finds nothing | Explicit empty state with the query echoed and a loosen-the-filters nudge | Dead ends need exits, not blank grids |
| Generation fails mid-build | Credits are charged only on successful completion | A failed build is free; atomic gating means no double-spend race either |
What's deliberately imperfect: if the credit-metering table itself errors, the gate fails open and generation proceeds unmetered. A billing bug must never lock users out of the product; the cost of that stance is that a database hiccup means free AI until it heals. I'd make the same call again — and it belongs in the documentation, not hidden in a catch block.
What's not handled yet, stated plainly: connection loss mid-edit (ordinary edits are plain server actions — no offline queue, no optimistic draft; only the multiplayer playtest reconnects gracefully) and rate limiting / bot protection, which don't exist anywhere in the app yet. Both are known, neither is invisible.
Distribution
The go-to-market is part of the build
A deck builder with no players is a database. Unlike my other projects, Grimoire shipped with its distribution mechanics in the codebase from week one:
- A referral ladder, not a referral link. Double-sided credit rewards, with named milestones — Advocate at 3 referrals, Champion at 5, Legend at 10 — so sharing has a progression, not just a coupon.
- Zero-touch creator onboarding. Comped Pro is an allowlist applied automatically at sign-in. Onboarding an influencer is adding one line to an environment variable — no admin panel, no manual grants, no waiting.
- Every public deck is a landing page. Shared decks render read-only with no account, carry a "Build your own" call to action, and are enumerated in the sitemap for search.
I'm actively working with Magic promoters and content creators on launch content now — that's the live experiment, and it's why the honest line up top says distribution is the open bet.
The gap I'd close first: per-deck social preview images and embeds don't exist yet, so a shared deck link renders a generic card in Discord and Twitter — and Discord is where Commander players live. For a share-driven growth loop, that's the highest-leverage missing piece, and it's at the top of the roadmap.
Reflection
What worked, what I'd do differently, when this approach is wrong
What worked
- Parity-not-outbuild scoping. Deciding on day one which features only had to be credible freed the two weeks to be spent where the product is actually different. This is the same altitude call I make in team settings; the solo build just makes it visible.
- AI-assisted velocity, human architecture. 66,761 lines in 15 days is Claude Code doing the typing. The calls that made the product work — the streaming ingest parser, the atomic credit gate, owned-printing resolution — came from debugging real failures, not from generation.
- Cost design as product design. Model tiering, hard caps, and charge-on-success were designed with the AI features, not bolted on after the first invoice. Ascend taught me that lesson in the other direction.
What I'd do differently
- Never ship a panel on stubbed data. The vendor-pricing providers (TCGplayer, Card Kingdom) are stubs, which means a "best place to sell" panel currently runs on fabricated numbers. It should have been feature-flagged off until the integrations were real. That's the first thing I'd fix, and it's the weakest part of the product today.
- Tests where the money is. Twelve test files in a codebase this size is thin everywhere, but the credit-limit and deck-save paths — the revenue-critical ones — are the inexcusable gaps.
- Reconcile estimates against reality. The internal AI-cost dashboard is an estimate that doesn't yet reconcile to the actual Anthropic bill. An estimate that's never checked is a guess with a UI.
- Email before launch, not after. Transactional email is still a console-log stub, which blocks password resets and any lifecycle messaging. Fine for an invite beta; not fine one week after it.
When I wouldn't ship this approach
The 15-day parity-plus-wedge sprint works when the incumbents' feature set is well-understood, the underlying data is public commodity (Scryfall is a gift), and the wedge is genuinely orthogonal to what they do. It's the wrong play when correctness is the product: Grimoire's own Rules Judge shows the edge of it — without retrieval over the actual Comprehensive Rules it gives good answers, not judge-grade ones, and I say so in the roadmap rather than in the marketing.
Next on the roadmap: per-deck social previews, the deck-page redesign, retrieval-grounded rules answers, camera-based card scanning for collection intake — and the long game: Grimoire's own playtest win-rate data feeding the Coach, which is the moat none of the incumbents can copy from a card database.
Status
On Grimoire
Grimoire is portfolio work and a real product: live in production, customer-facing, with a paid tier and a creator program mid-launch. It exists to test a wedge hypothesis and to demonstrate what solo designer-developer velocity looks like with current tools — strategy, design, code, and go-to-market from one seat, in 15 days.
I maintain it on my own time and in small windows. I'm available for full-time senior, staff, or lead IC work. Grimoire does not compete with that.