Monorepo for Aesthetic.Computer aesthetic.computer

AC Native — Stack Report#

Last updated: 2026-03-11

What Is This?#

AC Native is a bare-metal Linux system that boots from USB (or internal disk) directly into a creative computing runtime. No distro, no systemd, no desktop — just a custom kernel running a C binary as PID 1 that executes JavaScript "pieces" via QuickJS.

The Stack#

Layer 0: Hardware#

  • Target: ThinkPad X1 Nano Gen 2 (primary), any x86_64 UEFI machine
  • Display: DRM (Direct Rendering Manager) — writes pixels directly to framebuffer
  • Audio: ALSA (Advanced Linux Sound Architecture) — PCM output + Flite TTS
  • Input: evdev — keyboard, trackpad, touchscreen, joystick, NuPhy analog keys
  • WiFi: Intel iwlwifi (9260, AX200, AX201) via wpa_supplicant + dhclient
  • Storage: FAT32 EFI System Partition on USB or internal NVMe

Layer 1: Kernel#

  • Linux 6.14.2 — custom minimal config (~200 options vs ~5000 in a typical distro)
  • No distro — not Fedora, Ubuntu, or anything else. Raw kernel + initramfs
  • EFI stub boot — kernel IS the bootloader (BOOTX64.EFI on FAT32 ESP)
  • Embedded initramfs — root filesystem is LZ4-compressed CPIO archive baked into the kernel
  • Size: ~40MB total (kernel + initramfs)

Layer 2: Initramfs (Root Filesystem)#

Everything the system needs lives in a ~33MB compressed archive:

Component Size Purpose
ac-native binary 1.1 MB PID 1 — the entire runtime
Shared libraries ~40 MB (uncompressed) libc, libdrm, libasound, libssl, etc.
WiFi firmware 4.9 MB Intel iwlwifi microcode
Flite TTS 5.2 MB Text-to-speech (2 voices)
ALSA config 352 KB Audio device configuration
WiFi tools ~6 MB wpa_supplicant, dhclient, iw, ip
Dropbear SSH 228 KB SSH daemon for remote access
CA certificates ~200 KB HTTPS trust chain
Pieces (.mjs) ~120 KB JavaScript programs
Shell + utils ~3 MB bash, grep, curl, etc.

Layer 3: ac-native (The Runtime)#

A single C binary (~1.1MB) that does everything:

  • PID 1 init: Mounts /proc, /sys, /dev, /tmp. Sets CPU governor. Finds boot device
  • Display: DRM initialization, double-buffered framebuffer, 60fps vsync
  • Graphics: Software rasterizer — wipe, ink, line, box, circle, plot, write (bitmap fonts)
  • Audio: ALSA PCM output with synthesizer (sine, square, saw, triangle, noise)
  • Input: Multi-device polling (keyboard, mouse, trackpad, touch, analog keys)
  • WiFi: Scan, connect, DHCP — full network stack management
  • JavaScript: QuickJS engine with custom AC API bindings
  • Networking: curl (HTTP/S), WebSocket client (TLS), UDP client
  • OTA updates: Download vmlinuz, flash to EFI partition, verify, reboot
  • Config: JSON config on FAT32 partition (handle, colors, tokens)
  • SSH: Dropbear daemon for remote access

Layer 4: Pieces (JavaScript)#

Interactive programs executed by QuickJS with lifecycle functions:

boot() → [act() → sim() → paint()] × 60fps → leave()

Current pieces:

  • notepat.mjs — Musical notation pad (default boot piece, ~96KB)
  • prompt.mjs — Command line with KidLisp evaluation
  • lisp.mjs — KidLisp visual evaluator
  • claude.mjs — Claude API chat client (OAuth refresh tokens)
  • roz.mjs — Character piece

Boot Sequence#

UEFI firmware
  → BOOTX64.EFI (Linux kernel with embedded initramfs)
    → /init (symlink to /ac-native)
      → mount /proc /sys /dev /tmp
      → mount EFI partition to /mnt
      → read /mnt/config.json (handle, colors, tokens)
      → init display (DRM)
      → render boot title ("hi @jeffrey" with custom colors)
      → init audio → boot beep (E5→B5 two-tone)
      → init input (keyboard, trackpad, etc.)
      → init WiFi (auto-connect to saved network)
      → load piece.mjs → call boot()
      → main loop: input_poll → act → sim → paint → present

Boot time target: Sub-second to interactive piece.

Network Architecture#

All networking is outbound only (except SSH when enabled):

  • HTTP/S: curl via system() — used for OTA checks, clock sync, API calls
  • WebSocket: Custom TLS client in background pthread — AC chat/multiplayer
  • UDP: Raw datagrams for lightweight co-presence data
  • SSH: Dropbear on port 22 (auto-starts on WiFi connect)

OTA Update Flow#

  1. Check version: GET https://aesthetic.computer/api/native/version
  2. Download kernel: GET https://aesthetic.computer/api/native/vmlinuz (binary fetch with progress)
  3. Flash to EFI: Copy to /mnt/EFI/BOOT/BOOTX64.EFI with fsync + syncfs
  4. Verify: Drop page caches, byte-for-byte comparison of source vs destination
  5. Reboot: Show verified bytes count, then reboot(RB_AUTOBOOT)

Claude Integration (3 Approaches)#

1. Direct API Client (claude.mjs)#

  • Pure JavaScript piece running in QuickJS
  • Uses system.fetchPost() for HTTP POST requests
  • OAuth: Stores refresh token in config.json, exchanges for access token
  • Calls /v1/messages API with Claude Sonnet
  • No external dependencies

2. SSH Remote Access (dropbear)#

  • Lightweight SSH daemon (~228KB) bundled in initramfs
  • Auto-starts when WiFi connects
  • SSH in from any machine on the local network
  • Run Claude Code CLI remotely over the SSH session
  • ssh root@<device-ip>

3. Node.js + Claude Code CLI (planned)#

  • Bundle Node.js binary in initramfs
  • system.execNode(script) runs JS via Node subprocess
  • Could run actual @anthropic-ai/claude-code package
  • Renders output through AC native display

Key Files#

fedac/native/
  src/
    ac-native.c         — PID 1, main loop, boot sequence
    js-bindings.c/h     — QuickJS ↔ C API (graphics, audio, network, system)
    drm-display.c/h     — DRM framebuffer display
    audio.c/h           — ALSA audio + synthesizer
    input.c/h           — evdev input handling
    wifi.c/h            — WiFi management
    ws-client.c/h       — WebSocket client
    graph.c/h           — Software rasterizer
    font.c/h            — Bitmap font renderer
  pieces/
    notepat.mjs         — Musical notation (default piece)
    prompt.mjs          — Command prompt
    claude.mjs          — Claude API client
    lisp.mjs            — KidLisp evaluator
  scripts/
    build-and-flash.sh  — Full build pipeline
    upload-release.sh   — OTA release to DO Spaces
  kernel/
    config-minimal      — Linux kernel config
    build-kernel.sh     — Kernel compilation script
  Makefile              — ac-native binary build

Build Pipeline#

make CC=gcc                           → build/ac-native (1.1MB)
scripts/build-and-flash.sh            → build/vmlinuz (~40MB)
  ├── compile ac-native
  ├── create initramfs (copy binary + libs + firmware + tools + pieces)
  ├── compress with LZ4
  ├── build Linux kernel with embedded initramfs
  └── flash to USB via mtools (no root mount needed)

What Makes This Different#

  • No OS layer: No systemd, no package manager, no filesystem hierarchy. Just kernel + one binary
  • Sub-second boot: UEFI → interactive in under 1 second
  • Single binary runtime: Everything in one ~1.1MB C program
  • JavaScript pieces: Creative programs with immediate-mode graphics, audio synthesis, network
  • OTA with verification: Flash + fsync + drop caches + byte-compare before reboot
  • Fits on any USB: ~40MB total, boots on any UEFI x86_64 machine