Repository navigation
feat: let device users choose which configured programs are managed - #177
Merged
Merged
Conversation
Add `programSelection.allowUserChoice` to the daemon configuration (off by default). When it is on, the device user can opt out of every configured program, or keep only the ones they pick, with `agentdesktop programs set`. - The daemon stores the choice in its state directory and leaves the programs out before every apply, so each provider's existing cleanup removes only the files Agentdesktop owns. - Opted-out programs report a new `opted_out` state (proto, agent, controller) on every apply, so admins see it on the device page. - `GET /v1/programs` and `POST /v1/programs/choice` read and change the choice; a change re-applies right away and is reported to the controller. Refs #174
This was referenced Oct 15, 2026
There was a problem hiding this comment.
🟡 Changes recommended
Status publication ordering, one-shot validation, and automatic sign-in do not consistently respect program choices.
3 open findings
What changed in this PR
Adds policy-controlled program selection so device users can opt out of management while retaining fleet configuration.
Changes:
- Adds persistent choices and local API/CLI controls.
- Applies selections during reconciliation and reports
opted_out. - Documents policy behavior and adds focused tests.
| File | Description |
|---|---|
| schema/daemon-config.md | Documents selection policy. |
| schema/daemon-config.json | Adds selection policy schema. |
| README.md | Explains choices, persistence, and reporting. |
| crates/proto/proto/fleet.proto | Adds opted-out protocol state. |
| crates/core/src/model.rs | Defines choice and management models. |
| crates/core/src/config.rs | Adds policy configuration and tests. |
| crates/controller/src/database.rs | Maps and tests opted-out status. |
| crates/client/src/lib.rs | Supports JSON POST responses. |
| crates/agent/src/tick.rs | Shares current-configuration apply logic. |
| crates/agent/src/remote.rs | Supports opted-out status reporting. |
| crates/agent/src/reconcile/mod.rs | Filters programs and reports selections. |
| crates/agent/src/program_choice.rs | Persists and validates choices. |
| crates/agent/src/llm_proxy.rs | Updates test fixtures. |
| crates/agent/src/lib.rs | Registers choice storage module. |
| crates/agent/src/daemon.rs | Wires choice loading and controls. |
| crates/agent/src/cli.rs | Adds program selection commands. |
| crates/agent/src/api.rs | Adds management endpoints and tests. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
… sign-in - Number each apply under the apply lock and publish re-apply outcomes through one helper that never replaces a later apply's outcome, so a tick that finishes after a program choice change cannot report the old choice to the controller. - Validate `--once` against the chosen programs: an opted-out Copilot CLI or VS Code, or an opted-out gateway program, is only cleaned up. - Start no automatic gateway sign-in (startup, cached and pushed configuration) while the device user has opted out of every program that uses the gateway and no local LLM proxy runs; opting back in starts the device authorization that was skipped.
…ion (#178) - Device page: the "Managed programs" card labels the `opted_out` state "Opted out" with a neutral badge and a title explaining that the device user opted out of the program. - Configuration builder: a "Program selection" section with a "Let device users choose which programs are managed" checkbox. When checked, the generated YAML includes `programSelection: { allowUserChoice: true }`, and a notice warns that daemons predating the setting reject it. The checkbox is seeded from the active daemon configuration. - Rename the `.sandbox-compatibility` notice style to `.config-notice` so both sections share it. - Stories: a device with an opted-out program, a configuration seeded with `programSelection`, and an interaction test that toggling the checkbox adds and removes the key. Refs #174
Add a "Managed tools" card to the desktop Settings view, backed by the daemon's program management API. - Tauri commands `get_program_management` (GET /v1/programs) and `set_program_choice` (POST /v1/programs/choice) relay to the daemon. - The desktop model polls program management with the existing status poll and adds `setProgramChoice`, which shows the choice while saving and reports the daemon's error text when it refuses one. - When the policy allows a choice, the card offers All / Only these / None with a switch per configured tool; otherwise it lists the tools as managed by the organization. Each tool shows its last apply state, including "Opted out". - Stories cover each state, the choices sent, and the refused case. Refs #174
peterj
approved these changes
Oct 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Part of #174. Device users can now opt out of every program Agentdesktop manages, or keep only the ones they pick. A new policy switch decides whether they may.
What it does
programSelection.allowUserChoicein the daemon configuration (the local file or the one the controller pushes). It is off by default, and while it is off every configured program is managed, as today.agentdesktop programs set all|none|<program>.... The daemon stores it in<stateDir>/program-choice.json(0600). Withall, programs added to the policy later are managed too. Withnoneor a list, they stay unmanaged until the user chooses them.--once, dry run), the reconciler leaves out the programs the user opted out of. Each provider's existing cleanup then removes only the files it owns, including gateway routing, credential helpers, telemetry hooks and sandbox settings. Discovery is unaffected.opted_outprogram state (PROGRAM_STATE_OPTED_OUT = 8) is reported on every apply, so the controller's device page shows it steadily instead ofremovedonce. The controller stores states as integers, so no migration is needed; an older controller showsunspecified.GET /v1/programsreturns the switch, the choice, and each configured program with its last outcome.POST /v1/programs/choicechanges the choice. It returns 403 while the switch is off, 409 before the device has a configuration, and 400 for an unknown program.Turning the switch off keeps the stored choice but ignores it; turning it back on restores it.
Things to know
DaemonConfigdenies unknown fields, so a daemon older than this one rejects a pushed configuration that containsprogramSelection. The README and the schema say to upgrade devices first.Not in this PR
opted_outstate.Testing
opted_out.cargo fmt --check,cargo clippy --workspace --all-targets -D warnings, andmake generate-schemawith no diff.programs set claude-code,set noneandset allremoved and restored the files.setreturned 403.