Exploratory. Codex subagent and parallel-agent messages are implemented as structured cards, but the explicit linked-session card workflow described here is still future design work.
Related:
This brief describes a message type that represents another agent session linked from the current conversation. The linked sessions remain fully disjoined; the card is purely a graphical representation, a UI convenience for keeping related work visible in one place.
TermAl already has first-class sessions, workspace tabs, and several message types for things that happen inside a session. What it does not have is a clean way for one conversation to say:
And no way for a user to say:
Today the closest fallback is plain assistant text, but that loses structure:
Add a new message type that links to another real session.
The current conversation keeps a compact card pointing to the linked session. The linked session remains a normal first-class session with its own history, status, commands, diffs, approvals, and tabs. The two sessions are fully disjoined — they share no state and know nothing about each other. The card is purely a graphical shortcut.
This is a linked-session model, not a nested transcript model.
Three entry paths produce the same card:
/async command in the
composer. TermAl creates a new linked session, starts it with the provided
prompt, and inserts the card into the current conversation.The linked session is a whole conversation, not a snippet. The two sessions
are fully disjoined — there is no ownership relationship, no shared state, and
no coupling beyond the card that references a sessionId.
That means:
The card should not embed a copy of the linked session conversation.
If the full linked transcript is duplicated into the current conversation:
If the card only stores link metadata:
When an agent starts concurrent work, the current session receives a compact message card automatically, for example:
Spawned parallel Codex sessionReviewing git status in /Users/greg/GitHub/Personal/termalThe card should show:
active, idle, approval, or errorOpen sessionOpen in new tabThe user drags an existing session from the session list or another tab into the current conversation. A link card is inserted at the current scroll position. This lets the user assemble a single conversation view that tracks all the related work they care about.
The dragged session is not moved or modified — only a link card is created.
/async flow)The composer should also be able to create a linked session directly.
Examples:
/async compare our solution to the one used in ScyllaDB/async --codex do code reviewRecommended behavior:
/async is handled by TermAl, not forwarded verbatim to Claude or CodexconcurrentSession card right awayRecommended v1 flags:
--codex: start the linked session as Codex--claude: start the linked session as ClaudeRecommended default if no agent flag is provided:
Open questions for later:
--model <name>--workdir <path>--title <text>/async should support attaching files from the current draftThe linked session is just a normal session:
This design supports both behaviors the user asked for:
The inline card should stay summary-only. Detailed reading belongs in the linked session itself.
Recommended inline summary sources, in order:
preview field if presentFrontend:
type ConcurrentSessionMessage = BaseMessage & {
type: "concurrentSession";
sessionId: string;
agent: AgentType;
title: string;
detail?: string | null;
workdir: string;
originMessageId?: string | null;
};
Backend:
Message::ConcurrentSession {
id: String,
timestamp: String,
author: Author,
session_id: String,
agent: Agent,
title: String,
detail: Option<String>,
workdir: String,
origin_message_id: Option<String>,
}
Notes:
sessionId is the critical field. It links to the real linked session.title is the concise action summary shown on the card.detail is optional human-readable context.workdir is copied into the message so the historical record remains useful
even if the linked session is later removed.originMessageId is optional metadata for tracing which message created the
link.The UI should resolve live state for the linked session from the global
sessions array.
That means the card should:
sessionIdstatuspreviewMissing-session fallback:
UnavailableThis split should stay explicit:
The card should integrate with the current workspace model the same way any other session-opening action does.
Primary actions:
Open session: focus an existing tab for that session, or open it in the
active pane if none existsOpen in new tab: explicitly create/focus a separate session tab in the paneBecause the linked target is already a real session, no special nested pane model is needed.
If a session is already open somewhere, Open session should prefer focusing
the existing tab instead of creating duplicates.
ConcurrentSession variant to Message.sessionId (drag-in flow)./async flow).Open question:
sourceSessionId and automatically
add the link card to the source conversation, or should the caller create the
linked session and then post a separate link message?Recommended v1:
sourceSessionId on session creation. Backend
creates the linked session and appends the link card to the source
conversation in one operation. That avoids partial state where the linked
session exists but the source conversation never records the relationship.sessionId and appends the card to the current session. No session
creation involved./async flow: parse the local command before agent dispatch, create
the linked session, append the card to the current conversation, and send
the remaining prompt text to the new session as its first turn.Recommended request shape for /async:
type CreateLinkedSessionRequest = {
sourceSessionId: string;
agent?: "claude" | "codex";
prompt: string;
model?: string;
workdir?: string;
title?: string;
};
This should be a TermAl-native path, not a message that gets passed through to the underlying agent runtime unchanged.
Message in ui/src/types.ts with ConcurrentSessionMessage.ConcurrentSessionCard component in the message renderer.onOpenSession callback into the card renderer./async commands in the composer before normal message send./async ... text to the active session.Card behavior:
Minimal renderer inputs:
ConcurrentSessionMessagesessionIdOpen session and Open in new tab/async compare our solution to the one
used in ScyllaDB and let a second session research it while you continue the
main conversation./async --codex do code review to start a
parallel Codex review without leaving the current session.Examples:
Parallel sessionSpawned Codex sessionSpawned Claude review sessionPossible subcopy:
Reviewing repo status in /Users/greg/GitHub/Personal/termalWaiting for approval in the linked sessionFinished: summarized failing tests/async
command surfaceOnce the basic linked-session card exists, it can grow into richer coordination features:
spawned, watching, blocked, donesessionId.Open session and Open in new tab actions./async composer path for creating a linked session
from a prompt, with --claude and --codex as the initial explicit
switches.That delivers the main value quickly without introducing duplicated transcript state or a more complex nested conversation model.