diff --git a/packages/core/src/tool/subagent.ts b/packages/core/src/tool/subagent.ts
index 84131b18a6eb..b8c0975cdc50 100644
--- a/packages/core/src/tool/subagent.ts
+++ b/packages/core/src/tool/subagent.ts
@@ -69,8 +69,18 @@ export const Plugin = {
state: "completed" | "error" | "cancelled",
text: string,
) {
+ // TUI synthetic rows require a non-empty description to render in the parent transcript.
+ // Keep the structured XML body in text for model consumption; surface a short human label
+ // so background completions and failures remain visible without a follow-up model turn.
+ const label =
+ state === "error"
+ ? `Background subagent failed: ${description}`
+ : state === "cancelled"
+ ? `Background subagent cancelled: ${description}`
+ : `Background subagent completed: ${description}`
yield* runtime.session.synthetic({
sessionID: parentID,
+ description: label,
text: `\n${text}\n`,
})
})
diff --git a/packages/core/test/tool-subagent.test.ts b/packages/core/test/tool-subagent.test.ts
index 56e3587162d6..b0cd70e62684 100644
--- a/packages/core/test/tool-subagent.test.ts
+++ b/packages/core/test/tool-subagent.test.ts
@@ -289,6 +289,7 @@ describe("SubagentTool", () => {
yield* SessionPending.promoteSteers(database.db, events, parent.id)
const synthetic = (yield* sessions.context(parent.id)).filter((message) => message.type === "synthetic")
expect(synthetic).toHaveLength(1)
+ expect(synthetic[0]?.description).toBe("Background subagent completed: background review")
expect(synthetic[0]?.text).toContain(`