Repository navigation
fix: write Claude Desktop managed settings to the Windows policy registry - #193
Conversation
| "properties": { | ||
| "config": { | ||
| "description": "Configuration file.", | ||
| "description": "Configuration file. On Windows the managed settings live in the\npolicy registry key instead, and this file is only removed when an\nearlier Agentdesktop wrote it.", |
There was a problem hiding this comment.
🟡 Changes recommended
Registry-name validation, partial-write ownership recovery, and completion reporting need correction to prevent unintended policy changes and inaccurate status reports.
4 open issues
What changed in this PR
Fixes #186 by directing Claude Desktop’s Windows managed settings to the machine policy registry instead of an ignored JSON file, while preserving Linux and macOS behavior.
Changes:
- Adds registry planning, application, ownership tracking, and cleanup.
- Integrates registry-backed settings with discovery, reconciliation reporting, and Windows tests.
- Documents the Windows target and cleanup of previously managed files.
| File | Description |
|---|---|
schema/daemon-config.md |
Documents Windows registry behavior. |
schema/daemon-config.json |
Updates the generated configuration description. |
crates/core/src/config.rs |
Clarifies the legacy settings-file option. |
crates/agent/src/reconcile/registry.rs |
Adds registry reads, writes, and cleanup primitives. |
crates/agent/src/reconcile/plan.rs |
Integrates registry operations into reconciliation plans. |
crates/agent/src/reconcile/mod.rs |
Adds registry failure attribution and integration tests. |
crates/agent/src/provider/claude_desktop/reconcile.rs |
Plans owned registry settings and legacy-file cleanup. |
crates/agent/src/provider/claude_desktop/mod.rs |
Configures the Windows policy target. |
crates/agent/src/provider/claude_desktop/discovery.rs |
Discovers managed MCP servers from the registry. |
crates/agent/src/bin/agentdesktop-service.rs |
Removes a redundant status-handle clone. |
crates/agent/Cargo.toml |
Enables Windows registry APIs. |
Review effort: Balanced
| let Value::Object(settings) = settings else { | ||
| anyhow::bail!("Claude Desktop managed settings serialize to an object"); | ||
| }; | ||
| // Value names are case-insensitive to the registry, so every case |
| "Claude Desktop setting name {REGISTRY_OWNER_VALUE} is reserved for Agentdesktop's ownership marker" | ||
| ); | ||
| } | ||
| Ok(settings |
| if status != ERROR_SUCCESS { | ||
| return Err(registry_error(status)) | ||
| .with_context(|| format!("write {}\\{name}", display.display())); |
| #[cfg(windows)] | ||
| for key_plan in self.registry.into_inner() { | ||
| let key_path = key_plan.key.display_path(); | ||
| super::registry::apply(&key_plan) | ||
| .map_err(|error| (error, ApplyStop::Registry(key_path.clone())))?; |
…stry On Windows Claude Desktop reads its managed configuration from flat REG_SZ values directly under HKLM\SOFTWARE\Policies\Claude, so the managed-settings file under /etc was a silent no-op there. The provider now plans registry value changes instead: strings as they are, other values as their JSON text. A .agentdesktop.owner value lists the names Agentdesktop manages, so updates and removal touch nothing else, and the key is deleted only once nothing else remains in it. Any value under the key — the marker included — counts as machine policy to the app and shadows HKCU policy, so an empty managed set plans removal rather than leaving a marker-only key behind. Value names match case-insensitively, as the registry stores them. Dry runs show the pending registry changes like file diffs, and apply refuses when the key changed after planning. Also drops a redundant clone in agentdesktop-service that clippy flags (clone_on_copy) when building for Windows. Fixes agentdesktop-dev#186. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review round on agentdesktop-dev#193 (peterj + Copilot): - registry_values refuses names with an embedded NUL (RegSetValueExW would truncate to a different name than conflict checking and the ownership marker used), names past the registry's 16,383-character limit (the registry refuses them only after earlier values were written), names differing only in ASCII case (one registry value, two desired entries, no convergence), and data with an embedded NUL. - The ownership marker now brackets the writes: the first change claims every name the plan touches, so an apply that fails midway leaves everything already written claimed and recoverable; the claim shrinks to exactly the desired names last. - Per-program completion accounting now tracks registry key plans next to file operations: a program with pending registry work is Blocked, not Applied, when an earlier failure stopped the apply before the registry loop. - Lowercase "agentdesktop" in the new prose (schema regenerated). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6a01ad1 to
4120948
Compare
|
Review addressed in 4120948 (also rebased onto main): name validation (NUL, length, case-duplicates) now happens at planning, and the ownership marker is written first so a partial apply stays claimed and recoverable — I chose that over rollback since a registry rollback can itself fail. Registry work now counts in per-program completion reporting; CI incl. the Windows job is green. |
…e test Since #193 a Windows system daemon writes Claude Desktop's managed settings to the HKLM policy registry key instead of a file. The mixed-mode test seeds system-mode files through full_reconciler, so on Windows it targeted the live machine policy key and left no claude-desktop directory to snapshot, failing with NotFound. Point it at a disposable test key and include the key's values in the Claude Desktop snapshot. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Add Pi discovery and managed gateway configuration Detect the pi.dev coding-agent harness (@earendil-works/pi-coding-agent), inventory MCP servers and skills, and reconcile user-level models.json and settings.json so Pi can use the LLM gateway with a request-time credential helper. * docs: add Pi inventory screenshots for review Local Agent Desktop Tools view of Pi 0.85.1 with MCP and skills. * Include Pi in the controller-managed example config The controller watches examples/claude/claude-code.yaml. Add programs.pi so the Configuration UI shows Pi next to Claude Code/Desktop. * docs: add controller Pi configuration screenshot * style: keep agentdesktop lowercase in Pi copy * style: wrap ToolsView empty-state copy for biome * fix: address Pi gateway configuration and discovery issues * fix: discover Pi PowerShell shims on Windows * fix: protect Pi credentials and replace managed model catalogs * Remove Pi screenshots and format rebased tool icons * fix: align Pi inventory with the files Pi loads Project MCP files stay in the working directory unless a user-global adapter config opts into ancestorConfigRoots. Skill discovery keeps .pi/skills in the working directory and stops .agents/skills at the git root. Validation rejects Pi combined with Claude Desktop or Grok Build, and rejects empty Pi model IDs before models.json is written. * Skip programs unsupported by the daemon mode * test(agent): widen the LOGIN lock probe margin in the device login test Token-store reads briefly hold LOGIN, and on macOS they go to the Keychain, which can exceed the 100ms probe under load. Give the probe 1s against a 1.5s provider delay: a lock held across the round-trip still fails it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(agent): isolate Claude Desktop policy key in mixed-mode reconcile test Since #193 a Windows system daemon writes Claude Desktop's managed settings to the HKLM policy registry key instead of a file. The mixed-mode test seeds system-mode files through full_reconciler, so on Windows it targeted the live machine policy key and left no claude-desktop directory to snapshot, failing with NotFound. Point it at a disposable test key and include the key's values in the Claude Desktop snapshot. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>


On Windows, Claude Desktop reads managed settings from
HKLM\SOFTWARE\Policies\Claude,not from
/etc/claude-desktop/managed-settings.json(which lands inC:\etc\...).The settings were silently ignored. Fixes #186.
On Windows the provider now writes flat registry values under that key (strings as
REG_SZ, everything else as JSON text). It tracks the values it owns, so removing asetting deletes only our values. If nothing is managed, the key is not created: any value
there switches the app to machine policy. Linux and macOS are unchanged.
Testing: unit tests for encoding and plan semantics, registry round-trips on Windows, the
full agent suite on Windows 11 (347 passed), and an end-to-end apply, dry run and removal
on Windows 11.
🤖 Generated with Claude Code