v1.2.0
  1. ds
  2. Agent
  3. Approval

Approval

A permission card with risk, the command and the decision.

Run a command outside the workspace

Medium risk

The agent wants to restart the local indexer. This writes outside the repository and can interrupt other processes.

launchctl kickstart -k gui/501/com.fin1te.indexer

~/Library/LaunchAgents/com.fin1te.indexer.plist

Allowed once
Show code
<section class="approval" id="ap-demo" data-risk="medium" aria-labelledby="ap-demo-t">
  <div class="approval-head">
    <span class="approval-ico"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg></span>
    <h3 class="approval-title" id="ap-demo-t">Run a command outside the workspace</h3>
    <span class="approval-risk">Medium risk</span>
  </div>
  <p class="approval-note">The agent wants to restart the local indexer. This writes outside the repository and can interrupt other processes.</p>
  <pre class="approval-cmd"><code>launchctl kickstart -k gui/501/com.fin1te.indexer</code></pre>
  <p class="approval-path"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/></svg><b>~/Library/LaunchAgents/com.fin1te.indexer.plist</b></p>
  <div class="approval-actions">
    <button class="btn sm primary" type="button" data-approve="allow_once">Allow once</button>
    <button class="btn sm" type="button" data-approve="allow_session">Allow for session</button>
    <button class="btn sm ghost danger" type="button" data-approve="deny">Deny</button>
  </div>
  <div class="approval-decided" role="status">
    <span data-ok><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span><span data-no><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></span>
    <b data-decision-text>Allowed once</b>
  </div>
</section>

An approved action needs more than a yes and no. This card shows the risk, the exact command, the path it touches and the reason it is being asked for. The three decisions are separate buttons, because "allow for this session" is not the same permission as "allow once".

This demo is live. Pick a decision and the buttons are replaced by the outcome. The card takes the colour of that outcome: the accent stays for an allow, red for a deny.

Decided

Delete the local build cache

High risk

This removes 12 GB under ~/Library/Caches/axon. The next build will be slower.

rm -rf ~/Library/Caches/axon
Allowed for this session
Show code
<section class="approval" data-risk="high" data-state="decided" data-decision="allow_session" aria-labelledby="ap2-t">
  <div class="approval-head">
    <span class="approval-ico"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg></span>
    <h3 class="approval-title" id="ap2-t">Delete the local build cache</h3>
    <span class="approval-risk">High risk</span>
  </div>
  <p class="approval-note">This removes 12 GB under <code>~/Library/Caches/axon</code>. The next build will be slower.</p>
  <pre class="approval-cmd"><code>rm -rf ~/Library/Caches/axon</code></pre>
  <div class="approval-actions">
    <button class="btn sm primary" type="button">Allow once</button>
    <button class="btn sm" type="button">Allow for session</button>
    <button class="btn sm ghost danger" type="button">Deny</button>
  </div>
  <div class="approval-decided" role="status">
    <span data-ok><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span><span data-no><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></span>
    <b>Allowed for this session</b>
  </div>
</section>

The decided state keeps the evidence. The command and the risk stay visible, so a session log reads correctly after the fact. Only the actions become the result. The icon and the words carry the decision; the tint is the second signal.

Error

Push the release tag

High risk

The session ended before the command ran. Nothing was executed and the tag was not created.

git push origin v2.4.0
Code
<section class="approval" data-risk="high" data-state="error" aria-labelledby="ap3-t">
  <div class="approval-head">
    <span class="approval-ico"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg></span>
    <h3 class="approval-title" id="ap3-t">Push the release tag</h3>
    <span class="approval-risk">High risk</span>
  </div>
  <p class="approval-note">The session ended before the command ran. Nothing was executed and the tag was not created.</p>
  <pre class="approval-cmd"><code>git push origin v2.4.0</code></pre>
  <div class="approval-actions">
    <button class="btn sm primary" type="button" disabled>Allow once</button>
    <button class="btn sm" type="button" disabled>Allow for session</button>
    <button class="btn sm ghost danger" type="button" disabled>Deny</button>
  </div>
</section>

If the turn ends before the command runs, say that explicitly and leave the actions disabled. "Nothing was executed" is the sentence people need. Do not show a spinner over a decision that can no longer be made.

API

ClassOnWhat it does
.approvalsectionThe card. data-risk: low, medium, high. data-state: decided, loading, error.
.approval-headdivShield, title and risk.
.approval-titleh3One sentence naming the action.
.approval-riskspanA dot and the risk word. Pinned right.
.approval-cmdpreThe command, in mono. Keeps line breaks and scrolls sideways.
.approval-pathpThe file or directory, with a folder icon.
.approval-notepWhy the agent is asking, or what happened.
.approval-actionsdivAllow once, allow for session, deny. Disabled while loading.
.approval-decideddivThe result. Shown when data-state="decided".
data-decision="deny".approvalRed result and the deny mark.
Do
  • Name the risk in words and show the command.
  • Keep the evidence after the decision.
  • Make deny a real, reachable button.
Don't
  • A single OK button for a destructive command.
  • Auto-approving a session after one allow once.
  • Hiding the path or the command behind a hover.

Accessibility

  • Name the section with aria-labelledby pointing at the title, and give each button its own label.
  • The decided result is a role="status" region, so the change is announced without moving focus.
  • Risk is text, not colour alone. Low, medium and high each have a word and a dot.
  • At 390px the buttons fill the row and the risk moves under the title. The command still scrolls rather than wraps mid-token.