关于 flag-targeting
用于为 GrowthBook 现有功能标志添加、编辑或移除定向规则的技能,面向管理用户分组发布策略的团队。它支持条件、已保存组和前置标志,并将改动保存在草稿中等待发布。
主要功能
- 01添加、编辑和移除规则
- 02支持强制值与百分比推出
- 03组合属性条件、已保存组和前置标志
- 04变更先进入草稿修订
适用场景
- 01向匹配属性的用户定向提供标志值
- 02逐步向一定比例用户推出功能
- 03按已保存组或其他标志设置规则
- 04调整现有规则的范围或条件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ growthbook/ skills --skill flag-targeting安装后在 Claude Code 中输入/flag-targeting确认已加载。
详细介绍
flag-targeting
在现有的 GrowthBook 功能标记上添加、编辑或移除定向规则。支持 force(向匹配的用户提供指定值)和 rollout(向随机比例的用户提供某个值)规则类型,并全面支持条件、已保存分组和规则级前置条件。
所有更改都要经过草稿修订,并且需要发布。发布时请使用 flag-publish — 它可以处理需要审批和合并冲突等失败情况。
所有 API 调用都通过捆绑的辅助工具执行:${CLAUDE_PLUGIN_ROOT}/scripts/gb-call。需要在环境变量中设置 GB_API_KEY,或通过 /growthbook:gb-setup 将其写入 ~/.config/growthbook/.env。
必需输入
开始前收集:
- Flag ID — kebab-case 键。使用 flag-search 根据描述查找。
- 操作 —
add、edit或remove。根据用户的请求推断;修改前先确认。
各操作所需输入
add
- 规则类型 —
force(指定用户)或rollout(百分比)。根据措辞推断:“X% 的用户” → rollout;“针对符合 Y 条件的用户” → force。 - 值 — 匹配时规则提供的值。必须与标记的
valueType相符,并序列化为字符串。 - 范围 —
allEnvironments: true或environments: [<env-ids>]。如果未指定,请询问。 - 条件(可选)— 已保存分组、属性条件,或另一个标记的前置条件(参见下方的条件决策树)。
- 对于 rollout 规则 —
coverage(0–1)和hashAttribute(当 coverage < 1 时必需)。 - 描述(可选,但建议提供)。
edit
- 规则 ID — 通过交互方式显示带编号的列表来确定(步骤 3b)。用户按编号选择。
- 补丁字段 — 仅包含用户希望更改的字段。
remove
- 规则 ID — 以与 edit 相同的方式确定。
工作流
- [ ] 1. Fetch flag and current state
- [ ] 2. Confirm the action (add / edit / remove)
- [ ] 3a. Add path
- [ ] 3b. Edit path
- [ ] 3c. Remove path
- [ ] 4. Hand off to flag-publish
1. 获取标记及当前状态
gb-call GET /api/v2/features/<flag-id>
记录:valueType、environmentSettings 键(可用环境 ID)以及 rules 数组(包含完整列表及 ID、类型、范围和启用状态)。如果返回 404,则停止并提示:“没有 ID 为 <flag-id> 的标记。”建议使用 flag-search。
2. 确认操作
如果用户的请求不明确,请在修改前询问。
3a. 添加流程
新规则会追加到 rules 数组末尾。规则按从上到下的顺序进行评估;第一个匹配项生效。如果标记已有规则,请说明:
“该标记已有
<N>条规则;这条新规则将最后评估。如果它需要优先于现有规则,请在添加后通过 flag-rules 调整顺序。”
预先验证 value 是否与 valueType 相符 — API 在写入时不会检查是否匹配:
boolean→ 必须为"true"或"false"number→ 必须能解析为数字json→ 必须是有效的 JSONstring→ 任意非空字符串
确定范围。 根据 environmentSettings 确认环境 ID。设置 allEnvironments: true 或 environments: [...] 其中之一 — 不可同时设置。
获取可用属性 — 在询问用户描述任何条件之前执行此操作。如果标记属于某个项目,将其作为 projectId 传入,以仅获取相关属性(组织范围 + 项目范围);对于组织范围的标记,则省略该参数:
# Flag has a project:
gb-call GET '/api/v1/attributes?projectId=<flag-project-id>'
# Flag is org-wide (no project):
gb-call GET /api/v1/attributes
按类型对返回的列表进行分组并展示给用户,同时指出重要的元数据:
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)
如果没有属性(或没有适用范围内的属性),请提示:“该项目尚未注册定向属性。请先在 Settings → Attributes 下添加属性,再进行定向。”
为 rollout 规则确定 hashAttribute(当 coverage < 1 时必需):
在筛选后的属性列表中,优先选择 hashAttribute: true 的条目。“按用户”默认使用 id;“按公司”则选择公司范围的属性。
一条规则包含三个可以自由组合的独立定向属性。确定适用的属性,然后在提交前构建所有相关字段。
condition — 基于属性的定向(MongoDB 风格的 JSON 字符串)
根据传入 SDK 的属性定位用户。从上方获取的筛选列表中选择属性。如果用户的描述无法明确对应到可用属性,请展示列表并让用户选择。拒绝任何不在筛选列表中的属性名称——未注册的属性在 SDK 求值时会被静默忽略。
将条件对象序列化为 JSON 字符串并放入载荷中。
| 类别 | 运算符 | 含义 |
|---|---|---|
| 相等 | $eq、$ne(或直接使用键/值表示 eq) | =、≠ |
| 比较 | $lt、$lte、$gt、$gte | <、≤、>、≥ |
| 语义化版本 | $veq、$vne、$vlt、$vlte、$vgt、$vgte | 感知版本号的比较——"1.0.10" > "1.0.9"。用于 format: version 属性。 |
| 集合成员关系 | $in、$nin | 属于其中任一项、不属于其中任何项(区分大小写) |
| 集合成员关系(不区分大小写) | $ini、$nini | 属于其中任一项/不属于其中任何项——忽略大小写 |
| 字符串包含 | $includes、$notIncludes | 字符串或数组包含/不包含指定值 |
| 正则表达式 | $regex、$notRegex | 匹配/不匹配模式(区分大小写) |
| 正则表达式(不区分大小写) | $regexi、$notRegexi | 同上,但忽略大小写 |
| 存在性 | $exists、$notExists | 不是 NULL / 是 NULL |
| 空值 | $empty、$notEmpty | 字符串或数组为空/不为空 |
| 布尔值 | $true、$false | 属性为真值/假值 |
| 类型 | $type | JS 类型等于指定值(例如 "string"、"number") |
| 数组 | $elemMatch、$all、$alli、$size | 元素符合条件;包含所有值($alli 不区分大小写);长度比较 |
| 已保存分组(原始) | $inGroup、$notInGroup | 按 ID 属于/不属于已保存分组——优先使用 savedGroups 规则字段 |
| 逻辑 | $or、$and、$nor、$not | 顶层键之间为 AND 关系;使用这些运算符表示 OR / 取反 |
关键规则:
- 多个顶层键之间为 AND 关系:
{"country": "US", "plan": "pro"}要求两者都匹配。 - 默认情况下,字符串比较区分大小写——需要时使用
$ini/$regexi变体。 - 条件由客户端 SDK 进行求值——属性值不会传到 GrowthBook 服务器。
- 只能使用此表中的运算符。未列出的 MongoDB 运算符(例如
$where、$expr)会被静默忽略,永远不会匹配。
示例:
{"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 — 已保存分组定位(单独的规则字段)
定位属于预定义已保存分组的用户。获取可用分组:
gb-call GET /api/v1/saved-groups
将该字段构建为分组引用数组:
"savedGroups": [
{ "ids": ["<sg-id>"], "match": "all" }
]
ids— 要引用的已保存分组 ID 数组match: "all"— 用户必须属于列出的所有分组;"any"— 用户必须属于至少一个分组
对于在标志之外管理的命名人群(“Beta 测试者”“内部用户”“企业账户”),请使用已保存分组。相比在 condition 字符串中手动编写 $inGroup,应优先使用此方式。
prerequisites — 规则级前置条件定位(单独的规则字段)
根据另一个功能标志的求值结果,决定是否启用此规则。如果前置条件对某位用户不成立,则跳过此规则并按顺序评估下一条规则——这与会跳过整个标志的功能级前置条件不同。
"prerequisites": [
{ "id": "<flag-id>", "condition": "{\"value\": true}" }
]
condition 字符串针对 { "value": <前置条件标志的求值结果> } 进行求值。value 是唯一有效的顶层键。
以下两种条件涵盖了 99% 的情况:
| 目标 | 条件 |
|---|---|
| 布尔标志已开启 | {"value": true} |
| 布尔标志已关闭 | {"value": false} |
| 非布尔标志处于生效状态(返回任意值) | {"value": {"$exists": true}} |
| 非布尔标志未处于生效状态 | {"value": {"$exists": false}} |
对于更具体的情况(例如字符串标志等于某个特定变体),可使用上方 condition 部分中的完整运算符表——但在编写复杂的前置条件前,请先让用户确认。
组合使用这三项: 这三个属性采用 AND 逻辑组合。只有当用户属于已保存的用户组、属性条件匹配且所有前置标志均通过时,设置了全部三个属性的规则才会触发:
{
"condition": "{\"country\": \"US\"}",
"savedGroups": [{ "ids": ["sg_beta"], "match": "all" }],
"prerequisites": [{ "id": "new-checkout", "condition": "{\"value\": true}" }]
}
模糊情形(“VIP 客户”“企业用户”)——询问:这是 GrowthBook 中的命名用户组(已保存的用户组)、用户记录上的属性(条件),还是两者都有?
| 用户说 | 使用的字段 |
|---|---|
| “为我们的 Beta 测试用户启用” | savedGroups |
| “美国的用户” | 对 country 属性使用 condition |
| “使用 5.2 或更高版本的 iOS 用户” | condition:{"platform": "ios", "appVersion": {"$vgte": "5.2"}} |
| “仅当 new-checkout 标志开启时” | prerequisites |
| “企业用户” | 询问——是已保存的用户组,还是 {"plan": "enterprise"} 条件? |
构建并 POST 该负载:
{
"rule": {
"type": "force",
"value": "<string>",
"description": "<optional>",
"enabled": true,
"allEnvironments": false,
"environments": ["production"],
"condition": "<optional JSON string>",
"savedGroups": [{ "ids": ["<sg-id>"], "match": "all" }],
"prerequisites": [{ "id": "<flag-id>", "condition": "{\"value\": true}" }]
}
}
对于渐进发布:将 type 替换为 "rollout",并添加 coverage 和 hashAttribute。省略空数组和空字符串。
echo '<payload>' | gb-call POST /api/v2/features/<flag-id>/revisions/new/rules -
记录 revision.version。
3b. 编辑路径
将规则显示为编号列表:
Rules on `<flag-id>`:
1. [force] all envs value="true" "Beta testers" (saved group)
2. [rollout] production 10% hash=id
3. [force] staging value="false" "Kill switch"
用户按编号选择。显示当前值,并询问要更改哪些字段。
**空补丁保护:**如果拟议更改与当前值完全相同,则停止操作——“没有要应用的更改”。无操作草稿会消耗速率限制额度,并可能通过 resetReviewOnChange 使先前授予的审批失效。
编辑时的规则类型行为:
- **显式更改
type会被服务器拒绝。**若要将强制规则转换为实验引用规则:先移除,再重新添加(3c,然后执行 3a 或 flag-experiment)。 - **
force↔rollout会根据有效覆盖率自动切换。**将coverage: 0.25补丁应用于强制规则会静默地将其转换为渐进发布(还需要hashAttribute)。在摘要中说明类型转换。
实验引用规则的编辑规则:
- 服务器会拒绝的补丁:
value、coverage、controlValue。尽早停止并说明原因。 - 需要警告并确认的补丁:
experimentId、variations。API 允许修改,但会导致标志与实验悄然偏离。需要明确确认:“直接更改experimentId/variations可能导致标志规则与实验偏离。实验是唯一事实来源。确定要更改吗?” - 可以安全编辑:
enabled、condition、savedGroups、prerequisites、作用范围、description。
**作用范围细节:**更改作用范围时,始终同时发送 allEnvironments 和 environments。只发送 environments 而不发送 allEnvironments,会导致服务器推断 allEnvironments: false,从而静默缩小作用范围。
echo '<patch>' | gb-call PUT /api/v2/features/<flag-id>/revisions/new/rules/<rule-id> -
记录 revision.version。
3c. 移除路径
显示编号列表。确认:
“要从
<flag-id>移除规则<N>(<type>、<scope>、<summary>)吗?此操作会生成草稿,只有发布后才会生效。”
gb-call DELETE /api/v2/features/<flag-id>/revisions/new/rules/<rule-id>
移除实验引用规则时:“移除这条规则不会影响关联的实验。”
记录 revision.version。
4. 移交给 flag-publish
进行任何修改后,询问:“现在发布此更改,还是将其保留为草稿?”
移交给 flag-publish。它会处理:
- 需要审批(400)——提供评审流程、组织级绕过或按令牌绕过选项
- 合并冲突(409)——显示冲突字段,收集覆盖/丢弃决定,然后变基
Guardrails
- 草稿版本串联。 如果本次会话中之前的写入技能已在上下文中提供版本号,请明确使用该版本号(例如
.../revisions/42/rules),而不是new。这样可确保串联使用多个技能时,所有更改都在同一草稿中。若从头开始,则使用new——它会通过resolveOrCreateRevision自动创建或复用最近更新的未关闭草稿。 - 规则 ID 是 UUID(
fr_...),不是位置编号。 始终从rules数组中解析,绝不要猜测。 force与rollout在服务端大多只是表面区别。coverage < 1的force规则实际上就是 rollout。默认使用force,除非用户提到“百分比”或指定了 coverage;服务端会自动转换。coverage < 1时必须提供hashAttribute。 发送 POST 请求前先验证。- 作用范围:
allEnvironments: true和environments: [...]必须且只能设置其中一项。 绝不能同时设置。 - 询问条件前,始终先获取属性。 如果该标记的作用范围限定在项目,请使用
?projectId=<id>,以便服务端只返回相关属性。提前展示属性列表。用户提供的属性名称必须先确认在返回列表中;未经注册的属性在 SDK 求值时会静默地始终不匹配。 - 条件是 JSON 字符串。 验证其是否可解析。优先使用已保存的分组,而不是手写条件——它们可重复使用且便于管理。
valueType不匹配可能造成严重问题。 v2 规则添加处理程序在写入时不会验证。务必先在客户端进行验证。- 拒绝空补丁。 无操作的版本更新会消耗速率限制额度,还可能重置审核批准。
- 新规则会追加到底部。 按顺序匹配,命中第一条后即停止。提交前说明评估顺序方面的注意事项。
- 禁止自我批准。 执行
request-review后不要尝试执行submit-review。 - **环境开关由
flag-toggle处理,**而不是此技能。此技能不会更改环境级别的启用/禁用状态。
使用的端点
GET /api/v2/features/:id— 获取标记状态、当前规则、环境列表和 valueTypeGET /api/v1/attributes— 获取属性;如果该标记的作用范围限定在项目,请传入?projectId=<id>;构建任何条件前先展示属性列表;rollout 时选择hashAttributeGET /api/v1/saved-groups— 解析用于定向的已保存分组POST /api/v2/features/:id/revisions/new/rules— 添加规则PUT /api/v2/features/:id/revisions/new/rules/:ruleId— 编辑规则DELETE /api/v2/features/:id/revisions/new/rules/:ruleId— 移除规则
移交
flag-toggle— 用于环境级别的启用/禁用(紧急开关)flag-rules— 用于重新排列规则或将其路由到其他规则类型flag-experiment— 用于添加 experiment-ref 或内联实验规则flag-ramp— 用于逐步提高 rollout 规则的覆盖率flag-monitoring— 用于为 rollout 添加防护指标监控flag-prerequisites— 用于设置功能级前置条件门控flag-search— 用于根据描述解析标记 IDflag-publish— 用于发布草稿(处理审批和合并冲突)