config

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package config handles loading and validating Forge configuration from forge.yaml files and environment variable overrides.

Config resolution order (first found wins):

  1. --config flag (explicit path)
  2. ./forge.yaml (working directory)
  3. ~/.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

func ConfigFilePath(configFile string) string

ConfigFilePath returns the path of the config file that was loaded, or empty string if no file was found.

func Save

func Save(cfg *Config, path string) error

Save writes the config to the specified file path in YAML format. It uses yaml.Marshal with yaml struct tags so that every config field is persisted automatically — no new field can be silently dropped.

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"`
	// 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"`
}

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.

func Defaults

func Defaults() Config

Defaults returns a Config with sensible default values.

func Load

func Load(configFile string) (*Config, error)

Load reads the configuration from the given file path, or auto-discovers forge.yaml from the working directory or ~/.forge/config.yaml. Environment variables with the FORGE_ prefix override file values.

func (*Config) Validate

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

Validate checks the config for logical errors.

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"`
}

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) 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.

Jump to

Keyboard shortcuts

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