Documentation
¶
Overview ¶
Package userconfig persists per-machine user preferences for the system tray (auto-start toggles, default project, self-update state) in a single JSON file under a hidden app directory in the user's home.
One installed binary = one config file. The directory is named after the running binary, so a user who installs the same app under two different names ("wick-manager", "client-tools") gets two separate configs without collision.
Path:
~/.<binary>/config.json
Settings here are machine-wide, not per-project. Per-project state (e.g., wick app data) still lives in the project's wick.db when launched from a project directory.
Index ¶
- func Dir(name string) (string, error)
- func Path(name string) (string, error)
- func ResolveDBPath(appName, customPath string)
- func ResolvePort(customPort int)
- func Save(name string, cfg Config) error
- type Config
- type HookCapability
- type HookInstanceConfig
- type ProviderInstance
- type ProviderStatus
- type ProvidersConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Dir ¶ added in v0.8.9
Dir returns the absolute per-app data directory. Empty name falls back to the running binary's basename.
func Path ¶
Path returns the absolute config file path for the given project name. Empty name falls back to the running binary's basename.
func ResolveDBPath ¶
func ResolveDBPath(appName, customPath string)
ResolveDBPath determines the SQLite DB path and sets DATABASE_URL so config.Load() picks it up wherever it is called next.
Resolution order (first non-empty wins, never overwrites a higher priority):
- DATABASE_URL env already set (explicit env / CI override) → untouched
- cfg.DatabasePath set (user edited database_path in config.json)
- <binary_dir>/wick.db when wick.yml exists next to the binary (project mode)
- ~/.<appName>/wick.db (standalone / downloaded binary)
func ResolvePort ¶
func ResolvePort(customPort int)
ResolvePort sets the PORT env from cfg.Port so config.Load() picks it up wherever it is called next.
Resolution order (first non-empty wins, never overwrites a higher priority):
- PORT env already set (explicit env / CI override) → untouched
- customPort > 0 (user edited port in config.json)
- fall through → env.go envDefault picks the built-in default (9425)
Types ¶
type Config ¶
type Config struct {
// AutoStartApp registers the binary with the OS so it launches at
// user login (Windows: Run registry, macOS: LaunchAgent plist,
// Linux: XDG autostart .desktop). Toggle from Preferences ▶ Auto-start app.
AutoStartApp bool `json:"auto_start_app"`
// Tray auto-start toggles — applied at the next tray launch.
AutoStartServer bool `json:"auto_start_server"`
AutoStartWorker bool `json:"auto_start_worker"`
// Self-update toggle.
AutoUpdate bool `json:"auto_update"`
// Port overrides the HTTP listen port. 0 = use env PORT or default 9425.
// Set this in config.json to pin a custom port without touching .env.
Port int `json:"port,omitempty"`
// LogRetentionDays controls how many days of per-day log files are
// kept. 0 = use built-in default (7). Set in config.json to override.
LogRetentionDays int `json:"log_retention_days,omitempty"`
// DatabasePath overrides the SQLite DB location. Empty = auto-detect.
// Auto-detect: binary dir has wick.yml → <binary_dir>/wick.db,
// otherwise ~/.<appName>/wick.db.
// Set this manually in config.json if you need a custom location.
DatabasePath string `json:"database_path,omitempty"`
// Update state — managed by the updater, not user-facing.
StagedUpdatePath string `json:"staged_update_path,omitempty"`
StagedUpdateVersion string `json:"staged_update_version,omitempty"`
// Providers holds per-AI-provider overrides for the agents module
// (claude / codex / gemini). Each provider keeps its own binary
// path override + extra args. Empty / nil = full auto-detect via
// PATH lookup.
Providers ProvidersConfig `json:"providers,omitempty"`
// ProviderStatuses caches the last-known Probe result per
// instance, keyed `<type>/<name>`. Survives restart so the
// Providers page renders instantly instead of waiting on cold
// `--version` spawns. Refresh policy is owned by the agents
// module — this layer is a dumb store. Empty / nil = no cache.
ProviderStatuses map[string]ProviderStatus `json:"provider_statuses,omitempty"`
}
Config is the on-disk shape. Add fields with `json:"...,omitempty"` so older config files keep working when the binary upgrades.
type HookCapability ¶ added in v0.9.5
type HookCapability struct {
Supported bool `json:"supported,omitempty"`
Verified bool `json:"verified,omitempty"`
ProbedAt string `json:"probed_at,omitempty"`
Error string `json:"error,omitempty"`
Scope string `json:"scope,omitempty"` // "bash+edit+mcp" | "shell-only" | "untested"
}
HookCapability is the persisted snapshot of one hook-event probe. Mirrors capability.Capability — kept here as a separate struct so the userconfig package stays self-contained (no import of internal/agents/capability, which would invert the dependency).
type HookInstanceConfig ¶ added in v0.9.5
type HookInstanceConfig struct {
Enabled bool `json:"enabled,omitempty"`
}
HookInstanceConfig is the user's stored intent for one hook event on one provider instance. Kept as a struct (not just a bool) so we can grow per-event knobs (mode, allowlist, per-tool override) without another schema migration.
type ProviderInstance ¶ added in v0.9.0
type ProviderInstance struct {
Name string `json:"name"`
BinaryPath string `json:"binary_path,omitempty"`
Disabled bool `json:"disabled,omitempty"`
ExtraArgs []string `json:"extra_args,omitempty"`
Env []string `json:"env,omitempty"`
// Hooks captures the user's intent per hook event: "do you want
// wick to route this hook through the gate?". Keys are event
// names (PreToolUse for the command gate today; future events
// like SessionStart land as additional keys without schema
// churn). Absent / Enabled=false means the provider's own
// permission flow applies — no hook config gets installed on
// spawn.
Hooks map[string]HookInstanceConfig `json:"hooks,omitempty"`
}
ProviderInstance is one named configuration of a provider type. Name must be unique within a single type ("claude" can have one "work" + one "personal" but two "work" entries collide).
BinaryPath: absolute path to the CLI binary. Empty = LookPath the canonical type name on PATH.
Disabled: hide from new-session pickers and refuse to spawn. Useful when an instance is detected but known broken.
ExtraArgs: extra CLI flags appended after the canonical headless flags, before --resume. Forwarded to the provider's Spawner.
Env: extra `KEY=VALUE` pairs merged into the subprocess env on every spawn. The primary use case is per-instance credentials (different ANTHROPIC_API_KEY between work and personal claude) without leaking those into the user's global shell env.
type ProviderStatus ¶ added in v0.9.0
type ProviderStatus struct {
Path string `json:"path"`
PathFound bool `json:"path_found"`
Version string `json:"version,omitempty"`
VersionErr string `json:"version_err,omitempty"`
ScannedAt string `json:"scanned_at,omitempty"`
VersionAt string `json:"version_at,omitempty"`
// Hooks captures the runtime capability check per hook event name.
// Keys are provider-agnostic event names ("PreToolUse",
// "SessionStart", ...). Empty map = never probed, UI surfaces
// "click Test to verify".
Hooks map[string]HookCapability `json:"hooks,omitempty"`
}
ProviderStatus is the persisted shape of a Probe result.
Hooks holds per-event capability info (currently just "PreToolUse" for the command gate; future events like "SessionStart" or "UserPromptSubmit" land as additional map keys without struct churn). Persisting it here means the Providers page renders the gate-toggle state from disk without re-spawning the provider on every render — same TTL strategy as the version probe. Re-probe only fires when Version changes or the user clicks Rescan.
type ProvidersConfig ¶ added in v0.9.0
type ProvidersConfig struct {
Claude []ProviderInstance `json:"claude,omitempty"`
Codex []ProviderInstance `json:"codex,omitempty"`
Gemini []ProviderInstance `json:"gemini,omitempty"`
}
ProvidersConfig groups per-provider-type instance lists. One type (e.g. "claude") can hold multiple named instances so the user can run two different binaries / credential sets in parallel — typical case is a "work" claude on a corporate PAT next to a "personal" claude on a different PAT.
Bootstrap rule: on first boot the agents bootstrap auto-seeds one instance per supported type whose Name equals the type itself (`claude`, `codex`, `gemini`) with BinaryPath empty so LookPath resolves the canonical binary on PATH. Adding more instances is purely user-driven via the Providers page.