Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

83 lines
4.0 KiB
Markdown

# Feature Flags
Feature flags in Tutti are **pure config distribution**: durable storage in
daemon preferences, push to clients over the eventstream, a key registry, and
a query helper. The infrastructure is semantics-free — it stores and
distributes `map[string]bool` and nothing more. Each feature owns what "off"
means; that logic never belongs to the flag infrastructure.
## Taxonomy
- **Capability flags** gate daemon-enforced behavior (writes, orchestration,
runtime operations). The daemon must enforce them server-side so toggling
the UI cannot bypass the gate. Query them through the daemon registry
helper, never by poking the raw map.
- **UI-preference flags** only show or hide renderer surfaces. The renderer
catalog is sufficient; no daemon enforcement is required.
A flag can start as UI-preference and gain daemon enforcement later; keep the
same key when that happens.
`lab.connectors` is a capability flag whose owning surfaces span renderer
settings, daemon composition, and daemon-projected Composer Options. The daemon
reads it fail-closed during startup. When it is off, the Connector market,
runtime, MCP gateway, Agent runtime projection, and `tutti connector` command
provider are not constructed; consequently Connector policy is not injected
into Agent system prompts. Existing installed state remains on disk. Changing
the flag takes effect for daemon-owned Connector capabilities after the daemon
restarts. Renderer off semantics also remove the Connectors settings entry,
connector setup deep links, and connector entries from the Agent composer, and
the AgentGUI footer uses Tutti Mode as that slot's fallback. Renderer
projections must filter cached connector palette rows while the daemon-backed
Composer Options reread is in flight.
## Key contract
The daemon registry is the key contract:
- Go: `services/tuttid/biz/preferences/lab_flags.go`
- Renderer mirror: `apps/desktop/src/shared/featureFlags/catalog.ts`
Both must carry **identical keys and defaults**. When adding, renaming, or
removing a flag, change both sides in the same change. Storage and push are
already generic (`DesktopPreferences.FeatureFlags`,
`NormalizeDesktopFeatureFlags`, preferences eventstream updates), so a new
flag only needs registry entries and copy.
When a feature graduates, remove its registry entries and every owning-feature
gate in the same change. Historical stored values may remain in generic
preferences for compatibility, but graduated features must not consult them;
this makes the feature available to existing profiles even when their old
value was `false`.
Resolution rule on both sides: a stored value wins; absent keys fall back to
the registry default; absent unregistered keys resolve to `false`
(`IsLabFlagEnabled` in Go, `isFeatureEnabled` in TS).
## Defaults and off semantics
- Defaults are **fail-closed**: every Lab flag defaults to `false`. A flag
that must default on needs an explicit product decision recorded in the PR.
- Recommended default-off semantics (guidance, not a mandate): while a flag is
off, new writes are rejected or hidden, but existing data and already
running behavior are left unaffected. The owning feature decides and
documents its exact semantics.
## Naming
- `lab.*` for Lab experiments surfaced in the Lab settings section.
- Domain-scoped dotted keys for everything else, for example
`agent.extension.<source>` or `browser.chromeCookieImport`.
- Keys are lowercase camelCase segments joined by dots.
## Existing reference pattern
`services/tuttid/service/agentextension/manager.go` is the existing example
of feature-owned semantics: stable sources are enabled by generated product
configuration and ignore retired stored activation values, while Early Access
sources derive their own keys (`"agent.extension."+source.Key`) and decide what
disabled means (reconcile and stop). New consumers should prefer registry
constants and `IsLabFlagEnabled` over poking the raw map, while keeping their
own off and graduation semantics in the owning feature, exactly as the Agent
Extension manager does.