flags

package
v0.6.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package flags provides a layered feature flag resolver for the ox CLI.

Flags are resolved from multiple sources in ascending priority order:

defaults → daemon (remote settings) → env vars

Each source returns a Patch — only the fields it has an explicit opinion on. Nil fields in a Patch mean "no opinion" and won't override prior values. This lets sources be added or removed without changing merge semantics.

Usage:

// At CLI startup (zero network calls):
flags.Init(ctx, flags.DaemonProvider{CachedSettings: s}, flags.EnvProvider{})

// Anywhere in the process:
if flags.Get().DistillEnabled { ... }

Index

Constants

View Source
const CLISettingsFetchTimeout = 3 * time.Second

CLISettingsFetchTimeout is the maximum time to wait for /api/v1/cli/settings. Fail fast: if the server is slow, use cached/default values immediately.

View Source
const CLISettingsMaxAge = time.Hour

CLISettingsMaxAge is the maximum age of a cached CLISettingsResponse before it is considered stale. Stale cache is still used — the daemon refreshes in the background. This matches the 1-hour polling interval.

Variables

This section is empty.

Functions

func Init

func Init(ctx context.Context, providers ...Provider)

Init resolves flags from the given providers and stores the result globally. Providers are applied in the order given; later providers have higher priority. Safe to call multiple times (e.g., after daemon contact). Cost: no network calls — providers must not perform I/O during Patch().

func SaveCachedSettings

func SaveCachedSettings(endpointURL string, r *CLISettingsResponse) error

SaveCachedSettings atomically writes r into a per-endpoint cache file. Creates the cache directory if needed. Each endpoint writes its own file, so concurrent writes for different endpoints cannot race or lose each other's data.

Types

type CLIFeatures

type CLIFeatures struct {
	CodeDB      *bool `json:"codedb,omitempty"`
	Whisper     *bool `json:"whisper,omitempty"`
	Distill     *bool `json:"distill,omitempty"`
	AutoDistill *bool `json:"auto_distill,omitempty"`
	TUI         *bool `json:"tui,omitempty"`
}

CLIFeatures contains server-evaluated feature gate values. Fields are *bool so omitted JSON fields remain nil ("no opinion") rather than being zero-valued to false, which would incorrectly override default-on flags during rolling upgrades when the server hasn't added a new flag yet.

type CLIKillswitches

type CLIKillswitches struct {
	DisableFileDeleteTools bool `json:"disable_file_delete_tools"`
	DisableShellExecTools  bool `json:"disable_shell_exec_tools"`
}

CLIKillswitches contains server-evaluated kill switch values. All fields default to false (kill switches off) when the endpoint is unavailable.

type CLISettingsResponse

type CLISettingsResponse struct {
	Features     CLIFeatures     `json:"features"`
	Killswitches CLIKillswitches `json:"killswitches"`
	// PrimeAppend is appended to ox agent prime output after team context.
	// Allows the cloud to push org-wide prime additions without a CLI release.
	PrimeAppend string    `json:"prime_append,omitempty"`
	FetchedAt   time.Time `json:"fetched_at"`
}

CLISettingsResponse is the wire type for GET /api/v1/cli/settings.

sage-mono evaluates PostHog feature flags server-side (using device_id + user_id as distinct IDs) and returns pre-evaluated booleans. The ox CLI receives evaluated values — no PostHog SDK is needed in the CLI binary.

If the endpoint is unreachable, Defaults are used. The daemon polls this endpoint on a background interval (see ox-ha7r) and caches the result to disk so CLI startup never blocks on a network call.

func LoadCachedSettings

func LoadCachedSettings(endpointURL string) (*CLISettingsResponse, error)

LoadCachedSettings reads the cached CLISettingsResponse for the given endpoint. Returns nil with no error if the file doesn't exist or is corrupt — callers treat nil as "no cached settings, use defaults".

type DaemonProvider

type DaemonProvider struct {
	// CachedSettings is populated by the daemon IPC settings_get handler.
	// Nil means the daemon has not yet fetched remote settings.
	CachedSettings *CLISettingsResponse
}

DaemonProvider reads a pre-fetched CLISettingsResponse from the daemon IPC cache. At CLI startup, initFeatureFlags() queries the daemon via IPC (settings_get) and falls back to disk cache. The daemon polls GET /api/v1/cli/settings on a background interval (CLISettingsMaxAge).

func (DaemonProvider) Patch

func (p DaemonProvider) Patch(_ context.Context) (*Patch, Source, error)

type EnvProvider

type EnvProvider struct{}

EnvProvider reads FEATURE_* environment variables and maps them onto flag fields. Only variables that are explicitly set (non-empty) contribute a patch — unset variables leave the corresponding field nil (no opinion).

This preserves backward compatibility with the existing FEATURE_* conventions in internal/auth/feature.go without requiring changes to those call sites.

func (EnvProvider) Patch

func (EnvProvider) Patch(_ context.Context) (*Patch, Source, error)

type Flags

type Flags struct {
	// Feature gates — default true for authenticated users.
	// A server-side kill switch or env override can set these false.
	CodeDBEnabled  bool
	WhisperEnabled bool
	DistillEnabled bool
	AutoDistill    bool
	TUIEnabled     bool

	// Kill switches — default false (not activated).
	// Any source setting these true disables the capability.
	DisableFileDeleteTools bool
	DisableShellExecTools  bool

	// PrimeAppend is injected after team context in ox agent prime output.
	// Set by the remote settings endpoint to push org-wide prime additions
	// without requiring a CLI release or changes to CLAUDE.md.
	PrimeAppend string
}

Flags is the fully resolved set of feature flags for the current process. All fields have safe defaults via Defaults.

func Defaults

func Defaults() Flags

Defaults returns the baseline Flags used when no provider has an opinion. Feature gates are on; kill switches are off; string fields are empty.

func Get

func Get() Flags

Get returns the current process-wide resolved flags. Returns Defaults() if Init has not been called.

func Resolve

func Resolve(ctx context.Context, providers ...Provider) Flags

Resolve merges patches from all providers in order (lowest to highest priority) and returns the final Flags. Starts from Defaults so every field has a safe value even if no provider has an opinion on it.

type Patch

type Patch struct {
	CodeDBEnabled  *bool
	WhisperEnabled *bool
	DistillEnabled *bool
	AutoDistill    *bool
	TUIEnabled     *bool

	DisableFileDeleteTools *bool
	DisableShellExecTools  *bool

	PrimeAppend *string
}

Patch is a partial flag override from a single source. Nil fields mean "no opinion" — they are skipped during merge. NOTE: When adding fields, also update allNil() in env.go and applyPatch() in resolve.go.

func RemoteSettingsToPatch

func RemoteSettingsToPatch(r *CLISettingsResponse) *Patch

RemoteSettingsToPatch converts a CLISettingsResponse into a Patch. Called by the daemon after a successful fetch before caching.

type Provider

type Provider interface {
	Patch(ctx context.Context) (*Patch, Source, error)
}

Provider supplies a partial set of flag overrides from one source. Returning (nil, source, nil) means this provider has no opinion right now.

type Source

type Source int

Source identifies where a Patch came from, used by ox status display.

const (
	SourceDefault Source = iota // hardcoded safe defaults
	SourceDaemon                // daemon IPC cache of /api/v1/cli/settings
	SourceEnv                   // FEATURE_* environment variable overrides
)

func (Source) String

func (s Source) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL