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 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 ValidateIncludes(mainRepoPath string, includes []string) error
- func ValidateTriggerStructure(where string, t *TriggerConfig) []error
- type ActionConfig
- type Agent
- type Approvals
- type ApprovalsBuiltin
- type CodexOptions
- type Config
- type Delete
- type DeliverConfig
- type GitPullConfig
- type HeadlessConfig
- type InputConfig
- type Keybindings
- type LaunchConfig
- type MCPServerConfig
- type Messages
- type Notifications
- type OrchestratorConfig
- type OrchestratorSandboxConfig
- type Overlay
- type PRWatchConfig
- func (p PRWatchConfig) DebounceDuration() time.Duration
- func (p PRWatchConfig) MaxNotifications() int
- func (p PRWatchConfig) PollMergedDuration() time.Duration
- func (p PRWatchConfig) PollPendingDuration() time.Duration
- func (p PRWatchConfig) PollTerminalDuration() time.Duration
- func (p PRWatchConfig) TrustedAssociationSet() map[string]bool
- type PairRate
- type Paths
- type RemoteConfig
- type RepoConfig
- type SandboxConfig
- type SandboxNetworkConfig
- type ScheduleConfig
- type StatusBar
- type StatusConfig
- type TemplateVars
- type TodoConfig
- type TrackerConfig
- type TriggerConfig
- type TriggerPolicy
- type TriggerVars
- type TriggersRuntime
- type UnknownKey
- type WatchConfig
- type Watcher
Constants ¶
const ( LaunchMaxConcurrentDefault = 3 LaunchStartupTimeoutDefault = 3 * time.Minute LaunchSettleTimeoutDefault = 10 * time.Second )
Launch tuning defaults. MaxConcurrent defaults to 3 because the #1092 evidence showed ~4 concurrent startups completing fine while the 5th stalled.
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 ( NotifyPriorityLow = "low" NotifyPriorityNormal = "normal" NotifyPriorityHigh = "high" )
Notification priority levels for `gr notify`.
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 DefaultDeleteRetention = 24 * time.Hour
DefaultDeleteRetention is the soft-delete retention window used when [delete] retention is unset.
const DefaultNotifyMaxPerHour = 12
DefaultNotifyMaxPerHour is the rolling-hour cap on low/normal push notifications used when [notifications] max_per_hour is unset.
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 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 (
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 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.69.0
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 is byte-for-byte identical to the built-in defaults.
func EffectiveTOML ¶ added in v0.69.0
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.69.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 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.69.0
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 ValidateIncludes ¶ added in v0.69.0
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 ValidateTriggerStructure ¶ added in v0.69.0
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.69.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.69.0
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.69.0
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.69.0
func (a ActionConfig) Sandboxed() bool
Sandboxed reports whether a command action runs sandboxed (nil => true).
func (ActionConfig) SessionIdleTimeout ¶ added in v0.69.0
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.69.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"`
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"`
}
func (Agent) HeadlessCapableEnabled ¶ added in v0.69.0
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) PreTrustWorkspaceEnabled ¶ added in v0.48.0
func (Agent) PromptInjectionEnabled ¶ added in v0.32.0
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"`
}
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) 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.69.0
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.69.0
func (o CodexOptions) IsZero() bool
IsZero reports whether no Codex option is set.
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"`
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)
}
func LoadOrDefault ¶
func RedactSecrets ¶ added in v0.69.0
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 Delete ¶ added in v0.66.16
type Delete struct {
Retention string `toml:"retention"`
}
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.
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.69.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
}
DeliverConfig routes action output. All fields are templated at fire time.
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.69.0
type HeadlessConfig struct {
Experimental bool `toml:"experimental"`
Default bool `toml:"default"`
}
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.
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"`
}
type LaunchConfig ¶ added in v0.69.0
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"`
}
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.69.0
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) SettleTimeoutDuration ¶ added in v0.69.0
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) StartupTimeoutDuration ¶ added in v0.69.0
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.
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
func (Messages) MaxAgeDuration ¶ added in v0.3.0
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"`
}
func (Notifications) InQuietHours ¶ added in v0.69.0
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.69.0
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.69.0
func (n Notifications) NotifyBackendName() string
NotifyBackendName returns the effective push-notification backend, defaulting to "macos" when unset.
func (Notifications) QuietHoursConfigured ¶ added in v0.69.0
func (n Notifications) QuietHoursConfigured() bool
QuietHoursConfigured reports whether a quiet-hours window is fully set.
func (Notifications) Validate ¶ added in v0.69.0
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"`
}
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 OrchestratorSandboxConfig ¶ added in v0.46.0
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"`
}
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) DebounceDuration ¶ added in v0.59.0
func (p PRWatchConfig) DebounceDuration() time.Duration
DebounceDuration is the minimum cooldown between notifications to one session.
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) 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) TrustedAssociationSet ¶ added in v0.69.0
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).
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 (tsnet mode).
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 means no
// configured limit here (the daemon applies its own default).
PairRequestRate string `toml:"pair_request_rate"`
}
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) 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 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 ScheduleConfig ¶ added in v0.69.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 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
}
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) 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) 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).
type TrackerConfig ¶ added in v0.69.0
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.69.0
func (t TrackerConfig) ActiveStateOr() string
ActiveStateOr returns the configured active state, defaulting to open.
func (TrackerConfig) GraceDuration ¶ added in v0.69.0
func (t TrackerConfig) GraceDuration() time.Duration
GraceDuration returns the reap grace window, defaulting to 5m.
func (TrackerConfig) LimitOr ¶ added in v0.69.0
func (t TrackerConfig) LimitOr() int
LimitOr returns the per-poll issue fetch cap, defaulting to 50.
func (TrackerConfig) ProviderOr ¶ added in v0.69.0
func (t TrackerConfig) ProviderOr() string
ProviderOr returns the configured provider, defaulting to github.
func (TrackerConfig) ReapMode ¶ added in v0.69.0
func (t TrackerConfig) ReapMode() string
ReapMode returns the configured reap policy, defaulting to stop.
func (TrackerConfig) RepoPath ¶ added in v0.69.0
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 TriggerConfig ¶ added in v0.69.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
Action ActionConfig `toml:"action"`
Policy TriggerPolicy `toml:"policy"`
}
TriggerConfig is one [[trigger]] block. A trigger is (source) -> (action): exactly one of Schedule (#592) or Watch (#593) is the source, and Action is what runs. Everything below the source line is shared between the two source kinds. See docs/design/2026-07-11-triggers-design.md.
func (TriggerConfig) IsSchedule ¶ added in v0.69.0
func (t TriggerConfig) IsSchedule() bool
IsSchedule / IsWatch report the source kind.
func (TriggerConfig) IsWatch ¶ added in v0.69.0
func (t TriggerConfig) IsWatch() bool
func (TriggerConfig) TriggerEnabled ¶ added in v0.69.0
func (t TriggerConfig) TriggerEnabled() bool
TriggerEnabled reports whether the trigger is enabled (nil => true).
type TriggerPolicy ¶ added in v0.69.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.69.0
func (p TriggerPolicy) OverlapMode() string
OverlapMode returns the effective overlap policy (empty => skip).
func (TriggerPolicy) RateLimitParsed ¶ added in v0.69.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.69.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
// 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 "")
}
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 TriggersRuntime ¶ added in v0.69.0
type TriggersRuntime struct {
MaxConcurrent int `toml:"max_concurrent"` // default 4
}
TriggersRuntime holds daemon-wide trigger settings ([triggers] table, distinct from the [[trigger]] array).
func (TriggersRuntime) MaxConcurrentOr ¶ added in v0.69.0
func (r TriggersRuntime) MaxConcurrentOr() int
MaxConcurrentOr returns the daemon-wide concurrency cap, defaulting to 4.
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 WatchConfig ¶ added in v0.69.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.69.0
func (w WatchConfig) DebounceDuration() time.Duration
DebounceDuration returns the watch debounce, defaulting to 30s.