REFERENCE
SDK Demos
How to use @asgard-js/core and @asgard-js/react, with demos you can try on the page.
Dock the Run-Chrome Yourself
The Task Check List and Subagent List are run-level chrome — they describe the state of the whole turn, not of any one message. So the SDK docks them in a fixed strip that sits outside the thread's scroll box, between it and the composer.
Why Outside the Scroll Box
They used to render at the tail of the thread and scroll with the messages. The result: during a streaming run the thread kept growing and auto-scrolling, shoving the panels around. Moved into a fixed strip, they now stay put while a run streams.
The strip has two more rules:
- Capped at 50% of the body height, scrolling internally past that — the thread always keeps the other half
- When there is no chrome, the strip does not exist and takes no space — the composer sits flush against the last message
Placing Them Yourself
<Chatbot hideRunChrome {...rest} />With that set, the built-in panels are not rendered and you can put the exported
<TaskList>/<SubagentList>anywhere — a right rail, a drawer, a separate tab.import { TaskList, SubagentList, AsgardThemeScope } from "@asgard-js/react";
import { deriveTasks, deriveSubagents } from "@asgard-js/core";
// conversation comes from useAsgardContext()
const tasks = deriveTasks(conversation);
const subagents = deriveSubagents(conversation);
<AsgardThemeScope theme={theme}>
<SubagentList subagents={subagents} locale="en-US" />
<TaskList tasks={tasks} locale="en-US" />
</AsgardThemeScope>Always wrap inAsgardThemeScopeOutside
<Chatbot>the panels miss the design tokens the chat shell emits and fall back to the light-themed defaults. See Re-establish the Theme.Where the Data Comes From
Both panels take plain arrays — they are not coupled to SDK state:
function TaskList(props: { tasks: Task[]; locale?: Locale }): ReactNode;
function SubagentList(props: { subagents: Subagent[]; locale?: Locale }): ReactNode;deriveTasks/deriveSubagentsfold both out of aConversation. To subscribe rather than recompute, core also offerscreateDerivedStores, withtasksEqual/subagentsEqualfor comparison.import {
deriveTasks, deriveSubagents,
tasksEqual, subagentsEqual,
createDerivedStores,
} from "@asgard-js/core";Types
interface Task {
id: string;
subject: string; // Noun-form title; shown when not in progress
activeForm?: string; // Present-continuous label; preferred while in progress
description?: string; // Full detail, shown when the row is expanded
status: "pending" | "in_progress" | "completed";
}
interface Subagent {
parentToolUseId: string; // Correlation key = the Agent tool-call that spawned it
agentId?: string;
subagentType?: string; // e.g. general-purpose
description?: string;
status: "running" | "completed" | "failed" | "cancelled";
summary?: string;
tools: SubagentToolCall[]; // The child tool-calls this subagent ran
}A subagent's terminal status comes only from the
subagent.completeevent — it is never inferred from theAgenttool-call's own completion (async subagents complete their tool-call early withasync_launched).See Also
- Task Check List, Subagent List — the built-in versions
- Re-establish the Theme
- Locales — per-panel
locale - Headless — draw everything yourself