Agent run patterns
Agent consoles have converged on a small shared vocabulary: a runs table, a streaming session log, collapsible step traces, plan diffs, and a human approval gate (the furniture of GitHub's Agent HQ "mission control" and of LangSmith-style trace views alike). Soma ships every substrate; the three compositions below are the recurring assemblies, built purely from parts documented elsewhere on this site. As with the trust primitives above, the domain semantics stay in the consumer.
Inline tool-call indicator composition: soma-log line + spinner → check swap
A tool call is one log line
with two states: while running, a small spinner sits in the
level slot and the text is muted ("Searching…"); on
completion the spinner swaps for a check tinted with the
success token and the text firms up to the result. The
muted-while-pending tint uses --soma-color-text-muted
(informational, AA) — never -subtle:
Appends a running line, completes it after a
moment. role="log" makes appended lines
announce themselves.
<!-- done: check in the level slot, normal text -->
<div class="soma-log-line">
<span class="soma-log-time">14:02:11</span>
<span class="soma-log-level"><span class="soma-icon soma-icon-check"
style="color: var(--soma-color-success)"></span></span>
<span class="soma-log-text">Searched the web for "CVE-2026-1337 fix" · 12 results</span>
</div>
<!-- running: spinner in the level slot, muted text -->
<div class="soma-log-line">
<span class="soma-log-time">14:02:14</span>
<span class="soma-log-level"><span class="soma-spinner soma-spinner-small"
role="status" aria-label="Tool call running"></span></span>
<span class="soma-log-text" style="color: var(--soma-color-text-muted)">Reading services/api-backend/deploy.yaml…</span>
</div>
Your streaming code performs the swap: replace the spinner span with the check icon and drop the muted tint — two DOM writes per completed call.
Collapsible step block composition: soma-expander + log / diff excerpts
The intermediate-reasoning pattern: each agent step is an expander, closed by default so the run reads as a summary and opened where the operator wants the full trace. The trigger line carries the step verdict (a badge); the content carries the evidence, a log or diff excerpt. Auto-init: no wiring.
<div class="soma-accordion">
<button class="soma-expander-trigger" aria-controls="step-plan" aria-expanded="false">
Step 2 — Plan the change
<span class="soma-badge">3 tool calls</span>
</button>
<div id="step-plan" class="soma-expander-content" aria-hidden="true">
<div class="soma-log" role="log" tabindex="0" aria-label="Step 2 tool calls">…</div>
</div>
<!-- …one trigger + content pair per step; a diff excerpt works the same way -->
</div>
Approval gate flow composition: ApprovalCard + Soma.confirm() + kill-switch banner
The ApprovalCard above carries the evidence; the gate adds
the decision mechanics. Effectful decisions get a second
confirmation via Soma.confirm()
(a promise: Esc/backdrop resolve false, so
"no decision" can never read as approval), and the kill
switch escalates out-of-band to a page-level
soma-banner-critical
via Soma.banner() (the same affordance as the
navbar Stop button, announced as an alert):
Scale api-backend from 3 to 6 replicas —
requested by devops-agent session
s-4821, estimated +$118/mo.
Gate state: pending
// The live gate above, exactly as this page wires it:
const gateOut = document.getElementById('gate-out');
document.getElementById('gate-approve').addEventListener('click', async () => {
const ok = await Soma.confirm({
title: 'Apply this plan?',
body: 'Scales api-backend to 6 replicas in production (+$118/mo).',
confirmLabel: 'Approve and run',
});
gateOut.textContent = ok ? 'approved — executing' : 'pending';
if (ok) Soma.toast({ title: 'Plan approved',
body: 'devops-agent is executing (step 4 of 6)', appearance: 'success' });
});
document.getElementById('gate-reject').addEventListener('click', async () => {
if (await Soma.confirm({
title: 'Reject this plan?',
body: 'devops-agent keeps the session open and re-plans.',
appearance: 'danger',
confirmLabel: 'Reject',
})) gateOut.textContent = 'rejected — agent re-planning';
});
// Kill switch: out-of-band escalation, not part of the approve/reject pair.
const stopBtn = document.getElementById('gate-stop');
stopBtn.addEventListener('click', () => {
stopBtn.disabled = true;
gateOut.textContent = 'stopped — kill switch engaged';
Soma.banner({
appearance: 'critical',
body: 'Kill switch engaged — all agent actions are paused at project scope.',
close: 'manual',
}).on('close', () => { stopBtn.disabled = false; });
});