Summary
When you edit a team and deselect a member, a confirm dialog appears with three
buttons: Cancel, Keep agent, and Remove agent. The dialog text is "X will be
removed from this team. Do you also want to remove the agent completely?"
(desktop/src/features/agents/ui/RemoveMembersConfirmDialog.tsx:39-40).
What the dialog doesn't say is that "Remove agent" also deletes the agent's
nsec from the OS keyring. Unless the owner has a copy of the key somewhere
outside the app, the agent's identity is gone for good.
There is a second, smaller problem in the same flow: the loop that deletes the
removed personas swallows every error
(desktop/src/features/agents/ui/useTeamActions.ts:194-200, see the
"Best-effort" comment), so a partial or failed delete never surfaces.
To be clear, I'm not asking to change the cascade itself. The persona-to-agent
cascade is deliberate and covered by tests
(desktop/src-tauri/src/commands/personas/delete_cascade_tests.rs). The
problem is that an irreversible, key-destroying action sits behind a dialog
that reads like a routine membership question.
This bites hardest when a pre-existing agent was only temporarily added to a
team. The dialog treats that agent the same as one created for the team, and
since "Remove agent" is the button that completes the removal the user already
started, it's easy to read it as the thorough version of un-seating rather
than as identity destruction.
Steps to reproduce
- Create a managed agent and assign it to a team.
- Edit the team, deselect the agent, save.
- In the confirm dialog, click "Remove agent".
- The managed-agent record is deleted from
managed-agents.json and the nsec
is removed from the OS keyring (delete_agent_key,
desktop/src-tauri/src/commands/personas/mod.rs:238, inside
delete_persona, mod.rs:113). If the key existed nowhere else, the
identity is unrecoverable.
What we observed (real incident, 2026-08-03)
I removed a working agent from a team through this flow, expecting a
membership change. I did not register the third option as anything destructive
at the time; I only understood what it did when I retested the flow after the
loss. The result was the record and keyring nsec gone and the agent offline
for about 46 minutes.
We recovered only because I happened to keep a copy of the nsec outside the
app. With the key in hand we restored the record and then pulled the auth tag
and profile back off the agent's live kind:0 on the relay. Everything except
the nsec turned out to be recoverable. The private key is the single point of
no return.
That recovery path is not a product feature. The app's built-in NIP-49
encrypted backup (desktop/src-tauri/src/key_backup.rs) covers only the
user's own identity key per its module contract, and I couldn't find any
export or backup path for managed-agent keys (the agent-config layer masks
secrets by design). A user without an out-of-band copy of the agent's key
loses the identity permanently.
Expected behavior
- The destructive option should say plainly that it permanently deletes the
agent, its private key, and its configuration, and that this can't be
undone. Given that a key is being destroyed, typed confirmation or similar
friction seems proportionate.
- Errors from
deletePersona in the removal loop should be shown to the user
instead of dropped.
A soft-delete window before the keyring entry is destroyed would be a nice
follow-on, but it isn't needed to close this.
Offer
I can put up a small PR for the dialog wording and the error surfacing if
you're open to it.
Summary
When you edit a team and deselect a member, a confirm dialog appears with three
buttons: Cancel, Keep agent, and Remove agent. The dialog text is "X will be
removed from this team. Do you also want to remove the agent completely?"
(
desktop/src/features/agents/ui/RemoveMembersConfirmDialog.tsx:39-40).What the dialog doesn't say is that "Remove agent" also deletes the agent's
nsec from the OS keyring. Unless the owner has a copy of the key somewhere
outside the app, the agent's identity is gone for good.
There is a second, smaller problem in the same flow: the loop that deletes the
removed personas swallows every error
(
desktop/src/features/agents/ui/useTeamActions.ts:194-200, see the"Best-effort" comment), so a partial or failed delete never surfaces.
To be clear, I'm not asking to change the cascade itself. The persona-to-agent
cascade is deliberate and covered by tests
(
desktop/src-tauri/src/commands/personas/delete_cascade_tests.rs). Theproblem is that an irreversible, key-destroying action sits behind a dialog
that reads like a routine membership question.
This bites hardest when a pre-existing agent was only temporarily added to a
team. The dialog treats that agent the same as one created for the team, and
since "Remove agent" is the button that completes the removal the user already
started, it's easy to read it as the thorough version of un-seating rather
than as identity destruction.
Steps to reproduce
managed-agents.jsonand the nsecis removed from the OS keyring (
delete_agent_key,desktop/src-tauri/src/commands/personas/mod.rs:238, insidedelete_persona,mod.rs:113). If the key existed nowhere else, theidentity is unrecoverable.
What we observed (real incident, 2026-08-03)
I removed a working agent from a team through this flow, expecting a
membership change. I did not register the third option as anything destructive
at the time; I only understood what it did when I retested the flow after the
loss. The result was the record and keyring nsec gone and the agent offline
for about 46 minutes.
We recovered only because I happened to keep a copy of the nsec outside the
app. With the key in hand we restored the record and then pulled the auth tag
and profile back off the agent's live kind:0 on the relay. Everything except
the nsec turned out to be recoverable. The private key is the single point of
no return.
That recovery path is not a product feature. The app's built-in NIP-49
encrypted backup (
desktop/src-tauri/src/key_backup.rs) covers only theuser's own identity key per its module contract, and I couldn't find any
export or backup path for managed-agent keys (the agent-config layer masks
secrets by design). A user without an out-of-band copy of the agent's key
loses the identity permanently.
Expected behavior
agent, its private key, and its configuration, and that this can't be
undone. Given that a key is being destroyed, typed confirmation or similar
friction seems proportionate.
deletePersonain the removal loop should be shown to the userinstead of dropped.
A soft-delete window before the keyring entry is destroyed would be a nice
follow-on, but it isn't needed to close this.
Offer
I can put up a small PR for the dialog wording and the error surfacing if
you're open to it.