feat(settings): config-file-driven settings manifest + daemon RPC#186
Merged
Conversation
Add the daemon foundation for a comprehensive, config-file-driven settings surface that every frontend (web, TUI, later mobile) renders generically. - Declarative settings manifest (src/daemon/settings/manifest.ts): every user-tunable knob across tabs -> groups -> fields, including a per-backend tab for each of the six backends. Serves as the single source of truth so adding a knob is one entry, picked up by all clients. - Settings store (src/daemon/settings/store.ts): reads effective values with daemon precedence (env > config.json > default) and provenance; writes back atomically. Config patches are validated as a whole against the authoritative zod schema (one bad patch rejects the batch -> nothing written). Env/secret patches update ~/.codeoid/.env (0600), preserving comments. Secret VALUES are never returned to a client (presence + source only); process.env is updated live. - Protocol (@codeoid/protocol): settings manifest + snapshot types and the settings.schema / settings.get / settings.set messages, zod validation, and SETTINGS_READ / SETTINGS_WRITE scopes (operator gets read, not write). - Wire the three scope-gated RPC handlers into SessionManager. Both files (config.json + .env) stay directly hand-editable — the page is just a typed front-end over them. Tests: manifest integrity + a config-path drift guard, store read/write/ validate/secret handling, and handler scope gating. Full suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Gemini code reviewThis PR implements a declarative settings manifest and store in the daemon, exposing get/set/schema endpoints to the RPC layer with scope-gated security. While the architecture is sound and well-tested, there are a couple of edge cases in the naive .env file parser regarding multiline variables and double-quote backslash escaping. Findings: 🔴 0 · 🟠 0 · 🟡 1 · 🟢 1 Tokens spent · ⬆️ Input: 23,079 · ⬇️ Output: 591 · Σ Total: 36,631 |
…d-trip) Address the Gemini review on #186: - Reject env values containing a newline with a per-key error instead of splitting them across lines and corrupting .env (the format is single-line, matching loadDotEnv). - quoteEnv no longer escapes quotes. loadDotEnv strips one surrounding quote pair and never unescapes, so escaping broke the round-trip; wrapping-only round-trips even for embedded quotes (only the outer pair is stripped). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 16, 2026
saucam
added a commit
that referenced
this pull request
Jul 21, 2026
0.3.1 (#202) was cut as a version-bump-only release and shipped without a CHANGELOG entry. Backfill what it carried (placed between 0.3.2 and 0.3.0): the cross-backend MCP mounter (#197–#201), VWS memory across all backends (#179–#185), the config-driven settings surface (#186–#188), per-sandbox ZeroID registrar-key auth (#200), embed SSO via URL-hash handoff (#195), and the codex approval / fork-mode fixes (#181, #194, #196). Docs-only; no version change (0.3.1 is already tagged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
saucam
added a commit
that referenced
this pull request
Jul 21, 2026
0.3.1 (#202) was cut as a version-bump-only release and shipped without a CHANGELOG entry. Backfill what it carried (placed between 0.3.2 and 0.3.0): the cross-backend MCP mounter (#197–#201), VWS memory across all backends (#179–#185), the config-driven settings surface (#186–#188), per-sandbox ZeroID registrar-key auth (#200), embed SSO via URL-hash handoff (#195), and the codex approval / fork-mode fixes (#181, #194, #196). Docs-only; no version change (0.3.1 is already tagged). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The daemon foundation for a comprehensive, config-file-driven settings surface. This is PR 1 of 3 — the single source of truth that the web (Solid) and codeoid-ui (Rust) clients will render generically (mobile later). No UI in this PR.
The design goal (from the ask): a SOTA, config-file-driven settings screen with tabs for every supported backend and each backend's knobs, where power users can also edit the underlying files directly. This PR makes the daemon expose exactly that as a declarative manifest + read/write RPC, so a new knob is one manifest entry picked up by every client — no per-client edits, no drift.
How
src/daemon/settings/manifest.ts) — every user-tunable knob organizedtabs → groups → fields, including a dedicated per-backend tab for each of the six backends (Claude, Codex, Gemini CLI, pi, OpenAI, Gemini), plus General, Memory & Context (incl. the VWS context strategy), Fleet & Dispatch, Identity & Auth, Frontends, and Hooks. Each field declares itskind, backing store, config path / env var, default, bounds, help, and when a change takes effect (applies).src/daemon/settings/store.ts):config.jsonand the whole object is validated against the authoritative zod schema — one bad patch rejects the batch and nothing is written. Env/secret patches update~/.codeoid/.env(0600), preserving comments and unrelated keys.process.envis updated live so a subsequentgetreflects reality and per-session env knobs apply to new sessions without a restart.@codeoid/protocol) — manifest + snapshot types, thesettings.schema/settings.get/settings.setmessages with zod validation, and newSETTINGS_READ/SETTINGS_WRITEscopes.OPERATORgets read but not write (config can rewrite secrets + provider wiring — owner-only).SessionManager.handle.Design notes
~/.codeoid/config.json(validated) and~/.codeoid/.env(secrets + env-only knobs). The settings page is just a typed front-end over them — editing the files directly stays fully supported.config.jsonvia the UI, and their values are never sent to a client.appliessignal: config-backed fields are read once at boot, so they're markedrestart; per-session env knobs (context strategy, seed budget) arenext-session. The UI can show an accurate "restart to apply" banner..env. Promoting the hot ones to first-classconfig.jsonfields is a clean follow-up that won't change the manifest-driven UI.Tests
src/tests/settings.test.ts— manifest integrity + a config-path drift guard (every config-backed path is a real, correctly-typed schema location), store read/write/validate + secret handling (env-file vs external), and handler scope gating throughSessionManager.handle.scopes.test.ts/protocol.test.ts/schemas.test.tsupdated for the two new scopes and three new messages.bun run typecheck✅ ·bun run lint✅ ·bun run build✅ ·bun run test✅ (1473 pass / 0 fail)Follow-ups
🤖 Generated with Claude Code