Documentation
¶
Overview ¶
Session-lifetime composed-config cache: the single read source for one run.
Composes the global and per-project settings layers into one effective config (95).
Locates the project root by walking upward for the innermost .codemeld/settings.yaml marker.
Loads and validates settings/template YAML, classifying load failures.
Derives and validates <project>/.codemeld/settings.local.yaml, the per-user layer codemeld writes.
Validates settings.yaml against the embedded JSON Schema, reporting the dotted offending key.
Index ¶
- Constants
- Variables
- func BlockedPathAdd(home, item, heading string) any
- func BlockedPathRemove(home, path string, occurrence int) any
- func Compose(globalLayer, projectLayer map[string]any, localLayer ...map[string]any) (map[string]any, error)
- func CopyLayer(raw map[string]any) map[string]any
- func DiscoveredModelsPath(globalSettingsPath string) string
- func EnforceGlobalOnly(perProjectPath string, perProject map[string]any) error
- func FormatLoadError(path string, cat LoadFailure, err error, consequence LoadConsequence) string
- func FormatYAMLParseFailure(src []byte, err error, consequence LoadConsequence) string
- func LayerPermissions(raw map[string]any, kind permissions.LayerKind) ([]permissions.PermissionEntry, error)
- func LocalSettingsLockPath(projectRoot string) string
- func LocalSettingsPath(projectRoot string) string
- func LocateProjectRoot(cwd string, mode string) (root string, layers []string, warnings []string, err error)
- func PermissionDelete(dedupKey permissions.DedupKey) any
- func RewriteKey(path, key string, newValue any) (fsutil.AtomicWriteStep, fserrors.Category, error)
- func UpdateDiscoveredModelsProvider(path, providerID string, entry DiscoveredProvider) error
- func UpdateDiscoveredModelsProviderThen(path, providerID string, entry DiscoveredProvider, then func() error) error
- func Validate(yamlBytes []byte, filePath string) error
- func ValidatePermissionEntries(path string, raw map[string]any) error
- func WarnIfBroaderThan0600(path string)
- type AnchorReadError
- type Cache
- func (c *Cache) AgentInstructionsMaxFileBytes() int
- func (c *Cache) AgentMaxConcurrency() int
- func (c *Cache) AppendPermission(e permissions.PermissionEntry)
- func (c *Cache) Attribution() bool
- func (c *Cache) DeclaredCommands() []permissions.DeclaredCommand
- func (c *Cache) Discovery() string
- func (c *Cache) Favorites() []Favorite
- func (c *Cache) LayerPaths() []string
- func (c *Cache) LayeredPermissions() []permissions.PermissionEntry
- func (c *Cache) MaxToolOutputBytes() int
- func (c *Cache) ModeDefault() (mode string, configured bool)
- func (c *Cache) ModelActiveRaw() (any, bool)
- func (c *Cache) ModelLastUsedRaw() (any, bool)
- func (c *Cache) OpenRouterDataCollection() string
- func (c *Cache) OpenRouterMaxPrice(model string) (provider.MaxPrice, bool)
- func (c *Cache) OpenRouterSort() string
- func (c *Cache) Permissions() []permissions.PermissionEntry
- func (c *Cache) ProgramLookup() string
- func (c *Cache) ProjectRoot() string
- func (c *Cache) Provider(name string) (provider.ProviderEntry, bool)
- func (c *Cache) ProviderRetry() RetrySettings
- func (c *Cache) Providers() map[string]provider.ProviderEntry
- func (c *Cache) ReloadDiscoveredCatalog()
- func (c *Cache) RemovePermission(e permissions.PermissionEntry) bool
- func (c *Cache) RetentionDays() int
- func (c *Cache) SelectableCatalog() provider.Catalog
- func (c *Cache) SetAttribution(on bool) (PersistReason, fserrors.Category, error)
- func (c *Cache) SetLayeredPermissions(entries []permissions.PermissionEntry)
- func (c *Cache) SetModelActiveRaw(v any)
- func (c *Cache) SetModelLastUsedRaw(v any)
- func (c *Cache) SetOpenRouterConnection(baseURL, apiKey string)
- func (c *Cache) SetOpenRouterDataCollection(v string) (PersistReason, fserrors.Category, error)
- func (c *Cache) SetOpenRouterMaxPrice(model string, p provider.MaxPrice) (PersistReason, fserrors.Category, error)
- func (c *Cache) SetOpenRouterSort(v string) (PersistReason, fserrors.Category, error)
- func (c *Cache) SetProvider(id string, entry provider.ProviderEntry)
- func (c *Cache) SetRetentionDays(days int) (PersistReason, fserrors.Category, error)
- func (c *Cache) SetSharedTempFolders(allow bool) (PersistReason, fserrors.Category, error)
- func (c *Cache) SharedTempFolders() (allowed, answered bool)
- func (c *Cache) ToggleFavorite(target Favorite, want bool) ([]Favorite, PersistReason, fserrors.Category, error)
- func (c *Cache) VCSPreferred() string
- func (c *Cache) VCSPriority() []string
- func (c *Cache) WebResearch() WebResearchSettings
- func (c *Cache) WebResearchAPIKey() string
- type DiscoveredModel
- type DiscoveredModelsStore
- type DiscoveredProvider
- type Favorite
- type LoadConsequence
- type LoadFailure
- func LoadYAML(path string) (doc *ast.File, raw map[string]any, cat LoadFailure, err error)
- func LoadYAMLBytes(b []byte, path string) (doc *ast.File, raw map[string]any, cat LoadFailure, err error)
- func ValidateGlobalSettingsBytes(b []byte, path string) (raw map[string]any, cat LoadFailure, err error)
- func ValidateLocalSettingsBytes(b []byte, path string) (raw map[string]any, cat LoadFailure, err error)
- func ValidateProjectSettingsBytes(b []byte, path string) (raw map[string]any, cat LoadFailure, err error)
- type OpenRouterMaxPrice
- type PermissionDeleteOp
- type PersistReason
- type RetrySettings
- type WebResearchSettings
Constants ¶
const ( KeyPermissions = "permissions" KeyModelActive = "model.active" KeyModelLastUsed = "model.last_used" // KeyAuthOpenAIChatGPT is the codemeld-owned, global-only ChatGPT session // state stored under auth.openai-chatgpt. Pass a yaml-marshalable mapping value // to set it, or the AuthDelete sentinel to remove it (logout). KeyAuthOpenAIChatGPT = "auth.openai-chatgpt" KeyAttribution = "attribution" KeyRetentionDays = "sessions.retention_days" )
Codemeld-owned YAML keys per §Reserved Values "Codemeld-owned YAML keys".
const ( KeyOpenRouterRoutingDataCollection = "provider.openrouter.routing.data_collection" KeyOpenRouterRoutingSort = "provider.openrouter.routing.sort" KeyOpenRouterRoutingMaxPrice = "provider.openrouter.routing.max_price" )
const ( // DiscoveredModelsVersion is the current models.yaml schema version. It is written // on every store and lets future readers migrate or reject incompatible shapes. DiscoveredModelsVersion = 1 )
const KeyProviderPrefix = "provider."
Variables ¶
var AuthDelete any = authDeleteValue{}
AuthDelete is the newValue sentinel passed to Persist/RewriteKey with KeyAuthOpenAIChatGPT to delete the stored ChatGPT session instead of writing one. Deleting an absent session is a no-op success that creates no file.
var ErrReservedProviderID = errors.New("provider.openai-chatgpt is reserved; its credentials are stored under auth.openai-chatgpt, not as a provider entry")
ErrReservedProviderID is returned by RewriteKey/Persist when a caller tries to write provider.openai-chatgpt. That provider id is built-in and reserved; a user-defined provider.openai-chatgpt entry is rejected at load, and its session credentials are stored only under auth.openai-chatgpt. The writer refuses it regardless of caller so the credential-write path is fail-closed.
Functions ¶
func BlockedPathAdd ¶
func BlockedPathRemove ¶
func Compose ¶
func Compose(globalLayer, projectLayer map[string]any, localLayer ...map[string]any) (map[string]any, error)
localLayer is optional so the one production caller can adopt the third layer without changing shape; passing none composes exactly what two layers composed before.
func CopyLayer ¶
CopyLayer deep-copies a decoded settings layer so a snapshot retained past composition shares no structure with the map Compose merges.
func DiscoveredModelsPath ¶
DiscoveredModelsPath returns the path of the shared discovered-model store for the given global settings file. The store sits beside settings.yaml in the global config directory. An empty settings path yields "" so a caller with no known settings location skips the store. The path is local only — reading or writing it performs no network I/O; writer and reader derive their target from this same helper so they cannot drift.
func EnforceGlobalOnly ¶
EnforceGlobalOnly reports the first global-only key found in a decoded per-project settings map. The returned error's text matches the settings loader's schema-validation shape ("<file>: schema validation failed at <key>: <detail>") so callers render it with FormatLoadError under SchemaValidationError. It returns nil when the map carries no global-only key. Run it only on per-project maps after LoadYAML succeeds; the global file legitimately holds these keys.
func FormatLoadError ¶
func FormatLoadError(path string, cat LoadFailure, err error, consequence LoadConsequence) string
FormatLoadError renders the stderr message for a non-LoadOK category, returning "" for LoadOK. The category tokens are an internal classification and never appear in the result.
func FormatYAMLParseFailure ¶
func FormatYAMLParseFailure(src []byte, err error, consequence LoadConsequence) string
FormatYAMLParseFailure renders the same body FormatLoadError builds for a parse failure, without the path attribution, for a caller whose own error type supplies that attribution.
func LayerPermissions ¶
func LayerPermissions(raw map[string]any, kind permissions.LayerKind) ([]permissions.PermissionEntry, error)
LayerPermissions stamps provenance as the layer is read — before anything is concatenated or deduplicated — so it can never be claimed by the file's own content.
func LocalSettingsLockPath ¶
func LocalSettingsPath ¶
LocalSettingsPath returns the per-user settings file inside the project root the active discovery.boundary already resolved. It stats nothing and never walks.
func LocateProjectRoot ¶
func LocateProjectRoot(cwd string, mode string) (root string, layers []string, warnings []string, err error)
LocateProjectRoot resolves the project root for the given discovery boundary mode. cwd is the launch directory (the walk anchor), normalized to an absolute cleaned path; layers holds the discovered .codemeld/settings.yaml path (at most one). In project-root mode the walk skips non-anchor unreadable directories with a warning and stops at the innermost ancestor with a marker, falling back to the anchor if none match; an unreadable anchor yields a *AnchorReadError. Discovery is read-only.
func PermissionDelete ¶
func PermissionDelete(dedupKey permissions.DedupKey) any
PermissionDelete is the newValue passed to Persist/RewriteKey with KeyPermissions to remove the permission entry whose identity matches dedupKey, instead of appending one. Removing an entry that is absent — no file, no permissions: key, or no matching entry — is a no-op success that creates no file.
func RewriteKey ¶
RewriteKey persists one codemeld-owned YAML key (KeyPermissions, KeyModelActive, KeyModelLastUsed, KeyAuthOpenAIChatGPT, KeyAttribution, or a KeyProviderPrefix+name provider entry) into the file at path, preserving every other top-level or nested key, comment, and adjacent whitespace byte-for-byte per step (3). newValue is a permissions.PermissionEntry for KeyPermissions, or any yaml.Marshal-able payload (typically yaml.MapSlice with provider/id/effort in that order) for the two model keys. For a KeyProviderPrefix+name key newValue is a yaml.Marshal-able provider.ProviderEntry shape, schema-validated before any write; writing provider.openai-chatgpt is refused (ErrReservedProviderID). Returns (zero, zero, nil) on success; fsutil.WriteAtomic's (step, cat, err) unchanged on atomic-write failure; or (fsutil.LoadStep, best-effort cat, err) for any pre-write failure with the on-disk file untouched.
func UpdateDiscoveredModelsProvider ¶
func UpdateDiscoveredModelsProvider(path, providerID string, entry DiscoveredProvider) error
UpdateDiscoveredModelsProvider sets providerID's entry to models in the store at path, preserving every other provider's entry, and republishes the whole store owner-only and atomically under a sidecar lock. The read-merge-write happens under the lock so concurrent updates to different providers cannot lose each other's rows. It stamps the current schema version. An empty path is a no-op (nil error) so a caller with no known settings location silently skips persistence.
func UpdateDiscoveredModelsProviderThen ¶
func UpdateDiscoveredModelsProviderThen(path, providerID string, entry DiscoveredProvider, then func() error) error
UpdateDiscoveredModelsProviderThen sets providerID's store entry, runs then while still holding the discovered-models lock, and restores the exact prior store bytes if then fails. This lets callers pair the store write with a later durable write without allowing concurrent store updates to be clobbered by rollback.
func Validate ¶
Validate checks settings.yaml bytes against the embedded JSON Schema, using filePath only in error messages. Cross-reference checks (model.active / model.last_used) are intentionally not performed here.
func ValidatePermissionEntries ¶
ValidatePermissionEntries rejects a layer holding an entry the schema admits but ParseEntry does not. Cache builds its permission view from the composed config, where deduplication can drop an invalid layer entry behind an equivalent one from another layer, so the entry has to be parsed at its source to be rejected at all.
func WarnIfBroaderThan0600 ¶
func WarnIfBroaderThan0600(path string)
WarnIfBroaderThan0600 emits one advisory stderr warning when the file's mode exposes any group/other bit. The global settings file holds plaintext credentials — provider API keys and, under, ChatGPT session tokens (auth.openai-chatgpt) — so the warning names both rather than API keys alone. Advisory only: the file is never rewritten or chmod'd. Suppressed on Windows and when the file is absent. The final component is inspected without following it, so a settings path that is a symbolic link — which the readers reject rather than follow — never produces a warning derived from its target's mode.
Types ¶
type AnchorReadError ¶
AnchorReadError reports that the walk anchor (the launch CWD) could not be listed, so the upward walk never started.
func (*AnchorReadError) Error ¶
func (e *AnchorReadError) Error() string
func (*AnchorReadError) Unwrap ¶
func (e *AnchorReadError) Unwrap() error
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache is the single, session-lifetime read source for composed configuration. It is built once from the composed config and never re-reads files so external edits to the on-disk YAML are deliberately invisible for the run (Non-Goals: "no live config reload during a running session"). In-process permission grants and model selections made via the write-back methods are visible to subsequent reads immediately but are not persisted to disk by those methods, and there is no general reload API.
ToggleFavorite, SetAttribution, and SetSharedTempFolders are the exceptions: they durably write the global settings layer through the locked writer and replace the cached value only from that write's confirmed result.
func (*Cache) AgentInstructionsMaxFileBytes ¶
AgentInstructionsMaxFileBytes returns agent_instructions.max_file_bytes (default 65536).
func (*Cache) AgentMaxConcurrency ¶
AgentMaxConcurrency returns agent.max_concurrency (default 3).
func (*Cache) AppendPermission ¶
func (c *Cache) AppendPermission(e permissions.PermissionEntry)
AppendPermission adds an in-memory permission grant so it is visible to subsequent Permissions reads without re-reading config. The entry is taken already-typed: session-scoped grants that the on-disk parser rejects are stored here directly rather than round-tripped through it.
func (*Cache) Attribution ¶
func (*Cache) DeclaredCommands ¶
func (c *Cache) DeclaredCommands() []permissions.DeclaredCommand
func (*Cache) Discovery ¶
Discovery returns the discovery.boundary mode (default launch-dir-only when omitted).
func (*Cache) LayerPaths ¶
LayerPaths returns a copy of the ordered settings-layer paths that composed the session config; mutating it does not change the cache.
func (*Cache) LayeredPermissions ¶
func (c *Cache) LayeredPermissions() []permissions.PermissionEntry
func (*Cache) MaxToolOutputBytes ¶
MaxToolOutputBytes returns sessions.max_tool_output_bytes (default 65536, minimum 256).
func (*Cache) ModeDefault ¶
ModeDefault returns the resolved launch default interaction mode (mode.default) and whether the key was present in the composed config. When the key is absent or not a string the mode falls back to "build" with configured=false; callers map the boolean to the interaction_mode source (false -> "default", true -> "config"). Enum validity of the value is enforced upstream by the settings schema and downstream by the interaction_mode event, mirroring how Discovery returns the raw boundary string without re-validating the enum.
func (*Cache) ModelActiveRaw ¶
ModelActiveRaw returns a copy of the raw model.active value and whether it is set. The value is left unvalidated for the model package's shape and cross-reference checks.
func (*Cache) ModelLastUsedRaw ¶
ModelLastUsedRaw returns a copy of the raw model.last_used value and whether it is set, left unvalidated for the model package's checks.
func (*Cache) OpenRouterDataCollection ¶
func (*Cache) OpenRouterMaxPrice ¶
func (*Cache) OpenRouterSort ¶
func (*Cache) Permissions ¶
func (c *Cache) Permissions() []permissions.PermissionEntry
Permissions returns a copy of the in-memory permission list (composed on-disk grants plus any session grants appended this run); mutating it does not change the cache.
func (*Cache) ProgramLookup ¶
func (*Cache) ProjectRoot ¶
ProjectRoot returns the resolved project root used for this session.
func (*Cache) Provider ¶
func (c *Cache) Provider(name string) (provider.ProviderEntry, bool)
Provider returns a copy of the named provider entry and whether it is configured. The boolean distinguishes a missing provider from one configured with empty values, which model validation relies on.
func (*Cache) ProviderRetry ¶
func (c *Cache) ProviderRetry() RetrySettings
ProviderRetry returns the resolved provider.retry auto-retry settings, filled with the hard-coded defaults for any omitted key. Enum/range validity is enforced upstream by the settings schema; this mirrors the other accessors' "return the configured value or the default" contract.
func (*Cache) Providers ¶
func (c *Cache) Providers() map[string]provider.ProviderEntry
Providers returns a copy of every configured provider entry keyed by name; mutating the returned map or its entries does not change the cache.
func (*Cache) ReloadDiscoveredCatalog ¶
func (c *Cache) ReloadDiscoveredCatalog()
func (*Cache) RemovePermission ¶
func (c *Cache) RemovePermission(e permissions.PermissionEntry) bool
RemovePermission drops the first in-memory permission grant whose identity (DedupKey) matches e — the in-memory half of a grant revoke and the counterpart of AppendPermission — and reports whether it removed one. A caller that records a revoke needs that result: a false means the table never held the grant (a stale or duplicate request), so nothing was revoked to record. It matches a session grant the same way (the DedupKey carries grant_kind). Like AppendPermission it takes no lock of its own: a production caller mutating the live grant table must serialize this through the same holder that guards AppendPermission (bootstrap's syncGrants) so a concurrent prompt-gate append cannot race the removal. Previously returned Permissions slices are unaffected because Permissions clones before returning.
func (*Cache) RetentionDays ¶
RetentionDays returns sessions.retention_days (default 30).
func (*Cache) SelectableCatalog ¶
SelectableCatalog returns the merged selectable-provider catalog for this run: the configured provider.<name> entries plus the built-in providers that declare selectable models outside the provider: map (the OpenAI ChatGPT provider). It is the single cross-reference source for model validation, resume recovery, and no-selectable diagnostics, so a provider: openai-chatgpt selection validates against the built-in catalog rather than provider.openai-chatgpt.models. The returned catalog's accessors copy their entries, so the cached session view cannot be mutated through it.
func (*Cache) SetAttribution ¶
SetAttribution writes attribution to the global settings layer and, only once that write has succeeded, updates the session value Attribution reports. attribution is global-only (see firstGlobalOnlyViolation), so layerPaths[0] is both the sole source and the sole write target.
func (*Cache) SetLayeredPermissions ¶
func (c *Cache) SetLayeredPermissions(entries []permissions.PermissionEntry)
SetLayeredPermissions labels each effective grant with the nearest layer holding it, which is not the surviving copy's layer: deduplication keeps the farthest one. A session grant appended later carries no layer.
func (*Cache) SetModelActiveRaw ¶
SetModelActiveRaw replaces the cached raw model.active value so later reads see the new selection immediately. It updates only this value; shape validation stays in the model package and persistence in the shared persistence path.
func (*Cache) SetModelLastUsedRaw ¶
SetModelLastUsedRaw replaces the cached raw model.last_used value visible to later reads immediately; validation and persistence stay elsewhere.
func (*Cache) SetOpenRouterConnection ¶
func (*Cache) SetOpenRouterDataCollection ¶
func (*Cache) SetOpenRouterMaxPrice ¶
func (*Cache) SetOpenRouterSort ¶
The cache never holds "default": the client sends any non-empty Sort as provider.sort.
func (*Cache) SetProvider ¶
func (c *Cache) SetProvider(id string, entry provider.ProviderEntry)
SetProvider adds or replaces one composed provider entry and rebuilds the selectable catalog from the updated set, so a provider connected mid-session (via /connect, after its durable settings write) becomes selectable through the existing catalog surfaces — the model picker and /model — without a restart. It is the single-entry analogue of what NewCache does for the whole provider block: the rebuild runs through the same provider.BuildCatalog path, so a built-in selectable id (openai-chatgpt) still wins over a settings-shaped entry of the same name, and a configured provider with no settings model list picks up the ids discovered into the system-owned models.yaml store — so a /connect that writes models.yaml before this call makes those ids selectable now, with no restart. This does not persist anything — durable writes stay in config.Persist.
func (*Cache) SetRetentionDays ¶
func (*Cache) SetSharedTempFolders ¶
func (*Cache) SharedTempFolders ¶
func (*Cache) ToggleFavorite ¶
func (*Cache) VCSPreferred ¶
VCSPreferred returns vcs.preferred, or "" when unset.
func (*Cache) VCSPriority ¶
VCSPriority returns a copy of the vcs.priority tie-break order (default [git, hg, jj]); mutating it does not change the cache.
func (*Cache) WebResearch ¶
func (c *Cache) WebResearch() WebResearchSettings
func (*Cache) WebResearchAPIKey ¶
The API key must not be logged, emitted, or included in errors or tool results.
type DiscoveredModel ¶
type DiscoveredModel struct {
ID string `yaml:"id"`
DisplayName string `yaml:"display_name,omitempty"`
ContextWindow int64 `yaml:"context_window,omitempty"`
InputModalities []string `yaml:"input_modalities,omitempty"`
Capabilities map[string]any `yaml:"capabilities,omitempty"`
}
DiscoveredModel is one discovered model's whitelisted selection/capability metadata. Capabilities holds provider-specific fields (e.g. reasoning levels, verbosity) as a generic map so this package needs no provider-specific types. Producers should place only safe, non-secret values there; as a backstop the write path redacts secret-shaped keys and values (see sanitizeProvider) so auth material cannot reach the on-disk store.
type DiscoveredModelsStore ¶
type DiscoveredModelsStore struct {
Version int `yaml:"version"`
Providers map[string]DiscoveredProvider `yaml:"providers"`
}
DiscoveredModelsStore is the codemeld-owned, persisted discovered-model store. It is keyed by provider id so several providers share one file, and it carries only selection/capability metadata — never API keys, auth headers, prompts, or raw provider responses. The shape is deliberately generic (plain strings, ints, and a free-form capabilities map) so provider and bootstrap packages can populate it without internal/config depending on them.
func ReadDiscoveredModels ¶
func ReadDiscoveredModels(path string) (DiscoveredModelsStore, error)
type DiscoveredProvider ¶
type DiscoveredProvider struct {
RefreshedAt string `yaml:"refreshed_at,omitempty"`
Source string `yaml:"source,omitempty"`
Models []DiscoveredModel `yaml:"models"`
}
DiscoveredProvider is one provider's discovered model list plus optional, secret-free refresh metadata. RefreshedAt/Source are advisory only; consumers must still tolerate their absence.
type Favorite ¶
Favorite is one favorited provider/model pair as stored in ordered model.favorites entries. Identity is exact string equality on both fields, so the same model ID offered by two providers stays two distinct favorites.
type LoadConsequence ¶
type LoadConsequence string
LoadConsequence states what the failure did to the run in progress. The formatter cannot derive it: the same category aborts a launch from one caller and is only reported by another.
const LaunchAborted LoadConsequence = "codemeld did not start"
type LoadFailure ¶
type LoadFailure string
LoadFailure classifies a settings/template load outcome; its string values are the category tokens reported on stderr.
const ( LoadOK LoadFailure = "none" UnreadableFile LoadFailure = "unreadable_file" YAMLParseError LoadFailure = "yaml_parse_error" SchemaValidationError LoadFailure = "schema_validation_error" )
func LoadYAML ¶
LoadYAML reads and validates a settings or VCS-template YAML file, returning the comment-preserving AST and decoded raw map on success, or a non-LoadOK category and the underlying error on failure.
func LoadYAMLBytes ¶
func LoadYAMLBytes(b []byte, path string) (doc *ast.File, raw map[string]any, cat LoadFailure, err error)
LoadYAMLBytes validates settings or VCS-template YAML the caller has already read. path names the source for diagnostics only and is never opened.
func ValidateGlobalSettingsBytes ¶
func ValidateGlobalSettingsBytes(b []byte, path string) (raw map[string]any, cat LoadFailure, err error)
ValidateGlobalSettingsBytes applies every global-layer rule to settings bytes the caller has already read under its own bound. path names the source for diagnostics only and is never opened, so a caller that reads through a hardened descriptor keeps that guarantee.
type OpenRouterMaxPrice ¶
type PermissionDeleteOp ¶
type PermissionDeleteOp struct {
Key permissions.DedupKey
Removed bool
}
type PersistReason ¶
type PersistReason string
PersistReason classifies the outcome of a Persist call in the vocabulary shared with the permission/model persist-failure events. ReasonNone covers a successful write; every other value is a distinct failure path.
const ( ReasonNone PersistReason = "none" ReasonLockTimeout PersistReason = "lock_timeout" ReasonLockAcquireError PersistReason = "lock_acquire_error" ReasonRereadParseError PersistReason = "reread_parse_error" ReasonRereadIOError PersistReason = "reread_io_error" ReasonWriteError PersistReason = "write_error" ReasonRenameError PersistReason = "rename_error" ReasonParentDirError PersistReason = "parent_dir_error" )
func Persist ¶
func Persist(targetPath, key string, newValue any) (reason PersistReason, errCat fserrors.Category, err error)
Persist is the single internal chokepoint for every folder/global permission write and every model.active/model.last_used write, implementing the protocol: ensure the parent directory, take a 2-second advisory lock on the dedicated sidecar lock file (targetPath+".lock"), re-read and validate the latest contents, byte-preservingly merge newValue into key, write atomically, and release the lock. newValue is the matching payload RewriteKey expects for key. For KeyPermissions that is either a permissions.PermissionEntry to append an entry or a PermissionDelete(dedupKey) sentinel to remove one — both take this same sidecar-lock + re-read-validate + atomic-replace path. The model keys take a yaml-marshalable value.
The lock is held on the sidecar — never on targetPath itself — because every write replaces the settings file's inode via atomic rename, which would orphan a lock taken on that inode and break mutual exclusion for three or more concurrent writers. The lock does NOT create the settings file; an absent settings file is created by RewriteKey's atomic write under the held lock ("Create-file-if-absent").
On success it returns (ReasonNone, "", nil). On failure it returns the reason, the error category, and the underlying error. lock_timeout and reread_parse_error carry no category (the failure did not originate in an OS file syscall); every other failure carries the category observed by the helper that hit the OS error. For reason reread_parse_error, reread_io_error, lock_timeout, or lock_acquire_error the merge/write is skipped entirely and the existing file is left untouched (special branch).
targetPath is treated as final: callers snapshot the project-root path when the triggering prompt is raised ("write-target snapshot") and pass it in Persist does not re-resolve project root. The TUI notice and the persist-failure event are the caller's responsibility, so Persist performs no logging or event emission of its own.
func PersistLocal ¶
func PersistLocal(projectRoot, key string, newValue any) (created bool, reason PersistReason, errCat fserrors.Category, err error)
PersistLocal is the single write path into the local settings file. created reports a write that made the file, derived from stats taken either side of the write rather than from inside Persist's lock window, so two processes creating it at once may both report it.
type RetrySettings ¶
RetrySettings is the resolved provider.retry auto-retry configuration: whether auto-retry is enabled, the total attempt cap (including the first), and the exponential-backoff base and cap in milliseconds. The per-turn retry wall-clock budget is not a settings knob — it has a fixed default applied at the turn layer.
type WebResearchSettings ¶
WebResearchSettings excludes the API key so formatted settings cannot disclose it.