Skip to content

fix: write Claude Desktop managed settings to the Windows policy registry - #193

Merged
peterj merged 2 commits into
agentdesktop-dev:mainfrom
LutzLange:fix/claude-desktop-windows-registry
Oct 23, 2026
Merged

peterj merged 2 commits into
agentdesktop-dev:mainfrom
LutzLange:fix/claude-desktop-windows-registry

Conversation

@LutzLange

Copy link
Copy Markdown
Collaborator

On Windows, Claude Desktop reads managed settings from HKLM\SOFTWARE\Policies\Claude,
not from /etc/claude-desktop/managed-settings.json (which lands in C:\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 a
setting 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

Comment thread schema/daemon-config.json Outdated
"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.",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "agentdesktop"

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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
Comment on lines +277 to +279
if status != ERROR_SUCCESS {
return Err(registry_error(status))
.with_context(|| format!("write {}\\{name}", display.display()));
Comment thread crates/agent/src/reconcile/plan.rs Outdated
Comment on lines +233 to +237
#[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())))?;
LutzLange and others added 2 commits October 23, 2026 09:34
…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>
@LutzLange
LutzLange force-pushed the fix/claude-desktop-windows-registry branch from 6a01ad1 to 4120948 Compare October 23, 2026 07:39
@LutzLange

Copy link
Copy Markdown
Collaborator Author

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.

@peterj
peterj merged commit 6fb7efe into agentdesktop-dev:main Oct 23, 2026
3 checks passed
sebbycorp added a commit that referenced this pull request Oct 23, 2026
…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>
sebbycorp added a commit that referenced this pull request Oct 23, 2026
* 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>
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.

Claude Desktop managed settings never reach Windows (written to /etc/..., the app reads HKLM\SOFTWARE\Policies\Claude)

3 participants