A Windows-first Rust shell experiment built around explicit process launch, typed parsing, and narrow execution policy.
CreateProcessW over cmd.exe fallback. Explicit handles over ambient
inheritance. Small shell syntax over accidental compatibility.
Install · Docs · Quick Start · Capabilities · Syntax · Configuration · Verification
Created by Adrian Paredez, with Sole as his sovereign cognitive work partner.
M.I.L.N.E.R. stands for Managed Intent Layer for Native Execution Runtime. It is named in homage to Robin Milner, whose work on typed systems and communicating processes reflects the project's focus on structured intent, bounded execution, and process interaction.
Important
Milner is experimental. It is useful for studying a hardened Windows process runner and a deliberately small shell surface. Treat it as a research-grade command runtime, not as a production terminal environment.
Warning
Milner intentionally rejects .bat and .cmd targets. Batch files have
command processor quoting and metacharacter semantics that Milner does not yet
claim to make safe.
Install the latest Windows release binary:
irm https://paredez.dev/install.ps1 | iexDownload and verify the latest Windows release binary manually:
$asset = "milner-x86_64-pc-windows-msvc.zip"
$base = "https://github.com/AdrianParedez/milner/releases/latest/download"
Invoke-WebRequest "$base/$asset" -OutFile $asset
Invoke-WebRequest "$base/$asset.sha256" -OutFile "$asset.sha256"
$expected = (Get-Content "$asset.sha256").Split(" ")[0]
$actual = (Get-FileHash $asset -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actual -ne $expected) { throw "checksum mismatch" }
Expand-Archive $asset -DestinationPath .\milner
.\milner\milner.exe --promptInstall from source:
cargo install --git https://github.com/AdrianParedez/milner --locked
milner --promptRelease binaries are published when a vX.Y.Z tag is pushed.
The public documentation is organized under docs/:
cargo build
.\target\debug\milner.exe --no-config cargo --version
.\target\debug\milner.exe --no-config --line "cargo --version"
.\target\debug\milner.exe --no-config --promptPrompt mode:
milner> cargo --version
milner> pwd
milner> cd C:\Windows
milner> exit 0
Use exit [code] to leave prompt mode. In a Windows console, Ctrl +
Z then Enter sends EOF.
milner.exe <program> <args...>
milner.exe [options] <program> <args...>
milner.exe [options] --line <command-line>
milner.exe [options] --prompt
options:
--no-config
--config <file>
--cwd <dir>
--set-env NAME=VALUE
--unset-env NAME
--timeout-ms <ms>
Examples:
milner.exe --no-config notepad.exe
milner.exe --no-config powershell -NoProfile -Command "Get-Date"
milner.exe --no-config --line "cargo --version > version.txt"
milner.exe --no-config --line "powershell -NoProfile -Command \"[Console]::Error.Write('err')\" 2> error.txt"
milner.exe --no-config --timeout-ms 1000 powershell -NoProfile -Command "Start-Sleep 30"Policy shape at a glance:
+ milner.exe --line "cargo --version"
+ milner.exe --line "cargo --version > version.txt"
+ milner.exe --line "where powershell | findstr powershell"
- milner.exe --line "build.cmd"
- milner.exe --line "echo %PATH%"
- milner.exe --line "cargo test && cargo clippy"| Area | Current behaviour |
|---|---|
| Native launch | Resolves executables and launches with CreateProcessW.1 |
| Command parsing | Parses commands into typed structures before execution. |
| Prompt mode | Provides cd, pwd, complete, and exit built-ins. |
| Redirection | Supports stdin, stdout write/append, and stderr write/append redirection. |
| Pipelines | Supports exactly one two-command external pipeline. |
| Execution policy | Rejects unsupported operators, .bat, and .cmd targets. |
| Handles | Gives children only intended stdin, stdout, and stderr. |
| Configuration | Reads a small config subset for prompt, history, records, and aliases. |
| Cancellation | Cancels foreground process trees with --timeout-ms <ms>, Ctrl+C, or Ctrl+Break. |
More command examples
milner.exe --no-config --cwd C:\Windows notepad.exe
milner.exe --no-config --set-env MILNER_DEMO=1 powershell -NoProfile -Command "$env:MILNER_DEMO"
milner.exe --no-config --line "cargo --version >> output.txt"
milner.exe --no-config --line "powershell -NoProfile -Command \"[Console]::Error.Write('err')\" 2>> error.txt"
milner.exe --no-config --timeout-ms 1000 powershell -NoProfile -Command "Start-Sleep 30"| Form | Status | Notes |
|---|---|---|
program arg |
Supported | Bare words and quoted arguments. |
"empty" "" |
Supported | Empty quoted arguments are preserved. |
stdout > file |
Supported | Redirect stdout, replacing the target. |
stdout >> file |
Supported | Redirect stdout, appending to the target. |
stderr 2> file |
Supported | Redirect stderr, replacing the target. |
stderr 2>> file |
Supported | Redirect stderr, appending to the target. |
stdin < file |
Supported | Redirect stdin from a file. |
left | right |
Supported | Exactly one external two-command pipeline. |
&&, ||, ; |
Rejected | Explicit parse errors. |
| Variables, globs, substitution | Not supported | No silent expansion. |
.bat, .cmd |
Rejected | No cmd.exe fallback. |
Milner starts without configuration.
Default config path:
%APPDATA%\milner\config.toml
Use:
.\target\debug\milner.exe --config "$env:APPDATA\milner\config.toml" --prompt
.\target\debug\milner.exe --no-config --promptCurrent config subset:
[prompt]
text = "milner> "
[history]
enabled = false
path = C:\Users\you\AppData\Roaming\milner\history.txt
[records]
enabled = false
path = C:\Users\you\AppData\Roaming\milner\records.ndjson
[aliases]
gs = git statusImportant
Unknown sections and keys are rejected with a file path and line number.
History is disabled by default. When enabled without an explicit path, Milner writes history to:
%APPDATA%\milner\history.txt
History avoids recording command lines that contain obvious secret words such as
password, secret, or token.
Execution records are disabled by default. When enabled without an explicit path, Milner writes newline-delimited JSON records to:
%APPDATA%\milner\records.ndjson
Execution records are local only. They include parsed command structure,
resolution result, cwd, timing, exit or error status, and policy decisions.
They do not include environment values, stdout content, stderr content, or
remote telemetry. Milner skips records for command lines that contain obvious
secret words such as password, secret, or token.
Alias boundaries
- Alias cycles are detected.
- Alias values cannot include redirection.
- Alias values cannot include pipelines.
- Alias expansion cannot bypass executable resolution.
- Alias expansion cannot bypass
.bator.cmdrejection.
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test
.\target\debug\milner.exe --no-config powershell -NoProfile -Command "exit 0"Optional combined runner:
cargo install cargo-make cargo-nextest
cargo make verify-testsGenerate local Rust HTML documentation:
cargo doc --no-deps --document-private-itemsOpen:
target\doc\milner\index.html
GitHub Actions also uploads generated Rust HTML docs as the
milner-rustdoc-html artifact.
Known limitations
- Windows-only.
- No ConPTY or pseudoconsole terminal hosting.
- No arbitrary-length pipelines.
- No variables, globbing, aliases with redirection, or command substitution.
- No background jobs.
- No line editor crate, persistent completion engine, or theme system.
Licensed under the Apache License, Version 2.0. See LICENSE.
Footnotes
-
CreateProcessWstill receives a Windows command-line string, but Milner resolves the executable path first and passes it separately aslpApplicationName. ↩