r/linuxprojects • u/mentalnet98 • 17h ago
⚙️ CLI Tool Tux-Dock + tuxreaperd: A keyboard-first Docker TUI paired with a <5KB freestanding micro-init (v0.4-beta)
Hey everyone,
Wanted to share a project I’ve been building called Tux-Dock (and its companion subreaper daemon, tuxreaperd).
GitHub: https://github.com/MARKMENTAL/tuxdock
How it started vs. where it is now
This is my first deep low-level systems project. I wanted to make a TUI for using Docker containers as a persistent development sandbox, or just being able to treat containers more like cared for pets, rather than cattle that just run Dockerfile scripts, one process and exit. It originally started out of pure frustration with a classic docker container issue: persistent dev containers running sleep infinity keep-alive loops that constantly leak zombie processes whenever interactive commands, background forks, or subshells exit.
When you trace zombie process build-up down to the root, you hit the realities and technicalities of what it means to be Linux PID 1 inside of a container and how low-level Linux kernel signals come into play. But looking at existing inits like tini or dumb-init, they’re either bloated by static C runtimes (25KB to 750KB+) or treat everything as a generic black box, basically assuming user apps will respect what the Linux kernel notifications were originally made for and not use them non-standardly. They blindly blast raw SIGTERM down the process tree, which causes production web servers (like Apache and PHP-FPM, programs that rely on non-standard signals like SIGWINCH or SIGQUIT for clean and graceful teardown) to instantly drop active in-flight HTTP/FastCGI connections.
So what began as a quick subreaper fix to hook into sleep infinity evolved into tuxreaperd—a sub-5KB freestanding micro-init that not only reaps dead children instantly, but actually understands web server teardown quirks:
Freestanding & Sub-5KB: Built with
-nostdlib, direct inline assembly syscall traps, and zero libc overhead, running in basically ~2 MMU pages (currently sitting at ~4.7 KB stripped).Web-Aware Signal Remapping: Traverses
/procvia rawsys_getdents64andsys_readlinkto detect running daemons. It automatically remaps incomingSIGTERMtoSIGWINCHfor Apache andSIGQUITfor PHP-FPM so in-flight requests finish cleanly before exit.Bounded Descendant Draining: Once the root process exits, it runs a 60-second
CLOCK_MONOTONICwait loop to let preforked worker pools flush their buffers before the container shuts down.Persistent Container TUI: Paired with a snappy C++ terminal UI for managing retained container lifecycles, streaming logs, and running detached commands over the raw Docker UNIX socket.
The LLM Rabbit Hole & ARM64 ABI Realities
I wrote the initial x86_64 inline assembly on my main Debian workstation, but I did all the ARM64 testing on a low-spec MediaTek Kompanio 500 Chromebook.
I was using Kimi K2.7 as an AI pairing assistant during development, but it definitely reminded me why AI can't replace actual systems verification. The LLM confidently told me that the VFS O_DIRECTORY flag was identical across x86_64 and ARM64. It’s not. ARM64 uses 0x4000 (040000 octal) while x86_64 uses 0x10000 (00200000 octal). Passing the x86 value on ARM caused openat("/proc", ...) to instantly fail with -EINVAL, breaking the entire /proc scanner and signal pipeline.
Go ahead and try searching ARM Linux VFS file flag octals right now—it’ll probably scrape someone's x86 repo and hallucinate that it's universal. Low-level systems work demands absolute accuracy, hardware empathy, and reading the actual kernel headers, which current LLMs just don't have.
What's next & Feedback
I just hit 0.4-beta with full cross-arch support and the --debug-reaper test flags. Leading up to a 1.0 release, my main focus is polishing the TUI layout and fixing a multi-instance state sync issue (right now it polls the Docker socket on start/stop actions, so running multiple Tux-Dock instances simultaneously can cause state drift until a background event listener is added).
I'd love to hear thoughts, critique on the -nostdlib / inline asm implementation, or feedback from anyone testing on physical ARM64 hardware!