config

package
v1.42.0 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2026 License: AGPL-3.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// InstanceLockFileName is the exclusive, process-lifetime lock file used
	// to prevent two stapler-squad server processes from running against the
	// same config/DB directory at once.
	InstanceLockFileName = "instance.lock"
	// DefaultInstanceLockTimeout bounds how long a starting process waits for
	// a prior process to release the instance lock before giving up. Matches
	// scripts/install-service.sh's wait_for_port_release budget so a normal
	// service restart doesn't spuriously fail here.
	DefaultInstanceLockTimeout = 10 * time.Second
)
View Source
const (
	StateFileName     = "state.json"
	InstancesFileName = "instances.json"
)
View Source
const (
	// DefaultLockTimeout is the default timeout for acquiring locks
	DefaultLockTimeout = 5 * time.Second
	// LockFileName is the name of the lock file
	LockFileName = "state.lock"
)
View Source
const (
	ConfigFileName = "config.json"
)
View Source
const DiscoveryConfigFileName = "discovery.json"

Variables

View Source
var (
	ErrConfigNotFound = fmt.Errorf("config file not found")
	ErrInvalidConfig  = fmt.Errorf("invalid config file")
	ErrInvalidJSON    = fmt.Errorf("invalid JSON")
)

Common errors for Claude config operations

View Source
var ErrAliasNotFound = errors.New("alias not found")

ErrAliasNotFound is returned by ResolveAlias when no alias matches the given name.

Functions

func AcquireInstanceLock added in v1.42.0

func AcquireInstanceLock(configDir string, timeout time.Duration) (*flock.Flock, error)

AcquireInstanceLock takes an exclusive lock on instance.lock in configDir, retrying until timeout elapses. Unlike the PID/port-based liveness checks documented in .claude/rules/service-restart-orphan-process.md, the OS releases a flock the moment the holding process's file descriptors close — including on an unclean exit or reparenting to PID 1 — so a prior process that launchd/systemd has lost track of still can't hold this lock forever.

Returns the acquired *flock.Flock; the caller must keep it alive for the life of the process and Unlock() it on shutdown.

func DefaultLauncherPresetsPath added in v1.42.0

func DefaultLauncherPresetsPath() (string, error)

DefaultLauncherPresetsPath returns the resolved path to launcher-presets.json, honoring the same instance-isolation rules as the rest of config/ (GetConfigDir).

func EnsureWorkspaceMeta

func EnsureWorkspaceMeta()

EnsureWorkspaceMeta writes workspace metadata for the current configuration directory. Should be called once at server startup. Skips test mode directories.

func ExpandEnvVars added in v1.35.0

func ExpandEnvVars(m map[string]string) map[string]string

ExpandEnvVars expands ${VAR_NAME} tokens in map values using os.LookupEnv. If any referenced env var is not set (vs. set to ""), the key is omitted from the result and a warning is logged.

func GetAliasesByGroup added in v1.35.0

func GetAliasesByGroup(cfg *Config) map[string][]AliasConfig

GetAliasesByGroup groups all aliases by their Group field. Aliases without a Group are stored under the empty-string key "".

func GetAvailablePrograms

func GetAvailablePrograms() []string

GetAvailablePrograms is a package-level convenience wrapper using the default executor. Callers that need a custom executor should use NewConfigWithExecutor(exec).GetAvailablePrograms().

func GetClaudeCommand

func GetClaudeCommand() (string, error)

GetClaudeCommand is a package-level convenience wrapper using the default executor. Callers that need a custom executor should use NewConfigWithExecutor(exec).GetClaudeCommand().

func GetClaudeDir

func GetClaudeDir() (string, error)

GetClaudeDir returns the path to the ~/.claude directory

func GetConfigDir

func GetConfigDir() (string, error)

GetConfigDir returns the path to the application's configuration directory with hierarchical isolation for safe multi-instance and test execution.

Priority hierarchy:

  1. Test directory override via STAPLER_SQUAD_TEST_DIR (for --test-mode flag)
  2. Explicit instance ID via STAPLER_SQUAD_INSTANCE environment variable
  3. Test mode auto-detection (automatic isolation for tests/benchmarks)
  4. Preferred workspace from preference file (explicit switch via SwitchDatabase RPC)
  5. Per-directory workspace isolation, opt-in via STAPLER_SQUAD_WORKSPACE_MODE=true
  6. Global shared state (default)

func GetConfigDirForDir added in v1.35.0

func GetConfigDirForDir(dir string) (string, error)

GetConfigDirForDir returns the path to the application's configuration directory using the provided directory for workspace-based isolation.

func GetPreferredWorkspaceFile

func GetPreferredWorkspaceFile(baseDir string) string

GetPreferredWorkspaceFile returns the path to the preferred workspace preference file.

func ImportSessionEnabled added in v1.42.0

func ImportSessionEnabled() bool

ImportSessionEnabled reports whether the import-external-session feature (Phase 1: ssq-mux single-session import) is enabled. Unlike GetFeatureFlag, this is a plain environment variable rather than a persisted config flag — the feature involves signaling live, unmanaged processes (SIGSTOP/SIGCONT) outside Stapler Squad's own supervision, so it defaults to a deliberate, explicit opt-in per deployment/session rather than a UI-toggleable persisted setting. Re-read on every call (not cached) so it can be flipped without a server restart, matching the re-read behavior of GetFeatureFlag.

func IsIsolatedInstance added in v1.39.0

func IsIsolatedInstance() bool

IsIsolatedInstance reports whether this process's config/DB state is isolated from the shared default (~/.stapler-squad) directory by ANY known mechanism: a `go test` binary (IsTestMode), an explicit named instance (IsNamedInstance), or a STAPLER_SQUAD_TEST_DIR override (GetConfigDirForDir priority 1 — used by --test-mode harnesses like tests/demo/helpers.go's StartDemoServer). Isolated DB state does NOT imply an isolated tmux socket under any of these mechanisms — see IsNamedInstance's doc comment for the confirmed incident that motivated this check. Call sites that could otherwise touch shared, non-isolated resources (like the default tmux socket in ReconcileOrphanedTmuxSessions) must skip when this is true. STAPLER_SQUAD_TEST_DIR was the still-missing case: a demo/test-mode harness process gets a fully isolated DB via GetConfigDirForDir but, before this check existed, its startup orphan sweep still targeted the shared default tmux socket — killing every real production session it didn't recognize.

func IsNamedInstance added in v1.39.0

func IsNamedInstance() bool

IsNamedInstance reports whether this process is running as an explicitly named, non-default instance (STAPLER_SQUAD_INSTANCE set to anything other than "" or "shared" — see GetConfigDirForDir's priority hierarchy above). A named instance gets its own isolated DB/config directory but does NOT get its own tmux socket — it shares the default tmux server with every other instance on the machine, including the real production one. IsTestMode() alone doesn't catch this: this repo's own E2E harness (tests/e2e, per CLAUDE.md: "STAPLER_SQUAD_INSTANCE=e2e-local ./stapler-squad --tmux-keep-server") runs the real production binary, not a `go test` binary, so IsTestMode() returns false for it even though it has exactly the same "small, isolated instance list vs. the shared tmux socket" hazard a `go test` binary does. Confirmed live: an e2e-local run's orphan sweep killed 5 unrelated production tmux sessions it had never heard of, including the interactive session this very fix was written in.

func IsTestMode added in v1.35.0

func IsTestMode() bool

IsTestMode detects if the application is running in test/benchmark mode

func SaveConfig

func SaveConfig(config *Config) error

SaveConfig exports the saveConfig function for use by other packages.

func SaveDiscoveryConfig

func SaveDiscoveryConfig(config *DiscoveryConfig) error

SaveDiscoveryConfig saves the discovery configuration to disk

func SaveState

func SaveState(state *State) error

SaveState saves the state to disk with locking.

func SetPreferredWorkspace

func SetPreferredWorkspace(baseDir, configDir string) error

SetPreferredWorkspace atomically writes the preferred workspace config dir path. Pass configDir="" to clear the preference.

Types

type AliasConfig added in v1.35.0

type AliasConfig struct {
	// Name is the unique alias identifier (e.g. "myproj"). Must match ^[\w-]+$.
	Name string `json:"name"`
	// Group is an optional display group for palette organization.
	Group string `json:"group,omitempty"`
	// Path is the working directory for the session (supports ~/... expansion).
	Path string `json:"path,omitempty"`
	// Description is a human-readable summary shown in the palette.
	Description string `json:"description,omitempty"`
	// Profile is the named profile to apply when resolving defaults.
	Profile string `json:"profile,omitempty"`
	// Program overrides the default program (e.g. "aider").
	Program string `json:"program,omitempty"`
	// AutoYes auto-approves all prompts for this alias.
	AutoYes bool `json:"auto_yes,omitempty"`
	// Tags are pre-applied to sessions created from this alias.
	Tags []string `json:"tags,omitempty"`
	// EnvVars are environment variables set for sessions from this alias.
	EnvVars map[string]string `json:"env_vars,omitempty"`
	// CLIFlags are CLI flags appended to the program command for this alias.
	// At session creation, invocation-time extraFlags are appended after these.
	CLIFlags string `json:"cli_flags,omitempty"`
	// SessionType overrides the session creation mode for this alias.
	// SessionTypeDefault (empty) means use the default (directory session).
	SessionType SessionType `json:"session_type,omitempty"`
	// NamePrefix is prepended to the user-supplied session label when naming sessions.
	// For example, prefix "ssq-" + label "my-feature" → session name "ssq-my-feature".
	NamePrefix string `json:"name_prefix,omitempty"`
}

AliasConfig defines a named session preset invoked via @name in the omnibar. Name must match ^[\w-]+$ (letters, digits, hyphens, underscores only).

func FindAlias added in v1.35.0

func FindAlias(cfg *Config, name string) *AliasConfig

FindAlias returns the AliasConfig with the given name (case-insensitive), or nil if not found.

type AppState

type AppState interface {
	// GetHelpScreensSeen returns the bitmask of seen help screens
	GetHelpScreensSeen() uint32
	// SetHelpScreensSeen updates the bitmask of seen help screens
	SetHelpScreensSeen(seen uint32) error
}

AppState handles application-level state

type BrowserPassthroughCDPConfig added in v1.35.0

type BrowserPassthroughCDPConfig struct {
	// ScreencastQuality is the JPEG compression quality (1–100).
	// Default: 70.
	ScreencastQuality int `json:"screencast_quality,omitempty"`
	// ScreencastMaxWidth is the maximum frame width in pixels.
	// Default: 1280.
	ScreencastMaxWidth int `json:"screencast_max_width,omitempty"`
	// ScreencastMaxHeight is the maximum frame height in pixels.
	// Default: 800.
	ScreencastMaxHeight int `json:"screencast_max_height,omitempty"`
	// ScreencastMaxFPS is the target frame-rate cap (frames per second).
	// Default: 15 (one frame delivered every ~67 ms via everyNthFrame heuristic).
	ScreencastMaxFPS int `json:"screencast_max_fps,omitempty"`
}

BrowserPassthroughCDPConfig holds tunable parameters for the Chrome DevTools Protocol screencast stream. All fields default to zero (use CDPConfigOrDefault to apply canonical defaults).

func (*BrowserPassthroughCDPConfig) CDPConfigOrDefault added in v1.35.0

CDPConfigOrDefault returns a BrowserPassthroughCDPConfig with any zero-value fields replaced by the canonical defaults. This allows a partial JSON config (e.g. only ScreencastQuality set) to inherit the remaining defaults.

type BrowserPassthroughConfig added in v1.35.0

type BrowserPassthroughConfig struct {
	// Enabled controls whether VNC is started for new sessions.
	// When nil (absent from config), VNC is enabled when required binaries are present.
	// Set to false to unconditionally disable VNC for all sessions.
	Enabled *bool `json:"enabled,omitempty"`
	// DisplayBase is the first X11 display number to allocate (e.g. 100 for :100).
	// Default: 100.
	DisplayBase int `json:"display_base,omitempty"`
	// DisplayRangeMax is the number of display numbers to search above DisplayBase.
	// Default: 100 (searches :100–:199).
	DisplayRangeMax int `json:"display_range_max,omitempty"`
	// Resolution is the Xvfb screen resolution string (WxHxDepth).
	// Default: "1280x800x24".
	Resolution string `json:"resolution,omitempty"`
	// CDP holds tunable parameters for the CDP screencast stream.
	// Absent (zero) values are filled in by CDPConfigOrDefault().
	CDP BrowserPassthroughCDPConfig `json:"cdp,omitempty"`
}

BrowserPassthroughConfig controls the per-session virtual display (Xvfb + x11vnc) feature.

func (*BrowserPassthroughConfig) IsEnabled added in v1.35.0

func (c *BrowserPassthroughConfig) IsEnabled() bool

IsEnabled returns false unless the user has explicitly set enabled=true. When Enabled is nil (absent from config), browser passthrough is disabled.

type CapacityConfig added in v1.35.0

type CapacityConfig struct {
	// TransitionMode controls auto vs manual transition. Default: "manual".
	TransitionMode TransitionMode `json:"transition_mode,omitempty"`
	// ContextWindowWarnPct is the context usage percentage to trigger a warning. Default: 0.75.
	ContextWindowWarnPct float64 `json:"context_window_warn_pct,omitempty"`
	// ContextWindowAutoPct is the context usage percentage to trigger auto-transition (in auto mode). Default: 0.90.
	ContextWindowAutoPct float64 `json:"context_window_auto_pct,omitempty"`
	// RateLimitWarnRemaining triggers a warning when remaining requests fall below this. Default: 10.
	RateLimitWarnRemaining int `json:"rate_limit_warn_remaining,omitempty"`
	// CostBudgetUSD is the accumulated USD cost limit. 0 means no limit. Default: 0.
	CostBudgetUSD float64 `json:"cost_budget_usd,omitempty"`
	// PollIntervalSeconds controls limit API querying frequency. Default: 60.
	PollIntervalSeconds int `json:"poll_interval_seconds,omitempty"`
	// ProviderPriority lists fallback providers in order of preference.
	ProviderPriority []ProviderPriority `json:"provider_priority,omitempty"`
}

CapacityConfig holds configuration for the provider capacity monitoring and transition feature.

func (CapacityConfig) CapacityConfigOrDefault added in v1.35.0

func (c CapacityConfig) CapacityConfigOrDefault() CapacityConfig

CapacityConfigOrDefault returns a CapacityConfig with standard defaults applied to zero fields.

type ClaudeConfigManager

type ClaudeConfigManager struct {
	// contains filtered or unexported fields
}

ClaudeConfigManager manages access to Claude configuration files located in the ~/.claude directory

func NewClaudeConfigManager

func NewClaudeConfigManager() (*ClaudeConfigManager, error)

NewClaudeConfigManager creates a new ClaudeConfigManager instance with the ~/.claude directory resolved

func (*ClaudeConfigManager) GetConfig

func (m *ClaudeConfigManager) GetConfig(filename string) (*ConfigFile, error)

GetConfig reads a specific Claude configuration file by name Common file names include "CLAUDE.md", "settings.json", "agents.md"

func (*ClaudeConfigManager) ListConfigs

func (m *ClaudeConfigManager) ListConfigs() ([]ConfigFile, error)

ListConfigs returns all configuration files in the ~/.claude directory

func (*ClaudeConfigManager) UpdateConfig

func (m *ClaudeConfigManager) UpdateConfig(filename string, content string) error

UpdateConfig updates a Claude configuration file atomically with backup It creates a .bak file before writing, and uses a temporary file for atomicity. JSON files are validated before writing to prevent corrupt settings files.

func (*ClaudeConfigManager) UpdateConfigWithValidation

func (m *ClaudeConfigManager) UpdateConfigWithValidation(filename string, content string) error

UpdateConfigWithValidation updates a config file with JSON validation This is a convenience method that combines validation and update

func (*ClaudeConfigManager) ValidateJSON

func (m *ClaudeConfigManager) ValidateJSON(filename string, content string) error

ValidateJSON validates a JSON configuration file against a schema Returns nil if valid, error with details if invalid

type CommandExecutor

type CommandExecutor interface {
	Command(name string, args ...string) *exec.Cmd
	Output(cmd *exec.Cmd) ([]byte, error)
	LookPath(file string) (string, error)
}

CommandExecutor defines the interface for executing external commands

type Config

type Config struct {

	// ListenAddress is the address the HTTP server listens on.
	// Default: "localhost:8543". Set to "0.0.0.0:8543" for remote access.
	ListenAddress string `json:"listen_address"`
	// PasskeyRPID is the WebAuthn Relying Party ID (effective domain, no scheme/port).
	// Example: "192.168.1.42" or "myhost.local". Must match the hostname clients use.
	// Required when remote access is enabled.
	PasskeyRPID string `json:"passkey_rp_id"`
	// PasskeyEnabled controls whether passkey authentication is enforced.
	// Automatically set to true when non-localhost listen address is used.
	PasskeyEnabled bool `json:"passkey_enabled"`
	// DefaultProgram is the default program to run in new instances
	DefaultProgram string `json:"default_program"`
	// AutoYes is a flag to automatically accept all prompts.
	AutoYes bool `json:"auto_yes"`
	// DaemonPollInterval is the interval (ms) at which the daemon polls sessions for autoyes mode.
	DaemonPollInterval int `json:"daemon_poll_interval"`
	// BranchPrefix is the prefix used for git branches created by the application.
	BranchPrefix string `json:"branch_prefix"`
	// DetectNewSessions is a flag to enable detection of new sessions from other windows
	DetectNewSessions bool `json:"detect_new_sessions"`
	// SessionDetectionInterval is the interval (ms) at which the daemon checks for new sessions
	SessionDetectionInterval int `json:"session_detection_interval"`
	// StateRefreshInterval is the interval (ms) at which the state is refreshed from disk
	StateRefreshInterval int `json:"state_refresh_interval"`
	// LogsEnabled is a flag to enable logging to files
	LogsEnabled bool `json:"logs_enabled"`
	// LogsDir is the directory where logs are stored (defaults to ~/.stapler-squad/logs)
	LogsDir string `json:"logs_dir"`
	// LogMaxSize is the maximum size of a log file in megabytes before it gets rotated
	LogMaxSize int `json:"log_max_size"`
	// LogMaxFiles is the maximum number of rotated log files to keep (not including the current log file)
	LogMaxFiles int `json:"log_max_files"`
	// LogMaxAge is the maximum number of days to keep rotated log files
	LogMaxAge int `json:"log_max_age"`
	// LogCompress is a flag to enable compression of rotated log files
	LogCompress bool `json:"log_compress"`
	// UseSessionLogs is a flag to enable per-session log files
	UseSessionLogs bool `json:"use_session_logs"`
	// TmuxSessionPrefix allows customizing the tmux session prefix for process isolation
	TmuxSessionPrefix string `json:"tmux_session_prefix"`
	// PerformBackgroundHealthChecks enables non-blocking health checks for session maintenance
	PerformBackgroundHealthChecks bool `json:"perform_background_health_checks"`
	// KeyCategories defines custom category mappings for key bindings in help system
	KeyCategories map[string]string `json:"key_categories"`
	// VCSPreference controls which version control system to prefer when both are available
	// Options: "auto" (prefer JJ if available), "jj" (always use JJ), "git" (always use Git)
	VCSPreference string `json:"vcs_preference"`
	// AvailablePrograms is a list of detected CLI programs
	AvailablePrograms []string `json:"available_programs"`
	// ConfigVersion tracks the schema version for future migrations (1 = session_defaults added)
	ConfigVersion int `json:"config_version,omitempty"`
	// SessionDefaults holds named profiles, directory rules, and global defaults for new sessions.
	SessionDefaults SessionDefaults `json:"session_defaults,omitempty"`
	// Notifications holds the user's notification delivery preferences.
	Notifications NotificationPrefs `json:"notifications,omitempty"`
	// OneOffBaseDir is the base directory where one-off session directories are created.
	// Default: "~/oneoff". Tilde is expanded at runtime. Created automatically on first use.
	OneOffBaseDir string `json:"one_off_base_dir,omitempty"`
	// PyroscopeServerAddress is the Pyroscope server URL for continuous profiling.
	// Empty string (the default) disables continuous profiling.
	// Example: "http://localhost:4040"
	PyroscopeServerAddress string `json:"pyroscope_server_address,omitempty"`
	// NewProjectBaseDir is the base directory where new project directories are created.
	// Default: "~/Projects". Tilde is expanded at runtime. Created on first use.
	// Zero-value (empty string) is backwards-compatible — existing configs load without change.
	NewProjectBaseDir string `json:"new_project_base_dir,omitempty"`
	// MachineEncryptionKey is a base64-encoded 32-byte AES-256-GCM key for local data encryption.
	// Generated on first run and persisted here. Used to encrypt sensitive token data in ItemSource configs.
	MachineEncryptionKey string `json:"machine_encryption_key,omitempty"`
	// MaxAutoReworkIterations caps how many automated work sessions the backlog auto-reopen
	// loop will spawn for a single item before leaving it for manual review. 0 = use the
	// default (20). Individual items can also override this via
	// BacklogItemData.ReworkCapOverride (0 = unlimited for that item, >0 = that item's own
	// cap) — see effectiveReworkCap in server/services/backlog_service_triage.go.
	MaxAutoReworkIterations int `json:"max_auto_rework_iterations,omitempty"`
	// MaxConcurrentBacklogWorkItems caps how many distinct backlog items may be
	// "in_progress" at the same time. 0 = use the default (2). Values above
	// maxConcurrentBacklogWorkItemsHardCeiling are clamped to the ceiling.
	MaxConcurrentBacklogWorkItems int `json:"max_concurrent_backlog_work_items,omitempty"`
	// AutoSpawnReadyItems controls whether "ready" backlog items (post-triage, plan
	// approved or SkipPlanning) automatically claim a free WIP slot and spawn a work
	// session — in priority order (P1 first) — the moment one is free, without a
	// human clicking "Spawn Session". A *bool, not bool: the zero value of bool
	// can't represent "unset" the way 0 does for the int settings above, and this
	// setting's default is true (unlike SkipReviewGate/AutoCreatePR's per-item
	// false-by-default opt-ins), so nil must mean "use the default", not "disabled".
	// Pass explicit false to require manual spawning instead.
	AutoSpawnReadyItems *bool `json:"auto_spawn_ready_items,omitempty"`

	// AnalyticsMaxRows is the maximum number of analytics events to retain in the database.
	// When exceeded, the oldest rows are deleted. 0 means no row-count limit.
	// Default: 100_000.
	AnalyticsMaxRows int `json:"analytics_max_rows,omitempty"`
	// AnalyticsMaxAgeDays is the maximum age in days of analytics events to retain.
	// Events older than this are deleted. 0 means no age limit.
	// Default: 90.
	AnalyticsMaxAgeDays int `json:"analytics_max_age_days,omitempty"`
	// BrowserPassthrough configures the per-session Xvfb + x11vnc virtual display feature.
	BrowserPassthrough BrowserPassthroughConfig `json:"browser_passthrough,omitempty"`
	// FeatureFlags stores the enabled/disabled state of named runtime feature flags.
	// Keys are machine names (e.g. "backlog"); values are booleans.
	// Absent key == disabled (false is the safe default for all flags).
	FeatureFlags map[string]bool `json:"feature_flags,omitempty"`
	// Hibernation holds configuration for the session hibernation feature.
	Hibernation HibernationConfig `json:"hibernation,omitempty"`
	// Capacity holds configuration for the provider capacity monitoring and transition feature.
	Capacity CapacityConfig `json:"capacity,omitempty"`
	// Quota holds configuration for the account-wide session-quota gate that
	// pauses/resumes backlog automation based on inferred quota headroom.
	Quota QuotaConfig `json:"quota,omitempty"`
	// TmuxExecGate bounds concurrent tmux subprocess execution across all processes.
	TmuxExecGate TmuxExecGateConfig `json:"tmux_exec_gate,omitempty"`
	// SessionRetention holds configuration for the automatic session-retention cleanup sweep.
	SessionRetention SessionRetentionConfig `json:"session_retention,omitempty"`

	// EscapeAnalyticsCaptureLevel controls the verbosity of escape sequence capture.
	// Valid values: "full" (store raw bytes + hash), "summary" (type/length only), "off" (disabled).
	// Default: "summary".
	EscapeAnalyticsCaptureLevel string `json:"escapeAnalyticsCaptureLevel,omitempty"`
	// EscapeAnalyticsSamplingRate is the fraction of sessions to capture, in [0.0, 1.0].
	// 1.0 captures all sessions; 0.0 captures none.
	// A nil pointer means "unset" and defaults to 1.0 at load time.
	// Using a pointer allows 0.0 (capture nothing) to be distinguished from the zero value.
	// Default: 1.0.
	EscapeAnalyticsSamplingRate *float64 `json:"escapeAnalyticsSamplingRate,omitempty"`
	// EscapeAnalyticsMaxRowsPerSession is the maximum number of escape event rows stored per session.
	// Default: 10000.
	EscapeAnalyticsMaxRowsPerSession int `json:"escapeAnalyticsMaxRowsPerSession,omitempty"`
	// EscapeAnalyticsDisableOSCRedaction disables OSC payload redaction when true.
	// By default (false), OSC payloads (clipboard, window title, CWD) are redacted for security.
	// Set to true only if you explicitly need to capture raw OSC payload content.
	EscapeAnalyticsDisableOSCRedaction bool `json:"escapeAnalyticsDisableOSCRedaction,omitempty"`
	// EscapeAnalyticsRetentionDays is the number of days to retain escape event rows.
	// Default: 7.
	EscapeAnalyticsRetentionDays int `json:"escapeAnalyticsRetentionDays,omitempty"`
	// AnthropicAPIKey is the API key for the Anthropic AI API.
	// Used by the AI rule generation feature (GenerateSuggestedRule RPC).
	// Set via config.json or the ANTHROPIC_API_KEY environment variable.
	// Do not log this value.
	AnthropicAPIKey string `json:"anthropicApiKey,omitempty"`
	// ProcessManagerBackend selects the process manager implementation.
	// Valid values: "tmux" (default), "native" (Phase 2).
	// Empty string is backwards-compatible and defaults to "tmux".
	ProcessManagerBackend string `json:"process_manager_backend,omitempty"`
	// GitHubEnterpriseHosts registers GitHub Enterprise Server instances (beyond
	// github.com) with their own OAuth App client IDs, enabling device-flow login,
	// PR polling, and link detection against those hosts. Empty means github.com only.
	GitHubEnterpriseHosts []GitHubEnterpriseHost `json:"github_enterprise_hosts,omitempty"`
	// contains filtered or unexported fields
}

Config represents the application configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns the default configuration

func LoadConfig

func LoadConfig() *Config

func LoadConfigFromPath added in v1.16.0

func LoadConfigFromPath(path string) (*Config, error)

LoadConfigFromPath loads and parses a config file from an explicit path. Returns the config and any error encountered.

func NewConfig added in v1.35.0

func NewConfig() *Config

NewConfig creates a Config with the default timeout executor.

func NewConfigWithExecutor added in v1.35.0

func NewConfigWithExecutor(exec CommandExecutor) *Config

NewConfigWithExecutor creates a Config with an explicit command executor. Pass nil to use the default timeout executor.

func (*Config) AnalyticsMaxAgeDaysOrDefault added in v1.35.0

func (c *Config) AnalyticsMaxAgeDaysOrDefault() int

AnalyticsMaxAgeDaysOrDefault returns the configured max analytics age in days, or 90 if not set (zero value).

func (*Config) AnalyticsMaxRowsOrDefault added in v1.35.0

func (c *Config) AnalyticsMaxRowsOrDefault() int

AnalyticsMaxRowsOrDefault returns the configured max analytics rows, or 100_000 if not set (zero value).

func (*Config) AutoSpawnReadyItemsOrDefault added in v1.41.0

func (c *Config) AutoSpawnReadyItemsOrDefault() bool

AutoSpawnReadyItemsOrDefault reports whether "ready" items should be automatically dequeued and spawned — in priority order, respecting the WIP cap — the moment a slot frees up, without a human manually clicking "Spawn Session". Defaults to true (nil or c == nil); pass explicit false to require manual spawning instead.

func (*Config) BacklogAttachmentDirOrDefault added in v1.39.0

func (c *Config) BacklogAttachmentDirOrDefault() (string, error)

BacklogAttachmentDirOrDefault returns the resolved backlog attachment directory. Uploaded images referenced from backlog item descriptions are stored here, durably (unlike the 24h temp paste dir) since they're linked from persisted markdown text. Always defaults to "~/.stapler-squad/backlog-attachments".

func (*Config) GetAvailablePrograms added in v1.35.0

func (c *Config) GetAvailablePrograms() []string

GetAvailablePrograms returns a list of all detected CLI programs.

func (*Config) GetClaudeCommand added in v1.35.0

func (c *Config) GetClaudeCommand() (string, error)

GetClaudeCommand attempts to find the "claude" command in the user's shell It checks in the following order: 1. Shell alias resolution (proxy-claude, then claude) 2. PATH lookup

If both fail, it returns an error.

func (*Config) GetFeatureFlag added in v1.35.0

func (c *Config) GetFeatureFlag(name string) bool

GetFeatureFlag returns the persisted enabled state of the named feature flag. Absent key returns false — all feature flags default to disabled. Currently recognized flags:

"backlog" — enables the Backlog tab and backlog lifecycle controller.

func (*Config) GetGitHubEnterpriseHosts added in v1.41.0

func (c *Config) GetGitHubEnterpriseHosts() []GitHubEnterpriseHost

GetGitHubEnterpriseHosts returns the configured GHES hosts, or nil if c is nil.

func (*Config) GetKeyCategoryForKey

func (c *Config) GetKeyCategoryForKey(key string) string

GetKeyCategoryForKey returns the category for a specific key, or empty string if not found

func (*Config) GetOrCreateEncryptionKey added in v1.35.0

func (c *Config) GetOrCreateEncryptionKey() ([]byte, error)

GetOrCreateEncryptionKey returns the 32-byte AES-256-GCM key for local data encryption. Generates and persists a new key on first call. Non-fatal errors during save are logged.

func (*Config) HeadlessFailureCaptureDirOrDefault added in v1.42.0

func (c *Config) HeadlessFailureCaptureDirOrDefault() (string, error)

HeadlessFailureCaptureDirOrDefault returns the resolved directory for durable headless (triage/review claude -p) failure captures — see session.WriteHeadlessFailureCapture. Always defaults to "~/.stapler-squad/headless-failures".

func (*Config) HibernationCheckpointDirOrDefault added in v1.35.0

func (c *Config) HibernationCheckpointDirOrDefault() (string, error)

HibernationCheckpointDirOrDefault returns the resolved hibernation checkpoint directory. If CheckpointDir is empty, it returns "~/.stapler-squad/checkpoints" with ~ expanded. The directory is NOT created here — the checkpoint writer creates it on first use.

func (*Config) MaxAutoReworkIterationsOrDefault added in v1.39.0

func (c *Config) MaxAutoReworkIterationsOrDefault() int

MaxAutoReworkIterationsOrDefault returns the configured rework-cap ceiling, or 20 if not set (zero value) or c is nil (BacklogService's cfg is nil in some test setups). Raised from 3 to 20: 3 was tripping routinely on real, ultimately-fixable items (e.g. a multi-round diff/review-harness flake, or a straightforward merge conflict) well before the work was actually stuck, forcing manual "Reopen for Revision" clicks for otherwise-recoverable items. Genuinely stuck items still get caught — just later — and per-item overrides (BacklogItemData.ReworkCapOverride) exist for cases that need to go further still.

func (*Config) MaxConcurrentBacklogWorkItemsOrDefault added in v1.41.0

func (c *Config) MaxConcurrentBacklogWorkItemsOrDefault() int

MaxConcurrentBacklogWorkItemsOrDefault returns the configured backlog work-item concurrency cap, clamped to [1, maxConcurrentBacklogWorkItemsHardCeiling]. Falls back to the default (2) if unset (<=0) or c is nil.

func (*Config) NewProjectBaseDirOrDefault added in v1.35.0

func (c *Config) NewProjectBaseDirOrDefault() (string, error)

NewProjectBaseDirOrDefault returns the resolved new-project base directory. If NewProjectBaseDir is empty, it defaults to "~/Projects" with ~ expanded.

func (*Config) OSCPayloadsAreRedacted added in v1.35.0

func (c *Config) OSCPayloadsAreRedacted() bool

OSCPayloadsAreRedacted returns true when OSC payload redaction is enabled (the default). Redaction prevents PII (clipboard contents, window titles, CWD paths) from being stored in escape event records. Set EscapeAnalyticsDisableOSCRedaction=true in config to opt out.

func (*Config) OneOffBaseDirOrDefault added in v1.21.0

func (c *Config) OneOffBaseDirOrDefault() (string, error)

OneOffBaseDirOrDefault returns the resolved one-off base directory. If OneOffBaseDir is empty, it returns "~/oneoff" with ~ expanded to the current user's home directory. The directory is NOT created here — call namegen.GenerateAndCreate to create it on first use.

func (*Config) RemoveKeyCategory

func (c *Config) RemoveKeyCategory(key string)

RemoveKeyCategory removes the category mapping for a specific key

func (*Config) SetFeatureFlag added in v1.35.0

func (c *Config) SetFeatureFlag(name string, value bool) error

SetFeatureFlag sets the named feature flag and persists the config to disk.

func (*Config) SetKeyCategory

func (c *Config) SetKeyCategory(key, category string)

SetKeyCategory updates the category for a specific key

func (*Config) TriageArtifactDirOrDefault added in v1.37.0

func (c *Config) TriageArtifactDirOrDefault() (string, error)

TriageArtifactDirOrDefault returns the resolved triage artifact directory. Triage workers write their planning files here instead of into the item's repo. Always defaults to "~/.stapler-squad/triage-artifacts".

type ConfigFile

type ConfigFile struct {
	// Name is the filename (e.g., "CLAUDE.md", "settings.json", "agents.md")
	Name string
	// Path is the absolute path to the file
	Path string
	// Content is the file contents
	Content string
	// ModTime is the last modification timestamp
	ModTime time.Time
}

ConfigFile represents a single Claude configuration file

type DirectoryRule added in v1.12.0

type DirectoryRule struct {
	// Path is the absolute path prefix to match (longest match wins).
	Path string `json:"path"`
	// Profile is the optional named profile to apply when this rule matches.
	Profile string `json:"profile,omitempty"`
	// Overrides are field-level overrides applied after the profile (if any).
	Overrides ProfileDefaults `json:"overrides,omitempty"`
}

DirectoryRule associates a working-directory path prefix with profile defaults.

type DiscoveryConfig

type DiscoveryConfig struct {
	// Mode determines which types of instances to discover
	Mode DiscoveryMode `json:"mode"`

	// AllowExternalAttach controls whether users can attach to external instances
	AllowExternalAttach bool `json:"allow_external_attach"`

	// ConfirmExternalOperations requires confirmation before operations on external instances
	ConfirmExternalOperations bool `json:"confirm_external_operations"`

	// SocketPaths defines custom socket paths for discovery (optional)
	// Empty means use system defaults (/tmp/tmux-*/default)
	SocketPaths []string `json:"socket_paths"`

	// ExcludedSocketPaths defines socket paths to skip during discovery
	ExcludedSocketPaths []string `json:"excluded_socket_paths"`

	// DiscoverInterval is the interval (ms) at which external instances are scanned
	DiscoverInterval int `json:"discover_interval"`

	// AutoRefreshExternal enables automatic refresh of external instance metadata
	AutoRefreshExternal bool `json:"auto_refresh_external"`
}

DiscoveryConfig controls instance discovery behavior and safety settings

func DefaultDiscoveryConfig

func DefaultDiscoveryConfig() *DiscoveryConfig

DefaultDiscoveryConfig returns the default discovery configuration By default, only managed instances are shown for safety

func LoadDiscoveryConfig

func LoadDiscoveryConfig() *DiscoveryConfig

LoadDiscoveryConfig loads the discovery configuration from disk

func (*DiscoveryConfig) CanAttachToExternal

func (c *DiscoveryConfig) CanAttachToExternal() bool

CanAttachToExternal returns true if attaching to external instances is allowed

func (*DiscoveryConfig) IsExternalDiscoveryEnabled

func (c *DiscoveryConfig) IsExternalDiscoveryEnabled() bool

IsExternalDiscoveryEnabled returns true if external instance discovery is enabled

func (*DiscoveryConfig) IsManagedDiscoveryEnabled

func (c *DiscoveryConfig) IsManagedDiscoveryEnabled() bool

IsManagedDiscoveryEnabled returns true if managed instance discovery is enabled

func (*DiscoveryConfig) ShouldConfirmOperation

func (c *DiscoveryConfig) ShouldConfirmOperation(isExternal bool) bool

ShouldConfirmOperation returns true if the operation requires user confirmation

func (*DiscoveryConfig) ShouldShowExternalInstances

func (c *DiscoveryConfig) ShouldShowExternalInstances() bool

ShouldShowExternalInstances returns true if external instances should be displayed

type DiscoveryMode

type DiscoveryMode string

DiscoveryMode defines how the application discovers Claude instances

const (
	// DiscoveryManagedOnly discovers only instances created by stapler-squad
	DiscoveryManagedOnly DiscoveryMode = "managed-only"

	// DiscoveryExternalOnly discovers only external Claude instances
	DiscoveryExternalOnly DiscoveryMode = "external-only"

	// DiscoveryAll discovers both managed and external instances
	DiscoveryAll DiscoveryMode = "all"
)

type GitHubEnterpriseHost added in v1.41.0

type GitHubEnterpriseHost struct {
	// Host is the bare hostname (no scheme, no trailing slash), e.g. "github.example.com".
	Host string `json:"host"`
	// ClientID is the OAuth App client ID registered on that GHES instance.
	ClientID string `json:"client_id"`
}

GitHubEnterpriseHost registers a GitHub Enterprise Server instance's OAuth App client ID so device-flow login can target that host in addition to github.com.

type HibernationConfig added in v1.35.0

type HibernationConfig struct {
	// Enabled controls whether hibernation is active. Default: true.
	Enabled bool `json:"enabled"`
	// IdleTimeoutMinutes is the number of minutes a session must be idle before
	// the sweeper automatically hibernates it. Default: 20.
	IdleTimeoutMinutes int `json:"idle_timeout_minutes"`
	// ResourcePressureThreshold is the memory usage percentage at which the
	// sweeper begins hibernating idle sessions. Default: 85.
	ResourcePressureThreshold int `json:"resource_pressure_threshold_pct"`
	// CheckpointDir is the directory where hibernation checkpoint data is stored.
	// Default: "~/.stapler-squad/checkpoints". Tilde is expanded at runtime.
	CheckpointDir string `json:"checkpoint_dir"`
	// RetentionDays is the number of days to retain stale checkpoint data.
	// Default: 30.
	RetentionDays int `json:"retention_days"`
}

HibernationConfig holds configuration for the session hibernation feature.

type LauncherPreset added in v1.42.0

type LauncherPreset struct {
	ID          string   `json:"id"`
	Label       string   `json:"label"`
	Argv        []string `json:"argv"`
	Program     string   `json:"program,omitempty"`
	DefaultPath string   `json:"default_path,omitempty"`
}

LauncherPreset is one hand-authored entry in launcher-presets.json: a named, argv-based launch shortcut (e.g. a specific agent + flags, or a remote-exec ssh command). argv is never shell-split — argv[0] maps to Program, argv[1:] maps to session.Instance.ExtraArgs, both shell-quoted independently at launch time (see buildLaunchCommand in session/instance_tmux.go).

type LauncherPresetsFile added in v1.42.0

type LauncherPresetsFile struct {
	Version int              `json:"version"`
	Presets []LauncherPreset `json:"presets"`
}

LauncherPresetsFile is the top-level document shape of launcher-presets.json.

func LoadLauncherPresets added in v1.42.0

func LoadLauncherPresets(path string) (*LauncherPresetsFile, error)

LoadLauncherPresets reads and validates launcher-presets.json at path.

A missing file is reported via an os.IsNotExist-satisfying error, distinguishable from a validation failure — callers treat "not exist" as "zero presets, no error to surface" and any other error as a loud, whole-file rejection to surface as load_error.

type NotificationPrefs added in v1.16.0

type NotificationPrefs struct {
	// PushEnabled controls whether web push notifications are sent.
	// Default is false (opt-in).
	PushEnabled bool `json:"push_enabled"`
}

NotificationPrefs holds the user's notification delivery preferences.

type ProfileDefaults added in v1.12.0

type ProfileDefaults struct {
	Name        string            `json:"name"`
	Description string            `json:"description,omitempty"`
	Program     string            `json:"program,omitempty"`
	AutoYes     bool              `json:"auto_yes,omitempty"`
	Tags        []string          `json:"tags,omitempty"`
	EnvVars     map[string]string `json:"env_vars,omitempty"`
	CLIFlags    string            `json:"cli_flags,omitempty"`
	CreatedAt   time.Time         `json:"created_at"`
	UpdatedAt   time.Time         `json:"updated_at"`
}

ProfileDefaults holds the configurable fields for a named profile.

type ProviderPriority added in v1.35.0

type ProviderPriority struct {
	CLI   string `json:"cli"`
	Model string `json:"model"`
}

ProviderPriority defines a prioritized CLI and model target for transitions.

type QuotaConfig added in v1.42.0

type QuotaConfig struct {
	// Enabled gates the entire feature. When false, the gate is a no-op and
	// BacklogController's toggle behaves exactly as it does today. Default: false.
	Enabled bool `json:"enabled,omitempty"`
	// PauseBelowHeadroomPct is the soft/proactive threshold: backlog is paused
	// once estimated headroom drops below this percentage. Default: 20.0.
	PauseBelowHeadroomPct float64 `json:"pause_below_headroom_pct,omitempty"`
	// ResumeMarginPct is added to PauseBelowHeadroomPct to form the resume
	// threshold, avoiding flapping right at the pause line. Default: 15.0.
	ResumeMarginPct float64 `json:"resume_margin_pct,omitempty"`
	// ConsecutiveTicksToPause is how many consecutive below-threshold reconcile
	// ticks are required before the soft signal pauses backlog. Default: 2.
	ConsecutiveTicksToPause int `json:"consecutive_ticks_to_pause,omitempty"`
	// ConsecutiveTicksToResume is how many consecutive above-threshold reconcile
	// ticks are required before the soft signal resumes backlog. Default: 3.
	ConsecutiveTicksToResume int `json:"consecutive_ticks_to_resume,omitempty"`
	// AssumedWindowTokenBudget is the operator-supplied assumed token budget for
	// the trailing 5h window. Anthropic publishes no real budget, so this must be
	// calibrated manually; 0 (the default) disables the soft/percentage signal
	// entirely, leaving only the hard/reactive rate-limit override active.
	AssumedWindowTokenBudget int64 `json:"assumed_window_token_budget,omitempty"`
	// RateLimitWindowMinutes is how long a detected rate-limit event keeps the
	// hard/reactive override active. Default: 30.
	RateLimitWindowMinutes int `json:"rate_limit_window_minutes,omitempty"`
	// ManualOverrideGraceMinutes is how long after a detected manual override the
	// notification cooldown is bypassed for the next auto-transition. Default: 10.
	ManualOverrideGraceMinutes int `json:"manual_override_grace_minutes,omitempty"`
	// ForegroundThrottleDelaySeconds is how long the foreground-session dispatch
	// throttle stays active after the most recently observed foreground activity.
	// Default: 300.
	ForegroundThrottleDelaySeconds int `json:"foreground_throttle_delay_seconds,omitempty"`
}

QuotaConfig holds configuration for the account-wide Claude Code session-quota gate that pauses/resumes backlog automation (see BacklogController) based on an inferred quota-headroom signal, plus a foreground-session dispatch throttle.

func (QuotaConfig) QuotaConfigOrDefault added in v1.42.0

func (c QuotaConfig) QuotaConfigOrDefault() QuotaConfig

QuotaConfigOrDefault returns a QuotaConfig with standard defaults applied to zero fields.

type ResolvedDefaults added in v1.12.0

type ResolvedDefaults struct {
	Program  string
	AutoYes  bool
	Tags     []string
	EnvVars  map[string]string
	CLIFlags string

	// Path is the working directory path from an alias (empty for non-alias resolution).
	Path string
	// Branch is the git branch hint from alias invocation (e.g. from @alias:branch).
	Branch string
	// SessionLabel is the session label from alias invocation (text between alias and --)
	SessionLabel string

	// Source tracking — which layers contributed to this result.
	UsedGlobal       bool
	UsedDirectory    bool
	UsedProfile      bool
	MatchedDirectory string
}

ResolvedDefaults is the merged result of all applicable default layers for a new session.

func ResolveAlias added in v1.35.0

func ResolveAlias(cfg *Config, aliasName, branch, label, extraFlags string) (ResolvedDefaults, error)

ResolveAlias resolves an alias by name and returns merged session defaults. Resolution order: global → directory → profile → alias inline fields. The alias's CLIFlags replace each prior layer (same as mergeProfileInto semantics). extraFlags are appended to the final CLIFlags as an explicit invocation-time step.

Path, Branch, and SessionLabel are promoted into the returned ResolvedDefaults so callers do not need to access the raw AliasConfig.

func ResolveDefaults added in v1.12.0

func ResolveDefaults(cfg *Config, workingDir, profileName string) ResolvedDefaults

ResolveDefaults merges the three layers of session defaults (global → directory → profile) for the given working directory and optional profile name.

Precedence (lowest → highest):

  1. cfg.DefaultProgram (legacy fallback)
  2. cfg.SessionDefaults global fields
  3. DirectoryRule.Overrides for the longest-matching path prefix
  4. Named profile (profileName argument)

Merge semantics:

  • Scalar fields (Program, CLIFlags): non-empty source value overwrites target
  • AutoYes: true in any layer sets it true
  • Tags: union across all layers (duplicates removed)
  • EnvVars: higher-layer key overwrites lower-layer key

type SessionDefaults added in v1.12.0

type SessionDefaults struct {
	// Program is the default AI program (e.g., "claude", "aider").
	Program string `json:"program,omitempty"`
	// AutoYes auto-approves prompts in new sessions.
	AutoYes bool `json:"auto_yes,omitempty"`
	// Tags are pre-applied to every new session.
	Tags []string `json:"tags,omitempty"`
	// EnvVars are environment variables passed to new sessions.
	EnvVars map[string]string `json:"env_vars,omitempty"`
	// CLIFlags are additional CLI flags for the program.
	CLIFlags string `json:"cli_flags,omitempty"`
	// Profiles maps profile name → profile configuration.
	Profiles map[string]ProfileDefaults `json:"profiles,omitempty"`
	// DirectoryRules are path-based rules matched against the session's working directory.
	DirectoryRules []DirectoryRule `json:"directory_rules,omitempty"`
	// Aliases are named session presets invoked via @name in the omnibar.
	Aliases []AliasConfig `json:"aliases,omitempty"`
}

SessionDefaults is the top-level container for all session default configuration.

type SessionRetentionConfig added in v1.41.0

type SessionRetentionConfig struct {
	// Enabled controls whether the retention sweep runs. A pointer so a config
	// saved before this field existed (nil) can be distinguished from an explicit
	// `false` — nil defaults to enabled, matching AutoSpawnReadyItems's pattern.
	Enabled *bool `json:"enabled,omitempty"`
	// RetentionDays is how many days after a session is archived before the sweep
	// is eligible to delete it (still subject to safety checks). Default: 14.
	RetentionDays int `json:"retention_days,omitempty"`
}

SessionRetentionConfig holds configuration for the automatic session-retention cleanup sweep, which deletes archived sessions past a retention window once they pass safety checks (clean worktree, no open PR).

func (SessionRetentionConfig) EnabledOrDefault added in v1.41.0

func (c SessionRetentionConfig) EnabledOrDefault() bool

EnabledOrDefault returns whether the sweep is enabled, defaulting to true when unset.

func (SessionRetentionConfig) RetentionDaysOrDefault added in v1.41.0

func (c SessionRetentionConfig) RetentionDaysOrDefault() int

RetentionDaysOrDefault returns RetentionDays, falling back to defaultSessionRetentionDays when unset (<=0).

type SessionType added in v1.35.0

type SessionType string

SessionType is the session creation mode (directory, new_worktree, existing_worktree, etc.). Defined here so both the config layer and the session layer share the same type without a circular import — session already imports config.

const (
	// SessionTypeDefault uses the default behavior (directory session).
	SessionTypeDefault SessionType = ""
	// SessionTypeDirectory creates a simple directory session without a worktree.
	SessionTypeDirectory SessionType = "directory"
	// SessionTypeNewWorktree creates a new git worktree for the session.
	SessionTypeNewWorktree SessionType = "new_worktree"
	// SessionTypeExistingWorktree reuses an existing git worktree.
	SessionTypeExistingWorktree SessionType = "existing_worktree"
	// SessionTypeNewProject creates a new directory with a git repo.
	SessionTypeNewProject SessionType = "new_project"
	// SessionTypeOneOff creates a temporary directory under OneOffBaseDir with a generated name.
	SessionTypeOneOff SessionType = "one_off"
)

func (SessionType) IsValid added in v1.35.0

func (st SessionType) IsValid() bool

IsValid reports whether st is a recognized session type.

type State

type State struct {
	// HelpScreensSeen is a bitmask tracking which help screens have been shown
	HelpScreensSeen uint32 `json:"help_screens_seen"`
	// UI stores the UI preferences and state
	UI UIState `json:"ui"`
	// contains filtered or unexported fields
}

State represents the application state that persists between sessions

func DefaultState

func DefaultState() *State

DefaultState returns the default state

func LoadState

func LoadState() *State

LoadState loads the state from disk with locking. If it cannot be done, we return the default state.

func NewTestState

func NewTestState(testDir string) *State

NewTestState creates a test state with isolated storage in the given directory This prevents tests from loading or interfering with production data

func (*State) Close

func (s *State) Close() error

Close releases any locks held by this state

func (*State) GetCategoryExpanded

func (s *State) GetCategoryExpanded(category string) bool

GetCategoryExpanded returns whether a category is expanded (defaults to true for new categories)

func (*State) GetHelpScreensSeen

func (s *State) GetHelpScreensSeen() uint32

GetHelpScreensSeen returns the bitmask of seen help screens

func (*State) GetSearchState

func (s *State) GetSearchState() (bool, string)

GetSearchState returns the current search mode and query

func (*State) GetSelectedIndex

func (s *State) GetSelectedIndex() int

GetSelectedIndex returns the last selected session index

func (*State) GetUIState

func (s *State) GetUIState() UIState

GetUIState returns a copy of the current UI state

func (*State) RefreshState

func (s *State) RefreshState() error

RefreshState reloads state from disk with locking

func (*State) SetCategoryExpanded

func (s *State) SetCategoryExpanded(category string, expanded bool) error

SetCategoryExpanded updates the expanded state for a category

func (*State) SetHelpScreensSeen

func (s *State) SetHelpScreensSeen(seen uint32) error

SetHelpScreensSeen updates the bitmask of seen help screens

func (*State) SetHidePaused

func (s *State) SetHidePaused(hidePaused bool) error

SetHidePaused updates the hide paused filter state

func (*State) SetSearchMode

func (s *State) SetSearchMode(searchMode bool, query string) error

SetSearchMode updates the search mode state

func (*State) SetSelectedIndex

func (s *State) SetSelectedIndex(index int) error

SetSelectedIndex updates the selected session index

type StateManager

type StateManager interface {
	AppState
	UIStateAccess

	// RefreshState reloads state from disk to detect changes made by other processes
	RefreshState() error

	// Close releases any resources held by the state manager
	Close() error
}

StateManager combines app state and UI state management

type TmuxExecGateConfig added in v1.37.0

type TmuxExecGateConfig struct {
	// Slots is the number of concurrent tmux subprocess execution slots.
	// Zero or unset means "use the default" — see SlotsOrDefault. Default: 8.
	Slots int `json:"slots"`
}

TmuxExecGateConfig bounds how many tmux subprocesses may run concurrently against one tmux server, across every process on the machine (the main daemon and every --mcp process) — tmux's server is single-threaded, so unbounded concurrent subprocess spawns degrade it for everyone.

func (TmuxExecGateConfig) SlotsOrDefault added in v1.37.0

func (c TmuxExecGateConfig) SlotsOrDefault() int

SlotsOrDefault returns Slots, falling back to defaultTmuxExecGateSlots when unset (covers both a fresh zero-value struct and a config.json saved before this field existed, which unmarshals the same way).

type TransitionMode added in v1.35.0

type TransitionMode string

TransitionMode controls how the system responds when capacity thresholds are crossed.

const (
	// TransitionModeManual displays a suggestion banner; the user must click to switch.
	TransitionModeManual TransitionMode = "manual"
	// TransitionModeAuto automatically transitions sessions without user interaction.
	TransitionModeAuto TransitionMode = "auto"
	// TransitionModeNotify shows a warning notification without offering transition UI.
	TransitionModeNotify TransitionMode = "notify"
)

type UIState

type UIState struct {
	// HidePaused controls whether paused sessions are filtered out
	HidePaused bool `json:"hide_paused"`
	// CategoryExpanded maps category names to their expanded state
	CategoryExpanded map[string]bool `json:"category_expanded"`
	// SearchMode tracks if search mode was active
	SearchMode bool `json:"search_mode"`
	// SearchQuery holds the last search query
	SearchQuery string `json:"search_query"`
	// SelectedIdx tracks the last selected session index
	SelectedIdx int `json:"selected_idx"`
}

UIState represents UI preferences that persist between sessions

type UIStateAccess

type UIStateAccess interface {
	// GetUIState returns a copy of the current UI state
	GetUIState() UIState
	// SetHidePaused updates the hide paused filter state
	SetHidePaused(hidePaused bool) error
	// SetCategoryExpanded updates the expanded state for a category
	SetCategoryExpanded(category string, expanded bool) error
	// GetCategoryExpanded returns whether a category is expanded
	GetCategoryExpanded(category string) bool
	// SetSearchMode updates the search mode state
	SetSearchMode(searchMode bool, query string) error
	// GetSearchState returns the current search mode and query
	GetSearchState() (bool, string)
	// SetSelectedIndex updates the selected session index
	SetSelectedIndex(index int) error
	// GetSelectedIndex returns the last selected session index
	GetSelectedIndex() int
}

UIStateAccess provides methods for accessing and modifying UI state

type WorkspaceMeta

type WorkspaceMeta struct {
	WorkspaceID string    `json:"workspace_id"` // dir name (hash or instance name)
	Type        string    `json:"type"`         // "workspace", "instance", "shared"
	CWD         string    `json:"cwd"`
	Name        string    `json:"name"`       // last path component of CWD, or "Default"
	ConfigDir   string    `json:"config_dir"` // absolute path to this workspace dir
	LastUsed    time.Time `json:"last_used"`
}

WorkspaceMeta stores display information about a workspace/database. Written to each workspace directory at startup to enable workspace discovery.

func ListAvailableWorkspaces

func ListAvailableWorkspaces(baseDir string) ([]WorkspaceMeta, error)

ListAvailableWorkspaces discovers all known workspaces by scanning workspace and instance subdirs. Skips test directories. Returns an empty slice (not an error) if none are found.

func ReadWorkspaceMeta

func ReadWorkspaceMeta(configDir string) (WorkspaceMeta, error)

ReadWorkspaceMeta reads workspace metadata from the given config directory.

Jump to

Keyboard shortcuts

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