Tools a run may attempt but not simply use: gated by a live yes/no, bounded by a ceiling the machine's owner set, and failing closed on every path.
allowTools runs with no questions asked. askTools is the other thing: tools the
model may attempt, each one gated by a live yes/no.
The ceiling#
A yes can only ever select from the machine's own askTools set. So an approver that
says yes to everything, including a hostile or compromised one, cannot widen the
machine past what its owner pre-authorised.
what an approval can unlock ⊆ machine grant askTools
That property is what makes offering a non-local approver safe at all. Without it,
remote approval would be a way to hand a control plane a blank cheque.
A tool outside the askable set is refused without asking anyone. No approval request
is sent, so the approval channel cannot be used to enumerate what a machine might say
yes to.
Who answers#
JSON
{ "approver": "desktop" }
|
|
local |
Prompt on this machine's terminal. Trusts nobody else, and needs somebody to be looking at one |
desktop |
Ask the Soba app on this machine, in a real window |
remote |
Ask your app, where the user already is |
none |
Never ask. askTools are simply unavailable |
Safe in every case, because the ceiling bounds what a yes can unlock.
desktop exists because local is unusable for the case the worker is mostly in. A
background service installed weeks ago has no terminal, so a machine set to ask would
deny every escalation and the person who could have said yes would never learn they had
been asked. The app listens on a unix socket in ~/.soba (mode 0600), not a port, so
it is unreachable from the network by construction. If the app is not running, the
worker denies, exactly as it does with no terminal.
Every path fails closed#
Timeout, transport error, malformed answer, no approver reachable: all deny.
Anything that is not an explicit yes is a no, and that is structural rather than a rule
someone has to remember.
An approval channel that errors open is worse than none, because it reads as protection
while granting everything.
A decision lasts exactly one run#
It is never persisted. An approval can never widen a future run, and there is no
accumulated set of "things this machine has said yes to before" for an attacker to grow.
Every decision is appended to ~/.soba/audit.log, on the machine, not on Soba's
servers.
Permission modes#
The mode your app asks for and the machine's own mode intersect to the less permissive
of the two.
| Mode |
|
ask |
Escalations round-trip to an approver, bounded by askTools |
deny |
Anything outside the allowlist fails the call; the run continues |
auto |
The runtime proceeds within the resolved allowlist, no prompting |
There is deliberately no "skip all permission checks" mode.
The prompt yields to the approver#
Neither the install prompt nor stdin is touched while the local approver may be
listening for a permission answer. Losing a real approval to a UI nicety is not a trade
worth making.