Roadmap¶
Where Punix is going, and roughly in what order. For what already works, see what works; for what doesn't, limitations.
One rule governs everything on this page: nothing gets built without a real driver: a host in the corpus that needs it, or an explicit product decision. Several designs on this list are finished on paper and deliberately not coded, because code without a consumer is maintenance debt.
Stage 7: Corpus scale β ¶
Done. The brewβPCL translator handles every dominant Homebrew install shape (cargo, go, npm, autotools, cmake, meson, swift, pip, git-tag). 385 recipes build green from source; 67% of Homebrew's 500 most-installed formulae resolve through the corpus.
What's left here is a long tail rather than a milestone: translator extensions (multi-source Perl-CPAN bundles, git-only head do sources, vendored submodules) and per-recipe build fixes. Blockers names each one and the shape of its fix, so a contribution lands in the right layer.
Stage 8: Lifecycle and a second backend π§¶
The current arc. It closes most of limitations.
Already landed:
- Services actually start.
--activaterunsdaemon-reload+restartover the transport after the atomic flip;--enablemakes it survive a reboot. Proven byexamples/tangled-deploy, which deploys once and then restarts the container to show the stack coming back from the persisted generation alone. scope = "user": no root anywhere, units in~/.config/systemd/user/. This is what the planned--unit-dirflag turned into: the unit directory travels with the allowed config roots and the activator verb, so all three move together as one scope rather than as three knobs. Still local-only.punix verify: read-only drift detection against the current generation. Details.- Secrets to a
0600sidecar: automatic for any service whose environment holds a resolved secret.
Still open:
- A second service backend.
launchd(macOS),supervisord,docker-compose. The transport seam already takes them; the interesting part is that the fields you write today are systemd-shaped, so a portable stack needs a neutral service vocabulary underneath, rather than a second renderer. That's a design slice, not a rename. - Rollback should check the target's store rather than the deploy host's.
punix verifydoes this correctly and settles the shape;service rollbackhasn't adopted it. punix service set-current STACK N: jump to any preserved generation, forwards or backwards, instead of only stepping back one.- Cross-arch deploys should build on the target through the transport rather than pushing binaries that can't run there.
from_filesecrets need their own conformance test: they work; the property isn't pinned.
Stage 9: Release evidence¶
The proof v2.0 ships with:
- A ~3-minute screencast deploying a real monitoring stack to a cloud VM from a Mac.
- A blog post whose commands you can paste verbatim and end up with a working Grafana.
- Public CI badges, green on x86_64 and aarch64.
- This limitations page, complete.
v2.0 means "it works, look at this."
The remaining work is running it: examples/smallorg (four hosts, a derived WireGuard mesh, TLS, Postgres, a backup timer, and a monitoring stack whose scrape list is generated from the fleet model) is green in containers. Pointing it at rented hardware is the next step.
Stage 10: After 2.0¶
- Binary caches. The seam is already cut: the build loop asks a substituter for a path before building it, and today that's an empty list. Filling it in with an S3-style or peer-to-peer cache means popular packages stop being rebuilt on every machine.
- Reproducibility CI. Build the corpus on one architecture, snapshot it, rebuild on another, diff. Any drift turns the build red.
punix doctor: one command that runs every consistency check there is.
What is never coming¶
Three things are ruled out on purpose, and the design depends on their absence:
- Subtyping in the language. The type checker is provably decidable because there's no subtyping. Adding it would trade a guarantee for convenience.
- First-class type members. Same proof, same answer.
- Import-from-derivation: running a build in order to find out what the next build needs. That's an effect, and effects live below the eval/realise line. The equivalent capability exists as a deploy-time fetch instead.
β Decisions for the frozen constitutional layer.
Related¶
- What works: current capabilities, in plain language.
- Corpus status: the package side.
- Limitations: the gap list.