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.
Four verbs
| verb | is about to |
|---|---|
| read | open a file |
| write | create or change one |
| run | execute a command |
| reach | connect 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.
| width | covers |
|---|---|
once | this call and nothing else — the default, and the only answer that cannot be over-granted |
exact | this path, or this exact command line, again |
directory | anything under it. Paths are normalised before the check, so work/sub/../../secret is not covered by a grant on work. |
program | git, whatever the arguments. A command line carrying a metacharacter is refused rather than matched — git status; rm -rf / is not git. |
anything | every 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.
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.