Feature flags

Where Pulse reads feature flags from, how to change them, and what happens when the source is unavailable.

Feature flags turn product features on or off for a whole deployment, or for chosen workspaces, teams, roles or users. This page is for the people who run a Pulse deployment. Workspace settings are covered in Administration.

A flag only shows or hides a feature. It never grants access: a feature that is on still enforces the usual permissions.

Where flags come from

Flags live in pulse-api's own flag store. They are platform-wide, so one definition covers every workspace on the deployment. Every component reads them from pulse-api:

ComponentReads flags through
pulse-api and the schedulerthe flag store directly
Pulse Agent services (pulse-agent, pulse-ai)pulse-api's service evaluation endpoint
Web, Mac and iOS appspulse-api's client endpoint (POST /api/v1/ofrep/v1/evaluate/flags)

No client contacts Unleash.

Choosing the source

pulse-api, the scheduler and pulse-agent each pick their source with FEATURE_FLAGS_SOURCE:

ValueAnswers from
pulsepulse-api's flag store. Use this.
unleashAn Unleash server, set with UNLEASH_URL and UNLEASH_API_TOKEN. Without them, every flag answers its default. This is the variable's default, kept for older deployments.
noneNothing. Every flag answers its default.
FEATURE_FLAGS_SOURCE=pulse

An empty or unknown value stops the service from starting. Changing the source takes a restart.

  • Hosted Pulse runs on pulse. Unleash is no longer used.
  • pulse-ctl installations always run on pulse. pulse-ctl writes the setting itself and refuses FEATURE_FLAGS_SOURCE and any UNLEASH_* key in service_env.
  • pulse-ai has no setting. It always reads from pulse-api.

Unleash is optional. If you run it today, a platform administrator can copy its flags into the store with POST /api/v1/admin/feature-flags/import/unleash?dry_run=true. Remove dry_run to write. Flags that the store cannot represent, such as partial rollouts or variants, are reported instead of imported.

Under unleash, edits saved in the flag store have no effect. Switch to pulse before you manage flags in backoffice.

Default values

Each time pulse-api starts, it adds every flag it knows that the store doesn't hold yet, at that flag's default. A flag an administrator has changed is never reset, so a new installation needs no seeding.

FlagDefaultControls
pulse_agentonPulse Agent in the apps and the agent service
pulse_loopsonLoops: scheduled and event-triggered agent work. When it is off, Loop routes answer LOOPS_DISABLED and the apps hide Loops.
subagentsonPulse Agent sub-agents
project_coordinatoroffThe Project Coordinator agent
pulse_live_effects_offoffA kill switch: on turns off live visual effects in the web app.
pulse_judgmentsoffTypeSafe judgments in Pulse Agent. They send workspace text to typesafe.ai, so the flag stays off until an administrator turns it on.
environment_runner_routingoffRouting coding sessions to a runner from the environment's execution target
agent_appsoffThird-party agent apps

Changing a flag

A platform administrator changes flags in backoffice under Feature flags (/feature-flags), or through /api/v1/admin/feature-flags. Every change requires a signed-in session. An API key or an OAuth application token cannot change flags.

A flag is on, off or targeted. A targeted flag holds rules, and it is on when any rule matches. A rule matches when all of its conditions hold:

  • the workspace is one of the listed workspaces
  • the user is one of the listed users
  • the user belongs to one of the listed teams
  • the user's workspace role is one of the listed roles
  • the user is a platform admin

A targeted flag is off for everyone that no rule matches, whatever its default. Background work such as scheduled Loop runs has no user, so it matches only workspace conditions. Target pulse_loops by workspace.

Every change is kept in the flag's history. Archiving a flag is final: it then answers its default and can't be edited. To copy flags between deployments, export them with GET /api/v1/admin/feature-flags/export and import the file with POST /api/v1/admin/feature-flags/import.

Every service picks up a change within about a minute. Nothing needs a restart or a config apply.

On a deployment you configure yourself, UNLEASH_OVERRIDES=flag=true,other=false on pulse-api forces a value under every source. pulse-ctl doesn't accept it, so on a pulse-ctl installation change the flag in backoffice instead.

When the source is unavailable

A flag read never fails. When the source can't answer, every component falls back the same way:

SituationAnswer
No source (none, or unleash without a server)The flag's default.
Starting up, before the first answerThe last known value if there is one, otherwise the default. pulse_loops answers off here, so no Loop runs before the source has answered. Scheduled runs wait and retry.
The source stops answeringThe last known values, until it recovers by itself.
The source doesn't define the flagThe flag's default.

Backoffice's Feature flags screen warns when edits have no effect because the store is not the source. GET /api/v1/admin/feature-flags reports the source and whether it is ready or stale in status, and pulse-api exports the same as the pulse_feature_flag_source_ready{source} and pulse_feature_flag_source_stale{source} metrics.

Last updated on