Files
kandev/docs/decisions/0018-runtime-settings-overrides.md
T

79 lines
3.6 KiB
Markdown

# 0018: Runtime settings overrides
**Status:** accepted (amended 2026-08-11)
**Date:** 2026-06-14
**Area:** backend, frontend, cli
## Context
`profiles.yaml` is the shipped source of runtime defaults for production, dev,
and e2e. It works well for releases and launch profiles, but users still need
an in-app way to opt into install-level feature toggles such as Office mode
without editing environment variables. Some toggles affect startup-time service
construction and route registration, so changing them safely requires a clear
restart model.
## Decision
`profiles.yaml` remains immutable shipped defaults. User changes are persisted
as install-level SQLite overrides and resolved at backend startup using this
precedence:
```text
explicit environment variable > persisted install override > profiles.yaml active profile > Go zero value
```
The backend owns a typed runtime-flag registry with user-facing labels,
descriptions, stability metadata, risk descriptions, env-var names, and restart
requirements. The Feature Toggles UI renders that registry state rather than
hardcoding env-var behavior in React.
V1 exposed Office mode and Debug mode. Later registrations included the App
Status Bar, opt-in Authentication, and Claude background prompt handoff
experiment. The App Status Bar subsequently graduated from the registry into a
portable user Appearance preference; its key and environment variable remain
retired identities under
[ADR-2026-08-11-user-owned-status-bar-visibility](2026-08-11-user-owned-status-bar-visibility.md).
Office mode and the handoff experiment are marked experimental; Debug mode is
the user-facing toggle for debug behavior, including agent message debug logs.
Agent message logs are not a separate top-level toggle.
V1 toggle changes require restart. Restart is launcher/supervisor mediated:
- In CLI-managed modes (`kandev start`, `kandev run`), the Go backend requests
restart from the native launcher, and the launcher restarts its backend
child.
- In service-managed modes, restart delegates to systemd or launchd when the
backend can prove it is safe.
- If no supported supervisor is available, the UI shows manual restart
instructions.
The Go backend must not directly fork or exec an unmanaged replacement process,
because it does not own the web child process, launcher logs, browser URL, or
process-tree cleanup.
## Consequences
- Self-host deployment env remains authoritative and auditable.
- Users get a visible, reversible in-app override path.
- Startup-gated features keep predictable initialization semantics.
- The UI can distinguish default, override, env-locked, and pending-restart
states.
- Restart support needs CLI/service coordination rather than a backend-only
handler.
- Feature Toggle mutations are restricted to admins, especially for Debug mode;
members may read effective state so the frontend can render consistently.
## Alternatives Considered
1. **Edit `profiles.yaml` from the UI.** Rejected. The file is embedded in
release artifacts and represents shipped defaults, not mutable user state.
2. **Let DB overrides beat environment variables.** Rejected. Deployment env is
the safest authority for managed/self-hosted installs.
3. **Make the backend spawn a replacement process.** Rejected. The Node launcher
or OS service manager owns the process tree.
4. **Expose every profile knob.** Rejected for v1. Mock providers and e2e
tuning are test infrastructure, not user-facing Feature Toggles.
5. **Show agent message logs as a separate toggle.** Rejected. It is a debug
sub-behavior and would duplicate the Debug mode mental model.