33 KiB
FDS/OS MASTER IMPLEMENTATION PLAN
This is the complete design specification, including future components and command interfaces. M0–M12 software acceptance is complete, including Dasung base integration and the signed local 0.1.0 release. Tests requiring physical Pi hardware are deferred; software and VM checks remain in scope. See the implementation ledger. A command appearing here is not evidence that it exists in the checkout. Start with the project overview and first-build walkthrough for current usage, or the roadmap for implementation status. The 67 numbered sections below retain the full project requirements.
1. Project objective
Implement an independent Linux distribution for Raspberry Pi 5:
FDS/OS — Felis Data Systems Operating System
FDS/OS targets a retro portable computer with these characteristics:
- Raspberry Pi 5
- aarch64
- 12 USB cartridge bays
- removable SYSTEM / DATA / PROGRAM / ENVIRONMENT cartridges
- Dasung Paperlike 13K grayscale E-Ink display
- removable battery
- Very fast boot
- Very fast shutdown
- native s6 init
- Void/XBPS package ecosystem
- glibc as the system ABI
- Rust + static musl for FDS-owned programs wherever practical
Core design principle:
Preserve compatibility with modern Linux software while making FDS-owned software as independent of distribution runtime libraries as practical.
2. ABI and libc strategy
The system must have two distinct userspace domains.
2.1 General userspace
Use:
glibc
Applies to:
GNU coreutils
GNU binutils
bash
grep
sed
gawk
findutils
util-linux
procps-ng
Xorg
WindowMaker
XBPS packages
Python
GCC
LLVM
third-party software
The system package architecture is:
aarch64
Do not use:
aarch64-musl
2.2 FDS control plane
FDS-maintained programs default to:
Rust
+
aarch64-unknown-linux-musl
+
static linking
Include at least:
fds-stage0
fds
fds-cartridged
fds-burn
fds-inspect
fds-eject
fds-profile
fds-power
fds-boottrace
Principle:
FDS-owned runtime program
↓
static musl where practical
↓
Linux syscall ABI
These programs should not depend on the system's glibc version.
The following checks must pass:
file /usr/bin/fds
ldd /usr/bin/fds
Expected output resembles:
statically linked
not a dynamic executable
3. Do not convert the entire system to musl
Do not force the following components to use musl:
Xorg
WindowMaker
general XBPS packages
GNU toolchain
graphics stack
plugin-heavy applications
Do not attempt to maintain two complete repositories:
glibc repository
musl repository
The purpose of musl is limited to:
Providing a stable, self-contained static linking environment for FDS-owned control-plane executables.
4. Init architecture
FDS/OS must be a native s6 system.
Final architecture:
Linux
↓
/sbin/init
↓
s6-linux-init
↓
s6-svscan
↓
s6-rc
Prohibited:
systemd → s6
runit → s6
OpenRC → s6
custom shell PID1 → s6
PID 1 must ultimately belong to the s6 architecture.
Use:
skalibs
execline
s6
s6-linux-init
s6-rc
The s6-rc source database resides at:
/etc/s6-rc/source
compiled database:
/etc/s6-rc/compiled
live database:
/run/s6-rc
The compiled database must be generated during image construction.
Normal boot must never run:
s6-rc-compile
5. Package architecture
Use Void Linux only for:
upstream package ecosystem
XBPS
xbps-src
glibc packages
GNU packages
kernel packaging reference
third-party packages
FDS defines its own:
fds-base
Do not directly depend on an all-inclusive Void base metapackage.
Initial dependencies of fds-base:
glibc
glibc-locales
coreutils
binutils
findutils
diffutils
grep
sed
gawk
bash
tar
gzip
xz
util-linux
procps-ng
shadow
kbd
e2fsprogs
dosfstools
erofs-utils
eudev
kmod
iproute2
iputils
pciutils
usbutils
ca-certificates
tzdata
xbps
skalibs
execline
s6
s6-linux-init
s6-rc
fds-base-files
fds-cartridged
fds-cli
fds-dasungd
FDS-owned static-musl binaries must not require:
musl runtime package
musl is already statically linked into each executable.
6. Build host
Primary build machine:
x86_64 Arch Linux
Target:
aarch64 Raspberry Pi 5
Normal development must not require an ARM build host.
The Pi 5 serves as:
deployment target
hardware validation target
performance target
It is not the primary build machine.
Void's xbps-src supports foreign Linux hosts. Cross-build with:
./xbps-src -a aarch64 pkg PACKAGE
This performs a cross build.
Rust FDS components use:
aarch64-unknown-linux-musl
This Rust target explicitly supports cross-compilation from other hosts.
7. Repository layout
Create:
fds-os/
│
├── README.md
├── Makefile
├── Cargo.toml
│
├── docs/
│ ├── architecture.md
│ ├── boot.md
│ ├── cartridges.md
│ ├── services.md
│ ├── packages.md
│ ├── performance.md
│ └── recovery.md
│
├── vendor/
│ └── void-packages/
│
├── packages/
│ ├── fds-base/
│ ├── fds-base-files/
│ ├── fds-kernel/
│ ├── fds-cartridged/
│ ├── fds-cli/
│ └── fds-eink/
│
├── rust/
│ ├── fds-common/
│ ├── fds-stage0/
│ ├── fds-cli/
│ ├── fds-cartridged/
│ ├── fds-burn/
│ └── fds-boottrace/
│
├── s6/
│ └── source/
│
├── profiles/
│ ├── cli.toml
│ ├── development.toml
│ ├── windowmaker.toml
│ └── recovery.toml
│
├── image/
│ ├── build-rootfs
│ ├── build-system-cartridge
│ ├── build-boot-volume
│ ├── build-initramfs
│ └── build-recovery
│
├── tools/
│ ├── bootstrap-host
│ ├── build-package
│ ├── qemu-test
│ ├── burn
│ └── configure-pi-eeprom
│
├── tests/
│ ├── unit/
│ ├── integration/
│ └── hardware/
│
└── out/
8. Managing the Void upstream
Do not maintain a long-lived fork with changes throughout void-packages.
Use:
vendor/void-packages
Pin it to a specific commit.
Record:
VOID_PACKAGES_COMMIT
Inject FDS packages through an overlay.
Required relationship:
same FDS commit
+
same Void commit
=
same package input
Do not drift with daily changes to the Void rolling repository.
9. Rust workspace
Create the workspace:
[workspace]
members = [
"rust/fds-common",
"rust/fds-stage0",
"rust/fds-cli",
"rust/fds-cartridged",
"rust/fds-burn",
"rust/fds-boottrace",
]
Default release profile:
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true
Benchmark performance-critical binaries with:
opt-level = z
vs
opt-level = 2
vs
opt-level = 3
Do not assume that the smallest executable starts fastest.
10. Rust dependency policy
Use Clap for every Rust command-line interface, including test helpers. Declare
typed commands, options, validation, and generated help; do not hand-parse the
argument vector. The workspace shares the version already used by Dasung and
pins it in Cargo.lock. Kernel command-line files and cartridge metadata remain
separate domain formats with their own strict parsers.
FDS core programs should avoid:
tokio
openssl
glibc-specific crates
libudev-sys
large asynchronous runtimes
Prefer:
std
libc crate
rustix
nix
serde
toml
small synchronous event loop
netlink/sysfs directly where reasonable
Do not introduce a large runtime merely to listen for a few uevents.
11. Boot architecture
The machine's internal NVMe belongs to the:
machine firmware layer
The SYSTEM cartridge contains the:
operating system userspace
Boot sequence:
Raspberry Pi EEPROM
↓
internal NVMe
↓
kernel
↓
tiny FDS initramfs
↓
fds-stage0
↓
locate SYSTEM cartridge
↓
mount EROFS
↓
switch_root
↓
s6
↓
READY
Do not make Raspberry Pi firmware search all 12 USB cartridges for a boot device.
12. Internal NVMe layout
Recommended layout:
GPT
p1 FDS_BOOT
FAT32
512 MB
p2 FDS_RECOVERY
EROFS
1–2 GB
p3 FDS_INTERNAL
ext4
FDS_BOOT
Contains:
Pi firmware
kernel
DTBs
config.txt
cmdline.txt
FDS initramfs
FDS_RECOVERY
Contains a complete, independent recovery environment.
FDS_INTERNAL
Record:
hardware configuration
Bay topology
boot performance history
cached cartridge metadata
diagnostics
Do not store ordinary user files here.
13. SYSTEM cartridge
SYSTEM cartridge:
GPT
+
partition name FDS_SYSTEM
+
EROFS
For example:
/dev/???
└── GPT PARTNAME=FDS_SYSTEM
Never depend on:
/dev/sda
/dev/sdb
With 12 USB devices, these names are completely unreliable identifiers.
root:
read-only
14. fds-stage0
fds-stage0 is a static-musl Rust executable.
Target:
single executable initramfs control program
Avoid including the following wherever practical:
shell
BusyBox
glibc
Python
udev
Its responsibilities are limited to:
mount /proc
mount /sys
mount devtmpfs
enumerate block devices
find GPT PARTNAME FDS_SYSTEM
mount EROFS root
move /proc /sys /dev
switch_root
exec /sbin/init
Prefer direct use of:
mount(2)
openat
read
ioctl
netlink/sysfs
pivot_root/switch_root equivalent
Do not invoke a shell or external commands.
15. Missing SYSTEM cartridge
For the selected Dasung monitor, early userspace must provide the display's control/keepalive and correct video mode before showing this prompt. The base SYSTEM daemon starts later and cannot satisfy missing-SYSTEM display requirements by itself. Implement and verify this handoff as part of Pi boot integration.
When no SYSTEM cartridge is present:
Display:
FELIS DATA SYSTEMS
PORTABLE COMPUTER FP-85
BOOT ROM 0.1
SYSTEM MEDIA NOT PRESENT
INSERT SYSTEM CARTRIDGE
Then:
continue listening for block device changes
When a SYSTEM cartridge is inserted:
Resume boot immediately.
A reboot must not be required.
16. Multiple SYSTEM cartridges
When multiple partitions are found with:
FDS_SYSTEM
Do not choose one arbitrarily.
Display:
MULTIPLE SYSTEM CARTRIDGES
BAY 02 FDS/OS 0.1
BAY 08 FDS/OS DEVELOPMENT
SELECT SYSTEM:
Version 1 may enter a recovery/debug console.
Add interactive selection in version 2.
17. Kernel strategy
Start the first version from Void's Raspberry Pi 5 kernel packaging.
Do not maintain a large kernel fork from day one.
Create:
fds-kernel
Maintain only:
config delta
packaging
version policy
Build boot-critical drivers into the kernel wherever practical:
BCM2712
RP1
PCIe
USB host
USB hub
USB mass storage
SCSI disk
NVMe
devtmpfs
EROFS
ext4
FAT
HID keyboard
console
DRM/KMS
optional:
Wi-Fi
Bluetooth
USB Ethernet
USB Serial
audio
SDR
These optional drivers may be modules.
18. Initramfs
Target:
As close as practical to:
/init -> fds-stage0
Test these formats:
uncompressed cpio
lz4
zstd
gzip
Benchmark on a real Pi 5.
The following observation:
zstd image smaller
does not establish that boot will be faster.
NVMe capacity is inexpensive.
Boot milliseconds matter.
19. Raspberry Pi firmware optimisation
production EEPROM:
Disable unnecessary network installation behavior.
In particular:
NET_INSTALL_ENABLED=0
NET_INSTALL_AT_POWER_ON=0
Raspberry Pi's official guidance states that USB controller initialization and device enumeration to detect a network-install keyboard add about one second to boot, making these features worth disabling on embedded devices that need fast startup.
Provide:
tools/configure-pi-eeprom
Together with:
development.conf
production.conf
All EEPROM changes must be:
documented
reversible
20. Filesystem model
SYSTEM:
EROFS
read-only
runtime:
/run tmpfs
/tmp tmpfs
/var/tmp tmpfs
/var/log tmpfs
Do not run root filesystem fsck during boot.
Do not write logs to SYSTEM.
Do not update SYSTEM in place.
21. User data
DATA cartridge:
GPT PARTNAME=FDS_DATA
filesystem=ext4
After insertion:
/data
Alternatively:
/home/fds
Mount this path from the DATA cartridge.
When no DATA cartridge is present:
ephemeral tmpfs home
Therefore:
The machine itself does not own user data.
22. Native s6 service graph
Minimum boot bundle:
boot
├── runtime-fs
├── hostname
├── console
├── eudevd
├── udev-trigger
├── cartridged
├── getty
└── dasungd
Explicitly excluded from the boot bundle:
network
DHCP
NTP
sshd
D-Bus
Xorg
WindowMaker
Bluetooth
Wi-Fi
23. Fast boot principle
The interactive shell should depend only on:
root mounted
console ready
/dev minimally usable
It must not depend on:
all USB devices enumerated
cartridge catalog scan
network
clock synchronization
GUI
The intended sequence is:
power on
↓
kernel
↓
root
↓
s6
↓
FDS>
Everything else proceeds in parallel afterward.
24. eudev
The normal system uses:
eudev
However, do not use:
udevadm settle
as a global boot barrier.
Correct sequence:
start eudevd
↓
trigger existing devices
↓
continue boot
Services that need a particular device must handle their own readiness.
25. cartridged
Implement:
fds-cartridged
static-musl Rust.
Responsibilities:
listen for USB/block events
identify physical hub/port
map device → BAY 01..12
inspect storage metadata
mount/unmount cartridges
activate FDS profiles
communicate state to fds CLI
Do not depend on:
/dev/sdX ordering
Use:
sysfs USB topology
to identify physical bays.
26. Bay topology
Configuration:
/etc/fds/bays.toml
Example:
[front]
hub = "usb-topology-id"
[front.ports]
1 = 1
2 = 2
3 = 3
4 = 4
5 = 5
6 = 6
[rear]
hub = "usb-topology-id"
[rear.ports]
1 = 7
2 = 8
3 = 9
4 = 10
5 = 11
6 = 12
Users see:
BAY 01
...
BAY 12
They must not see:
1-2.4.1
except in debug mode.
27. Cartridge metadata
At the root of a storage cartridge:
/FDS/CARTRIDGE.TOML
Format:
format = 1
[cartridge]
id = "fds.windowmaker"
name = "WINDOW SYSTEM"
class = "environment"
version = "0.1"
[media]
writable = false
[activation]
profile = "windowmaker"
classes:
system
data
program
environment
hardware
utility
28. Hardware cartridges
USB hardware without a filesystem includes:
For example:
USB Ethernet
USB Serial
USB Wi-Fi
USB Audio
Identify it using:
VID
PID
serial
USB class
physical bay
Use these identifiers for recognition.
Maintain:
/etc/fds/hardware-catalog.toml
Do not require every hardware cartridge to contain storage.
29. ENVIRONMENT cartridge v1
Do not place the entire Xorg and WindowMaker runtime on cartridges in version 1.
Implement the activation logic first:
The SYSTEM image already contains:
Xorg
WindowMaker
fonts
theme
The ENVIRONMENT cartridge initially provides only:
capability key
+
configuration
On insertion:
WINDOW SYSTEM
↓
cartridged
↓
fds-profile activate windowmaker
↓
s6-rc change +desktop
On removal:
desktop down
↓
return CLI
Move the GUI runtime onto the cartridge in version 2.
30. WindowMaker stack
Display managers are prohibited.
Do not use:
GDM
SDDM
LightDM
Use:
s6
↓
Xorg
↓
WindowMaker
A single-user machine may use:
autologin FDS console
Activating a GUI profile starts the user's graphical session directly.
31. E-Ink profile
Use the grayscale profile as the default WindowMaker appearance on every display. Install it globally and seed new user preferences without replacing existing customization. The native FDS Control panel follows the same style.
The monitor controller is base hardware support, independent of the desktop
profile. Include the existing Rust dasungd for the user's Paperlike 13K grayscale
in every SYSTEM image and the native s6 boot bundle. Maintain the confirmed
profile, static-musl target, reconnect handling, and SPI-driver protection.
See Dasung integration for implementation, usage, and the remaining
Pi and physical recovery checks. It must not require an ENVIRONMENT cartridge.
Create:
fds-eink
Configuration:
no compositor
no transparency
no fade
no desktop animation
no smooth window animation
outline move
outline resize
static wallpaper
high contrast
WindowMaker should prioritize:
black
white
2–4 grayscale levels
Fonts:
Terminus
other high-contrast bitmap-friendly fonts
Do not update the clock every second.
32. PROGRAM cartridge
Create software cartridges on a generic Linux workstation using fds-cartridge.
Each format-2 software recipe identifies a Void source package and its commands.
The tool builds with xbps-src, installs the package and runtime dependencies
into a private tree, and creates GPT images with metadata partition 1 plus one
or more EROFS program partitions.
Payloads contain programs/SOFTWARE-ID/ installed roots, including executable
files and libraries. Verify tree integrity and architecture on insertion; run
new software directly from the read-only EROFS mount without guest extraction.
Retain reading of legacy PROGRAM media and catalogue-format-1 archives.
Publish commands through /run/fds/bin using a managed foreground launcher.
Keep fds run BAY -- SOFTWARE-ID:COMMAND for managed background execution.
Both paths run as the ordinary user and participate in safe eject and unplug
cleanup. Resolve names by lowest bay, then lexical selector; expose qualified
bBAY:SOFTWARE-ID:COMMAND aliases without overriding base system commands.
Provide fds-control, a native static Rust X11 panel styled to match the default
grayscale WindowMaker desktop. It displays bays and software, opens commands in
a terminal, requests rescans and safe eject, and reports service errors.
33. FDS CLI
fds is a static-musl Rust binary.
Implement at least:
fds info
fds bays
fds bay 3
fds cartridge 3
fds eject 3
fds profiles
fds profile activate windowmaker
fds poweroff
fds reboot
fds boot-profile
Output should be concise, fast, and suitable for E-Ink.
For example:
FDS> fds bays
01 SYSTEM FDS/OS 0.1 ONLINE
02 DATA FELIS ONLINE
03 ENVIRONMENT WINDOW SYSTEM ONLINE
04 PROGRAM TEXT TOOLS ONLINE
05 EMPTY
06 EMPTY
07 ETHERNET EC-1 ONLINE
08 EMPTY
09 EMPTY
10 EMPTY
11 EMPTY
12 EMPTY
34. fds-burn
The target media client remains static-musl Rust. New software creation and
writing use native Linux workstation fds-cartridge: build Void source packages, construct
and verify the complete metadata-first GPT image, preview the USB target, then
write and verify that full image. Never assemble software partitions piecemeal
on the destination drive. See the workstation workflow.
Responsible for:
inspect target
partition media
write image
verify
write cartridge metadata
Typical usage:
fds burn system fds-system-cli.img BAY04
Alternatively:
fds burn data BAY04 --label FELIS
Destructive operations require explicit confirmation.
35. Package installation model
A running SYSTEM cartridge must not use:
sudo xbps-install -Su
to modify itself in place.
Use XBPS for:
building images
resolving package dependencies
resolving libraries for installed PROGRAM package trees
development profile
SYSTEM update sequence:
build new SYSTEM image
↓
write new cartridge
↓
swap cartridge
rollback:
put old cartridge back
36. Image builder
Implement:
make rootfs PROFILE=cli
Internal workflow:
create empty root
↓
xbps-install -r ROOT ...
↓
install FDS packages
↓
apply profile
↓
generate locales
↓
generate caches
↓
compile s6-rc database
↓
remove build junk
↓
make EROFS
All of the following must happen at build time:
locale generation
font cache generation
s6-rc compilation
ldconfig
package configuration
Do not perform them during boot.
37. Build interface
Eventually support:
make bootstrap
make packages
make rootfs PROFILE=cli
make rootfs PROFILE=development
make system-card PROFILE=cli
make system-card PROFILE=development
make initramfs
make kernel
make boot-volume
make recovery
make all
output:
out/
├── fds-boot.img
├── fds-initramfs.img
├── fds-recovery.img
├── fds-system-cli.img
├── fds-system-development.img
└── packages/
38. Cross compilation policy
All FDS Rust binaries must support building on x86_64 with:
cargo build \
--release \
--target aarch64-unknown-linux-musl
All FDS XBPS packages should support the following wherever practical:
./xbps-src -a aarch64 pkg PACKAGE
For cross-built packages, xbps-src selects the corresponding cross environment and exposes variables such as XBPS_CROSS_BASE and XBPS_RUST_TARGET.
If a package cannot be cross-built:
Fallback priority:
1. Use an official Void aarch64 binary
2. Fix the cross build
3. QEMU native-aarch64 build
4. Build natively on the Pi only as a last resort
The normal build pipeline must not require a Pi.
39. Host-side QEMU testing
Set up this workflow on the Framework:
x86_64 Arch
↓
cross build
↓
aarch64 image
↓
QEMU smoke test
↓
real Pi test
Use QEMU to test:
s6 graph
shell
package contents
static-musl binaries
config parsing
filesystem layout
shutdown logic
cartridge metadata
Use a real Pi to test:
firmware
RP1
USB topology
12 bays
E-Ink
power behaviour
actual boot timing
40. Boot performance targets
Define:
T0 power applied
T1 kernel entered
T2 fds-stage0 entered
T3 switch_root
T4 s6 running
T5 CLI accepts input
T6 WindowMaker accepts input
Target:
kernel → CLI:
< 1.5 seconds target
< 2.0 seconds maximum target
s6 → CLI:
< 400 ms target
cold power → CLI:
< 3 seconds stretch goal
< 5 seconds hard goal
CLI → WindowMaker:
< 2 seconds
These are targets, not claimed performance results.
Actual measurements are required.
41. fds-boottrace
Implement:
fds-boottrace
Record:
kernel timestamp
stage0 start
SYSTEM found
root mounted
switch_root
s6 start
console ready
desktop ready
Output:
FDS BOOT PROFILE
KERNEL .............. 0.713 s
STAGE0 .............. 0.094 s
SYSTEM DISCOVERY .... 0.082 s
ROOT SWITCH ......... 0.031 s
S6 .................. 0.047 s
CONSOLE ............. 0.073 s
KERNEL → READY ...... 1.040 s
Save benchmarks in:
docs/performance.md
42. Performance regression rule
Any commit that causes:
boot regression > 100ms
must:
explain it
or fix it
Do not add an artificial delay for a retro splash screen:
sleep 1
If FDS can boot in 800 ms, let it boot in 800 ms.
43. Fast boot blacklist
Prohibited on the critical path:
DHCP
DNS
NTP
sshd
Wi-Fi setup
Bluetooth setup
package updates
package verification
font cache generation
locale generation
s6-rc compilation
global udev settle
GUI login manager
Python
filesystem fsck for read-only root
persistent log flush
These activities must run:
build time
on demand
or parallel after READY
44. Networking
network bundle:
network
By default, it is not part of:
boot
When an Ethernet cartridge is present or the user explicitly requests networking:
s6-rc change +network
DHCP must never delay the appearance of:
FDS>
The prompt must remain independent of DHCP.
45. Logging
Normal logging location:
/run/log
tmpfs.
Persist only:
important errors
explicit debug captures
boot performance
Do not persist tens of megabytes of journal data as a server distribution might.
FDS does not use a journal service.
This is intentional.
46. Shutdown
Provide:
fds poweroff
Sequence:
freeze new cartridge operations
↓
stop GUI
↓
stop program services
↓
stop network
↓
sync DATA filesystems
↓
unmount DATA
↓
stop remaining services
↓
poweroff
SYSTEM root:
read-only
It therefore does not need to wait for journal writes to SYSTEM.
47. Shutdown performance
Target:
idle poweroff:
< 1 second target
normal writable DATA:
< 1.5 seconds target
Do not use:
sleep 5
to wait for daemons.
s6 must base shutdown on actual process exit and readiness.
48. Eject semantics
Users cannot safely unplug writable DATA without ejecting it first.
Command:
fds eject 02
Behavior:
identify dependent programs
↓
stop them
↓
syncfs()
↓
unmount
↓
mark SAFE
Output:
BAY 02
DATA CARTRIDGE FELIS
SAFE TO REMOVE
A physical LED or eject mechanism may be integrated later.
49. Recovery environment
FDS_RECOVERY must not depend on a SYSTEM cartridge.
Include at least:
bash
GNU coreutils
util-linux
filesystem tools
XBPS tools
fds
fds-burn
fds-inspect
FDS tools in recovery remain static-musl binaries.
Recovery supports:
inspect SYSTEM
burn SYSTEM
repair DATA
diagnose USB bays
inspect boot log
50. Security
Strictly prohibited:
/FDS/autorun.sh
executed automatically as root when a cartridge is inserted.
Cartridge manifests must be declarative.
For example:
profile = "windowmaker"
Instead of:
run = "/media/card/haha.sh"
PROGRAM cartridges run with ordinary user privileges by default.
51. Initial boot UI
Production boot should suppress Linux kernel console noise.
Display:
FELIS DATA SYSTEMS
PORTABLE COMPUTER FP-85
FDS BOOT ROM 0.1
MEMORY ........ READY
SYSTEM ........ FDS/OS 0.1
CARTRIDGE BUS . READY
READY.
_
However:
Do not delay startup to display these lines one at a time.
A single repaint is sufficient.
A retro appearance does not require a four-second delay.
52. Development SYSTEM cartridge
The development profile may include a large toolset:
gcc
clang
binutils
make
cmake
meson
ninja
pkg-config
rust
cargo
git
gdb
strace
perf
vim/neovim
Provided that these tools:
do not start daemons
they should not significantly slow boot.
Disk usage is not boot latency.
53. Milestone M0 — Host build environment
Implement:
repo skeleton
pin void-packages
install/use XBPS host tools
xbps-src bootstrap
aarch64 cross toolchain
Rust musl target
Acceptance:
On the x86_64 Framework, it must be possible to:
build aarch64 package
build static-musl hello-world
Verify that the executable is static.
54. M1 — FDS base rootfs
Implement:
fds-base
fds-base-files
glibc system
GNU userland
XBPS
Acceptance:
Generate:
out/rootfs-aarch64.tar
Verify:
glibc present
GNU coreutils present
GNU binutils present
musl runtime package not required
BusyBox absent
systemd absent
runit absent
55. M2 — Native s6
Implement the complete stack:
s6-linux-init
s6-svscan
s6-rc
Acceptance:
In the booted rootfs:
PID1 belongs to s6 architecture
Also verify that:
s6-rc change
can control a test service.
56. M3 — static-musl FDS tooling
Implement:
fds-common
fds CLI skeleton
fds-stage0 skeleton
All components use:
Rust
aarch64-unknown-linux-musl
static
Acceptance:
readelf
file
ldd
must demonstrate the absence of a glibc runtime dependency.
57. M4 — Pi boot
Implement:
FDS_BOOT
kernel
initramfs
fds-stage0
SYSTEM EROFS
switch_root
s6
Acceptance:
Pi:
power on
↓
internal NVMe kernel
↓
USB SYSTEM cartridge
↓
FDS>
58. M5 — Fast CLI
Optimize:
firmware
kernel
initramfs
stage0
s6 graph
getty
shell startup
Acceptance:
kernel → FDS> <2 sec
Create the first measured version of:
docs/performance.md
59. M6 — Cartridge daemon
Implement:
udev/netlink events
hub discovery
12 bay topology
metadata
mounting
eject
Acceptance:
With 12 USB devices inserted simultaneously:
every device maps to the correct physical BAY
60. M7 — DATA cartridge
Implement:
mount
home/data integration
safe eject
Acceptance:
After a sustained write test:
fds eject
must leave the filesystem clean.
61. M8 — WindowMaker
Implement:
Xorg
WindowMaker
E-Ink theme
environment profile
Acceptance:
On insertion of an ENVIRONMENT cartridge:
CLI → WindowMaker
On cartridge removal or profile deactivation:
WindowMaker → CLI
No reboot is required.
62. M9 — Cartridge image tools
Implement:
fds burn
fds inspect
fds format
Acceptance:
The machine itself can create:
SYSTEM
DATA
PROGRAM
ENVIRONMENT
cartridge.
63. M10 — Shutdown optimisation
Complete:
service stop graph
DATA sync
DATA unmount
fast halt
Acceptance:
idle shutdown <1s target
normal shutdown <1.5s target
Filesystem corruption is unacceptable.
64. M11 — 12-device stress testing
Hardware:
12 USB devices
Test:
cold boot
hot insert
hot remove
simultaneous enumeration
simultaneous IO
reboot
shutdown
Check:
bay mapping stability
USB resets
kernel errors
boot regression
power issues
65. M12 — Production hardening
Complete:
release signing
image versioning
package pinning
reproducible build work
recovery
documentation
production EEPROM config
Release:
FDS/OS 0.1
66. Codex implementation rules
Codex must follow these rules:
- Implement only the current milestone at a time.
- Do not implement later features ahead of schedule.
- Keep the repository buildable at every milestone.
- Default every custom FDS binary to static musl.
- Keep general userspace on glibc.
- Do not introduce systemd.
- Do not introduce runit.
- Do not use BusyBox to implement early userspace.
- Do not use
sleepto hide races. - Do not let networking block the console.
- Do not generate caches during boot when they can be generated at build time.
- Do not depend on
/dev/sdXordering. - Do not automatically execute arbitrary root scripts from cartridge contents.
- Explain the necessity of each new dependency.
- Support every boot optimization with benchmarks.
- Support x86_64 to aarch64 cross builds for all FDS packages wherever practical.
- Use native Pi builds only as a documented fallback.
- Keep documentation synchronized with the implementation.
67. First Codex task
Implement only M0 now.
Specific requirements:
A. Create the repository skeleton.
B. Add vendor/void-packages,
pinned to a specific commit.
C. Write tools/bootstrap-host,
supporting Arch Linux x86_64.
D. Verify the static XBPS host tools.
E. bootstrap xbps-src build environment.
F. Verify:
./xbps-src -a aarch64 pkg <simple-package>
G. Initialize the Rust workspace.
H. Configure:
aarch64-unknown-linux-musl
I. Build:
rust/fds-smoketest
J. Verify:
- architecture = AArch64
- static executable
- no glibc dependency
K. Provide:
make bootstrap
make smoke-test
L. Create docs/build-host.md,
accurately documenting all dependencies and commands.
M. Add automated checks that exit nonzero on failure.
N. Do not begin s6, kernel, GUI, or cartridge daemon implementation.
On completion, report:
1. changed files
2. exact build commands
3. smoke-test output
4. known limitations
5. next milestone proposal
The original M0 gate above has been satisfied. The user explicitly authorized M1; its workflow and evidence are in M1 rootfs and M1 validation. The user subsequently authorized M2; see Native init. The user subsequently authorized implementation through M12, with physical Pi testing deferred. The implementation ledger above records the current evidence and remaining work.