Targeting Rules
Targeting decides who gets what based on the evaluation context, plan, region, version, anything you pass. Rules run before the base rollout, so you can serve specific cohorts precisely and let everyone else fall through.
The shape
A flag's rules is an ordered array (max 64). Each rule has up to 32 conditions and serves either "on" or "off", optionally gated by its own rolloutPct.
type Rule = {
id: string;
description?: string;
conditions: Condition[]; // max 32, all must match (AND)
serve: "on" | "off";
rolloutPct?: number; // 0–100, gates this rule's served value
};
type Condition = {
attribute: string; // e.g. "plan", "region", "version"
op: Operator;
value: unknown;
};Operators
| Operator | Meaning |
|---|---|
eq / neq | Equals / not equals |
in / not_in | Value is (not) in a list |
contains | String contains substring |
gt / gte / lt / lte | Numeric comparisons |
semver_eq / semver_gt / semver_lt | Semantic-version comparisons |
Evaluation order
Rules are evaluated top to bottom. The first rule whose conditions all match decides the served value, optionally gated by that rule's rolloutPct. If no rule matches, the flag's base enabled + rolloutPct applies. Order your rules most-specific first.
A worked example
Serve the new checkout ON to all internal users, then to Pro users on version 4.2.0 or newer, but only 50% of them, and let everyone else fall through to the base config.
{
"rules": [
{
"id": "rule_internal",
"description": "Always on for staff",
"conditions": [
{ "attribute": "email", "op": "contains", "value": "@shipos.app" }
],
"serve": "on"
},
{
"id": "rule_pro_v42",
"description": "50% of Pro on v4.2+",
"conditions": [
{ "attribute": "plan", "op": "eq", "value": "pro" },
{ "attribute": "version", "op": "semver_gte", "value": "4.2.0" }
],
"serve": "on",
"rolloutPct": 50
}
]
}Passing attributes
Attributes come from the evaluation context you pass to the SDK, the userId and an attributes object. Rules match against these keys.
const useV2 = await shipos.flag("checkout-v2", {
userId: "u_42",
attributes: {
plan: "pro",
region: "eu",
version: "4.3.1",
email: "dana@shipos.app",
},
default: false,
});Setting rules
Set targeting via the MCP tool or the config API.
Claude → set_targeting {
key: "checkout-v2",
env: "prod",
rules: [ { id: "rule_pro_v42", conditions: [...], serve: "on", rolloutPct: 50 } ]
}
✅ checkout-v2 @ prod → 1 rulePUT https://app.shipos.app/api/v1/flags/{id}/environments/prod/config
Authorization: Bearer sos_agt_...
Content-Type: application/json
{
"expectedVersion": 7,
"rules": [
{ "id": "rule_pro_v42", "conditions": [ ... ], "serve": "on", "rolloutPct": 50 }
]
}Rules are validated before they save
Rules compose with rollouts and the base config, see how a value is chosen.