Documentation
¶
Overview ¶
Package config handles loading and validating Forge configuration from forge.yaml files and environment variable overrides.
Config resolution order (first found wins):
- --config flag (explicit path)
- ./forge.yaml (working directory)
- ~/.forge/config.yaml (user home)
Environment variables override file values with the FORGE_ prefix:
FORGE_SETTINGS_POLL_INTERVAL=60s FORGE_SETTINGS_MAX_TOTAL_SMITHS=4
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ConfigFilePath ¶
ConfigFilePath returns the path of the config file that was loaded, or empty string if no file was found.
Types ¶
type AnvilConfig ¶
type AnvilConfig struct {
Path string `mapstructure:"path" yaml:"path"`
MaxSmiths int `mapstructure:"max_smiths" yaml:"max_smiths"`
AutoDispatch string `mapstructure:"auto_dispatch" yaml:"auto_dispatch"`
AutoDispatchTag string `mapstructure:"auto_dispatch_tag" yaml:"auto_dispatch_tag,omitempty"`
AutoDispatchMinPriority int `mapstructure:"auto_dispatch_min_priority" yaml:"auto_dispatch_min_priority"`
// Platform specifies the VCS hosting platform for this anvil.
// Valid values: "github" (default), "gitlab", "gitea", "bitbucket", "azuredevops".
// Determines which VCS provider is used for PR operations.
Platform string `mapstructure:"platform" yaml:"platform,omitempty"`
// SchematicEnabled controls whether the Schematic pre-worker runs for
// beads in this anvil. When nil, the global setting is used. Set to
// a pointer to false to disable per-anvil.
SchematicEnabled *bool `mapstructure:"schematic_enabled" yaml:"schematic_enabled,omitempty"`
// GolangciLint controls whether golangci-lint runs as a Temper step
// for Go projects. When nil (default), golangci-lint runs if the
// binary is found on PATH. Set to a pointer to false to disable.
GolangciLint *bool `mapstructure:"golangci_lint" yaml:"golangci_lint,omitempty"`
// GoRaceDetection enables the Go race detector (-race flag) as a
// separate temper step for this anvil. When nil, the global setting
// is used. Default off since -race slows tests and increases memory.
GoRaceDetection *bool `mapstructure:"go_race_detection" yaml:"go_race_detection,omitempty"`
// DepcheckEnabled controls whether the depcheck monitor scans this
// anvil for outdated dependencies. When nil (default), depcheck runs
// as normal (opt-out). Set to false to skip this anvil entirely.
DepcheckEnabled *bool `mapstructure:"depcheck_enabled" yaml:"depcheck_enabled,omitempty"`
// QuestgiverEnabled controls whether the QuestGiver monitor runs
// quests for this anvil. When nil (default), the global setting is used.
// Set to false to skip this anvil entirely.
QuestgiverEnabled *bool `mapstructure:"questgiver_enabled" yaml:"questgiver_enabled,omitempty"`
// AutoMerge enables automatic merging of PRs when they reach the
// ready-to-merge state (CI passing, no conflicts, no unresolved
// threads, no pending reviews). External PRs (ext-*) are never
// auto-merged. Default: false.
AutoMerge bool `mapstructure:"auto_merge" yaml:"auto_merge,omitempty"`
// QuestgiverSetupCmd is a shell command to run before quest execution
// for this anvil (e.g. "podman compose up -d").
QuestgiverSetupCmd string `mapstructure:"questgiver_setup_cmd" yaml:"questgiver_setup_cmd,omitempty"`
// QuestgiverTeardownCmd is a shell command to run after quest execution
// for this anvil (e.g. "podman compose down").
QuestgiverTeardownCmd string `mapstructure:"questgiver_teardown_cmd" yaml:"questgiver_teardown_cmd,omitempty"`
}
AnvilConfig defines a registered repository (anvil).
type Config ¶
type Config struct {
Anvils map[string]AnvilConfig `mapstructure:"anvils" yaml:"anvils"`
Settings SettingsConfig `mapstructure:"settings" yaml:"settings"`
Notifications NotificationsConfig `mapstructure:"notifications" yaml:"notifications,omitempty"`
}
Config is the top-level configuration for The Forge.
type NotificationsConfig ¶
type NotificationsConfig struct {
// Legacy flat fields — kept for backward compatibility.
TeamsWebhookURL string `mapstructure:"teams_webhook_url" yaml:"teams_webhook_url,omitempty"`
Enabled bool `mapstructure:"enabled" yaml:"enabled"`
// Events to notify on. Empty = all. Options: pr_created, bead_failed, daily_cost, worker_done, bead_decomposed, release_published, pr_ready_to_merge.
Events []string `mapstructure:"events" yaml:"events,omitempty"`
// ReleaseWebhookURLs is a list of generic JSON webhook URLs that receive
// a release_published payload when 'forge notify release' is called.
// These receive a simple JSON object (not a Teams Adaptive Card) suitable
// for custom dashboards or other receivers.
ReleaseWebhookURLs []string `mapstructure:"release_webhook_urls" yaml:"release_webhook_urls,omitempty"`
// PRReadyWebhookURLs is a list of generic JSON webhook URLs that receive
// a pr_ready_to_merge payload when a PR enters ready-to-merge state.
// These receive a simple JSON object (not a Teams Adaptive Card) suitable
// for custom dashboards or other receivers.
PRReadyWebhookURLs []string `mapstructure:"pr_ready_webhook_urls" yaml:"pr_ready_webhook_urls,omitempty"`
// Teams holds the new nested Teams webhook configuration.
// If set, takes precedence over the legacy teams_webhook_url and events fields.
Teams TeamsNotificationConfig `mapstructure:"teams" yaml:"teams,omitempty"`
// Webhooks is a list of generic JSON webhook targets. Each target can filter
// events independently. Supported events: pr_created, worker_done, bead_failed,
// bead_decomposed, pr_ready_to_merge, release, daily_cost.
Webhooks []WebhookTargetConfig `mapstructure:"webhooks" yaml:"webhooks,omitempty"`
}
NotificationsConfig holds webhook and notification settings.
func (NotificationsConfig) ResolvedTeamsEvents ¶ added in v0.4.0
func (n NotificationsConfig) ResolvedTeamsEvents() []string
ResolvedTeamsEvents returns the effective Teams event filter. The new nested teams.events takes precedence over the legacy events field.
func (NotificationsConfig) ResolvedTeamsURL ¶ added in v0.4.0
func (n NotificationsConfig) ResolvedTeamsURL() string
ResolvedTeamsURL returns the effective Teams webhook URL. The new nested teams.webhook_url takes precedence over the legacy teams_webhook_url field.
type SettingsConfig ¶
type SettingsConfig struct {
PollInterval time.Duration `mapstructure:"poll_interval" yaml:"poll_interval"`
SmithTimeout time.Duration `mapstructure:"smith_timeout" yaml:"smith_timeout"`
MaxTotalSmiths int `mapstructure:"max_total_smiths" yaml:"max_total_smiths"`
MaxReviewAttempts int `mapstructure:"max_review_attempts" yaml:"max_review_attempts"`
// MaxPipelineIterations is the maximum number of Smith-Warden cycles
// in the initial pipeline loop before declaring failure. This controls
// how many times Smith can be asked to revise its implementation based
// on Temper or Warden feedback during a single bead run. Default: 5.
MaxPipelineIterations int `mapstructure:"max_pipeline_iterations" yaml:"max_pipeline_iterations"`
ClaudeFlags []string `mapstructure:"claude_flags" yaml:"claude_flags"`
// Providers is the ordered list of AI providers to try.
// Each entry is a Kind string ("claude", "gemini") or "kind:command" pair.
// When a provider signals a rate limit the next one in the list is tried.
// Defaults to ["claude", "gemini"] when empty.
Providers []string `mapstructure:"providers" yaml:"providers,omitempty"`
// RateLimitBackoff is how long dispatchBead waits after releasing a bead
// back to open when all providers are rate limited. During this window the
// bead slot stays reserved (activeBeads) so the poller does not
// immediately re-claim it. Defaults to 5 minutes.
RateLimitBackoff time.Duration `mapstructure:"rate_limit_backoff" yaml:"rate_limit_backoff"`
// SmithProviders is the ordered list of AI providers used specifically for
// dispatch pipeline (Smith + Warden + Schematic). When empty, Providers is
// used as fallback. This lets smiths run a more capable model (e.g.
// claude/claude-opus-4-6) while lifecycle workers (cifix, reviewfix) use a
// lighter model. Accepts the same "kind/model" format as Providers.
SmithProviders []string `mapstructure:"smith_providers" yaml:"smith_providers,omitempty"`
// SchematicEnabled enables the Schematic pre-worker globally. When true,
// beads that exceed the word threshold or carry the "decompose" tag are
// analysed before Smith starts. Default: false.
SchematicEnabled bool `mapstructure:"schematic_enabled" yaml:"schematic_enabled"`
// SchematicWordThreshold is the minimum word count in a bead description
// to trigger automatic schematic analysis. When this value is zero or
// unset, the daemon applies an effective default of 100.
SchematicWordThreshold int `mapstructure:"schematic_word_threshold" yaml:"schematic_word_threshold,omitempty"`
// BellowsInterval is how often the Bellows PR monitor polls GitHub for
// status changes on open PRs. Defaults to 2 minutes.
BellowsInterval time.Duration `mapstructure:"bellows_interval" yaml:"bellows_interval"`
// DailyCostLimit is the maximum estimated USD spend per calendar day.
// When the running total exceeds this value, auto-dispatch is paused until
// the next calendar day. Zero means no limit (default).
DailyCostLimit float64 `mapstructure:"daily_cost_limit" yaml:"daily_cost_limit,omitempty"`
// MaxCIFixAttempts is the maximum number of CI fix cycles per PR before
// the PR is considered exhausted. Default: 5.
MaxCIFixAttempts int `mapstructure:"max_ci_fix_attempts" yaml:"max_ci_fix_attempts"`
// MaxReviewFixAttempts is the maximum number of review fix cycles per PR
// before the PR is considered exhausted. Default: 5.
MaxReviewFixAttempts int `mapstructure:"max_review_fix_attempts" yaml:"max_review_fix_attempts"`
// MaxRebaseAttempts is the maximum number of conflict rebase attempts per
// PR before the PR is considered exhausted. Default: 3.
MaxRebaseAttempts int `mapstructure:"max_rebase_attempts" yaml:"max_rebase_attempts"`
// MergeStrategy controls how PRs are merged from the Hearth TUI.
// Valid values: "squash" (default), "merge", "rebase".
MergeStrategy string `mapstructure:"merge_strategy" yaml:"merge_strategy,omitempty"`
// StaleInterval is how long a worker's log file can go without being
// modified before the worker is marked as stalled. A value of 0 disables
// stale detection. Defaults to 5 minutes.
StaleInterval time.Duration `mapstructure:"stale_interval" yaml:"stale_interval"`
// DepcheckInterval is how often the dependency checker runs 'go list -m -u all'
// on Go anvils. A value of 0 disables depcheck. Defaults to 168h (weekly).
DepcheckInterval time.Duration `mapstructure:"depcheck_interval" yaml:"depcheck_interval,omitempty"`
// DepcheckTimeout is the maximum time allowed for a single 'go list -m -u all'
// invocation per anvil. Defaults to 5 minutes.
DepcheckTimeout time.Duration `mapstructure:"depcheck_timeout" yaml:"depcheck_timeout,omitempty"`
// VulncheckInterval is how often govulncheck runs on registered Go anvils.
// Set to 0 to disable scheduled scanning. Default: 24h (daily).
VulncheckInterval time.Duration `mapstructure:"vulncheck_interval" yaml:"vulncheck_interval,omitempty"`
// VulncheckTimeout is the maximum time allowed for a single govulncheck
// invocation per anvil (govulncheck downloads the vuln DB on first run).
// Defaults to 10 minutes.
VulncheckTimeout time.Duration `mapstructure:"vulncheck_timeout" yaml:"vulncheck_timeout,omitempty"`
// VulncheckEnabled controls whether vulnerability scanning is active.
// When false, scheduled scanning and "forge scan" are disabled regardless
// of VulncheckInterval. Default: true.
VulncheckEnabled *bool `mapstructure:"vulncheck_enabled" yaml:"vulncheck_enabled,omitempty"`
// GoRaceDetection enables the Go race detector (-race flag) as a
// separate temper step globally. Per-anvil settings override this.
// Default: false.
GoRaceDetection bool `mapstructure:"go_race_detection" yaml:"go_race_detection"`
// AutoLearnRules enables automatic learning of Warden review rules from
// Copilot comments when a PR is merged. Bellows will fetch Copilot review
// comments, distill them into rules via Claude, and save them to the
// anvil's .forge/warden-rules.yaml. Default: false.
AutoLearnRules bool `mapstructure:"auto_learn_rules" yaml:"auto_learn_rules"`
// CopilotDailyRequestLimit is the maximum number of weighted Copilot
// premium requests per calendar day. When the running total exceeds this
// value, the Copilot provider is skipped in the fallback chain (other
// providers are unaffected). Zero means no limit (default).
// Premium requests are weighted by model multiplier (e.g. opus 4.6 = 3x).
CopilotDailyRequestLimit int `mapstructure:"copilot_daily_request_limit" yaml:"copilot_daily_request_limit,omitempty"`
// CrucibleEnabled enables automatic Crucible orchestration for parent beads
// that have children (blocks other beads). When true, the daemon detects
// parent beads during polling and dispatches them through the Crucible
// instead of the normal pipeline. Default: false.
CrucibleEnabled bool `mapstructure:"crucible_enabled" yaml:"crucible_enabled"`
// AutoMergeCrucibleChildren controls whether child PRs targeting a Crucible
// feature branch are automatically merged (squash) after the pipeline
// succeeds. Default: true.
AutoMergeCrucibleChildren *bool `mapstructure:"auto_merge_crucible_children" yaml:"auto_merge_crucible_children,omitempty"`
// WardenModelOverride sets an alternative model for Copilot provider entries
// when running the Warden review stage. Non-Copilot providers are unaffected.
// Useful for routing review to a cheaper model (e.g. claude-haiku-4-5 at 0.33x
// premium) while keeping Smith on a stronger model. Empty = use provider default.
WardenModelOverride string `mapstructure:"warden_model_override" yaml:"warden_model_override,omitempty"`
// SchematicModelOverride sets an alternative model for Copilot provider entries
// when running the Schematic pre-analysis stage. Non-Copilot providers are
// unaffected. Empty = use provider default.
SchematicModelOverride string `mapstructure:"schematic_model_override" yaml:"schematic_model_override,omitempty"`
// CopilotSkipWardenSmallDiffs enables automatic Warden skip for small,
// low-risk diffs when the primary provider is Copilot. Saves one premium
// request for trivial changes (docs, tests, or ≤2 files under 100 lines).
// Default: false (opt-in).
CopilotSkipWardenSmallDiffs bool `mapstructure:"copilot_skip_warden_small_diffs" yaml:"copilot_skip_warden_small_diffs"`
// CopilotBatchCIFixes enables batching multiple CI failures into a single
// Smith invocation when the provider is Copilot. Saves premium requests
// when a PR has multiple failing checks. Default: false (opt-in).
CopilotBatchCIFixes bool `mapstructure:"copilot_batch_ci_fixes" yaml:"copilot_batch_ci_fixes"`
// CopilotBatchReviewFixes enables batching multiple review comments into a
// single Smith invocation when the provider is Copilot. Saves premium
// requests when a PR has multiple review comments. Default: false (opt-in).
CopilotBatchReviewFixes bool `mapstructure:"copilot_batch_review_fixes" yaml:"copilot_batch_review_fixes"`
// WardenFullRereview, when true, forces the Warden to do a full independent
// review on every iteration instead of a focused re-review that only checks
// whether prior feedback was addressed. Default: false (focused re-review).
WardenFullRereview bool `mapstructure:"warden_full_rereview" yaml:"warden_full_rereview"`
// CopilotCombinedSmithWarden embeds Warden review criteria into the Smith
// prompt so Smith self-reviews its own diff, eliminating the separate
// Warden request. A real Warden still runs for P0-P1 beads, when the
// self-review flags concerns, or via random sampling. Only effective when
// the primary provider is Copilot. Default: false (opt-in, high risk).
CopilotCombinedSmithWarden bool `mapstructure:"copilot_combined_smith_warden" yaml:"copilot_combined_smith_warden"`
// CopilotWardenSampleRate is the probability (0.0–1.0) that a real Warden
// review is spawned even when the self-review approves, for quality
// validation. Only used when CopilotCombinedSmithWarden is true.
// Default: 0.1 (10%).
CopilotWardenSampleRate float64 `mapstructure:"copilot_warden_sample_rate" yaml:"copilot_warden_sample_rate"`
// SmelterEnabled controls whether the Smelter background process is active.
// When true (default), the Smelter runs on a schedule defined by
// SmelterInterval. Set to false to disable.
SmelterEnabled *bool `mapstructure:"smelter_enabled" yaml:"smelter_enabled,omitempty"`
// SmelterInterval is how often the Smelter runs its background processing.
// Defaults to 8h. Set to 0 to disable scheduled runs.
SmelterInterval time.Duration `mapstructure:"smelter_interval" yaml:"smelter_interval,omitempty"`
// QuestgiverEnabled controls whether the QuestGiver monitor is active
// globally. When nil (default), QuestGiver is disabled. Set to true to
// enable scheduled quest execution.
QuestgiverEnabled *bool `mapstructure:"questgiver_enabled" yaml:"questgiver_enabled,omitempty"`
// QuestgiverInterval is how often the QuestGiver monitor polls anvils
// for quests to execute. Defaults to 24h (daily).
QuestgiverInterval time.Duration `mapstructure:"questgiver_interval" yaml:"questgiver_interval,omitempty"`
// AdventurerTimeout is the maximum time allowed for a single quest
// execution. Defaults to 5 minutes.
AdventurerTimeout time.Duration `mapstructure:"adventurer_timeout" yaml:"adventurer_timeout,omitempty"`
}
SettingsConfig holds global operational settings.
func (SettingsConfig) IsAutoMergeCrucibleChildren ¶
func (s SettingsConfig) IsAutoMergeCrucibleChildren() bool
IsAutoMergeCrucibleChildren returns true unless auto_merge_crucible_children is explicitly false. Defaults to true.
func (SettingsConfig) IsQuestgiverEnabled ¶ added in v0.9.0
func (s SettingsConfig) IsQuestgiverEnabled() bool
IsQuestgiverEnabled returns true only when questgiver_enabled is explicitly true. Defaults to false (nil = disabled).
func (SettingsConfig) IsSmelterEnabled ¶ added in v0.10.0
func (s SettingsConfig) IsSmelterEnabled() bool
IsSmelterEnabled returns true unless smelter_enabled is explicitly false. Defaults to true.
func (SettingsConfig) IsVulncheckEnabled ¶
func (s SettingsConfig) IsVulncheckEnabled() bool
IsVulncheckEnabled returns true unless vulncheck_enabled is explicitly false.
func (SettingsConfig) MarshalYAML ¶
func (s SettingsConfig) MarshalYAML() (interface{}, error)
MarshalYAML serialises SettingsConfig with time.Duration fields as human-readable strings (e.g. "30s", "5m0s") instead of nanosecond ints.
type TeamsNotificationConfig ¶ added in v0.4.0
type TeamsNotificationConfig struct {
WebhookURL string `mapstructure:"webhook_url" yaml:"webhook_url,omitempty"`
Events []string `mapstructure:"events" yaml:"events,omitempty"`
}
TeamsNotificationConfig holds configuration for the MS Teams webhook. Used in the new nested notifications.teams config structure.
type WebhookTargetConfig ¶ added in v0.4.0
type WebhookTargetConfig struct {
Name string `mapstructure:"name" yaml:"name"`
URL string `mapstructure:"url" yaml:"url"`
Events []string `mapstructure:"events" yaml:"events,omitempty"`
}
WebhookTargetConfig defines a single generic JSON webhook target. Each target receives a simple JSON payload (not an Adaptive Card) and can filter which events it receives.