Steps and approvals
tier 2 — classesWhat an agent thought, which tools it ran, what it means to do next, and what it asks permission for. The person stays in charge: every step can be opened and read, and nothing that writes happens before somebody says yes. All of it is markup the app writes, in the app's words, with no script. A run that spans many steps, branches and hand-offs is a workflow.
Reasoning
details.reasoning folds away the thinking behind an answer. It is a native
<details>, so it opens from the keyboard and with scripting off;
.reasoning-chevron turns as it opens, and .reasoning-body hangs the text
off a rule under it. The summary says how long the agent thought, which is what most readers want
to know without opening it.
Thought for 4 s
The question is about one night and one region, so the sync log for that window comes first. If the sync timed out, something else held the tables; the nightly maintenance jobs are the usual suspects.
Check the runbook for the timeout, then confirm against the lock history.
<details class="reasoning" style="max-width: 520px">
<summary><i class="ri-arrow-right-s-line reasoning-chevron"></i><span>Thought for 4 s</span></summary>
<div class="reasoning-body">
<p>The question is about one night and one region, so the sync log for that window comes first. If the sync timed out, something else held the tables; the nightly maintenance jobs are the usual suspects.</p>
<p>Check the runbook for the timeout, then confirm against the lock history.</p>
</div>
</details>
Steps
ol.agent-steps is the tool calls behind an answer, in order. Each <li>
carries data-state — pending, running,
done or failed, the same words as .steps
— an .agent-step-icon, and a details.agent-step that opens on what
the step sent and what came back. .agent-step-meta is the count and the time, on the
end. A running step's marker is a small orb.
Show the call, not a description of it. The .code-block inside is
what lets a reader check the agent's work; a failed step keeps the error in its own words.
-
Searched the runbook for “sync timeout”
search(index: "runbook", query: "sync timeout", limit: 4) -
Read 3 log files on build-runner-04
02:14:07 sync ERROR timed out after 600 s waiting for lock on orders 02:25:31 maint INFO vacuum finished on orders (681 s) -
Opened a shell on orders-console-01
ssh orders-console-01: the agent's role may not open a shell here -
Querying src-db-14 for locks held over 60 s
SELECT relation, mode, duration FROM lock_history WHERE duration > interval '60 s'; -
Draft a new maintenance window
Not started.
<ol class="agent-steps" style="max-width: 560px">
<li data-state="done">
<span class="agent-step-icon"><i class="ri-check-line"></i></span>
<details class="agent-step">
<summary><span class="agent-step-label"><i class="ri-search-line"></i><span>Searched the runbook for “sync timeout”</span></span><span class="agent-step-meta">4 results · 1.2 s</span></summary>
<pre class="code-block"><code>search(index: "runbook", query: "sync timeout", limit: 4)</code></pre>
</details>
</li>
<li data-state="done">
<span class="agent-step-icon"><i class="ri-check-line"></i></span>
<details class="agent-step" open>
<summary><span class="agent-step-label"><i class="ri-file-text-line"></i><span>Read 3 log files on build-runner-04</span></span><span class="agent-step-meta">2.4 s</span></summary>
<pre class="code-block"><code>02:14:07 sync ERROR timed out after 600 s waiting for lock on orders
02:25:31 maint INFO vacuum finished on orders (681 s)</code></pre>
</details>
</li>
<li data-state="failed">
<span class="agent-step-icon"><i class="ri-close-line"></i></span>
<details class="agent-step">
<summary><span class="agent-step-label"><i class="ri-terminal-box-line"></i><span>Opened a shell on orders-console-01</span></span><span class="agent-step-meta">Permission denied</span></summary>
<pre class="code-block"><code>ssh orders-console-01: the agent's role may not open a shell here</code></pre>
</details>
</li>
<li data-state="running">
<span class="agent-step-icon"><span class="orb orb--sm" data-orb="working" role="img" aria-label="Running"></span></span>
<details class="agent-step">
<summary><span class="agent-step-label"><i class="ri-database-2-line"></i><span>Querying src-db-14 for locks held over 60 s</span></span><span class="agent-step-meta">0.8 s</span></summary>
<pre class="code-block"><code>SELECT relation, mode, duration FROM lock_history WHERE duration > interval '60 s';</code></pre>
</details>
</li>
<li data-state="pending">
<span class="agent-step-icon"></span>
<details class="agent-step">
<summary><span class="agent-step-label"><i class="ri-edit-line"></i><span>Draft a new maintenance window</span></span></summary>
<p class="text-muted text-sm">Not started.</p>
</details>
</li>
</ol>
Plan
ul.agent-plan is what the agent means to do and how far it got: data-state
on each item is done, current or skipped, or nothing for a
step still to come. Mark the current one aria-current="step" too. A
.progress above it gives the same count at a glance.
- Find when the sync stopped
- Find what held the lock
- Draft a new maintenance window
- Ask for approval
- Restart the sync by hand
<div class="card" style="max-width: 400px">
<div class="card-head"><strong>Plan</strong><span class="text-muted text-sm text-nums">2 of 5</span></div>
<div class="card-body sedna-col sedna-gap-3">
<div class="progress" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" aria-label="Plan progress"><div class="progress-bar" style="width: 40%"></div></div>
<ul class="agent-plan">
<li data-state="done"><span class="agent-plan-mark"><i class="ri-check-line"></i></span><span class="agent-plan-label">Find when the sync stopped</span></li>
<li data-state="done"><span class="agent-plan-mark"><i class="ri-check-line"></i></span><span class="agent-plan-label">Find what held the lock</span></li>
<li data-state="current" aria-current="step"><span class="agent-plan-mark"><span class="orb orb--sm" data-orb="working" role="img" aria-label="In progress"></span></span><span class="agent-plan-label">Draft a new maintenance window</span></li>
<li><span class="agent-plan-mark"></span><span class="agent-plan-label">Ask for approval</span></li>
<li data-state="skipped"><span class="agent-plan-mark"><i class="ri-subtract-line"></i></span><span class="agent-plan-label">Restart the sync by hand</span></li>
</ul>
</div>
</div>
Asking before it acts
.agent-approval on a .card is the agent asking
permission. .agent-approval-change is the change itself — what, from, to —
and chips under it say what kind of change it is. Approve is .btn--go.btn--solid, because it
lets the action out; taking control back is .btn--warn; deny is quiet. The library's
own meanings, so an approval reads the same as every other outward action in the app.
Once the reader answers, data-state="approved" or "denied" swaps
.agent-approval-actions for .agent-approval-result, which names who
answered and when. Keep an undo there while the change can still be taken back.
<div class="sedna-row-wrap sedna-gap-3" style="align-items: start">
<div class="card agent-approval" style="width: 380px">
<div class="card-head">
<div class="agent-approval-head">
<span class="agent-approval-icon"><i class="ri-shield-check-line"></i></span>
<span class="agent-approval-title"><strong>Change a schedule</strong><span>Ops agent asks before it writes</span></span>
</div>
</div>
<div class="card-body sedna-col sedna-gap-3">
<div class="agent-approval-change"><span>src-db-14 · vacuum.start</span><s>02:00</s><i class="ri-arrow-right-line" aria-label="to" role="img"></i><strong>03:30</strong></div>
<div class="chip-set">
<span class="chip"><i class="ri-edit-line"></i><span class="chip-label">Writes 1 setting</span></span>
<span class="chip"><i class="ri-loop-left-line"></i><span class="chip-label">Reversible</span></span>
</div>
</div>
<div class="card-foot">
<div class="agent-approval-actions">
<button class="btn btn--ghost" type="button">Deny</button>
<button class="btn btn--warn sedna-push" type="button">Take over</button>
<button class="btn btn--go btn--solid" type="button"><i class="ri-check-line"></i><span>Approve</span></button>
</div>
<div class="agent-approval-result">
<i class="ri-checkbox-circle-fill"></i><span>Approved by Alex Fischer</span>
</div>
</div>
</div>
<div class="card agent-approval" data-state="approved" style="width: 380px">
<div class="card-head">
<div class="agent-approval-head">
<span class="agent-approval-icon"><i class="ri-shield-check-line"></i></span>
<span class="agent-approval-title"><strong>Change a schedule</strong><span>Ops agent asks before it writes</span></span>
</div>
</div>
<div class="card-body">
<div class="agent-approval-change"><span>src-db-14 · vacuum.start</span><s>02:00</s><i class="ri-arrow-right-line" aria-label="to" role="img"></i><strong>03:30</strong></div>
</div>
<div class="card-foot">
<div class="agent-approval-actions">
<button class="btn btn--ghost" type="button">Deny</button>
<button class="btn btn--go btn--solid" type="button"><i class="ri-check-line"></i><span>Approve</span></button>
</div>
<div class="agent-approval-result">
<i class="ri-checkbox-circle-fill"></i><span>Approved by Alex Fischer at 09:31</span>
<button class="btn btn--sm btn--ghost sedna-push" type="button">Undo</button>
</div>
</div>
</div>
</div>