diff --git a/desktop/src/features/agents/ui/AgentIdentityCard.tsx b/desktop/src/features/agents/ui/AgentIdentityCard.tsx
index b0668616a..ee11c9273 100644
--- a/desktop/src/features/agents/ui/AgentIdentityCard.tsx
+++ b/desktop/src/features/agents/ui/AgentIdentityCard.tsx
@@ -11,6 +11,7 @@ type AgentIdentityCardProps = {
avatarUrl?: string | null;
dataTestId: string;
label: string;
+ identityLabel?: string | null;
modelLabel?: string | null;
onClick: () => void;
/** Optional badge rendered below the label (e.g. "Restart required"). */
@@ -24,6 +25,7 @@ export function AgentIdentityCard({
avatarUrl,
dataTestId,
label,
+ identityLabel,
modelLabel,
onClick,
statusBadge,
@@ -72,6 +74,11 @@ export function AgentIdentityCard({
{label}
+ {identityLabel ? (
+
+ {identityLabel}
+
+ ) : null}
{modelLabel ? (
{modelLabel}
diff --git a/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx b/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx
index 47cb78c60..cf1f27fe2 100644
--- a/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx
+++ b/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx
@@ -8,18 +8,21 @@ import {
import { resolveAgentCardModelLabel } from "@/features/agents/lib/agentCardModelLabel";
import { friendlyAgentLastError } from "@/features/agents/lib/friendlyAgentLastError";
import { isManagedAgentActive } from "@/features/agents/lib/managedAgentControlActions";
-import { pickProfileAgent } from "@/features/agents/lib/pickProfileAgent";
import { useUserProfileQuery } from "@/features/profile/hooks";
import type { AgentPersona, ManagedAgent } from "@/shared/api/types";
import type { ProfilePanelOpenOptions } from "@/shared/context/ProfilePanelContext";
import { useFeedbackToasts } from "@/shared/hooks/useToastEffect";
+import { truncatePubkey } from "@/shared/lib/pubkey";
import { Badge } from "@/shared/ui/badge";
import { IdentityCardSkeleton } from "@/shared/ui/identity-card-skeleton";
import { AgentIdentityCard } from "./AgentIdentityCard";
import { AgentRuntimeAvatarControl } from "./AgentRuntimeAvatarControl";
import { CreateIdentityCard } from "./CreateIdentityCard";
import { PersonaActionsMenu } from "./PersonaActionsMenu";
-import { buildUnifiedGroups } from "./unifiedAgentGroups";
+import {
+ buildUnifiedGroups,
+ profileAgentsForGroup,
+} from "./unifiedAgentGroups";
type UnifiedAgentsSectionProps = {
defaultModel: string;
@@ -128,41 +131,96 @@ export function UnifiedAgentsSection(props: UnifiedAgentsSectionProps) {
disabled={isPersonasPending}
onClick={onOpenCatalog}
/>
- {groups.map((group) => {
- const profileAgent = pickProfileAgent(group.agents);
- return (
- (
-
- onSharePersona(persona, linkedAgent, effectiveAvatarUrl)
- }
- />
- )}
- agent={profileAgent}
- defaultModel={defaultModel}
- key={group.persona.id}
- persona={group.persona}
- restartingAgentPubkey={restartingAgentPubkey}
- startingAgentPubkey={startingAgentPubkey}
- startingPersonaIds={startingPersonaIds}
- onOpenAgentProfile={onOpenAgentProfile}
- onOpenPersonaProfile={onOpenPersonaProfile}
- onRestartAgent={onRestartAgent}
- onStartAgent={onStartAgent}
- onStartPersona={onStartPersona}
- />
- );
+ {groups.flatMap((group) => {
+ const profileAgents = profileAgentsForGroup(group.agents);
+ const cards: Array = [];
+
+ if (profileAgents.length === 0) {
+ cards.push(
+ (
+
+ onSharePersona(
+ persona,
+ linkedAgent,
+ effectiveAvatarUrl,
+ )
+ }
+ />
+ )}
+ agent={undefined}
+ defaultModel={defaultModel}
+ key={`persona:${group.persona.id}`}
+ persona={group.persona}
+ restartingAgentPubkey={restartingAgentPubkey}
+ startingAgentPubkey={startingAgentPubkey}
+ startingPersonaIds={startingPersonaIds}
+ onOpenAgentProfile={onOpenAgentProfile}
+ onOpenPersonaProfile={onOpenPersonaProfile}
+ onRestartAgent={onRestartAgent}
+ onStartAgent={onStartAgent}
+ onStartPersona={onStartPersona}
+ />,
+ );
+ return cards;
+ }
+
+ for (const [index, profileAgent] of profileAgents.entries()) {
+ cards.push(
+ (
+
+ onSharePersona(
+ persona,
+ linkedAgent,
+ effectiveAvatarUrl,
+ )
+ }
+ />
+ )
+ : undefined
+ }
+ agent={profileAgent}
+ defaultModel={defaultModel}
+ key={`agent:${profileAgent.pubkey}`}
+ persona={group.persona}
+ restartingAgentPubkey={restartingAgentPubkey}
+ startingAgentPubkey={startingAgentPubkey}
+ startingPersonaIds={startingPersonaIds}
+ onOpenAgentProfile={onOpenAgentProfile}
+ onOpenPersonaProfile={onOpenPersonaProfile}
+ onRestartAgent={onRestartAgent}
+ onStartAgent={onStartAgent}
+ onStartPersona={onStartPersona}
+ />,
+ );
+ }
+
+ return cards;
})}
@@ -309,6 +367,7 @@ function AgentPersonaCard({
}
avatarUrl={avatarUrl}
dataTestId={`persona-agent-row-${persona.id}`}
+ identityLabel={agent ? truncatePubkey(agent.pubkey) : null}
label={title}
modelLabel={modelLabel}
onClick={() => {
diff --git a/desktop/src/features/agents/ui/unifiedAgentGroups.test.mjs b/desktop/src/features/agents/ui/unifiedAgentGroups.test.mjs
new file mode 100644
index 000000000..1095d85bd
--- /dev/null
+++ b/desktop/src/features/agents/ui/unifiedAgentGroups.test.mjs
@@ -0,0 +1,71 @@
+import assert from "node:assert/strict";
+import test from "node:test";
+
+import {
+ buildUnifiedGroups,
+ profileAgentsForGroup,
+} from "./unifiedAgentGroups.ts";
+
+function agent(pubkey, overrides = {}) {
+ return {
+ pubkey,
+ name: overrides.name ?? "Fizz",
+ personaId: overrides.personaId ?? "builtin:fizz",
+ status: overrides.status ?? "stopped",
+ ...overrides,
+ };
+}
+
+const fizz = { id: "builtin:fizz", displayName: "Fizz" };
+
+test("buildUnifiedGroups retains every managed instance for one persona", () => {
+ const first = agent("a".repeat(64));
+ const second = agent("b".repeat(64));
+
+ const { groups, ungrouped, unknown } = buildUnifiedGroups(
+ [fizz],
+ [first, second],
+ );
+
+ assert.deepEqual(groups, [{ persona: fizz, agents: [first, second] }]);
+ assert.deepEqual(ungrouped, []);
+ assert.deepEqual(unknown, []);
+});
+
+test("profileAgentsForGroup returns every instance in stable order without mutating input", () => {
+ const stopped = agent("a".repeat(64), { name: "Zulu" });
+ const runningLater = agent("c".repeat(64), {
+ name: "Alpha",
+ status: "running",
+ });
+ const runningEarlier = agent("b".repeat(64), {
+ name: "Alpha",
+ status: "running",
+ });
+ const input = [stopped, runningLater, runningEarlier];
+
+ assert.deepEqual(profileAgentsForGroup(input), [
+ runningEarlier,
+ runningLater,
+ stopped,
+ ]);
+ assert.deepEqual(input, [stopped, runningLater, runningEarlier]);
+});
+
+test("a relay-restored persona instance follows the same visible group path", () => {
+ const relayRestored = agent("c".repeat(64), {
+ name: "Recovered Fizz",
+ status: "stopped",
+ });
+
+ const { groups } = buildUnifiedGroups([fizz], [relayRestored]);
+
+ assert.deepEqual(profileAgentsForGroup(groups[0].agents), [relayRestored]);
+});
+
+test("a persona with no managed instance remains an empty group", () => {
+ const { groups } = buildUnifiedGroups([fizz], []);
+
+ assert.deepEqual(groups, [{ persona: fizz, agents: [] }]);
+ assert.deepEqual(profileAgentsForGroup(groups[0].agents), []);
+});
diff --git a/desktop/src/features/agents/ui/unifiedAgentGroups.ts b/desktop/src/features/agents/ui/unifiedAgentGroups.ts
index 60c44f929..c48b42e22 100644
--- a/desktop/src/features/agents/ui/unifiedAgentGroups.ts
+++ b/desktop/src/features/agents/ui/unifiedAgentGroups.ts
@@ -1,3 +1,4 @@
+import { isManagedAgentActive } from "@/features/agents/lib/managedAgentControlActions";
import type { AgentPersona, ManagedAgent } from "@/shared/api/types";
type PersonaGroup = { persona: AgentPersona; agents: ManagedAgent[] };
@@ -32,3 +33,14 @@ export function buildUnifiedGroups(
return { groups, ungrouped, unknown };
}
+
+export function profileAgentsForGroup(agents: ManagedAgent[]) {
+ return [...agents].sort((left, right) => {
+ const activeDiff =
+ Number(isManagedAgentActive(right)) - Number(isManagedAgentActive(left));
+ if (activeDiff !== 0) return activeDiff;
+ const nameDiff = left.name.localeCompare(right.name);
+ if (nameDiff !== 0) return nameDiff;
+ return left.pubkey.localeCompare(right.pubkey);
+ });
+}
diff --git a/desktop/tests/e2e/agents.spec.ts b/desktop/tests/e2e/agents.spec.ts
index 7a3925eb6..c919f325c 100644
--- a/desktop/tests/e2e/agents.spec.ts
+++ b/desktop/tests/e2e/agents.spec.ts
@@ -226,6 +226,35 @@ async function countCommandInvocations(
);
}
+test("Agents view keeps every managed instance that shares a persona visible", async ({
+ page,
+}) => {
+ const personaId = "custom:multi-fizz";
+ const firstPubkey = "a".repeat(64);
+ const secondPubkey = "b".repeat(64);
+ await installMockBridge(page, {
+ personas: [
+ {
+ id: personaId,
+ displayName: "Fizz",
+ systemPrompt: "Move fast.",
+ },
+ ],
+ managedAgents: [
+ { pubkey: firstPubkey, name: "Fizz", personaId },
+ { pubkey: secondPubkey, name: "Fizz", personaId },
+ ],
+ });
+ await gotoApp(page);
+ await page.getByTestId("open-agents-view").click();
+
+ const cards = page.getByTestId(`persona-agent-row-${personaId}`);
+ await expect(cards).toHaveCount(2);
+ await expect(cards.nth(0)).toContainText("aaaaaaaa…aaaa");
+ await expect(cards.nth(1)).toContainText("bbbbbbbb…bbbb");
+ await expect(page.getByLabel("Open actions for Fizz")).toHaveCount(1);
+});
+
test("catalog hides built-ins and shows the shared-agent empty state", async ({
page,
}) => {