flag-create · git:20260924.a44cf8f · 2026-09-24 · sha256 daf47e07d827ff7f

flag-create git:20260924.a44cf8fA

Immutable. This exact content never changes and is served at /api/v1/blob/daf47e07d827ff7f.

---
name: flag-create
description: "This skill should be used to create a runtime feature flag end-to-end across Flagsmith, server.ts, .env.example, and Doppler."
---

<!-- 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-create

Creates a new runtime feature flag in Flagsmith **and** wires it into the
codebase + Doppler in one step. Use this instead of the Flagsmith UI when
adding a flag that the app needs to read.

## When to use

- Adding a new runtime flag (server-side resolution path; client consumes
  via `useFeatureFlag()` after rebuild).

## When NOT to use

- Adding an env-only DCE flag (like `dev-signin`) — those don't go through
  Flagsmith; just hand-edit `ENV_FLAGS` in `server.ts` + `.env.example`.
- Toggling an existing flag → use `soleur:flag-set-role`.

## Arguments

<arguments> #$ARGUMENTS </arguments>

Required positional: `<kebab-flag-name>`.
Optional: `--description "<text>"`, `--dev-on` (default off), `--prd-on`
(default off), `--dry-run`, `--flagsmith-only`.

`--flagsmith-only` creates **only** the Flagsmith feature for a flag that is
**already code-wired** (already in `RUNTIME_FLAGS` + `.env.example` + Doppler).
It skips the server.ts / `.env.example` / Doppler mutations **and** the "already
appears in server.ts" exit-1 precheck (which would otherwise fire precisely
because the flag is already wired). Use it to back-fill the Flagsmith feature for
a flag that shipped its code wiring in an earlier PR, before scoping it per-org
with `soleur:flag-set-role <flag> <env> on --org <orgId>`.

## Prerequisites

- Doppler authed with access to `soleur` configs `dev`, `prd`, `cli_ops`.
- Worktree of the soleur repo (script edits files in `apps/web-platform/`).
- `curl` + `python3` on PATH.

## Procedure

```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/flag-create/scripts/create.sh" <flag-name> \
  [--description "..."] [--dev-on] [--prd-on] [--dry-run]
```

The script (full in [scripts/create.sh](./scripts/create.sh)):

1. **Validate name** — kebab-case, not already in `RUNTIME_FLAGS`, not in
   `ENV_FLAGS`, not already a feature in Flagsmith.
2. **Print proposed mutations** (4 lines):
   - Flagsmith: create feature `<name>` with default_enabled=false.
   - server.ts: append `"<name>": "FLAG_<NAME>"` to `RUNTIME_FLAGS`.
   - .env.example: insert `FLAG_<NAME>=0` under the runtime flags section.
   - Doppler dev + prd: `FLAG_<NAME>=<0|1>` (mirrors prd-segment initial state).
3. **Operator ack** — literal `yes`.
4. **Create feature in Flagsmith** —
   `POST /api/v1/projects/39082/features/` with `name`, `description`,
   `default_enabled: false`.
5. **Apply segment overrides** (if `--dev-on` or `--prd-on`) — for each
   env, push a v2 version with `feature_states_to_create` setting the
   target segment's enabled state to true. Same pattern as
   `soleur:flag-set-role`.
6. **Edit files** — append `RUNTIME_FLAGS` entry; append `FLAG_<NAME>=<0|1>`
   to `.env.example`.
7. **Mirror Doppler** — `doppler secrets set FLAG_<NAME>=<0|1>` in dev + prd.
8. **Print next-action hint** — "commit `server.ts` + `.env.example` so
   the resolution path can read the new flag".

## Exit codes

- `0` — success / dry-run.
- `1` — name validation failure.
- `2` — prerequisite missing.
- `3` — Flagsmith API error.
- `4` — file edit failed.
- `5` — Doppler write failed.

## Sharp edges

- The skill edits source files. Run from a clean worktree where you're
  prepared to commit the changes. Skill prints the `git diff` after.
- New flag's identifier sent to Flagsmith uses the same `role:<role>`
  cache pattern as existing flags (see
  `apps/web-platform/lib/feature-flags/server.ts`); no per-user behavior.
- This skill does NOT create a CI verify probe or test for the new flag.
  Add one in the PR that consumes the flag.

## Cross-references

- ADR: `knowledge-base/engineering/architecture/decisions/ADR-038-feature-flags-flagsmith.md`
- Sibling skills (flag CRUD set): `soleur:flag-set-role` (Update), `soleur:flag-list` (Read), `soleur:flag-delete` (Delete), `soleur:user-set-role`