This skill should be used to delete a runtime feature flag end-to-end (the inverse of flag-create): removes it from Flagsmith, server.ts RUNTIME_FLAGS, .env.example, the flag-set-role flip.sh map, and Doppler dev+prd, with a WORM audit and typed-yes guardrail.
16 stars
0 votes
0 copies
1 view
Added September 3, 2026
ai-agentspythongoshellbashgitapidocumentation
Works with
claude code
terminal
cli
api
Security analysis
B75/100
criticalSends environment variables or credentials to an external URL
Installs into .claude/skills of the current project.
Are you the author of Flag Delete?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/jikig-ai-flag-delete)
---
name: flag-delete
description: "This skill should be used to delete a runtime feature flag end-to-end (the inverse of flag-create): removes it from Flagsmith, server.ts RUNTIME_FLAGS, .env.example, the flag-set-role flip.sh map, and Doppler dev+prd, with a WORM audit and typed-yes guardrail."
disable-model-invocation: true
---
<!-- soleur-cloud-mode:start -->
**Cloud Mode (Devin):** before pipeline work run `bash "${CLAUDE_PLUGIN_ROOT}/scripts/cloud-detect.sh"`. If `CLAUDE_PLUGIN_ROOT` is unset (cloud exec shells do not export it), resolve the root by IDENTITY, never by script basename: for `d` in `"$HOME/.local/share/devin/cli/plugins/cache"` and `/opt/.devin/plugins`, skip unless `[ -d "$d" ]`, then `MANIFEST="$(find "$d" -path '*/.claude-plugin/plugin.json' -exec grep -l '"name"[[:space:]]*:[[:space:]]*"soleur"' {} + 2>/dev/null | head -1)"`, `ROOT="${MANIFEST%/.claude-plugin/plugin.json}"` — one resolution, two consumers: `$ROOT/scripts/cloud-detect.sh` and `$ROOT/scripts/precommit-guard.sh`. (Shape check, not authentication: a planted `{"name":"soleur"}` dir passes — ADR-179 A11.) `local` or `not-local:no-devin-env` proceeds normally; any other `not-local:<reason>` applies `<plugin-root>/devin/INSTRUCTIONS.md` §Cloud Mode: emit the `--banner`, fan out sequentially with `Reviewed-Coverage: sequential-fallback` disclosure (never claim an independent review ran), `message_user` ack before any secrets read or production mutation, and run `precommit-guard.sh` before any `git commit` — hooks do not fire in cloud.
<!-- soleur-cloud-mode:end -->
<!-- grok-harness-invoke:start -->
**Grok Build (`plugins/soleur/lib/harness.ts` `invokeSkill()`):** Read this SKILL.md in this process and run it to completion. A one-segment `soleur:<name>` in this document names a SKILL — on Grok Build, Read `plugins/soleur/skills/<name>/SKILL.md` in this process; it is not a nested tool_use. A multi-segment id such as `soleur:<domain>:<name>` names an AGENT: spawn it, never Read it, and on Grok Build spawn_subagent takes the id with its colons replaced by hyphens (`agentIdToGrokSubagentType`). **Claude Code:** Skill tool for a skill (`soleur:<name>`), Task tool with `subagent_type` for an agent. Forbidden is executing a subset, not the Read.
<!-- grok-harness-invoke:end -->
# flag-delete
Removes a runtime feature flag from **all five** sites — the exact inverse of
`flag-create`, the **Delete** verb of the flag CRUD set. Destructive: gated by a
dry-run, a typed-`yes` confirmation, and a WORM audit row written before any
mutation.
## When to use
- Retiring a runtime flag whose rollout is complete (or was abandoned).
- Before deleting, run `soleur:flag-list` to see the flag's blast radius
(which segments/roles/orgs it targets — all destroyed by the Flagsmith
cascade).
## When NOT to use
- Turning a flag off without removing it → `soleur:flag-set-role <flag> <env> off`.
- Removing a build-time DCE flag (`dev-signin`) → hand-edit `ENV_FLAGS` in
`server.ts` + `.env.example` (it has no Flagsmith feature).
## When to use this skill vs other flag skills
The flag CRUD set: `soleur:flag-create` (Create), `soleur:flag-set-role`
(Update — per-role/per-org), `soleur:flag-list` (Read),
**`soleur:flag-delete` (Delete — this)**. Initial wiring is the
`${CLAUDE_PLUGIN_ROOT}/skills/flag-bootstrap/SETUP.md` runbook (operator documentation, not an invocable
skill).
## Arguments
<arguments> #$ARGUMENTS </arguments>
Required positional: `<kebab-flag-name>`.
Optional: `--dry-run` (enumerate the 5 mutations and exit before any change).
There is intentionally **no** `--yes`/`--force` bypass — the typed-`yes` prompt
always gates a real delete, and it needs a person at a terminal, because the audit row accepts only that
acknowledgement (ADR-249; staged-gate migration is tracked in #9387).
## Prerequisites
- Doppler authed with access to `soleur` configs `dev`, `prd`, `cli_ops`.
- Worktree of the soleur repo (the script edits `apps/web-platform/` + `flip.sh`).
- `curl` + `python3` + `jq` on PATH.
## Procedure
The agent runs only the preview:
```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/flag-delete/scripts/delete.sh" <flag-name> --dry-run
```
## The write is the one typed-`yes` handoff (ADR-249)
The write path asks for a typed `yes` through the operator-script library's TTY
acknowledgement, because the audit row this script writes records only that kind of
acknowledgement (ADR-249); moving it to the staged agent-run approval gate that
generated operator scripts use is tracked in #9387. It has no skip variable and no
flag. An agent's shell has no TTY, so a write run there stops with exit `64` and `SOLEUR_BOOTSTRAP_INPUT_REQUIRED` on
stdout, before any credential is fetched. Exit `64` is a refusal, never a success.
The agent therefore does every other step itself (reads, the dry-run preview,
preflight, verification) and hands over only the typed-`yes` write:
1. Runs the script with `--dry-run` and shows the preview. That mode needs no TTY
and makes no writes.
2. Prints the exact write command below, in a fenced block, for the operator to type
at a terminal prompt (Warp), the one step an agent cannot take. It replaces `<WORKTREE>` with the absolute path of
the worktree that holds this change (`git rev-parse --show-toplevel`) and
`<ARGS>` with `<flag-name>`, without `--dry-run`. It never prints a
`${CLAUDE_PLUGIN_ROOT}` or repo-relative form. The script also edits repo files in the directory it runs from, so an operator running it from the main checkout or another worktree would land the code wiring in the wrong tree while Flagsmith and Doppler change.
3. Does not run the command, and does not run it through Claude Code's `!` prefix
either (whether that gives the command a TTY is unmeasured, ADR-249). The
printed command is an undone operator step under
`wg-block-pr-ready-on-undeferred-operator-steps`: record it where the pipeline
tracks operator steps, and do not mark a PR ready until the operator says it ran.
<!-- operator-write-command -->
```bash
cd <WORKTREE> && bash <WORKTREE>/plugins/soleur/skills/flag-delete/scripts/delete.sh <ARGS>
```
The operator types `yes` at the prompt. Any other answer stops the script with exit
`1` and `SOLEUR_BOOTSTRAP_ABORTED stage=ack`, before anything is written.
The script (full in [scripts/delete.sh](./scripts/delete.sh)) deletes from **5
sites** (the issue's 4-site framing misses the `flip.sh` map):
1. **Flagsmith feature** — `DELETE /api/v1/projects/39082/features/{id}/` →
HTTP 204. The DB cascade removes all segment + identity overrides; no manual
pre-deletion needed. The feature_id is resolved by an **exact** `name ==`
match (the `?q=` filter is substring, so a bare pick could delete the wrong
feature).
2. **server.ts** — strip the `"<name>": "FLAG_<X>"` entry from `RUNTIME_FLAGS`.
3. **.env.example** — remove the `FLAG_<X>=` line.
4. **flip.sh** — remove the `["<name>"]="FLAG_<X>"` entry from the
`flag-set-role` `FLAG_ENV_VARS` map (a stale entry lets `flag-set-role` try
to flip a deleted flag).
5. **Doppler** — delete the secret in `soleur/dev` AND `soleur/prd` (each delete
line redirects stdout to `/dev/null` — the Doppler delete command otherwise
prints the full remaining config).
Order: name-validate → confirm flag present in `RUNTIME_FLAGS` → resolve
Flagsmith id → propose/dry-run/typed-`yes` → **WORM audit (action `archive`)
before any mutation** → Flagsmith DELETE → code edits → Doppler deletes →
verify deletion.
## Exit codes
- `0` — success / dry-run.
- `1` — name validation failure (or flag not in `RUNTIME_FLAGS`), or the operator
did not type `yes` (`SOLEUR_BOOTSTRAP_ABORTED stage=ack`; nothing mutated).
- `2` — prerequisite missing.
- `3` — Flagsmith API error (non-204 DELETE).
- `4` — file edit or audit append failed.
- `5` — Doppler delete failed.
- `64` — a write run with no TTY (`SOLEUR_BOOTSTRAP_INPUT_REQUIRED`): nothing was
fetched or changed; hand the command to the operator (above).
## Recovery from a partial delete
The 5 sites fail independently. The exit code + stderr message identify how far
the delete got, so a partial state is recoverable:
- **exit 3** — nothing mutated (Flagsmith DELETE is the first mutation; a
non-204 means no code/Doppler change). Re-run is safe.
- **exit 4, "FATAL: audit RPC …"** — pre-mutation: the WORM append failed
before the Flagsmith DELETE, so nothing changed. Re-run is safe.
- **exit 4, server.ts/.env.example/flip.sh edit message** — the Flagsmith
feature is gone but a code edit failed. Half-deleted: finish the remaining
edits + Doppler deletes by hand, or re-run (the code-cleanup steps are
idempotent — each is a no-op if already removed).
- **exit 5** — Flagsmith + all code files done; a Doppler delete failed. Re-run
(idempotent) or remove `FLAG_<X>` from Doppler dev/prd by hand.
A clean exit `0` is the full-delete signal. The WORM `action` enum (migration
071: `on`/`off`/`create`/`archive`) has no "delete" value — `archive` is the
sanctioned flag-removed action, so no schema change is needed.
## Sharp edges
- **Destructive + edits source files.** Run from a clean worktree and review
the diff (server.ts + .env.example + flip.sh) before committing.
- The Flagsmith name is **reusable** after delete (the soft-delete unique index
ignores deleted rows — verified live 2026-06-15), so a create→delete→recreate
round-trip works.
- The management API key is read via `doppler secrets get … -c cli_ops --plain`
and passed only to `curl -H Authorization` — never echoed.
## Cross-references
- ADR: `knowledge-base/engineering/architecture/decisions/ADR-038-feature-flags-flagsmith.md`
- Inverse skill: `soleur:flag-create`. Sibling skills: `soleur:flag-list`, `soleur:flag-set-role`.