AI-native
How do you keep AI-written code behind declared feature flags?
Put every flag in one registry in your code, check flags only through a typed helper that accepts the registry's keys, and let the compiler, a lint rule and a test of both flag states catch anything that goes around it. Then an agent can't misspell a flag, invent one, or ship a change that only works with the flag on.
Updated November 9, 2026
Why do plain string flag keys break with agents?
Most flag SDKs take the flag key as a string. An agent that types new_chekout instead of new_checkout gets no error: the flag is unknown, so the check is off, and the feature silently never ships. An agent can also check a flag nobody created, or leave a check behind after the flag is deleted. At the pace agents merge changes, nobody spots these by eye. Flagger.gg's guide to typed feature flags makes the flag list part of the code instead of a convention.
What are the five steps?
- Declare every flag in one registry, such as
flags.tsorflags.go, with a summary, a description and an owner. Unfinished work gets a not-ready reason. - Check flags only through a typed helper that takes the registry's key type, so a misspelled or undeclared key is a compile error rather than a quiet "off".
- Ban direct SDK calls elsewhere with a lint rule, so the helper is the only way in.
- Test both states of every new flag, on and off, so an agent's change has to work both ways.
- Tell the agent the rules in the file it reads, such as AGENTS.md or CLAUDE.md, and let CI enforce them.
What does it look like in TypeScript?
In Flagger.gg's Node SDK, the registry is passed as defs, and a short wrapper makes the check strict:
export const FLAGS = {
new_checkout: {
summary: "Customers see the rebuilt checkout",
description: "New checkout flow in web/checkout",
owner: "payments",
notReady: "Tax step not done",
},
} satisfies Record<string, Def>;
export type FlagKey = keyof typeof FLAGS;
export const isOn = (key: FlagKey, ctx?: FlagContext) => flagger.flag(key, ctx);isOn("new_chekout") is now a type error. ESLint's no-restricted-imports rule then blocks importing the SDK anywhere but the registry file. In Go, the same idea uses a Key type and one constant per flag, and a bad or duplicate key in the registry fails at start-up rather than in production traffic.
How do you test both states?
A typed key proves the flag exists, not that the code works with it off. Flagger.gg's Go and Node SDKs include a bothFlagStates helper that runs a test once with the flag on and once with it off, plus withFlag and setFlagOverride for narrower cases.
What does Flagger.gg do with the registry?
- When the app starts, the SDK registers the registry: missing flags are created and descriptions updated, but a deploy never overwrites a state someone set.
- New flags follow the project's policy: in auto-live mode, the default, a new flag starts on unless it has a not-ready reason; with approvals on, new flags start off.
- A flag that exists in the service but no app has registered recently is marked "Not in code yet" in the Release console.
- An unknown key is off, never an error.
Public npm and go get installs of the SDKs are listed as in development. For the wider workflow, see trunk-based development with AI agents and how to write instructions for AI coding agents.
Frequently asked questions
What is a typed feature flag?
A flag whose key is checked by the compiler against a registry in your code, so a misspelled or undeclared flag fails the build instead of silently reading as off.
Why would an AI agent misspell a flag?
Agents type keys from memory or context like anyone else. With string keys, a typo isn't an error, so the mistake ships unnoticed.
Does a typed flag guarantee the code works?
No. It proves the flag exists. Test the code with the flag both on and off as well.
Can I install Flagger.gg's SDKs from npm today?
Public npm and go get installs are listed by Flagger.gg as in development.