flipt
GitHub管理 Flipt 功能标志,支持列出、查询及配置回滚规则。强调只读操作,禁止通过 API 写入,需通过 GitOps PR 变更状态。详细说明了环境变量与 Flipt 的覆盖逻辑及暗色标志的处理陷阱。
Trigger Scenarios
Install
npx skills add civitai/civitai --skill flipt -g -y
SKILL.md
Frontmatter
{
"name": "flipt",
"description": "Manage Flipt feature flags - list, create, enable\/disable, and configure rollout rules. Use when you need to control feature flag state or set up segmented rollouts."
}
Flipt Feature Flag Management
Use this skill to manage Flipt feature flags for controlled feature rollouts.
Running Commands
Use the included script:
node .claude/skills/flipt/flipt.mjs <command> [options]
Commands
| Command | Description |
|---|---|
list |
List all flags |
get <key> |
Get details for a specific flag |
create / enable / disable / delete |
Refuse with exit 2 and print the GitOps steps — see below |
add-variant / remove-variant / set-rollout |
Same |
Reads work over the API; writes are deliberately refused. This Flipt is v2, GitOps-backed by a private state repo, so a merged change becomes visible within about a poll interval.
Never write through the API. Flag state is reviewed material — change flags by opening a PR against the state repo, never by calling the API. This skill refuses writes for that reason.
What a key does to the app
The monolith's flag registry (src/server/services/feature-flags.service.ts) declares a
static availability per flag, and Flipt overrides it in both directions — except on a flag
whose FEATURE_FLAG_<KEY> environment variable was APPLIED, which is removed from Flipt's
control entirely (createFeatureFlags records it in envOverriddenFlags; hasFeature then
skips Flipt for it).
Whether a variable is applied has exactly one rule, and it is not "is the variable set":
| Registry entry | Its FEATURE_FLAG_<KEY> variable |
Flipt |
|---|---|---|
availability: [] with a fliptKey |
ignored — cannot switch it on | keeps control |
| anything else | applied | skipped entirely |
🔴 So a NON-dark flag can carry a fliptKey, have that key set enabled: false, and still be
on for everyone. Toggling it in flag state changes nothing and looks like Flipt is broken.
Before you read such a flag's Flipt value as its effective state — or set one expecting an effect
— check whether a variable names it in the environment you care about.
🔴 Do not invert that check on a dark flag. A variable naming an availability: [] flag that
has a key is discarded, so the flag is dark, off, and still Flipt-owned — the opposite of pinned
out. The server logs a [feature-flags] warning naming each one it discards at startup.
Consequences before you add or toggle a key:
- A flag declared
availability: []that has afliptKeyis dark: static evaluation is false for everyone and that key is its only on-switch. AFEATURE_FLAG_<KEY>environment variable cannot lift it. Creating the key and enabling it is what ships the feature. - A flag declared
availability: []with nofliptKeyhas no Flipt switch at all, so itsFEATURE_FLAG_<KEY>variable still applies and is the only way to turn it on. Today that iscoinbasePaymentsandnowpaymentPayments, both written in the legacy array form (coinbasePayments: []), which a search foravailability: []does not find. Adding afliptKeyto one of these moves ownership to Flipt and makes its variable inert. - A flag declared
['public'](or any role) is live: creating its key withenabled: falseand no rollout turns the feature off for everyone — the intended kill switch, and the intended accident. Only if noFEATURE_FLAG_<KEY>variable names it. If one does, that kill switch is inert and nothing reports it.
To switch on a dark flag that has a fliptKey locally, set
FLIPT_LOCAL_OVERRIDES=<fliptKey>=on rather than touching shared flag state; it is ignored when
NODE_ENV=production, and it does not reach getFliptBoolean call sites. For a dark flag with
no key there is nothing to name here — use its FEATURE_FLAG_<KEY> variable.
Treat FLIPT_API_TOKEN as a live secret: read it from env, never inline it, and
don't copy it into anything new.
Flags live at /api/v2/environments/{env}/namespaces/{ns}/resources/flipt.core.Flag.
The environment (civitai-app) and namespace (default) are discovered at
runtime — the environment marked default: true, then its default namespace —
so a second environment can't silently redirect reads. Override with
FLIPT_ENVIRONMENT / FLIPT_NAMESPACE if ever needed.
Responses carry a revision equal to the flipt-state commit SHA, which is the
quickest way to confirm a flag change has actually synced:
node .claude/skills/flipt/flipt.mjs list --json | head -3 # revision == your commit
Options
| Flag | Description |
|---|---|
--description <text>, -d |
Description for new flag |
--enabled |
Create flag as enabled (default: disabled) |
--variant |
Create as variant flag (default: boolean) |
--variants <keys> |
Comma-separated variant keys (first is default) |
--default <key> |
Set default variant key |
--rollout <pct> |
Rollout percentage (default: 100) |
--segment <key> |
Segment key for rules (default: all-users) |
--json |
Output results as JSON |
--quiet, -q |
Minimal output |
--force, -f |
Skip confirmation prompts |
Examples
# List all flags
node .claude/skills/flipt/flipt.mjs list
# Get a specific flag
node .claude/skills/flipt/flipt.mjs get gift-card-vendor-waifu-way
# Creating / toggling a flag goes through GitOps — see below.
# These commands exit 2 and print the steps:
node .claude/skills/flipt/flipt.mjs disable my-feature
# JSON output for scripting
node .claude/skills/flipt/flipt.mjs list --json
GitOps Integration
Flipt uses GitOps - flags are stored in the civitai/flipt-state repository. Changes made via the API are temporary and will be overwritten on the next Git sync (every 30 seconds).
For permanent changes, edit the repository directly:
# Clone the state repo
gh repo clone civitai/flipt-state /tmp/flipt-state
# Edit civitai-app/default/features.yaml
# Add your flag under the `flags:` section
# Commit and push
cd /tmp/flipt-state
git add -A && git commit -m "Add new feature flag" && git push
Flag Format in YAML
flags:
- key: my-feature-flag
name: my-feature-flag
type: BOOLEAN_FLAG_TYPE
description: Description of what this flag controls
enabled: false
# Optional: rollout rules
rollouts:
- threshold:
percentage: 50
value: true
- segment:
keys:
- moderators
operator: OR_SEGMENT_OPERATOR
value: true
Safety Notes
- Do not write through the API: it pushes an unreviewed commit to
flipt-statemain - Test before enabling: Use segments for gradual rollout
- Coordinate with team: Others may be editing the same flags
Environment Setup
Copy .env.example to .env and configure:
cp .claude/skills/flipt/.env.example .claude/skills/flipt/.env
The skill needs FLIPT_URL and FLIPT_API_TOKEN to connect to Flipt.
🔴 THE SKILL'S OWN .env IS NOT OPTIONAL, AND THE ROOT .env IS NOT A SUBSTITUTE.
loadEnv reads this skill's .env and then the project root's, first value winning — so the
root's FLIPT_URL IS picked up when this file is absent, and that is the trap rather than the
rescue. The root's FLIPT_URL is the BROWSER-FACING host: every path under it answers 302 to a
GitHub OAuth login, so no bearer token will ever work against it. Measured 2026-10-05, after this
skill's .env had been lost: /meta/info, /health, /api/v1/namespaces,
/api/v2/environments and /evaluate/v1/boolean all 302 to the OAuth provider.
So adding only a token to the root .env leaves the skill broken in a WORSE way than it is
now: the "FLIPT_URL and FLIPT_API_TOKEN must be set" error disappears and is replaced by HTML
login pages failing to parse as JSON — a confusing failure instead of a clear one. Both values
belong in this skill's .env together.
FLIPT_FETCHER_SECRET, which the root .env does carry, is a DIFFERENT credential and is not
an API token — it does not authenticate these calls.
Ask an infra owner for the API endpoint and a read/query token. The specifics are
deliberately not written here: this repository is public, and how to reach a production service
past its proxy is exactly what the Security section of CLAUDE.md keeps out of it.
Once you have it, protect it — these files are one git clean from gone and this one has already
been lost once:
node .claude/skills/dev-server/cli.mjs wt env --backup # copies skill credentials outside the repo
Version History
-
b80af8e
Current 2026-10-20 06:21
文档补充了 .env 加载顺序陷阱,说明根目录 FLIPT_URL 会导致 OAuth 跳转错误,并重申生产凭证不应提交至公共仓库。
-
c706944
2026-09-23 10:05
修复环境变量覆盖逻辑:当标志声明为暗黑模式时,忽略环境变量覆盖,确保仅通过 Flipt 键控制开关状态。
- 4214ecb 2026-08-20 18:49


