Summary
The persona fold and the standalone-agent backfill can each create a definition for the same conceptual persona, stranding an orphaned duplicate. The Agents screen renders the orphan as a second card for the same agent in a permanent error state (red badge), with no hint it's a deletable leftover.
What the store ends up with
One agent ("Ron Swanson") after both migrations have run:
| record |
slug |
pubkey |
persona_id |
created by |
| definition A |
<agent pubkey hex> |
empty |
— |
backfill_standalone_agents (migration/backfill.rs — slug = pubkey by design) |
| definition B |
<uuid> |
empty |
— |
fold_personas_into_agent_store (migration/fold.rs — legacy persona id) |
| instance |
— |
<pubkey> |
<agent pubkey hex> |
linked to definition A |
Definition B is referenced by nothing: key-less, instance-less, permanently un-launchable. The UI shows it as a duplicate card with an error badge next to the healthy one.
Why it happens
fold_personas_in_dir dedupes folded personas by slug against the store — correct in isolation.
backfill_standalone_agents_in_dir targets instances with persona_id: None and manufactures a NEW definition slugged by the instance's pubkey, without first checking whether a just-folded definition already matches the instance (by name/prompt content). Result: the instance links to the manufactured definition and the folded one is orphaned.
Recurrence trigger
Anything that resurrects personas.json (restoring app data from a backup, or running a pre-fold build against the shared data dir) re-runs the fold and re-imports the UUID definitions — users see duplicates "come back" after cleaning up, which invites destructive app-data wipes.
Repro
- Pre-fold data dir:
personas.json with N custom personas + managed-agents.json with N standalone instances (persona_id: null).
- Boot a current build: fold imports N UUID-slugged definitions; backfill manufactures N pubkey-slugged definitions and links the instances to those.
- Agents screen: every agent appears twice; one card healthy, one erroring.
- Delete the orphans by hand, restore
personas.json from any backup, reboot → duplicates return.
Suggested fixes (any of)
- Backfill: before manufacturing, try to adopt an existing key-less definition matching the instance (name + prompt hash), and link to it instead.
- Boot-time GC (or one-shot migration): drop key-less, non-builtin definitions whose slug no instance references.
- UI: surface orphaned definitions as such ("no instance, from an old import") with a delete affordance instead of a generic error badge.
Workaround
Quit the app and filter managed-agents.json: remove records with empty pubkey whose slug is not builtin:* and is not any instance's persona_id.
🤖 Generated with Claude Code
Summary
The persona fold and the standalone-agent backfill can each create a definition for the same conceptual persona, stranding an orphaned duplicate. The Agents screen renders the orphan as a second card for the same agent in a permanent error state (red badge), with no hint it's a deletable leftover.
What the store ends up with
One agent ("Ron Swanson") after both migrations have run:
slugpubkeypersona_id<agent pubkey hex>backfill_standalone_agents(migration/backfill.rs — slug = pubkey by design)<uuid>fold_personas_into_agent_store(migration/fold.rs — legacy persona id)<pubkey><agent pubkey hex>Definition B is referenced by nothing: key-less, instance-less, permanently un-launchable. The UI shows it as a duplicate card with an error badge next to the healthy one.
Why it happens
fold_personas_in_dirdedupes folded personas byslugagainst the store — correct in isolation.backfill_standalone_agents_in_dirtargets instances withpersona_id: Noneand manufactures a NEW definition slugged by the instance's pubkey, without first checking whether a just-folded definition already matches the instance (by name/prompt content). Result: the instance links to the manufactured definition and the folded one is orphaned.Recurrence trigger
Anything that resurrects
personas.json(restoring app data from a backup, or running a pre-fold build against the shared data dir) re-runs the fold and re-imports the UUID definitions — users see duplicates "come back" after cleaning up, which invites destructive app-data wipes.Repro
personas.jsonwith N custom personas +managed-agents.jsonwith N standalone instances (persona_id: null).personas.jsonfrom any backup, reboot → duplicates return.Suggested fixes (any of)
Workaround
Quit the app and filter
managed-agents.json: remove records with emptypubkeywhoseslugis notbuiltin:*and is not any instance'spersona_id.🤖 Generated with Claude Code