AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Flag Cleanup

skill-growthbook-skills-flag-cleanup · by growthbook

Archive or delete a stale GrowthBook feature flag, walking the user through inlining the flag's effective value at call sites in the codebase before removal. Use when the user says "delete this flag", "remove this stale flag", "clean up flag X", "archive this flag", "we don't need this flag anymore", or "get rid of this flag and its experiment-ref rule". For finding stale flags first, use flag-se…

No reviews yet
0 installs
7 views
0.0% view→install

Install

$ agentstack add skill-growthbook-skills-flag-cleanup

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-growthbook-skills-flag-cleanup)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Flag Cleanup? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

flag-cleanup

Archive or delete a stale feature flag. Two paths: archive (reversible, soft-disable) or delete (permanent; always goes through archive first as a safety gate). The skill coordinates code-cleanup with the agent's general Read/Edit tools, surfacing call sites from GrowthBook's Code References API (when configured) or falling back to Grep against the user's current directory.

All API calls go through the bundled helper: ${CLAUDE_PLUGIN_ROOT}/scripts/gb-call. It needs GB_API_KEY — set in your shell, or written to ~/.config/growthbook/.env by /growthbook:setup. If unset or invalid, gb-call's error message points back at /growthbook:setup.

Required inputs

Collect from the user before starting. Prompt for what's missing.

  • Flag ID — kebab-case key. If the user gives a description, route to flag-search first to resolve.
  • Actionarchive (reversible) or delete (permanent; includes archive). Inferred from wording: "archive" / "disable" → archive; "delete" / "remove" / "clean up" / "get rid of" → delete. Confirm before mutating.

Workflow

Track progress with this checklist. Do not skip or reorder; each step gates the next.

- [ ] 1. Fetch flag, verify safety preconditions (incl. bulk experiment check)
- [ ] 2. Compute defaultValue + detect behavior-change divergences
- [ ] 3. Find call sites (Code References API → Grep fallback w/ cwd check)
- [ ] 4. Walk the user through inlining, batched by file
- [ ] 5. Archive the flag (revision-and-publish; branch to 5a on 403, 5b on 409)
- [ ] 6. Verify-or-rollback gate (delete path only)
- [ ] 7. Delete the flag (delete path only)
- [ ] 8. Report, including reverse-prerequisite limitation warning

1. Fetch flag and verify safety preconditions

gb-call GET /api/v2/features/

Capture from the response: archived (boolean), defaultValue, valueType, environmentSettings (which envs are enabled), rules (the full array, including any experiment-ref rules), holdout (informational), project.

If 404, halt: "no flag with id `." Suggest flag-search` to list flags.

Run the safety checks. Halt if any of these fire:

  • archived === true and the user asked to archive → already archived. Either re-confirm intent ("you said archive; this flag is already archived — did you mean delete?") or exit clean.
  • archived === true and the user asked to delete → this is a continuation of a prior cleanup session (or the user archived in the UI). Ask:

> This flag is already archived — looks like you're picking up where a previous cleanup left off. Did you already inline the flag's value at call sites in your codebase? > - Yes → I'll skip the behavior-change check and code-cleanup walkthrough; we'll go straight to the verify-or-rollback gate before delete. > - No → I'll still walk through steps 2–4 first, since the code references may still exist.

If yes, jump to step 6 (the archive step 5 is a no-op since archived: true → true makes no change server-side; the handler short-circuits when feature.archived equals the requested value).

  • neverStale: true is set on the feature. Confirm via the staleness endpoint:

``bash gb-call GET '/api/v2/stale-features?ids=' ` If the response includes staleReason: "never-stale", halt: > This flag is marked neverStale — someone explicitly said it should never be cleaned up automatically (kill switch, ops toggle, license gate, etc.). To proceed, remove the neverStale flag in the GrowthBook UI at /features/` first and re-run me.

  • Active experiment-ref rule pointing at a running experiment. One bulk call covers the common case:

``bash gb-call GET '/api/v1/experiments?trackingKey=&status=running' ` This works because experiment-launch sets trackingKey === flag-id by convention. If the response array is non-empty, halt: > This flag is wired into experiment () which is still running. Stop that experiment first (experiment-stop`), then re-run me.

Defensive cross-check. If the bulk call returns empty but the flag has experiment-ref rules in its rules array, the experiment may have been manually wired with experimentId ≠ trackingKey. Iterate the experiment-ref rules and fetch each one as a fallback: ``bash gb-call GET /api/v1/experiments/ ` If any returns status: "running"`, halt with the same message.

Temporary rollout check. While fetching linked experiments, also note any with status: "stopped" AND enableTemporaryRollout: true — these are not a blocker (the experiment is stopped), but step 2 must use the winner value as the inline replacement. Surface a reminder: > "Temporary rollout is active on experiment ` — all users currently see the winner value. Step 2 will use the winner value as the inline replacement, not defaultValue`."

  • Draft experiment referencing the flag. Lower-priority than running, but worth a warn-and-confirm. Reuse the bulk query with a different status filter:

``bash gb-call GET '/api/v1/experiments?trackingKey=&status=draft' ` If non-empty, warn: > Note: this flag is the trackingKey for draft experiment `. Deleting the flag won't break anything immediately, but it will prevent that experiment from launching successfully. Proceed?

  • Unresolved draft revision on the flag. A draft would be discarded by the archive:

``bash gb-call GET /api/v2/features//revisions/latest ` If 404, no draft exists — continue. If a draft is returned, halt: > There's an active draft revision () on this flag. Cleaning up the flag would discard those pending changes. Either publish or discard the draft in the GrowthBook UI at /features/` first.

  • /stale-features doesn't flag this as stale and the user is asking to delete. Warn but don't halt:

> Heads-up: GrowthBook doesn't flag this as stale. It's still enabled in `` with active rules. Proceed?

2. Compute the inline-replacement value and detect behavior changes

After archival, every rule stops evaluating — the flag returns defaultValue for all callers. The inline replacement value is usually defaultValue, but not always — see the temporary rollout case below.

Check for an active temporary rollout first. For each experiment-ref rule in the flag, fetch the linked experiment:

gb-call GET /api/v1/experiments/

If experiment.status === "stopped" AND experiment.enableTemporaryRollout === true:

  • The experiment's releasedVariationId tells you which variation is serving 100% of traffic.
  • Find that variation's value in the experiment-ref rule's variations array.
  • That value — not defaultValue — is what all users currently see.
  • Use it as the inline replacement value. Warn the user clearly:

> "Temporary rollout is active on this flag. All users currently see the winner value `. After cleanup, all users will shift to defaultValue: . If these differ, inlining is the correct replacement — not `."

For valueType: "json", surface the raw JSON-encoded string and let the user adapt the inline shape.

The real question this step exists to answer is: does cleanup change behavior in production?

Walk the rules array and flag anything that previously diverged from defaultValue:

  • A force rule serving a different value to a targeted segment.
  • An active rollout rule (coverage > 0) — even one with no condition.
  • An experiment-ref rule: fetch the linked experiment. If stopped with temporary rollout, the winner value is the divergence (handled above). If still assigning traffic normally (stopped experiment, no temporary rollout), users are split across variations — archiving shifts everyone to defaultValue, which is a change for treatment-group users.

Surface a table:

Behavior-change check for :
  defaultValue (post-cleanup):  "true"

  Pre-cleanup divergences (these stop applying after archive):
    production:  rule 1 (force, "beta testers" saved-group) served "false" → those users will now get "true"
    production:  rule 2 (rollout, 25% via id)              served "false" → 25% of traffic will shift to "true"
    staging:     no divergence — all traffic gets "true" today

Is this the intent?

If the table is empty (no divergences), the cleanup is purely cosmetic and the user can proceed without further confirmation. If any rule diverged, halt and confirm — this is real behavior change.

3. Find call sites

Try Code References first:

gb-call GET /api/v1/code-refs/

The response is {codeRefs: [{ repo, branch, platform, refs: [{filePath, startingLineNumber, lines, flagKey}] }, ...]}. One document per (repo, branch) — a feature may have multiple entries if Code References has been pushed from multiple branches.

  • Non-empty response → present line-level references to the user, grouped by file, with branch info if multiple branches are represented. Cite that the data is from Code References (so the user knows it may be stale relative to local edits).
  • Empty response → either Code References isn't configured, or the flag genuinely isn't referenced. Before falling back to Grep, confirm the working directory:

> Code References returned no results. I'll search the current directory (`) for `. Is that where the code that uses this flag lives, or should I look somewhere else?

After confirmation, use the Grep tool to search for the flag ID (kebab-case key, exact match) in the project. Limit to relevant file types (source code, not vendored directories).

If both Code References and Grep return empty, surface: > Couldn't find any code references to `. If you're confident the flag isn't used anywhere, proceed to step 5. Otherwise, double-check the working directory or look at Code References at /features/` for stale data.

4. Walk the user through inlining

Batch by file, not by line. A single file may have multiple references to the same flag; asking the user to approve N separate Edits in the same file is friction. For each file with references:

  • Use the Read tool to load the full file (once).
  • Surface a per-file summary: file path + count of references + the lines that reference the flag.
  • Propose a single Edit that replaces all references in the file with defaultValue (or the user-confirmed inline value).
  • The Edit goes through Claude Code's normal permission flow — the user reviews and approves the whole-file change once.
  • The user can also say "skip this file" (handle later) or "edit some but not all" (fall back to per-reference Edits within just that file).

Track which files have been handled and which were skipped. When the user signals "done with inlining" (or there are no call sites), proceed.

If the user wants to defer code-cleanup entirely ("just archive the flag now, I'll clean up code later"), allow it — the archive is reversible and the user can re-run this skill later to finish the code-cleanup before deletion.

5. Archive the flag

echo '{"archived": true}' \
  | gb-call POST /api/v2/features/ -

What happens server-side. This isn't a metadata patch. Setting archived triggers createAndPublishRevision server-side — a new revision is created and published atomically. The same failure modes that affect any v2 publish apply:

  • 2xx → archived. Proceed to step 6 (delete path) or step 8 (archive-only path).
  • 403 with "approval required" body → step 5a.
  • 409 → step 5b (merge conflict; another actor changed the flag between our GET and our archive POST).
  • Other 4xx → halt with the body.

A revision-history entry will appear for the archive event — surface this in step 8.

5a. Approval required for archive

Same three-option branch as flag-targeting, but with one critical asymmetry between archive and delete:

> Your org requires approval before this flag can be archived. To proceed: > > A. Standard review flow (recommended) — I'll request review on the change; a teammate approves it in the GrowthBook UI at /features/; you re-run me to resume. > > B. Org-wide bypass — admin enables "REST API always bypasses approval requirements" in Settings → General → Approvals. This single setting authorizes both archive and the final delete step. > > C. Per-token bypass — use a PAT with bypassApprovalChecks permission. This authorizes archive but NOT delete. The per-token permission is intentionally a review-workflow bypass only, not a destructive-action override. If your end goal is archive-only, this works. If you want to delete, you'll still need the org-wide setting from option B (or an admin to do the delete in the UI). Surface this asymmetry to the user before they pick C — don't let them discover it at step 7.

For path A, request review on the draft and halt:

echo '{"comment":"Auto-requested by flag-cleanup"}' \
  | gb-call POST /api/v2/features//revisions//request-review -

Do not attempt submit-review — the API rejects self-approval.

5b. Merge conflict on archive

A 409 on the archive POST means the draft's base revision is stale — a teammate (or another agent invocation) published changes to the same flag between our step 1 (GET) and our step 5 (POST). Do not auto-rebase. Halt with:

> Your archive of ` couldn't be applied — the flag has changed since I last looked at it. To resolve: > > - Open /features/` in the GrowthBook UI. > - Reconcile the change (either rebase our pending archive on top, or discard and re-run me to start fresh against the new live state). > > Re-run me after the conflict is resolved.

Surface the conflict body verbatim. The POST /api/v2/features//revisions//rebase endpoint exists for opt-in resolution; v1 stays conservative for the same reasons flag-targeting does — merge resolution needs human judgment per conflicting field.

6. Verify-or-rollback gate (delete path only)

After archive succeeds, halt and confirm with the user. Frame the irreversibility of delete in the prompt itself, not just in a guardrail the user may not have read:

> The flag is archived. At this point the action is fully reversible — unarchive in the UI (or reply "rollback") and everything goes back. Once we delete, the flag and all its revisions are gone permanently; there's no undo. > > Before I delete: > > - Check that nothing in your codebase broke. Run your tests; deploy to staging; verify the app behaves correctly with defaultValue instead of the old rules; whatever your normal post-flag-removal check is. > - When you're confident, reply "proceed" and I'll delete. > - Reply "rollback" and I'll unarchive.

This is the load-bearing gate of the skill. Permanent deletion is a one-way door and the user should sit with the archived-but-not-deleted state for at least one verification cycle. Don't collapse the two steps even if the user pushes for it.

If the user picks "rollback": undo the archive by setting archived: false via the same endpoint:

echo '{"archived": false}' \
  | gb-call POST /api/v2/features/ -

This goes through the same revision-and-publish flow as the archive — same approval-required and merge-conflict failure modes apply. Verify it completes cleanly, surface the outcome, and exit.

7. Delete the flag (delete path only)

gb-call DELETE /api/v2/features/
  • 2xx with {deletedId} → proceed to report.
  • 403 → almost certainly the restApiBypassesReviews setting is off. The flag is archived, just not deletable via the API. Surface:

> Your org requires the "REST API always bypasses approval requirements" setting to be enabled before flags can be deleted via the API. The flag is archived; you can either: > > - Ask an admin to enable the setting (Settings → General → Approvals), then re-run me to finish the delete. > - Delete manually in the GrowthBook UI at /features/ (the archived flag is still listed there). > > Per-token `

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.