Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ To configure specific tools without the picker, pass a comma-separated list:
ucode configure --agents claude,codex
```

Claude Code and Codex are configured locally by default. Their launches read any higher-precedence
OS-managed settings and block only when they conflict; launches never modify them or request
administrator access. To intentionally configure selected supported agents machine-wide, run:

```bash
ucode configure --sync-managed-settings
```

The normal agent picker still runs, and synchronization applies only to the selected Claude Code
and Codex agents. This can affect agents launched outside ucode, including editor extensions. A
later plain configure or `ucode revert` restores only the managed changes previously made by ucode,
preserving administrator changes.

Available agent names are `codex`, `claude`, `gemini`, `opencode`, `copilot`, and `pi`. `cursor` is also accepted (MCP-only — it registers Databricks MCP servers but configures no models).

Naming agents explicitly is treated as a request for all of them: if any one isn't available on the workspace, the run fails without configuring the others. Add `--skip-unavailable` to configure the available subset instead and skip the rest with a warning:
Expand Down Expand Up @@ -239,11 +252,11 @@ ucode publish # publish it to the workspace

`ucode setup` walks through the agents to enable and which one bare `ucode` launches, then per agent:
Databricks-hosted models or an external Model Provider Service and the models to expose. Interactive
Claude Code and Codex configuration installs gateway-critical values in the OS-managed settings
scope so enterprise settings cannot silently override ucode. Non-interactive and CI runs use local
files without invoking `sudo`, and stop with an actionable error if an existing managed value
conflicts. Claude subscription relay is local-only because its loopback proxy exists only for that
session.
Claude Code and Codex configuration uses local ucode files unless the user explicitly passes
`--sync-managed-settings`. Existing managed values are always checked because they take precedence;
conflicting values stop configuration or launch without being overwritten. Configure and launch
never invoke `sudo` without the explicit flag, and launches are always read-only. Claude subscription
relay is local-only because its loopback proxy exists only for that session.
Claude Code is asked one model per family (opus/sonnet/haiku/fable), since it selects models by family
alias; any family can be skipped.

Expand Down Expand Up @@ -337,6 +350,7 @@ The output looks like:
| `ucode revert` | Clear saved state and restore backed-up config files |
| `ucode configure --dry-run` | Preview config files without writing them |
| `ucode configure --agents claude,codex` | Configure specific agents without the interactive picker |
| `ucode configure --sync-managed-settings` | Explicitly synchronize selected Claude Code and Codex OS-managed settings; may require administrator access and affect agents outside ucode |
| `ucode configure --workspaces https://first.databricks.com,https://second.databricks.com` | Configure workspaces without the interactive picker |
| `ucode configure --profiles DEFAULT` | Configure using existing Databricks CLI profiles (hosts come from `~/.databrickscfg`) |
| `ucode configure --profiles DEFAULT --use-pat` | Authenticate with the profile's personal access token — no browser login |
Expand Down Expand Up @@ -379,8 +393,8 @@ control the installation.
|------|------|
| `~/.codex/ucode.config.toml` (or legacy `~/.codex/config.toml`) | Codex |
| `~/.claude/ucode-settings.json` | Claude Code settings generated by ucode |
| `/etc/claude-code/managed-settings.json` (Linux) or `/Library/Application Support/ClaudeCode/managed-settings.json` (macOS) | Claude Code OS-managed settings |
| `/etc/codex/managed_config.toml` | Codex OS-managed settings |
| `/etc/claude-code/managed-settings.json` (Linux) or `/Library/Application Support/ClaudeCode/managed-settings.json` (macOS) | Optional Claude Code OS-managed settings, changed only by explicit synchronization or restoration |
| `/etc/codex/managed_config.toml` | Optional Codex OS-managed settings, changed only by explicit synchronization or restoration |
| `~/.gemini/.env` | Gemini CLI |
| `~/.config/opencode/opencode.json` | OpenCode |
| `~/.copilot/.env` | GitHub Copilot CLI |
Expand All @@ -389,7 +403,8 @@ control the installation.
| `~/.ucode/managed-state.json` | The managed config — authored by `ucode setup` (admins) and refreshed from the workspace on launch |
| `~/.ucode/managed-backups/` | Baseline backups for OS-managed files changed by ucode |

Existing files are backed up before being overwritten. `ucode revert` restores backups.
Files changed by ucode are backed up first. `ucode revert` restores only ucode-owned changes and
preserves later administrator edits.


## Documentation
Expand Down
99 changes: 52 additions & 47 deletions docs/os-managed-settings-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ The two stacked PRs make precedence handling deterministic:
2. The Codex PR reuses that lifecycle for TOML, applies it to Codex, and removes the old optional
managed-settings path.

After both PRs merge, interactive configuration reconciles the agent's OS-managed file by default.
Non-interactive and CI execution never elevates privileges and instead uses local settings when the
managed file is compatible.
Claude and Codex configuration is local-only by default. OS-managed synchronization requires the
explicit `--sync-managed-settings` flag and applies to the supported agents selected by the normal
configure flow. Launches never write managed files or elevate privileges; they only verify that
existing higher-precedence values are compatible.

## Configuration Files

Expand All @@ -23,37 +24,38 @@ managed file is compatible.
| Claude Code | `~/.claude/ucode-settings.json` | Linux: `/etc/claude-code/managed-settings.json`; macOS: `/Library/Application Support/ClaudeCode/managed-settings.json` |
| Codex | `~/.codex/ucode.config.toml` | `/etc/codex/managed_config.toml` |

The local file is always written. The OS-managed file is additionally reconciled during interactive
configuration, except for Claude subscription relay.
The local file is always written. OS-managed files are changed only by explicit synchronization or
restoration, except for Claude subscription relay, which is always local-only.

## Interactive Detection
## Explicit Synchronization

An invocation may modify OS-managed settings only when standard input is a TTY. Standard output does
not affect the decision, so piping logs does not disable an otherwise interactive configuration.
CI, pipes, cron jobs, and headless subprocesses normally have non-TTY standard input and therefore
remain local-only.
`ucode configure` uses local settings. `--sync-managed-settings` is the user's explicit consent to
configure selected Claude Code and Codex agents machine-wide. The normal picker still runs when no
agents are named, and the command fails before agent installation or configuration when none of the
final selections support synchronization. Because a write may require administrator approval, an
actual change still requires standard input to be a TTY. An already-identical or compatible external
file needs no elevation.

This is a new shared ucode distinction. The previous implementation inferred interactivity from
command shape in some flows and did not guard managed-file writes consistently.
TTY state is only a privilege boundary; it does not select configuration scope and never changes
whether a cached launch is valid.

## Behavior Matrix

| Invocation | Managed file | Behavior |
| --- | --- | --- |
| Interactive | Absent | Create it from the ucode configuration after recording an absent baseline. |
| Interactive | Unrelated or partially populated | Preserve unrelated values and add or update all ucode-owned values. |
| Interactive | Conflicting | Back up the baseline, replace the conflicting ucode-owned values, and verify. |
| Interactive | Already identical | Continue without a backup, write, or `sudo` invocation. |
| Non-interactive | Absent | Use the local ucode file. Do not create the managed file. |
| Non-interactive | Ucode-owned values absent or equal | Use the local ucode file. Do not modify the managed file. |
| Non-interactive | Ucode-owned value conflicts | Stop before launching because the higher-precedence value would override ucode. |
| Plain configure or launch | Absent | Use the local ucode file. Do not create the managed file. |
| Plain configure or launch | Compatible | Use the local ucode file. Do not modify the managed file. |
| Plain configure or launch | Conflicting | Stop because the higher-precedence value would override ucode. |
| Explicit sync | Absent | Create it after recording an absent baseline. |
| Explicit sync | Last version written by ucode | Update and verify it. |
| Explicit sync | Compatible external file | Leave it untouched. |
| Explicit sync | Conflicting or externally modified file | Refuse to overwrite it. |
| Any | Invalid, unreadable, or symlinked | Stop without modifying the file because precedence cannot be established safely. |

`ucode configure`, first-time `ucode claude` or `ucode codex`, and later launches all use the same
agent-specific reconciliation path. A first-time launch from an interactive terminal can therefore
request administrator permission. A first-time non-interactive launch remains local-only.
First-time and later `ucode claude` and `ucode codex` launches use only the read-only compatibility
path. They never request administrator permission.

## Interactive Reconciliation
## Explicit Reconciliation

For each agent, ucode:

Expand All @@ -66,9 +68,9 @@ For each agent, ucode:
7. Reads the installed file back and verifies its exact contents.
8. Records the last-applied snapshot, owned paths, and a launch fingerprint.

An existing managed file is reconciled even when it does not currently conflict. This ensures every
ucode-required value exists at the highest-precedence scope and avoids separate behavior for absent,
partial, and conflicting files.
An existing file is updated only when it exactly matches ucode's last-applied snapshot. A compatible
external file remains untouched, and a conflicting or externally modified file is preserved and
reported.

## Privileged Write Transaction

Expand Down Expand Up @@ -124,9 +126,11 @@ If ucode cannot complete a write or revert, the backup remains available for a l
- Preserve externally changed values rather than replacing them with stale baseline values.
- Refuse an unsafe or unparsable merge and retain the backup.

A revert that needs to change an OS-managed file must run interactively. A successful revert removes
that agent's backup record. The existing local configuration and ucode state cleanup still occur as
part of the command.
A plain `ucode configure --agent claude` performs the same restoration before writing new local
settings, making it the opt-out path after explicit synchronization. A restoration that needs to
change an OS-managed file must run interactively. If restoration fails, local configuration can
continue, the backup remains available, and launches do not retry elevation. A successful
restoration removes that agent's backup record.

## Cached Launches

Expand All @@ -138,19 +142,19 @@ After a successful managed reconciliation or compatibility check, ucode stores:
- size;
- nanosecond modification and change times.

A cached launch performs one `stat()` call and compares this fingerprint. When it matches, ucode
does not read, parse, back up, write, or invoke `sudo`. When it changes, the normal reconciliation or
compatibility path runs again. This catches later MDM replacement without adding meaningful latency
to unchanged launches.
A missing managed file is valid without a fingerprint. For an existing file, a cached launch
compares its fingerprint. When it matches, ucode does not parse the file. When it changes, ucode
runs the read-only compatibility path again. Launches never back up, write, restore, or invoke
`sudo`.

The verification scopes distinguish:

- an interactively reconciled managed file;
- a managed file verified as compatible with local settings;
- a managed file verified as compatible with Claude relay.

A compatibility fingerprint created non-interactively cannot suppress the next interactive
reconciliation.
Compatibility fingerprints are valid independently of TTY state. Only the explicit synchronization
flag selects the write path.

## Claude Subscription Relay

Expand Down Expand Up @@ -178,15 +182,14 @@ standard Databricks authentication.
invalid, unreadable, missing, or unsupported;
- whether a managed baseline backup is available.

Interactive updates announce the backup location, administrator-permission request, and verified
result. An identical file produces no elevation message.
Explicit updates announce the backup location, administrator-permission request, and verified
result. An identical or compatible external file produces no elevation message.

Representative blockers are:

```text
Claude Code configuration cannot be applied non-interactively because OS-managed settings at
<path> override ucode values: env.ANTHROPIC_BASE_URL. Run `ucode configure --agent claude` from an
interactive terminal or contact your administrator.
Claude Code OS-managed settings at <path> override ucode values: env.ANTHROPIC_BASE_URL. ucode did
not modify the file during this launch. Contact your administrator.
```

```text
Expand All @@ -199,27 +202,29 @@ Cannot safely update Codex managed settings at <path>: <parse error>. ucode did
Repair it or contact your administrator.
```

Write, verification, parse, symlink, and managed-conflict failures block the agent launch. Recovery
information always identifies the file and recommends either an interactive configure/revert or
administrator help.
Parse, symlink, unreadable-file, and managed-conflict failures block launch. Write and restoration
failures occur only during explicit configure or revert operations. Recovery information identifies
the file and recommends configure, revert, or administrator help.

## PR Boundaries

### PR 1: Claude Code

- Add shared strict reads, fingerprints, compatibility checks, secure backups, atomic privileged
writes, immutable-flag handling, verification, status, and three-way revert helpers.
- Make interactive Claude configuration reconcile OS-managed JSON by default.
- Add non-interactive local fallback with conflict detection.
- Make Claude configuration local-only by default and add explicit managed synchronization.
- Make every launch read-only with conflict detection.
- Restore prior ucode-managed changes during plain configure and revert.
- Add Claude relay-specific safety checks.
- Add Claude managed status and revert output.
- Remove Claude's old managed-settings scope choice.

### PR 2: Codex

- Stack on the Claude PR and reuse the shared lifecycle with strict TOML parsing and serialization.
- Make interactive Codex configuration reconcile OS-managed TOML by default.
- Add non-interactive local fallback with conflict detection.
- Make Codex configuration local-only by default and add explicit managed synchronization.
- Make every launch read-only with conflict detection.
- Restore prior ucode-managed changes during plain configure and revert.
- Add Codex fingerprinted cached launches, status, and revert behavior.
- Keep opt-in smart-routing hooks in the local Codex config rather than adding them by default to
machine-managed policy.
Expand Down
Loading
Loading