Documentation
¶
Overview ¶
Package config handles loading and resolution of team and user configuration.
Package config handles loading and resolution of team and user configuration.
Index ¶
- Constants
- func ArchiveDir(tc *TeamConfig) string
- func FindTeamConfigPath(startDir string) (string, error)
- func IsValidRole(role string) bool
- func KnownPresets() []string
- func ParseDuration(s string) (time.Duration, error)
- func UserConfigDir() string
- func UserConfigPath() string
- func ValidRoles() []string
- func WriteUserConfig(path string, cfg *UserConfig) error
- type AutoAdvanceConfig
- type BlockedConfig
- type BuildConfig
- type DashboardConfig
- type DeployConfig
- type Diagnostic
- type DoScope
- type EffectConfig
- type Environment
- type FastTrackConfig
- type GateConfig
- type IntakeConfig
- type IntakeSource
- type IntegrationsConfig
- type JiraConfig
- type LinkExistsGate
- type LintResult
- type NotifyEffect
- type Owners
- type PassiveAwarenessConfig
- type PipelineConfig
- func (p PipelineConfig) IsValidReversion(from, to string) bool
- func (p PipelineConfig) IsValidTransition(from, to string) bool
- func (p PipelineConfig) NextStage(current string) (string, bool)
- func (p PipelineConfig) RequiredStages() []StageConfig
- func (p PipelineConfig) StageByName(name string) *StageConfig
- func (p PipelineConfig) StageIndex(name string) int
- func (p PipelineConfig) StageNames() []string
- type PreferencesConfig
- type ProviderConfig
- type ResolvedConfig
- func (r *ResolvedConfig) AIDraftsEnabled() bool
- func (r *ResolvedConfig) AutoPushEnabled() bool
- func (r *ResolvedConfig) AutoPushPolicy() string
- func (r *ResolvedConfig) CanonicalHandle() string
- func (r *ResolvedConfig) CycleLabel() string
- func (r *ResolvedConfig) EffectiveAgentConfig() ProviderConfig
- func (r *ResolvedConfig) HasIntegration(category string) bool
- func (r *ResolvedConfig) IdentityForCategory(category string) string
- func (r *ResolvedConfig) IntegrationProvider(category string) string
- func (r *ResolvedConfig) OwnerRole(override string) string
- func (r *ResolvedConfig) Pipeline() PipelineConfig
- func (r *ResolvedConfig) ProviderHandle(provider string) string
- func (r *ResolvedConfig) TeamName() string
- func (r *ResolvedConfig) UserHandle() string
- func (r *ResolvedConfig) UserIdentities() []string
- func (r *ResolvedConfig) UserName() string
- type ReviewConfig
- type Severity
- type SpecsRepoConfig
- type StageConfig
- type StageDashboardConfig
- type StageReviewConfig
- type SyncConfig
- type TeamConfig
- type TransitionConfig
- type TransitionsConfig
- type UpdatePMEffect
- type UrgencyConfig
- type UserConfig
- type WarningConfig
- type WebhookEffect
Constants ¶
const ( // AutoPushAuto publishes local edits automatically (the default). AutoPushAuto = "auto" // AutoPushPrompt asks for confirmation before publishing on interactive // surfaces; async surfaces (TUI, MCP) treat it as AutoPushAuto. AutoPushPrompt = "prompt" // AutoPushOff preserves the manual model: edits stay local until the user // runs 'spec push'. AutoPushOff = "off" )
Auto-push policy values for SyncConfig.AutoPush. They govern whether a local mutation (an editor edit, a thread comment) is published to the specs repo without the user remembering to run 'spec push'.
const ( // BlockedScopeAll shows every blocked spec (default; back-compat). BlockedScopeAll = "all" // BlockedScopeInvolved shows blocked specs the viewer authors or is assigned. BlockedScopeInvolved = "involved" // BlockedScopeOwningRole shows blocked specs whose pre-block stage the // viewer's role owned. BlockedScopeOwningRole = "owning_role" )
Blocked scope constants govern which blocked specs appear in a viewer's BLOCKED section.
const ( MultiplexerTmux = "tmux" MultiplexerZellij = "zellij" MultiplexerWezterm = "wezterm" MultiplexerIterm2 = "iterm2" MultiplexerNone = "none" )
Multiplexer constants.
Variables ¶
This section is empty.
Functions ¶
func ArchiveDir ¶
func ArchiveDir(tc *TeamConfig) string
ArchiveDir returns the configured archive directory.
func FindTeamConfigPath ¶
FindTeamConfigPath searches for spec.config.yaml starting from dir, then up.
func KnownPresets ¶ added in v0.23.0
func KnownPresets() []string
KnownPresets returns the built-in pipeline preset names recognised by the linter.
func ParseDuration ¶ added in v0.30.0
ParseDuration parses a duration string with support for day ("d") and week ("w") units in addition to Go's standard units (ns, us, ms, s, m, h). Tokens may be combined, e.g. "1w2d", "5d", "30m", "48h". A bare "0" yields zero. Whitespace is trimmed and parsing is case-insensitive.
func UserConfigDir ¶
func UserConfigDir() string
UserConfigDir returns the path to the ~/.spec/ directory.
func UserConfigPath ¶
func UserConfigPath() string
UserConfigPath returns the path to ~/.spec/config.yaml.
func WriteUserConfig ¶
func WriteUserConfig(path string, cfg *UserConfig) error
WriteUserConfig writes a user config to disk.
Types ¶
type AutoAdvanceConfig ¶
type AutoAdvanceConfig struct {
// Enabled allows explicitly disabling auto-advance even if When is set.
Enabled *bool `yaml:"enabled,omitempty"`
// When is an expression that triggers auto-advance when true.
// Example: "prs.all_approved and prs.threads_resolved"
When string `yaml:"when,omitempty"`
// Notify lists targets to notify on auto-advance.
// Example: ["author", "next_owner"]
Notify []string `yaml:"notify,omitempty"`
// QuietHours prevents auto-advance during specified hours.
// Format: "HH:MM-HH:MM" in local timezone.
// Example: "22:00-08:00"
QuietHours string `yaml:"quiet_hours,omitempty"`
// RequireApproval requires a specific role to have approved (e.g., "tl").
RequireApproval string `yaml:"require_approval,omitempty"`
// ExcludeLabels prevents auto-advance for specs with these labels.
ExcludeLabels []string `yaml:"exclude_labels,omitempty"`
}
AutoAdvanceConfig configures automatic stage advancement.
func (*AutoAdvanceConfig) IsEnabled ¶
func (a *AutoAdvanceConfig) IsEnabled() bool
IsEnabled returns whether auto-advance is enabled. Defaults to true if When is set and Enabled is not explicitly false.
type BlockedConfig ¶ added in v0.22.1
type BlockedConfig struct {
// VisibleTo lists roles that may see the BLOCKED section. Empty = all roles.
VisibleTo []string `yaml:"visible_to,omitempty"`
// Scope filters which blocked specs appear: "all" (default), "involved",
// or "owning_role".
Scope string `yaml:"scope,omitempty"`
}
BlockedConfig configures the dashboard BLOCKED section.
func (BlockedConfig) EffectiveScope ¶ added in v0.22.1
func (b BlockedConfig) EffectiveScope() string
EffectiveScope returns the configured blocked scope, defaulting to "all".
func (BlockedConfig) RoleCanSee ¶ added in v0.22.1
func (b BlockedConfig) RoleCanSee(role string) bool
RoleCanSee reports whether a role may see the BLOCKED section at all. An empty VisibleTo list means every role can (back-compat).
type BuildConfig ¶ added in v0.16.0
type BuildConfig struct {
// MaxParallel bounds how many ready nodes the orchestrator fans out at
// once. Surfaced to the agent via the DAG resource. Defaults to 4.
MaxParallel int `yaml:"max_parallel,omitempty"`
// Router selects the skill-routing model handed to the build engine:
// "registry" (default) routes per-node from .agents/skills/registry.yaml;
// "none" routes nothing and lets the harness discover skills. Empty = default.
Router string `yaml:"router,omitempty"`
// Strategy selects the VCS/review workflow: "stacked-draft-pr" (default)
// stacks a draft PR per node; "none" keeps work on local branches with no
// finishing tools. Empty = default.
Strategy string `yaml:"strategy,omitempty"`
}
BuildConfig tunes the build engine's DAG orchestration.
func (BuildConfig) GetMaxParallel ¶ added in v0.16.0
func (b BuildConfig) GetMaxParallel() int
GetMaxParallel returns the configured fan-out bound or the default.
type DashboardConfig ¶
type DashboardConfig struct {
StaleThreshold string `yaml:"stale_threshold"`
RefreshTTL int `yaml:"refresh_ttl"`
Blocked BlockedConfig `yaml:"blocked,omitempty"`
Urgency UrgencyConfig `yaml:"urgency,omitempty"`
Review ReviewConfig `yaml:"review,omitempty"`
}
DashboardConfig defines dashboard behaviour.
func (DashboardConfig) EasingCurve ¶ added in v0.30.0
func (d DashboardConfig) EasingCurve() urgency.Curve
EasingCurve resolves the configured easing name to an urgency.Curve, defaulting to ease-in when unset or unrecognised.
func (DashboardConfig) ReviewWindow ¶ added in v0.30.0
func (d DashboardConfig) ReviewWindow() (window time.Duration, ok bool)
ReviewWindow parses the REVIEW staleness window. ok is false when no window is configured (empty, "none", "0", or unparseable), meaning REVIEW rows are never stale.
type DeployConfig ¶
type DeployConfig struct {
Provider string `yaml:"provider"`
Environments []Environment `yaml:"environments"`
}
DeployConfig holds deployment provider and environments.
type Diagnostic ¶ added in v0.23.0
type Diagnostic struct {
File string `json:"file"`
Line int `json:"line"`
Column int `json:"column,omitempty"`
Severity Severity `json:"severity"`
Field string `json:"field,omitempty"`
Message string `json:"message"`
Suggestion string `json:"suggestion,omitempty"`
}
Diagnostic is a single line-precise lint finding. Line and Column are 1-based; Column is 0 when only a line is known.
type DoScope ¶ added in v0.22.1
type DoScope string
DoScope controls who sees specs at a stage in their dashboard DO section.
const ( // DoScopeRole shows the spec to anyone whose role owns the stage. Default. DoScopeRole DoScope = "role" // DoScopeAssignee shows the spec to its assignee(s) only; unassigned specs // fall back to the whole owning role when the stage is claimable. DoScopeAssignee DoScope = "assignee" // DoScopeAuthor shows the spec to its author only. DoScopeAuthor DoScope = "author" // DoScopeNone hides the spec from DO entirely (pipeline view only). DoScopeNone DoScope = "none" )
type EffectConfig ¶
type EffectConfig struct {
// Notify sends a notification. Can be a string (target) or NotifyEffect.
Notify *NotifyEffect `yaml:"notify,omitempty"`
// Sync triggers document sync ("outbound" or "inbound").
Sync string `yaml:"sync,omitempty"`
// UpdatePM updates the PM tool (Jira, Linear, etc.).
UpdatePM *UpdatePMEffect `yaml:"update_pm,omitempty"`
// LogDecision adds an entry to the decision log.
LogDecision string `yaml:"log_decision,omitempty"`
// Increment increments a frontmatter counter (e.g., "revert_count").
Increment string `yaml:"increment,omitempty"`
// Webhook calls an external URL.
Webhook *WebhookEffect `yaml:"webhook,omitempty"`
// Archive moves the spec to archive/.
Archive bool `yaml:"archive,omitempty"`
// Trigger invokes a named workflow or action.
Trigger string `yaml:"trigger,omitempty"`
// When is an expression that must be true for this effect to run.
When string `yaml:"when,omitempty"`
}
EffectConfig defines a side effect for stage transitions.
type Environment ¶
type Environment struct {
Name string `yaml:"name"`
Auto bool `yaml:"auto"`
Gate string `yaml:"gate,omitempty"`
}
Environment defines a deployment target.
type FastTrackConfig ¶
type FastTrackConfig struct {
// Enabled allows fast-track bug fixes. Defaults to false.
Enabled bool `yaml:"enabled,omitempty"`
// AllowedRoles lists roles that can create fast-track specs.
// Defaults to ["engineer", "tl"].
AllowedRoles []string `yaml:"allowed_roles,omitempty"`
// MaxDuration is the maximum time before escalation (e.g., "2d", "48h").
// If exceeded, notifies TL and/or PM.
MaxDuration string `yaml:"max_duration,omitempty"`
// RequireLabels requires fast-track specs to have specific labels (e.g., ["bug", "hotfix"]).
RequireLabels []string `yaml:"require_labels,omitempty"`
}
FastTrackConfig configures the `spec fix` fast-track workflow.
func (*FastTrackConfig) GetAllowedRoles ¶
func (f *FastTrackConfig) GetAllowedRoles() []string
GetAllowedRoles returns allowed roles or default ["engineer", "tl"].
func (*FastTrackConfig) IsEnabled ¶
func (f *FastTrackConfig) IsEnabled() bool
IsEnabled returns whether fast-track is enabled.
func (*FastTrackConfig) IsRoleAllowed ¶
func (f *FastTrackConfig) IsRoleAllowed(role string) bool
IsRoleAllowed checks if a role can create fast-track specs.
type GateConfig ¶
type GateConfig struct {
// Simple gate types (mutually exclusive with Expr)
SectionNotEmpty string `yaml:"section_not_empty,omitempty"`
SectionComplete string `yaml:"section_complete,omitempty"` // Deprecated: use SectionNotEmpty
PRStackExists *bool `yaml:"pr_stack_exists,omitempty"` // Deprecated: use StepsExists
StepsExists *bool `yaml:"steps_exists,omitempty"` // Build plan has at least one step
PRsApproved *bool `yaml:"prs_approved,omitempty"`
ReviewApproved *bool `yaml:"review_approved,omitempty"` // Technical plan review is approved
Duration string `yaml:"duration,omitempty"`
LinkExists *LinkExistsGate `yaml:"link_exists,omitempty"`
// Expression gate
Expr string `yaml:"expr,omitempty"`
Message string `yaml:"message,omitempty"`
// Logical operators (contain nested gates)
All []GateConfig `yaml:"all,omitempty"`
Any []GateConfig `yaml:"any,omitempty"`
Not *GateConfig `yaml:"not,omitempty"`
}
GateConfig defines a gate condition for stage advancement.
func (GateConfig) GetSectionNotEmpty ¶
func (g GateConfig) GetSectionNotEmpty() string
GetSectionNotEmpty returns the section slug for section_not_empty or section_complete gates.
func (GateConfig) HasReviewApproved ¶
func (g GateConfig) HasReviewApproved() bool
HasReviewApproved returns true if ReviewApproved gate is set.
func (GateConfig) HasStepsExists ¶
func (g GateConfig) HasStepsExists() bool
HasStepsExists returns true if either StepsExists or legacy PRStackExists is set.
func (GateConfig) IsSimple ¶
func (g GateConfig) IsSimple() bool
IsSimple returns true if this is a simple (non-logical) gate.
func (GateConfig) Type ¶
func (g GateConfig) Type() string
Type returns the gate type as a string for display.
func (GateConfig) Value ¶
func (g GateConfig) Value() string
Value returns the gate's primary value as a string for display.
type IntakeConfig ¶
type IntakeConfig struct {
Sources []IntakeSource `yaml:"sources"`
}
IntakeConfig holds intake source definitions.
type IntakeSource ¶
type IntakeSource struct {
Provider string `yaml:"provider"`
AutoCreate bool `yaml:"auto_create"`
Filter string `yaml:"filter,omitempty"`
Channel string `yaml:"channel,omitempty"`
Trigger string `yaml:"trigger,omitempty"`
Token string `yaml:"token,omitempty"`
}
IntakeSource defines an external intake source.
type IntegrationsConfig ¶
type IntegrationsConfig struct {
Comms ProviderConfig `yaml:"comms"`
PM ProviderConfig `yaml:"pm"`
Docs ProviderConfig `yaml:"docs"`
Repo ProviderConfig `yaml:"repo"`
Agent ProviderConfig `yaml:"agent"`
AI ProviderConfig `yaml:"ai"`
Design ProviderConfig `yaml:"design"`
Deploy DeployConfig `yaml:"deploy"`
Intake IntakeConfig `yaml:"intake"`
}
IntegrationsConfig holds all integration provider configs.
type JiraConfig ¶ added in v0.22.1
type JiraConfig struct {
BaseURL string
Email string
Token string
ProjectKey string
// BoardID scopes board analytics; 0 means unset.
BoardID int
// TeamID is the Jira Team field value (Advanced Roadmaps / Plans).
TeamID string
EpicIssueType string
StoryIssueType string
// Fields maps logical field names (epic_name, team, sprint, story_points)
// to instance-specific custom-field ids (e.g. customfield_10011).
Fields map[string]string
// Labels are applied to every spec-created issue; Components likewise.
Labels []string
Components []string
// SyncStories opts into creating Jira stories from build steps.
SyncStories bool
// StatusMap maps spec pipeline stage names to Jira status names. A stage
// absent from the map is a no-op for status sync.
StatusMap map[string]string
RequestTimeout time.Duration
}
JiraConfig is the typed Jira PM configuration parsed from the generic ProviderConfig. It binds a spec workspace to a specific project, board, and team, and carries the custom-field ids and status map the integration needs to land issues where the board's analytics expect them.
Every field is explicit: custom-field ids vary per Jira instance and must never be guessed (see docs/JIRA_HARDENING_PLAN.md §P1).
func (JiraConfig) Field ¶ added in v0.22.1
func (j JiraConfig) Field(name string) string
Field returns the configured custom-field id for a logical name, or "".
func (JiraConfig) IsComplete ¶ added in v0.22.1
func (j JiraConfig) IsComplete() bool
IsComplete reports whether the minimum fields required to talk to Jira are present. Missing required fields degrade the integration to a noop.
func (JiraConfig) MappedStatus ¶ added in v0.22.1
func (j JiraConfig) MappedStatus(stage string) (string, bool)
MappedStatus returns the Jira status mapped to a spec stage and whether a mapping exists. Lookups are case-insensitive on the stage name.
type LinkExistsGate ¶
type LinkExistsGate struct {
Section string `yaml:"section"`
Type string `yaml:"type,omitempty"` // e.g., "figma", "github"
}
LinkExistsGate checks for a link in a specific section.
func (*LinkExistsGate) UnmarshalYAML ¶ added in v0.4.1
func (g *LinkExistsGate) UnmarshalYAML(unmarshal func(interface{}) error) error
UnmarshalYAML supports both string and object formats:
link_exists: pr # simple string
link_exists: { section: pr } # object form
link_exists: { section: pr, type: github }
type LintResult ¶ added in v0.23.0
type LintResult struct {
File string `json:"file"`
Diagnostics []Diagnostic `json:"diagnostics"`
}
LintResult is the full outcome of linting one config file.
func LintTeamConfigFile ¶ added in v0.23.0
func LintTeamConfigFile(path string) (LintResult, error)
LintTeamConfigFile reads and lints a team config file at path. A read or parse failure is itself returned as an error-severity diagnostic so the caller always gets a structured result.
func LintUserIdentitiesFile ¶ added in v0.25.0
func LintUserIdentitiesFile(path string, teamCfg *TeamConfig) (LintResult, error)
LintUserIdentitiesFile validates the per-provider identity map in a user config file against the providers a team config actually configures. It is advisory only — every finding is a warning, never an error — because a stale or mis-keyed identity degrades gracefully (the canonical handle stands in).
teamCfg may be nil (no joined team), in which case there is nothing to cross-reference and the result is empty.
func (LintResult) HasErrors ¶ added in v0.23.0
func (r LintResult) HasErrors() bool
HasErrors reports whether any diagnostic is an error (blocks exit 0).
type NotifyEffect ¶
type NotifyEffect struct {
// Target is who to notify (e.g., "next_owner", "tl", "#channel", "@user").
Target string `yaml:"target,omitempty"`
// Targets allows multiple notification targets.
Targets []string `yaml:"targets,omitempty"`
// Channel overrides the default channel.
Channel string `yaml:"channel,omitempty"`
// Template is the notification template name.
Template string `yaml:"template,omitempty"`
}
NotifyEffect configures a notification.
func (*NotifyEffect) UnmarshalYAML ¶
func (n *NotifyEffect) UnmarshalYAML(unmarshal func(interface{}) error) error
UnmarshalYAML allows notify to be a string or object.
type Owners ¶
type Owners []string
Owners represents one or more owner roles for a pipeline stage. In YAML, it can be specified as a single string or an array:
owner: pm # single owner owner: [pm, tl] # multiple owners
func (*Owners) UnmarshalYAML ¶
UnmarshalYAML allows owner to be a string or array in YAML.
type PassiveAwarenessConfig ¶
type PassiveAwarenessConfig struct {
// Show whitelists item types to display. If empty, shows all.
// Valid types: review_requests, spec_owned, mentions, triage, fyi, blocked
Show []string `yaml:"show,omitempty"`
// Hide blacklists item types to suppress.
Hide []string `yaml:"hide,omitempty"`
// DuringBuild shows awareness during `spec do` and `spec build`.
// Defaults to false to avoid interrupting flow state.
DuringBuild bool `yaml:"during_build,omitempty"`
// DismissDuration is how long dismissed items stay hidden.
// Defaults to "2h". Valid formats: "30m", "2h", "1d".
DismissDuration string `yaml:"dismiss_duration,omitempty"`
}
PassiveAwarenessConfig controls what pending items are shown in the awareness line on every spec command.
type PipelineConfig ¶
type PipelineConfig struct {
// Preset is the name of a built-in pipeline preset (e.g., "minimal", "product").
// If set, the preset's stages are used as the base configuration.
Preset string `yaml:"preset,omitempty"`
// Skip lists stage names to remove from the preset.
// Only meaningful when Preset is set.
Skip []string `yaml:"skip,omitempty"`
// Stages defines the pipeline stages. When Preset is set, these override
// or extend the preset's stages. When Preset is empty, these are the
// complete stage definitions.
Stages []StageConfig `yaml:"stages,omitempty"`
}
PipelineConfig defines the configurable pipeline stages.
func DefaultPipeline ¶
func DefaultPipeline() PipelineConfig
DefaultPipeline returns the default pipeline configuration when none is specified. This is the "product" preset - a full lifecycle pipeline.
func EffectivePipeline ¶
func EffectivePipeline(tc *TeamConfig) PipelineConfig
EffectivePipeline returns the pipeline from team config, or default if empty.
func (PipelineConfig) IsValidReversion ¶
func (p PipelineConfig) IsValidReversion(from, to string) bool
IsValidReversion returns true if reverting from `from` to `to` is valid (i.e., `to` comes before `from` in the pipeline).
func (PipelineConfig) IsValidTransition ¶
func (p PipelineConfig) IsValidTransition(from, to string) bool
IsValidTransition returns true if transitioning from `from` to `to` is valid (i.e., `to` comes after `from` in the pipeline).
func (PipelineConfig) NextStage ¶
func (p PipelineConfig) NextStage(current string) (string, bool)
NextStage returns the next stage after the given one.
func (PipelineConfig) RequiredStages ¶
func (p PipelineConfig) RequiredStages() []StageConfig
RequiredStages returns non-optional stages.
func (PipelineConfig) StageByName ¶
func (p PipelineConfig) StageByName(name string) *StageConfig
StageByName returns the stage config with the given name, or nil.
func (PipelineConfig) StageIndex ¶
func (p PipelineConfig) StageIndex(name string) int
StageIndex returns the index of the stage with the given name, or -1.
func (PipelineConfig) StageNames ¶
func (p PipelineConfig) StageNames() []string
StageNames returns the names of all stages in order.
type PreferencesConfig ¶
type PreferencesConfig struct {
Editor string `yaml:"editor"`
DashboardSections []string `yaml:"dashboard_sections"`
StandupAutoPost bool `yaml:"standup_auto_post"`
AIDrafts *bool `yaml:"ai_drafts,omitempty"`
// Theme sets the TUI colour theme.
// Valid values: auto (default), catppuccin-mocha, catppuccin-latte,
// catppuccin-macchiato, catppuccin-frappe, gruvbox-dark, dracula,
// tokyo-night, nord, solarized-dark, solarized-light, rose-pine,
// kanagawa, everforest-dark, everforest-light, github-dark, github-light,
// ayu-mirage, ayu-light, modus-vivendi, modus-operandi, graphite.
Theme string `yaml:"theme,omitempty"`
// RefreshInterval sets the TUI auto-refresh period (e.g. "30s", "1m").
// Defaults to 30s.
RefreshInterval string `yaml:"refresh_interval,omitempty"`
// Mouse enables mouse support in the TUI (click tabs, click items).
// Defaults to false.
Mouse bool `yaml:"mouse,omitempty"`
// Multiplexer specifies the terminal multiplexer for cross-repo navigation.
// Valid values: tmux, zellij, wezterm, iterm2, none
// If empty or "none", falls back to manual navigation prompts.
Multiplexer string `yaml:"multiplexer,omitempty"`
// AutoPull automatically pulls stale specs when running `spec do`.
// If false, prompts the user before pulling.
AutoPull bool `yaml:"auto_pull,omitempty"`
// Defaults to true. Set to false for manual navigation.
AutoNavigate *bool `yaml:"auto_navigate,omitempty"`
// PassiveAwareness configures the passive awareness line shown on commands.
PassiveAwareness *PassiveAwarenessConfig `yaml:"passive_awareness,omitempty"`
}
PreferencesConfig holds personal preferences.
func (PreferencesConfig) AIDraftsEnabled ¶
func (p PreferencesConfig) AIDraftsEnabled() bool
AIDraftsEnabled returns whether AI drafts are enabled. Defaults to true if not explicitly set.
func (PreferencesConfig) AutoNavigateEnabled ¶
func (p PreferencesConfig) AutoNavigateEnabled() bool
AutoNavigateEnabled returns whether auto-navigation to new repos is enabled. Defaults to true if not explicitly set.
func (PreferencesConfig) GetDismissDuration ¶
func (p PreferencesConfig) GetDismissDuration() string
GetDismissDuration returns the dismiss duration or the default "2h".
func (PreferencesConfig) ShowPassiveAwarenessDuringBuild ¶
func (p PreferencesConfig) ShowPassiveAwarenessDuringBuild() bool
ShowPassiveAwarenessDuringBuild returns whether to show awareness during builds.
type ProviderConfig ¶
type ProviderConfig struct {
Provider string `yaml:"provider"`
Extra map[string]string `yaml:"-"`
// contains filtered or unexported fields
}
ProviderConfig is a generic integration config with a provider name and extra fields.
func (ProviderConfig) Get ¶
func (p ProviderConfig) Get(key string) string
Get returns an extra config value by key.
func (ProviderConfig) Jira ¶ added in v0.22.1
func (p ProviderConfig) Jira() JiraConfig
Jira parses the generic PM ProviderConfig into a typed JiraConfig. Scalar keys come from the flattened Extra map; nested keys (fields, status_map, labels, components) are read from the preserved raw YAML so structured values survive (Extra stringifies them).
func (ProviderConfig) MarshalYAML ¶ added in v0.15.0
func (p ProviderConfig) MarshalYAML() (interface{}, error)
MarshalYAML emits provider plus all extra settings so a ProviderConfig round-trips through WriteUserConfig (e.g. a TUI settings save) without dropping keys like `command` or `skill`, which live in Extra (yaml:"-").
func (*ProviderConfig) UnmarshalYAML ¶
func (p *ProviderConfig) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML captures all keys into raw and extracts provider + extras.
type ResolvedConfig ¶
type ResolvedConfig struct {
Team *TeamConfig
User *UserConfig
// TeamConfigPath is the path to the team config file, if found.
TeamConfigPath string
// UserConfigPath is the path to the user config file.
UserConfigPath string
// SpecsRepoDir is the local path to the specs/ sub-directory within
// the specs repo clone. All spec, triage, and archive content lives here.
SpecsRepoDir string
}
ResolvedConfig holds the fully resolved team + user configuration.
func Resolve ¶
func Resolve() (*ResolvedConfig, error)
Resolve loads the full configuration from all sources. Resolution chain: cwd → repo root → specs repo clone → user config.
func (*ResolvedConfig) AIDraftsEnabled ¶
func (r *ResolvedConfig) AIDraftsEnabled() bool
AIDraftsEnabled returns whether AI drafting is enabled for the user.
func (*ResolvedConfig) AutoPushEnabled ¶ added in v0.26.0
func (r *ResolvedConfig) AutoPushEnabled() bool
AutoPushEnabled reports whether automatic publishing is active for async surfaces (TUI, MCP). Only AutoPushOff disables it; AutoPushPrompt is treated as enabled because those surfaces cannot prompt.
func (*ResolvedConfig) AutoPushPolicy ¶ added in v0.26.0
func (r *ResolvedConfig) AutoPushPolicy() string
AutoPushPolicy returns the effective auto-push policy, defaulting to AutoPushAuto when unset or no team config is present.
func (*ResolvedConfig) CanonicalHandle ¶ added in v0.25.0
func (r *ResolvedConfig) CanonicalHandle() string
CanonicalHandle returns the user's spec-internal identity token, falling back to the display name when no handle is configured.
func (*ResolvedConfig) CycleLabel ¶
func (r *ResolvedConfig) CycleLabel() string
CycleLabel returns the current cycle label.
func (*ResolvedConfig) EffectiveAgentConfig ¶ added in v0.15.0
func (r *ResolvedConfig) EffectiveAgentConfig() ProviderConfig
EffectiveAgentConfig returns the coding-agent provider config to use, preferring the per-user override (~/.spec/config.yaml `agent:`) when its provider is set, then the team default (integrations.agent), then empty. This lets engineers pick their own harness while keeping a shared baseline.
func (*ResolvedConfig) HasIntegration ¶
func (r *ResolvedConfig) HasIntegration(category string) bool
HasIntegration checks if a specific integration category has a non-empty provider.
func (*ResolvedConfig) IdentityForCategory ¶ added in v0.25.0
func (r *ResolvedConfig) IdentityForCategory(category string) string
IdentityForCategory resolves the handle to use for an integration category ("repo", "comms", "pm", "docs", "agent", "ai", "design", "deploy"): it maps the category to the team's configured provider, then resolves that provider's handle. Falls back to the canonical handle when the category has no provider or no mapping exists.
func (*ResolvedConfig) IntegrationProvider ¶ added in v0.25.0
func (r *ResolvedConfig) IntegrationProvider(category string) string
IntegrationProvider returns the team's configured provider name for an integration category (e.g. "repo" -> "github"), or "" when no team config or category is set.
func (*ResolvedConfig) OwnerRole ¶
func (r *ResolvedConfig) OwnerRole(override string) string
OwnerRole returns the user's owner role, with optional override.
func (*ResolvedConfig) Pipeline ¶
func (r *ResolvedConfig) Pipeline() PipelineConfig
Pipeline returns the effective pipeline config.
func (*ResolvedConfig) ProviderHandle ¶ added in v0.25.0
func (r *ResolvedConfig) ProviderHandle(provider string) string
ProviderHandle returns the user's handle for a named integration provider (e.g. "github", "slack"), falling back to the canonical handle when the provider is unmapped. An empty or "none" provider yields the canonical handle.
func (*ResolvedConfig) TeamName ¶
func (r *ResolvedConfig) TeamName() string
TeamName returns the team name.
func (*ResolvedConfig) UserHandle ¶
func (r *ResolvedConfig) UserHandle() string
UserHandle returns the configured spec-canonical handle. Retained as an alias of CanonicalHandle for callers that predate per-integration identity resolution; spec-internal identity (frontmatter, threads) uses this.
func (*ResolvedConfig) UserIdentities ¶ added in v0.25.0
func (r *ResolvedConfig) UserIdentities() []string
UserIdentities returns every identity the user is known by — the canonical handle, the display name, and every per-provider handle — de-duplicated. Identity-matching callers (dashboard scope, awareness) use this so a spec authored or assigned under any of the user's handles is recognised as theirs.
func (*ResolvedConfig) UserName ¶
func (r *ResolvedConfig) UserName() string
UserName returns the configured user name.
type ReviewConfig ¶ added in v0.30.0
type ReviewConfig struct {
// StaleAfter is the review-age window for the time-urgency gradient on
// REVIEW rows, measured from when the PR was opened. Accepts m/h/d/w units
// (e.g. "4h", "2d"). Empty, "none", or "0" (the default) means review rows
// are never coloured — the gradient is opt-in, with no global fallback.
StaleAfter string `yaml:"stale_after,omitempty"`
}
ReviewConfig tunes the REVIEW section of the dashboard.
type SpecsRepoConfig ¶
type SpecsRepoConfig struct {
Provider string `yaml:"provider"`
Owner string `yaml:"owner"`
Repo string `yaml:"repo"`
Branch string `yaml:"branch"`
Token string `yaml:"token"`
}
SpecsRepoConfig defines the specs repository location.
type StageConfig ¶
type StageConfig struct {
// Name is the stage identifier (lowercase, underscores allowed).
Name string `yaml:"name"`
// Owner is the role(s) that own this stage. Can be a single role
// or an array of roles in YAML.
Owner Owners `yaml:"owner,omitempty"`
// Dashboard controls how this stage's specs surface in the DO section.
Dashboard StageDashboardConfig `yaml:"dashboard,omitempty"`
// OwnerRole is the legacy field for backward compatibility.
//
// Deprecated: Use Owner instead.
OwnerRole string `yaml:"owner_role,omitempty"`
// Icon is an emoji displayed in pipeline views.
Icon string `yaml:"icon,omitempty"`
// Optional marks the stage as skippable in the pipeline flow.
Optional bool `yaml:"optional,omitempty"`
// SkipWhen is an expression that, when true, causes the stage to be
// automatically skipped during advancement.
SkipWhen string `yaml:"skip_when,omitempty"`
// StaleAfter is the dwell window for the time-urgency gradient: once a spec
// has spent this long in this stage, its dashboard/pipeline row reaches full
// urgency. Accepts m/h/d/w units (e.g. "30m", "48h", "5d", "2w"). Empty,
// "none", or "0" means the stage is never stale and shows no colouring —
// there is no global fallback window.
StaleAfter string `yaml:"stale_after,omitempty"`
// Gates are conditions that must be satisfied to advance from this stage.
Gates []GateConfig `yaml:"gates,omitempty"`
// Warnings are time-based alerts that don't block advancement.
Warnings []WarningConfig `yaml:"warnings,omitempty"`
// Transitions customizes advance and revert behavior.
Transitions TransitionsConfig `yaml:"transitions,omitempty"`
// OnEnter lists effects to execute when entering this stage.
OnEnter []EffectConfig `yaml:"on_enter,omitempty"`
// OnExit lists effects to execute when leaving this stage.
OnExit []EffectConfig `yaml:"on_exit,omitempty"`
// AutoArchive moves the spec to archive/ when entering this stage.
AutoArchive bool `yaml:"auto_archive,omitempty"`
// Review configures plan review requirements for this stage.
// Used primarily for the engineering stage to require technical plan approval.
Review *StageReviewConfig `yaml:"review,omitempty"`
// AutoAdvance configures automatic stage advancement when gates are satisfied.
AutoAdvance *AutoAdvanceConfig `yaml:"auto_advance,omitempty"`
}
StageConfig defines a single pipeline stage.
func (StageConfig) GetOwner ¶
func (s StageConfig) GetOwner() string
GetOwner returns the effective owner as a display string. For multiple owners, returns comma-separated list. Falls back to legacy OwnerRole if Owner is not set.
func (StageConfig) HasOwner ¶
func (s StageConfig) HasOwner(role string) bool
HasOwner returns true if role is an owner of this stage. Also returns true if no owners are defined (open stage) or if role is empty.
func (StageConfig) StaleWindow ¶ added in v0.30.0
func (s StageConfig) StaleWindow() (window time.Duration, ok bool)
StaleWindow parses StaleAfter into a duration. ok is false when the stage has no configured window (empty, "none", or "0", or an unparseable value), meaning the stage is never stale.
type StageDashboardConfig ¶ added in v0.22.1
type StageDashboardConfig struct {
// DoScope controls who sees specs at this stage in their DO section.
// One of: "role" (default), "assignee", "author", "none".
DoScope string `yaml:"do_scope,omitempty"`
// Claimable, when true (the default), surfaces unassigned specs to the
// whole owning role under assignee scope so they can be claimed. Set false
// to hide unassigned specs from everyone until explicitly assigned.
Claimable *bool `yaml:"claimable,omitempty"`
}
StageDashboardConfig configures how a stage's specs surface in the dashboard.
func (StageDashboardConfig) IsClaimable ¶ added in v0.22.1
func (d StageDashboardConfig) IsClaimable() bool
IsClaimable reports whether unassigned specs surface to the owning role under assignee scope. Defaults to true.
func (StageDashboardConfig) Scope ¶ added in v0.22.1
func (d StageDashboardConfig) Scope() DoScope
Scope returns the effective DO scope, defaulting to role when unset or invalid.
type StageReviewConfig ¶
type StageReviewConfig struct {
// Required indicates whether review is required to advance.
// Defaults to true when Review is present.
Required *bool `yaml:"required,omitempty"`
// Reviewers lists who can review (roles like "tl" or named users like "@mike").
// Special value "author" allows self-review.
Reviewers []string `yaml:"reviewers,omitempty"`
// MinApprovals is the minimum number of approvals required.
// Defaults to 1.
MinApprovals int `yaml:"min_approvals,omitempty"`
}
StageReviewConfig configures plan review requirements.
func (*StageReviewConfig) GetMinApprovals ¶
func (r *StageReviewConfig) GetMinApprovals() int
GetMinApprovals returns the minimum approvals or default of 1.
func (*StageReviewConfig) IsRequired ¶
func (r *StageReviewConfig) IsRequired() bool
IsRequired returns whether review is required. Defaults to true if not explicitly set.
type SyncConfig ¶
type SyncConfig struct {
OutboundOnAdvance bool `yaml:"outbound_on_advance"`
ConflictStrategy string `yaml:"conflict_strategy"`
// AutoPush governs whether local edits and comments are published to the
// specs repo automatically. One of AutoPushAuto, AutoPushPrompt, AutoPushOff.
AutoPush string `yaml:"auto_push"`
}
SyncConfig defines sync behaviour.
type TeamConfig ¶
type TeamConfig struct {
Version string `yaml:"version"`
Team struct {
Name string `yaml:"name"`
CycleLabel string `yaml:"cycle_label"`
} `yaml:"team"`
SpecsRepo SpecsRepoConfig `yaml:"specs_repo"`
Integrations IntegrationsConfig `yaml:"integrations"`
Sync SyncConfig `yaml:"sync"`
Archive struct {
Directory string `yaml:"directory"`
} `yaml:"archive"`
Dashboard DashboardConfig `yaml:"dashboard"`
Pipeline PipelineConfig `yaml:"pipeline"`
// FastTrack configures engineer self-service for small bug fixes.
FastTrack *FastTrackConfig `yaml:"fast_track,omitempty"`
// Build configures the agentic build orchestration (DAG fan-out).
Build BuildConfig `yaml:"build,omitempty"`
}
TeamConfig represents the spec.config.yaml file committed to the specs repo.
func LoadTeamConfig ¶
func LoadTeamConfig(path string) (*TeamConfig, error)
LoadTeamConfig reads and parses a spec.config.yaml file.
type TransitionConfig ¶
type TransitionConfig struct {
// To lists allowed target stages. Empty means default (next for advance,
// any previous for revert).
To []string `yaml:"to,omitempty"`
// Gates are additional conditions for this specific transition.
Gates []GateConfig `yaml:"gates,omitempty"`
// Require lists required fields (e.g., ["reason"] for reverts).
Require []string `yaml:"require,omitempty"`
// Effects are side effects to execute on transition.
Effects []EffectConfig `yaml:"effects,omitempty"`
}
TransitionConfig defines behavior for a specific transition type.
type TransitionsConfig ¶
type TransitionsConfig struct {
Advance TransitionConfig `yaml:"advance,omitempty"`
Revert TransitionConfig `yaml:"revert,omitempty"`
}
TransitionsConfig customizes stage transition behavior.
type UpdatePMEffect ¶
type UpdatePMEffect struct {
Status string `yaml:"status,omitempty"`
}
UpdatePMEffect configures PM tool updates.
type UrgencyConfig ¶ added in v0.30.0
type UrgencyConfig struct {
// Easing selects how the raw dwell fraction is shaped into colour intensity:
// "linear", "ease-in" (default), or "ease-in-strong".
Easing string `yaml:"easing,omitempty"`
}
UrgencyConfig tunes the time-urgency gradient shared by the dashboard DO section and the pipeline screen.
type UserConfig ¶
type UserConfig struct {
User struct {
OwnerRole string `yaml:"owner_role"`
Name string `yaml:"name"`
// Handle is the spec-canonical identity token — a stable, user-chosen
// name that identifies the person inside spec (frontmatter author and
// assignees, thread author, decision log). It never leaves spec, so it
// can be anything the user likes. It is also the universal fallback for
// any per-integration identity that is not explicitly mapped.
Handle string `yaml:"handle"`
// Identities maps an integration provider name (e.g. "github", "slack",
// "teams", "jira") to the user's handle on that service. A person's
// handle differs on every service, so adapter calls must receive the
// service-specific value, not the canonical handle. Optional and
// additive: an absent or partial map falls back to Handle, so existing
// configs behave identically.
Identities map[string]string `yaml:"identities,omitempty"`
} `yaml:"user"`
Preferences PreferencesConfig `yaml:"preferences"`
// Agent is an OPTIONAL per-user coding-agent override. A coding harness is
// a personal tool, so each engineer may pick their own (e.g. claude-code or
// pi) regardless of the team default. When set (provider non-empty), it
// takes precedence over integrations.agent in the team config.
Agent *ProviderConfig `yaml:"agent,omitempty"`
// Workspaces maps repo names to local filesystem paths.
// Used for cross-repo navigation in multi-repo build plans.
// Example: workspaces: { auth-service: ~/code/auth-service }
Workspaces map[string]string `yaml:"workspaces,omitempty"`
}
UserConfig represents the ~/.spec/config.yaml personal config file.
func LoadUserConfig ¶
func LoadUserConfig(path string) (*UserConfig, error)
LoadUserConfig reads and parses the user config file.
func LoadUserConfigWithDefaults ¶
func LoadUserConfigWithDefaults() (*UserConfig, string)
LoadUserConfigWithDefaults loads user config or returns defaults if file doesn't exist.
func (*UserConfig) GetWorkspacePath ¶
func (c *UserConfig) GetWorkspacePath(repoName string) string
GetWorkspacePath returns the local path for a repo, or empty string if not configured.
type WarningConfig ¶
type WarningConfig struct {
// After is the duration after which the warning triggers (e.g., "5d", "48h").
After string `yaml:"after"`
// Message is displayed when the warning is active.
Message string `yaml:"message"`
// Notify is the target to notify (e.g., "tl", "#channel").
Notify string `yaml:"notify,omitempty"`
}
WarningConfig defines a time-based warning for a stage.
type WebhookEffect ¶
type WebhookEffect struct {
URL string `yaml:"url"`
Method string `yaml:"method,omitempty"` // default: POST
Headers map[string]string `yaml:"headers,omitempty"`
Body map[string]string `yaml:"body,omitempty"`
Timeout string `yaml:"timeout,omitempty"` // default: 10s
}
WebhookEffect configures an external webhook call.