nervネルフ

What may run

Every read, write, command and host passes the ledger before it happens — and the answer is reusable, or every session is a hundred prompts.

plate 10the ledger, in order

Four verbs

verbis about to
readopen a file
writecreate or change one
runexecute a command
reachconnect to a host

Five widths

The verb is what is about to happen; the width is how far the answer reaches. The width is what makes a ledger worth having instead of a prompt per call.

widthcovers
oncethis call and nothing else — the default, and the only answer that cannot be over-granted
exactthis path, or this exact command line, again
directoryanything under it. Paths are normalised before the check, so work/sub/../../secret is not covered by a grant on work.
programgit, whatever the arguments. A command line carrying a metacharacter is refused rather than matched — git status; rm -rf / is not git.
anythingevery action of that verb, for this session

Granting in advance

magi.allow = {
  { verb = "read",  directory = "/home/you/work" },
  { verb = "run",   program = "git" },
}

A rule written down is not a question asked. The standing answers are ones you decided in advance, in a file, rather than under time pressure mid-turn. A rule naming no width grants nothing.

Confinement is a wall

magi.confine refuses paths outside the session root outright — no prompt, no grant, no appeal. It applies whether or not there is anybody there to ask, which is why it sits before the ledger rather than inside it.

It is not containment. Confinement covers read, write and edit. It moved work to the shell, which has none — bwrap in front of the shell peer is what actually contains anything.

When nobody is there

A run with no UI attached has nobody to ask. It is refused, and the tool is told why — a session whose front end has detached does not get to assume the answer would have been yes. That is why magi -p refuses an ungranted read rather than hanging on a question nobody can see.