All jobs

Find Stale Feature Flags in PostHog

Yes. An agent lists your PostHog feature flags and returns the ones safe to remove: fully rolled out, not evaluated in 30 days, or disabled.

What the agent does

The run reads PostHog through PostHog's remote MCP server, https://mcp.posthog.com/mcp, which the Rush connector catalog lists for product analytics, feature flags, experiments, error tracking and logs. Connect it once with POST /me/connections {"type": "mcp", "name": "posthog", "url": "https://mcp.posthog.com/mcp", "auth": {"mode": "oauth"}}. Rush also bundles PostHog's own skills from its ai-plugin repository, and a skill tied to a connector joins every run that reaches that connector's server.

The agent lists every feature flag in the project: its key, whether it is active, its release conditions and rollout percentage, any multivariate variants, the date it was created and who created it. A flag with one condition set rolling out to 100 percent of everyone, with no property filters, counts as fully rolled out; a flag that is 100 percent for one cohort only does not, and the agent keeps the two apart.

Evaluation counts come from events. When an SDK evaluates a flag it sends a $feature_flag_called event with the flag's key, so the agent queries those events for the last 30 days, grouped by flag, and records the last time each flag was evaluated. A flag with none in that window is either dead in code or only read by a server SDK that does not send the event, and the report says that a zero is a lead, not proof.

With both lists it builds the cleanup set in three groups: active flags fully rolled out for more than 30 days, flags with no evaluations in 30 days, and flags that are turned off. Each row has the key, the rollout, the created date and the last change it can read. Flags that back a running experiment are listed separately, since removing one ends the experiment. The prompt says to change no flag, and the agent writes stale-flags.md in its sandbox.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Use the PostHog connection to list all feature flags in the project with their active state, release conditions, rollout, variants, creation date and creator. Count $feature_flag_called events per flag key for the last 30 days and record each flag's last evaluation. Write stale-flags.md listing, in separate sections: active flags rolled out to 100 percent of all users for over 30 days, flags with no evaluations in 30 days, and disabled flags, each with its key, rollout, created date and last change. List flags tied to a running experiment apart from the rest. Read only: change, disable or delete no flag.",
  "connections": [
    "posthog"
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

The session returns stale-flags.md as an artifact. It opens with a count per group and then one table per group. A developer can work down the fully-rolled-out table first: those flags have a known winner, so removing them means deleting the losing branch in code and then the flag in PostHog.

The query behind the evaluation counts is in the session's transcript with its result, so anyone can rerun it in PostHog to check a zero. Before deleting anything, search the codebase for each key: a flag with no evaluations may still be read by a backend that does not send $feature_flag_called, and removing it there would change behaviour. A follow-up message to the same session can ask the agent to turn the list into a cleanup issue per flag.

Run it on every first Monday of the month

An automation with a schedule trigger in a Project can run this monthly, with a cron for the first Monday and your timezone. Each run reads the flags as they are that morning, so a flag cleaned up last month drops off and a flag that reached 100 percent since then appears.

With a webhook URL on the key, Rush POSTs run.completed when the turn ends. Your server can read the session, take the stale-flags.md link from its artifacts and post the fully-rolled-out count to the team channel, where it works as a monthly nudge.

The use case this job follows, with its automation and trigger: Produce a report or file, no repo.

Why run it on Rush?

Flag debt builds up because no one owns the question "which of these can go", and answering it means joining the flag list with event data by hand. The agent does that join in its own sandbox through the connection and writes the answer down, with the query that produced each number.

Because it is read only and recorded, it is safe to run against production PostHog: the transcript shows that no flag was changed. Teams with several PostHog projects can start one run per project at the same time, up to the key's concurrent run limit, and compare the lists.

Frequently asked questions

Will it delete or change any flags?

No. The prompt says to change no flag, and every tool call is in the session's transcript, so you can confirm nothing was written. Removing a flag stays a decision a person makes after checking the code.

Why would a live flag show zero evaluations?

The count comes from $feature_flag_called events. Some server-side setups evaluate flags locally and do not send that event, so a flag read only by them looks unused. The report marks zeros as leads to check in code.

Can it also find the flag keys in my code?

Yes, in a run that has the repository too. Add it as a resource, {"url": "https://github.com/your-org/your-app"}, and ask the agent to search for each key and list the files that read it beside each flag.