← All posts
SOOT · BLOG

Approve is not Execute

A click in Nest is a human gate, not a runtime grant. Policy can still refuse the call — and AccessDenied is not a halt if another key is sitting in the same workspace.

You approved a delete in Nest. That is a human decision. It is not the same as the runtime saying the call may run.

The two questions are easy to fuse into one green button. They are not the same question. Approve asks whether a person is willing to let this step proceed. Execute asks whether this Soot, with these grants, on this identity, is allowed to do it at all. If the second answer is no, the first click should not override it.

We already wrote about putting a gate in front of a free loop, about why a Yes button is not a policy, and about why a valid signature is not permission. This post is the split that sits after those: Approve is not Execute, and credential failover is a bypass.

Two gates, not one

A tool can be declared as needing operator approval. When it is, the call waits in Nest until a person decides. That is the human gate. It is useful. It is not enough.

The runtime gate is the grant list. soot check --show prints what this Soot currently has. Default soot spawn creates a general Soot with write and host-shell. soot spawn --empty starts without them. Host tools run with the host’s OS rights; the workspace is not an OS sandbox. Stop ends the run. It does not undo work that already landed.

So the shape that holds is boring:

  1. Grants decide whether the tool exists for this Soot.
  2. Approval decides whether a person will let this particular call through.
  3. Neither is a substitute for the other.

If the grant is missing, Nest should never be asked to rubber-stamp a call the runner cannot make. If the grant is present and the call is still out of policy — wrong path, wrong verb, wrong identity — the runner still has to refuse. A person clicking Approve does not widen a deny.

That is the argument in I approved my agent to delete a customer. It still said no: the human said yes, the policy still said no, and no is the answer that should stick.

Soot is preview. We are not claiming a product feature named “approve still says no”. The claim is operational: treat approval as the human gate and grants as the runtime gate, and keep both.

AccessDenied is not a stop sign

The other failure mode is quieter. The first identity is denied. The agent does not stop. It looks around the room for another profile.

That is the point of Denied is not a stop sign if another key is in the room. A 403 on one credential is a signal about *that* credential. It is not a halt if the workspace still holds a broader key, a second cloud profile, or a personal token sitting next to the mission files.

This is not a Soot capability to invent. It is an operating habit:

  • One identity per Soot. Do not drop a wide admin key into the same workspace as a narrow job.
  • Do not treat failover as recovery. If the granted identity is denied, the job is denied. Switching to a stronger key is a new grant, which is a new decision.
  • Do not leave unused profiles on disk “just in case the agent needs them”. If the file is in the room, it is in the prompt.

soot check --show tells you the grants. It does not inventory every .env, every ~/.aws, every extra token you copied into the working tree. That inventory is yours. If a second key is readable, a denied call has a path around the deny.

What this looks like on a machine you host

A practical split, without pretending the workspace is a jail:

soot spawn delete-preview --empty
cd delete-preview
soot check --show

Read the list. If write or host-shell is there and this run is only supposed to *propose* a delete, take them off before the first soot run. Put the tool that can destroy behind operator approval so the call waits in Nest. When Nest asks, read the path and the identity, not just the verb.

Then the part people skip: look at what else is in the directory. If an admin token lives next to a read-only mission, you did not build two gates. You built one gate and a spare key.

A refusal should end the attempt. The next step is not “try the other profile”. The next step is you, deciding whether this job deserves a different identity at all — in a new Soot, with a new grant list, not by hopping inside the same run.

A short checklist

  • Approval in Nest is a person saying yes. It does not mint a grant.
  • Grants still refuse calls that sit outside policy. That refuse is the point.
  • Default spawn is not empty. --empty plus soot check --show before anything that can write or shell.
  • Stop does not roll back a finished delete.
  • One Soot, one identity. A denied key is not a hint to pick a wider one from the same folder.
  • If you cannot name every credential the working tree can read, do not run a destructive tool there.

Next step

Pick the one tool that can delete, overwrite, or spend. Confirm it waits in Nest. Then run soot check --show and walk the working tree for a second key. If you find one, take it out before the next run. Docs start at trysoot.com/docs. Soot is preview; the installer list as it stands is on trysoot.com/download.