# x-agentos **Repository Path**: openkylin/x-agentos ## Basic Information - **Project Name**: x-agentos - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-17 - **Last Updated**: 2026-08-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # x-agentos 一个"开机即 Agent"的极简 Linux 系统:**Alpine (arm64) + busybox init + Cage (Wayland kiosk 合成器) + Chromium + DeepSeek Harness (dsh)**。 没有 GNOME/KDE/XFCE,没有 X11,没有显示管理器,没有 systemd,没有 OpenRC —— PID 1 就是 busybox `init`,全部服务定义在一个 `/etc/inittab` 里(约 10 行)。 开机 → busybox init → Cage 全屏拉起 Chromium → 打开本地运行的 DeepSeek Harness Web UI(`http://127.0.0.1:3080`)。全程原生 Wayland 渲染。 ``` ┌──────────────────────────────────────────────┐ │ busybox init (PID 1) │ │ ├─ ::sysinit /etc/init.d/kiosk-boot │ ← 文件系统/网络/运行时目录 │ ├─ ::respawn seatd -g video │ ← seat/DRM 授权 │ ├─ ::respawn dsh web (Node, su kiosk) │ ← Web UI, 127.0.0.1:3080 │ ├─ tty1::respawn kiosk-session │ ← cage → chromium 全屏 │ └─ ttyAMA0::respawn getty │ ← 串口调试控制台 ├──────────────────────────────────────────────┤ │ Alpine 3.22 minimal (arm64, musl) │ └──────────────────────────────────────────────┘ ``` `respawn` 动作自带看门狗:进程退出即重拉,等价 systemd 的 `Restart=always`。 ## 仓库结构 ``` ├── make-image.sh # 唯一构建器: alpine-minirootfs + proot + qemu-aarch64-static, 无需 Docker ├── run-qemu.sh # QEMU 启动 (gui / headless / dump 截图) ├── cage/ # Cage 上游源码 (kiosk 定制修改的基础, 见下) ├── tools/ # 调试辅助工具 (如 chromium-renderer-tests) └── files/ ├── alpine/ │ ├── inittab # busybox init 服务定义 (整个"服务管理器") │ ├── kiosk-boot # sysinit 一次性初始化 (mount/网络/运行时目录) │ ├── kiosk-shutdown # shutdown 时 sync + umount │ └── initramfs-init # QEMU virt 专用最小 /init (virtio + ext4) ├── kiosk-session # cage 启动脚本 (等落地页就绪 → exec cage chromium) ├── kiosk-url # 落地页地址 (现在是 http://127.0.0.1:3080) └── chromium-kiosk.json # Chromium 管控策略 (禁下载/devtools/设置页等) ``` ## cage 源码 `cage/` 目录内嵌了 [cage-kiosk/cage](https://github.com/cage-kiosk/cage) 上游源码 (master @ `5491610`),共 14 个 C 文件约 3.4k 行,作为后续针对 kiosk 场景 定制修改的基础。构建依赖 wlroots,需 `meson build`(见 `cage/README.md`)。 ## 制作镜像 不依赖 Docker。在 x86_64 宿主机上用 `proot + qemu-aarch64-static` 用户态模拟 直接组装 arm64 rootfs(不注册任何 `binfmt_misc` 规则)。 前置依赖(Ubuntu/Debian): ```bash sudo apt-get install -y proot qemu-user-static curl tar e2fsprogs \ cpio gzip xz-utils file # node-pty 交叉编译还需要 musl 工具链 + node-gyp: curl -fsSL https://more.musl.cc/x86_64-linux-musl/aarch64-linux-musl-cross.tgz \ | sudo tar xz -C /opt sudo npm install -g node-gyp ``` musl 交叉工具链默认取 `/opt/aarch64-linux-musl-cross`(脚本内写死,装到别处 请改 `make-image.sh` 里的 `CC/CXX/AR` 三行)。 构建: ```bash sudo ./make-image.sh ``` 需要 root 的原因:`proot` 需要 `/proc`,`mkfs.ext4 -d` 需要正确写入文件 属主。可用 `MIRROR=` / `ROOTFS=` / `BUILD_DIR=` 环境变量覆盖镜像源与工作目录。 为防误删数据,`ROOTFS` 已存在时脚本直接退出。 流程(约 15-30 分钟,chromium 与 node 原生模块在 qemu 用户态模拟下较慢): 1. 下载 `alpine-minirootfs` 3.22 aarch64 并解包 2. `proot + qemu-aarch64-static` 里 `apk add` 内核(lts)/cage/chromium/seatd/Node 3. ARM64 Node 安装 `@deepseek-ai/dsh`,宿主 musl 交叉工具链编译 `node-pty` 4. 创建 kiosk 用户,部署 inittab / kiosk-boot / kiosk-session / 管控策略 5. `mkinitfs` 后修补 modules 索引,换用面向 QEMU virt 的最小 `/init` 6. `mkfs.ext4 -d` 打成**整盘 ext4 镜像**(无分区表)并导出内核 产物: | 文件 | 说明 | |---|---| | `build/kiosk-alpine.img` | 系统镜像(8G 稀疏,实际 ~2GB),QEMU 里是 `/dev/vda` | | `build/vmlinuz-alpine` | Alpine linux-lts arm64 内核 | | `build/initramfs-alpine` | 配套 initramfs | ## 启动 (QEMU aarch64) ```bash ./run-qemu.sh gui # SDL 图形窗口, 直接看到 kiosk 画面 ./run-qemu.sh headless # 无显示, 串口日志输出到终端 ./run-qemu.sh dump # 通过 monitor socket 截屏到 build/*.ppm ``` 关键参数(脚本已内置,自己写启动命令时别漏): ```bash qemu-system-aarch64 \ -machine virt -cpu cortex-a57 -smp 8 -m 3072 \ -global virtio-mmio.force-legacy=false \ # 必须! 见"踩坑" -kernel build/vmlinuz-alpine -initrd build/initramfs-alpine \ -append "root=/dev/vda rw console=ttyAMA0 quiet" \ -drive file=build/kiosk-alpine.img,format=raw,if=virtio \ -device virtio-net-device,netdev=n0 -netdev user,id=n0 \ -device virtio-keyboard-pci -device virtio-tablet-pci \ -device virtio-gpu-pci ``` 无 GPU 环境走软渲染:镜像内 `/etc/kiosk/env` 设置了 `WLR_RENDERER=pixman`, Chromium 走 ANGLE/OpenGL (llvmpipe);真机部署时删掉这个文件即可恢复硬件加速。 首次启动后 Chromium 会打开 dsh 的 Web UI,**在界面里自行填写 DeepSeek API key**(保存在 kiosk 用户 home 目录,镜像不内置任何凭据)。 ## 常用运维 ```bash # 换落地页: 串口登录后编辑 /etc/kiosk/url, 重启 (respawn 会重拉 kiosk-session) # 镜像内的默认值来自 files/kiosk-url, 重新制作镜像时生效 # 串口登录排查 (root/kiosk, 调试用密码) # dsh 日志: /dev/ttyAMA0 上的 respawn 输出; kiosk-session 的 stderr 也重定向到串口 ``` ## 踩坑实录 (全部实测踩过) 1. **QEMU `virt` 机器 virtio-mmio 默认 legacy**:`force-legacy=true` 时设备无 `VIRTIO_F_VERSION_1`,`virtio_gpu` 驱动直接拒绝绑定,guest 里 `/sys/class/drm` 为空、cage 黑屏。必须 `-global virtio-mmio.force-legacy=false` 2. **Chromium `--disable-gpu` 在 Alpine 上反而不行**:Alpine 的 Chromium 包不带 `libvk_swiftshader.so`,"disabled" GL 模式回退 Vulkan 时反复杀掉 Viz GPU 进程。改用 `--use-gl=angle --use-angle=gl`(llvmpipe),实测稳定 3. **proot 生成的 initramfs 缺 modules 索引**:`modules.dep/alias` 遗漏导致 QEMU 里无法自动加载 `virtio_blk/ext4`。构建脚本会补齐索引并换用自带的 最小 `/init`(见 `files/alpine/initramfs-init`) 4. **dsh 依赖 `node-pty` 原生模块**:qemu 用户态跑 node-gyp 慢且易错,改为 `--ignore-scripts` 安装 + 宿主 musl 交叉工具链 `node-gyp rebuild --arch=arm64`, 并用 `readelf` 验证产物是 AArch64 5. **proot 下 `adduser` 偶尔不写 group**:只落 passwd、不落同 GID 的 group, 脚本显式补 `kiosk:x:1000:kiosk` 6. **`pkill` 自匹配**:`pkill -f qemu-system-aarch64` 会杀掉包含该串的自身 shell,用 `pkill -f 'qemu-system-aarch64 -machine'` 或精确进程名 ## 安全说明 - 调试构建内置了 root 密码(`root:kiosk`,见 `make-image.sh` 的 `chpasswd` 行), **正式部署前删除** - kiosk 用户为 `/sbin/nologin`,无交互 shell - Chromium 通过 managed policy 禁用了下载、文件对话框、devtools、设置页等 ## License MIT(`cage/` 目录为上游 MIT 许可,见 `cage/LICENSE`)