enable AI's Full Potential with OTF Kits: Consistent, Reliable Code for Production-Ready Apps
The agent wave is real. Cursor autocompletes a form by the time you've typed the label. Claude Code refactors a 4,000-line file while you grab coffee. Lovable and Bolt turn a Thursday-morning sketch into a working app before lunch. The throughput enable is genuine — for the first time, the gap between "idea" and "running prototype" is measured in minutes, not weeks.
The bottleneck moved. It's not prompt quality anymore. It's what the agent is building on top of.
Here's the pattern I keep seeing in codebases that ship and codebases that don't: the ones that ship hand the agent a contract. The ones that don't hand it a blank file and ask it to invent the design system from scratch. Same agent, same prompt, wildly different outcomes.
The contract is the kit. The kit is the difference.
1. What "AI-configured" actually means
A kit that respects agents isn't a fancy component library. It's three things, and the third one is the one most people skip.
First: the components themselves. Type-safe props, predictable behavior, around 200 of them covering the cases an agent actually reaches for — Button, Dialog, DataTable, FormField, Sheet, Toast. The same <Button variant="primary" size="md"> renders on web, iOS, and Android from one codebase. No "well, on mobile we use…" branches in the prompt.
Second: design tokens. Colors, spacing, radii, typography — one source of truth that flips a theme across every platform. An agent that pulls a token can't drift off-brand because there is no off-brand to drift into.
Third, and the load-bearing one: agent configs. CLAUDE.md, .cursorrules, and a directory of tested prompts that tell the agent here's the kit, here are its conventions, extend it — don't regenerate it.
# Inside a kit, after install
ls -la
# CLAUDE.md ← read first, sets the contract
# .cursorrules ← Cursor's entry point
# ai/
# prompts/ ← 20+ tested prompts, named by intent
# README.mdThat ai/ directory is the thing. It converts the agent from a generator into an extender.
2. The Button test
Take any modern AI coding tool. Ask it three times, in three fresh sessions, to "add a primary button to the pricing page".
Session A writes a button with bg-blue-600. Session B writes one with bg-indigo-500 hover:bg-indigo-600. Session C writes one with a custom focus ring that breaks the keyboard outline. Same prompt. Same model. Three different design systems.
Now point the same agent at a kit with CLAUDE.md and the right prompt:
<!-- ai/prompts/add-primary-button.md -->
You are extending an existing UI kit, not generating from scratch.
1. Read /CLAUDE.md to understand the component conventions.
2. The primary button is already exported as `<Button variant="primary" size="md">`.
3. Import from the kit; do not re-implement.
4. Match the existing spacing tokens on the pricing page.
5. Return the diff, not a rewrite.Same agent, same model, three sessions. You get three Buttons that look identical, behave identically, and pass the same a11y checks — because the agent isn't deciding what a Button is. The kit already decided.

11 production screens. Login, database, payments — all wired.
The SaaS Dashboard Kit ships everything already connected. Nothing to set up. Live demo at saas.otf-kit.dev.
3. Pre-tested beats regenerated
Every kit ships through a 24-item design checklist before it's released. Color contrast, focus rings, touch targets, keyboard navigation, RTL handling, dark-mode parity, token coverage. Regenerated components skip every one of those checks until something breaks in production.
The test isn't "does it compile". It's "does it survive a screen reader on a 4-year-old Android". You can't ship that test in a prompt. You can ship it in a kit.
4. What the configs actually look like
Here's the entry point an agent reads first. This is the contract.
<!-- CLAUDE.md (excerpt) -->
# Project UI Contract
This project uses the OTF UI kit. Components live in `@otfdashkit/ui` (web)
and `@otfdashkit/ui-native` (mobile). The same component name and props
render on both.
## When adding UI
- Import from the kit. Never re-implement `Button`, `Input`, `Dialog`,
`Card`, `Sheet`, `Toast`, or `DataTable`.
- Pull colors, spacing, and radii from `@otfdashkit/tokens`. Do not hardcode
hex values or pixel sizes.
- New components must compose existing primitives. They do not redefine
them.
- Every interactive element must pass keyboard navigation. Tab order
matches visual order.
## When refactoring
- Do not rename exported components.
- Do not change a prop's type without updating the kit first.
- Mobile parity: a change on web must not regress the iOS/Android build.The agent reads that, then reads .cursorrules, then reads the prompt that matches the task. The three layers are redundant on purpose. Drop any one and the agent drifts. Keep all three and it stays in the lane.
5. When the agent needs to add something the kit doesn't have
The interesting case is composition. The kit has Card. It doesn't have PricingCard. Here's what an ungrounded agent writes:
// Before — regenerated, drifts over time
function PricingCard({ tier, price }: { tier: string; price: number }) {
return (
<div className="rounded-lg border p-6 shadow-sm">
<h3 className="text-xl font-semibold">{tier}</h3>
<p className="text-3xl">${price}/mo</p>
{/* ... */}
</div>
);
}Hardcoded radii, hardcoded padding, hardcoded typography, hardcoded shadow. Every one of those will drift from the rest of the app by next sprint.
The kit-aware version:
// After — kit-extended, composes primitives
import { Card, CardHeader, CardTitle, CardBody } from "@otfdashkit/ui";
import { tokens } from "@otfdashkit/tokens";
export function PricingCard({ tier, price }: { tier: string; price: number }) {
return (
<Card>
<CardHeader>
<CardTitle>{tier}</CardTitle>
</CardHeader>
<CardBody>
<p style={{ font: tokens.heading }}>${price}/mo</p>
</CardBody>
</Card>
);
}Same shape. Same intent. No hardcoded values. The card inherits every a11y check, every dark-mode rule, every focus ring the kit already passed.

6. The number that matters
The cost of agent drift isn't the first wrong Button. It's the fifteenth. Each one is a small "why does this look different from the others?" bug that lands in code review, gets fixed with a one-line token swap, and erodes trust in the next agent output. By Friday the team's writing the UI by hand again because "the agent doesn't get it".
A kit that an agent extends — with configs, tokens, and pre-tested components — collapses that loop. The agent's first output is the right output, because the contract decided before the agent started.
7. The durable layer underneath the churn
Cursor will ship a new model. Claude Code will ship a new workflow. Lovable will ship a new builder. The list of agent tools that come and go is longer than the list of design systems that come and go, by an order of magnitude.
The kit is the part that doesn't churn. Same <Button>, same tokens, same CLAUDE.md, regardless of which model wrote which file. That's the layer worth investing in.
Use the agent — all of them, they're genuinely good now. And hand it a contract it can extend instead of a blank file it has to invent.
Ship the product, not the setup.
- 11 production screens — auth, billing, team, analytics, settings
- Real database, payments, and login — all wired on day 1
- AI configs pre-tuned so your agent extends instead of regenerates