bots-garden/mini-mepublic Fork
⑂ feature/resume-acp
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
🛟 Updated. 46087c3 · on feature/resume-acp · k33g · 8d ago
yolo-and-permissions.md · 54 lines · 6.5 KBmarkdown
Blame HistoryOpen raw

Yolo mode and permissions — explanation

What is this about?

A coding agent runs commands and writes files on your machine. Somebody has to decide whether each of those calls may run: either the user, call by call, or nobody, because the user decided once and for all to let the agent act. mini-me calls the second choice yolo mode and makes it one setting, yolo, read the same way by the three front ends — the line mode, the window and the editor (ACP) — and by an agent asked by another one.

Why yolo is the default

mini-me is built to drive a small local model through many short steps. Asking before each ls makes that loop unusable in practice, and the line mode — the first front end — never asked at all. Before this setting existed, the behaviour depended on where you ran mm: the line mode never asked, the window asked only with permissions: ask, and the editor always asked, whatever you wanted. The same agent file did not mean the same thing in three places.

The default was therefore set to what most runs already did — run without asking — and the protection became a deliberate, visible choice: yolo: false. The banner says which way it is set (yolo: on / yolo: off (tools ask)), so nobody finds out by surprise, in either direction. The consequence worth knowing: in an editor, the permission dialog only appears with yolo: false; it used to appear always.

Existing versus asking

Two different questions are kept apart on purpose:

  • Does the tool exist? bashTool, editTools, fetchContentTool. A tool that does not exist is not declared to the model at all; it cannot even try.
  • Does an existing tool ask before running? yolo.

So yolo: true with bashTool: false is an agent that edits files freely but has no shell, and yolo: false with bashTool: true is an agent that has a shell but needs your consent for each command. Merging the two into one tri-state (bashTool: ask) was considered and rejected: it would have to be repeated for every tool, while the real decision — "do I trust this agent to act alone right now?" — is a single one.

Only the calls that change something ask: bash, write_file, edit_file, fetch_content when it saves, lsp rename, and the plan actions that change a plan. Reads (read_file, read_skill, the lsp navigation actions, fetch_content without output) never ask: a dialog on every read teaches people to click "allow" without reading.

Four answers, one memory

When a call asks, the answer can be once or for the session, and yes or no: allow once, allow this tool for the session, reject this call, never allow this tool in this session. "Never" exists because a refusal that only lasts one call leaves you rejecting the same retry again and again; "reject once" exists because without it the only way to say no would be final. A session's remembered answers are kept per tool name, survive /new (the editor still sees the same session), and disappear when mm exits.

The rules live in one package, internal/consent: the yolo check (Gate), the four answers (Answer), what a session remembers (Policy) and the line mode's prompt hook. Each front end only draws the question its own way — a 🔐 line, the window's box, the editor's dialog. Before, each front end had its own map of "allowed for this session", and the three had already started to differ.

Why the asking agent decides

With mmConfigs, one agent can ask another (/ask-jan, mm --ask jan). Two configuration files, two yolo values: which one wins? The one of the agent the user started. It is the only agent with a user in front of it, and the user chose its configuration for this session; the asked agent's file was written for a different situation — perhaps for running alone in yolo mode.

Technically, the asked agent is started with AGENT_YOLO=false, so it submits every call it would gate through the ACP permission request — the same channel an editor uses. The asking agent receives it and runs it through its own consent.Gate: in yolo mode it allows at once; otherwise it asks its own user, in its own front end, and remembers the answer under jan/bash so that allowing Jan's shell does not allow yours. The asked agent itself never remembers anything: it is asked again each time, and the asking agent's memory answers.

One refinement keeps the same principle: the user's file may give an asked agent its own yolo, in that agent's mmConfigs entry (homer: {path: …, yolo: true}). It then decides that agent's calls instead of the asking agent's yolo: true runs them — a coder trusted with edits once the hand-off was approved —, false asks for each one even when the asking agent runs freely. It is still the file the user started that decides; the asked agent's own file still does not count.

Modes that cannot ask

mm -p and mm --ask have nobody to ask: the first is a one-shot run, the second reads its question from stdin. With yolo: false they reject the calls that would ask and say so once on stderr. Allowing them silently would turn yolo: false into a setting that depends on how you launched mm, which is exactly the inconsistency this design removes; hanging on an invisible question would block scripts forever.

Rejected alternatives

  • A --yolo command-line flag only. It would not reach the sandbox kits or an editor's launch settings, which set environment variables and files, not flags. AGENT_YOLO covers the one-run case instead.
  • Keeping permissions: ask | auto. It was read by the window only and appeared in no shipped configuration. It still works — ask means yolo: false — with a deprecation warning, so old files keep their protection.
  • Letting yolo override MCP servers marked ask. An MCP server is third-party code the user explicitly marked as untrusted; yolo: true keeps that per-server choice. yolo: false, on the other hand, makes every MCP tool ask: turning protection on should never leave a hole.

How it relates to the rest

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Yolo mode and permissions — explanation

## What is this about?

A coding agent runs commands and writes files on your machine. Somebody has to decide whether each of those calls may run: either the user, call by call, or nobody, because the user decided once and for all to let the agent act. mini-me calls the second choice **yolo mode** and makes it one setting, `yolo`, read the same way by the three front ends — the line mode, the window and the editor (ACP) — and by an agent asked by another one.

## Why yolo is the default

mini-me is built to drive a small local model through many short steps. Asking before each `ls` makes that loop unusable in practice, and the line mode — the first front end — never asked at all. Before this setting existed, the behaviour depended on where you ran mm: the line mode never asked, the window asked only with `permissions: ask`, and the editor always asked, whatever you wanted. The same agent file did not mean the same thing in three places.

The default was therefore set to what most runs already did — run without asking — and the protection became a deliberate, visible choice: `yolo: false`. The banner says which way it is set (`yolo: on` / `yolo: off (tools ask)`), so nobody finds out by surprise, in either direction. The consequence worth knowing: in an editor, the permission dialog only appears with `yolo: false`; it used to appear always.

## Existing versus asking

Two different questions are kept apart on purpose:

- **Does the tool exist?** `bashTool`, `editTools`, `fetchContentTool`. A tool that does not exist is not declared to the model at all; it cannot even try.
- **Does an existing tool ask before running?** `yolo`.

So `yolo: true` with `bashTool: false` is an agent that edits files freely but has no shell, and `yolo: false` with `bashTool: true` is an agent that has a shell but needs your consent for each command. Merging the two into one tri-state (`bashTool: ask`) was considered and rejected: it would have to be repeated for every tool, while the real decision — "do I trust this agent to act alone right now?" — is a single one.

Only the calls that change something ask: `bash`, `write_file`, `edit_file`, `fetch_content` when it saves, `lsp` `rename`, and the `plan` actions that change a plan. Reads (`read_file`, `read_skill`, the `lsp` navigation actions, `fetch_content` without `output`) never ask: a dialog on every read teaches people to click "allow" without reading.

## Four answers, one memory

When a call asks, the answer can be *once* or *for the session*, and *yes* or *no*: allow once, allow this tool for the session, reject this call, never allow this tool in this session. "Never" exists because a refusal that only lasts one call leaves you rejecting the same retry again and again; "reject once" exists because without it the only way to say no would be final. A session's remembered answers are kept per tool name, survive `/new` (the editor still sees the same session), and disappear when mm exits.

The rules live in one package, `internal/consent`: the `yolo` check (`Gate`), the four answers (`Answer`), what a session remembers (`Policy`) and the line mode's prompt hook. Each front end only draws the question its own way — a `🔐` line, the window's box, the editor's dialog. Before, each front end had its own map of "allowed for this session", and the three had already started to differ.

## Why the asking agent decides

With `mmConfigs`, one agent can ask another (`/ask-jan`, `mm --ask jan`). Two configuration files, two `yolo` values: which one wins? The one of the agent the **user started**. It is the only agent with a user in front of it, and the user chose its configuration for this session; the asked agent's file was written for a different situation — perhaps for running alone in yolo mode.

Technically, the asked agent is started with `AGENT_YOLO=false`, so it submits every call it would gate through the ACP permission request — the same channel an editor uses. The asking agent receives it and runs it through its own `consent.Gate`: in yolo mode it allows at once; otherwise it asks its own user, in its own front end, and remembers the answer under `jan/bash` so that allowing Jan's shell does not allow yours. The asked agent itself never remembers anything: it is asked again each time, and the asking agent's memory answers.

One refinement keeps the same principle: the user's file may give an asked agent its own `yolo`, in that agent's `mmConfigs` entry (`homer: {path: …, yolo: true}`). It then decides that agent's calls instead of the asking agent's `yolo`: `true` runs them — a coder trusted with edits once the hand-off was approved —, `false` asks for each one even when the asking agent runs freely. It is still the file the user started that decides; the asked agent's own file still does not count.

## Modes that cannot ask

`mm -p` and `mm --ask` have nobody to ask: the first is a one-shot run, the second reads its question from stdin. With `yolo: false` they reject the calls that would ask and say so once on stderr. Allowing them silently would turn `yolo: false` into a setting that depends on how you launched mm, which is exactly the inconsistency this design removes; hanging on an invisible question would block scripts forever.

## Rejected alternatives

- **A `--yolo` command-line flag only.** It would not reach the sandbox kits or an editor's launch settings, which set environment variables and files, not flags. `AGENT_YOLO` covers the one-run case instead.
- **Keeping `permissions: ask | auto`.** It was read by the window only and appeared in no shipped configuration. It still works — `ask` means `yolo: false` — with a deprecation warning, so old files keep their protection.
- **Letting yolo override MCP servers marked `ask`.** An MCP server is third-party code the user explicitly marked as untrusted; `yolo: true` keeps that per-server choice. `yolo: false`, on the other hand, makes every MCP tool ask: turning protection on should never leave a hole.

## How it relates to the rest

- Configuration keys: [configuration reference](../reference/configuration.md).
- How to turn it on: [How to confirm tool calls](../how-to/confirm-tool-calls.md).
- The event path the front ends share (`ui.Sink`, `Allow`): [Architecture](architecture.md).
- Asking another agent: [Asking another agent](asking-another-agent.md).
- Deciding by rule rather than by asking: [Hooks](hooks.md) — a `preToolCall` hook runs before the consent question, so a call it denies is never put to the user.