FreeWilly puts upstream Moby into a WSL2 distribution it owns, serves the docker_engine pipe every tool you already have looks for, and shows your containers in one window. Per-user install, no administrator prompt, and nothing left running that you did not ask for.
freewilly read context~150 tokengine running wsl:freewilly api=v1.43 pipe=docker_engine ctx=default(ok) web up 6m healthy svc:shop/web :8080→80 listening db up 6m healthy svc:shop/db :5432→5432 listening api exited 137 ×3/2m svc:shop/api OOM limit=512m disk images 14G (4.2G dangling) volumes 2.1G (1 unused) compose ./docker-compose.yaml → shop 3 svc, 3 present cursor c:4f21a0
freewilly read doctor api~200 tokfreewilly read logs api --dedup --budget 1500 --out .freewilly/logs/api.log~300 tokfreewilly do compose up --wait~100 tokfreewilly read verify svc:shop/api~80 tokA scripted session. The costs are targets the benchmark must prove or falsify, acceptance criteria and not measurements. Steps 1, 2, 3 and 5 are reads, so one allowlist line, Bash(freewilly read:*), removes every prompt on the inspection path while step 4 still asks.
FreeWilly is a Docker installation whose primary operator is a coding agent. The agent runs, inspects and diagnoses; you install, approve and intervene. Every decision on the agent surface is judged in tokens rather than clicks, which is why the site opens on a session and not a screenshot.
The desktop path is not sacrificed: the installer, the tray and the window are what it is for, and they landed before the agent surface did rather than after.
Binding, in the same sense as the product's. A feature that breaks one is wrong even if it was asked for. Each names the defect it prevents.
Every agent-facing capability is a freewilly CLI verb first. An MCP tool is a second head over the same method, or it does not exist.
Learning what the machine is running is a product feature, not a docs problem. Needing six commands to learn the engine's state is a defect in FreeWilly.
Every response has a size ceiling and the canonical task has a measured cost. “It got cheaper” has to be a number, and a regression fails the build.
An unbounded log read is the largest token sink here. Write it to disk and let the agent Grep it, so it pays for the lines that match, not for the whole log.
A 64-hex id changes on every recreate. The address is the name: svc:<project>/<service>, or the container name. Ids stop being currency threaded across calls.
Every refusal carries what was wrong, what is allowed, the nearest match, a correct example, and the Windows fact that explains it. An error that costs a round trip to read is a defect.
Read and write are split at the argv level so an allowlist can tell them apart. Destructive calls take a confirm token, and everything the agent creates is labelled with its session.
Give it cheap textual proof that what it started works (the port listens from Windows, the mount resolved, the service answered), or every mistake costs a trip back to you.
A cursor and a change feed, so a follow-up session reads the delta rather than re-deriving the whole machine from nothing.
The surface is a shape over the Engine API and facts Windows already knows. It is not a second Docker CLI and never grows a build, a push or a compose up of its own.
Moby and the docker CLI are Apache-2.0 and always were. What a company pays for, and what a managed laptop cannot install, is the wrapper around them. FreeWilly is a different wrapper: it installs the same engine, gets out of the way, and stops when you tell it to.
Free at any headcount, for any use, with no seat maths and no renewal date. That is the whole reason to try this instead of the thing everyone already has.
No Windows service, no scheduled task, and autostart is off until you turn it on. The engine runs for exactly as long as something is running it. An engine that holds gigabytes from every boot is the complaint this project starts from.
Everything lands under %LOCALAPPDATA%\FreeWilly: the verified downloads, the distribution's disk, and the docker.exe that goes on your PATH. Which is what reaches a corporate laptop you are not an administrator on.
Alpine's minirootfs, Docker's own static Linux binaries, Docker's own Windows CLI, each pinned to a version and a SHA-256 this project states itself. Nothing is patched, so nothing here can be blamed for how the engine behaves.
A preflight reads the Windows build, virtualization, the WSL2 kernel and any rival engine, and refuses the install while a blocking row is not green. Nothing is written to disk while the answer is no.
The distribution is called freewilly and it is this tool's, never yours. Your own WSL distros are untouched, and removing the engine cannot take anything of yours with it.
“It does not work on my machine” has five common causes on Windows, and they have five different remedies. freewilly --preflight names the one you have, prints the command that fixes it, changes nothing, and exits 1 so an installer can stop rather than fail halfway.
FreeWilly preflight: what this machine can host [ok ] Windows build Windows 10.0, build 26200 [ok ] Hardware virtualization enabled: a hypervisor is already running [FAIL] WSL2 not installed: wsl.exe is not on this machine -> Run `wsl --install --no-distribution` in an administrator terminal, then reboot. [ok ] Container engine nothing else owns the docker command or the docker_engine pipe 1 row blocks an install. Nothing has been copied to disk.
The same check runs inside the installer, and the same report is what a clean Windows 11 virtual machine is driven through on the way to a release, because a red row nobody has ever executed is not a check.
Provisioning runs from an installer, where there is no terminal to answer a prompt in. So every step is unattended, every step is named, and the run stops at the first failure. A report listing six failures where there was one is a report nobody can act on.
Five of the eleven steps, one per artefact: the Alpine root filesystem, the static Linux engine, the Windows CLI zip, and the Compose and Buildx plugins, each downloaded and checked against a digest recorded in this repository, not one served by the same host as the file. Already verified on disk means no second download.
The engine tarball's member list is read locally: do the entries share one top directory, and are dockerd, containerd, runc and the rest actually in there? A bad archive is caught before a distribution exists.
wsl --import freewilly … --version 2. A fixed name that is this tool's, so an apt upgrade or a wsl --unregister you ran for your own reasons cannot take the engine with it.
One non-interactive sh script under set -e, so it stops where it broke: iptables and socat from apk, the binaries unpacked into /usr/local/bin, and systemd=false, because nothing here is a service.
docker.exe is extracted to …\FreeWilly\bin. Putting that directory on your PATH is the installer's job, and this step's only job is being the path it points at.
Both plugins go where the CLI looks for one, so docker compose up and docker buildx build work from the install rather than from a second download, pinned by digest like everything else here. Every build the daemon kept is a page in the window, which is also where the docker-desktop:// link buildx prints at the end of a build lands.
--plan prints every pinned version, digest and path and reaches nothing at all. --acquire downloads and verifies, and stops before WSL2 is touched. Both change nothing outside this tool's own directory.
--plan the pinned versions, digests and paths; reaches nothing
--acquire download and verify every artefact, and stop
--provision acquire, import the distribution, install the engine
--run start the engine and serve the pipe until Ctrl+C
--stop stop the engine and terminate the distribution
--status what the engine is doing, by asking it
--fsck check the distribution's filesystem; --repair to mend what it finds
--fsck-drill rehearse the repair on a scratch disk dirtied on purpose, touching
nothing on this machine
--compact hand back what the virtual disk is holding and nothing wants; with
the --as-administrator flag it takes the route Windows leaves when
it has turned the other one off, raising a prompt and stopping WSL
--compact-drill rehearse the compaction on a scratch disk grown and emptied on
purpose, touching nothing on this machine; add the same
flag as above to rehearse the elevated route instead
--api version and containers, read through the Engine API
--watch print /events as they happen, until Ctrl+C
--autostart on | off | status - off unless you turn it on
Exit code 0 means the mode finished; 1 names the step it stopped at. For --status, 1 means the engine is not answering.docker commands do not need to knowA Linux dockerd cannot create a Windows named pipe, because that is a Win32 object. So something on the Windows side has to, or every shell and every script you already have needs a DOCKER_HOST. FreeWilly is that something.
The pipe is created for your account and nobody else. A forwarded port cannot say that, and full access to the Engine API is full access to the machine, so the hop runs over wsl.exe's stdio instead.
It is the same pipe name, so the CLI, Compose, Testcontainers, an IDE plugin and whatever your CI script does locally all find it without a setting. Nothing has to be told about FreeWilly.
The app talks HTTP over the pipe directly, a named-pipe stream handed to .NET's own HTTP handler, pinned to Engine API v1.43. No NuGet package, and no shelling out to docker.exe once per refresh.
The icon carries the engine state as a shape, and colour only reinforces it. At sixteen pixels a hue is a hint: two of these are seen at a glance, by people who may not separate red from green, against a taskbar that is light on one machine and dark on the next. These three are still distinguishable in a screenshot printed in black and white.
A filled disc. And it means the engine answered: the state comes from the event stream's own connection, not from remembering that a start was clicked.
A ring with a bite out of it: the same outline as stopped and unmistakably not it, which is what tells “on its way up” from “not running” without relying on hue.
A plain ring. Start engine is one click away in the menu, and it launches the engine in a process the tray does not own.
Because that is what the tool is opened for. Name, image, state, how long it has been up, and the ports. And the ports are links, because a published 8080 is the thing you actually wanted and retyping localhost:8080 is a small daily tax a GUI exists to remove.
ThemeMode="System", so light and dark follow the OS, with no extra package./events as the daemon writes it, and only the events that change a container list cost a read, because the rest would be a poll in disguisedocker run in any shell appears without you touching the windowhttp://localhost:x is not where a published UDP port isdocker-desktop:// link buildx prints at the end of every build lands, because the record it names is one the daemon kept and only the address was deadwsl.exe said the last time it would not start, and the suspend it did not survive. Beside it, what the machine under the engine is doing: the WSL and kernel versions, the root device and whether it is still writable, what ext4 has recorded against it, and what the virtual disk says it is against what Windows is really charging for it, beside the space used inside and left on the drive: a disk that was handed back keeps its size on paper long after the volume stopped paying for it. And a check that reads the filesystem, which offers to repair it only once it has found something and shown you what, beside a Compact button that drops the build cache, trims the filesystem and hands the freed blocks back. Current Windows builds have sparse virtual disks turned off, and where the hand-back is refused for that reason the page offers the one route left: it asks for administrator rights, shuts every WSL distribution down rather than only this product's, and costs nothing at all if the prompt is declinedEach section above has a page to link at, whether from a README, an issue, or a search result.
The five common causes of a Docker failure on Windows, each with the command that fixes it, read-only and exit 1 while a blocking row is not green.
Read the page →Eleven unattended steps that stop at the first failure: acquire and verify five artefacts by digest, inspect the archive, import an owned WSL2 distro, install inside it, and place the CLI with its Compose and Buildx plugins.
Read the page →A Linux dockerd cannot create a Windows named pipe, so FreeWilly serves docker_engine and forwards over wsl.exe stdio. The ACL grants your account and nobody else, which a forwarded port cannot express.
Read the page →One window that is the list of containers, with ports as links; acting on a container; logs and a shell for what the state does not say; and images and volumes made legible.
Read the page →One budgeted context pack answers a session's opening questions; read doctor is the diagnostic join; and every refusal carries the Windows fact that explains it.
Read the page →Five things this project has decided against, written down where they can be pointed at. A tool with no stated non-goals is a tool that will eventually be asked for all of them.
Kubernetes, extensions, a dashboard for everything. The list a user actually opens the app for is short, and stopping there is what keeps this small enough to trust.
Upstream Moby, unpatched, pinned by digest. If the engine misbehaves, that is between you and upstream, and this project has not touched it.
Linux already has the engine, and the entire mechanism here is WSL2 and a Windows named pipe. Portability would mean a different tool wearing the same name.
Nothing is measured, nothing is sent, and there is nothing to register. There is no build of this with an opt-out.
The complaint that sends people looking for an alternative is an engine holding gigabytes from every boot. Not being that is the product, not a preference.
The release page carries the installer and the SHA256SUMS.txt to check it against, and nothing else to choose between. It installs into %LOCALAPPDATA%\FreeWilly for your account alone, which is what reaches a managed corporate laptop, the machine this project exists for. The WSL2 feature the engine needs may still want elevation of its own; the installer runs the preflight and says so rather than failing halfway through a download.
Uninstalling removes what was installed and asks about what was created. The freewilly distribution holds every image, container and volume you have, so it is never deleted without a question, and an unattended uninstall keeps it.