Skip to content

[AIGTWY-4290] Reconcile OS managed settings on workspace switch - #392

Open
david-siqi-liu wants to merge 1 commit into
mainfrom
david-l_data/AIGTWY-4290
Open

[AIGTWY-4290] Reconcile OS managed settings on workspace switch#392
david-siqi-liu wants to merge 1 commit into
mainfrom
david-l_data/AIGTWY-4290

Conversation

@david-siqi-liu

Copy link
Copy Markdown
Collaborator

Fixes the OS-managed-file lifecycle gap from #319: when a workspace publishes a managed coding-agent config with use_as_global_settings=true, ucode writes the agent's root-owned OS managed file (Claude: /etc/claude-code/managed-settings.json, Codex: /etc/codex/managed_config.toml). There was no inverse path, so switching to a workspace with no managed config (or one that drops global settings) left the prior workspace's config applying to a bare claude/codex.

What changed:

  • managed_files.py: write_managed_file snapshots each OS file's pre-ucode state into a machine-global ledger (~/.ucode/managed-os-backups.json) and commits that record only after a successful sudo write. New restore_managed_file puts the original back, or removes a file ucode created when there was no original. Drift-suppressed (no sudo when the file already matches) and nonfatal (permission or sudo failures warn and never block the private-config launch).
  • agents/init.py: reconcile_global_settings undoes the write for every global-settings agent the current config no longer marks global, so both claude and codex are reconciled regardless of which one is launched. An agent the config still wants global is left alone; its writer rewrites it.
  • cli.py: reconcile runs on launch (_launch_tool), on configure (_resolve_workspace_then_maybe_reject, including its early-return managed branch), and on bare ucode (_launch_managed_default, before its no-config early return). It is gated on the managed-config feature so --skip-managed-config does not tear down a config the workspace still publishes.

Design: this mirrors the reviewer-preferred approach on the #319 threads (save the original and restore it, rather than selectively pruning ucode's keys), which preserves unrelated IT-authored settings.

Known limitations (deliberately out of scope for this ticket):

  • Files written by a pre-ledger ucode version cannot be enrolled retroactively, since the true pre-ucode original was never recorded; a machine already carrying an old global write keeps it until the config next changes.
  • The ledger is per-user under ~/.ucode, matching state.json. Multi-user machines and concurrent launches share the single machine-global OS file without cross-user coordination, the same as the Global settings claude codex #319 write path.
  • An admin editing the OS file while ucode's config is active will have that edit replaced by the captured original on cleanup, which is the intended restore-original behavior.

Test plan:

  • New unit and integration tests cover: the capture/restore lifecycle, Claude and Codex workspace A to B cleanup, original values restored, a ucode-created file removed, unrelated IT keys preserved, cross-agent reconcile (launching one agent reconciles the other), same-workspace reconcile making no privileged call, missing files, sudo failure staying nonfatal, an unreadable original left untouched, a failed write recording no ownership, the feature-disabled path skipping reconcile, unsupported platforms staying safe, and reconcile wired at all three entry points.
  • Regression proof: disabling the reconcile call makes the launch wiring test fail.
  • Focused suites and the broad non-e2e suite pass locally via the checkout venv; CI runs the full unit gate including ruff check, ruff format, and ty.

This pull request and its description were written by Isaac.

@david-siqi-liu
david-siqi-liu marked this pull request as ready for review August 25, 2026 21:35
@david-siqi-liu
david-siqi-liu force-pushed the david-l_data/AIGTWY-4290 branch 2 times, most recently from a758171 to 5be0791 Compare August 26, 2026 16:37
…obal settings

ucode's write into an agent's OS-level managed file (under use_as_global_settings)
had no inverse: switching to a workspace whose managed config drops global settings
left the prior workspace's config applying to a bare `claude`/`codex`.

- managed_files: capture each OS file's pre-ucode state into a machine-global ledger
  on first write, and add restore_managed_file to put it back (or remove a file ucode
  created). Drift-suppressed and nonfatal, mirroring the reviewer-preferred "back up
  and restore the original" over selective key pruning.
- agents: reconcile_global_settings undoes the write for every global-settings agent
  the current config no longer marks global (both agents, whichever one launches).
- cli: reconcile on launch, on configure (incl. the early-return managed branch), and
  on bare `ucode` before its no-config early return.

Co-authored-by: Isaac <no-reply@databricks.com>
@david-siqi-liu
david-siqi-liu force-pushed the david-l_data/AIGTWY-4290 branch from 5be0791 to 8cd2104 Compare August 26, 2026 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant