Run feature flags end to end without building up flag debt: classify the flag, name it well, roll it out on a safe ladder, flip it as a kill switch, and retire it on schedule. Use when adding a flag, reviewing one, ramping a release, or cleaning up dead flags.
./install.sh feature-flag-workflowname: feature-flag-workflow description: Run feature flags end to end without building up flag debt: classify the flag, name it well, roll it out on a safe ladder, flip it as a kill switch, and retire it on schedule. Use when adding a flag, reviewing one, ramping a release, or cleaning up dead flags.
Feature flags decouple deploying code from releasing it. Done sloppily they become dead conditionals, surprise resurrections, and branches nobody dares touch. This skill is the full discipline: classify, name, launch, ramp, and retire every flag on purpose. The core rule: a release flag is an unpaid loan, Total Cost = Cost of Feature + Cost of Flag Cleanup. Ship the cleanup the same way you ship the feature.
Use Martin Fowler's taxonomy (https://martinfowler.com/articles/feature-toggles.html). The type decides the lifespan, and the lifespan is what rots when misclassified.
| Type | Purpose | Lifespan | Example | |---|---|---|---| | release | Ship dark code, roll out gradually | Days to weeks. Retire after full launch | release.checkout.v2-flow | | experiment | A/B test a cohort | Hours to weeks. Retire when the test concludes | experiment.onboarding.simplified-flow | | ops | Kill switch, circuit breaker, degrade mode | Long-lived on purpose | ops.payments.stripe-integration | | permission | Gate by plan, role, or tenant | Lives with the product | permission.reporting.advanced-analytics |
The classic error mode is treating a release toggle as a permission toggle: "we never turned it off, so now it's permanent." Flag debt starts there.
Convention: <type>.<domain>.<feature>, all lowercase, dots or dashes as separators. Examples: release.invoicing.pdf-export, ops.search.circuit-breaker. Never reuse a flag name, even after retirement. A recycled name makes history unreadable and old config ambiguous.
Every new flag gets four things at creation:
release and experiment flags. A flag with no expiry date is a defect waiting to happen.Never go 0 to 100 in one flip. The standard ladder, each step held while metrics settle:
internal users -> 1% -> 10% -> 50% -> 100% (bake briefly) -> retire
Rules for each ramp:
A flag flip is a production config change and gets treated like one: log who changed it, when, old value, new value. Audit trail is non-negotiable once flags control anything beyond cosmetics.
Two flip paths, used deliberately:
Rule of thumb: need it live now -> dashboard; want it recorded -> config.
Kill switches (ops flags) are the permanent exception to "flags are temporary". Every feature with external dependencies (third-party APIs, fragile services) gets one. A kill switch removed because nobody used it last quarter is a future outage.
Detection rules. A flag is dead when any of these hold:
release flag at 100% rollout for more than ~14 daysexperiment flag past its end daterelease flag older than ~30 days with no removal ticket on fileStaged retirement (borrowed from teams that paid down real flag debt):
Before deleting, verify the flag is truly dead. A flag that looks inactive in the control plane may still be evaluated by an old client, a scheduled job, or a fallback path. Also scan for dynamic evaluation (string interpolation, reflection) before declaring a flag unused. Flag removal is a design decision: do not remove flags you cannot fully trace.
When asked to run this skill, produce:
bin/flag_inventory.py --card <name> --type <type> --owner <team> --expiry <YYYY-MM-DD> to generate a consistent card.bin/flag_inventory.py --scan <repo-path> output showing every flag read found in code, naming-convention violations, and candidates for retirement.ops and permission types.max_connections is a permanent operational setting; it is not a flag and gets no expiry date.if Rails.env.production?) and permission checks (if user.admin?) are not feature flags either.publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.