config

package
v0.5.3 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package config loads Seamless configuration from a single YAML file with SEAMLESS_* environment overrides. Env wins over file; file wins over defaults.

Deliberately halved from Seam v1: no JWT/auth/multi-user config, no ChromaDB. Auth is a single static bearer key; vectors live in SQLite.

Index

Constants

View Source
const (
	ProviderOpenAI    = "openai"
	ProviderOllama    = "ollama"
	ProviderAnthropic = "anthropic"
)

LLM provider identifiers.

View Source
const (
	// RoleServer runs the daemon on this machine. The default.
	RoleServer = "server"
	// RoleClient runs no daemon here: every surface dials server_url instead.
	RoleClient = "client"
)

Roles are the accepted role values.

View Source
const DialTimeout = 5 * time.Second

DialTimeout bounds how long a client waits to ESTABLISH a connection to the daemon. It is separate from the whole-request deadline because a down daemon must fail fast even on the surfaces where the response may legitimately take minutes (the mcp-proxy bridge, whose tool calls can be LLM-backed).

View Source
const (
	// MaxEmbeddingDimensions bounds a configured/requested vector size. Current
	// providers are in the low thousands; 65,536 permits future models while
	// preventing a typo from driving unbounded vector allocations downstream.
	MaxEmbeddingDimensions = 65_536
)

Variables

View Source
var ConsoleLevels = []string{"basic", "standard", "advanced"}

ConsoleLevels are the accepted console.level values, ordered from the fewest surfaces to the most. Every enum, help string, and registry derives from this slice; the order is the nesting order (each level shows everything the previous one does).

Roles is the canonical role set, for validation and for the message that names the accepted values.

View Source
var UtilityModes = []string{"auto", "on", "off"}

UtilityModes are the accepted briefing.utility_mode values.

Functions

func Hostname added in v0.5.0

func Hostname() string

Hostname is this machine's hostname, lower-cased and cached for the life of the process: it identifies which device a session, a repo mapping, or a captured plan came from, so it is read on hot paths (every hook fires one) and must not re-syscall each time.

Lower-cased because it is compared with hostnames that arrived over the wire, where case is not preserved. An unreadable hostname yields "", which callers must treat as "unknown machine" rather than as a name -- never as a stand-in for the local one.

Types

type Anthropic

type Anthropic struct {
	APIKey    string `yaml:"api_key"`
	BaseURL   string `yaml:"base_url"`
	ChatModel string `yaml:"chat_model"`
}

Anthropic is a chat-only provider (no embeddings API).

type Briefing

type Briefing struct {
	// ConstraintMaxFull is how many top-ranked constraints render as full
	// "- name: description" bullets in the Constraints section; the rest
	// collapse into one compact "+N more, equally binding" line that still
	// names every one. 0 disables the tiering (every constraint renders full,
	// the legacy behavior).
	ConstraintMaxFull int `yaml:"constraint_max_full" json:"constraintMaxFull"`
	// ConventionMaxFull is how many top-ranked conventions render as full
	// bullets in the budget-competing Conventions section; the rest stay
	// behind the section's count line ("recall kind=convention"). Starred
	// conventions always render full past the cap. 0 disables the tiering
	// (every convention renders full), matching ConstraintMaxFull semantics.
	ConventionMaxFull int `yaml:"convention_max_full" json:"conventionMaxFull"`
	// MemoryMaxAgeDays drops memory-index lines not updated within this many
	// days. 0 = no recency filter. Constraints and stages are exempt.
	MemoryMaxAgeDays int `yaml:"memory_max_age_days" json:"memoryMaxAgeDays"`
	// MemoryMaxItems caps the memory-index line count before budget packing.
	// 0 = budget-only (no cap).
	MemoryMaxItems int `yaml:"memory_max_items" json:"memoryMaxItems"`
	// FindingsCount is how many recent findings to inject. 0 hides the section.
	FindingsCount int `yaml:"findings_count" json:"findingsCount"`
	// FindingsMaxAgeDays drops findings older than this many days. 0 = no filter.
	FindingsMaxAgeDays int `yaml:"findings_max_age_days" json:"findingsMaxAgeDays"`
	// ReadyTasksShown is how many ready-task titles the ready line names.
	// 0 hides the line entirely.
	ReadyTasksShown int `yaml:"ready_tasks_shown" json:"readyTasksShown"`
	// PendingPlanMaxDays is how far back captured-but-unapproved Claude Code
	// plans earn "awaiting approval" lines. 0 = no age cutoff.
	PendingPlanMaxDays int `yaml:"pending_plan_max_days" json:"pendingPlanMaxDays"`
	// StageUnknownMaxAgeDays is the grace window (days since last update) a
	// stage memory stays pinned when its Status header is missing or not a live
	// gate (open/in_progress/blocked). Past it the stage leaves the briefing --
	// recall still finds it. 0 = pin forever (the historical behavior).
	StageUnknownMaxAgeDays int `yaml:"stage_unknown_max_age_days" json:"stageUnknownMaxAgeDays"`
	// HardCapMultiplier times budgets.max_briefing_tokens is the absolute
	// truncation ceiling. 0 falls back to 2.
	HardCapMultiplier int `yaml:"hard_cap_multiplier" json:"hardCapMultiplier"`
	// IncludeParentMemories folds a shared parent project's active memories
	// into a child project's briefing (the historical automatic behavior).
	IncludeParentMemories bool `yaml:"include_parent_memories" json:"includeParentMemories"`
	// SiblingFindingsCount is how many recent findings from family-member
	// projects to inject. 0 hides the section.
	SiblingFindingsCount int `yaml:"sibling_findings_count" json:"siblingFindingsCount"`
	// IncludeSiblingMemories folds family-member projects' active memories
	// (constraints and stages excluded) into the briefing as a low-priority
	// "Sibling memories" section. Off by default to avoid crowding.
	IncludeSiblingMemories bool `yaml:"include_sibling_memories" json:"includeSiblingMemories"`
	// UtilityWeight is utility's share of the briefing memory-index sort key:
	// (1-w)*recency + w*utility, both half-life-decayed to [0,1). 0 = pure
	// recency (the legacy order); constraints, stages, and favorites are pinned
	// regardless. Applies only where utility ranking is active (UtilityMode).
	UtilityWeight float64 `yaml:"utility_weight" json:"utilityWeight"`
	// UtilityMode gates the briefing's utility re-ordering: "auto" (default)
	// activates per project once the gardener's readiness latch trips, "on"
	// activates everywhere immediately, "off" disables it everywhere. The
	// bounded recall/prompt-recall boosts are not gated by this.
	UtilityMode string `yaml:"utility_mode" json:"utilityMode"`
}

Briefing tunes what the SessionStart briefing auto-injects: how many items each section carries, recency filters, related-project cross-over, and the hard-cap multiplier. Defaults reproduce the historical hardcoded behavior. The JSON tags back the console's runtime override row (see store.BriefingConfig), which layers on top of this file/env base.

The never-drop invariant: constraints and active-plan rollups are exempt from every filter here, and so is a pinned stage while its Status header marks a live gate -- recency and count filters apply only to the memory index, findings, and sibling sections. ConstraintMaxFull shapes how constraints render (full vs compact), never whether they appear. A stage with no live gate holds its pin only through the StageUnknownMaxAgeDays grace window.

func (Briefing) Validate

func (b Briefing) Validate() error

Validate rejects hard-invalid briefing knobs. Shared by the file/env load path and the console's settings form.

type BriefingPreset added in v0.5.3

type BriefingPreset struct {
	// Key is the stable identifier ("lean", "balanced", "rich").
	Key string
	// Label is the owner-facing name.
	Label string
	// Intent is one line saying who the preset is for.
	Intent string
	// Briefing is the full recipe.
	Briefing Briefing
}

BriefingPreset is a named, whole-struct briefing recipe the console offers as one choice. A preset sets every knob in Briefing and nothing else: the token budget (budgets.max_briefing_tokens) is config-only and no preset touches it.

func BriefingPresets added in v0.5.3

func BriefingPresets() []BriefingPreset

BriefingPresets returns the presets, leanest first, freshly allocated so no caller can mutate a shared table. Balanced is Defaults().Briefing exactly (a test asserts it), so a fresh installation is on a named preset from the start.

func MatchBriefingPreset added in v0.5.3

func MatchBriefingPreset(b Briefing) (BriefingPreset, bool)

MatchBriefingPreset reports which preset b is exactly, if any. An empty utility_mode means "auto" (the briefing treats them alike), so it matches as auto; every other knob must be equal.

type Budgets

type Budgets struct {
	MaxBriefingTokens  int `yaml:"max_briefing_tokens"`
	RecallBudgetTokens int `yaml:"recall_budget_tokens"`
	// ToolEventMaxChars caps each captured field (tool-call args value, result,
	// hook prompt, session findings) of an Interactions transport event at this
	// many runes. 0 = unlimited (the default): content is stored in full, and the
	// tool-event retention prune -- not truncation -- is the growth control.
	ToolEventMaxChars int `yaml:"tool_event_max_chars"`
}

Budgets holds token budgets for retrieval.

type Capture

type Capture struct {
	// AllowedPorts are the only destination ports capture_url may dial, enforced
	// on the initial URL and on every redirect hop. Empty is deliberately NOT
	// "any port": an unset key, an explicit `allowed_ports: []`, or an empty env
	// override all fall back to the 80/443 default, so the SSRF port guard cannot
	// be switched off by omission. Ports outside 1-65535 are rejected by Validate.
	AllowedPorts []int `yaml:"allowed_ports"`
}

Capture configures the SSRF-guarded URL fetch behind the capture_url tool. Unrelated to PlanCapture, which is about Claude Code plan mode.

type Config

type Config struct {
	// Addr is the HTTP bind address (host:port). Defaults to 127.0.0.1:8081.
	Addr string `yaml:"addr"`
	// DataDir holds the SQLite database and markdown trees. A leading ~ expands.
	DataDir string `yaml:"data_dir"`
	// Role is this install's part in a deployment: RoleServer (the default) runs
	// the daemon here; RoleClient runs none and dials AdvertisedURL instead.
	// Read it through IsClient, never by comparing this string.
	Role string `yaml:"role"`
	// AdvertisedURL is the base URL clients dial (yaml key `server_url`). Empty
	// means "derive it from Addr", which is what a loopback install wants. Set
	// it when the bind address is not the address clients use -- a wildcard
	// bind, a LAN name, a TLS listener. Read it through ServerURL, which applies
	// that derivation; this field is the raw configured value.
	AdvertisedURL string `yaml:"server_url"`
	// AllowedHosts are EXTRA Host-header values the daemon answers to, beyond
	// the loopback names, the concrete bind host, and ServerHost. Naming even
	// one turns the Host allowlist on for a wildcard bind (see hostGuard).
	AllowedHosts []string `yaml:"allowed_hosts"`
	// TLS makes the listener HTTPS and tells the CLI which root CA to trust.
	TLS TLS `yaml:"tls"`

	MCP         MCP         `yaml:"mcp"`
	Budgets     Budgets     `yaml:"budgets"`
	Briefing    Briefing    `yaml:"briefing"`
	Features    Features    `yaml:"features"`
	Console     Console     `yaml:"console"`
	Search      Search      `yaml:"search"`
	LLM         LLM         `yaml:"llm"`
	Gardener    Gardener    `yaml:"gardener"`
	Capture     Capture     `yaml:"capture"`
	PlanCapture PlanCapture `yaml:"plan_capture"`
	// contains filtered or unexported fields
}

Config is the fully-resolved Seamless configuration.

func Defaults

func Defaults() Config

Defaults returns the built-in configuration. File and env values are layered on top of these, so absent keys keep their default.

func EnsureAPIKey

func EnsureAPIKey(cfg Config) (Config, string, error)

EnsureAPIKey makes a true first run self-configuring: when no config file exists anywhere in the search order and SEAMLESS_MCP_API_KEY is absent from the environment, it generates a bearer key, writes it to ~/.config/seamless/seamless.yaml (0600), and returns the updated config plus the path it wrote. In every other case it changes nothing and returns "": a key already set, an owner-authored config file (even one with an empty key), or an env override (even set-but-empty) are never edited on the owner's behalf -- the existing empty-key warning paths stay in charge there.

func EnsureClientConfig added in v0.5.0

func EnsureClientConfig(url, key string) (Config, string, error)

EnsureClientConfig writes the config file that makes THIS machine a client of a seamlessd running somewhere else: `role: client`, the `server_url` clients dial, and the bearer key that server issued. It is `install-hooks --server-url`'s first-run step, and it returns the loaded result plus the path it wrote ("" when it wrote nothing).

It refuses in exactly the ways EnsureAPIKey refuses, for the same reason -- the config file is the owner's, and a bootstrap that edits one is a bootstrap that can silently repoint an install:

  • A config file anywhere in the search order is NEVER edited. The error names the file and the exact lines to add by hand. The one file that is not an error is one that already says exactly this (sameClientConfig): nothing is written there either, but there is also nothing to complain about, which is what keeps re-running the installer from failing.
  • The create is O_EXCL 0600, so a process that bootstrapped between the search and the create keeps its file. An identical client config is that race resolving in agreement and is returned as the winner; anything else is the same refusal, because silently adopting a file that points somewhere else would wire this machine to the wrong server.
  • No key is generated. A client's key belongs to the server it dials, so there is nothing valid to invent: the key comes from the key argument (--api-key), else from SEAMLESS_MCP_API_KEY, and neither present is an error rather than a config that cannot authenticate.

There is deliberately no data_dir: a client holds no corpus and opens no database.

func Load

func Load() (Config, error)

Load resolves configuration from the first config file found in the search order ($SEAMLESS_CONFIG, ~/.config/seamless/seamless.yaml, ./seamless.yaml), then applies SEAMLESS_* environment overrides and expands paths.

func LoadFrom

func LoadFrom(path string) (Config, error)

LoadFrom loads defaults, overlays the YAML file at path (if non-empty), applies environment overrides, and expands paths. An empty path uses defaults + env.

func (Config) AllowedHostsEffective added in v0.5.0

func (c Config) AllowedHostsEffective() []string

AllowedHostsEffective is the extra-Host allowlist the daemon answers to: the configured allowed_hosts, plus the host of a CONFIGURED server_url. The advertised host is in the list whenever it was named, because advertising a name the guard then rejects is a self-inflicted 421.

Loopback names and the concrete bind host are NOT here: hostGuard adds those itself, and they are facts about the listener rather than operator intent. That distinction is load-bearing. A DERIVED ServerHost is exactly one of those two -- loopback for a wildcard bind, the bind host for a concrete one -- so putting it in this list would add nothing the guard did not already allow while making the list non-empty, and a non-empty list is precisely what switches the guard on for a wildcard bind. The daemon would start refusing every Host but loopback on an `addr: 0.0.0.0` install where the operator named nothing at all.

Empty return = "the operator has named no host", which is the state hostGuard reads as "a wildcard bind cannot have an allowlist".

func (Config) DBPath

func (c Config) DBPath() string

DBPath is the SQLite database path.

func (Config) HTTPClient added in v0.5.0

func (c Config) HTTPClient(timeout time.Duration) (*http.Client, error)

HTTPClient is the one HTTP client constructor for talking to a Seamless daemon. Every surface that carries the bearer key goes through it -- the seam CLI's hook, mcp-proxy, doctor, status, version, console JSON and MCP dial, and seamlessd's own client-role surfaces (install-hooks reading the server's feature state, the client-role doctor's live tools/list count) -- because the TLS trust decision must be identical on all of them: an https server_url with a private CA either verifies everywhere or the install half-works in a way that reads as an intermittent network fault.

That sharing is the point, and it is load-bearing beyond tidiness: the alternative a caller reaches for when this constructor is out of import range is its own client, and the shortest such client is one that skips verification. A bearer key must never travel over a connection whose certificate was not verified, so the constructor has to be reachable from every binary that holds the key.

timeout is the whole-request deadline; 0 means none (the mcp-proxy bridge, whose tool calls can be LLM-slow). DialTimeout applies either way.

A configured-but-unusable tls.ca_file is an ERROR, never a silent fall back to the system pool: the request would then fail at the TLS handshake and look exactly like an outage, which is the local-vs-remote distinction AGENTS.md requires be kept (llm-degradation-remote-vs-local, same rule). The error names the config key, because the repair is in this machine's file and nowhere else.

func (Config) IsClient added in v0.5.0

func (c Config) IsClient() bool

IsClient reports whether this install runs no daemon of its own and dials a server elsewhere instead.

It is the single predicate every branching call site shares. An unset role is the default (server): absence means the default, and a role that is neither value never reaches here, because Validate refuses it at load.

func (Config) MemoryDir

func (c Config) MemoryDir() string

MemoryDir is the root of the per-project memory markdown tree.

func (Config) NotesDir

func (c Config) NotesDir() string

NotesDir is the root of the notes markdown tree.

func (Config) ServerHost added in v0.5.0

func (c Config) ServerHost() string

ServerHost is the bare host of ServerURL: no scheme, no port, no IPv6 brackets, lower-cased -- the form a Host header and a TLS SAN carry, and the form the Host allowlist compares against.

func (Config) ServerURL added in v0.5.0

func (c Config) ServerURL() string

ServerURL is the base URL (scheme://host[:port], no trailing slash) that clients -- the seam CLI, installed hooks, the MCP registration, the console opener, the published cards -- use to reach this install's daemon.

It is the single derivation: five copies of "split addr, map the wildcard to loopback, prefix http://" used to live in cmd/seam, cmd/seamlessd (twice), cmd/seambench and cmd/docsgen, and they had already drifted from each other on the malformed-addr edge. Bind address and client target are different questions that happen to have the same answer on a loopback install; keeping one derivation here is what lets the second question get its own answer (server_url) without hunting the first one down in five files. A configured server_url wins outright: it is the operator saying "this is where clients reach me", which is precisely the question no bind address can answer once the two differ (a wildcard bind, a LAN name, a reverse proxy).

func (Config) SourcePath

func (c Config) SourcePath() string

SourcePath returns the config file that was loaded, or "" if defaults+env only.

func (Config) TLSEnabled added in v0.5.0

func (c Config) TLSEnabled() bool

TLSEnabled reports whether the daemon serves HTTPS rather than HTTP -- which is what decides ServerURL's scheme, whether the console's session cookie may be marked Secure, and what the non-loopback bind warning may truthfully claim.

Both halves of the pair are required because serving TLS needs both; Validate refuses a half-set pair at load, so a lone cert_file can never quietly read as "no TLS" here.

func (Config) Validate

func (c Config) Validate() error

Validate rejects hard-invalid configuration. Soft issues (empty API keys) are surfaced as warnings by the doctor, not here.

type Console added in v0.5.3

type Console struct {
	// Level is how much of the console the owner sees: "basic" (the fewest
	// screens and knobs -- the default for a fresh installation), "standard"
	// (adds the coordination screens: tasks, plans, projects, the fleet view),
	// or "advanced" (every screen and knob, including the analytics and the
	// raw transport). Hidden screens stay reachable by URL; nothing is locked.
	// Empty means the default. An installation upgraded with sessions already
	// recorded is seeded "advanced" by a one-time store migration, so an
	// upgrade never hides a screen someone was using.
	Level string `yaml:"level" json:"level"`
}

Console tunes the human-facing observability console. Nothing here changes what agents receive: the console level is presentation only (briefings, MCP tools, hooks, the gardener, and recall are identical at every level).

The JSON tags back the console's runtime override row (see store.ConsoleLevel), which layers over this file/env base exactly like the features and briefing overrides: the row wins until the owner resets it.

func (Console) Validate added in v0.5.3

func (c Console) Validate() error

Validate rejects a present-but-unrecognized console level. Absent (empty) means the default, never a silent fallback for a typo.

type Features added in v0.4.10

type Features struct {
	// Research enables research labs and trials: the Labs and Trials console
	// screens, the trials search scope, and the lab_open, trial_record, and
	// trial_query MCP tools.
	Research bool `yaml:"research" json:"research"`
	// Momentum enables the gentle momentum surfaces woven into existing
	// screens: the plan finish-line card on Overview and its briefing
	// emphasis, the activity calendar with capture streaks, knowledge payoff
	// moments, and project maturity stages.
	Momentum bool `yaml:"momentum" json:"momentum"`
	// Gamification enables the arcade layer of the Now screen: the day tape,
	// the personal-records rail, the hot-streak pulse, and the celebration
	// moments.
	Gamification bool `yaml:"gamification" json:"gamification"`
}

Features toggles the OPTIONAL features -- the parts of Seamless the owner can switch on and off. Optional features ship OFF: a fresh installation exposes none of them until the owner enables one in the console (Settings -> Features) or in this file. Disabling hides a feature's console screens, its MCP tools, and any agent-facing mention of it; it never deletes stored data, and re-enabling restores every surface.

The JSON tags back the console's runtime override row (see store.FeaturesConfig), which layers over this file/env base. The surfaces each feature owns live in internal/features, not here -- this struct is only the on/off state.

type Gardener

type Gardener struct {
	Enabled bool `yaml:"enabled"`
	// IntervalMinutes is the ticker period between full gardener passes.
	IntervalMinutes int `yaml:"interval_minutes"`
	// DedupThreshold is the cosine-similarity floor at/above which two active
	// memories are proposed for a merge.
	DedupThreshold float64 `yaml:"dedup_threshold"`
	// StalenessDays is the no-activity age (no update, injection, or read) beyond
	// which an active memory is proposed for archiving.
	StalenessDays int `yaml:"staleness_days"`
	// DigestDays is the trailing window of completed sessions rolled into a
	// monthly digest proposal.
	DigestDays int `yaml:"digest_days"`
	// ToolEventRetentionDays is the age beyond which transport-level Interactions
	// events (tool.call, hook.prompt) are pruned by the gardener. 0 disables the
	// prune; domain events are never pruned regardless.
	ToolEventRetentionDays int `yaml:"tool_event_retention_days"`
	// StalePlanDays is the age beyond which a captured, never-approved Claude
	// Code plan (plan-status draft/presented) is proposed for abandonment.
	// 0 disables the pass.
	StalePlanDays int `yaml:"stale_plan_days"`
	// StaleStageDays is the age (days since last update) beyond which a stage
	// memory that is not a live gate -- Status done, missing, or unrecognized --
	// is proposed for archiving. Live gates (open/in_progress/blocked) are never
	// proposed regardless of age. 0 disables the pass.
	StaleStageDays int `yaml:"stale_stage_days"`
	// SessionIdleMinutes is the no-activity age beyond which an active session
	// is considered dead: the gardener reaper expires it and the console stops
	// counting it as live. It is the single liveness threshold shared by both,
	// so the reaper cutoff and the console "live" window never drift.
	// Must be positive. The fully resolved config already supplies 45 when the
	// key is absent, so zero is an explicit invalid value rather than a second,
	// silent spelling of the default.
	SessionIdleMinutes int `yaml:"session_idle_minutes"`
}

Gardener configures the propose-only maintenance passes and their ticker.

type LLM

type LLM struct {
	Provider  string    `yaml:"provider"`
	OpenAI    OpenAI    `yaml:"openai"`
	Ollama    Ollama    `yaml:"ollama"`
	Anthropic Anthropic `yaml:"anthropic"`
}

LLM configures chat (digests) and embeddings. OpenAI is the default provider.

func (LLM) EmbeddingModel added in v0.4.1

func (l LLM) EmbeddingModel() string

EmbeddingModel returns the embedding model the configured provider would use, or "" for a provider with no embeddings API (Anthropic) or an unknown one. It reports configuration, not capability: the provider may still lack the credential to actually serve it.

type MCP

type MCP struct {
	APIKey string `yaml:"api_key"`
}

MCP holds the static bearer key guarding /api/mcp and the console.

type Ollama

type Ollama struct {
	BaseURL        string `yaml:"base_url"`
	ChatModel      string `yaml:"chat_model"`
	EmbeddingModel string `yaml:"embedding_model"`
	EmbeddingDims  int    `yaml:"embedding_dims"`
}

Ollama is the local provider (chat + embeddings).

type OpenAI

type OpenAI struct {
	APIKey         string `yaml:"api_key"`
	BaseURL        string `yaml:"base_url"`
	ChatModel      string `yaml:"chat_model"`
	EmbeddingModel string `yaml:"embedding_model"`
	// EmbeddingDims is the model's native dimensionality; 0 = auto-detect from
	// the first embedding response.
	EmbeddingDims int `yaml:"embedding_dims"`
}

OpenAI is the first-class provider (chat + embeddings).

type PlanCapture

type PlanCapture struct {
	// Enabled turns the plan-capture hook endpoints into no-ops when false.
	Enabled bool `yaml:"enabled"`
	// AutoTask creates a tracking task ("Implement plan: ...") when a plan is
	// approved, composing it into the plan via plan_slug.
	AutoTask bool `yaml:"auto_task"`
	// InjectRelated returns related prior plans/memories as additionalContext on
	// a session's first captured plan iteration.
	InjectRelated bool `yaml:"inject_related"`
}

PlanCapture configures capturing Claude Code plan-mode iterations and planning subagents into notes via the PostToolUse/SubagentStop hooks.

type Search struct {
	// SemanticFloor is the minimum cosine similarity a semantic-only hit needs
	// to appear in search results; hits the lexical leg also matched are exempt.
	// Without it the cosine leg is pure nearest-neighbor -- there is always a
	// "nearest" item, so any query fills the page. 0 disables the floor. Useful
	// values depend on the embedding model; the default suits OpenAI
	// text-embedding-3-*.
	SemanticFloor float64 `yaml:"semantic_floor"`
}

Search tunes the human-facing console search (retrieve.Search). Agent-facing recall is deliberately not covered: an agent can judge a weak hit for itself, but an observer reads "20 results" as 20 matches.

type TLS added in v0.5.0

type TLS struct {
	// CertFile is the PEM certificate chain the daemon serves. A leading ~ expands.
	CertFile string `yaml:"cert_file"`
	// KeyFile is the PEM private key for CertFile. A leading ~ expands.
	KeyFile string `yaml:"key_file"`
	// CAFile is an extra root CA the seam CLI trusts when dialing an https
	// server_url. A leading ~ expands.
	CAFile string `yaml:"ca_file"`
}

TLS holds the daemon's HTTPS material and the client's extra trust root.

cert_file/key_file are a SERVER pair -- set both and the daemon serves HTTPS (TLSEnabled). ca_file is the CLIENT half: the root CA `seam` adds to the system pool so a self-signed or private-CA server certificate verifies. They are separate keys because the two halves live on different machines.

Jump to

Keyboard shortcuts

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