For the agent's operator

Configure it once, and the reads stop asking

Listing containers and deleting a volume are one string to an allowlist, so a user either grants every docker call — which permits deleting a volume — or approves each one. Splitting the verbs in argv makes it one line of settings, and what that buys is not keystrokes: it is the removal of an interruption from the 90% of agent Docker work that mutates nothing.

10 verbs, and every one of them exists. The list below is the registry the build reads, so a verb that has not landed is not on it — and the ceiling beside each one is the figure a build fails on rather than a number this page claims.

The friction this removes

What plain docker costs an agent, and what replaces it

None of this is a defect in Docker. Every one of these is what a CLI built for a person at a keyboard does to a reader that pays per token, cannot see the screen, and has to ask permission — and the costs on the left are measured, not estimated.

The canonical task, measured: bring the stack up and say why the api container is not answering 11,711 est. tokens 6 calls target 5,000 over 5

Measured over the Engine API's compact payload, which is the transport this project's own surface is built on — so read it as a floor for today's cost, not a ceiling. docker inspect prints indented JSON, so an agent going through the CLI pays several times this for the same entity. The ceilings on the right are asserted by a test: a response that grew fails the build.

The output is a table for a person, and the reader is not one

docker today

docker ps -a

1,906 tok measured

Columns truncate, rows come back in creation order — which moves the moment anything is recreated, so two reads cannot be diffed — and nothing carries a cursor. So a session re-reads the whole machine three to five times as state moves, and that re-discovery, not the log, is the largest single driver of the total.

here

freewilly read context

200 tok ceiling

One payload: the engine, every container with its state and compose address, the published ports, the disk, and a cursor that fingerprints the machine. Sorted by name, so it caches and a diff means something. It also answers the canonical question — OOM limit=512m — in the first call, with no second one.

Four fields cost the whole entity

docker today

docker inspect api

1,603 tok measured

Three to six hundred lines of JSON, of which an agent reads four: the exit code, whether it was OOM-killed, the port bindings and the mounts. There is no projection to ask for, so the whole entity tree — every default, every piece of authoring metadata — is paid for to learn four things.

here

freewilly read doctor api

305 tok ceiling

The same join, returned as a verdict and a remedy per row, over the model the preflight already uses: state, memory, restarts, health, ports and mounts. What comes back is the conclusion and the action, not the fields they were read from.

A restart loop is billed once per restart

docker today

docker logs --tail 200 api

4,170 tok measured

--tail is the only instrument: no dedup, no level filter, no cursor, no ceiling. A container that restarted eight times hands over the same stack trace eight times, and the caller either truncates blind or pays for all of it.

here

freewilly read logs api --dedup --level warn --out .freewilly/logs/api.log

400 tok ceiling

--dedup collapses an identical line to one and a count, across the whole read rather than only adjacent ones — the copies of a trace are separated by everything each run printed. --level keeps every line that did not say what it was, so the filter can narrow the log without hiding the answer. And --out writes it to a file the agent Greps, paying for the lines that match instead of for the log.

A truncated read is indistinguishable from a log that ended

docker today

docker logs --tail 200 api | head

A cut arrives looking exactly like the end of the output. Nothing in what comes back says a line was dropped or where to resume, so a reader draws a conclusion from a page that was never the whole story — and nobody finds out.

here

truncated 37 more line(s) — budget reached, read on from the cursor

Every budgeted payload here cuts from the end, states how much it cut, and prints the cursor to read on from. A silent truncation is the one thing a ceiling must not become, so it is the property the tests hold rather than the size.

The id is the currency, and it changes on every recreate

docker today

docker inspect 9c1f0b7a4e2d…

A 64-hex id has to be threaded across calls by hand, and it is gone the next time the container is recreated. Meanwhile the same service is called one thing by docker ps and another by docker compose ps, so an agent holding one name cannot always use it with the other command.

here

freewilly read doctor svc:shop/api

The address is the name: the container's, or svc:<project>/<service> read off the compose labels the daemon already carries. Ids stay valid and stop being currency, so a name learned in the first call still works in the fifth.

The last question is one Docker does not answer at all

docker today

docker port api

This reports the mapping the daemon intends, which is not the same claim as 8080 answers from Windows — a running container with a bound port can answer nothing. And when the bind fails, port is already allocated does not say what holds it, because the daemon does not know. So the agent cannot see whether its own work landed, and closing that gap means coming back to you to look — the most expensive unit in the system.

here

freewilly read verify svc:shop/api

240 tok ceiling

FreeWilly is a Windows process, so it can join what the daemon cannot: whether the host port actually listens, which PID holds it, whether a rival engine is answering the pipe, whether a stale context is pointing the CLI elsewhere. read doctor already carries the port fact; read verify is the standalone proof, and read ports is the refusal that names the process holding the port.

Every call is a permission decision

docker today

Bash(docker:*)

docker ps and docker rm -f -v are the same string to an allowlist. No Docker tool can express the rule a user actually wants, because docker mixes both in one verb namespace — so you either grant the lot, which permits deleting a volume, or approve every read by hand.

here

Bash(freewilly read:*)

Reads and writes are separate words in argv, so the rule is one line — and it is enforced under it: a read verb is written against a handle with no start, no remove and no prune on it, and a test drives every one of them and requires each request it made to be a GET.

Nothing carries over, so session N+1 costs what session N did

docker today

docker ps -a # again, from nothing

There is no cursor and no delta, so the next session re-derives the machine the last one already learned. The most expensive read on this page is the one that was paid for yesterday.

here

freewilly read changes --since c:4f21a0

Every pack already prints a state cursor, and the tray already holds the engine's event stream open for the window — so the delta is a cursor over a stream the user started rather than a daemon this adds. It is the only mechanism here that makes a second session cheaper than the first.

The one line that pays for it

One entry in .claude/settings.json:

Bash(freewilly read:*)

read is a promise, not a naming convention: a verb under it that writes is a defect. So this single grant removes every prompt on the inspection path, while every do still asks.

read — the inspection path (no prompt)

context 200 tok

the whole machine in one budgeted, terse payload — engine, services, ports, disk, cursor

doctor <name> 305 tok

the diagnostic join: the verdict and the remedy for one container

logs <name> 400 tok

deduped and budgeted, written to a file the agent Greps — paying for matches, not the whole log

ps 320 tok

the container list, addressed by name, with a cursor

ports 120 tok

what is published, and whether it actually listens from Windows

changes --since <cur> 115 tok

the delta since last session, so N+1 is cheaper than N

verify <target> 240 tok

cheap textual proof a service answers — the agent cannot see

do — the mutating path (still asks)

compose up 140 tok

brings the project here up, stamped so do reclaim can take it back

engine 40 tok

start or stop the engine itself

reclaim 170 tok

an undo scoped to this session's own labels
Discovery

The plugin that makes it discoverable

A surface nobody discovers is one nobody uses, and the moment it is discoverable is the moment the installer runs. So the Claude Code plugin — the skill, the allowlist entry, and a project brief generated from the live machine — ships with the install rather than being something to go and find.

Scope

What it deliberately refuses

FreeWilly is the substrate; the intelligence is the caller's. It is a CLI over the Engine API and facts Windows already knows — not a second Docker CLI (P10).

No model

It calls no LLM.

No prompts

It stores none.

No API keys

There is no secret to hold.

No build

That stays docker's.

No push

And so does that.

No registry auth

do compose shells out to yours.