Skip to content

Proposal: user-local and global config layers so personal settings are not committed #296

Open

Description

@skovtunenko

Problem

All UI settings except translation engines are persisted to openspec/.openspecui.json inside the project. As soon as I change the theme, editor, terminal or notification preferences, the file shows up in git status and is offered for commit. These are personal preferences: my teammates use different ones, so committing them either overrides their setup or creates constant churn in PRs.

Today the only workarounds are .git/info/exclude, git update-index --skip-worktree or a symlink, and none of them lets me keep the same personal settings across projects.

Current behavior (as of 4d8c007)

  • ConfigManager (packages/core/src/config.ts) reads and writes only <project>/openspec/.openspecui.json. The path is hardcoded, there is no CLI flag or env var to relocate it.
  • GlobalSettingsManager (packages/core/src/global-settings.ts) writes ~/.openspecui/settings.json, but its schema covers only translation, translationCache, translationEngines and servePresentation.
  • There is no merge or fallback between the two files.

Proposal

Introduce layered resolution for OpenSpecUIConfig, lowest to highest priority:

  1. Built-in defaults
  2. User global config: ~/.openspecui/config.json (respecting OPENSPECUI_HOME), same schema as OpenSpecUIConfig
  3. Project shared config: openspec/.openspecui.json (committed, team-wide, unchanged semantics)
  4. Project local config: openspec/.openspecui.local.json (personal, never committed)

Details:

  • Deep merge per key, the same way the current partial-override persistence already works.
  • The Settings UI lets the user pick the write scope: "All my projects" (global), "This project, only me" (local), "This project, shared with team" (shared). The default scope for new changes should be local or global, so personal changes do not touch the committed file unless explicitly requested.
  • Each setting shows where its effective value comes from, with a reset per layer.
  • On first write to .openspecui.local.json, add it to .gitignore (or at least document it and warn if it is not ignored).
  • All three files are watched reactively, as openspec/.openspecui.json is today.
  • Backward compatible: an existing openspec/.openspecui.json keeps working as the shared layer, no migration required.

Optionally, an env var such as OPENSPECUI_CONFIG to point the global layer to a custom file.

Acceptance criteria

  • Changing personal settings in the UI with the default scope does not modify any tracked file.
  • The same personal settings apply in every project without copying files.
  • Team-wide values (for example cli.command / cli.args) can still be committed in openspec/.openspecui.json.
  • README documents the layers, file paths and precedence.

Activity

  1. Gaubee commented on Oct 1, 2026

    @Gaubee
    Contributor

    Hi — thanks for the thorough proposal; the code references are accurate, and the problem (personal UI preferences surfacing in git status as churn) is real.

    A few notes mapping your proposal onto the current architecture, so the discussion has the right frame:

    • A user-global layer already exists, but only partially. GlobalSettingsManager (~/.openspecui/settings.json, with servePresentation, translation engines, and cache keys) was introduced for exactly the "personal, cross-project" concern — but as you note, it covers only a few keys while ConfigManager hardcodes the project file. Generalizing this split is the natural next step rather than inventing a new mechanism.
    • One boundary worth keeping crisp: OpenSpecUI's own settings (theme, editor, terminal, notifications — your layers 2/4) are separate from OpenSpec CLI-owned configuration (openspec config path, global defaultStore, Agent delivery policy), which this project deliberately never mirrors or rewrites. A layered design here should scope itself to OpenSpecUIConfig keys only.
    • Reactive watching of the new layers is cheap to promise: the physical reactive file writer/observer machinery already watches openspec/.openspecui.json and would extend to .openspecui.local.json and the global file.
    • Auto-editing .gitignore on first local write is the one point I'd want to discuss separately — silently modifying a tracked, team-visible file from a "personal settings" flow is a trust-boundary question, and a loud warning (plus documentation) may be the better default than an automatic edit.

    We're tracking this as a candidate change (config-layering). The v14 CLI adaptation line currently in flight (#297) doesn't touch ConfigManager's path resolution, so this proposal remains cleanly independent of it — no conflict either way. I can't commit to a timeline yet, but the acceptance criteria you listed are the right shape and would translate directly into the change's checkpoints.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions