-
Notifications
You must be signed in to change notification settings - Fork 4.2k
feat(desktop): add device-local agent hosting policy - #7419
feat(desktop): add device-local agent hosting policy #7419lechnertech-mike wants to merge 4 commits into
Conversation
Signed-off-by: Michael Lechner <25083998+lechnertech-mike@users.noreply.github.com>
Signed-off-by: Michael Lechner <25083998+lechnertech-mike@users.noreply.github.com>
🔐 Codex Security Review
Status: review required for the current range.
The current range is
3c7f288c60d67df78577b237e27c3dfc8831aaa1...76a1a6e40c3dd3c9c3018748aa1515d8b96ebe3a.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 76a1a6e40c3dd3c9c3018748aa1515d8b96ebe3ato authorize a new review.
Any previous review applies only to its recorded range.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
i️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6144b1983
i️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Michael Lechner <25083998+lechnertech-mike@users.noreply.github.com>
lechnertech-mike
commented
Sep 6, 2026
@codex review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 99a6ef5d92
i️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2 Badge Scope protected identities to their configured community
Pass the active relay and owner into this guard before matching a preferred entry. As written, relay_url and owner_pubkey are ignored, so after configuring Scout for owner A on community A, switching the same Desktop to owner/community B still prevents creating, editing, or hosting an unrelated Scout there. This makes a community-scoped binding behave as an installation-wide name reservation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This guard intentionally uses the installation-wide local hosting namespace. unique_names::preflight also rejects same-name local records and personas before querying the owner/community directory. Scoping the entire guard would additionally allow an exact protected key or definition to become locally runnable after an account/community switch.
relay_url and owner_pubkey scope discovery preferences; they do not partition the local hosting catalog. I clarified this explicitly in docs/agent-device-policy.md in 76a1a6e. I am keeping that behavior in this PR. Supporting unrelated same-name local agents across communities would require a consistent change to the local catalog collision rules as well as this guard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2 Badge Validate preferred public keys when loading the policy
Reject semantically invalid preferred bindings here rather than accepting any strings that deserialize. The documented setup requires hand-editing this file, and a typo in preferred_agents[].pubkey is later forwarded by complete_search as a Nostr authors filter; the relay cannot deserialize that filter and the entire matching people search fails instead of reporting a recoverable policy-load error.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 76a1a6e. Policy loading now validates both preferred public-key fields and canonicalizes valid hex values. Malformed values return a recoverable policy-load error identifying the binding index and field, without forwarding them into a relay authors filter or echoing the supplied value.
The regression reproduced accepting an invalid public key before the fix and now covers malformed agent/owner keys plus uppercase normalization. Full just ci passed, and the final diff received independent review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2 Badge Reap existing processes before skipping client-only restore
Run the restore housekeeping before returning for client-only mode, and suppress only the later spawn phase. If the user saves client-only mode and Desktop crashes before graceful shutdown, the next launch returns here before kill_stale_tracked_processes and the three orphan sweeps, allowing the old agent process tree to keep responding and accessing local resources until the periodic sweeper eventually catches it one or two intervals later.
AGENTS.md reference: AGENTS.md:L194-L202
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 76a1a6e. Client-only mode now executes the existing tracked-process cleanup and orphan sweeps before suppressing restoration. Changed lifecycle state is saved; no restore candidates proceed to the spawn phase. Errors returned by the preparation step propagate.
Regression tests exercise the production cleanup/restore decision seam and reproduced both skipped housekeeping and swallowed cleanup errors before the fix. They verify ordering and suppression; they do not claim a live crash/process-termination test. Full just ci passed, and the final diff received independent review.
Signed-off-by: Michael Lechner <25083998+lechnertech-mike@users.noreply.github.com>
lechnertech-mike
commented
Sep 6, 2026
@codex review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76a1a6e40c
i️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1 Badge Preserve deletion recovery while selective sync is active
When tombstone_managed_agent_pending hits a transient SQLite error after the managed-agent record has already been removed, it still logs and swallows that failure; this new early return also disables reconcile_deleted_heads, so unique-name mode has no later path that can reconstruct the missing kind:5/kind:9035 work and the deleted agent can remain visible indefinitely. The fresh evidence beyond the earlier registry finding is that eligibility is now prepared, but the actual deletion-journal write can still fail without propagation or retry.
AGENTS.md reference: AGENTS.md:L167-L174
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2 Badge Keep people discovery usable after policy load failures
If the manually edited device-policy file is malformed, unreadable, or oversized, active() returns its cached error here before any relay request. Consequently ordinary people search—including mention autocomplete and recipient pickers—fails completely rather than merely disabling local hosting; list_relay_agents and list_personas propagate the same error. Treat policy-load failures as fail-closed for execution while allowing these non-hosting reads to proceed without preference filtering so users can still interact with remote identities and recover in Settings.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2 Badge Reject persona renames that duplicate linked identities
When unique-name mode is enabled on an installation that already has multiple instances linked to the same persona and more than one still carries the persona's display name, this preflight validates only the current records against the proposed name. Because none has the new name yet, the check passes, and propagate_persona_name_rename subsequently assigns that same new name to every matching linked record, creating duplicate local identities despite unique-name mode. Validate the complete prospective cascade and reject a rename that would assign one name to multiple pubkeys.
Useful? React with 👍 / 👎.
Uh oh!
There was an error while loading. Please reload this page.
Summary
When two Desktops use the same owner account, the second installation can create another instance of an agent already hosted elsewhere. Removing a copied definition can then publish a deletion to the shared account. This adds an opt-in device policy for a secondary Desktop: use remote agents in client-only mode, or host additional agents with distinct names while protecting explicitly selected remote identities.
Related issue
Related to #2648, #3440, and #5319. I searched existing issues and PRs before submission. The closest overlapping work is #6883 (adding existing remote agents to channels) and #6259 (showing the host computer). This proposal adds device-local execution and outgoing synchronization controls; it does not replace that discovery or host-label work.
Setup and scope
Existing remote identities must be entered explicitly in
agents/agent-device-policy.jsonaspreferred_agents. The UI discloses that an empty list does not stop copied local/autostart records; client-only mode is available to stop all local hosting until bindings are configured. See the configuration guide.Local hosting reservations span the installation; the binding owner/community scopes discovery, not separate local hosting namespaces.
This is not a relay-wide lock or atomic name reservation: another unconfigured client can still create agents, including during simultaneous creation. Team imports/catalog publication require unrestricted hosting. Disabling both restrictions resumes retained synchronization after restart, as disclosed in Settings. Maintainer feedback on whether this opt-in policy fits the intended multi-device model would be welcome.
Testing
just cipassed on76a1a6e4: formatting/lint/static gates, workspace unit tests, desktop/web builds, 6,456 desktop tests, 3,204 native desktop tests (19 ignored), and 2,072 mobile tests.d6144b19(frontend unchanged by the review follow-up):pnpm exec playwright test tests/e2e/client-only-agents.spec.ts tests/e2e/remote-owned-mentions.spec.ts tests/e2e/mention-recipients.spec.ts --project=smoke --workers=1: 45 passed.git diff --checkpassed. Tests used isolated fixtures with live Buzz credentials removed from the test environment.The patch received an independent code review, including fresh runs of the nine policy model tests and six Settings component tests. Regression coverage includes an offline configuration edit that preserves the name, an offline rename that is refused, and the empty-protection disclosure.
Manual verification procedure for two test installations using the same owner account:
The automated browser checks and screenshots use isolated mock data. Live two-device delivery and runtime execution have not been verified for this PR revision.
UI
Before, on the current
maintree:Agent settings before
After, with unique-name mode and an explicit remote identity preference:
Agent settings after
After, showing the disclosure when no existing identities are protected:
Empty protection disclosure