Install
$ agentstack add skill-growthbook-skills-flag-targeting ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
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 →About
flag-targeting
Add, edit, or remove targeting rules on an existing GrowthBook feature flag. Handles force (serve a specific value to matched users) and rollout (serve a value to a random percentage of users) rule types, with full support for conditions, saved groups, and rule-level prerequisites.
Every change goes through a draft revision and requires publishing. For publishing, use flag-publish — it handles approval-required and merge-conflict failure modes.
All API calls go through the bundled helper: ${CLAUDE_PLUGIN_ROOT}/scripts/gb-call. It needs GB_API_KEY set in env or written to ~/.config/growthbook/.env by /growthbook:setup.
Required inputs
Collect before starting:
- Flag ID — kebab-case key. Use flag-search to resolve from a description.
- Action —
add,edit, orremove. Infer from the user's request; confirm before mutating.
Per-action inputs
add
- Rule type —
force(specific users) orrollout(percentage). Infer from wording: "X% of users" → rollout; "for users matching Y" → force. - Value — what the rule serves when matched. Must match the flag's
valueType, serialized as a string. - Scope —
allEnvironments: trueorenvironments: []. Ask if not specified. - Conditions (optional) — saved group, attribute condition, or prerequisite on another flag (see conditions decision tree below).
- For rollout rules —
coverage(0–1) andhashAttribute(required when coverage
Capture: `valueType`, `environmentSettings` keys (available env IDs), `rules` array (full list with IDs, types, scope, enabled state). If 404, halt: "no flag with id ``." Suggest flag-search.
### 2. Confirm the action
If the user's request is ambiguous, ask before mutating.
### 3a. Add path
**New rules append to the bottom** of the rules array. Rules evaluate top-to-bottom; first match wins. If the flag already has rules, surface this:
> "The flag has `` existing rule(s); this new rule will be evaluated last. If it needs priority over an existing rule, reorder via flag-rules after adding."
**Pre-validate `value` against `valueType`** — the API doesn't catch mismatches at write time:
- `boolean` → must be `"true"` or `"false"`
- `number` → must parse as a number
- `json` → must be valid JSON
- `string` → any non-empty string
**Resolve scope.** Confirm the environment IDs against `environmentSettings`. Set either `allEnvironments: true` or `environments: [...]` — never both.
**Fetch available attributes** — do this before asking the user to describe any condition. If the flag has a project, pass it as `projectId` to get only relevant attributes (org-wide + project-scoped); omit it for org-wide flags:
```bash
# Flag has a project:
gb-call GET '/api/v1/attributes?projectId='
# Flag is org-wide (no project):
gb-call GET /api/v1/attributes
Surface the returned list to the user grouped by type, with notable metadata called out:
Available targeting attributes for this flag:
id (string, hashAttribute)
country (string, format: isoCountryCode)
app_version (string, format: version)
plan (enum: free|pro|enterprise)
is_employee (boolean)
If no attributes exist (or none are in scope), warn: "No targeting attributes are registered for this project. Add them under Settings → Attributes before targeting."
Resolve hashAttribute for rollout rules (required when coverage , ≥ | | Semantic version | $veq, $vne, $vlt, $vlte, $vgt, $vgte | Version-aware comparison — "1.0.10" > "1.0.9". Use on format: version attributes. | | Set membership | $in, $nin | is any of, is none of (case-sensitive) | | Set membership (case-insensitive) | $ini, $nini | is any of / none of — ignores case | | String contains | $includes, $notIncludes | string or array contains / does not contain value | | Regex | $regex, $notRegex | matches / does not match pattern (case-sensitive) | | Regex (case-insensitive) | $regexi, $notRegexi | same, ignores case | | Existence | $exists, $notExists | is not NULL / is NULL | | Emptiness | $empty, $notEmpty | string or array is empty / not empty | | Boolean | $true, $false | attribute is truthy / falsy | | Type | $type | JS type equals value (e.g. "string", "number") | | Array | $elemMatch, $all, $alli, $size | element matches condition; all values present ($alli = case-insensitive); length comparison | | Saved group (raw) | $inGroup, $notInGroup | in / not in a saved group by ID — prefer the savedGroups rule field instead | | Logical | $or, $and, $nor, $not | top-level keys are ANDed; use these for OR / negation |
Key rules:
- Multiple top-level keys are ANDed:
{"country": "US", "plan": "pro"}requires both. - String comparisons are case-sensitive by default — use
$ini/$regexivariants when needed. - Conditions are evaluated client-side by the SDK — attribute values never reach GrowthBook servers.
- Only use operators from this table. Unlisted MongoDB operators (e.g.
$where,$expr) silently never match.
Examples:
{"country": "US"}
{"country": {"$ini": ["us", "ca", "gb"]}}
{"plan": {"$ne": "free"}}
{"appVersion": {"$vgte": "3.0.0"}}
{"age": {"$gte": 18, "$lt": 65}}
{"email": {"$regexi": "@acme\\.com$"}}
{"$or": [{"country": "US"}, {"beta": true}]}
{"tags": {"$includes": "power-user"}}
{"company": {"$exists": true}, "plan": {"$in": ["pro", "enterprise"]}}
savedGroups — saved group targeting (separate rule field)
Targets users who belong to a pre-defined saved group. Fetch available groups:
gb-call GET /api/v1/saved-groups
Build the field as an array of group references:
"savedGroups": [
{ "ids": [""], "match": "all" }
]
ids— array of saved group IDs to referencematch: "all"— user must be in all listed groups;"any"— user must be in at least one
Use saved groups for named populations managed outside the flag ("beta testers", "internal users", "enterprise accounts"). Prefer this over hand-writing $inGroup in the condition string.
prerequisites — rule-level prerequisite targeting (separate rule field)
Gates this rule on the evaluated value of another feature flag. If the prerequisite condition fails for a user, this rule is skipped (the next rule in order is evaluated instead — distinct from feature-level prerequisites which skip the entire flag).
"prerequisites": [
{ "id": "", "condition": "{\"value\": true}" }
]
The condition string evaluates against { "value": }. value is the only valid top-level key.
The two conditions that cover 99% of cases:
| Goal | Condition | | --- | --- | | Boolean flag is on | {"value": true} | | Boolean flag is off | {"value": false} | | Non-boolean flag is live (returning any value) | {"value": {"$exists": true}} | | Non-boolean flag is not live | {"value": {"$exists": false}} |
For anything more specific (e.g. string flag equals a particular variant), the full operator table from the condition section above applies — but ask the user to confirm before writing complex prerequisite conditions.
Combining all three:
All three properties are ANDed together. A rule with all three set fires only when the user is in the saved group AND the attribute condition matches AND all prerequisite flags pass:
{
"condition": "{\"country\": \"US\"}",
"savedGroups": [{ "ids": ["sg_beta"], "match": "all" }],
"prerequisites": [{ "id": "new-checkout", "condition": "{\"value\": true}" }]
}
Ambiguous cases ("VIP customers", "enterprise users") — ask: is this a named group in GrowthBook (saved group), an attribute on the user record (condition), or both?
| User says | Field to use | | --- | --- | | "Turn it on for our beta testers" | savedGroups | | "Users in the US" | condition on country attribute | | "iOS users on version 5.2 or higher" | condition: {"platform": "ios", "appVersion": {"$vgte": "5.2"}} | | "Only when the new-checkout flag is on" | prerequisites | | "Enterprise users" | Ask — saved group or {"plan": "enterprise"} condition? |
Build and POST the payload:
{
"rule": {
"type": "force",
"value": "",
"description": "",
"enabled": true,
"allEnvironments": false,
"environments": ["production"],
"condition": "",
"savedGroups": [{ "ids": [""], "match": "all" }],
"prerequisites": [{ "id": "", "condition": "{\"value\": true}" }]
}
}
For rollout: swap type: "rollout", add coverage and hashAttribute. Omit empty arrays/strings.
echo '' | gb-call POST /api/v2/features//revisions/new/rules -
Capture revision.version.
3b. Edit path
Show the rules as a numbered list:
Rules on ``:
1. [force] all envs value="true" "Beta testers" (saved group)
2. [rollout] production 10% hash=id
3. [force] staging value="false" "Kill switch"
User picks by number. Surface current values; ask which fields to change.
Empty-patch guard: if the proposed changes match current values verbatim, halt — "no changes to apply." A no-op draft burns rate-limit budget and can invalidate previously-granted approvals via resetReviewOnChange.
Rule-type behavior on edit:
- Explicit
typechanges are server-rejected. To convert a force rule to an experiment-ref rule: remove and re-add (3c then 3a or flag-experiment). force↔rolloutauto-flips based on effective coverage. Patchingcoverage: 0.25onto a force rule silently converts it to rollout (also requireshashAttribute). Report the type transition in the summary.
experiment-ref edit rules:
- Server-rejected patches:
value,coverage,controlValue. Halt early with explanation. - Warn-and-confirm patches:
experimentId,variations. API allows them but causes silent flag/experiment drift. Require explicit confirmation: "ChangingexperimentId/variationsdirectly can cause the flag rule and experiment to drift. The experiment is the source of truth. Are you sure?" - Safe to edit:
enabled,condition,savedGroups,prerequisites, scope,description.
Scope subtlety: when changing scope, always send both allEnvironments and environments together. Sending only environments without allEnvironments causes the server to infer allEnvironments: false, silently narrowing scope.
echo '' | gb-call PUT /api/v2/features//revisions/new/rules/ -
Capture revision.version.
3c. Remove path
Show the numbered list. Confirm:
> "Remove rule ` (, , ) from `? This goes into a draft and only takes effect after publishing."
gb-call DELETE /api/v2/features//revisions/new/rules/
For experiment-ref removal: "The linked experiment is not affected by removing this rule."
Capture revision.version.
4. Hand off to flag-publish
After any mutation, ask: "Publish this change now, or leave it as a draft?"
Hand off to flag-publish. It handles:
- Approval-required (400) — offer review flow, org-wide bypass, per-token bypass
- Merge conflict (409) — show conflict fields, collect overwrite/discard decisions, rebase
Guardrails
- Draft version threading. If a version number is already in context from a previous write skill in this session, use it explicitly (e.g.
.../revisions/42/rules) instead ofnew. This keeps all changes in the same draft across chained skills. Fall back tonewwhen starting fresh — it auto-creates or reuses the most recently updated open draft viaresolveOrCreateRevision. - Rule ID is a UUID (
fr_...), not a position number. Always resolve from therulesarray — never guess. forcevsrolloutis mostly cosmetic server-side. A force rule withcoveragewhen the flag is project-scoped so the server returns only relevant attributes. Surface the list upfront. Never accept an attribute name the user provides without confirming it's in the returned list — unregistered attributes silently never match at SDK evaluation time.- Conditions are JSON strings. Validate they're parseable. Prefer Saved Groups over hand-written conditions — they're reusable and managed.
valueTypemismatch is a footgun. The v2 rule-add handler doesn't validate at write time. Always pre-validate client-side.- Refuse empty patches. A no-op revision update burns rate limit and can reset review approvals.
- New rules append to the bottom. First match wins. Surface evaluation order concerns before posting.
- Self-approval blocked. Don't attempt
submit-reviewafterrequest-review. - Environment toggles are handled by flag-toggle, not this skill. This skill does not touch env-level enable/disable.
Endpoints used
GET /api/v2/features/:id— fetch flag state, current rules, env list, valueTypeGET /api/v1/attributes— fetch attributes; pass?projectId=when the flag is project-scoped; surface upfront before building any condition; pickhashAttributefor rolloutsGET /api/v1/saved-groups— resolve saved groups for targetingPOST /api/v2/features/:id/revisions/new/rules— add rulePUT /api/v2/features/:id/revisions/new/rules/:ruleId— edit ruleDELETE /api/v2/features/:id/revisions/new/rules/:ruleId— remove rule
Handoffs
flag-toggle— for environment-level enable/disable (kill switch)flag-rules— for reordering rules or routing to other rule typesflag-experiment— for adding experiment-ref or inline experiment rulesflag-ramp— to progressively increase coverage on a rollout rule over timeflag-monitoring— to add guardrail metric monitoring to a rolloutflag-prerequisites— for feature-level prerequisite gatesflag-search— to resolve a flag ID from a descriptionflag-publish— to publish the draft (handles approval and merge conflicts)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: growthbook
- Source: growthbook/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.