Documentation
¶
Index ¶
- Constants
- Variables
- func DefaultAgentPrompt() string
- func DefaultTOML() []byte
- func DiffFromDefaults(cfg *Config, toLabel string) (string, error)
- func EffectiveTOML(cfg *Config) ([]byte, error)
- func Expand(s string, vars TemplateVars) (string, error)
- func ExpandPath(p string) string
- func ExpandPathRelative(p, baseDir string) string
- func ExpandSlice(ss []string, vars TemplateVars) ([]string, error)
- func ExpandTrigger(s string, vars TriggerVars) (string, error)
- func IncludeEnvVarName(repoBasename string) string
- func IsTemplateVar(name string) bool
- func LegacyRuntimeDirs() []string
- func NormalizeNotifyPriority(p string) (string, bool)
- func ParseDurationWithDays(s string) (time.Duration, error)
- func ResolveConfigPath(explicit string) (path string, exists bool, err error)
- func ResolvePath(p string) string
- func ResolveProfile() (profile string, appName string, err error)
- func ValidPromptInjection(s string) bool
- func ValidateIncludes(mainRepoPath string, includes []string) error
- func ValidateScenarioLifecycle(c ScenarioLifecycleConfig) error
- func ValidateTriggerStructure(where string, t *TriggerConfig) []error
- type ActionConfig
- type Agent
- func (a Agent) AddDirArgsFor(base TemplateVars, dirs []string) ([]string, error)
- func (a Agent) HeadlessCapableEnabled() bool
- func (a Agent) IdleTimeoutDuration() time.Duration
- func (a Agent) InterruptCountValue() int
- func (a Agent) InterruptDelay() time.Duration
- func (a Agent) OptionArgsFor(vars TemplateVars) ([]string, error)
- func (a Agent) PreTrustWorkspaceEnabled() bool
- func (a Agent) PromptInjectionEnabled() bool
- type AgentOptionArg
- type Approvals
- func (a Approvals) BackendExecTimeout(backend string) (time.Duration, bool)
- func (a Approvals) CommandTimeoutDuration() time.Duration
- func (a Approvals) HookEnabled() bool
- func (a Approvals) LocalmostTimeoutDuration() time.Duration
- func (a Approvals) ResolveBackend() (backend, deprecation string, err error)
- func (a Approvals) TimeoutDuration() time.Duration
- func (a Approvals) Validate() error
- type ApprovalsBuiltin
- type CodexOptions
- type CompletionConfig
- type Config
- type ConfigReload
- type ConnectionConfig
- func (c ConnectionConfig) DialTimeoutDuration() time.Duration
- func (c ConnectionConfig) HandshakeTimeoutDuration() time.Duration
- func (c ConnectionConfig) ReconnectIntervalDuration() time.Duration
- func (c ConnectionConfig) ReconnectTimeoutDuration() time.Duration
- func (c ConnectionConfig) RemoteDialTimeoutDuration() time.Duration
- func (c ConnectionConfig) RemoteHandshakeTimeoutDuration() time.Duration
- func (c ConnectionConfig) RemotePairingTimeoutDuration() time.Duration
- func (c ConnectionConfig) StartPollIntervalDuration() time.Duration
- func (c ConnectionConfig) StartTimeoutDuration() time.Duration
- type Delete
- type DeliverConfig
- type DetectionConfig
- func (d DetectionConfig) AdoptedGraceDuration() time.Duration
- func (d DetectionConfig) FetchIntervalDuration() time.Duration
- func (d DetectionConfig) FetchTimeoutDuration() time.Duration
- func (d DetectionConfig) HookActivityWindowDuration() time.Duration
- func (d DetectionConfig) HookStartWindowDuration() time.Duration
- func (d DetectionConfig) HookTerminalWindowDuration() time.Duration
- func (d DetectionConfig) RecentOutputWindowDuration() time.Duration
- func (d DetectionConfig) ScanIntervalDuration() time.Duration
- func (d DetectionConfig) SilentThresholdDuration() time.Duration
- type GCConfig
- type GCXConfig
- type GitConfig
- type GitPullConfig
- type HeadlessConfig
- type InputConfig
- type Keybindings
- type LaunchConfig
- func (l LaunchConfig) MaxConcurrentOrDefault() int
- func (l LaunchConfig) MaxRestartsOrDefault() int
- func (l LaunchConfig) SettleTimeoutDuration() time.Duration
- func (l LaunchConfig) SlotPollIntervalDuration() time.Duration
- func (l LaunchConfig) StartupTimeoutDuration() time.Duration
- func (l LaunchConfig) WatchdogIntervalDuration() time.Duration
- type LifecycleConfig
- func (l LifecycleConfig) AdoptedPollIntervalDuration() time.Duration
- func (l LifecycleConfig) AdoptedTimeoutDuration() time.Duration
- func (l LifecycleConfig) ConvertForceKillTimeoutDuration() time.Duration
- func (l LifecycleConfig) ConvertKillTimeoutDuration() time.Duration
- func (l LifecycleConfig) ConvertSettleTimeoutDuration() time.Duration
- func (l LifecycleConfig) DefaultColsOrDefault() uint16
- func (l LifecycleConfig) DefaultRowsOrDefault() uint16
- func (l LifecycleConfig) InputDelayDuration() time.Duration
- func (l LifecycleConfig) MassExitThresholdOrDefault() int
- func (l LifecycleConfig) MassExitWindowDuration() time.Duration
- func (l LifecycleConfig) MaxLogBytesOrDefault() int64
- func (l LifecycleConfig) ProcessKillGraceDuration() time.Duration
- func (l LifecycleConfig) ScrollbackHydrationBytesOrDefault() int
- type LimitsConfig
- func (l LimitsConfig) ApprovalDisplayBytesOrDefault() int
- func (l LimitsConfig) InboxPreviewBytesOrDefault() int
- func (l LimitsConfig) LastMessageRunesOrDefault() int
- func (l LimitsConfig) LogLinesOrDefault() int
- func (l LimitsConfig) MCPLogReadBytesOrDefault() int
- func (l LimitsConfig) WaitBufferBytesOrDefault() int
- func (l LimitsConfig) WaitScanLinesOrDefault() int
- type MCPServerConfig
- type Messages
- func (m Messages) BusyTimeoutDuration() time.Duration
- func (m Messages) ClampConversationLimit(limit int) int
- func (m Messages) ConversationMaxLimitOrDefault() int
- func (m Messages) ConversationPageSizeOrDefault() int
- func (m Messages) JailListLimitOrDefault() int
- func (m Messages) MaxAgeDuration() time.Duration
- func (m Messages) SubscriberBufferOrDefault() int
- type MigrationConfig
- type NotificationTiming
- func (t NotificationTiming) CoalesceWindowDuration() time.Duration
- func (t NotificationTiming) DispatchTimeoutDuration() time.Duration
- func (t NotificationTiming) InboxCooldownDuration() time.Duration
- func (t NotificationTiming) InboxDetachedDelayDuration() time.Duration
- func (t NotificationTiming) InboxIdleTimeoutDuration() time.Duration
- func (t NotificationTiming) InboxMaxWaitDuration() time.Duration
- type Notifications
- type OrchestratorConfig
- type OrchestratorRestartConfig
- type OrchestratorSandboxConfig
- type Overlay
- type OverlayKeybindings
- type PRWatchAdvancedConfig
- type PRWatchConfig
- func (p PRWatchConfig) BaseTickDuration() time.Duration
- func (p PRWatchConfig) BatchSize() int
- func (p PRWatchConfig) CommentBodyMaxBytes() int
- func (p PRWatchConfig) DebounceDuration() time.Duration
- func (p PRWatchConfig) GHTimeoutDuration() time.Duration
- func (p PRWatchConfig) KickChannelSize() int
- func (p PRWatchConfig) KickCooldownDuration() time.Duration
- func (p PRWatchConfig) KickedNoPRBackoffDuration() time.Duration
- func (p PRWatchConfig) MaxNotifications() int
- func (p PRWatchConfig) MaxPromptedAuthors() int
- func (p PRWatchConfig) NoPRNegativeCacheDuration() time.Duration
- func (p PRWatchConfig) NotificationRateLimit() int
- func (p PRWatchConfig) NotificationRateWindowDuration() time.Duration
- func (p PRWatchConfig) PollMergedDuration() time.Duration
- func (p PRWatchConfig) PollPendingDuration() time.Duration
- func (p PRWatchConfig) PollTerminalDuration() time.Duration
- func (p PRWatchConfig) RefDebounceDuration() time.Duration
- func (p PRWatchConfig) RefReconcileIntervalDuration() time.Duration
- func (p PRWatchConfig) TrustedAssociationSet() map[string]bool
- func (p PRWatchConfig) UntrustedAuthorPromptRate() int
- func (p PRWatchConfig) UntrustedAuthorPromptWindowDuration() time.Duration
- type PairRate
- type Paths
- type RemoteConfig
- type RepoConfig
- type ResourceMonitor
- type SandboxConfig
- type SandboxNetworkConfig
- type ScenarioLifecycleConfig
- type ScheduleConfig
- type StatusBar
- type StatusConfig
- type TemplateVars
- type TerminalConfig
- type TodoConfig
- func (t TodoConfig) BusyTimeoutDuration() time.Duration
- func (t TodoConfig) ClaimLeaseDuration() time.Duration
- func (t TodoConfig) EmitMode() string
- func (t TodoConfig) ListLimitOrDefault() int
- func (t TodoConfig) MaxNoteOrDefault() int
- func (t TodoConfig) MaxTitleOrDefault() int
- func (t TodoConfig) RetentionDuration() time.Duration
- func (t TodoConfig) SweepIntervalDuration() time.Duration
- type TokenAccounting
- type ToolsConfig
- type TrackerConfig
- type TranscriptConfig
- type TriggerConfig
- type TriggerPolicy
- type TriggerVars
- type TriggersAdvancedConfig
- type TriggersRuntime
- func (r TriggersRuntime) CommandOutputCap() int
- func (r TriggersRuntime) MaxConcurrentOr() int
- func (r TriggersRuntime) RunHistoryMax() int
- func (r TriggersRuntime) SchedulerTickDuration() time.Duration
- func (r TriggersRuntime) WatchBuiltinIgnores() []string
- func (r TriggersRuntime) WatchReconcileIntervalDuration() time.Duration
- func (r TriggersRuntime) WatchRetryBaseBackoffDuration() time.Duration
- func (r TriggersRuntime) WatchRetryMaxBackoffDuration() time.Duration
- type UnknownKey
- type UpdatesConfig
- type WatchConfig
- type Watcher
Constants ¶
const ( ConnectionDialTimeoutDefault = 500 * time.Millisecond ConnectionHandshakeTimeoutDefault = 5 * time.Second ConnectionStartTimeoutDefault = 5 * time.Second ConnectionStartPollIntervalDefault = 50 * time.Millisecond ConnectionReconnectTimeoutDefault = 10 * time.Second ConnectionReconnectIntervalDefault = 250 * time.Millisecond ConnectionRemoteDialTimeoutDefault = 10 * time.Second ConnectionRemoteHandshakeTimeoutDefault = 15 * time.Second ConnectionRemotePairingTimeoutDefault = 11 * time.Minute )
Connection timing defaults. Each mirrors the fixed value that governed the behaviour before issue #1242 made the policy configurable.
const ( HeadlessMaxLineBytesDefault = 16 * 1024 * 1024 HeadlessControlTimeoutDefault = 30 * time.Second HeadlessInterruptTimeoutDefault = 5 * time.Second HeadlessPreviewBytesDefault = 16 * 1024 )
Headless processing-limit defaults. Each mirrors the fixed constant that governed the behaviour before issue #1250 made the limits configurable.
const ( TranscriptMaxContextBytesDefault = 256 * 1024 TranscriptMaxToolOutputBytesDefault = 4 * 1024 TranscriptMaxLineBytesDefault = 16 * 1024 * 1024 TranscriptMaxMetadataBytesDefault = 4 * 1024 * 1024 )
Transcript processing-limit defaults. Each mirrors the fixed constant that governed the transcript reader/renderer before issue #1250.
const ( RemoteMaxPendingPairingsDefault = 16 RemoteMaxPendingPairingsMax = 1024 RemotePendingPairingTTLDefault = 10 * time.Minute RemotePendingPairingTTLMin = time.Minute RemotePendingPairingTTLMax = 24 * time.Hour RemotePairFallbackCountDefault = 5 RemotePairFallbackCountMax = 1000 RemotePairFallbackWindowDefault = time.Minute RemotePairFallbackWindowMin = time.Second RemotePairFallbackWindowMax = 24 * time.Hour )
Pairing policy bounds. Defaults preserve the historically-fixed values (16 pending, 10m TTL, 5/min fallback rate); the ceilings/floors keep an operator override from disabling anti-flood protection or pinning requests forever.
const ( OrchestratorInitialBackoffDefault = 2 * time.Second OrchestratorMaxBackoffDefault = 300 * time.Second OrchestratorMultiplierDefault = 2.0 OrchestratorStableResetDefault = 60 * time.Second OrchestratorFreshStartThresholdDefault = 3 )
Orchestrator restart defaults. The default schedule preserves graith's historical backoff curve exactly; the geometric defaults apply only when a user clears Schedule to opt into computed backoff.
const ( LaunchMaxConcurrentDefault = 3 LaunchStartupTimeoutDefault = 3 * time.Minute LaunchSettleTimeoutDefault = 10 * time.Second LaunchMaxRestartsDefault = 3 LaunchWatchdogIntervalDefault = 15 * time.Second LaunchSlotPollIntervalDefault = 100 * time.Millisecond )
Launch tuning defaults. MaxConcurrent defaults to 3 because the #1092 evidence showed ~4 concurrent startups completing fine while the 5th stalled.
const ( ConvertSettleTimeoutDefault = 5 * time.Second ConvertKillTimeoutDefault = 3 * time.Second ConvertForceKillTimeoutDefault = 3 * time.Second MassExitWindowDefault = 2 * time.Second MassExitThresholdDefault = 5 ProcessKillGraceDefault = 5 * time.Second AdoptedTimeoutDefault = 24 * time.Hour AdoptedPollIntervalDefault = time.Second ScrollbackHydrationBytesDefault = 128 * 1024 InputDelayDefault = 50 * time.Millisecond DefaultColsDefault = 80 DefaultRowsDefault = 24 MaxLogBytesDefault = 100 * 1024 * 1024 )
Lifecycle policy defaults. Each mirrors the fixed constant or bare literal that governed the behaviour before issue #1243 made the policy configurable.
const ( DetectionScanIntervalDefault = 500 * time.Millisecond DetectionFetchIntervalDefault = 5 * time.Minute DetectionFetchTimeoutDefault = 30 * time.Second DetectionSilentThresholdDefault = 20 * time.Second DetectionAdoptedGraceDefault = 60 * time.Second DetectionRecentOutputWindowDefault = 3 * time.Second DetectionHookStartWindowDefault = 5 * time.Second DetectionHookActivityWindowDefault = 30 * time.Second DetectionHookTerminalWindowDefault = 30 * time.Minute )
Detection timing defaults. Each mirrors the fixed constant that governed the behaviour before issue #1241 made the policy configurable.
const ( TokenPollIntervalDefault = 30 * time.Second TokenStartupDelayDefault = 5 * time.Second TokenBatchSizeDefault = 8 )
Token-accounting defaults mirror the fixed constants that governed the loop before issue #1244 made the policy configurable.
const ( ResourceSampleIntervalDefault = 30 * time.Second ResourceSampleHistoryDefault = 5 )
Resource-monitor defaults mirror the fixed constants that governed the loop before issue #1244 made the policy configurable.
const ( LimitsLogLinesDefault = 300 LimitsWaitScanLinesDefault = 500 LimitsWaitBufferBytesDefault = 64 * 1024 LimitsMCPLogReadBytesDefault = 1 << 20 // 1 MiB LimitsApprovalDisplayBytesDefault = 500 LimitsLastMessageRunesDefault = 2000 LimitsInboxPreviewBytesDefault = 1000 )
Limits defaults mirror the fixed constants and literals that governed each surface before issue #1252 unified them.
const ( TerminalRefreshIntervalDefault = 2 * time.Second TerminalSummaryWidth = 40 )
Terminal presentation defaults mirror the fixed literals that governed the behaviour before issue #1254 made the policy configurable.
const ( // PRWatchKickChannelSizeDefault absorbs a modest burst of git-ref events; // timer polling remains the fallback when the best-effort channel is full. PRWatchKickChannelSizeDefault = 64 // PRWatchKickChannelSizeMax bounds startup allocation for the channel. A // 4096-entry buffer is ample for large fleets while keeping the allocation // small and predictable even when configuration is untrusted. PRWatchKickChannelSizeMax = 4096 )
const ( MessagesConversationPageSizeDefault = 500 MessagesConversationMaxLimitDefault = 2000 MessagesJailListLimitDefault = 2000 MessagesSubscriberBufferDefault = 64 MessagesBusyTimeoutDefault = 5 * time.Second )
Messages operational-limit defaults, mirroring the fixed literals that governed the message log before issue #1249 made them configurable.
const ( MessagesConversationMaxLimitCeiling = 100_000 MessagesJailListLimitCeiling = 100_000 MessagesSubscriberBufferCeiling = 65_536 MessagesBusyTimeoutCeiling = 5 * time.Minute )
Hard safety ceilings for the [messages] operational limits. Config may tune a value up to (but not past) its ceiling; Validate rejects anything above it so a typo can't request an absurd allocation, unbounded sort, or an effectively infinite lock wait.
const ( // DefaultPurgeStartupDelay is how long after startup the first purge sweep // runs, catching windows that expired while the daemon was down without // racing the rest of daemon initialisation. DefaultPurgeStartupDelay = 30 * time.Second // DefaultPurgeInterval is how often the purge sweep runs after the first. DefaultPurgeInterval = 10 * time.Minute )
Purge-loop scheduling defaults, used when the matching [delete] key is unset. The window they sweep is measured in hours, so the cadence is deliberately coarse: purging a little late is harmless, and only the frozen ExpiresAt (not this timing) decides whether a session is recoverable.
const ( TodoEmitScenario = "scenario" // emit only for scenario-scoped lists (default) TodoEmitAll = "all" // emit for every scope TodoEmitOff = "off" // never emit )
Emit-events modes for the task-list subsystem.
const ( TodoMaxTitleDefault = 500 TodoMaxNoteDefault = 2000 TodoListLimitDefault = 2000 TodoSweepIntervalDefault = time.Minute TodoBusyTimeoutDefault = 5 * time.Second )
Task-list ([todo]) operational-limit defaults, mirroring the fixed literals that governed the store before issue #1249 made them configurable.
const ( TodoMaxTitleCeiling = 500 TodoMaxNoteCeiling = 2000 TodoListLimitCeiling = 100_000 TodoBusyTimeoutCeiling = 5 * time.Minute )
Hard safety ceilings for the [todo] operational limits. TodoMaxTitleCeiling and TodoMaxNoteCeiling equal the database CHECK constraints baked into the schema at creation — config may tighten below them but never past them, so a configured limit can never exceed what the database will accept. The others bound allocation and lock-wait time.
const ( NotifyCoalesceWindowDefault = 30 * time.Second NotifyDispatchTimeoutDefault = 15 * time.Second NotifyInboxIdleTimeoutDefault = 10 * time.Second NotifyInboxMaxWaitDefault = 2 * time.Minute NotifyInboxCooldownDefault = 30 * time.Second NotifyInboxDetachedDelayDefault = 5 * time.Second )
Notification timing defaults. Each mirrors the fixed constant that governed the behaviour before issue #1245 made the policy configurable.
const ( NotifyPriorityLow = "low" NotifyPriorityNormal = "normal" NotifyPriorityHigh = "high" )
Notification priority levels for `gr notify`.
const ( PromptInjectionAppendSystemPrompt = "append_system_prompt" PromptInjectionCursorRules = "cursor_rules" PromptInjectionDeveloperInstructions = "developer_instructions" PromptInjectionNone = "none" )
Valid values for [agents.<name>].prompt_injection. Each names a prompt delivery mechanism graith owns: append_system_prompt is Claude's --append-system-prompt flag, cursor_rules writes a .cursor/rules file, developer_instructions is Codex's -c developer_instructions override, and none suppresses injection. graith owns this enum (it maps to graith's own launch behaviour), so an unknown value is a config error rather than a silent no-op. See issue #1232.
const ( ScenarioCleanupOff = "off" ScenarioCleanupOnSuccess = "on_success" ScenarioCleanupAlways = "always" )
const ( TrackerStateOpen = "open" TrackerStateClosed = "closed" TrackerStateAll = "all" )
Tracker active-state values for TrackerConfig.ActiveState.
const ( TrackerReapStop = "stop" // stop the agent (recoverable via gr resume) TrackerReapDelete = "delete" // soft-delete the session (recoverable via gr restore) TrackerReapNone = "none" // leave the session; report only )
Tracker reap-policy values for TrackerConfig.Reap.
const ( ActionCommand = "command" ActionSession = "session" ActionScenario = "scenario" ActionMessage = "message" ActionTracker = "tracker" )
Action type values for ActionConfig.Type.
const ( OverlapSkip = "skip" OverlapAllow = "allow" OverlapQueue = "queue" // deferred to v2 )
Overlap policy values for TriggerPolicy.Overlap.
const ( CleanupAlways = "always" // delete on any stop CleanupOnSuccess = "on_success" // delete only on a clean (exit 0) stop )
Auto-cleanup mode values for a session action's AutoCleanup.
const ConfigReloadDebounceDefault = 200 * time.Millisecond
ConfigReloadDebounceDefault is the quiet period the config-file watcher waits after the last write before reloading, used when config reload_debounce is unset. It coalesces an editor's write-truncate-write burst into one reload.
const DefaultDeleteRetention = 24 * time.Hour
DefaultDeleteRetention is the soft-delete retention window used when [delete] retention is unset.
const DefaultGCOrphanMinAge = 5 * time.Minute
DefaultGCOrphanMinAge is the minimum age an orphaned worktree/scratch directory must have before GC will remove it, used when [gc] orphan_min_age is unset. Directories are created early in a session's lifecycle (during StatusCreating, before the session is committed to state), so a young directory may belong to an in-flight create that GC would otherwise race and destroy — the floor is a safety margin, not a cosmetic delay.
const DefaultNotifyMaxPerHour = 12
DefaultNotifyMaxPerHour is the rolling-hour cap on low/normal push notifications used when [notifications] max_per_hour is unset.
const DefaultRemotePort = 4823
DefaultRemotePort is the TCP port the tailnet control listener binds when [remote] port is unset, and the default the `gr remote pair` client dials. It is the single source of truth for the port on the Go side; the embedded default_config.toml carries the same value (kept in lockstep by a test) and the Swift clients mirror it via GraithTransport.defaultRemotePort.
const DefaultTodoClaimLease = 30 * time.Minute
DefaultTodoClaimLease is the default claim-lease window: an in-progress item whose owner has made no progress for this long is auto-reopened. 0 disables.
const (
GCXEventOnCallAlertGroup = "oncall_alert_group"
)
const MigrationHealthWindowDefault = 1500 * time.Millisecond
MigrationHealthWindowDefault is how long Migrate waits to confirm the target agent survived startup before declaring the migration successful, used when [migration] health_window is unset (issue #1250).
const RedactedMask = "***"
RedactedMask is the placeholder substituted for secret-bearing values when a config is rendered for a caller that must not see raw secrets.
const ReservedTriggerNamePrefix = "scenario:"
ReservedTriggerNamePrefix is reserved for the daemon's namespaced scenario-embedded trigger names (scenario:<id>:<name>). A config-origin trigger name must not use it, or it would be misrouted to a scenario lookup.
const SQLiteBusyTimeoutResolution = time.Millisecond
SQLiteBusyTimeoutResolution is the smallest busy_timeout SQLite can honour. The pragma takes a whole number of milliseconds, so any positive duration below 1ms would render as busy_timeout(0), which disables lock waiting entirely. Both the messages and todo busy timeouts are validated and clamped to at least this resolution (see #1322).
const (
TrackerProviderGitHub = "github"
)
Tracker provider values for TrackerConfig.Provider.
Variables ¶
var DefaultTrustedAssociations = []string{"OWNER", "MEMBER", "COLLABORATOR"}
DefaultTrustedAssociations is the trusted author_association set used when pr_watch.trusted_author_associations is unset. It is the "has write access to, or is a member of the org that owns, the repo" tier; CONTRIBUTOR is excluded deliberately (on a public repo it means only "merged a commit once", and bots can carry it — see the author-trust design doc).
var DefaultWatchBuiltinIgnores = []string{".git/", ".git", ".hg/", ".svn/", "*.swp", "*.swx", "4913", ".DS_Store"}
DefaultWatchBuiltinIgnores is the daemon-wide set of directories/patterns never watched by a file-watch trigger when [triggers.advanced] watch_builtin_ignores is unset. Watching any of these is never useful and they are prime feedback-loop / churn sources. Materialized in default_config.toml.
var SandboxSignalModes = []string{"isolated", "allow_same_sandbox", "allow_all"}
SandboxSignalModes are the accepted values for [sandbox] signal_mode. They mirror nono v0.66.0's security.signal_mode enum. Empty is also valid (inherit nono's base-profile default).
Functions ¶
func DefaultAgentPrompt ¶ added in v0.35.0
func DefaultAgentPrompt() string
func DefaultTOML ¶ added in v0.19.0
func DefaultTOML() []byte
func DiffFromDefaults ¶ added in v0.68.5
DiffFromDefaults returns a unified diff (built-in defaults → cfg) of the two TOML renderings. toLabel names the "to" side in the diff header (e.g. the config file path, or "effective"). An empty return means cfg's effective rendering is byte-for-byte identical to the built-in defaults' rendering.
func EffectiveTOML ¶ added in v0.68.5
EffectiveTOML renders cfg as TOML — the effective, fully-merged configuration (built-in defaults overlaid with the user's file). This is what `gr config show` prints and what the GUI's config viewer displays.
func ExpandPath ¶ added in v0.11.0
func ExpandPathRelative ¶ added in v0.66.0
ExpandPathRelative resolves a configured path deterministically: it expands a leading ~/, and resolves a still-relative path against baseDir (the directory holding the config file) rather than the process working directory, then cleans the result. This keeps a value like [approvals.builtin] config resolving to the same absolute path regardless of which directory the daemon or CLI happens to run from. An empty (or whitespace-only) path stays empty so callers can distinguish "unset" from a resolved path.
func ExpandSlice ¶
func ExpandSlice(ss []string, vars TemplateVars) ([]string, error)
func ExpandTrigger ¶ added in v0.67.0
func ExpandTrigger(s string, vars TriggerVars) (string, error)
ExpandTrigger replaces {token} occurrences in s using the trigger variable set. An unknown token is an error (parity with Expand's discipline).
func IncludeEnvVarName ¶ added in v0.19.0
func IsTemplateVar ¶ added in v0.69.1
IsTemplateVar reports whether name is a known template variable (one of the keys TemplateVars expands). Used to validate an agent's option_args `when` gate so a typo (`when = "reasoning"`) is caught at config-load time rather than silently never firing.
func LegacyRuntimeDirs ¶ added in v0.11.0
func LegacyRuntimeDirs() []string
LegacyRuntimeDirs returns paths where older versions stored the socket and PID file (TMPDIR or /tmp fallbacks). Used during startup to detect and clean up an orphaned daemon after the socket location changed.
func NormalizeNotifyPriority ¶ added in v0.67.2
NormalizeNotifyPriority resolves a user-supplied priority to a canonical level, defaulting an empty value to "normal". It reports ok=false for an unrecognised value so callers can reject it.
func ParseDurationWithDays ¶ added in v0.3.0
func ResolveConfigPath ¶ added in v0.66.0
ResolveConfigPath returns the config file that LoadOrDefault(explicit) would read and whether that file exists on disk. When explicit is set it is used verbatim. When empty, resolution mirrors LoadOrDefault: the profile/XDG path, falling back to the legacy macOS path only when the XDG file is absent and no profile is active. Diagnostics (e.g. gr doctor) use this so the reported and inspected file is the same one the CLI/daemon actually load.
func ResolvePath ¶ added in v0.16.5
func ResolveProfile ¶ added in v0.18.0
func ValidPromptInjection ¶ added in v0.69.1
ValidPromptInjection reports whether s is empty (name-based fallback) or one of the known prompt_injection method names.
func ValidateIncludes ¶ added in v0.68.7
ValidateIncludes checks a set of include paths against the main repo for the collisions that would break the worktree/env-var layout: an include equal to the main repo, duplicate basenames (across the main repo and the includes), and generated GRAITH_INCLUDE_* env-var name collisions. Included worktrees and their env vars are keyed by basename, so these must be unique. Used both by repo-config validation and by the session-create path for scenario-supplied includes (issue #1046), so both surfaces reject the same footguns up front rather than failing with a low-level git error mid-setup.
func ValidateScenarioLifecycle ¶ added in v0.69.2
func ValidateScenarioLifecycle(c ScenarioLifecycleConfig) error
func ValidateTriggerStructure ¶ added in v0.68.5
func ValidateTriggerStructure(where string, t *TriggerConfig) []error
ValidateTriggerStructure runs the config-independent structural validation for a single trigger: exactly one source, the source's own rules, the action's shape, and the policy. Config-dependent checks (allowed_repo_paths and [orchestrator] enabled) are layered on separately by validateActionConfigDeps. It is exported so the scenario-file loader can hold scenario-embedded [[trigger]] blocks to the same shape rules without a full *Config.
Types ¶
type ActionConfig ¶ added in v0.67.0
type ActionConfig struct {
Type string `toml:"type"` // command | session | scenario | message | tracker
// command:
Command string `toml:"command"`
Repo string `toml:"repo"` // required for schedule commands; rejected for watch
Timeout string `toml:"timeout"` // max run time; default 5m
Mutating bool `toml:"mutating"` // may write its execution root; rejected in v1
Sandbox *bool `toml:"sandbox"` // nil => default true; false runs unconfined
// SandboxConfig is extra sandbox grants merged onto the base command profile,
// mirroring the MCP-server pattern (MCPServerConfig.SandboxConfig).
SandboxConfig *SandboxConfig `toml:"sandbox_config"`
// session:
Prompt string `toml:"prompt"`
Agent string `toml:"agent"`
Model string `toml:"model"`
Ensure bool `toml:"ensure"` // idempotent ensure-reviewer (watch source only)
// AutoCleanup soft-deletes a trigger-spawned session once it stops, so a
// finished briefing/report session doesn't clutter `gr list`. It is a union
// of bool and string: absent/false/"" disables it; true (or "always")
// deletes on any stop; "on_success" deletes only on a clean (exit 0) stop.
// Decoded as any so TOML can supply either a bool or the string enum; use
// AutoCleanupMode to normalise. Session action only.
AutoCleanup any `toml:"auto_cleanup"`
// IdleTimeout auto-stops the spawned session after it sits idle (agent at
// rest, no attached client) this long, overriding the agent default. A Go
// duration ("1m", "5m"). Session action only. When unset, an
// auto_cleanup="always" session defaults to a short idle window so a finished
// briefing reaps itself promptly (finish -> idle-stop -> soft-delete); see
// SessionIdleTimeout.
IdleTimeout string `toml:"idle_timeout"`
// scenario:
Scenario string `toml:"scenario"`
// tracker: keep live sessions in sync with an issue tracker. On each
// scheduled fire the daemon polls the tracker for active issues and
// reconciles sessions against them — spawning one per active issue (seeded
// with the templated Prompt above) and reaping the session when its issue
// leaves the active state. Schedule source only. See TrackerConfig and
// docs/design/2026-07-16-tracker-poll-action.md.
Tracker *TrackerConfig `toml:"tracker"`
// message:
Body string `toml:"body"`
// notify (any action type): when NotifyOnComplete is set, the daemon fires a
// proactive push notification (see [notifications]) once the action finishes
// firing. NotifyMessage is the body (templated with the trigger vars;
// defaults to a generic "<name> completed"); NotifyPriority is low/normal/high
// (defaults to normal, or high when the action errored).
NotifyOnComplete bool `toml:"notify_on_complete"`
NotifyMessage string `toml:"notify_message"`
NotifyPriority string `toml:"notify_priority"`
Deliver DeliverConfig `toml:"deliver"`
}
ActionConfig is the shared action vocabulary. Type selects the verb.
func (ActionConfig) AutoCleanupMode ¶ added in v0.67.2
func (a ActionConfig) AutoCleanupMode() (string, error)
AutoCleanupMode normalises the auto_cleanup union to "" (disabled), CleanupAlways, or CleanupOnSuccess. true is shorthand for "always"; false and an absent value are disabled. Any other value is a config error.
func (ActionConfig) RepoPath ¶ added in v0.67.2
func (a ActionConfig) RepoPath() string
RepoPath returns the action's configured repo canonicalised the same way sessions and the store CLI treat a repo path: a leading ~/ expanded, made absolute, and symlinks resolved (via ResolvePath). This matters for repo-store delivery, whose namespace is keyed off the repo path — a raw ~/... or a symlinked spelling would otherwise scope to a different store than the one agents read. It returns "" when no repo is set — unlike ResolvePath/ExpandPath, which would resolve "" to the working directory — so callers can still distinguish "unset" (shared store / no execution root) from a resolved path.
func (ActionConfig) Sandboxed ¶ added in v0.67.0
func (a ActionConfig) Sandboxed() bool
Sandboxed reports whether a command action runs sandboxed (nil => true).
func (ActionConfig) SessionIdleTimeout ¶ added in v0.67.2
func (a ActionConfig) SessionIdleTimeout() (time.Duration, error)
SessionIdleTimeout resolves the idle-stop window for a spawned session action. An explicit idle_timeout always wins. Otherwise an auto_cleanup="always" session gets defaultAutoCleanupIdle so it reaps itself promptly. "on_success" is deliberately not auto-idled: an idle-stop is a non-zero (SIGTERM) exit that "on_success" would not clean up, so idling it would just leave stopped clutter — the very thing auto_cleanup avoids. 0 means "use the agent default".
func (ActionConfig) TimeoutDuration ¶ added in v0.67.0
func (a ActionConfig) TimeoutDuration() time.Duration
TimeoutDuration returns a command action's timeout, defaulting to 5m.
type Agent ¶
type Agent struct {
Command string `json:"command" toml:"command"`
Args []string `json:"args,omitempty" toml:"args"`
ResumeArgs []string `json:"resume_args,omitempty" toml:"resume_args"`
ForkArgs []string `json:"fork_args,omitempty" toml:"fork_args"`
Env map[string]string `json:"env,omitempty" toml:"env"`
IdleTimeout string `json:"idle_timeout,omitempty" toml:"idle_timeout"`
InjectPrompt *bool `json:"inject_prompt,omitempty" toml:"inject_prompt"`
// PromptInjection selects HOW graith delivers its operating prompt to this
// agent (append_system_prompt / cursor_rules / developer_instructions /
// none). It is distinct from InjectPrompt, which is the on/off switch. An
// empty value falls back to name-based detection so the built-in claude,
// cursor, and codex agents work without explicit config; a custom agent
// must set this to receive a prompt at all. Validated in Config.Validate.
// See issue #1232.
PromptInjection string `json:"prompt_injection,omitempty" toml:"prompt_injection"`
PreTrustWorkspace *bool `json:"pre_trust_workspace,omitempty" toml:"pre_trust_workspace"`
Sandbox SandboxConfig `json:"sandbox" toml:"sandbox"`
MCPServers map[string]MCPServerConfig `json:"mcp_servers,omitempty" toml:"mcp_servers"`
ValidateModel string `json:"validate_model,omitempty" toml:"validate_model"`
// InterruptCount is how many times the interrupt byte (Ctrl-C, 0x03) is sent
// to interrupt this agent, and InterruptDelayMs is the pause in milliseconds
// between successive sends. Some agent TUIs ignore a single Ctrl-C and need
// two rapid presses to actually interrupt (Claude's TUI wants ~200ms apart),
// so both are configurable per agent. Unset means the built-in defaults
// (count 1, delay 0). See issue #620.
InterruptCount *int `json:"interrupt_count,omitempty" toml:"interrupt_count"`
InterruptDelayMs *int `json:"interrupt_delay_ms,omitempty" toml:"interrupt_delay_ms"`
// HeadlessCapable marks an agent as supporting headless stream-json mode
// (issue #1075). Unset means not capable — only agents explicitly flagged
// (Claude Code in v1) may run headless, so a --headless request against an
// unsupported agent fails closed rather than silently downgrading.
HeadlessCapable *bool `json:"headless_capable,omitempty" toml:"headless_capable"`
// AddDirArgs is the flag template graith uses to grant the agent access to an
// additional directory — each included repo's co-located worktree. It is
// expanded once per directory with {dir} bound to that path (see
// AddDirArgsFor). An empty AddDirArgs means the agent's CLI has no such flag,
// so its included worktrees are exposed only via the GRAITH_INCLUDE_*_PATH env
// vars; this replaces the former hard-coded agentSupportsAddDir allowlist so a
// custom agent can opt in from config alone (issue #1236). Built-in
// claude/codex/cursor set ["--add-dir", "{dir}"].
AddDirArgs []string `json:"add_dir_args,omitempty" toml:"add_dir_args"`
// HeadlessArgs is the argv prefix graith prepends when launching this agent in
// headless stream-json mode (issue #1075); the agent's own template-expanded
// args follow it. Only consulted for a headless session. Moving it here (from
// the former hard-coded headlessArgs) lets a custom headless_capable agent
// define its own control-channel flags (issue #1236). Built-in claude sets the
// `-p --output-format stream-json …` flags.
HeadlessArgs []string `json:"headless_args,omitempty" toml:"headless_args"`
// OptionArgs are conditional argv groups appended after the base args on every
// launch (create/resume/fork). Each group's Args are template-expanded and
// appended only when its When template variable resolves non-empty, so an
// unset option leaves the agent's own default untouched — e.g. codex's
// ["--model", "{model}"] gated on `when = "model"`. This moves the formerly
// hard-coded codex adapter (model / profile / reasoning-effort / service-tier
// / search / approval flags) into config so custom agents can define their own
// conditional flags (issue #1236).
OptionArgs []AgentOptionArg `json:"option_args,omitempty" toml:"option_args"`
}
func (Agent) AddDirArgsFor ¶ added in v0.69.1
func (a Agent) AddDirArgsFor(base TemplateVars, dirs []string) ([]string, error)
AddDirArgsFor builds the add-directory flags granting the agent access to each of dirs, expanding a.AddDirArgs once per directory with {dir} bound to it (the rest of base is carried through so a template may also reference the usual vars). Empty AddDirArgs — or no directories — yields nil, so an agent whose CLI has no add-dir flag never has an unknown flag injected. Empty directory entries are skipped defensively.
func (Agent) HeadlessCapableEnabled ¶ added in v0.67.8
HeadlessCapableEnabled reports whether this agent may run in headless stream-json mode. Defaults to false when unset.
func (Agent) IdleTimeoutDuration ¶
func (Agent) InterruptCountValue ¶ added in v0.66.2
InterruptCountValue returns how many times the interrupt byte (Ctrl-C, 0x03) should be sent to interrupt this agent. Defaults to 1 when unset; a value below 1 is clamped to 1 so an interrupt always sends at least once.
func (Agent) InterruptDelay ¶ added in v0.66.2
InterruptDelay returns the pause between successive interrupt bytes. Defaults to 0 (send back-to-back) when unset; a negative value is treated as 0.
func (Agent) OptionArgsFor ¶ added in v0.69.1
func (a Agent) OptionArgsFor(vars TemplateVars) ([]string, error)
OptionArgsFor expands the agent's conditional option-arg groups against vars, appending each group only when its When gate resolves non-empty (an empty When always emits). Returns nil when no group fires, so it is safe to append unconditionally on every launch path. This is the config-driven replacement for the hard-coded codex flag adapter (issue #1236).
func (Agent) PreTrustWorkspaceEnabled ¶ added in v0.48.0
func (Agent) PromptInjectionEnabled ¶ added in v0.32.0
type AgentOptionArg ¶ added in v0.69.1
type AgentOptionArg struct {
// When names the template variable that gates this group: the args are
// emitted only when the variable resolves to a non-empty value ("true" for a
// boolean such as web_search). An empty When emits the group unconditionally.
When string `json:"when,omitempty" toml:"when"`
// Args are the argv templates emitted when the gate passes. They are expanded
// with the same TemplateVars as the base args plus the option variables.
Args []string `json:"args" toml:"args"`
}
AgentOptionArg is one conditional argv group for an agent (see Agent.OptionArgs).
type Approvals ¶ added in v0.13.0
type Approvals struct {
// Enabled controls whether the PreToolUse approve-request gating hook is
// installed. nil (unset) means disabled: the status/lifecycle hooks are
// still installed but the approval gate is not, because unattended agents
// otherwise see their own tool calls as human-rejected and the OS sandbox
// is the intended guardrail. Set to true to opt back into human approval
// gating.
Enabled *bool `toml:"enabled"`
// Backend selects who makes the automated decision: "" (none — always
// prompt the human), "command"/"external" (delegate to a command over
// graith's JSON contract), "localmost" (the real localmost binary over its
// native protocol), or "builtin" (graith's built-in localmost-compatible
// engine). It is the canonical selector; Mode is the deprecated predecessor.
Backend string `toml:"backend"`
Mode string `toml:"mode"`
AutoPop bool `toml:"auto_pop"`
Timeout string `toml:"timeout"`
Command string `toml:"command"`
Builtin ApprovalsBuiltin `toml:"builtin"`
// CommandTimeout bounds a single external "command"/"external" backend
// invocation; LocalmostTimeout bounds a single "localmost" binary check.
// Both default to defaultBackendExecTimeout (5s) when unset (see
// CommandTimeoutDuration/LocalmostTimeoutDuration). Each must be positive,
// no larger than maxBackendExecTimeout, and strictly shorter than the
// enclosing human/headless approval Timeout so a hung backend cannot outlive
// the deadline that encloses it — a class of bug that previously caused
// approval-behaviour glitches (see #244). Validate enforces this hierarchy.
CommandTimeout string `toml:"command_timeout"`
LocalmostTimeout string `toml:"localmost_timeout"`
}
func (Approvals) BackendExecTimeout ¶ added in v0.69.1
BackendExecTimeout returns the effective execution timeout for a resolved backend name and whether that backend runs a bounded subprocess at all. Only the command/external and localmost backends spawn a child process; the others (prompt/builtin/auto) decide in-process and have no execution timeout.
func (Approvals) CommandTimeoutDuration ¶ added in v0.69.1
CommandTimeoutDuration is the effective execution timeout for the command/external backend, falling back to defaultBackendExecTimeout when unset or unparseable. Validate rejects a set-but-invalid value up front, so a fallback here only happens for an unset field.
func (Approvals) HookEnabled ¶ added in v0.65.0
HookEnabled reports whether the approve-request PreToolUse hook should be installed. Defaults to false when unset — approval gating is opt-in.
func (Approvals) LocalmostTimeoutDuration ¶ added in v0.69.1
LocalmostTimeoutDuration is the effective execution timeout for the localmost backend, falling back to defaultBackendExecTimeout when unset or unparseable.
func (Approvals) ResolveBackend ¶ added in v0.64.4
ResolveBackend resolves the effective approvals backend, applying back-compat for the deprecated Mode field. It returns the backend name, a non-empty deprecation message when a legacy Mode value was used (callers log it once), and an error for an unknown backend or a conflicting Mode+Backend pair.
Resolution order:
- If Backend is set, use it. If a legacy Mode is ALSO set and maps to a different backend, that is a hard error (refuse to guess intent).
- Else if Mode is one of command/external/localmost, map it to the "command" backend (historical behaviour) and return a deprecation message. A Mode with no Backend is always a warning, never an error.
- Else, the "prompt" backend (no automation).
func (Approvals) TimeoutDuration ¶ added in v0.13.0
func (Approvals) Validate ¶ added in v0.64.5
Validate checks the [approvals] config for static contradictions that would otherwise only surface as an opaque fail-closed session crash at create time (see #740). It rejects an unknown or conflicting backend/mode (via ResolveBackend) and a command key set for a resolved backend that ignores it. Backend *availability* (command present, localmost binary on PATH, builtin config loadable) is still deferred to session-create by the daemon.
type ApprovalsBuiltin ¶ added in v0.64.4
type ApprovalsBuiltin struct {
// Config is the path to a localmost-format config.json (allow/deny rules).
Config string `toml:"config"`
// Allow and Deny are the inline allow/deny rulesets. Each element is either
// a bare rule string ("@arg @*") or a table with per-rule keys
// (rule/unless/redirect/pipe). They are decoded as []any so both TOML forms
// — an array of strings and an array of tables ([[approvals.builtin.allow]])
// — are accepted, then converted to the localmost schema (see InlineJSON).
Allow []any `toml:"allow"`
Deny []any `toml:"deny"`
// AllowSafeXargs and AskNoninteractive mirror the localmost top-level flags.
// nil means unset (the engine's default of true applies).
AllowSafeXargs *bool `toml:"allowSafeXargs"`
AskNoninteractive *bool `toml:"askNoninteractive"`
}
ApprovalsBuiltin configures the built-in localmost-compatible engine. Rules can be supplied either as a path to an external localmost-format config.json (Config), or inline in config.toml via Allow/Deny/AllowSafeXargs/ AskNoninteractive. The two forms are mutually exclusive (see Approvals.Validate).
func (ApprovalsBuiltin) HasInline ¶ added in v0.66.0
func (b ApprovalsBuiltin) HasInline() bool
HasInline reports whether any inline ruleset field is set. When true, the rules are read from config.toml rather than an external Config file. An empty array (allow = []) defines no rules and does not count as inline, so it does not spuriously conflict with an external Config path.
func (ApprovalsBuiltin) InlineJSON ¶ added in v0.66.0
func (b ApprovalsBuiltin) InlineJSON() ([]byte, error)
InlineJSON renders the inline ruleset as localmost-format config.json bytes, so the existing (tested) localmost parser can compile it. The TOML keys map 1:1 to the localmost JSON schema (allow/deny/allowSafeXargs/askNoninteractive, and per-rule rule/unless/redirect/pipe), so a plain JSON re-encode suffices.
type CodexOptions ¶ added in v0.68.8
type CodexOptions struct {
Profile string `json:"profile,omitempty"`
ReasoningEffort string `json:"reasoning_effort,omitempty"`
ServiceTier string `json:"service_tier,omitempty"`
WebSearch bool `json:"web_search,omitempty"`
ApprovalPolicy string `json:"approval_policy,omitempty"`
}
CodexOptions holds typed per-session options for the Codex CLI (issue #1186). Each maps to a Codex flag or `-c` config override and is emitted only when set, so an unset field leaves Codex's own default untouched. The session model is tracked separately (SessionState.Model / CreateOpts.Model) and is not repeated here. These are Codex-specific: setting any against a non-codex agent is an error rather than a silent no-op. Reasoning effort and service tier are passed as `-c model_reasoning_effort=…` / `-c service_tier=…` because Codex has no dedicated flag for them; profile, web search, and approval policy have flags.
func (CodexOptions) IsZero ¶ added in v0.68.8
func (o CodexOptions) IsZero() bool
IsZero reports whether no Codex option is set.
type CompletionConfig ¶ added in v0.69.2
CompletionConfig is the todo-derived scenario-completion source. It is only valid on a scenario-embedded trigger. Session optionally names the scenario member whose worktree supplies execution/mirror context; command and session actions require it. Event defaults to "complete" when omitted (the only v1 event).
type Config ¶
type Config struct {
DefaultAgent string `toml:"default_agent"`
GitHubUsername string `toml:"github_username"`
BranchPrefix string `toml:"branch_prefix"`
DataDir string `toml:"data_dir"`
FetchOnCreate bool `toml:"fetch_on_create"`
AgentPrompt string `toml:"agent_prompt"`
AllowedRepoPaths []string `toml:"allowed_repo_paths"`
Repos []RepoConfig `toml:"repos"`
StatusBar StatusBar `toml:"status_bar"`
Keybindings Keybindings `toml:"keybindings"`
Notifications Notifications `toml:"notifications"`
Messages Messages `toml:"messages"`
Delete Delete `toml:"delete"`
GC GCConfig `toml:"gc"`
Todo TodoConfig `toml:"todo"`
Sandbox SandboxConfig `toml:"sandbox"`
Approvals Approvals `toml:"approvals"`
Status StatusConfig `toml:"status"`
GitPull GitPullConfig `toml:"git_pull"`
Launch LaunchConfig `toml:"launch"`
PRWatch PRWatchConfig `toml:"pr_watch"`
MCPServers []MCPServerConfig `toml:"mcp_servers"`
Overlay Overlay `toml:"overlay"`
Orchestrator OrchestratorConfig `toml:"orchestrator"`
Remote RemoteConfig `toml:"remote"`
Input InputConfig `toml:"input"`
Agents map[string]Agent `toml:"agents"`
Triggers []TriggerConfig `toml:"trigger"` // [[trigger]] array
TriggersRuntime TriggersRuntime `toml:"triggers"` // [triggers] table (daemon-wide settings)
Headless HeadlessConfig `toml:"headless"` // [headless] table (issue #1075)
Updates UpdatesConfig `toml:"updates"` // [updates] table (issue #1253)
Detection DetectionConfig `toml:"detection"` // [detection] table (issue #1241)
ConfigReload ConfigReload `toml:"config"` // [config] table (issue #1237)
Tools ToolsConfig `toml:"tools"` // [tools] table (issue #1238)
Git GitConfig `toml:"git"` // [git] table (issue #1238)
Connection ConnectionConfig `toml:"connection"` // [connection] table (issue #1242)
TokenAccounting TokenAccounting `toml:"token_accounting"` // [token_accounting] table (issue #1244)
ResourceMonitor ResourceMonitor `toml:"resource_monitor"` // [resource_monitor] table (issue #1244)
Migration MigrationConfig `toml:"migration"` // [migration] table (issue #1250)
Transcript TranscriptConfig `toml:"transcript"` // [transcript] table (issue #1250)
Limits LimitsConfig `toml:"limits"` // [limits] table (issue #1252)
Lifecycle LifecycleConfig `toml:"lifecycle"` // [lifecycle] table (issue #1243)
Terminal TerminalConfig `toml:"terminal"` // [terminal] table (issue #1254)
// Warnings collects non-fatal configuration problems detected at load time
// (e.g. conflicting keybindings). They are surfaced to the user but do not
// prevent startup. Not serialised. See issue #1233.
Warnings []string `toml:"-"`
// SourceDir is the absolute directory containing the config.toml this Config
// was loaded from. It anchors relative paths in the config (currently the
// [tools] executable overrides) so they mean the same file regardless of the
// process working directory or a later exec.Cmd.Dir. Empty for an in-memory
// Default() with no source file. Not serialised. See issue #1293.
SourceDir string `toml:"-"`
}
func LoadOrDefault ¶
func RedactSecrets ¶ added in v0.68.5
RedactSecrets returns a copy of cfg with secret-bearing values masked: the per-server and per-agent `env` maps, whose values routinely hold tokens and API keys inline in config.toml. Map keys are preserved (so the shape stays visible); only the values are replaced with RedactedMask. cfg is not mutated.
The daemon renders this — not the raw config — over the control protocol, so a remote paired human, or a local session reading via the socket, sees the configuration structure without its secrets. `gr config show`/`diff` read the file directly (not through the daemon) and are deliberately unaffected.
func (*Config) AvailableRepoPaths ¶ added in v0.66.13
AvailableRepoPaths returns the repo paths the orchestrator may use, combining the allowed_repo_paths list and the [[repos]] entries with ~ expanded, in config order and de-duplicated. It returns nil when none are configured.
func (*Config) FindRepo ¶ added in v0.18.0
func (c *Config) FindRepo(repoPath string) (RepoConfig, bool)
func (*Config) OrchestratorSandboxMerged ¶ added in v0.46.0
func (c *Config) OrchestratorSandboxMerged(agentName string) SandboxConfig
func (*Config) RepoPathAllowed ¶ added in v0.11.0
type ConfigReload ¶ added in v0.69.1
type ConfigReload struct {
// ReloadDebounce is the quiet period the file watcher waits after the last
// write before reloading. Empty, unparseable, or non-positive uses the
// default (ConfigReloadDebounceDefault).
ReloadDebounce string `toml:"reload_debounce"`
}
ConfigReload is the config block: settings governing how graith handles its own configuration file. Currently just the hot-reload debounce, moved out of a bare literal in the watcher so `gr config show` reflects it (issue #1237).
func (ConfigReload) ReloadDebounceDuration ¶ added in v0.69.1
func (c ConfigReload) ReloadDebounceDuration() time.Duration
ReloadDebounceDuration resolves the config-reload debounce. Empty, unparseable, or non-positive falls back to the default so a typo never busy-loops the watcher (Validate rejects a set-but-invalid value at load; this is the runtime fail-safe).
type ConnectionConfig ¶ added in v0.69.1
type ConnectionConfig struct {
// DialTimeout bounds a single Unix-socket dial to the local daemon
// (default "500ms").
DialTimeout string `toml:"dial_timeout"`
// HandshakeTimeout bounds the local-daemon handshake exchange, so a stale
// or wedged socket can't hang a command forever (default "5s").
HandshakeTimeout string `toml:"handshake_timeout"`
// StartTimeout is the aggregate bound while EnsureDaemon waits for a freshly
// spawned daemon to begin answering handshakes (default "5s"). Individual
// dial/handshake policies are capped at the time remaining.
StartTimeout string `toml:"start_timeout"`
// StartPollInterval is how often EnsureDaemon re-probes the socket while
// waiting for a spawned daemon to come up (default "50ms").
StartPollInterval string `toml:"start_poll_interval"`
// ReconnectTimeout bounds the attach disconnect-recovery retry before the
// client gives up reattaching (default "10s").
ReconnectTimeout string `toml:"reconnect_timeout"`
// ReconnectInterval is how often the attach recovery loop re-probes the
// daemon while reconnecting (default "250ms").
ReconnectInterval string `toml:"reconnect_interval"`
// RemoteDialTimeout bounds the TCP dial to a paired remote daemon
// (default "10s").
RemoteDialTimeout string `toml:"remote_dial_timeout"`
// RemoteHandshakeTimeout bounds the remote handshake plus
// proof-of-possession exchange (default "15s").
RemoteHandshakeTimeout string `toml:"remote_handshake_timeout"`
// RemotePairingTimeout bounds how long the CLI waits for the remote human to
// approve `gr pair`, and should sit just past the daemon's pending-pairing
// TTL (default "11m").
RemotePairingTimeout string `toml:"remote_pairing_timeout"`
}
ConnectionConfig is the [connection] block tuning the deadlines and retry cadence the stateless `gr` client applies when talking to a daemon (issue #1242). Previously these were hard-coded (local dial 500ms, handshake/start 5s, startup re-probe 50ms, attach reconnect 10s/250ms, remote dial/handshake 10s/15s, remote pairing wait 11m). Slow machines, high-latency links, and remote daemons on constrained networks can legitimately exceed the built-in bounds, so each is overridable. Every value is a duration; an empty, unparseable, or non-positive entry keeps the built-in default (a bad value is rejected at config load by Validate). These are read once at CLI startup and installed into the client, so a change takes effect on the next `gr` invocation.
func (ConnectionConfig) DialTimeoutDuration ¶ added in v0.69.1
func (c ConnectionConfig) DialTimeoutDuration() time.Duration
DialTimeoutDuration returns the local-daemon dial timeout, or the default when unset, unparseable, or non-positive (a zero/negative timeout would abort the dial immediately).
func (ConnectionConfig) HandshakeTimeoutDuration ¶ added in v0.69.1
func (c ConnectionConfig) HandshakeTimeoutDuration() time.Duration
HandshakeTimeoutDuration returns the local-daemon handshake timeout, or the default when unset, unparseable, or non-positive.
func (ConnectionConfig) ReconnectIntervalDuration ¶ added in v0.69.1
func (c ConnectionConfig) ReconnectIntervalDuration() time.Duration
ReconnectIntervalDuration returns the attach reconnect re-probe interval, or the default when unset, unparseable, or non-positive (a zero interval would busy-loop).
func (ConnectionConfig) ReconnectTimeoutDuration ¶ added in v0.69.1
func (c ConnectionConfig) ReconnectTimeoutDuration() time.Duration
ReconnectTimeoutDuration returns the attach reconnect deadline, or the default when unset, unparseable, or non-positive.
func (ConnectionConfig) RemoteDialTimeoutDuration ¶ added in v0.69.1
func (c ConnectionConfig) RemoteDialTimeoutDuration() time.Duration
RemoteDialTimeoutDuration returns the remote TCP dial timeout, or the default when unset, unparseable, or non-positive.
func (ConnectionConfig) RemoteHandshakeTimeoutDuration ¶ added in v0.69.1
func (c ConnectionConfig) RemoteHandshakeTimeoutDuration() time.Duration
RemoteHandshakeTimeoutDuration returns the remote handshake/PoP timeout, or the default when unset, unparseable, or non-positive.
func (ConnectionConfig) RemotePairingTimeoutDuration ¶ added in v0.69.1
func (c ConnectionConfig) RemotePairingTimeoutDuration() time.Duration
RemotePairingTimeoutDuration returns the remote pairing-approval wait, or the default when unset, unparseable, or non-positive.
func (ConnectionConfig) StartPollIntervalDuration ¶ added in v0.69.1
func (c ConnectionConfig) StartPollIntervalDuration() time.Duration
StartPollIntervalDuration returns the daemon-startup re-probe interval, or the default when unset, unparseable, or non-positive (a zero interval would busy-loop).
func (ConnectionConfig) StartTimeoutDuration ¶ added in v0.69.1
func (c ConnectionConfig) StartTimeoutDuration() time.Duration
StartTimeoutDuration returns the daemon-startup wait, or the default when unset, unparseable, or non-positive.
type Delete ¶ added in v0.66.16
type Delete struct {
Retention string `toml:"retention"`
PurgeStartupDelay string `toml:"purge_startup_delay"`
PurgeInterval string `toml:"purge_interval"`
}
Delete configures the soft-delete behaviour of `gr delete`. When retention is a positive duration, `gr delete` marks a session deleted and keeps its worktree/state for the window; the daemon purges it after the window elapses. A retention of "0" disables soft delete: `gr delete` is then rejected (with a message pointing at `gr purge`), since delete must never destroy — `gr purge` remains the way to hard-delete immediately.
PurgeStartupDelay and PurgeInterval tune ONLY the sweep cadence, never whether a session is recoverable: a session is purged only once its frozen ExpiresAt (DeletedAt + retention) has passed, so no timing value can turn soft delete into an immediate hard delete.
func (Delete) PurgeIntervalDuration ¶ added in v0.69.1
PurgeIntervalDuration resolves the steady-state interval between purge sweeps. Unset, unparseable, or non-positive values fall back to the default.
func (Delete) PurgeStartupDelayDuration ¶ added in v0.69.1
PurgeStartupDelayDuration resolves the delay before the first purge sweep. Unset, unparseable, or non-positive values fall back to the default so a typo never silently changes startup behaviour (Validate rejects a bad value at load; this is the runtime fail-safe).
func (Delete) RetentionDuration ¶ added in v0.66.16
RetentionDuration resolves the configured soft-delete retention window. An unset value defaults to DefaultDeleteRetention (24h); "0" (or any zero duration) disables soft delete. An unparseable value falls back to the default so a typo never silently turns off recovery.
type DeliverConfig ¶ added in v0.67.0
type DeliverConfig struct {
Inbox string `toml:"inbox"` // session name, "orchestrator", or a template like "{session_name}"
Topic string `toml:"topic"` // pub/sub topic
Store string `toml:"store"` // store key (prefix "shared:" for the shared store)
Wake bool `toml:"wake"` // resume a non-orchestrator stopped inbox target
Required bool `toml:"required"` // delivery failure fails a completion action and gates on_success cleanup
}
DeliverConfig routes action output. All fields are templated at fire time.
type DetectionConfig ¶ added in v0.69.1
type DetectionConfig struct {
// ScanInterval is how often the detection loop scans PTY scrollback to
// classify low-risk agent status (active/ready). Empty uses the default
// (DetectionScanIntervalDefault).
ScanInterval string `toml:"scan_interval"`
// FetchInterval is how often the detection loop refreshes remote tracking
// refs (`git fetch`) so the diverged-from-base count stays fresh. Empty uses
// the default (DetectionFetchIntervalDefault).
FetchInterval string `toml:"fetch_interval"`
// FetchTimeout bounds a single per-repo `git fetch` so a slow or hung remote
// can't stall the fetch pass for other sessions. Empty uses the default
// (DetectionFetchTimeoutDefault).
FetchTimeout string `toml:"fetch_timeout"`
// SilentThreshold is how long a running session's PTY may produce zero
// output before the daemon warns it is silent (issue #1087). Empty uses the
// default (DetectionSilentThresholdDefault).
SilentThreshold string `toml:"silent_threshold"`
// AdoptedGrace is the window after daemon-upgrade PTY adoption during which
// an unknown detection result falls back to the previous status instead of
// clobbering it. Empty uses the default (DetectionAdoptedGraceDefault).
AdoptedGrace string `toml:"adopted_grace"`
// RecentOutputWindow is the age below which recent PTY output alone implies
// the agent is active when pattern matching is inconclusive. Empty uses the
// default (DetectionRecentOutputWindowDefault).
RecentOutputWindow string `toml:"recent_output_window"`
// HookStartWindow is how long a SessionStart hook report stays authoritative
// over PTY scraping. Empty uses the default (DetectionHookStartWindowDefault).
HookStartWindow string `toml:"hook_start_window"`
// HookActivityWindow is how long a tool-use hook report (UserPromptSubmit,
// PreToolUse, PostToolUse) stays authoritative. Empty uses the default
// (DetectionHookActivityWindowDefault).
HookActivityWindow string `toml:"hook_activity_window"`
// HookTerminalWindow is how long a terminal hook report (ready/approval:
// Stop, idle_prompt, permission_prompt, PermissionRequest) stays
// authoritative. Empty uses the default (DetectionHookTerminalWindowDefault).
HookTerminalWindow string `toml:"hook_terminal_window"`
}
DetectionConfig is the [detection] block gathering the agent-detection and status-classification timing policy that was previously spread as fixed constants across the daemon and detector packages (issue #1241). Every field is optional: an empty or unparseable value falls back to the matching default constant, preserving the historical behaviour.
func (DetectionConfig) AdoptedGraceDuration ¶ added in v0.69.1
func (d DetectionConfig) AdoptedGraceDuration() time.Duration
AdoptedGraceDuration returns the adopted-session fallback window, or the default when unset or unparseable. A "0" disables the fallback.
func (DetectionConfig) FetchIntervalDuration ¶ added in v0.69.1
func (d DetectionConfig) FetchIntervalDuration() time.Duration
FetchIntervalDuration returns the remote-fetch cadence, or the default when unset, unparseable, or non-positive.
func (DetectionConfig) FetchTimeoutDuration ¶ added in v0.69.1
func (d DetectionConfig) FetchTimeoutDuration() time.Duration
FetchTimeoutDuration returns the per-repo fetch timeout, or the default when unset, unparseable, or non-positive.
func (DetectionConfig) HookActivityWindowDuration ¶ added in v0.69.1
func (d DetectionConfig) HookActivityWindowDuration() time.Duration
HookActivityWindowDuration returns the tool-use hook-authority window, or the default when unset, unparseable, or non-positive.
func (DetectionConfig) HookStartWindowDuration ¶ added in v0.69.1
func (d DetectionConfig) HookStartWindowDuration() time.Duration
HookStartWindowDuration returns the SessionStart hook-authority window, or the default when unset, unparseable, or non-positive.
func (DetectionConfig) HookTerminalWindowDuration ¶ added in v0.69.1
func (d DetectionConfig) HookTerminalWindowDuration() time.Duration
HookTerminalWindowDuration returns the ready/approval hook-authority window, or the default when unset, unparseable, or non-positive.
func (DetectionConfig) RecentOutputWindowDuration ¶ added in v0.69.1
func (d DetectionConfig) RecentOutputWindowDuration() time.Duration
RecentOutputWindowDuration returns the recent-output-implies-active window, or the default when unset or unparseable. A "0" disables the fallback.
func (DetectionConfig) ScanIntervalDuration ¶ added in v0.69.1
func (d DetectionConfig) ScanIntervalDuration() time.Duration
ScanIntervalDuration returns the PTY scan cadence, or the default when unset, unparseable, or non-positive (a zero/negative scan interval would busy-loop).
func (DetectionConfig) SilentThresholdDuration ¶ added in v0.69.1
func (d DetectionConfig) SilentThresholdDuration() time.Duration
SilentThresholdDuration returns the zero-output warning window. Empty or unparseable uses the default; a non-positive value keeps the default because a session is never past a "zero" threshold in a meaningful way.
type GCConfig ¶ added in v0.69.1
type GCConfig struct {
OrphanMinAge string `toml:"orphan_min_age"`
}
GCConfig is the [gc] block. It tunes orphan garbage collection — the sweep (via `gr gc`) that reclaims worktree and scratch directories left behind by sessions no longer in state.
func (GCConfig) OrphanMinAgeDuration ¶ added in v0.69.1
OrphanMinAgeDuration resolves the orphan minimum age. Unset or unparseable falls back to the default; a negative value also falls back (a bad value must not widen GC to newly-created directories). "0" is honoured: an operator who explicitly opts out of the age floor gets immediate GC eligibility.
type GCXConfig ¶ added in v0.69.2
type GCXConfig struct {
Event string `toml:"event"` // oncall_alert_group (v1; default)
Context string `toml:"context"` // gcx context (required; credentials remain owned by gcx)
Every string `toml:"every"` // poll cadence; default 1m
Timeout string `toml:"timeout"` // timeout for each gcx invocation; default 30s
OnCallUserID string `toml:"oncall_user_id"` // stable human user PK; paired with ScheduleIDs
ScheduleIDs []string `toml:"schedule_ids"` // schedules used for the current-on-call gate
TeamIDs []string `toml:"team_ids"` // optional alert-group team filters
IntegrationIDs []string `toml:"integration_ids"` // optional alert-group integration filters
States []string `toml:"states"` // firing|acknowledged|resolved|silenced; default firing
MaxAge string `toml:"max_age"` // alert lookback and seen-ID retention; default 24h
Limit int `toml:"limit"` // result cap; reaching it fails closed; default 100
}
GCXConfig is the Grafana Cloud event source. V1 polls OnCall alert groups through an existing gcx context and can gate delivery on a pinned human being currently present in one of the selected OnCall schedules.
func (GCXConfig) EventOr ¶ added in v0.69.2
EventOr returns the selected event kind, defaulting to the only v1 kind.
func (GCXConfig) EveryDuration ¶ added in v0.69.2
EveryDuration returns the poll cadence, defaulting to 1m.
func (GCXConfig) LimitOr ¶ added in v0.69.2
LimitOr returns the alert-group result cap, defaulting to 100.
func (GCXConfig) MaxAgeDuration ¶ added in v0.69.2
MaxAgeDuration returns the alert lookback/cursor retention, defaulting to 24h.
func (GCXConfig) StatesOr ¶ added in v0.69.2
StatesOr returns a fresh copy of the configured states, defaulting to firing.
func (GCXConfig) TimeoutDuration ¶ added in v0.69.2
TimeoutDuration returns the per-gcx-command timeout, defaulting to 30s.
type GitConfig ¶ added in v0.69.1
type GitConfig struct {
// FetchTimeout bounds a single `git fetch` (default "2m").
FetchTimeout string `toml:"fetch_timeout"`
// MergeTimeout bounds a single fast-forward merge in the git-pull loop
// (default "2m").
MergeTimeout string `toml:"merge_timeout"`
// UsernameTimeout bounds GitHub-username discovery, which may invoke `gh`
// (default "15s").
UsernameTimeout string `toml:"username_timeout"`
}
GitConfig is the [git] block tuning the timeouts graith applies to the git operations it runs during session lifecycle (issue #1238). Slower repositories, large fetches, and high-latency remotes can legitimately exceed the built-in 2m fetch / 2m merge / 15s username bounds. An empty field keeps the built-in default. Note this is distinct from [git_pull], which configures the background maintenance-pull loop.
func (GitConfig) FetchTimeoutDuration ¶ added in v0.69.1
FetchTimeoutDuration returns the configured git-fetch timeout, defaulting to 2m when unset or unparseable (a bad value is rejected at load by Validate).
func (GitConfig) MergeTimeoutDuration ¶ added in v0.69.1
MergeTimeoutDuration returns the configured merge timeout, defaulting to 2m.
func (GitConfig) UsernameTimeoutDuration ¶ added in v0.69.1
UsernameTimeoutDuration returns the configured username-discovery timeout, defaulting to 15s.
type GitPullConfig ¶ added in v0.42.0
func (GitPullConfig) IntervalDuration ¶ added in v0.42.0
func (g GitPullConfig) IntervalDuration() time.Duration
type HeadlessConfig ¶ added in v0.67.8
type HeadlessConfig struct {
Experimental bool `toml:"experimental"`
Default bool `toml:"default"`
// MaxLineBytes bounds a single stream-json line read from the agent's stdout.
// Large tool outputs or base64 images exceed the 64KiB default scanner token,
// so the driver raises the cap. 0/negative uses HeadlessMaxLineBytesDefault.
MaxLineBytes int `toml:"max_line_bytes"`
// ControlTimeout bounds how long a synchronous control request waits for its
// matching control_response before failing. Empty/unparseable/non-positive
// uses HeadlessControlTimeoutDefault.
ControlTimeout string `toml:"control_timeout"`
// InterruptTimeout bounds the interrupt control round-trip; it is much shorter
// than ControlTimeout because a caller interrupting an agent wants a prompt
// fall-through to SIGINT. Empty/unparseable/non-positive uses
// HeadlessInterruptTimeoutDefault.
InterruptTimeout string `toml:"interrupt_timeout"`
// PreviewBytes bounds how much scrollback tail the overlay preview and
// screen_preview control message render. 0/negative uses
// HeadlessPreviewBytesDefault.
PreviewBytes int `toml:"preview_bytes"`
}
HeadlessConfig is the [headless] block gating headless stream-json sessions (issue #1075). Headless is inert unless Experimental is true — the control protocol it uses is an SDK-internal contract, so v1 is opt-in and experimental. Default, when Experimental is on, decides whether new sessions go headless without an explicit --headless.
The remaining fields make the headless driver's processing limits tunable (issue #1250). Each is optional: an empty/zero/non-positive value falls back to the matching default constant, preserving historical behaviour.
func (HeadlessConfig) ControlTimeoutDuration ¶ added in v0.69.1
func (h HeadlessConfig) ControlTimeoutDuration() time.Duration
ControlTimeoutDuration returns the control-request timeout, or the default when unset, unparseable, or non-positive.
func (HeadlessConfig) InterruptTimeoutDuration ¶ added in v0.69.1
func (h HeadlessConfig) InterruptTimeoutDuration() time.Duration
InterruptTimeoutDuration returns the interrupt round-trip timeout, or the default when unset, unparseable, or non-positive.
func (HeadlessConfig) MaxLineBytesOrDefault ¶ added in v0.69.1
func (h HeadlessConfig) MaxLineBytesOrDefault() int
MaxLineBytesOrDefault returns the stream-json line cap, or the default when unset or non-positive.
func (HeadlessConfig) PreviewBytesOrDefault ¶ added in v0.69.1
func (h HeadlessConfig) PreviewBytesOrDefault() int
PreviewBytesOrDefault returns the preview tail cap, or the default when unset or non-positive.
type InputConfig ¶ added in v0.66.16
type InputConfig struct {
// DragArrowKeys enables touch/hold-and-drag arrow keys:
// press-and-hold the left mouse button then drag to emit discrete arrow-key
// presses to the focused pane. Off by default because it repurposes
// left-drag (which terminals otherwise use for text selection). Mouse-wheel
// scrolling is always passed through unchanged.
DragArrowKeys bool `toml:"drag_arrow_keys"`
// DragArrowThreshold is the number of cells of drag movement that produces
// one arrow-key press. Values below 1 fall back to the default.
DragArrowThreshold int `toml:"drag_arrow_threshold"`
}
InputConfig is the optional [input] block controlling terminal input gestures in the attach passthrough loop.
type Keybindings ¶
type Keybindings struct {
Prefix string `toml:"prefix"`
NewSession string `toml:"new_session"`
ForkSession string `toml:"fork_session"`
DeleteSession string `toml:"delete_session"`
Detach string `toml:"detach"`
SessionList string `toml:"session_list"`
NextSession string `toml:"next_session"`
PrevSession string `toml:"prev_session"`
LastSession string `toml:"last_session"`
ResumeSession string `toml:"resume_session"`
RenameSession string `toml:"rename_session"`
Search string `toml:"search"`
ScrollMode string `toml:"scroll_mode"`
Shell string `toml:"shell"`
OrchestratorSession string `toml:"orchestrator_session"`
// Prefix-action commands issued from an attached session (prefix key then
// one of these). Previously hard-coded as m/a/r (issue #1233).
Messages string `toml:"messages"`
Approvals string `toml:"approvals"`
RestartSession string `toml:"restart_session"`
// Overlay holds the keys used inside the full-screen terminal overlays
// (dashboard, approval prompt, message viewer, scroll pager). See #1233.
Overlay OverlayKeybindings `toml:"overlay"`
}
func (Keybindings) Conflicts ¶ added in v0.69.1
func (k Keybindings) Conflicts() []string
Conflicts reports keybinding collisions among the prefix-action commands — the keys pressed after the prefix while attached to a session. Two commands bound to the same key mean only the first (in the passthrough switch order) ever fires, so the config is almost certainly a mistake. Picker/overlay keys operate in a separate mode and may legitimately reuse a prefix-command key, so they are not compared here. Each returned string names one collision; an empty slice means no conflicts. The result feeds a warning, not an error, so a misconfiguration is surfaced without refusing to start (issue #1233).
type LaunchConfig ¶ added in v0.67.7
type LaunchConfig struct {
// MaxConcurrent bounds how many agent spawns may be in their startup window
// at once. Values < 1 fall back to the default (LaunchMaxConcurrentDefault).
MaxConcurrent int `toml:"max_concurrent"`
// StartupTimeout is how long a session may stay running with no output before
// the startup watchdog kills and restarts it fresh. "0" disables the
// watchdog; empty uses the default (LaunchStartupTimeoutDefault).
StartupTimeout string `toml:"startup_timeout"`
// SettleTimeout caps how long a launch holds its throttle slot waiting for
// the session's first output before releasing it anyway. Empty uses the
// default (LaunchSettleTimeoutDefault); "0" releases immediately after spawn.
SettleTimeout string `toml:"settle_timeout"`
// MaxRestarts caps how many consecutive startup-watchdog restarts a single
// session may receive before it is marked errored instead of restarted again,
// preventing a restart storm for a fundamentally-broken session (#1092). The
// counter resets once the session produces output. Values < 1 fall back to the
// default (LaunchMaxRestartsDefault). To turn the watchdog off entirely, set
// startup_timeout to "0" rather than dropping this to zero.
MaxRestarts int `toml:"max_restarts"`
// WatchdogInterval is how often the startup watchdog scans for stuck sessions.
// Empty, unparseable, or non-positive uses the default
// (LaunchWatchdogIntervalDefault); a zero cadence would busy-loop. Read once
// when the watchdog loop starts, so a change takes effect on the next daemon
// (re)start.
WatchdogInterval string `toml:"watchdog_interval"`
// SlotPollInterval is how often a held throttle slot polls a freshly-spawned
// session for its first output before releasing. Empty, unparseable, or
// non-positive uses the default (LaunchSlotPollIntervalDefault); a zero cadence
// would busy-loop.
SlotPollInterval string `toml:"slot_poll_interval"`
}
LaunchConfig bounds concurrent agent-session startup and recovers sessions that stall during launch (issue #1092). Bursts of `gr new` otherwise let many heavyweight agent runtimes initialise at once, and the tail can stall for minutes or hang forever at ~9MB RSS (sandbox wrapper only, agent never loaded).
func (LaunchConfig) MaxConcurrentOrDefault ¶ added in v0.67.7
func (l LaunchConfig) MaxConcurrentOrDefault() int
MaxConcurrentOrDefault returns the configured concurrency, clamped to a sensible minimum. A non-positive value means "use the default".
func (LaunchConfig) MaxRestartsOrDefault ¶ added in v0.69.1
func (l LaunchConfig) MaxRestartsOrDefault() int
MaxRestartsOrDefault returns the stuck-launch restart budget, or the default when < 1 (mirrors MaxConcurrentOrDefault). The watchdog is disabled via startup_timeout = "0", not by zeroing this.
func (LaunchConfig) SettleTimeoutDuration ¶ added in v0.67.7
func (l LaunchConfig) SettleTimeoutDuration() time.Duration
SettleTimeoutDuration returns how long a slot waits for first output. Empty uses the default; an explicit "0" releases the slot as soon as the spawn returns.
func (LaunchConfig) SlotPollIntervalDuration ¶ added in v0.69.1
func (l LaunchConfig) SlotPollIntervalDuration() time.Duration
SlotPollIntervalDuration returns the settle poll cadence, or the default when unset, unparseable, or non-positive (a zero cadence would busy-loop).
func (LaunchConfig) StartupTimeoutDuration ¶ added in v0.67.7
func (l LaunchConfig) StartupTimeoutDuration() time.Duration
StartupTimeoutDuration returns the watchdog threshold. Empty uses the default; an explicit "0" (or any non-positive parse) disables the watchdog.
func (LaunchConfig) WatchdogIntervalDuration ¶ added in v0.69.1
func (l LaunchConfig) WatchdogIntervalDuration() time.Duration
WatchdogIntervalDuration returns the watchdog scan cadence, or the default when unset, unparseable, or non-positive (a zero cadence would busy-loop).
type LifecycleConfig ¶ added in v0.69.1
type LifecycleConfig struct {
// ConvertSettleTimeout bounds how long ConvertToInteractive waits for an
// interrupted headless process to settle and exit before escalating to
// SIGTERM. Empty or non-positive uses the default (ConvertSettleTimeoutDefault).
ConvertSettleTimeout string `toml:"convert_settle_timeout"`
// ConvertKillTimeout bounds the SIGTERM step before the final SIGKILL. Empty
// or non-positive uses the default (ConvertKillTimeoutDefault).
ConvertKillTimeout string `toml:"convert_kill_timeout"`
// ConvertForceKillTimeout bounds the final wait after SIGKILL so a process
// whose Done() never closes can't stall the convert forever. Empty or
// non-positive uses the default (ConvertForceKillTimeoutDefault).
ConvertForceKillTimeout string `toml:"convert_force_kill_timeout"`
// MassExitWindow is the rolling window over which many near-simultaneous
// session exits are counted as a likely external signal (OOM killer/jetsam).
// Empty or non-positive uses the default (MassExitWindowDefault).
MassExitWindow string `toml:"mass_exit_window"`
// MassExitThreshold is how many exits within MassExitWindow trigger the
// mass-exit warning. Values < 1 fall back to the default (MassExitThresholdDefault).
MassExitThreshold int `toml:"mass_exit_threshold"`
// ProcessKillGrace is how long killProcessGroup waits after SIGTERM before
// sending SIGKILL to a session's process group. Empty or non-positive uses the
// default (ProcessKillGraceDefault).
ProcessKillGrace string `toml:"process_kill_grace"`
// AdoptedTimeout is the safety deadline the adopted-PTY babysit loop applies
// when it cannot verify process identity by start time. Empty or non-positive
// uses the default (AdoptedTimeoutDefault). Applies to sessions adopted after
// the change (daemon upgrade).
AdoptedTimeout string `toml:"adopted_timeout"`
// AdoptedPollInterval is how often the adopted-PTY babysit loop polls for
// process exit. Empty or non-positive uses the default
// (AdoptedPollIntervalDefault); a zero cadence would busy-loop.
AdoptedPollInterval string `toml:"adopted_poll_interval"`
// ScrollbackHydrationBytes is how many bytes of the scrollback tail are
// replayed into an adopted session's virtual screen at adopt time. Values < 0
// fall back to the default (ScrollbackHydrationBytesDefault); "0" disables
// hydration.
ScrollbackHydrationBytes int `toml:"scrollback_hydration_bytes"`
// InputDelay is the pause between writing text and the submit carriage return
// in WriteInputAndSubmit, so a TUI doesn't treat text+CR as a paste. Empty,
// unparseable, or non-positive uses the default (InputDelayDefault) — a zero
// pause would defeat the paste guard. Applies to sessions launched after the
// change.
InputDelay string `toml:"input_delay"`
// DefaultCols / DefaultRows are the terminal geometry used by daemon launch
// paths (watchdog restart, orchestrator, scenarios, triggers, adoption) when
// no client geometry is available. Values < 1 fall back to the defaults
// (DefaultColsDefault / DefaultRowsDefault). Applies to sessions launched
// after the change; an attaching client resizes to its real geometry.
DefaultCols int `toml:"default_cols"`
DefaultRows int `toml:"default_rows"`
// MaxLogBytes caps the per-session scrollback log file. Values < 0 fall back
// to the default (MaxLogBytesDefault); "0" means unlimited. Applies to sessions
// launched (or adopted) after the change.
MaxLogBytes int64 `toml:"max_log_bytes"`
}
LifecycleConfig is the [lifecycle] block gathering the session-lifecycle and PTY policy that was previously spread as fixed constants and bare literals across the daemon, headless, and pty packages (issue #1243): the convert-to-interactive signal-escalation waits, the headless interrupt round-trip, mass-exit detection, the process-teardown grace, adopted-PTY babysit timing, scrollback hydration, terminal-input pacing, the default launch geometry, and the per-session log cap.
The signal-escalation ORDER (interrupt → SIGTERM → SIGKILL) stays a code invariant; only the wait durations between steps are tunable here. Every field is optional: an empty/unparseable/out-of-range value falls back to the matching default constant, preserving the historical behaviour. Geometry and log/ hydration limits apply only to sessions launched (or adopted) after the change; running sessions keep the geometry and caps they started with.
func (LifecycleConfig) AdoptedPollIntervalDuration ¶ added in v0.69.1
func (l LifecycleConfig) AdoptedPollIntervalDuration() time.Duration
AdoptedPollIntervalDuration returns the adopted-PTY poll cadence, or the default when unset, unparseable, or non-positive (a zero cadence would busy-loop).
func (LifecycleConfig) AdoptedTimeoutDuration ¶ added in v0.69.1
func (l LifecycleConfig) AdoptedTimeoutDuration() time.Duration
AdoptedTimeoutDuration returns the adopted-PTY safety deadline, or the default when unset, unparseable, or non-positive.
func (LifecycleConfig) ConvertForceKillTimeoutDuration ¶ added in v0.69.1
func (l LifecycleConfig) ConvertForceKillTimeoutDuration() time.Duration
ConvertForceKillTimeoutDuration returns the post-SIGKILL wait, or the default when unset, unparseable, or non-positive.
func (LifecycleConfig) ConvertKillTimeoutDuration ¶ added in v0.69.1
func (l LifecycleConfig) ConvertKillTimeoutDuration() time.Duration
ConvertKillTimeoutDuration returns the SIGTERM-step wait, or the default when unset, unparseable, or non-positive.
func (LifecycleConfig) ConvertSettleTimeoutDuration ¶ added in v0.69.1
func (l LifecycleConfig) ConvertSettleTimeoutDuration() time.Duration
ConvertSettleTimeoutDuration returns the interrupt→settle wait, or the default when unset, unparseable, or non-positive.
func (LifecycleConfig) DefaultColsOrDefault ¶ added in v0.69.1
func (l LifecycleConfig) DefaultColsOrDefault() uint16
DefaultColsOrDefault returns the default launch column count, or the default when < 1.
func (LifecycleConfig) DefaultRowsOrDefault ¶ added in v0.69.1
func (l LifecycleConfig) DefaultRowsOrDefault() uint16
DefaultRowsOrDefault returns the default launch row count, or the default when < 1.
func (LifecycleConfig) InputDelayDuration ¶ added in v0.69.1
func (l LifecycleConfig) InputDelayDuration() time.Duration
InputDelayDuration returns the type-then-submit pause, or the default when unset, unparseable, or non-positive (a zero pause would defeat the paste guard).
func (LifecycleConfig) MassExitThresholdOrDefault ¶ added in v0.69.1
func (l LifecycleConfig) MassExitThresholdOrDefault() int
MassExitThresholdOrDefault returns the mass-exit exit-count threshold, or the default when < 1 (a zero threshold has no meaningful trigger).
func (LifecycleConfig) MassExitWindowDuration ¶ added in v0.69.1
func (l LifecycleConfig) MassExitWindowDuration() time.Duration
MassExitWindowDuration returns the mass-exit detection window, or the default when unset, unparseable, or non-positive.
func (LifecycleConfig) MaxLogBytesOrDefault ¶ added in v0.69.1
func (l LifecycleConfig) MaxLogBytesOrDefault() int64
MaxLogBytesOrDefault returns the per-session log cap. A value < 0 means "use the default"; "0" is honoured (unlimited, as the scrollback writer treats a non-positive cap as no limit).
func (LifecycleConfig) ProcessKillGraceDuration ¶ added in v0.69.1
func (l LifecycleConfig) ProcessKillGraceDuration() time.Duration
ProcessKillGraceDuration returns the SIGTERM→SIGKILL grace, or the default when unset, unparseable, or non-positive.
func (LifecycleConfig) ScrollbackHydrationBytesOrDefault ¶ added in v0.69.1
func (l LifecycleConfig) ScrollbackHydrationBytesOrDefault() int
ScrollbackHydrationBytesOrDefault returns the adopt-time hydration size. A value < 0 means "use the default"; "0" is honoured (disable hydration).
type LimitsConfig ¶ added in v0.69.1
type LimitsConfig struct {
// LogLines is the default number of trailing output lines shown when a
// `lines`/`-n` count is not given: `gr logs`, `gr mcp logs`, the scrollback
// replayed to a client on attach, and the MCP log reader all share it. Values
// < 1 fall back to the default (LimitsLogLinesDefault).
LogLines int `toml:"log_lines"`
// WaitScanLines bounds how much existing scrollback `gr wait --contains`
// scans for an already-present match before it starts following live output.
// Values < 1 fall back to the default (LimitsWaitScanLinesDefault).
WaitScanLines int `toml:"wait_scan_lines"`
// WaitBufferBytes bounds the retained partial line in the live `gr wait`
// matcher so a long stream without a newline can't grow the buffer without
// limit. Values < 1 fall back to the default (LimitsWaitBufferBytesDefault).
WaitBufferBytes int `toml:"wait_buffer_bytes"`
// MCPLogReadBytes bounds how many trailing bytes of an MCP server log file
// are read before splitting into lines, keeping a huge log from being loaded
// whole. Values < 1 fall back to the default (LimitsMCPLogReadBytesDefault).
MCPLogReadBytes int `toml:"mcp_log_read_bytes"`
// ApprovalDisplayBytes caps the tool input shown in the approval overlay and
// broadcast to attached clients (the full input is still what backends
// evaluate). Values < 1 fall back to the default
// (LimitsApprovalDisplayBytesDefault).
ApprovalDisplayBytes int `toml:"approval_display_bytes"`
// LastMessageRunes bounds the agent's final Stop message the status hook
// forwards to the daemon, so a large final output never becomes an unbounded
// control frame. Counted in runes (never splits a multi-byte character).
// Values < 1 fall back to the default (LimitsLastMessageRunesDefault).
LastMessageRunes int `toml:"last_message_runes"`
// InboxPreviewBytes bounds the unread-inbox preview injected into a session's
// SessionStart hook context. Values < 1 fall back to the default
// (LimitsInboxPreviewBytesDefault).
InboxPreviewBytes int `toml:"inbox_preview_bytes"`
}
LimitsConfig is the [limits] block gathering the user-visible output, log, wait, and display truncation caps that were previously duplicated as unrelated Go constants and literals across the daemon, CLI, and MCP manager (issue #1252). Unifying them means changing one place updates every surface. Every field is optional: a value < 1 falls back to the matching default constant, preserving the historical behaviour. Units are stated in each field name (lines, bytes, runes) so a single number is unambiguous.
func (LimitsConfig) ApprovalDisplayBytesOrDefault ¶ added in v0.69.1
func (l LimitsConfig) ApprovalDisplayBytesOrDefault() int
ApprovalDisplayBytesOrDefault returns the approval-overlay display cap, clamped to a sensible minimum. A value < 1 means "use the default".
func (LimitsConfig) InboxPreviewBytesOrDefault ¶ added in v0.69.1
func (l LimitsConfig) InboxPreviewBytesOrDefault() int
InboxPreviewBytesOrDefault returns the inbox-preview byte cap, clamped to a sensible minimum. A value < 1 means "use the default".
func (LimitsConfig) LastMessageRunesOrDefault ¶ added in v0.69.1
func (l LimitsConfig) LastMessageRunesOrDefault() int
LastMessageRunesOrDefault returns the hook last-message rune cap, clamped to a sensible minimum. A value < 1 means "use the default".
func (LimitsConfig) LogLinesOrDefault ¶ added in v0.69.1
func (l LimitsConfig) LogLinesOrDefault() int
LogLinesOrDefault returns the default log-tail line count, clamped to a sensible minimum. A value < 1 means "use the default".
func (LimitsConfig) MCPLogReadBytesOrDefault ¶ added in v0.69.1
func (l LimitsConfig) MCPLogReadBytesOrDefault() int
MCPLogReadBytesOrDefault returns the MCP log read cap, clamped to a sensible minimum. A value < 1 means "use the default".
func (LimitsConfig) WaitBufferBytesOrDefault ¶ added in v0.69.1
func (l LimitsConfig) WaitBufferBytesOrDefault() int
WaitBufferBytesOrDefault returns the `gr wait` matcher partial-line cap, clamped to a sensible minimum. A value < 1 means "use the default".
func (LimitsConfig) WaitScanLinesOrDefault ¶ added in v0.69.1
func (l LimitsConfig) WaitScanLinesOrDefault() int
WaitScanLinesOrDefault returns the `gr wait` scrollback-scan line count, clamped to a sensible minimum. A value < 1 means "use the default".
type MCPServerConfig ¶ added in v0.22.0
type MCPServerConfig struct {
Name string `json:"-" toml:"name"`
Command string `json:"command" toml:"command"`
Args []string `json:"args,omitempty" toml:"args,omitempty"`
Env map[string]string `json:"env,omitempty" toml:"env,omitempty"`
Disabled bool `json:"-" toml:"disabled,omitempty"`
Sandbox *bool `json:"-" toml:"sandbox,omitempty"`
SandboxConfig *SandboxConfig `json:"-" toml:"sandbox_config,omitempty"`
}
func MergeMCPServers ¶ added in v0.22.0
func MergeMCPServers(global []MCPServerConfig, overrides map[string]MCPServerConfig) []MCPServerConfig
type Messages ¶ added in v0.3.0
type Messages struct {
// MaxAge is the message-retention window: messages older than this are swept
// by the cleanup loop. An empty value or an explicit "0" is the documented
// "retain forever" sentinel (no age-based cleanup). A non-empty value is
// validated at load: an unparseable or negative duration is rejected so a typo
// cannot silently turn a bounded-retention deployment into keep-forever
// (issue #1321). Reloadable.
MaxAge string `toml:"max_age"`
MaxPerStream int `toml:"max_per_stream"`
// ConversationPageSize is the page size applied when a msg_conversation
// request supplies a non-positive limit. Values < 1 fall back to the default
// (MessagesConversationPageSizeDefault). Reloadable.
ConversationPageSize int `toml:"conversation_page_size"`
// ConversationMaxLimit is the hard cap on how many messages a single
// msg_conversation request may sort, bounding a local perf/DoS footgun. Values
// < 1 fall back to the default (MessagesConversationMaxLimitDefault); a value
// above MessagesConversationMaxLimitCeiling is rejected at load. Reloadable.
ConversationMaxLimit int `toml:"conversation_max_limit"`
// JailListLimit caps how many quarantined comments a jail listing returns
// (newest first), so the query can't force an unbounded allocation. Values < 1
// fall back to the default (MessagesJailListLimitDefault); a value above
// MessagesJailListLimitCeiling is rejected at load. Reloadable.
JailListLimit int `toml:"jail_list_limit"`
// SubscriberBuffer is the per-subscriber pub/sub channel capacity. A slow
// reader that fills its buffer drops further messages until it drains (the
// stored log stays authoritative), so this is a load-tuning knob for
// installations with bursty fan-out. Values < 1 fall back to the default
// (MessagesSubscriberBufferDefault); a value above
// MessagesSubscriberBufferCeiling is rejected at load. Restart-only.
SubscriberBuffer int `toml:"subscriber_buffer"`
// BusyTimeout is the SQLite busy_timeout for the messages database — how long
// a contended operation waits for the lock before erroring. It is graith's
// database operation deadline. Empty/unset uses the default
// (MessagesBusyTimeoutDefault, 5s). An explicit value must parse and fall in
// [SQLiteBusyTimeoutResolution, MessagesBusyTimeoutCeiling] (1ms–5m):
// SQLite's busy_timeout has millisecond resolution, so a positive sub-1ms
// value would collapse to busy_timeout(0) and disable lock waiting, and it —
// along with any unparseable, non-positive, or above-ceiling value — is
// rejected at load. Restart-only.
BusyTimeout string `toml:"busy_timeout"`
}
Messages is the [messages] block. It governs the message-log subsystem: the cleanup retention (MaxAge/MaxPerStream) plus the operational limits made configurable by issue #1249 — conversation paging bounds, the jail listing cap, the pub/sub subscriber buffer, and the SQLite busy/operation timeout.
SubscriberBuffer and BusyTimeout are fixed at store-open time, so a change to either takes effect only on daemon restart. The conversation paging bounds and the jail cap are read per-request, so they apply on reload.
func (Messages) BusyTimeoutDuration ¶ added in v0.69.1
BusyTimeoutDuration returns the messages-database SQLite busy_timeout, or the default when unset, unparseable, or non-positive (a zero/negative timeout would make a contended write fail immediately instead of waiting).
func (Messages) ClampConversationLimit ¶ added in v0.69.1
ClampConversationLimit normalizes a client-supplied conversation limit: a non-positive limit becomes the configured page size, and any limit above the configured maximum is capped at it.
func (Messages) ConversationMaxLimitOrDefault ¶ added in v0.69.1
ConversationMaxLimitOrDefault returns the hard cap on a single conversation sort. A non-positive value means "use the default".
func (Messages) ConversationPageSizeOrDefault ¶ added in v0.69.1
ConversationPageSizeOrDefault returns the default conversation page size (used when a request supplies a non-positive limit). A non-positive configured value means "use the default"; the result is additionally clamped to the effective max limit so a misconfigured page size can never exceed the hard cap.
func (Messages) JailListLimitOrDefault ¶ added in v0.69.1
JailListLimitOrDefault returns the jail listing row cap. A non-positive value means "use the default".
func (Messages) MaxAgeDuration ¶ added in v0.3.0
MaxAgeDuration returns the message-retention window. An empty value or an explicit zero is the documented "retain forever" sentinel (returns 0, which runMessageCleanupFromConfig treats as no age-based cleanup). Load/reload validation rejects a non-empty unparseable or negative value; this accessor keeps a defensive fallback to 0 (retain forever) for directly-constructed configs so a garbage value can never turn into a negative window that would otherwise select a future cutoff and delete everything.
func (Messages) SubscriberBufferOrDefault ¶ added in v0.69.1
SubscriberBufferOrDefault returns the per-subscriber channel capacity. A non-positive value means "use the default".
type MigrationConfig ¶ added in v0.69.1
type MigrationConfig struct {
// HealthWindow is how long Migrate waits to confirm the target agent survived
// startup before declaring the migration successful. Empty/unparseable/
// non-positive uses MigrationHealthWindowDefault.
HealthWindow string `toml:"health_window"`
}
MigrationConfig is the [migration] block tuning the cross-agent conversation migration (issue #1250). HealthWindow is optional: empty, unparseable, or non-positive falls back to MigrationHealthWindowDefault.
func (MigrationConfig) HealthWindowDuration ¶ added in v0.69.1
func (m MigrationConfig) HealthWindowDuration() time.Duration
HealthWindowDuration returns the migration startup-health window, or the default when unset, unparseable, or non-positive.
type NotificationTiming ¶ added in v0.69.1
type NotificationTiming struct {
// CoalesceWindow is how long an identical (title+message+priority) push
// notification is dropped as a duplicate, coalescing rapid-fire events. Empty
// uses the default (NotifyCoalesceWindowDefault); "0" disables coalescing.
CoalesceWindow string `toml:"coalesce_window"`
// DispatchTimeout bounds a single backend dispatch (osascript / notifier app /
// command) so a hung helper can't block the caller. Empty or non-positive uses
// the default (NotifyDispatchTimeoutDefault).
DispatchTimeout string `toml:"dispatch_timeout"`
// InboxIdleTimeout is how long an attached session's PTY must be free of user
// input before an inbox notification or `gr type` input is injected, so it
// doesn't land mid-type. Empty or non-positive uses the default
// (NotifyInboxIdleTimeoutDefault).
InboxIdleTimeout string `toml:"inbox_idle_timeout"`
// InboxMaxWait caps the total wait for user idle before an inbox notification
// or `gr type` input is injected regardless. Empty or non-positive uses the
// default (NotifyInboxMaxWaitDefault).
InboxMaxWait string `toml:"inbox_max_wait"`
// InboxCooldown is the minimum interval between unread-inbox notifications to
// one session, throttling repeat nudges. Empty uses the default
// (NotifyInboxCooldownDefault); "0" disables the cooldown.
InboxCooldown string `toml:"inbox_cooldown"`
// InboxDetachedDelay is the settle delay before notifying a session with no
// attached client (no user-idle signal to wait on). Empty uses the default
// (NotifyInboxDetachedDelayDefault); "0" notifies immediately.
InboxDetachedDelay string `toml:"inbox_detached_delay"`
}
NotificationTiming gathers the notification timing policy that was previously spread as fixed constants across the daemon's push (pushnotify.go) and inbox-notification (notify.go) paths (issue #1245). Every field is optional: an empty or unparseable value falls back to the matching default constant, preserving the historical behaviour.
func (NotificationTiming) CoalesceWindowDuration ¶ added in v0.69.1
func (t NotificationTiming) CoalesceWindowDuration() time.Duration
CoalesceWindowDuration returns the push-notification coalescing window, or the default when unset or unparseable. A "0" disables coalescing.
func (NotificationTiming) DispatchTimeoutDuration ¶ added in v0.69.1
func (t NotificationTiming) DispatchTimeoutDuration() time.Duration
DispatchTimeoutDuration returns the per-backend dispatch timeout, or the default when unset, unparseable, or non-positive (a zero timeout would fail every dispatch instantly).
func (NotificationTiming) InboxCooldownDuration ¶ added in v0.69.1
func (t NotificationTiming) InboxCooldownDuration() time.Duration
InboxCooldownDuration returns the minimum interval between unread-inbox notifications to one session, or the default when unset or unparseable. A "0" disables the cooldown.
func (NotificationTiming) InboxDetachedDelayDuration ¶ added in v0.69.1
func (t NotificationTiming) InboxDetachedDelayDuration() time.Duration
InboxDetachedDelayDuration returns the settle delay before notifying a detached session, or the default when unset or unparseable. A "0" notifies immediately.
func (NotificationTiming) InboxIdleTimeoutDuration ¶ added in v0.69.1
func (t NotificationTiming) InboxIdleTimeoutDuration() time.Duration
InboxIdleTimeoutDuration returns the user-idle wait before an inbox notification or `gr type` input is injected, or the default when unset, unparseable, or non-positive.
func (NotificationTiming) InboxMaxWaitDuration ¶ added in v0.69.1
func (t NotificationTiming) InboxMaxWaitDuration() time.Duration
InboxMaxWaitDuration returns the cap on the shared inbox-notification and `gr type` user-idle wait, or the default when unset, unparseable, or non-positive.
type Notifications ¶ added in v0.2.0
type Notifications struct {
Enabled bool `toml:"enabled"`
OnApproval bool `toml:"on_approval"`
OnStopped bool `toml:"on_stopped"`
Command string `toml:"command"`
// Backend selects how proactive `gr notify` push notifications are delivered:
// "macos" (osascript desktop notification; the default when unset) or
// "command" (run [notifications] command with GRAITH_NOTIFY_* env vars). Other
// backends (ntfy/pushover/slack) are planned follow-ups and rejected for now.
Backend string `toml:"backend"`
// MaxPerHour rate-limits low/normal push notifications over a rolling hour so a
// misbehaving trigger can't storm the user. <=0 uses DefaultNotifyMaxPerHour.
// High-priority notifications bypass this limit.
MaxPerHour int `toml:"max_per_hour"`
// QuietHoursStart / QuietHoursEnd define a daily window ("HH:MM", 24-hour) in
// which low/normal push notifications are suppressed. The window may wrap past
// midnight (start > end, e.g. 22:00-07:00). Both must be set to take effect.
// High-priority notifications bypass quiet hours.
QuietHoursStart string `toml:"quiet_hours_start"`
QuietHoursEnd string `toml:"quiet_hours_end"`
// Timing carries the low-level coalescing, dispatch, and PTY-injection
// timing knobs under [notifications.timing]. Every field is optional and
// resolves to its documented default through the NotificationTiming accessors,
// so leaving the table out preserves the historical behaviour (issue #1245).
Timing NotificationTiming `toml:"timing"`
}
func (Notifications) InQuietHours ¶ added in v0.67.2
func (n Notifications) InQuietHours(t time.Time) bool
InQuietHours reports whether the local time t falls within the configured quiet-hours window. It supports a window that wraps past midnight (start > end). An unset or unparseable window returns false (fail-open: a typo mutes nothing rather than everything — Validate rejects a malformed window at load).
func (Notifications) MaxPerHourValue ¶ added in v0.67.2
func (n Notifications) MaxPerHourValue() int
MaxPerHourValue returns the effective rolling-hour push-notification cap, defaulting to DefaultNotifyMaxPerHour when unset (<=0).
func (Notifications) NotifyBackendName ¶ added in v0.67.2
func (n Notifications) NotifyBackendName() string
NotifyBackendName returns the effective push-notification backend, defaulting to "macos" when unset.
func (Notifications) QuietHoursConfigured ¶ added in v0.67.2
func (n Notifications) QuietHoursConfigured() bool
QuietHoursConfigured reports whether a quiet-hours window is fully set.
func (Notifications) Validate ¶ added in v0.67.2
func (n Notifications) Validate() error
Validate checks the [notifications] block for static errors: an unknown push backend, a malformed quiet-hours window, or a "command" backend with no command set. It fails closed so a typo surfaces at config-load rather than as a silent no-op notification.
type OrchestratorConfig ¶ added in v0.42.0
type OrchestratorConfig struct {
Enabled bool `toml:"enabled"`
Agent string `toml:"agent"`
Model string `toml:"model"`
IdleTimeout string `toml:"idle_timeout"`
Prompt string `toml:"prompt"`
PromptFile string `toml:"prompt_file"`
Sandbox OrchestratorSandboxConfig `toml:"sandbox"`
Restart OrchestratorRestartConfig `toml:"restart"`
}
func (OrchestratorConfig) AgentName ¶ added in v0.42.0
func (o OrchestratorConfig) AgentName(defaultAgent string) string
AgentName resolves the agent type the orchestrator session runs as. An explicit [orchestrator] agent wins; otherwise it inherits the top-level default_agent (passed in by the caller, which has access to the full config), falling back to "claude" only when neither is set.
func (OrchestratorConfig) IdleTimeoutDuration ¶ added in v0.42.0
func (o OrchestratorConfig) IdleTimeoutDuration() time.Duration
type OrchestratorRestartConfig ¶ added in v0.69.1
type OrchestratorRestartConfig struct {
// InitialBackoff is the first restart delay in geometric mode (Schedule empty).
// Empty uses OrchestratorInitialBackoffDefault.
InitialBackoff string `toml:"initial_backoff"`
// MaxBackoff caps the restart delay in geometric mode. Empty uses
// OrchestratorMaxBackoffDefault.
MaxBackoff string `toml:"max_backoff"`
// Multiplier grows the delay each attempt in geometric mode. Values <= 1 fall
// back to OrchestratorMultiplierDefault.
Multiplier float64 `toml:"multiplier"`
// Schedule is an explicit list of per-attempt delays. When set it overrides
// the geometric knobs; the last entry repeats for attempts beyond its length.
Schedule []string `toml:"schedule"`
// StableReset is how long a run must last before its exit resets the backoff
// level to 0. Empty uses OrchestratorStableResetDefault.
StableReset string `toml:"stable_reset"`
// FreshStartThreshold is the number of consecutive restarts after which the
// orchestrator is relaunched fresh (new agent session id). Values < 1 fall
// back to OrchestratorFreshStartThresholdDefault.
FreshStartThreshold int `toml:"fresh_start_threshold"`
}
OrchestratorRestartConfig tunes how the daemon auto-restarts the orchestrator after it exits unexpectedly (crash/watchdog, not a user/idle/shutdown stop).
Two backoff modes are supported. When Schedule is non-empty it wins: it is the explicit list of per-attempt delays, and the final entry repeats for every attempt beyond its length. When Schedule is empty a geometric backoff is computed as InitialBackoff × Multiplier^level, capped at MaxBackoff.
func (OrchestratorRestartConfig) DelayForLevel ¶ added in v0.69.1
func (r OrchestratorRestartConfig) DelayForLevel(level int) time.Duration
DelayForLevel returns the restart delay for a given (0-based) backoff level. An explicit Schedule wins, with its final entry repeating past its length; otherwise the delay is computed geometrically. With no restart config at all this reproduces graith's historical schedule (2s,4s,8s,16s,32s,60s,300s).
func (OrchestratorRestartConfig) FreshStartThresholdOrDefault ¶ added in v0.69.1
func (r OrchestratorRestartConfig) FreshStartThresholdOrDefault() int
FreshStartThresholdOrDefault returns the consecutive-restart count that triggers a fresh start. Non-positive values fall back to the default.
func (OrchestratorRestartConfig) StableResetDuration ¶ added in v0.69.1
func (r OrchestratorRestartConfig) StableResetDuration() time.Duration
StableResetDuration is how long a run must last before its exit resets the backoff level. Empty, unparseable, or non-positive uses OrchestratorStableResetDefault.
type OrchestratorSandboxConfig ¶ added in v0.46.0
type OverlayKeybindings ¶ added in v0.69.1
type OverlayKeybindings struct {
// Shared navigation, applied across the overlays.
Up string `toml:"up"`
Down string `toml:"down"`
PageUp string `toml:"page_up"`
PageDown string `toml:"page_down"`
Top string `toml:"top"`
Bottom string `toml:"bottom"`
Confirm string `toml:"confirm"`
Cancel string `toml:"cancel"`
// Dashboard actions.
DashboardAttach string `toml:"dashboard_attach"`
DashboardStop string `toml:"dashboard_stop"`
DashboardDelete string `toml:"dashboard_delete"`
DashboardResume string `toml:"dashboard_resume"`
// Approval prompt actions.
ApprovalAllow string `toml:"approval_allow"`
ApprovalDeny string `toml:"approval_deny"`
ApprovalAllowAll string `toml:"approval_allow_all"`
// Message viewer actions.
MessagePin string `toml:"message_pin"`
MessageExpandAll string `toml:"message_expand_all"`
MessageCollapseAll string `toml:"message_collapse_all"`
MessageNextConv string `toml:"message_next_conversation"`
MessagePrevConv string `toml:"message_prev_conversation"`
}
OverlayKeybindings configures the keys used inside the terminal TUI overlays. Every value is a space-separated list of bubbletea key names (single letters, "up", "down", "enter", "esc", "pgup", "ctrl+d", ...); pressing any listed key triggers the action. Empty fields fall back to the built-in defaults, so a partial [keybindings.overlay] table only overrides the keys it names.
type PRWatchAdvancedConfig ¶ added in v0.69.1
type PRWatchAdvancedConfig struct {
// BaseTick is the base poll-loop cadence (per-session gating paces the actual
// gh calls below it). Default 15s. Applied when the watch loop starts.
BaseTick string `toml:"base_tick"`
// BatchSize caps how many sessions are polled per tick, bounding gh load on a
// large fleet. Default 3.
BatchSize int `toml:"batch_size"`
// NoPRNegativeCache is how long a branch with no PR is left before re-resolving
// on the ordinary timer. Default 5m.
NoPRNegativeCache string `toml:"no_pr_negative_cache"`
// CommentBodyMaxBytes truncates each delivered PR-comment body to this many
// bytes, bounding notification size. Default 1024.
CommentBodyMaxBytes int `toml:"comment_body_max_bytes"`
// NotificationRateLimit / NotificationRateWindow are the per-session rolling
// anti-thrash backstop: at most this many notifications per window to one
// session. Defaults 5 per 30m.
NotificationRateLimit int `toml:"notification_rate_limit"`
NotificationRateWindow string `toml:"notification_rate_window"`
// UntrustedAuthorPromptRate / UntrustedAuthorPromptWindow bound the untrusted
// comment-author trust prompt to the orchestrator (a security surface — a busy
// public PR churning drive-by commenters must not flood it). Defaults 5 per 30m.
UntrustedAuthorPromptRate int `toml:"untrusted_author_prompt_rate"`
UntrustedAuthorPromptWindow string `toml:"untrusted_author_prompt_window"`
// MaxPromptedAuthors bounds the persisted set of already-surfaced untrusted
// authors so it can't grow without limit. Default 5000.
MaxPromptedAuthors int `toml:"max_prompted_authors"`
// KickCooldown is the minimum interval between git-ref-triggered immediate polls
// of one session (belt-and-braces over the ref-watch debounce). Default 3s.
KickCooldown string `toml:"kick_cooldown"`
// KickChannelSize is the buffered kick-channel capacity; a full channel drops
// the (best-effort) kick. Default 64. Applied when the watch state is built.
KickChannelSize int `toml:"kick_channel_size"`
// KickedNoPRBackoff is the short re-poll delay after a kicked poll finds no PR
// yet (a push is usually moments before `gh pr create`), instead of parking on
// the full negative cache. Default 20s.
KickedNoPRBackoff string `toml:"kicked_no_pr_backoff"`
// RefReconcileInterval is how often the git-ref watcher set is reconciled
// against live sessions. Default 2s. Applied when the ref-watch loop starts.
RefReconcileInterval string `toml:"ref_reconcile_interval"`
// RefDebounce coalesces the burst of ref/reflog writes one push/commit/checkout
// produces into a single kick. Default 750ms.
RefDebounce string `toml:"ref_debounce"`
// GHTimeout is the per-command timeout for the daemon's `gh` invocations, so a
// hung gh can never stall the loop. Default 5s.
GHTimeout string `toml:"gh_timeout"`
}
PRWatchAdvancedConfig carries the advanced tuning for the PR/CI watch loop and its git-ref accelerator. These were formerly hard-coded policy literals in the daemon; they are surfaced here so an operator can tune load, latency, retention, and the untrusted-author prompt-injection surface without a rebuild. Every field is optional: an unset (zero) value resolves to the documented default through the PRWatchConfig accessors, so leaving [pr_watch.advanced] out is a no-op.
type PRWatchConfig ¶ added in v0.59.0
type PRWatchConfig struct {
Enabled bool `toml:"enabled"`
NotifyCIFailures bool `toml:"notify_ci_failures"`
NotifyMergeConflicts bool `toml:"notify_merge_conflicts"`
NotifyReviewComments bool `toml:"notify_review_comments"`
NotifyPRComments bool `toml:"notify_pr_comments"`
NotifyReviewDecisions bool `toml:"notify_review_decisions"`
NotifyPRLifecycle bool `toml:"notify_pr_lifecycle"`
NotifyCIRecovery bool `toml:"notify_ci_recovery"`
PollPending string `toml:"poll_pending"`
PollTerminal string `toml:"poll_terminal"`
PollMerged string `toml:"poll_merged"`
MaxNotificationsPerPR int `toml:"max_notifications_per_pr"`
Debounce string `toml:"debounce"`
// CommentAuthorAllowlist trusts individual comment authors by login,
// case-insensitively and matched against the full "<name>[bot]" string. It is
// the ONLY way to trust a bot or GitHub App (their author_association is
// unreliable — a bot can carry NONE or CONTRIBUTOR), and also covers named
// humans. Defaults empty; discovery is via the orchestrator trust prompt.
CommentAuthorAllowlist []string `toml:"comment_author_allowlist"`
// TrustedAuthorAssociations is the set of GitHub author_association values
// treated as trusted. Defaults to OWNER/MEMBER/COLLABORATOR when unset (the
// "has write access to, or is a member of the org that owns, the repo" tier);
// CONTRIBUTOR is deliberately excluded. Values are normalised to upper-case
// via TrustedAssociationSet.
TrustedAuthorAssociations []string `toml:"trusted_author_associations"`
// NotifyUntrustedAuthors, when true, sends a one-time metadata-only message to
// the orchestrator the first time a comment from a not-yet-trusted author is
// seen, so the human can decide whether to allowlist them. It NEVER carries
// the untrusted comment body. False disables the prompt entirely (silent drop,
// still logged).
NotifyUntrustedAuthors bool `toml:"notify_untrusted_authors"`
// Advanced holds the low-level watcher-tuning knobs (loop cadence, batch size,
// caches, rate limits, ref-watch timing, gh timeout). Every field is optional
// and falls back to a sensible default via the accessors below, so a config
// that omits [pr_watch.advanced] entirely behaves exactly as before. Expose
// these only for operators who need to trade off load, latency, retention, and
// prompt-injection surface — the defaults suit ordinary use.
Advanced PRWatchAdvancedConfig `toml:"advanced"`
}
PRWatchConfig controls the PR & CI awareness loop, which resolves each session's GitHub PR via the gh CLI, polls its CI checks and review comments, and notifies the owning session's inbox on meaningful transitions.
Every notify_* sub-option defaults on: enabling pr_watch is meant to be a single switch (enabled = true) that turns on all notifications, and users selectively disable the classes they don't want. The classes are still gated separately because they carry different authority — a CI failure is a machine verdict (safe to act on), while a review comment or decision is human intent that may not be actionable — so each can be turned off independently.
Comments come in two distinct kinds, each with its own gate:
- NotifyReviewComments covers inline code-review comments (the pulls/{n}/comments surface) — feedback anchored to a file and line.
- NotifyPRComments covers regular conversation comments on the PR thread (the issues/{n}/comments surface) — issue-style comments not tied to a line of code.
They are separate signals: a reviewer leaving inline nits and someone dropping a "ship it" on the conversation thread differ, and a user may want one without the other.
For backward compatibility, notify_pr_comments used to be folded into notify_review_comments; see applyPRWatchCommentCompat, which keeps an older config that only set notify_review_comments delivering conversation comments.
func (PRWatchConfig) BaseTickDuration ¶ added in v0.69.1
func (p PRWatchConfig) BaseTickDuration() time.Duration
BaseTickDuration is the base poll-loop cadence. Default 15s; an unset, unparseable, or non-positive value uses the default (the poll loop feeds this straight to time.NewTicker, which panics on a non-positive interval).
func (PRWatchConfig) BatchSize ¶ added in v0.69.1
func (p PRWatchConfig) BatchSize() int
BatchSize caps sessions polled per tick. Default 3.
func (PRWatchConfig) CommentBodyMaxBytes ¶ added in v0.69.1
func (p PRWatchConfig) CommentBodyMaxBytes() int
CommentBodyMaxBytes is the per-comment body truncation cap. Default 1024.
func (PRWatchConfig) DebounceDuration ¶ added in v0.59.0
func (p PRWatchConfig) DebounceDuration() time.Duration
DebounceDuration is the minimum cooldown between notifications to one session.
func (PRWatchConfig) GHTimeoutDuration ¶ added in v0.69.1
func (p PRWatchConfig) GHTimeoutDuration() time.Duration
GHTimeoutDuration is the per-`gh`-command timeout. Default 5s.
func (PRWatchConfig) KickChannelSize ¶ added in v0.69.1
func (p PRWatchConfig) KickChannelSize() int
KickChannelSize is the buffered kick-channel capacity. Default 64, maximum 4096. Directly constructed configs above the maximum are defensively capped; loaded configs reject them during validation.
func (PRWatchConfig) KickCooldownDuration ¶ added in v0.69.1
func (p PRWatchConfig) KickCooldownDuration() time.Duration
KickCooldownDuration is the min interval between git-ref-triggered polls of one session. Default 3s.
func (PRWatchConfig) KickedNoPRBackoffDuration ¶ added in v0.69.1
func (p PRWatchConfig) KickedNoPRBackoffDuration() time.Duration
KickedNoPRBackoffDuration is the short re-poll delay after a kicked no-PR miss. Default 20s.
func (PRWatchConfig) MaxNotifications ¶ added in v0.59.0
func (p PRWatchConfig) MaxNotifications() int
MaxNotifications returns the per-head-SHA notification cap, defaulting to 10.
func (PRWatchConfig) MaxPromptedAuthors ¶ added in v0.69.1
func (p PRWatchConfig) MaxPromptedAuthors() int
MaxPromptedAuthors bounds the persisted surfaced-authors set. Default 5000.
func (PRWatchConfig) NoPRNegativeCacheDuration ¶ added in v0.69.1
func (p PRWatchConfig) NoPRNegativeCacheDuration() time.Duration
NoPRNegativeCacheDuration is the no-PR re-resolve interval. Default 5m.
func (PRWatchConfig) NotificationRateLimit ¶ added in v0.69.1
func (p PRWatchConfig) NotificationRateLimit() int
NotificationRateLimit is the per-session rolling notification cap. Default 5.
func (PRWatchConfig) NotificationRateWindowDuration ¶ added in v0.69.1
func (p PRWatchConfig) NotificationRateWindowDuration() time.Duration
NotificationRateWindowDuration is the per-session rate-limit window. Default 30m; an unset, unparseable, or non-positive value uses the default. This window bounds a rolling anti-thrash cap (NotificationRateLimit), so a zero/negative value must not slip through: it would prune every prior timestamp and disable the cap (issue #1304).
func (PRWatchConfig) PollMergedDuration ¶ added in v0.59.0
func (p PRWatchConfig) PollMergedDuration() time.Duration
PollMergedDuration is the sweep interval for merged/closed PRs.
func (PRWatchConfig) PollPendingDuration ¶ added in v0.59.0
func (p PRWatchConfig) PollPendingDuration() time.Duration
PollPendingDuration is the poll interval while a PR has pending/in-progress checks.
func (PRWatchConfig) PollTerminalDuration ¶ added in v0.59.0
func (p PRWatchConfig) PollTerminalDuration() time.Duration
PollTerminalDuration is the poll interval once all checks are terminal (PR still open).
func (PRWatchConfig) RefDebounceDuration ¶ added in v0.69.1
func (p PRWatchConfig) RefDebounceDuration() time.Duration
RefDebounceDuration coalesces a burst of ref writes into one kick. Default 750ms.
func (PRWatchConfig) RefReconcileIntervalDuration ¶ added in v0.69.1
func (p PRWatchConfig) RefReconcileIntervalDuration() time.Duration
RefReconcileIntervalDuration is the git-ref watcher reconcile cadence. Default 2s; an unset, unparseable, or non-positive value uses the default (the ref watcher feeds this straight to time.NewTicker, which panics on a non-positive interval).
func (PRWatchConfig) TrustedAssociationSet ¶ added in v0.67.1
func (p PRWatchConfig) TrustedAssociationSet() map[string]bool
TrustedAssociationSet returns the resolved set of trusted author_association values as an upper-cased lookup set. A configured list is normalised to upper-case (GitHub returns the enum upper-cased, but config is hand-written) and empty/whitespace entries are dropped.
The nil vs present-but-empty distinction is load-bearing and fails CLOSED (issue #1039):
- A NIL slice means "unset" (the Go zero value, or a config built without defaults) and falls back to DefaultTrustedAssociations. Load() seeds the field from default_config.toml, so an unset key in a real config resolves to the default three; nil here covers direct struct construction.
- A PRESENT-but-empty slice (trusted_author_associations = []) is an explicit "trust no association" — allowlist-only mode — and is honoured as an empty set. go-toml/v2 decodes `= []` to a non-nil empty slice, so it is distinguishable from an absent key, and we must NOT silently widen it back to the default (that would fail open on an operator asking to lock the gate down).
func (PRWatchConfig) UntrustedAuthorPromptRate ¶ added in v0.69.1
func (p PRWatchConfig) UntrustedAuthorPromptRate() int
UntrustedAuthorPromptRate caps untrusted-author trust prompts per window. Default 5.
func (PRWatchConfig) UntrustedAuthorPromptWindowDuration ¶ added in v0.69.1
func (p PRWatchConfig) UntrustedAuthorPromptWindowDuration() time.Duration
UntrustedAuthorPromptWindowDuration is the trust-prompt rate window. Default 30m; an unset, unparseable, or non-positive value uses the default. This window bounds the security-sensitive rolling anti-flood cap on untrusted-author trust prompts (UntrustedAuthorPromptRate); a zero/negative value must not slip through, or it would prune every prior timestamp and disable the cap (issue #1304).
type PairRate ¶ added in v0.66.3
PairRate is a parsed pair_request_rate: Count events per Per duration.
func ParsePairRequestRate ¶ added in v0.66.3
ParsePairRequestRate parses a "<n>/<unit>" rate such as "5/min". The unit is one of sec/min/hour (with the aliases second/minute/hour). The count must be a positive integer. Any other shape is a hard error (fail-closed).
type Paths ¶
type Paths struct {
Profile string
AppName string
ConfigFile string
DataDir string
RuntimeDir string
SocketPath string
PIDFile string
StateFile string
HumanTokenFile string
LogDir string
DaemonLog string
MessagesDB string
TodosDB string
TmpDir string
}
func ResolvePaths ¶
func (Paths) EnsureDirs ¶
func (Paths) WithDataDir ¶ added in v0.21.0
type RemoteConfig ¶ added in v0.66.3
type RemoteConfig struct {
// Enabled turns the remote listener on. Off by default; when false the rest
// of the block is not validated so a disabled block never blocks startup.
Enabled bool `toml:"enabled"`
// Mode selects the transport: "tsnet" (embedded Tailscale via tsnet) or
// "interface" (bind the host's existing tailnet interface IP).
Mode string `toml:"mode"`
// Hostname is the tsnet node name / MagicDNS label and the remote TLS
// certificate name.
Hostname string `toml:"hostname"`
// Port is the TCP port the listener binds.
Port int `toml:"port"`
// AuthKeyFile is the path to a tsnet auth key (tsnet mode only).
AuthKeyFile string `toml:"auth_key_file"`
// Tags are the tsnet ACL tags applied to the node (tsnet mode only).
Tags []string `toml:"tags"`
// AllowTailnetUsers is the WhoIs allowlist (Gate 1). Entries are either a
// tailnet user email or a "tag:"-prefixed tag. A bare "tag:" entry opts
// tagged nodes in; with no tag entry, tagged nodes are disallowed.
AllowTailnetUsers []string `toml:"allow_tailnet_users"`
// RequirePairing requires per-device pairing (Gate 2) for human-level
// rights. Defaults to true; false is UNSAFE (trusts the tailnet identity
// alone) and is restricted to read-only access — see the design doc §B.2.
RequirePairing bool `toml:"require_pairing"`
// PairRequestRate is the anti-flood limit on pending pair requests, written
// "<n>/<unit>" (e.g. "5/min"); units are sec, min, or hour. Empty falls back
// to the pair_fallback_count/pair_fallback_window rate below.
PairRequestRate string `toml:"pair_request_rate"`
// MaxPendingPairings caps how many unapproved pair requests may be
// outstanding at once (anti-flood). 0 uses the default
// (RemoteMaxPendingPairingsDefault); values outside [1,
// RemoteMaxPendingPairingsMax] are a hard config error.
MaxPendingPairings int `toml:"max_pending_pairings"`
// PendingPairingTTL is how long an unapproved pair request lives before it
// expires and can no longer be approved. Empty uses the default
// (RemotePendingPairingTTLDefault); a parsed value outside
// [RemotePendingPairingTTLMin, RemotePendingPairingTTLMax] is a hard error.
PendingPairingTTL string `toml:"pending_pairing_ttl"`
// PairFallbackCount is the request count of the rate limit applied when
// pair_request_rate is unset. 0 uses the default
// (RemotePairFallbackCountDefault); values outside [1,
// RemotePairFallbackCountMax] are a hard config error.
PairFallbackCount int `toml:"pair_fallback_count"`
// PairFallbackWindow is the window of the rate limit applied when
// pair_request_rate is unset. Empty uses the default
// (RemotePairFallbackWindowDefault); a parsed value outside
// [RemotePairFallbackWindowMin, RemotePairFallbackWindowMax] is a hard error.
PairFallbackWindow string `toml:"pair_fallback_window"`
}
RemoteConfig is the optional, off-by-default [remote] block that exposes a tailnet-facing control listener (see the native-app design doc §A.4/§B). It is fail-closed: when Enabled, an invalid block is a hard config-load error (static validation only — runtime listener provisioning failures, e.g. a missing tailnet IP or cert, are handled by the remote listener, not here).
func (RemoteConfig) AllowsTaggedNodes ¶ added in v0.66.3
func (r RemoteConfig) AllowsTaggedNodes() bool
AllowsTaggedNodes reports whether any allow_tailnet_users entry opts tagged nodes in (a "tag:"-prefixed entry). With no such entry, tagged nodes — which WhoIs resolves with no user — are disallowed by default.
func (RemoteConfig) MaxPendingPairingsOrDefault ¶ added in v0.69.1
func (r RemoteConfig) MaxPendingPairingsOrDefault() int
MaxPendingPairingsOrDefault returns the configured pending-pairing cap, applying the default when unset and clamping to the safe bounds so a caller that skipped Validate can never act on an unsafe value.
func (RemoteConfig) PairFallbackRate ¶ added in v0.69.1
func (r RemoteConfig) PairFallbackRate() PairRate
PairFallbackRate returns the rate limit applied when pair_request_rate is unset, applying defaults and clamping each component to its safe bounds.
func (RemoteConfig) PendingPairingTTLDuration ¶ added in v0.69.1
func (r RemoteConfig) PendingPairingTTLDuration() time.Duration
PendingPairingTTLDuration returns the configured pending-pairing TTL, applying the default when unset/unparseable and clamping to the safe bounds.
func (RemoteConfig) Validate ¶ added in v0.66.3
func (r RemoteConfig) Validate() error
Validate checks the [remote] block for static contradictions. Rules are only enforced when Enabled — a disabled block (even with otherwise-invalid values) always loads. It is fail-closed: an invalid enabled block is a hard error.
type RepoConfig ¶ added in v0.18.0
type RepoConfig struct {
Path string `toml:"path"`
AllowConcurrent bool `toml:"allow_concurrent"`
Singleton bool `toml:"singleton"`
Includes []string `toml:"includes"`
}
func (RepoConfig) Validate ¶ added in v0.19.0
func (rc RepoConfig) Validate() error
type ResourceMonitor ¶ added in v0.69.1
type ResourceMonitor struct {
// SampleInterval is the cadence at which each session's process group is
// snapshotted (and the per-session spacing that keeps a launch-burst kick
// from replacing an established session's history). Empty, unparseable, or
// non-positive uses the default (ResourceSampleIntervalDefault).
SampleInterval string `toml:"sample_interval"`
// SampleHistory is how many recent samples are retained per session (the
// window shown in an abnormal-exit report). Values < 1 fall back to the
// default (ResourceSampleHistoryDefault).
SampleHistory int `toml:"sample_history"`
}
ResourceMonitor is the [resource_monitor] block controlling the daemon's per-session resource-sampling loop, which snapshots each live session's process-group RSS/CPU/FD usage (issue #1244). The values were previously fixed constants in internal/daemon/resource_monitor.go; every field is optional and falls back to the matching default constant.
func (ResourceMonitor) SampleHistoryOrDefault ¶ added in v0.69.1
func (r ResourceMonitor) SampleHistoryOrDefault() int
SampleHistoryOrDefault returns the retained-sample count, clamped to a sensible minimum. A non-positive value means "use the default".
func (ResourceMonitor) SampleIntervalDuration ¶ added in v0.69.1
func (r ResourceMonitor) SampleIntervalDuration() time.Duration
SampleIntervalDuration returns the sampling cadence, or the default when unset, unparseable, or non-positive (a zero cadence would busy-loop).
type SandboxConfig ¶ added in v0.11.0
type SandboxConfig struct {
Enabled bool `json:"enabled" toml:"enabled"`
Disabled *bool `json:"disabled,omitempty" toml:"disabled,omitempty"`
// Backend selects the sandbox backend: "safehouse" (macOS only) or "nono"
// (Linux + macOS). It has NO default — when the sandbox is enabled and
// Backend is unset the daemon fails closed with an actionable error. This
// is a deliberate pre-1.0 behaviour change (see the nono sandbox design doc).
Backend string `json:"backend,omitempty" toml:"backend"`
Command string `json:"command,omitempty" toml:"command"`
// Profile (nono only) is the base profile graith's generated profile
// extends. Empty means nono's built-in "default" (its audited deny groups +
// base system paths). Set it to a maintained registry profile — e.g.
// "always-further/claude" — to inherit that agent's upstream file grants
// (its ~/.claude, ~/.claude.json, versioned binary dir, …) instead of
// hand-listing them via write_files.
//
// nono resolves "extends" by MERGING the base profile with graith's
// generated one. Collection fields (filesystem.allow/read,
// environment.allow_vars, network.allow_domain, …) are UNIONED (append +
// dedup) — graith's grants are added to, not substituted for, the base's;
// only scalar fields (e.g. workdir.access, security.signal_mode) are
// child-overridden. So graith's filesystem grants are always present, but
// graith's env allowlist can only WIDEN the base profile's, it cannot narrow
// it. A base profile that allows extra env vars, network
// domains, set_vars, command policies, or session hooks (which run outside
// the sandbox) therefore relaxes graith's baseline — so a custom profile is
// only as tight as the operator has audited it to be. Choose a trusted,
// least-privilege profile. nono's audited deny groups (deny_credentials, …)
// are marked required and merged into every resolved profile regardless of
// this field, so a custom base cannot silently drop the credential-deny
// baseline. The safehouse backend has no profile concept and ignores it.
Profile string `json:"profile,omitempty" toml:"profile"`
Features []string `json:"features,omitempty" toml:"features"`
ReadDirs []string `json:"read_dirs,omitempty" toml:"read_dirs"`
WriteDirs []string `json:"write_dirs,omitempty" toml:"write_dirs"`
// ReadFiles / WriteFiles grant access to individual files rather than whole
// directories. They exist for paths that can't be expressed as a directory
// grant without over-sharing — most importantly single files that live
// directly in $HOME (e.g. an agent's ~/.claude.json login file), where
// granting the parent directory would expose unrelated secrets (.env, ssh
// keys, tfvars). ReadFiles is read-only; WriteFiles is read+write, mirroring
// the read_dirs / write_dirs convention (where "write" means read+write, not
// nono's write-only mode). They map to the nono profile's
// filesystem.read_file / filesystem.allow_file; the safehouse backend folds
// them into its read-only / read-write path lists.
ReadFiles []string `json:"read_files,omitempty" toml:"read_files"`
WriteFiles []string `json:"write_files,omitempty" toml:"write_files"`
// SignalMode controls whether the sandboxed process may signal other
// processes. It maps to nono's security.signal_mode ("isolated",
// "allow_same_sandbox", "allow_all"). Empty inherits nono's base-profile
// default (allow_same_sandbox). safehouse ignores it. Setting "isolated"
// makes graith's `process-control` semantics meaningful under nono (Phase 1
// left it a no-op). See the nono sandbox design doc §C5.
SignalMode string `json:"signal_mode,omitempty" toml:"signal_mode"`
// Network is an optional egress policy. It maps to the nono profile's
// network section (network.block / network.allow_domain). safehouse has no
// network primitive and only warns. A network policy also raises the
// enforcement floor: nono needs Landlock ABI v4 (kernel 6.7+) to filter
// network, so a requested policy on an older kernel fails closed.
Network *SandboxNetworkConfig `json:"network,omitempty" toml:"network"`
}
func (SandboxConfig) Merge ¶ added in v0.11.0
func (s SandboxConfig) Merge(agent SandboxConfig) SandboxConfig
type SandboxNetworkConfig ¶ added in v0.64.0
type SandboxNetworkConfig struct {
// Block denies all outbound network access (nono is network-allowed by
// default). Maps to network.block = true.
Block bool `json:"block,omitempty" toml:"block"`
// AllowDomains is the proxy allowlist. Maps to network.allow_domain. When
// set, nono runs its L7 filtering proxy and only these domains are
// reachable. Entries are plain hostnames or URL globs.
AllowDomains []string `json:"allow_domains,omitempty" toml:"allow_domains"`
}
SandboxNetworkConfig is graith's egress policy. It maps directly onto nono v0.66.0's profile network section: Block -> network.block, AllowDomains -> network.allow_domain (an L7 proxy allowlist; a plain hostname allows the host, a URL glob restricts to matching endpoints).
func (*SandboxNetworkConfig) IsSet ¶ added in v0.64.0
func (n *SandboxNetworkConfig) IsSet() bool
IsSet reports whether this network policy requests any egress restriction. A nil or empty config requests nothing (matches nono's allow-by-default).
type ScenarioLifecycleConfig ¶ added in v0.69.2
type ScenarioLifecycleConfig struct {
Cleanup string `json:"cleanup,omitempty" toml:"cleanup"`
Delay string `json:"delay,omitempty" toml:"delay"`
}
ScenarioLifecycleConfig controls optional cleanup after a completion epoch. The zero value is deliberately disabled for backward compatibility.
func (ScenarioLifecycleConfig) CleanupMode ¶ added in v0.69.2
func (c ScenarioLifecycleConfig) CleanupMode() string
func (ScenarioLifecycleConfig) DelayDuration ¶ added in v0.69.2
func (c ScenarioLifecycleConfig) DelayDuration() time.Duration
type ScheduleConfig ¶ added in v0.67.0
type ScheduleConfig struct {
Cron string `toml:"cron"` // 5-field cron, or @hourly/@daily/@weekly/@monthly
Every string `toml:"every"` // Go duration (supports "7d"): "15m", "1h30m"
Timezone string `toml:"timezone"` // IANA zone for cron; default = daemon local time
}
ScheduleConfig is the time-driven source. Exactly one of Cron/Every is set.
type StatusConfig ¶ added in v0.32.0
type StatusConfig struct {
TTL string `toml:"ttl"`
}
func (StatusConfig) TTLDuration ¶ added in v0.32.0
func (s StatusConfig) TTLDuration() time.Duration
type TemplateVars ¶
type TemplateVars struct {
Username string
AgentSessionID string
SessionName string
SessionID string
WorktreePath string
ForkSourceAgentSessionID string
Model string
// Dir is the directory bound to {dir} when expanding an agent's
// add_dir_args, once per granted worktree (see Agent.AddDirArgsFor). It is
// empty in every other expansion context.
Dir string
// Profile, ReasoningEffort, ServiceTier, ApprovalPolicy, and WebSearch are
// the Codex per-session options (issue #1186) surfaced as template variables
// so an agent's conditional option_args groups (Agent.OptionArgsFor) can turn
// them into CLI flags from config rather than hard-coded Go (issue #1236).
// WebSearch is a boolean; it expands to "true" when set and "" otherwise, so
// an option_args group can gate on it with `when = "web_search"`.
Profile string
ReasoningEffort string
ServiceTier string
ApprovalPolicy string
WebSearch bool
}
type TerminalConfig ¶ added in v0.69.1
type TerminalConfig struct {
// RefreshInterval is the cadence at which the session picker, the dashboard,
// and an attached status bar re-poll the daemon for fresh session state.
// Empty, unparseable, or non-positive uses the default
// (TerminalRefreshIntervalDefault); a zero cadence would busy-loop.
RefreshInterval string `toml:"refresh_interval"`
// SummaryWidth is the maximum visible width (in cells) of a `gr status`
// summary shown against a session in the picker before it is truncated with
// an ellipsis. Values < 1 fall back to the default (TerminalSummaryWidth).
SummaryWidth int `toml:"summary_width"`
}
TerminalConfig is the [terminal] block: user-tunable interactive-TUI presentation preferences that were previously fixed literals in the client (issue #1254) — how often the picker/dashboard/status bar refresh, and how wide a `gr status` summary may grow in the picker before truncation.
Session-lifecycle presentation (the fallback terminal geometry and the per-session scrollback cap) is deliberately NOT here: it lives in the [lifecycle] block (issue #1243, default_cols/default_rows/max_log_bytes), which owns the daemon's PTY seed. Layout invariants (the picker's column arithmetic, wrap widths, the minimum name column, and the GUI's frame rate) are also excluded — they must match render logic and stay as documented constants. Every field is optional and falls back to its default constant.
func (TerminalConfig) RefreshIntervalDuration ¶ added in v0.69.1
func (t TerminalConfig) RefreshIntervalDuration() time.Duration
RefreshIntervalDuration returns the TUI refresh cadence, or the default when unset, unparseable, or non-positive (a zero cadence would busy-loop).
func (TerminalConfig) SummaryWidthValue ¶ added in v0.69.1
func (t TerminalConfig) SummaryWidthValue() int
SummaryWidthValue returns the picker summary truncation width, or the default when the configured value is non-positive.
type TodoConfig ¶ added in v0.69.0
type TodoConfig struct {
EmitEvents string `toml:"emit_events"` // "scenario" (default) | "all" | "off"
ClaimLease string `toml:"claim_lease"` // Go duration; "" = 30m default; "0" disables
Retention string `toml:"retention"` // Go duration; "" or "0" = keep done items forever
// MaxTitle is the maximum todo title length in bytes. Values < 1 fall back to
// the default (TodoMaxTitleDefault); a value above TodoMaxTitleCeiling — the
// hard limit baked into the database CHECK constraint — is rejected at load.
// Config may only tighten below the ceiling. Reloadable.
MaxTitle int `toml:"max_title"`
// MaxNote is the maximum todo note length in bytes. Values < 1 fall back to
// the default (TodoMaxNoteDefault); a value above TodoMaxNoteCeiling — the
// hard database CHECK ceiling — is rejected at load. Reloadable.
MaxNote int `toml:"max_note"`
// ListLimit caps how many items a single List/ListAll returns, so an in-scope
// caller can't force an unbounded allocation or a long store-mutex hold. Values
// < 1 fall back to the default (TodoListLimitDefault); a value above
// TodoListLimitCeiling is rejected at load. Restart-only (fixed at store open).
ListLimit int `toml:"list_limit"`
// SweepInterval is how often the lease/retention sweep loop runs. Empty,
// unparseable, or non-positive uses the default (TodoSweepIntervalDefault); a
// zero cadence would busy-loop. Restart-only (the loop ticker is built once).
SweepInterval string `toml:"sweep_interval"`
// BusyTimeout is the SQLite busy_timeout for the todos database. The claim
// contract ("loser gets zero rows") relies on a contended writer waiting rather
// than erroring with SQLITE_BUSY, so this is load-bearing. Empty/unset uses the
// default (TodoBusyTimeoutDefault, 5s). An explicit value must parse and fall
// in [SQLiteBusyTimeoutResolution, TodoBusyTimeoutCeiling] (1ms–5m): SQLite's
// busy_timeout has millisecond resolution, so a positive sub-1ms value would
// collapse to busy_timeout(0) and disable the wait the claim contract depends
// on, and it — along with any unparseable, non-positive, or above-ceiling
// value — is rejected at load. Restart-only.
BusyTimeout string `toml:"busy_timeout"`
}
TodoConfig is the [todo] block. It governs the first-class todo subsystem (issue #591): event emission on state change, the claim lease that reclaims stranded in-progress items, and the retention window that sweeps done items.
func (TodoConfig) BusyTimeoutDuration ¶ added in v0.69.1
func (t TodoConfig) BusyTimeoutDuration() time.Duration
BusyTimeoutDuration returns the todos-database SQLite busy_timeout, or the default when unset, unparseable, or non-positive (a zero/negative timeout would break the claim contract by failing a contended writer immediately).
func (TodoConfig) ClaimLeaseDuration ¶ added in v0.69.0
func (t TodoConfig) ClaimLeaseDuration() time.Duration
ClaimLeaseDuration resolves the claim-lease window. Unset (or, as a fail-safe, unparseable — though Validate rejects that at startup) defaults to 30m; an explicit "0" disables the lease sweep.
func (TodoConfig) EmitMode ¶ added in v0.69.0
func (t TodoConfig) EmitMode() string
EmitMode resolves the emit-events mode, defaulting to "scenario".
func (TodoConfig) ListLimitOrDefault ¶ added in v0.69.1
func (t TodoConfig) ListLimitOrDefault() int
ListLimitOrDefault returns the List/ListAll row cap. A non-positive value means "use the default".
func (TodoConfig) MaxNoteOrDefault ¶ added in v0.69.1
func (t TodoConfig) MaxNoteOrDefault() int
MaxNoteOrDefault returns the maximum note length. A non-positive value means "use the default".
func (TodoConfig) MaxTitleOrDefault ¶ added in v0.69.1
func (t TodoConfig) MaxTitleOrDefault() int
MaxTitleOrDefault returns the maximum title length. A non-positive value means "use the default".
func (TodoConfig) RetentionDuration ¶ added in v0.69.0
func (t TodoConfig) RetentionDuration() time.Duration
RetentionDuration resolves the done-item retention window. Unset or zero keeps done items indefinitely (returns 0).
func (TodoConfig) SweepIntervalDuration ¶ added in v0.69.1
func (t TodoConfig) SweepIntervalDuration() time.Duration
SweepIntervalDuration returns the lease/retention sweep cadence, or the default when unset, unparseable, or non-positive (a zero cadence would busy-loop the sweep timer).
type TokenAccounting ¶ added in v0.69.1
type TokenAccounting struct {
// PollInterval is the cadence at which the loop re-derives per-session token
// usage from transcripts. Empty, unparseable, or non-positive uses the
// default (TokenPollIntervalDefault); a zero cadence would busy-loop.
PollInterval string `toml:"poll_interval"`
// StartupDelay is the short first-tick delay after a daemon (re)start so
// `gr tokens` isn't blank for a full interval. Empty or unparseable uses the
// default (TokenStartupDelayDefault); an explicit "0" polls immediately.
StartupDelay string `toml:"startup_delay"`
// BatchSize bounds how many sessions are (re)parsed per tick so a large fleet
// with big transcripts can't stall the loop. Values < 1 fall back to the
// default (TokenBatchSizeDefault).
BatchSize int `toml:"batch_size"`
}
TokenAccounting is the [token_accounting] block controlling the daemon's per-session token-usage loop, which periodically re-derives token totals from each supported session's on-disk transcript (issue #1244). The values were previously fixed constants in internal/daemon/tokens.go; every field is optional and falls back to the matching default constant, preserving the historical behaviour.
func (TokenAccounting) BatchSizeOrDefault ¶ added in v0.69.1
func (t TokenAccounting) BatchSizeOrDefault() int
BatchSizeOrDefault returns the per-tick parse cap, clamped to a sensible minimum. A non-positive value means "use the default".
func (TokenAccounting) PollIntervalDuration ¶ added in v0.69.1
func (t TokenAccounting) PollIntervalDuration() time.Duration
PollIntervalDuration returns the token-poll cadence, or the default when unset, unparseable, or non-positive (a zero cadence would busy-loop).
func (TokenAccounting) StartupDelayDuration ¶ added in v0.69.1
func (t TokenAccounting) StartupDelayDuration() time.Duration
StartupDelayDuration returns the first-tick delay, or the default when unset or unparseable. An explicit "0" is honoured (poll immediately after start).
type ToolsConfig ¶ added in v0.69.1
type ToolsConfig struct {
// Git is the git executable (default "git").
Git string `toml:"git"`
// GH is the GitHub CLI executable (default "gh").
GH string `toml:"gh"`
// GCX is the Grafana Cloud CLI executable used by gcx trigger sources
// (default "gcx").
GCX string `toml:"gcx"`
// Shell runs notification and trigger commands as `<shell> -c <cmd>`
// (default "sh").
Shell string `toml:"shell"`
// OSAScript is the macOS osascript executable used for desktop
// notifications (default "osascript").
OSAScript string `toml:"osascript"`
// PS is the process-listing executable (default "/bin/ps").
PS string `toml:"ps"`
// Lsof is the open-files listing executable (default "/usr/sbin/lsof").
Lsof string `toml:"lsof"`
}
ToolsConfig is the tools block overriding the external executables graith shells out to (issue #1238). Each field may be a bare command name resolved on PATH ("git", "hub") or an absolute/relative path to a specific binary ("/run/current-system/sw/bin/git"). An empty field keeps graith's built-in default (see tools.Defaults). This unblocks Nix/custom-PATH installs, wrapper binaries, and alternate shells. Only explicit overrides are validated at startup; unset defaults retain plain PATH-lookup semantics.
func (ToolsConfig) Resolved ¶ added in v0.69.1
func (t ToolsConfig) Resolved(baseDir string) tools.Config
Resolved converts the config block into the tools package's Config, normalizing each path-valued override against baseDir (the directory holding config.toml). Empty fields are left empty here; tools.Configure fills them from tools.Defaults so there is a single source of default values. Because normalization produces a stable absolute path, the same value is used for validation and for execution regardless of the later exec.Cmd.Dir (#1293).
func (ToolsConfig) Validate ¶ added in v0.69.1
func (t ToolsConfig) Validate(baseDir string) error
Validate checks that every explicitly-set tool override resolves (a path exists and is executable; a bare name is found on PATH). Path-valued overrides are normalized against baseDir first, so a relative wrapper is validated at the exact location it will later be executed from. Unset fields are skipped so defaults keep PATH-lookup semantics.
type TrackerConfig ¶ added in v0.68.7
type TrackerConfig struct {
Provider string `toml:"provider"` // "github" (v1); "" defaults to github
Repo string `toml:"repo"` // resolves the tracker + is the spawn repo (required)
ActiveState string `toml:"active_state"` // open | closed | all (default open)
ActiveLabels []string `toml:"active_labels"` // active iff the issue has one of these (empty = any state-matching issue)
Assignee string `toml:"assignee"` // optional tracker assignee filter (e.g. "@me")
Grace string `toml:"grace"` // inactive this long before reaping; default 5m
MaxConcurrent int `toml:"max_concurrent"` // cap on live tracker sessions (0 = unlimited)
Reap string `toml:"reap"` // stop | delete | none (default stop)
Limit int `toml:"limit"` // max issues fetched per poll (default 50)
}
TrackerConfig configures a tracker action's poll + reconcile behaviour. The spawned sessions' agent/model/prompt come from the enclosing ActionConfig; this block is the tracker-specific part. See docs/design/2026-07-16-tracker-poll-action.md.
func (TrackerConfig) ActiveStateOr ¶ added in v0.68.7
func (t TrackerConfig) ActiveStateOr() string
ActiveStateOr returns the configured active state, defaulting to open.
func (TrackerConfig) GraceDuration ¶ added in v0.68.7
func (t TrackerConfig) GraceDuration() time.Duration
GraceDuration returns the reap grace window, defaulting to 5m.
func (TrackerConfig) LimitOr ¶ added in v0.68.7
func (t TrackerConfig) LimitOr() int
LimitOr returns the per-poll issue fetch cap, defaulting to 50.
func (TrackerConfig) ProviderOr ¶ added in v0.68.7
func (t TrackerConfig) ProviderOr() string
ProviderOr returns the configured provider, defaulting to github.
func (TrackerConfig) ReapMode ¶ added in v0.68.7
func (t TrackerConfig) ReapMode() string
ReapMode returns the configured reap policy, defaulting to stop.
func (TrackerConfig) RepoPath ¶ added in v0.68.7
func (t TrackerConfig) RepoPath() string
RepoPath returns the tracker repo canonicalised the same way ActionConfig.RepoPath treats a repo (see that method). Empty when unset.
type TranscriptConfig ¶ added in v0.69.1
type TranscriptConfig struct {
// MaxContextBytes is the approximate size budget for the rendered migration/
// fork context document; older turns are elided to fit. 0/negative uses
// TranscriptMaxContextBytesDefault.
MaxContextBytes int `toml:"max_context_bytes"`
// MaxToolOutputBytes caps each rendered tool-output block. 0/negative uses
// TranscriptMaxToolOutputBytesDefault.
MaxToolOutputBytes int `toml:"max_tool_output_bytes"`
// MaxLineBytes is the scanner buffer cap for a single transcript line while
// reading turns or summing usage (large tool outputs / base64 exceed the
// 64KiB default). 0/negative uses TranscriptMaxLineBytesDefault.
MaxLineBytes int `toml:"max_line_bytes"`
// MaxMetadataLineBytes is the scanner buffer cap for the small metadata-only
// scans (Codex rollout cwd / session-id lookup). 0/negative uses
// TranscriptMaxMetadataBytesDefault.
MaxMetadataLineBytes int `toml:"max_metadata_line_bytes"`
}
TranscriptConfig is the [transcript] block tuning the on-disk agent-transcript reader and renderer used by migration and fork (issue #1250). Every field is optional: a zero/non-positive value falls back to the matching default.
func (TranscriptConfig) MaxContextBytesOrDefault ¶ added in v0.69.1
func (t TranscriptConfig) MaxContextBytesOrDefault() int
MaxContextBytesOrDefault returns the rendered-context byte budget, or the default when unset or non-positive.
func (TranscriptConfig) MaxLineBytesOrDefault ¶ added in v0.69.1
func (t TranscriptConfig) MaxLineBytesOrDefault() int
MaxLineBytesOrDefault returns the transcript-line scanner cap, or the default when unset or non-positive.
func (TranscriptConfig) MaxMetadataLineBytesOrDefault ¶ added in v0.69.1
func (t TranscriptConfig) MaxMetadataLineBytesOrDefault() int
MaxMetadataLineBytesOrDefault returns the metadata-scan scanner cap, or the default when unset or non-positive.
func (TranscriptConfig) MaxToolOutputBytesOrDefault ¶ added in v0.69.1
func (t TranscriptConfig) MaxToolOutputBytesOrDefault() int
MaxToolOutputBytesOrDefault returns the per-tool-output cap, or the default when unset or non-positive.
type TriggerConfig ¶ added in v0.67.0
type TriggerConfig struct {
Name string `toml:"name"`
Enabled *bool `toml:"enabled"` // nil => default true; explicit false disables
Schedule *ScheduleConfig `toml:"schedule"` // time-driven source
Watch *WatchConfig `toml:"watch"` // file-event source
GCX *GCXConfig `toml:"gcx"` // Grafana Cloud event source
Completion *CompletionConfig `toml:"completion"` // scenario todo-completion edge
Action ActionConfig `toml:"action"`
Policy TriggerPolicy `toml:"policy"`
}
TriggerConfig is one [[trigger]] block. A trigger is (source) -> (action): exactly one of Schedule (#592), Watch (#593), GCX, or Completion is the source, and Action is what runs. Everything below the source line is shared between the source kinds. See docs/design/2026-07-11-triggers-design.md.
func (TriggerConfig) IsCompletion ¶ added in v0.69.2
func (t TriggerConfig) IsCompletion() bool
func (TriggerConfig) IsGCX ¶ added in v0.69.2
func (t TriggerConfig) IsGCX() bool
func (TriggerConfig) IsSchedule ¶ added in v0.67.0
func (t TriggerConfig) IsSchedule() bool
IsSchedule, IsWatch, IsGCX, and IsCompletion report the source kind.
func (TriggerConfig) IsWatch ¶ added in v0.67.0
func (t TriggerConfig) IsWatch() bool
func (TriggerConfig) TriggerEnabled ¶ added in v0.67.0
func (t TriggerConfig) TriggerEnabled() bool
TriggerEnabled reports whether the trigger is enabled (nil => true).
type TriggerPolicy ¶ added in v0.67.0
type TriggerPolicy struct {
CatchUp bool `toml:"catch_up"` // default false: never backfill missed fires
Overlap string `toml:"overlap"` // "" or "skip" (default) | "allow" | "queue"(v2)
RateLimit string `toml:"rate_limit"` // "N/duration"; default "5/30m"
}
TriggerPolicy controls missed-run / overlap / rate-limit behaviour.
func (TriggerPolicy) OverlapMode ¶ added in v0.67.0
func (p TriggerPolicy) OverlapMode() string
OverlapMode returns the effective overlap policy (empty => skip).
func (TriggerPolicy) RateLimitParsed ¶ added in v0.67.0
func (p TriggerPolicy) RateLimitParsed() (int, time.Duration)
RateLimitParsed parses "N/duration" (e.g. "5/30m"), defaulting to 5 per 30m.
type TriggerVars ¶ added in v0.67.0
type TriggerVars struct {
Name string // trigger name
Date string // e.g. 2026-07-11
Datetime string // RFC3339
FireTime string // scheduled/observed fire instant (RFC3339)
SessionName string // watch source: the bound session
WorktreePath string // watch source: the bound session's worktree
ChangedFiles string // watch source: comma-separated changed paths (or "")
ChangeCount string // watch source: number of changed paths
ScenarioID string // completion source: owning scenario ID
ScenarioName string // completion source: owning scenario name
CompletionEpoch string // completion source: monotonically increasing epoch
// Tracker action: the issue a spawned session is seeded from. These are known
// template tokens (they live in this shared struct), so they expand to the
// empty string — not an error — outside a tracker prompt; a genuinely unknown
// token still errors.
IssueNumber string // e.g. "643"
IssueTitle string
IssueBody string
IssueURL string
IssueLabels string // comma-separated label names (or "")
// GCX source: stable, structured event metadata. Raw alert title, labels,
// annotations, and subject are deliberately excluded because external alert
// text is untrusted input to an autonomous agent.
GCXEventID string
GCXEventKind string
GCXEventState string
GCXEventURL string
GCXTeamID string
GCXIntegrationID string
GCXStartedAt string
}
TriggerVars is the variable set available to trigger delivery/message templates. It is deliberately separate from TemplateVars (which is a fixed struct for agent-arg expansion) — trigger templates have their own tokens and must not silently accept agent-arg names. Like Expand, ExpandTrigger errors on an unknown {token}.
type TriggersAdvancedConfig ¶ added in v0.69.1
type TriggersAdvancedConfig struct {
// SchedulerTick is the trigger scheduler loop cadence. Cron granularity is one
// minute, so this only bounds sub-minute "every" intervals and dispatch
// latency. Default 1s. Applied when the scheduler loop starts.
SchedulerTick string `toml:"scheduler_tick"`
// RunHistoryMax caps how many past runs each trigger retains in its persisted
// history. Default 20.
RunHistoryMax int `toml:"run_history_max"`
// WatchReconcileInterval is how often file-watch bindings are reconciled
// against live sessions (creating, tearing down, and retrying degraded
// bindings). Default 2s. Applied when the file-watch loop starts.
WatchReconcileInterval string `toml:"watch_reconcile_interval"`
// WatchRetryBaseBackoff is the delay before the first retry of a degraded
// file-watch binding (e.g. one that hit fs.inotify.max_user_watches).
// Subsequent retries back off exponentially from here. Default 5s.
WatchRetryBaseBackoff string `toml:"watch_retry_base_backoff"`
// WatchRetryMaxBackoff caps the exponential degraded-binding backoff so a
// persistently degraded binding keeps retrying periodically. Default 5m.
WatchRetryMaxBackoff string `toml:"watch_retry_max_backoff"`
// WatchBuiltinIgnores is the daemon-wide set of directories/patterns never
// watched by any file-watch trigger (on top of git ignore rules and per-trigger
// watch.ignore). Omitting the key uses DefaultWatchBuiltinIgnores; an explicit
// empty list ([]) keeps only the mandatory ignores. ".git"/".git/" are always
// ignored regardless of this list (a watched .git churns constantly and creates
// a feedback loop).
WatchBuiltinIgnores []string `toml:"watch_builtin_ignores"`
// CommandOutputCap truncates a command action's captured output to this many
// bytes before delivery, bounding notification size. Default 4096.
CommandOutputCap int `toml:"command_output_cap"`
}
TriggersAdvancedConfig carries the advanced tuning for the trigger scheduler and the file-watch runtime. These were formerly hard-coded policy literals in the daemon (internal/daemon/trigger.go, filewatch.go, trigger_actions.go); they are surfaced here so an operator can tune scheduler latency, file-watch reconcile cadence, degraded-binding retry backoff, the always-ignored directory set, and the command-output cap without a rebuild. Every field is optional: an unset (zero/empty) value resolves to the documented default through the TriggersRuntime accessors, so leaving [triggers.advanced] out is a no-op.
type TriggersRuntime ¶ added in v0.67.0
type TriggersRuntime struct {
MaxConcurrent int `toml:"max_concurrent"` // default 4
// Advanced holds the low-level scheduler and file-watch tuning knobs (loop
// cadence, run-history retention, degraded-binding backoff, the daemon-wide
// watch ignore list, and the command-output cap). Every field is optional and
// falls back to the historical default via the accessors below, so a config
// that omits [triggers.advanced] behaves exactly as before. Expose these only
// for operators who need to trade off detection latency, filesystem-watch
// load, and notification size — the defaults suit ordinary use.
Advanced TriggersAdvancedConfig `toml:"advanced"`
}
TriggersRuntime holds daemon-wide trigger settings ([triggers] table, distinct from the [[trigger]] array).
func (TriggersRuntime) CommandOutputCap ¶ added in v0.69.1
func (r TriggersRuntime) CommandOutputCap() int
CommandOutputCap is the command-action output truncation cap in bytes. Default 4096.
func (TriggersRuntime) MaxConcurrentOr ¶ added in v0.67.0
func (r TriggersRuntime) MaxConcurrentOr() int
MaxConcurrentOr returns the daemon-wide concurrency cap, defaulting to 4.
func (TriggersRuntime) RunHistoryMax ¶ added in v0.69.1
func (r TriggersRuntime) RunHistoryMax() int
RunHistoryMax is the per-trigger retained run-history length. Default 20.
func (TriggersRuntime) SchedulerTickDuration ¶ added in v0.69.1
func (r TriggersRuntime) SchedulerTickDuration() time.Duration
SchedulerTickDuration is the trigger scheduler loop cadence. Default 1s; an unset, unparseable, or non-positive value uses the default (the scheduler feeds this straight to time.NewTicker, which panics on a non-positive interval).
func (TriggersRuntime) WatchBuiltinIgnores ¶ added in v0.69.1
func (r TriggersRuntime) WatchBuiltinIgnores() []string
WatchBuiltinIgnores returns the daemon-wide watch ignore list. An omitted key (nil) resolves to DefaultWatchBuiltinIgnores; an explicit empty list ([]) is honored as "only the mandatory ignores", so a nil slice and a present-empty slice are NOT conflated (issue #1309). The daemon additionally always ignores ".git"/".git/" regardless of this list. A fresh copy is returned so callers cannot mutate the shared default slice, and a present-empty list is returned as a non-nil slice so consumers can distinguish it from an omitted policy.
func (TriggersRuntime) WatchReconcileIntervalDuration ¶ added in v0.69.1
func (r TriggersRuntime) WatchReconcileIntervalDuration() time.Duration
WatchReconcileIntervalDuration is the file-watch binding reconcile cadence. Default 2s; an unset, unparseable, or non-positive value uses the default (the file watcher feeds this straight to time.NewTicker, which panics on a non-positive interval).
func (TriggersRuntime) WatchRetryBaseBackoffDuration ¶ added in v0.69.1
func (r TriggersRuntime) WatchRetryBaseBackoffDuration() time.Duration
WatchRetryBaseBackoffDuration is the first-retry delay for a degraded file-watch binding. An unset, unparseable, or non-positive value uses the 5s default. The resolved delay is capped by WatchRetryMaxBackoffDuration so the effective bounds remain coherent when a directly-constructed config sets base > max.
func (TriggersRuntime) WatchRetryMaxBackoffDuration ¶ added in v0.69.1
func (r TriggersRuntime) WatchRetryMaxBackoffDuration() time.Duration
WatchRetryMaxBackoffDuration caps the exponential degraded-binding backoff. An unset, unparseable, or non-positive value uses the 5m default.
type UnknownKey ¶ added in v0.66.0
type UnknownKey struct {
// Table is the dotted parent-table path, e.g. "agents.claude.sandbox".
// Empty for top-level keys.
Table string
// Name is the unrecognised leaf key, e.g. "read_dir".
Name string
// Suggestion is the closest known key in the same table, or "" if none is
// close enough to be worth a "did you mean".
Suggestion string
}
UnknownKey is a config key that graith's schema does not recognise. It is a diagnostic aid (surfaced by `gr doctor`), not a load error: the runtime load stays lenient so an older daemon won't refuse a config written for a newer graith, and a typo silently drops the key rather than bricking startup. See issue #720.
func UnknownKeys ¶ added in v0.66.0
func UnknownKeys(path string) ([]UnknownKey, error)
UnknownKeys parses the TOML at path and reports keys that don't map to any field in the Config schema — typos (read_dir vs read_dirs), keys under the wrong table, or options from a newer graith than this binary. Unknown keys are never returned as an error; the returned error is only for a missing, unreadable, or unparseable file.
func (UnknownKey) FullKey ¶ added in v0.66.0
func (u UnknownKey) FullKey() string
FullKey renders the key with its table prefix, e.g. "sandbox.read_dir".
type UpdatesConfig ¶ added in v0.69.1
type UpdatesConfig struct {
// Enabled turns the update check on. Defaults to true via the embedded
// default config; set false to disable all update-check network I/O.
Enabled bool `toml:"enabled"`
// Repository is the "owner/repo" whose latest release is queried. Empty uses
// the canonical d0ugal/graith repository.
Repository string `toml:"repository"`
// Interval is how often the check refreshes (cached between checks). Empty
// uses the 1h default; must parse as a duration.
Interval string `toml:"interval"`
// Timeout bounds the release HTTP request. Empty uses the 5s default; must
// parse as a duration.
Timeout string `toml:"timeout"`
}
UpdatesConfig is the [updates] block controlling the GitHub release check (issue #1253). It makes the previously hard-coded checker configurable for downstream forks, packaged/offline deployments, and users who don't want network update checks. Enabled defaults to true (set in the embedded default config) to preserve the historical opt-out behaviour; the remaining fields fall back to the version package defaults when empty.
func (UpdatesConfig) IntervalDuration ¶ added in v0.69.1
func (u UpdatesConfig) IntervalDuration() time.Duration
IntervalDuration returns the configured cache cadence, or 0 when unset/invalid so the version package applies its own default.
func (UpdatesConfig) TimeoutDuration ¶ added in v0.69.1
func (u UpdatesConfig) TimeoutDuration() time.Duration
TimeoutDuration returns the configured HTTP timeout, or 0 when unset/invalid so the version package applies its own default.
type WatchConfig ¶ added in v0.67.0
type WatchConfig struct {
Repo string `toml:"repo"` // bind to sessions on this repo
Role string `toml:"role"` // bind to sessions with this scenario role
Paths []string `toml:"paths"` // optional include globs (worktree-relative)
Ignore []string `toml:"ignore"` // extra ignore globs (added to built-ins + .gitignore)
Debounce string `toml:"debounce"` // quiet-window; default 30s
}
WatchConfig is the file-event source. It is a POLICY selector (repo/role), never a literal live session name in config. Binds to matching sessions as they are created.
func (WatchConfig) DebounceDuration ¶ added in v0.67.0
func (w WatchConfig) DebounceDuration() time.Duration
DebounceDuration returns the watch debounce, defaulting to 30s.
type Watcher ¶ added in v0.3.0
type Watcher struct {
// contains filtered or unexported fields
}
func NewWatcher ¶ added in v0.3.0
func NewWatcher(path string, onChange func(*Config) error, log *slog.Logger, debounce time.Duration) *Watcher
NewWatcher creates a config-file watcher. debounce is the quiet period after the last write before reloading; a non-positive value falls back to ConfigReloadDebounceDefault so callers can pass 0 to accept the default. An onChange error rejects the loaded generation and is logged as a reload failure rather than as a successful config reload.