config

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 36 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ConfigPathKey       = "config_path"
	FieldIDKey          = "field_id"
	FieldTypeKey        = "field_type"
	OptionIDKey         = "option_id"
	FieldIndexKey       = "field_index"
	OptionIndexKey      = "option_index"
	WorkspaceIDKey      = "workspace_id"
	WorkspaceColorKey   = "workspace_color"
	WorkspaceEmojiKey   = "workspace_emoji"
	WorkspaceEmojiLen   = "workspace_emoji_len"
	WorkspaceGroupIDKey = "workspace_group_id"
	GroupMemberKey      = "group_member"
	ExportDatasetKey    = "dataset"
)

Context keys for error values

View Source
const DefaultEmbeddingModel = "gemini-embedding-2"

DefaultEmbeddingModel is the default Gemini embedding model used when --embedding-model is not specified. The dimension is still controlled per-call via gollem's GenerateEmbedding(ctx, dimension, ...).

Variables

View Source
var (
	ErrConfigNotFound        = goerr.New("configuration file not found")
	ErrInvalidConfig         = goerr.New("invalid configuration")
	ErrDuplicateFieldID      = goerr.New("duplicate field ID")
	ErrDuplicateOptionID     = goerr.New("duplicate option ID")
	ErrInvalidFieldID        = goerr.New("invalid field ID format")
	ErrInvalidFieldType      = goerr.New("invalid field type")
	ErrMissingOptions        = goerr.New("select/multi-select field requires at least one option")
	ErrInvalidMetadata       = goerr.New("invalid metadata format")
	ErrMissingName           = goerr.New("name is required")
	ErrInvalidWorkspaceID    = goerr.New("invalid workspace ID format")
	ErrMissingWorkspaceID    = goerr.New("workspace ID is required")
	ErrDuplicateWorkspaceID  = goerr.New("duplicate workspace ID")
	ErrNoConfigFiles         = goerr.New("no configuration files found")
	ErrInvalidWelcomeMessage = goerr.New("invalid Slack welcome message template")
	// ErrWorkspaceEmojiColorConflict is returned when both emoji and color are
	// set in the [workspace] section. They are mutually exclusive because the
	// UI renders either an emoji badge (neutral background) or a colored
	// initials badge, never both.
	ErrWorkspaceEmojiColorConflict = goerr.New("workspace emoji and color are mutually exclusive")
	// ErrInvalidWorkspaceColor is returned when the [workspace] color is not a
	// 6-digit #RRGGBB hex code.
	ErrInvalidWorkspaceColor = goerr.New("invalid workspace color format")
	// ErrInvalidWorkspaceEmoji is returned when the [workspace] emoji exceeds
	// the allowed rune length.
	ErrInvalidWorkspaceEmoji = goerr.New("invalid workspace emoji")
	ErrInvalidCaseMode       = goerr.New("invalid case mode")
	ErrInvalidCaseTrigger    = goerr.New("invalid case trigger")
	ErrMissingMonitorChannel = goerr.New("thread mode requires [slack] channel")
	ErrInvalidMonitorChannel = goerr.New("invalid Slack channel ID")
	ErrMissingCaseStatus     = goerr.New("thread mode requires [case.status]")
	// ErrReactionRequiresThreadMode is returned when [slack] reaction is set on a
	// workspace that is not in thread mode. Reaction-triggered case creation needs
	// a destination thread, which only thread mode provides.
	ErrReactionRequiresThreadMode = goerr.New("[slack] reaction requires mode = \"thread\"")
	// ErrInvalidReactionEmoji is returned when [slack] reaction, after stripping
	// surrounding colons, is empty or contains characters outside a Slack emoji
	// name.
	ErrInvalidReactionEmoji = goerr.New("invalid Slack reaction emoji name")
	// ErrDuplicateReactionEmoji is returned when the same reaction emoji is
	// configured on more than one workspace, which would make emoji-to-workspace
	// resolution ambiguous.
	ErrDuplicateReactionEmoji = goerr.New("duplicate Slack reaction emoji across workspaces")

	// ErrWorkspaceChannelRequiresChannelMode is returned when workspace_channel is
	// set on a workspace that is not in channel mode. It names a separate channel
	// to host the cross-case agent; a thread-mode workspace already has one — the
	// monitored channel, where a channel-root mention runs that agent — so a
	// second one would only make channel-to-workspace routing ambiguous.
	// [slack.workspace_agent] itself is accepted in both modes.
	ErrWorkspaceChannelRequiresChannelMode = goerr.New("[slack] workspace_channel requires channel mode")
	// ErrMissingWorkspaceChannel is returned when [slack.workspace_agent] is set
	// on a CHANNEL-mode workspace but [slack] workspace_channel is empty: there
	// the agent runs in the workspace channel and is meaningless without it. In
	// thread mode the section stands alone (the monitored channel hosts it).
	ErrMissingWorkspaceChannel = goerr.New("[slack.workspace_agent] requires [slack] workspace_channel")
	// ErrInvalidWorkspaceChannel is returned when [slack] workspace_channel is not
	// a Slack channel ID (e.g. a channel name).
	ErrInvalidWorkspaceChannel = goerr.New("invalid Slack workspace_channel ID")
	// ErrDuplicateWorkspaceChannel is returned when the same channel ID is used as
	// a workspace_channel on more than one workspace, or collides with another
	// workspace's monitored channel, which would make channel-to-workspace routing
	// ambiguous.
	ErrDuplicateWorkspaceChannel = goerr.New("duplicate Slack workspace_channel across workspaces")
	// ErrWorkspaceAgentPromptConflict is returned when [slack.workspace_agent]
	// sets both prompt and prompt_file (mutually exclusive).
	ErrWorkspaceAgentPromptConflict = goerr.New("[slack.workspace_agent] prompt and prompt_file are mutually exclusive")
	// ErrWorkspaceAgentPromptEmpty is returned when [slack.workspace_agent]
	// prompt_file resolves to an empty file.
	ErrWorkspaceAgentPromptEmpty = goerr.New("[slack.workspace_agent] prompt_file is empty")
	// ErrMissingReferenceWorkspace is returned when a case_ref /
	// multi_case_ref field omits reference_workspace.
	ErrMissingReferenceWorkspace = goerr.New("case_ref field requires reference_workspace")
	// ErrUnexpectedReferenceWorkspace is returned when reference_workspace is set
	// on a field whose type is not a case_ref type.
	ErrUnexpectedReferenceWorkspace = goerr.New("reference_workspace is only valid for case_ref fields")
	// ErrUnknownReferenceWorkspace is returned when reference_workspace points at
	// a workspace ID that is not defined across the loaded configs.
	ErrUnknownReferenceWorkspace = goerr.New("reference_workspace points to an unknown workspace")
	// ErrRequiredCaseRefUnsupported is returned when a case_ref / multi_case_ref
	// field is marked required: the Slack case-creation modal cannot collect a
	// case reference, so a required one would make the case un-creatable.
	ErrRequiredCaseRefUnsupported = goerr.New("case_ref fields cannot be required")

	// ErrMissingWorkspaceGroupID is returned when a [[workspace_group]] omits id.
	ErrMissingWorkspaceGroupID = goerr.New("workspace group ID is required")
	// ErrInvalidWorkspaceGroupID is returned when a workspace group id does not
	// match the allowed pattern or exceeds the length limit.
	ErrInvalidWorkspaceGroupID = goerr.New("invalid workspace group ID format")
	// ErrDuplicateWorkspaceGroupID is returned when the same workspace group id
	// is defined more than once across the global config files.
	ErrDuplicateWorkspaceGroupID = goerr.New("duplicate workspace group ID")
	// ErrDuplicateGroupMember is returned when the same workspace id appears more
	// than once in a single group's members list.
	ErrDuplicateGroupMember = goerr.New("duplicate workspace group member")
	// ErrUnknownGroupMember is returned when a group member references a
	// workspace id that is not defined across the loaded workspace configs.
	ErrUnknownGroupMember = goerr.New("workspace group member references an unknown workspace")
	// ErrGlobalConfigContainsWorkspace is returned when a --global-config file
	// contains a [workspace] section. Workspace definitions belong under
	// --config (1 file = 1 workspace); the global config is for deployment-wide
	// settings only, so mixing the two is rejected loudly rather than ignored.
	ErrGlobalConfigContainsWorkspace = goerr.New("global config file must not contain a [workspace] section")

	// ErrInvalidExportConfig is returned when the [export] section is malformed,
	// e.g. a missing [export.bigquery] project.
	ErrInvalidExportConfig = goerr.New("invalid export configuration")
	// ErrInvalidExportDataset is returned when an [[export.bigquery.workspace]]
	// dataset name is not a valid BigQuery dataset ID (BigQuery forbids hyphens).
	ErrInvalidExportDataset = goerr.New("invalid export dataset name")
	// ErrDuplicateExportWorkspace is returned when the same workspace id — or the
	// same dataset name — appears more than once in the export config.
	ErrDuplicateExportWorkspace = goerr.New("duplicate export workspace mapping")
	// ErrUnknownExportWorkspace is returned when an export workspace mapping
	// references a workspace id not defined across the loaded workspace configs.
	ErrUnknownExportWorkspace = goerr.New("export workspace mapping references an unknown workspace")
	// ErrDuplicateExportConfig is returned when more than one global config file
	// defines an [export] section.
	ErrDuplicateExportConfig = goerr.New("duplicate [export] section across global config files")
)

Sentinel errors for configuration validation

Functions

func LoadFieldSchema

func LoadFieldSchema(path string) (*domainConfig.FieldSchema, error)

LoadFieldSchema loads the field schema configuration from a TOML file Returns an error if the file does not exist (config.toml is required)

func LoadWorkspaceGroups

func LoadWorkspaceGroups(paths []string) ([]*model.WorkspaceGroup, error)

LoadWorkspaceGroups walks the given file/dir paths, parses each .toml as a GlobalConfig, validates every [[workspace_group]] section, and rejects duplicate group IDs across files. It does not know the workspace set; member existence is checked by ConfigureGroups. Zero files (empty paths) yields an empty slice with no error — an unset --global-config is a valid state.

Types

type ActionSection

type ActionSection struct {
	Initial string                  `toml:"initial"`
	Closed  []string                `toml:"closed"`
	Status  []ActionStatusConfigRow `toml:"status"`
}

ActionSection represents the [action] section in a TOML config. When omitted (nil), the workspace inherits the default action status set.

type ActionStatusConfigRow

type ActionStatusConfigRow struct {
	ID          string `toml:"id"`
	Name        string `toml:"name"`
	Description string `toml:"description"`
	Color       string `toml:"color"`
	Emoji       string `toml:"emoji"`
}

ActionStatusConfigRow represents a single [[action.status]] entry.

type AppConfig

type AppConfig struct {
	Workspace WorkspaceBaseConfig `toml:"workspace"`
	Labels    Labels              `toml:"labels"`
	Fields    []FieldDefinition   `toml:"fields"`
	Slack     SlackSection        `toml:"slack"`
	Compile   CompileSection      `toml:"compile"`
	Assist    AssistSection       `toml:"assist"`
	Action    *ActionSection      `toml:"action"`
	Case      *CaseSection        `toml:"case"`
	Memo      *MemoSection        `toml:"memo"`
	Jobs      []JobSection        `toml:"job"`
}

AppConfig represents the application configuration. It holds TOML-parsed fields and provides CLI Flags()/Configure() methods.

func (*AppConfig) Configure

Configure loads workspace configs from CLI-provided paths and builds a WorkspaceRegistry. It reads "config" from the cli.Command since StringSliceFlag does not support Destination.

func (*AppConfig) ConfigureExport

func (a *AppConfig) ConfigureExport(c *cli.Command, ws *model.WorkspaceRegistry) (*ExportSection, error)

ConfigureExport reads the --global-config flag, loads the [export] section, and validates it against the workspace registry. It returns (nil, nil) when no [export] is configured (the export subcommand then errors out with a clear message). It mirrors ConfigureGroups so callers that do not export are untouched.

func (*AppConfig) ConfigureGroups

ConfigureGroups reads the --global-config flag, loads workspace groups, and cross-checks every member against the workspace registry. It returns a never-nil registry: an unset flag yields an empty registry (feature dormant). It is a separate method from Configure so the callers that do not need groups (assist / diagnosis / job runtime) are untouched.

func (*AppConfig) Flags

func (a *AppConfig) Flags() []cli.Flag

Flags returns CLI flags for workspace configuration.

func (*AppConfig) ToDomainFieldSchema

func (a *AppConfig) ToDomainFieldSchema() *domainConfig.FieldSchema

ToDomainFieldSchema converts AppConfig to domain FieldSchema

func (*AppConfig) ToDomainMemoConfig

func (a *AppConfig) ToDomainMemoConfig() *domainConfig.MemoConfig

ToDomainMemoConfig converts the [memo] section to a domain MemoConfig. Returns nil when [memo] is omitted, leaving the memo feature disabled for the workspace.

func (*AppConfig) Validate

func (a *AppConfig) Validate() error

Validate checks if the AppConfig is valid

type AssistSection

type AssistSection struct {
	Prompt   string `toml:"prompt"`
	Language string `toml:"language"`
}

AssistSection represents the [assist] section in a TOML config

type CaseEventSection

type CaseEventSection struct {
	On []string `toml:"on"`
}

CaseEventSection is the filter for `events.case`. The TOML `on` field is always an array; we deliberately do not accept a single string so the schema stays type-safe.

type CasePromptsSection

type CasePromptsSection struct {
	Create string `toml:"create"`
}

CasePromptsSection represents the [case.prompts] sub-table: workspace- specific additional prompts for the case agent, keyed by lifecycle phase. Only `create` (the thread-mode initialization agent) is consumed today; `mention` / `close` are reserved for future phases.

type CaseSection

type CaseSection struct {
	Initial string                  `toml:"initial"`
	Closed  []string                `toml:"closed"`
	Status  []ActionStatusConfigRow `toml:"status"`
	Prompts CasePromptsSection      `toml:"prompts"`
}

CaseSection represents the [case] section in a TOML config. It mirrors [action] but configures the status set that attaches to Cases in thread mode. It is required for thread-mode workspaces and ignored otherwise.

type CompileSection

type CompileSection struct {
	Prompt string `toml:"prompt"`
}

CompileSection represents the [compile] section in a TOML config

type Embedding

type Embedding struct {
	// contains filtered or unexported fields
}

Embedding holds CLI configuration for the embedding client. Embedding is always backed by Gemini; chat completion has its own LLM configuration (config.LLM) that may use a different provider entirely.

func (*Embedding) Flags

func (x *Embedding) Flags() []cli.Flag

Flags returns CLI flags for Embedding configuration.

func (*Embedding) IsEnabled

func (x *Embedding) IsEnabled() bool

IsEnabled reports whether the embedding client has the minimum configuration required to be constructed. The CLI commands all require embedding to be enabled; the helper exists so callers can fail fast with a clear message before reaching NewClient.

func (*Embedding) LogAttrs

func (x *Embedding) LogAttrs() []slog.Attr

LogAttrs returns log attributes describing the embedding configuration. Project ID, location, and model name are surfaced; no secret values exist to leak (Application Default Credentials are used by the Gemini SDK).

func (*Embedding) NewClient

func (x *Embedding) NewClient(ctx context.Context) (interfaces.EmbedClient, error)

NewClient builds an interfaces.EmbedClient backed by a dedicated Gemini client. Returns an error when --embedding-gemini-project-id is missing.

type ExportBigQuerySection

type ExportBigQuerySection struct {
	// Project is the destination GCP project ID. Required.
	Project string `toml:"project"`
	// Location is the BigQuery location (e.g. "US", "asia-northeast1") used when a
	// dataset must be created. Optional.
	Location string `toml:"location"`
	// Workspaces maps each exported workspace to its destination dataset. A
	// workspace not listed here is not exported.
	Workspaces []ExportWorkspaceMapping `toml:"workspace"`
}

ExportBigQuerySection configures the BigQuery export sink.

type ExportSection

type ExportSection struct {
	// IncludePrivate is the default for every workspace: when true, private Cases
	// (and their Actions / Memos) are exported too. Defaults to false — private
	// data is NOT exported unless explicitly opted in. A per-workspace mapping may
	// override it.
	IncludePrivate bool `toml:"include_private"`
	// BigQuery is the BigQuery sink configuration. Required (the only sink today).
	BigQuery *ExportBigQuerySection `toml:"bigquery"`
}

ExportSection represents the [export] section of a global config file: the deployment-wide configuration for the `export` subcommand. Nil when no global config declares [export] (the feature is then unavailable).

func LoadExportConfig

func LoadExportConfig(paths []string) (*ExportSection, error)

LoadExportConfig walks the given file/dir paths, parses each .toml as a GlobalConfig, and returns the single [export] section found. It returns (nil, nil) when no file declares [export], and an error when more than one does (the export config must have a single home). A stray [workspace] section is rejected, mirroring LoadWorkspaceGroups. Structural validation against the workspace registry is done by ConfigureExport, not here.

func (*ExportSection) IncludePrivateFor

func (s *ExportSection) IncludePrivateFor(m ExportWorkspaceMapping) bool

IncludePrivateFor returns the effective include_private for a mapping: the mapping's own value when set, otherwise the section-level default.

func (*ExportSection) Validate

func (s *ExportSection) Validate(ws *model.WorkspaceRegistry) error

Validate checks the export section against the workspace registry: BigQuery project presence, dataset-name validity, uniqueness of workspace ids and dataset names, and existence of every referenced workspace.

type ExportWorkspaceMapping

type ExportWorkspaceMapping struct {
	// ID is the workspace ID (must exist in the workspace registry).
	ID string `toml:"id"`
	// Dataset is the destination BigQuery dataset name. BigQuery dataset names
	// forbid hyphens, so this is given explicitly rather than derived from ID.
	Dataset string `toml:"dataset"`
	// IncludePrivate overrides the section-level default for this workspace when
	// set (non-nil). Nil means "inherit [export].include_private".
	IncludePrivate *bool `toml:"include_private"`
}

ExportWorkspaceMapping maps one workspace to a BigQuery dataset.

type FieldDefinition

type FieldDefinition struct {
	ID                 string        `toml:"id"`
	Name               string        `toml:"name"`
	Type               string        `toml:"type"`
	Required           bool          `toml:"required"`
	Description        string        `toml:"description"`
	Options            []FieldOption `toml:"options"`
	ReferenceWorkspace string        `toml:"reference_workspace"`
}

FieldDefinition represents a custom field definition

func (*FieldDefinition) Validate

func (f *FieldDefinition) Validate() error

Validate checks if the FieldDefinition is valid

type FieldOption

type FieldOption struct {
	ID          string         `toml:"id"`
	Name        string         `toml:"name"`
	Description string         `toml:"description"`
	Metadata    map[string]any `toml:"metadata"`
}

FieldOption represents an option for select/multi-select fields

func (*FieldOption) Validate

func (o *FieldOption) Validate(fieldID string) error

Validate checks if the FieldOption is valid

type GitHub

type GitHub struct {
	// contains filtered or unexported fields
}

GitHub holds configuration for the GitHub App integration

func (*GitHub) Configure

func (g *GitHub) Configure() (*github.Client, error)

Configure creates a new GitHub Client from the configured flags. Returns nil if not all flags are configured (GitHub features will be disabled).

func (*GitHub) Flags

func (g *GitHub) Flags() []cli.Flag

Flags returns CLI flags for GitHub App configuration

func (*GitHub) IsConfigured

func (g *GitHub) IsConfigured() bool

IsConfigured returns true if all required GitHub App flags are set

func (*GitHub) LogAttrs

func (g *GitHub) LogAttrs() []slog.Attr

LogAttrs returns log attributes for the GitHub configuration (secrets hidden)

type GlobalConfig

type GlobalConfig struct {
	// Workspace captures a stray [workspace] section so the loader can reject
	// it. Workspace definitions belong under --config, never here. It is a raw
	// map (not the real WorkspaceBaseConfig) because its only use is presence
	// detection; an empty [workspace] table still unmarshals to a non-nil map.
	Workspace       map[string]any          `toml:"workspace"`
	WorkspaceGroups []WorkspaceGroupSection `toml:"workspace_group"`
	Export          *ExportSection          `toml:"export"`
}

GlobalConfig represents a deployment-wide configuration file supplied via --global-config. It is distinct from the per-workspace files under --config (which stay "1 file = 1 workspace"): a global config file carries settings that span workspaces. Today it holds workspace group definitions only; new deployment-wide sections can be added here later without a new flag.

type HomeMessageLLM

type HomeMessageLLM struct {
	// contains filtered or unexported fields
}

HomeMessageLLM is a dedicated, optional LLM configuration for the home dashboard's greeting message. It mirrors config.LLM's provider dispatch but with its own flags so the greeting can target a cheaper/faster model than the main chat LLM. When left unconfigured (IsEnabled() == false), the caller falls back to the shared chat LLM client.

func (*HomeMessageLLM) Flags

func (x *HomeMessageLLM) Flags() []cli.Flag

Flags returns CLI flags for the home-message LLM configuration.

func (*HomeMessageLLM) IsEnabled

func (x *HomeMessageLLM) IsEnabled() bool

IsEnabled reports whether a dedicated home-message LLM provider is configured. When false, the caller uses the shared chat LLM client instead.

func (*HomeMessageLLM) LogAttrs

func (x *HomeMessageLLM) LogAttrs() []slog.Attr

LogAttrs returns log attributes for the home-message LLM configuration. Secrets are never included.

func (*HomeMessageLLM) NewClient

func (x *HomeMessageLLM) NewClient(ctx context.Context) (gollem.LLMClient, error)

NewClient builds a gollem.LLMClient for the configured provider. It must only be called when IsEnabled() is true.

type Jira

type Jira struct {
	// contains filtered or unexported fields
}

Jira holds configuration for the Jira Cloud read-only integration.

func (*Jira) Configure

func (j *Jira) Configure(ctx context.Context) ([]gollem.Tool, error)

Configure builds the Jira agent tools from the configured flags. Returns nil, nil if none of the three flags are set (Jira features will be disabled). Returns an error if only some are set: a partial configuration is a setup mistake, not an intentional opt-out, and silently disabling the tools would hide it from the operator.

func (*Jira) Flags

func (j *Jira) Flags() []cli.Flag

Flags returns CLI flags for Jira configuration.

func (*Jira) IsConfigured

func (j *Jira) IsConfigured() bool

IsConfigured returns true if all required Jira flags are set.

func (*Jira) LogAttrs

func (j *Jira) LogAttrs() []slog.Attr

LogAttrs returns log attributes for the Jira configuration (the API token is deliberately excluded).

type JobEventsSection

type JobEventsSection struct {
	Case      *CaseEventSection      `toml:"case"`
	Scheduled *ScheduledEventSection `toml:"scheduled"`
}

JobEventsSection mirrors the `events.<domain> = { ... }` map. At least one sub-domain pointer must be non-nil; both may be set simultaneously.

type JobSection

type JobSection struct {
	ID          string `toml:"id"`
	Name        string `toml:"name"`
	Description string `toml:"description"`
	// Prompt is the inline prompt template. Exactly one of Prompt or
	// PromptFile must be set; supplying both, or neither, fails at config
	// load time.
	Prompt string `toml:"prompt"`
	// PromptFile points to a file holding the prompt template, resolved
	// relative to the config file's directory. It exists so long prompts can
	// live outside the TOML instead of being inlined. The file contents
	// replace Prompt once read (see resolvePrompt); the runtime layer only
	// ever sees the resolved model.Job.Prompt.
	PromptFile string `toml:"prompt_file"`
	Disabled   bool   `toml:"disabled"`
	// Quiet, when true, suppresses the operational Slack notifications a
	// Job run normally emits (the "starting..." marker, per-run session-log
	// thread, and completion/failure markers). Defaults to false.
	Quiet bool `toml:"quiet"`
	// Strategy selects the execution runtime for this Job. Empty falls
	// back to "simple" (the v1 SingleLoopJobExecutor); set to "planexec"
	// to drive the Job through the plan-and-execute runtime shared with
	// proposal. Unknown values fail loud at config load time.
	Strategy string `toml:"strategy"`
	// Reflection enables the post-execution reflection pass that curates
	// workspace Knowledge from a successful run's conversation history.
	// Defaults to false. Skipped for private cases and failed runs.
	Reflection bool `toml:"reflection"`
	// Interactive enables mid-run user interaction (planexec Question →
	// Slack form → resume). Defaults to false. Requires strategy="planexec";
	// the combination with simple is rejected at config load time by
	// model.Job.Validate.
	Interactive bool             `toml:"interactive"`
	Events      JobEventsSection `toml:"events"`
}

JobSection is the TOML shape of a [[job]] entry. All event-shape validation runs at config load time: the runtime layer (pkg/usecase/job) trusts that every Job it receives has already been vetted.

func (*JobSection) Validate

func (s *JobSection) Validate(baseDir string) (*model.Job, error)

Validate parses and validates a single JobSection, returning a fully resolved model.Job on success. baseDir is the directory of the config file, used to resolve a relative prompt_file path. Returns an error wrapped with the job index so the caller can include it in its error message.

type LLM

type LLM struct {
	// contains filtered or unexported fields
}

LLM holds CLI configuration for LLM clients backed by gollem. It supports OpenAI, Anthropic Claude (direct API or Vertex AI), and Google Gemini.

func (*LLM) Flags

func (x *LLM) Flags() []cli.Flag

Flags returns CLI flags for LLM configuration.

func (*LLM) IsEnabled

func (x *LLM) IsEnabled() bool

IsEnabled reports whether an LLM provider has been configured.

func (*LLM) LogAttrs

func (x *LLM) LogAttrs() []slog.Attr

LogAttrs returns log attributes for the LLM configuration. Secrets are never included. Provider-specific attributes are emitted only when relevant to the active provider.

func (*LLM) NewClient

func (x *LLM) NewClient(ctx context.Context) (gollem.LLMClient, error)

NewClient builds a gollem.LLMClient for the configured provider. Returns (nil, nil) when the LLM feature is disabled (no provider configured).

type Labels

type Labels struct {
	Case string `toml:"case"`
}

Labels represents entity display labels

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

func (*Logger) Configure

func (x *Logger) Configure() (func(), error)

Configure sets up logger and returns closer function and error. You can call closer even if error is not nil.

func (*Logger) Flags

func (x *Logger) Flags() []cli.Flag

func (Logger) LogValue

func (x Logger) LogValue() slog.Value

type MCP

type MCP struct {
	// contains filtered or unexported fields
}

MCP holds the configuration for the MCP (Model Context Protocol) server endpoint and its Rego-based authorization. The MCP endpoint is only exposed when enabled, and only when at least one policy path is supplied — we never serve MCP without an authorization policy.

func (*MCP) Configure

func (m *MCP) Configure(c *cli.Command) (interfaces.PolicyClient, map[string]string, error)

Configure builds the PolicyClient and the env snapshot when MCP is enabled. It reads the slice flags from c (StringSliceFlag has no Destination).

When MCP is disabled it returns (nil, nil, nil). When MCP is enabled without any policy path it returns an error: exposing the MCP endpoint without an authorization policy would be an unauthenticated data leak, so we refuse to start rather than fall back to an open endpoint.

func (*MCP) Flags

func (m *MCP) Flags() []cli.Flag

Flags returns CLI flags for the MCP server and its policy source.

func (*MCP) IsEnabled

func (m *MCP) IsEnabled() bool

IsEnabled reports whether the MCP endpoint should be wired.

func (*MCP) LogAttrs

func (m *MCP) LogAttrs() []slog.Attr

LogAttrs returns log attributes describing the MCP configuration. Only the env variable names are logged, never their values.

type MemoSection

type MemoSection struct {
	// Description is the workspace's "strong definition" of the memo, injected
	// into the agent system prompt and shown in the WebUI.
	Description string `toml:"description"`
	// Fields are the memo custom field definitions ([[memo.fields]]), reusing
	// the same FieldDefinition schema as Case fields.
	Fields []FieldDefinition `toml:"fields"`
}

MemoSection represents the [memo] section in a TOML config. When omitted (nil) or with no fields, the workspace does not enable the memo feature.

type Repository

type Repository struct {
	// contains filtered or unexported fields
}

Repository holds CLI flags for repository backend configuration

func (*Repository) Backend

func (r *Repository) Backend() string

Backend returns the configured backend type

func (*Repository) Configure

func (r *Repository) Configure(ctx context.Context) (interfaces.Repository, error)

Configure initializes and returns a repository based on the configured backend. The caller is responsible for calling Close() on the returned repository.

func (*Repository) DatabaseID

func (r *Repository) DatabaseID() string

DatabaseID returns the Firestore database ID

func (*Repository) Flags

func (r *Repository) Flags() []cli.Flag

Flags returns CLI flags for repository configuration

func (*Repository) LogAttrs

func (r *Repository) LogAttrs() []slog.Attr

LogAttrs returns log attributes for the repository configuration

func (*Repository) ProjectID

func (r *Repository) ProjectID() string

ProjectID returns the Firestore project ID

type ScheduledEventSection

type ScheduledEventSection struct {
	Every string `toml:"every"`
	Cron  string `toml:"cron"`
}

ScheduledEventSection is the filter for `events.scheduled`. Exactly one of Every / Cron is required.

type Sentry

type Sentry struct {
	// contains filtered or unexported fields
}

Sentry binds the HECATONCHEIRES_SENTRY_* CLI flags / env vars and drives the Sentry SDK lifecycle through errutil. An empty DSN keeps Sentry disabled and the rest of the values are ignored.

func (*Sentry) Configure

func (x *Sentry) Configure(ctx context.Context)

Configure initializes the Sentry SDK from the bound flags. When the DSN is empty Sentry stays disabled. SDK-level init errors are reported via errutil.Handle but never fail startup — losing Sentry must not block the service from coming up.

func (*Sentry) Flags

func (x *Sentry) Flags() []cli.Flag

Flags returns CLI flags for Sentry configuration.

func (Sentry) LogValue

func (x Sentry) LogValue() slog.Value

LogValue masks the DSN so it never lands in operational logs while still surfacing the rest of the Sentry configuration for diagnostics.

type Slack

type Slack struct {
	// contains filtered or unexported fields
}

func (*Slack) AuthTeamID

func (x *Slack) AuthTeamID() string

AuthTeamID returns the team_id from auth.test response

func (*Slack) BotToken

func (x *Slack) BotToken() string

BotToken returns the Slack bot token

func (*Slack) Configure

func (x *Slack) Configure(ctx context.Context, repo interfaces.Repository, baseURL string) (usecase.AuthUseCaseInterface, error)

Configure creates an AuthUseCase if Slack is configured, otherwise returns NoAuthnUseCase

func (*Slack) DetectOrgLevel

func (x *Slack) DetectOrgLevel(ctx context.Context) error

DetectOrgLevel calls auth.test and auth.teams.list to determine if the bot token has access to multiple workspaces (multi-team / org-level behavior). It stores the result (isOrgLevel, authTeamID, enterpriseID) for later validation. If botToken is empty, this is a no-op (Slack features disabled).

func (*Slack) EnterpriseID

func (x *Slack) EnterpriseID() string

EnterpriseID returns the enterprise_id from auth.test response (empty for WS-level apps)

func (*Slack) Flags

func (x *Slack) Flags() []cli.Flag

func (*Slack) GetSlackUserInfo

func (x *Slack) GetSlackUserInfo(ctx context.Context, userID string) (*SlackUserInfo, error)

GetSlackUserInfo retrieves user information from Slack API

func (*Slack) IsConfigured

func (x *Slack) IsConfigured() bool

IsConfigured checks if Slack configuration is complete

func (*Slack) IsNoAuthMode

func (x *Slack) IsNoAuthMode() bool

IsNoAuthMode returns true if no-auth mode is enabled

func (*Slack) IsOrgLevel

func (x *Slack) IsOrgLevel() bool

IsOrgLevel returns whether the Slack app is org-level installed

func (*Slack) IsWebhookConfigured

func (x *Slack) IsWebhookConfigured() bool

IsWebhookConfigured checks if Slack webhook is configured

func (*Slack) LogAttrs

func (x *Slack) LogAttrs() []slog.Attr

LogAttrs returns log attributes for the Slack configuration (secrets hidden)

func (Slack) LogValue

func (x Slack) LogValue() slog.Value

func (*Slack) NoAuthUID

func (x *Slack) NoAuthUID() string

NoAuthUID returns the no-auth user ID

func (*Slack) NotificationSlotDuration

func (x *Slack) NotificationSlotDuration() time.Duration

NotificationSlotDuration returns the configured aggregation window.

func (*Slack) SetNoAuthUID

func (x *Slack) SetNoAuthUID(uid string)

SetNoAuthUID sets the no-auth user ID

func (*Slack) SigningSecret

func (x *Slack) SigningSecret() string

SigningSecret returns the Slack signing secret

func (*Slack) UserOAuthToken

func (x *Slack) UserOAuthToken() string

UserOAuthToken returns the Slack User OAuth Token for admin API operations

func (*Slack) ValidateWorkspaceTeamIDs

func (x *Slack) ValidateWorkspaceTeamIDs(configs []*WorkspaceConfig) error

ValidateWorkspaceTeamIDs validates slack.team_id settings in workspace configs based on whether the app is org-level or workspace-level.

  • Org-Level App: all workspaces must have slack.team_id set
  • WS-Level App: slack.team_id may be empty; if set, must match auth.test team_id

If botToken is empty (Slack disabled), validation is skipped.

type SlackInviteSection

type SlackInviteSection struct {
	Users  []string `toml:"users"`
	Groups []string `toml:"groups"`
}

SlackInviteSection represents the [slack.invite] section in a TOML config

type SlackSection

type SlackSection struct {
	ChannelPrefix   string             `toml:"channel_prefix"`
	TeamID          string             `toml:"team_id"`
	Invite          SlackInviteSection `toml:"invite"`
	WelcomeMessages []string           `toml:"welcome_messages"`
	// Mode selects the case-binding mode: "channel" (default) or "thread".
	Mode string `toml:"mode"`
	// Channel is the monitored Slack channel ID for thread mode (e.g. C0123...).
	Channel string `toml:"channel"`
	// AcceptBot, when true, makes bot-authored events (a channel-root post in
	// instant mode, or an @mention in mention mode) start a case in thread mode.
	// Default false: only human-authored events start a case.
	AcceptBot bool `toml:"accept_bot"`
	// Trigger selects what starts a case in thread mode: "instant" (default,
	// every channel-root post) or "mention" (only an @mention of the bot).
	// Ignored in channel mode.
	Trigger string `toml:"trigger"`
	// Reaction is the emoji name (with or without surrounding colons) that
	// triggers case creation when added to any visible message. Thread mode
	// only; empty disables the reaction trigger.
	Reaction string `toml:"reaction"`
	// WorkspaceChannel is the workspace-level shared channel ID where the
	// cross-case workspace agent runs (and future notifications flow). It
	// parallels Channel but is channel-mode only; empty disables the feature.
	WorkspaceChannel string `toml:"workspace_channel"`
	// WorkspaceAgent configures the cross-case agent ([slack.workspace_agent]).
	// nil when the subsection is omitted. Valid in both modes: in channel mode
	// the agent runs in WorkspaceChannel (which must then be set), in thread
	// mode it runs on a channel-root mention in the monitored Channel.
	WorkspaceAgent *WorkspaceAgentSection `toml:"workspace_agent"`
}

SlackSection represents the slack section in a TOML config

type SlackUserInfo

type SlackUserInfo struct {
	ID    string
	Email string
	Name  string
}

SlackUserInfo holds user information retrieved from Slack API

type Storage

type Storage struct {
	// contains filtered or unexported fields
}

Storage holds CLI flags for the Cloud Storage backend used by the agent session archive (gollem History + Trace persistence).

func (*Storage) Bucket

func (s *Storage) Bucket() string

Bucket returns the configured bucket name.

func (*Storage) Configure

func (s *Storage) Configure(ctx context.Context) (gollem.HistoryRepository, trace.Repository, func(), error)

Configure builds the gollem HistoryRepository and trace.Repository backed by Cloud Storage. The returned cleanup function closes the underlying storage client and must be called on shutdown. An error is returned when the bucket flag is empty.

func (*Storage) Flags

func (s *Storage) Flags() []cli.Flag

Flags returns the CLI flags for Cloud Storage configuration.

func (*Storage) LogAttrs

func (s *Storage) LogAttrs() []slog.Attr

LogAttrs returns log attributes describing the configuration.

func (*Storage) Prefix

func (s *Storage) Prefix() string

Prefix returns the configured object key prefix.

type WebFetch

type WebFetch struct {
	// contains filtered or unexported fields
}

WebFetch holds configuration for the agent webfetch tool. The shared LLM client (used for injection screening + Markdown formatting) is NOT held here: it lives in the usecase layer and is injected when the client is built.

func (*WebFetch) Flags

func (w *WebFetch) Flags() []cli.Flag

Flags returns CLI flags for the webfetch tool.

func (*WebFetch) IsEnabled

func (w *WebFetch) IsEnabled() bool

IsEnabled reports whether the webfetch tool should be wired.

func (*WebFetch) LogAttrs

func (w *WebFetch) LogAttrs() []slog.Attr

LogAttrs returns log attributes for the webfetch configuration.

func (*WebFetch) Settings

func (w *WebFetch) Settings() webfetch.ClientConfig

Settings returns the HTTP-side client config. ClientConfig.LLM is left nil: the usecase layer injects the shared LLM client before building the client.

type WorkspaceAgentSection

type WorkspaceAgentSection struct {
	Prompt     string `toml:"prompt"`
	PromptFile string `toml:"prompt_file"`
}

WorkspaceAgentSection represents the [slack.workspace_agent] subsection: the custom prompt for the cross-case agent that runs in the workspace channel.

type WorkspaceBaseConfig

type WorkspaceBaseConfig struct {
	ID          string `toml:"id"`
	Name        string `toml:"name"`
	Description string `toml:"description"` // Human-readable description used to disambiguate workspaces (especially for AI-side workspace estimation)
	// Emoji is an optional display glyph rendered in the workspace badge.
	// Mutually exclusive with Color. Empty when unset.
	Emoji string `toml:"emoji"`
	// Color is an optional #RRGGBB hex used as the workspace badge background.
	// Mutually exclusive with Emoji. Empty when unset.
	Color string `toml:"color"`
}

WorkspaceBaseConfig represents the [workspace] section in a TOML config

func (*WorkspaceBaseConfig) Validate

func (w *WorkspaceBaseConfig) Validate() error

Validate checks the optional emoji/color fields of the [workspace] section. emoji and color are mutually exclusive; color must be a #RRGGBB hex code; emoji must not exceed maxWorkspaceEmojiRunes runes.

type WorkspaceConfig

type WorkspaceConfig struct {
	ID                   string
	Name                 string
	Description          string
	Emoji                string
	Color                string
	SlackChannelPrefix   string
	SlackTeamID          string
	SlackInviteUsers     []string
	SlackInviteGroups    []string
	SlackWelcomeMessages []string
	FieldSchema          *domainConfig.FieldSchema
	MemoConfig           *domainConfig.MemoConfig
	ActionStatusSet      *model.ActionStatusSet
	CompilePrompt        string
	AssistPrompt         string
	AssistLanguage       string
	// CaseCreatePrompt is the workspace-specific additional prompt for the
	// thread-mode case initialization agent, from [case.prompts].create.
	CaseCreatePrompt    string
	Jobs                []*model.Job
	CaseMode            model.CaseMode
	CaseTrigger         model.CaseTrigger
	SlackMonitorChannel string
	AcceptBot           bool
	CaseStatusSet       *model.ActionStatusSet
	// ReactionEmoji is the normalized (colon-stripped) reaction trigger emoji,
	// empty when disabled.
	ReactionEmoji string
	// WorkspaceChannelID is the workspace-level shared channel ID (channel mode
	// only), empty when unset.
	WorkspaceChannelID string
	// WorkspaceAgentPrompt is the resolved custom prompt for the workspace agent
	// (from [slack.workspace_agent] prompt/prompt_file), empty when unset.
	WorkspaceAgentPrompt string
}

WorkspaceConfig represents a fully resolved workspace configuration

func LoadWorkspaceConfigs

func LoadWorkspaceConfigs(paths []string) ([]*WorkspaceConfig, error)

LoadWorkspaceConfigs loads workspace configurations from multiple paths. Each path can be a file or directory. Directories are walked recursively for .toml files.

type WorkspaceGroupSection

type WorkspaceGroupSection struct {
	ID          string   `toml:"id"`
	Name        string   `toml:"name"`
	Description string   `toml:"description"`
	Members     []string `toml:"members"`
}

WorkspaceGroupSection represents a single [[workspace_group]] table.

func (*WorkspaceGroupSection) Validate

func (s *WorkspaceGroupSection) Validate() error

Validate checks one group section in isolation: id presence and format, and member uniqueness within this group. Cross-file id uniqueness and member existence are enforced by the loader / ConfigureGroups once the full group and workspace sets are known.

Jump to

Keyboard shortcuts

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