Build plan · revision A
A System 7 workalike that boots on real hardware
A graphical-only Devuan ISO running mlvwm on XLibre, with a System Folder, no user accounts, AppImages in /Applications, and classic Mac software one double-click away. Everything but the last item is a weekend-to-a-fortnight project. The classic-app layer is where the difficulty lives — and the constraint that makes it hard is legal, not technical.
The headline finding: there is a fully redistributable path to running System 7 software, and it does not involve an Apple ROM. See Classic Applications.
Component scoreboard
| Component | Verdict | The actual obstacle |
|---|---|---|
| Boot straight to graphics | Easy | None. Standard live-image practice. |
| mlvwm on XLibre | Easy | 1990s imake and K&R C. XLibre is Xlib-compatible; mlvwm cannot tell it apart from Xorg. |
| “System Folder” layout | Scope call | Cosmetic version is trivial. A literal one means rebuilding the toolchain. |
| AppImages in /Applications | Easy | Menu regeneration, FUSE versions, and write persistence on a live ISO. |
| A Finder | Gap | mlvwm is only a window manager. No desktop icons, no file manager, no Trash. |
| No user accounts | Easy | Some applications refuse to run as uid 0. Use a fixed unprivileged user instead. |
| .sit / .hqx / .bin extraction | Easy | Preserving resource forks across the Linux filesystem. |
| Mounting HFS volumes | Easy | Prefer sandboxed FUSE over the in-kernel drivers — not because they are going away, but because parsing untrusted 1990s media in ring 0 is the wrong place for it. |
| Running System 7 applications | Hard | Apple ROMs and Apple system software are not redistributable. One clean-room path is. |
| Seamless (rootless) windows | Research | Nothing off-the-shelf does per-window compositing for 68k Mac software. |
The goal is zero text frames: from firmware handoff to a dithered desktop, the user never sees a console.
Decisions
- Base distribution: Devuan. It inherits Debian's archive, so the entire long tail you need is already packaged — unar, macutils, hfsutils, hfsprogs, qemu — without systemd underneath it. Alpine would give you a ~200 MB ISO, but rebuilding that long tail costs more time than the disk space is worth.
- Init. sysvinit is the default and the right call here: this system has a fixed, known boot path with no dynamic service topology to manage. runit is a reasonable alternative if you want supervision for the /Applications watcher, but the watcher belongs to the X session, not to init — start it from the session script and the question goes away.
- Hiding the console. quiet loglevel=0 vt.global_cursor_default=0 on the kernel command line, plus a Plymouth theme, or a bare X splash started from the initramfs if you want to skip Plymouth's dependency weight.
- No display manager. Autologin on tty1 via agetty --autologin macintosh in /etc/inittab, then startx from the shell profile. No getty on the other VTs, so there is no second console to stumble into.
- Image builder. live-build is packaged for Devuan and is the shortest path from a package list to a bootable ISO. Devuan's own Refracta tooling is the native alternative and is better at snapshotting a system you have already configured by hand — useful later, once the layout has stopped moving.
Devuan is a good fit beyond the init preference
A System 7 workalike wants a small, legible, static system with a fixed boot path and no service manager negotiating seats and sessions on its behalf. That is Devuan's whole thesis. The one thing to watch: some AppImages expect logind to exist. Devuan ships elogind for exactly this — install it, along with a minimal session dbus, and treat the pair as a compatibility shim for modern applications rather than as part of the system's own architecture.
Bases weighed
| Base | Verdict | Reasoning |
|---|---|---|
| Devuan | Chosen | Debian's archive without systemd. Every tool in this document is already packaged, which is the single largest time saver available. |
| Tiny Core | Steal from it | Architecturally the closest thing to this vision that already exists — see below. Rejected as the base on packaging grounds alone. |
| Alpine | Viable, costly | A ~200 MB ISO and a clean musl base, but the long tail is thinner and musl breaks a share of prebuilt AppImages outright. |
| Arch | No | A rolling base under an immutable, frozen-by-design system is a permanent maintenance tax for no benefit here. |
Tiny Core deserves a real answer, not a dismissal
It already implements three things this plan spends effort building. It runs entirely from RAM off a read-only base, which is exactly the immutable System Folder model. It boots straight into X with no display manager and no meaningful account model — the tc user with passwordless sudo is the “no user accounts” goal, already shipped. And its .tcz extension format is squashfs images mounted on demand, which is the same idea as dropping a self-contained bundle into a folder and having it become an application. The philosophical overlap is not partial; it is near-total.
What kills it as the base is the long tail. unar, macutils, hfsutils, hfsfuse, dmg2img, mlvwm, XLibre, Executor, and AMS would all become extensions you build and maintain yourself, on a busybox userland, using an on-demand toolchain. That is the entire dependency surface of this project moved onto your shoulders in exchange for saving a few hundred megabytes. AppImages compound it: they assume a conventional desktop baseline, and Tiny Core is the least conventional baseline available.
The useful synthesis: stay on Devuan and take Tiny Core's architecture anyway — read-only squashfs base, RAM-resident, writable overlay only where the user's own files live. That is already what Fig. 1 and Fig. 2 describe. Revisit Tiny Core as a separate minimal edition once the components are packaged and the porting cost is a known quantity rather than an open one.
Do not run the session as root
“No user accounts” is a user-experience goal, not a uid goal. Chromium-based AppImages and several other applications hard-refuse to start as uid 0. Ship a fixed unprivileged user — call it macintosh, uid 1000, no password, autologin, no account visible anywhere in the interface. Semantically account-free, practically sane. Classic Mac OS had no accounts either; it still ran as an unprivileged system.
What the finished system looks like in normal use: a mounted HFS volume, an AppImage running natively, and a 1994 application in a window beside it.
- 1Menu bar drawn by mlvwm's own bar, not a panel. The mark at the left is a placeholder — see Trade dress.
- 2The System Folder, presented read-only. Its contents are bind mounts onto ordinary FHS paths.
- 3/Applications holding AppImages and classic applications side by side, indistinguishable to the user.
- 4A mounted HFS volume from a period disk image, via userspace FUSE.
- 5A 1984 application running under a clean-room Toolbox reimplementation, framed by mlvwm.
- 6Trash supplied by the Finder replacement, since mlvwm has none.
The gap nobody mentions: mlvwm is only a window manager
It draws System 7 chrome and manages windows. It has no desktop icons, no file manager, no Trash, and no double-click-to-open. Almost everything in the mockup above that makes it feel like a Macintosh comes from a second program you still have to choose.
ROX-Filer is the closest lightweight fit — pinboard desktop icons, application directories, small dependency footprint. Before committing, look hard at helloSystem: it is a FreeBSD project that has already built most of this vision, and its Qt-based “Filer” is worth borrowing conceptually even though you cannot lift it wholesale onto Linux without work.
Make it a presentation layer, not a filesystem rewrite. The user sees a System Folder; the dynamic linker still sees the paths it was compiled against.
Hide the FHS directories from the Finder with a dotfile-style ignore list rather than by moving anything. The Finder replacement decides what is visible; the kernel keeps its own opinion. Nothing on the system needs patching.
Do not do this literally
A real System Folder — with the OS actually living there and no /usr or /lib at all — means a GoboLinux-style rebuild: patched dynamic linker, patched build system, every package rebuilt against new paths, and permanent divergence from the upstream archive. That is a distribution-year of work and it buys nothing the bind-mount presentation does not. Take the cosmetic route and spend the year on the classic-app layer instead.
Drop a file in a folder; it becomes an application. AppImage is already a single-file bundle, so this maps onto the Macintosh model almost for free.
Notes on implementation
- Marked block, not full rewrite. Bracket the generated menu with sentinel comments in .mlvwmrc so a user's hand edits outside the block survive regeneration.
- Restart, not reload. mlvwm predates runtime config reloading; the practical move is Restart, which preserves managed windows.
- Classic applications land here too. A System 7 application in /Applications gets the same treatment — the indexer just routes it to a different launcher. To the user there is one folder and one gesture.
The whole problem here is the resource fork. Solve it by never letting the payload sit on a Linux filesystem in the first place — go straight from archive to HFS image.
Toolchain
| Tool | Handles | Note |
|---|---|---|
| unar / lsar | StuffIt 1–5, much of SITX, BinHex, MacBinary, Compact Pro | The Unarchiver's command-line tools. Already in the archive, actively maintained, and can emit resource forks rather than discarding them. |
| macutils | .hqx, .bin, MacBinary streams | hexbin and macunpack. Ancient, unglamorous, and still the answer for 1980s uploads that unar declines. |
| hfsutils | Classic HFS read/write | hmount, hcopy -m, humount. Userspace, so no kernel exposure. This is how software gets into a volume. |
| hfsfuse | HFS+ / HFSX | Actively maintained FUSE driver. Read-oriented; treat it as the safe way to browse period media. |
| dmg2img | .dmg | Converts to a raw image the above tools can open. |
Prefer userspace mounting — for the security reason, not the removal reason
The in-kernel drivers survived. hfs and hfsplus had been orphaned since roughly 2014, and an effort to delete them outright ran through 2025. Maintainers stepped up instead: as of the current tree both are marked Maintained, with three maintainers and a dedicated git tree. Debian Ports carried much of the argument — without HFS, GRUB cannot boot PowerMacs. Any plan that assumed imminent removal was wrong.
The security argument is the one that actually decides this. These drivers have a long history of memory corruption on malformed volumes, serious enough that Debian carries a bug titled “HFS/HFS+ are insecure.” This system's whole purpose is mounting 30-year-old disk images of unknown provenance — hostile input parsed in ring 0. A FUSE process can be sandboxed and dies harmlessly when it faults. That is the better design no matter who maintains the kernel code, and unprivileged FUSE mounts suit a no-accounts live system better than a setuid mount helper besides.
Where the kernel driver still earns its place: trusted local volumes, and read-write HFS+, since hfsfuse is read-oriented. Make it a per-case choice rather than a blanket rule — userspace for anything the user just downloaded, kernel for volumes the system created itself.
This section decides the project. Everything else is assembly; this is the part with a real constraint, and the constraint is copyright rather than engineering.
Verified: Executor is redistributable
Cliff Matthews open-sourced Executor in 2008 under an MIT-style license (see COPYING in the source tree). It needs no Apple ROM and no Apple system software — it reimplements the classic Mac Toolbox the way Wine reimplements Win32, and installs its own synthetic system files on first run. It ships in your ISO with no legal asterisk.
One caveat worth designing around: the built-in debugger is based on cxmon, which is GPLv2+, so a stock build is effectively bound by the GPL for the whole binary. cxmon is optional and removable if you want a non-copyleft build — but for a Linux distribution shipping under the GPL anyway, this is a non-issue. Build it in.
The options, compared
| Approach | Apple ROM | Apple system software | Shippable in the ISO | Compatibility |
|---|---|---|---|---|
| Executor MIT + optional GPL component |
Not needed | Not needed | Yes | A subset. Many System 6 and 7-era applications run; many do not. Reimplementation coverage, not emulation completeness. |
| Advanced Mac Substitute actively developed |
Not needed | Not needed | Yes | Narrower today, but deliberately Apple-code-free and moving. The honest long-term bet; pair it with Executor rather than choosing. |
| Basilisk II | Required | Required | No | Excellent — it is real 68k emulation. Blocked on assets you cannot distribute. |
| Mini vMac | Required | Required | No | Superb for Plus-era software. Same blocker. |
| qemu-system-m68k -M q800 | Required | Required | No | Improving quickly. Same blocker. |
What “only legal methods” actually rules out
The ROM is the hard blocker, not the operating system. Apple's ROMs are copyrighted firmware and there is no licensed way to put one in a downloadable image. System 7.5.3 was famously a free download from Apple for years, but free to download is not licensed for you to redistribute, and those two get conflated constantly in retrocomputing circles.
That leaves a clean division. Ship Executor and AMS in the image, working out of the box, no setup. Then offer an optional first-run assistant that lets a user point at a ROM they dumped from hardware they own — which unlocks Basilisk II and full fidelity, entirely legally, without you ever distributing Apple's code. Shipping the dumping instructions is fine. Shipping the dump is not.
Default experience
Executor + AMS, preinstalled. Double-click a .sit, get a working application. Nothing to configure, nothing to acquire, nothing to explain. Compatibility is partial and that is an honest trade to state plainly in the documentation rather than paper over.
Enthusiast path
A ROM assistant in the System Folder. The user supplies their own dump; the system configures Basilisk II around it and the compatibility ceiling disappears. Opt-in, clearly labelled, and legally clean because the user supplies the only encumbered asset.
Nothing off the shelf gives you rootless 68k windows. But you get most of the effect cheaply, because mlvwm is already drawing System 7 chrome around everything.
The instance-per-application approach is not a consolation prize. A user launching MacPaint from /Applications gets a window with System 7 chrome that they can move, resize, and stack against a GIMP window that has identical chrome. The illusion holds for everything except overlapping modal dialogs inside a single classic application, which stay trapped in their instance's window.
Five milestones. The first four produce something people would actually install and use. The fifth is open-ended and should be treated that way from the start.
| # | Milestone | Done when |
|---|---|---|
| 1 | Bootable desktop | ISO boots to mlvwm with a ROX-Filer pinboard, no console visible, no login prompt, on both UEFI and BIOS. |
| 2 | Finder + /Applications | Dropping an AppImage into /Applications makes it appear in the menu and on the desktop within a second, and it survives reboot via the overlay. |
| 3 | Archives + volumes | Double-clicking a .sit in the Finder produces a mounted HFS volume with forks intact. No terminal involved. |
| 4 | Classic layer | Executor and AMS packaged; a classic application in /Applications launches from a double-click in a framed window. ROM assistant available but never required. |
| 5 | Seamless windowing | Individual classic windows are individual X windows. Ship 1–4 first and treat this as a separate project with its own timeline. |
Start here
The highest-information first step is milestone 1 plus a compile of mlvwm against XLibre. If the imake build fights you, you learn that in an afternoon rather than after committing to the whole architecture — and the fallback is to build against plain Xorg, which changes nothing else in this document.
| Risk | Severity | Mitigation |
|---|---|---|
| Shipping Apple fonts or icons | High | Chicago, Charcoal, and the System 7 icon set are Apple's property. Use clean-room bitmap lookalikes with explicit licenses, and check each one's terms individually — several popular “free” Chicago clones are personal-use only. |
| Apple logo in the menu bar | High | Trademark, not copyright, and no fair-use argument helps you here. Use an original mark. The placeholder in the mockup above is deliberately not an apple. |
| Imitating the System 7 look | Low | Trade dress is a grey area, but themes of this kind have existed unchallenged for three decades and mlvwm itself has shipped since the 1990s. The risk is in the assets, not the geometry. |
| XLibre packaging | Not a risk | Few distributions package it, but building and maintaining an X server is routine work here, so this is a task rather than an exposure. mlvwm links against Xlib and is indifferent to which server is on the other side; plain Xorg stays a drop-in fallback that changes nothing else in this document. |
| Malformed HFS volume corrupts kernel memory | Medium | The historical risk in these drivers, and this system exists to mount disk images of unknown provenance. Handled by defaulting to sandboxed FUSE mounts; the in-kernel path is reserved for volumes the system created itself. Removal is no longer a concern — both drivers are actively maintained again. |
| Executor compatibility ceiling | Medium | Real and permanent. State it plainly in the documentation, maintain a tested-application list, and offer the user-supplied-ROM path for anyone who needs full fidelity. |
| AppImages assume a desktop stack | Medium | Some expect XDG portals, a notification daemon, logind, or a working dbus session. On Devuan that means elogind plus a minimal session bus and the portal shims — install them deliberately as a compatibility layer rather than discovering the need one application at a time. |
Prior art worth reading before writing code
helloSystem has built a large share of this vision on FreeBSD, including the Finder replacement and the application-bundle model. GoboLinux is the cautionary tale for the literal System Folder. ROX-Filer supplies the desktop layer you are missing. Read all three before milestone 1; each one either saves you weeks or tells you which weeks not to spend.