The design contract is AI's control surface

You don't get reliable AI-built apps by writing a better prompt. You get them by giving the agent less room to invent.
If that sounds backwards, think about how it actually goes. You vibe code a proof of concept, show something working, get the business excited. Then you spend the next week babysitting the AI to keep it from drifting, compromising because you're too far in to start over, hoping nothing breaks in production. The app is beautiful and about 80% correct. It's the last 20% that drives you mad. Why does this button behave differently on two screens? Why is the same data table styled two ways? Why can this user reach the admin view?
You've watched the videos, taken the courses, followed the frameworks. And the apps still feel like a gamble.
That's not a prompting problem. You've been optimizing the wrong thing.
A prompt is a one-time instruction. If it's ambiguous, the model fills the blank with its own taste. Better wording narrows the blank a little. It doesn't close it. What closes it is a standard that lives outside the model, one the agent has to build against every time, instead of guessing at once.
At the European Power Platform Conference 2026, Charles Sexton's session on design systems gave that standard a name that has stuck with me ever since: the design contract.
What a design contract actually is
A design contract is the single source of truth for how your app family should look and behave. Not a brand PDF. Not a Figma file that makers eyeball and reinterpret. A machine-readable contract that makers, reviewers, and AI agents can all read the same way.
Most design debt doesn't come from careless people. It comes from repeated local decisions. One team puts the primary action at the bottom. Another puts it in the top command bar. A third splits it by context. Each choice is defensible on its own. Across an app estate it becomes support tickets, training cost, rework, and confused users. Nobody was careless. There was just no shared source.
A design contract changes the question from "which button style do you prefer?" to "which approved pattern applies here?" That's a governance move, not a decorative one.
For the agentic era it has four parts.
1. Design tokens. Named values for the decisions you repeat: colour, type, spacing, radius, elevation. The point isn't that #2563EB exists. It's that the maker reaches for Color.Primary because the name carries the meaning. Tokens now have a shared, vendor-neutral format too — the Design Tokens Community Group published its first stable spec, 2025.10, in October 2025.[^design-tokens]
2. Brand assignments. These map the tokens to the brands, departments, or app families that use them. The same component serves different contexts without every app inventing its own styling.
3. Component anatomy. The parts of a component: slots, states, variants, what's required, what's optional, and what's allowed to change. A card isn't a rectangle with text. It has a title, metadata, status, an action area, and empty, loading, error, and maybe approval states.
4. Behavioural rules. The part people forget. When do you use a primary button? When does a destructive action need confirmation? What must an approval card show before someone clicks Approve? Which validation runs before submit? This is where a design system becomes a production system.
A weak contract leaves the interpretation to the model. A strong one takes away as much of the guessing as you can. It doesn't make the AI perfect — nothing does. It makes the work checkable.
A strong contract can beat a strong model
The tempting fix for bad AI output is always "use a better model." Sometimes that's right. Often it's lazy.
If your instruction is vague, the most expensive model still has to guess. If your contract is strict, a cheaper model can often do the job, because the hard decisions are already made. Don't take that as a law — test it in your own environment. But the direction holds: the more your standards live outside the model, the less you depend on the model's taste.
So when a generated screen comes out wrong, don't fix that one screen by hand and move on. Ask what the contract failed to specify. Then fix the contract. Now the correction is one move instead of twenty local edits, and every screen after it inherits the fix.
That's the difference between prompting and engineering.
The harness makes the agent follow the contract
The contract says what good output looks like. It doesn't make the agent work a particular way. That's the harness.
A harness is the set of standing instructions and checks the agent works inside: where the contract lives, which component kit to use, how to run and test the app, what counts as a failed build, which packages are allowed, which files it must never touch, what the reviewer needs in the final summary. The exact files vary by tool — VS Code reads an AGENTS.md as always-on workspace instructions, and GitHub Copilot reads repository instructions from .github/copilot-instructions.md.[^vscode-agents][^github-instructions]
Keep it boring and explicit. A good harness turns "please build something" into "work inside this system, follow these rules, and show me what you changed." That's the whole game: a controlled loop the agent runs inside — not blind trust, and not pretending you'll read every generated line forever.
This is why Code Apps matter here
You can do some of this in any tool. You can do all of it when the app is files.
Code Apps let you build a Power App in a code-first IDE — React or Vue, developed locally — and still run it in Power Platform with the managed policies you'd expect: sharing limits, Conditional Access, Data Loss Prevention, and application lifecycle management.[^code-apps-overview] The reason that matters for AI isn't the framework. It's that the agent now works in a repo. It edits files, follows the harness, runs the tests, and hands you a diff you can review like any other change. Adding a data source even generates typed TypeScript model and service files in the repo, so the agent uses that structure instead of inventing its own way to reach data.[^code-apps-data]
That doesn't lower your responsibility — it raises it. Real code habits, real review. But it's the shape where the contract and the harness have something to bite on.
Your behavioural rules are your test list
Testing isn't a phase after the build anymore. It's part of it — and the design contract hands you the test cases for free.
Every behavioural rule is a test. "Never show Approve without the decision impact" is a test. "The role that shouldn't see this action can't" is a test. So is the duplicate submission, the required-field miss, the empty state, the error state, and the audit-trail check. Microsoft now points teams who want TypeScript and direct Playwright access to the Power Platform Playwright samples, the Playwright-native replacement for the retired Test Engine.[^playwright] Whatever tool you use, review has to move past "looks good to me" — and the contract already told you what to check.
The move this week
Pick one app family. Not your whole estate. One.
Find the decision people keep remaking: action placement, status cards, approval buttons, error messages, empty states, role-specific views. Write the first version of that rule as a tiny design contract.
# Case App Design Contract - v0.1
## Tokens
- Color.Primary: #2563EB
- Space.Md: 16
- Radius.Card: 8
## Component: ApprovalActionCard
Purpose: Show one approval decision with enough context for a human to decide.
Required slots:
- title
- requester
- submitted date
- decision impact
- primary action
- secondary action
States:
- pending
- approved
- rejected
- needs more information
Rules:
- Never show Approve without the decision impact.
- Destructive actions require confirmation.
- The primary action stays disabled until required fields are complete.
- Every decision writes approver, timestamp, prior value, new value, and reason.Then ask your AI tool to build one screen from it. Don't just judge the screen — judge the contract. Where did the AI still have to guess? What did it get wrong twice? Which rule belongs in the contract before anyone generates the next screen?
That's the muscle.
A prompt gets you one output. A contract improves the next hundred.

0 comments