# Feature flags

> For agents: start with the [agent guide](https://ratstack.sh/llms.txt). Every page is Markdown by default; add `Accept: text/html` for HTML.

Free workshop: [how to burn a trillion tokens and get good results](/tokenmaxx#interested).

## What it does

The `packages/flags` [cartridge](/lore/cartridges) evaluates typed flags.
A flag declares its name, [schema](/lore/schemas-define-the-boundary), default, owner, and removal date.

Handlers request the `Flags` [service](/lore/services-capture-dependencies) from core.
The Config [adapter](/lore/hexagonal-architecture) reads deployment configuration.
The memory adapter supplies rules for tests.

- `listFlags` lists names, owners, and removal dates.
- `getFlag` evaluates one flag for an optional subject.
- Allow-lists select a value for named subjects.
- Percentage rules use a stable hash of the flag name and subject.
- The first matching rule wins. Missing subjects use the default.

`EVENTS_ENABLED` defaults to `false`.
`EVENTS_IDENTITY_MODE` defaults to `daily`.
Config keeps the existing environment keys and boolean spellings.

[Alchemy](/skills/learn-alchemy) still selects analytics resources during deployment.
See [Analytics](/systems/analytics) for capture and identity behavior.

## The standard

- Flag values pass their declared schemas.
- Every declaration names an owner and a `removeBy` date.
- Lint rejects declarations without a literal removal date.
- The flags build rejects expired registered events flags with a typed repair message.
- Each subject keeps its rollout bucket when the rollout percentage changes.
- The lifecycle permits `declared` → `rollingOut` → `on` → `removed`.
- Declared [Effect](/lore/effect-basics) actors record lifecycle transitions. Removed flags stay removed.
- Each [capability](/systems/capabilities) shares its contract across surfaces. JSON encoding is required for `getFlag`.

This cartridge has no live storage or write capability.
Config remains the authority for deployment values.
The lifecycle journal is scoped memory, with no durable state between processes.

## How to check

1. Run `pnpm --filter @rat-stack/flags test` for rollout properties, adapters, and generated lifecycle histories.
2. Run `pnpm --filter @rat-stack/core exec vitest run test/patterns-rule.test.ts` for the removal-date [fence](/lore/the-fence).
3. Run `pnpm turbo run check test build --concurrency=1` for the full gate.
4. Inspect the deployment plan. Resource actions must remain unchanged for the same configuration.

To remove the cartridge, replace `flagsLayer` in `apps/mischief/src/flags.ts` with `Flags.defaults(eventFlags)` from core.
Remove the package dependency and its directory.
Callers and capabilities keep their typed defaults.

## Sources

1. [Flags cartridge](https://github.com/joelhooks/rat-stack/tree/main/packages/flags)
   rat-stack. Evaluation, Config and memory adapters, lifecycle, and behavior tests. Accessed 2026-10-08.

## Lore on this page

- [Cartridges](/lore/cartridges)

## Linked from

- Agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms.txt)

- Change log → What changed in the files served here, newest first. → [Read page](https://ratstack.sh/log)

- Full agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms-full.txt)

- Rat Stack systems | rat-stack → The systems rat-stack ships, the standard each keeps, and how to check it. → [Read page](https://ratstack.sh/systems)

- Source change history (log.md) → The generated change log as Markdown. → [Read page](https://ratstack.sh/log.md)
