Skip to content

Repository files navigation

kai

kai (n., Norwegian) — the quay: the edge of the dock where a ship is tied up and worked. Sibling to skrog, which is Norwegian for the hull.

A small aid for people using wslc who have Docker muscle memory. It takes a Docker command line, runs the wslc equivalent, and stops with a reason where wslc has no equivalent.

kai ps

CONTAINER ID   IMAGE     COMMAND            CREATED      STATUS      PORTS   NAMES
9a04f5414434   busybox   "sleep infinity"   2 days ago   Up 2 days           web

That is wslc list, and the output is wslc's — kai says nothing of its own when a translation is clean. When it will not run something, it says why:

kai run --restart unless-stopped nginx

kai: cannot run 'docker run --restart unless-stopped nginx'.
     wslc has no restart policy. A container that exits stays exited. Use
     a real Docker engine: Docker Desktop, Rancher Desktop, or skrog
     (https://github.com/wslkit/skrog).

--dry-run shows the translation without running it:

kai --dry-run run -d -p 8080:80 --name web nginx

  docker   docker run -d -p 8080:80 --name web nginx
  wslc     wslc run -d -p 8080:80 --name web nginx
  verdict  identical, no rewrite needed
kai --dry-run run --restart unless-stopped nginx

  docker   docker run --restart unless-stopped nginx
  wslc     (cannot be expressed)
  error    wslc has no restart policy. A container that exits stays
           exited. Use a real Docker engine: Docker Desktop, Rancher
           Desktop, or skrog (https://github.com/wslkit/skrog).

What kai is not

This matters more than the list of features, because every failure mode of a tool like this comes from quietly becoming one of these.

  • Not a Docker-compatible CLI. No API, no daemon, no compatibility promise.
  • Not an emulation layer. It rewrites spelling and reports the result. It never approximates: it will not implement a missing capability, fake a semantic wslc lacks, or drop an argument it cannot express. A single unsupported flag fails the whole invocation rather than running the rest.
  • Not a compose runner. kai never executes compose. It will read a compose file and tell you what wslc could not honour — see below.
  • Not a competitor to skrog. skrog serves the real Docker API, so unmodified docker, Compose, Testcontainers, buildx and Dev Containers work. kai serves a person typing at a prompt. Different problem, different answer.
  • Not a product with a support promise. A personal aid that happens to be public.

Status

Pre-release, v0.2: kai executes. It translates and runs, and refuses outright where wslc has no equivalent. What it will never do is approximate — a single unsupported flag fails the whole invocation rather than running the rest, because a container that came up without the flag you asked for looks like it worked.

Three rules it holds to while running things:

  • stdout belongs to wslc. Every message kai emits goes to stderr, so kai ps | ConvertFrom-Csv sees exactly what wslc list would have produced.

  • the exit code is wslc's, unchanged. kai's own refusal uses 125, which is distinguishable — wslc returns 1 for its own failures.

  • interactive works, because kai never captures output. kai run -it and kai exec -it inherit kai's own stdin, stdout and stderr.

    One limit worth knowing, measured rather than assumed: kai is a PowerShell function, so piping into it from PowerShell does not reach the container'x' | kai run -i --rm busybox cat gets you nothing. Pipeline input binds to the function; the container inherits the process's stdin. Redirecting a file, typing at a console, or piping from cmd/bash all work.

Tables measured against WSL 2.9.12, 2026-09-21. The wslc surface moves every release — re-measure before trusting them.

Aliasing docker to kai is not here yet; that is v0.3, and it is the one genuinely hazardous feature (§06 rule 1), so it arrives opt-in and refusing to shadow a real docker.

Requirements

  • PowerShell 7.3 or newer. kai pins $PSNativeCommandArgumentPassing = 'Standard' inside the module, and that mode does not exist below 7.3. It guards against inheriting Legacy from a caller's profile, which corrupts exactly the arguments Docker users pass — a spaced -e value, a --format template, a JSON --entrypoint.
  • WSL with wslc. wslc.exe lives in C:\Program Files\WSL. Unlike wsl.exe it has no alias stub in System32, so whether a bare wslc works depends on your shell. kai resolves it explicitly.
  • powershell-yaml, and only for kai compose check. Its absence is a supported state, not a broken one: the check says so and everything else keeps working.

Install

kai is not on the PowerShell Gallery yet. Per its own plan, publishing waits until somebody other than the author has run it.

git clone https://github.com/wslkit/kai
Import-Module ./kai/kai.psd1

When it is published, the two supported routes will be:

Install-Module kai            # or: Install-PSResource kai

If you install from a downloaded .zip instead, Windows marks the files as coming from the internet and RemoteSigned will refuse to load them. Unblock them first:

Unblock-File -Path .\kai\*.ps*1

No certificate is needed for any of this. That is deliberate — see PLAN.md §07a.

Using it

Translating a command

kai --dry-run cp ./local.txt web:/tmp/local.txt

  docker   docker cp ./local.txt web:/tmp/local.txt
  wslc     wslc container cp ./local.txt web:/tmp/local.txt
  verdict  rewritten -- wslc keeps cp under the container group rather
           than at the top level.

Where there is no equivalent at all, kai says what is missing, why it matters, and what to use instead:

kai --dry-run events

  docker   docker events
  wslc     (no equivalent)
  error    wslc exposes no engine event stream. Tools that reap containers
           by watching it -- Testcontainers' Ryuk is the one people hit --
           cannot work here at all. Use a real Docker engine: Docker
           Desktop, Rancher Desktop, or skrog
           (https://github.com/wslkit/skrog).

kai exits 125 when it refuses an invocation, which is distinguishable from anything wslc returns — wslc uses 1 for its own failures. The one ambiguity, shared with Docker for the same reason: a container that itself exits 125.

Checking a compose file

kai never runs compose. It will read one and tell you exactly what would be ignored — which is the more useful thing, because nothing errors when a key is dropped; the stack just comes up wrong.

kai compose check docker-compose.yml

  services: 3

  api
    image            supported
    ports            supported
    depends_on       NOT SUPPORTED   Dependency order is ignored. Services may start in any order.
    healthcheck      NOT SUPPORTED   No health checking, so nothing waits for a service to become ready.
    environment      supported
  db
    image            supported
    volumes          supported
    environment      supported
  worker
    build            NOT SUPPORTED   wslc compose cannot build. Pre-build the image and reference it by name instead.
    restart          NOT SUPPORTED   No restart policy. A container that exits stays exited.

  verdict: this file cannot run correctly under wslc compose.
           4 of 10 keys used are unsupported, and each of them is
           ignored rather than rejected -- the stack comes up wrong
           with nothing reporting an error.
           Use a real Docker engine: Docker Desktop, Rancher Desktop,
           or skrog (https://github.com/wslkit/skrog).

This report is provisional and says so in its own output. wslc compose has not shipped: the supported-key list is read from the C++ struct in an open draft pull request (microsoft/WSL#41526), not from anything you can run. It gets re-checked against the header when that lands.

Which commands map, and which do not

Measured against WSL 2.9.12. Four groups, and most of the surface is in the first one — the gap is much smaller than it looks.

Identical — type it and it works (25 commands, 5 groups)

kai passes these straight through and says nothing. There is nothing to translate.

attach build create exec export
images import info inspect kill
load login logout logs pull
push restart rmi run save
start stats stop tag version

And the command groups container, image, network, volume and system.

Already aliased by wslc itself (2)

wslc accepts the Docker spelling directly, so kai stays out of the way — §06 rule 3: never intercept what already works.

you type wslc runs who handles it
docker ps wslc list wslc, natively
docker rm wslc remove wslc, natively

Actually needs mapping (1)

you type kai runs why
docker cp wslc container cp wslc keeps cp under the container group rather than at the top level

That is the whole of it. One command.

No equivalent at all (19)

kai refuses these outright and says what to use instead. Eighteen of them are Docker commands with nothing behind them in wslc; the nineteenth is compose, which wslc has not shipped and kai would never run anyway.

command what is missing
commit cannot create an image from a container's current state
diff cannot report filesystem changes inside a container
events no engine event stream — see below
history cannot show an image's layer history
pause / unpause cannot suspend or resume a container's processes
port no command lists a container's published ports
rename cannot rename an existing container
top cannot list processes inside a container
update cannot change a running container's limits
wait cannot block until a container exits
search cannot search a registry
manifest no multi-architecture manifest tooling
plugin no plugin system
swarm no clustering or orchestration
context no notion of a context pointing at another engine
bake / builder Buildx features; wslc's build is not Buildx
compose not shipped, and kai never runs it — use kai compose check

events is the one that bites hardest: Testcontainers' Ryuk watches the engine event stream, so a whole class of tooling cannot work here at all.

And at flag level

A command existing is not the same as a flag existing. 20 common docker run / docker create flags are rejected outright, including --restart, --privileged, --add-host, --device, --cap-add, --platform, --volumes-from and --read-only.

kai refuses the whole invocation when one appears, rather than dropping it and running the rest.

You do not need to memorise any of this. Ask kai about the command you were about to type — kai --dry-run <command> — and it will tell you at the moment you need to know.

If you need a real Docker engine

Docker Desktop, Rancher Desktop, or skrog — which serves the real Docker API on Windows via WSL2, so Compose, Dev Containers and Testcontainers work unmodified.

Naming

No "docker" and no whale in the repository name, the module name, or any package id. The mark is not ours to use as a name. Referring to what kai does — "lets you type Docker commands against wslc" — is fine, and is how this should be described.

Contributing

See CONTRIBUTING.md. The design, the scope fence and the measurements behind all of the above are in PLAN.md.

Licence

Apache-2.0. See LICENSE.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages