# How we clear out old feature flags

Each week a Machine agent finds feature flags that are fully rolled out or long dead, deletes them along with the code they guard, and opens a PR. A person merges; live rollouts are left alone.

Canonical page: https://themachine.myapps.ai/use-cases/feature-flag-cleanup

Feature flags are meant to be short-lived. You ship behind one, watch the
rollout climb to 100%, and then somebody should come back and take it out. That
last bit almost never wins against the next thing on the roadmap. So the flags
collect, and each one leaves behind an `if`, an `else` nobody runs and a config
line nobody checks, until your codebase is hauling around every rollout you have
ever done.

Our fix is a cleanup agent on Machine that goes through the repo once a week,
picks out the flags that can safely go, deletes them along with the code they
guarded, and opens a PR. Merging its own PR is not allowed. Neither is touching
a flag that is still partway through a rollout: those get passed to a human
instead.

- **Team:** Machine
- **Runs on:** A weekly cron, picking up the same session
- **Connected systems:** GitHub
- **Mode:** PRs only · a person does the merge

## The problem

Every flag lives the same life: you ship behind it, ramp it up, reach 100%, and
remove it. The first three stages are urgent and someone owns them. The last
one is neither. Once a flag is at 100%, the team behind it has moved on to the
next project, and deleting a few lines of `if` logic loses every argument about
priorities.

No single flag looks expensive. The cost builds up. Each flag still in the code
is another branch an engineer has to think about, a path that may have quietly
dropped out of the tests, and a home for bugs as the unused side decays without
anyone noticing. Leave it, and the list of flags only ever gets longer, because
no one wants to be the person who deleted the one that still mattered.

## What we built

Once a week a cron job on Machine nudges the same **reusable session** back to
life: a cloud computer (a sandbox) the agent returns to each time, so cleanup
is a steady routine and not a one-time chore. The agent clones the repo, lists
every feature flag and puts each into one of four buckets: fully rolled out and
fine to remove, long dead with nothing checking it, still partly rolled out, or
part of a live experiment. Flags in the first two buckets get deleted along with
the dead code behind them, the tests are run to prove nothing broke, and a PR
goes up. Flags in the other two are left untouched and simply noted for a
person to review.

## How it works

### Return to one session every week

A **cron trigger** goes off weekly and picks up the same **session** instead of
spinning up a new one. The agent keeps a running record of how old each flag
is, where its rollout stands and what it has already proposed. That way it never
argues the same flag twice and never opens a second PR for one already waiting.

### Teach it how to sort the flags

The rules for spotting a dead flag are kept as a **skill**, a playbook the agent
carries from run to run. It describes what "fully rolled out" looks like in our
flag config and how long a flag must sit unchecked to count as long dead. Just
as important, it describes the signs of a partial rollout or a live experiment,
so the agent knows exactly where to stop.

### Work on the code through GitHub

The codebase is the only thing the agent touches, and it gets there through the
**GitHub** connector using a narrowly scoped token. It clones the repo, searches
for every place a flag is defined or checked, deletes the flag and the code it
guarded on a separate branch, runs the checks inside the sandbox, and opens a PR
with the `gh` CLI.

### Draw the lines it cannot cross

Flags that are partly rolled out, or part of a live experiment, are reported
and never removed. The agent cannot push to the default branch and cannot merge
its own PR. The GitHub token is passed into the sandbox only when a run starts,
and only handed to the agents you grant it to.

### Open the cleanup PR

With the flags sorted and the dead code gone, the agent runs the whole test
suite. Only on a pass does it push the branch and open a PR that lists every
flag it removed and the reason, plus a separate note on any flag it found still
mid-rollout. A person reviews it and merges it. Nothing merges by itself.

> **The pattern**
> Once a week a **cron** wakes a reusable **session** that tracks each flag's age
> and rollout status. The sorting rules are kept in a **skill**. The agent only
> deletes flags that are fully rolled out or long dead, and passes anything
> still mid-rollout to a person.

## Guardrails

This agent deletes code, so we limit it from both directions: what it is
allowed to take out, and what it must never touch.

- **Partial rollout is untouchable.** A flag that is still ramping up, or that
  belongs to a live experiment, stays put. The agent writes it down and moves
  on, and a person decides what happens to it.
- **No direct pushes, no self-merges.** Each change goes on its own branch and
  becomes a PR. Pushing to the default branch and merging its own work are both
  off limits.
- **Verification before the PR, not after.** The full test suite runs inside
  the sandbox on the cleanup branch. If a removal breaks something, it is
  dropped and noted, never handed to a person to unpick.
- **Scoped, ephemeral access.** The GitHub token is stored encrypted in the
  **Secrets Manager**, passed into the sandbox only for the run, and only handed
  to the agents you grant it to.
- **Everything is code.** The sorting rules, the running record and the agent's
  permissions are files in the repo, kept in version control. Changing them
  takes a reviewed change request.

## The outcome

- **Weekly:** Each flag checked again against where its rollout stands now
- **PR-only:** Each deletion arrives as a PR to review, never a direct push
- **0:** Flags mid-rollout that the agent has ever touched

Flags that once lingered at 100% for months are now gone within a week of
getting there, and the dead code goes with them. The agent suggests, a person
still decides on the merge, and any flag mid-rollout stays exactly as your team
left it.
