# Reemplazar systemd con arje en una máquina real > **Importante**: este flujo deja **systemd intacto** y agrega arje como > entrada GRUB alternativa. No es "destruir y reemplazar"; es "convivir > hasta confiar". Booteás arje cuando querés, volvés a systemd si rompe. ## 1. Estrategia | componente | qué hacemos | | --------------------- | -------------------------------------------------------- | | `/sbin/init` | NO se toca (sigue siendo systemd). | | `/lib/systemd/*` | NO se toca. | | `kernel + initramfs` | reusamos los del host (firmware, módulos, root FS). | | `init=` en GRUB | nueva entrada apunta a `/sbin/ente-zero`. | | `GRUB_DEFAULT` | NO se cambia. Sigue arrancando systemd por default. | | `/ente/seed.card.json`| nueva — define qué arranca arje. | | `/usr/sbin/ente-*` | binarios musl-static del fractal. | Booteo del kernel → initramfs nativo hace su trabajo (mountea root, carga módulos) → cuando llega el `switch_root`, en lugar de exec `/lib/systemd/systemd`, exec `/sbin/ente-zero`. Esto deja firmware y udev fuera del scope de arje (todavía). ## 2. Instalación ```bash # 1. (opcional) revisá la seed default que se va a copiar a /ente/ $EDITOR seeds/arje-host.card.json # 2. instalar sudo scripts/install-arje-as-init.sh # 3. (opcional) bootear arje SÓLO en el próximo reboot (no cambia default) sudo grub-reboot "arje (init=/sbin/ente-zero) — kernel $(uname -r)" sudo reboot ``` Si algo rompe en arje: reset/poweroff → en el menú GRUB elegir la entrada default (systemd) → volvés a un sistema funcional. `arje` no toca configuración de systemd, así que el rollback es instantáneo. Para **desinstalar**: ```bash sudo scripts/uninstall-arje.sh ``` ## 3. Filosofía vs systemd — y por qué arje no acapara systemd arranca, por default, **todo lo que tiene un `.service` con `WantedBy=multi-user.target`**, recursivamente vía dependencias. Eso es opaco y crece con cada paquete instalado. arje no tiene generadores, ni `WantedBy`, ni `Wants`, ni target trees. **Arranca exactamente lo declarado en `genesis: [...]` de la `seed.card.json`**, en el orden declarativo, con la `supervision` que declarás vos. Si no lo declaraste, no corre. Punto. ### 3a. Servicios que systemd arranca y arje NO debería migrar Estos son los sospechosos típicos en Debian/Ubuntu/Arch. **No agregues ninguno a tu seed** salvo que sepas que lo usás: | systemd unit | por qué saltearlo | | ------------------------------------ | ---------------------------------------- | | `ModemManager.service` | no tenés módem 3G/4G. | | `bluetooth.service` | si no usás bluetooth. | | `cups.service`, `cups-browsed` | si no imprimís. | | `avahi-daemon.service` | mDNS local. Ruido si no lo necesitás. | | `snapd.service` | si no usás snaps. | | `apt-daily.service`, `apt-daily-upgrade` | autoupdates — no son init. | | `unattended-upgrades.service` | corre tras boot, no init. | | `accounts-daemon.service` | UI helpers GNOME; no init. | | `colord.service` | calibración de color. No init. | | `geoclue.service` | localización. No init. | | `gdm.service`, `lightdm.service` | DM gráfico — agregalo SÓLO si querés GUI.| | `NetworkManager-wait-online.service` | espera red. arje no necesita "esperar". | | `systemd-timesyncd.service` | reemplaza con cron-like + ntpd one-shot. | | `systemd-machined.service` | reemplazado por `ente-machined-compat`. | | `systemd-logind.service` | reemplazado por `ente-logind-compat`. | | `systemd-resolved.service` | reemplazado por `ente-resolved-compat`. | | `systemd-hostnamed.service` | reemplazado por `ente-hostnamed-compat`. | | `systemd-timedated.service` | reemplazado por `ente-timedated-compat`. | | `systemd-localed.service` | reemplazado por `ente-localed-compat`. | | `systemd-journald.service` | reemplazado por `ente-journald-compat`. | | `systemd-tmpfiles-*.service` | reemplazado por `ente-tmpfiles-compat`. | | `systemd-binfmt.service` | reemplazado por `ente-binfmt-compat`. | | `polkitd.service` | reemplazado por `ente-polkit-compat`. | Las últimas 12 ya están como Cards en `seeds/arje-host.card.json`. Las de la mitad de arriba **no** — no las agregues. ### 3b. Servicios que SÍ necesitás declarar (y que ya están en `arje-host.card.json`) | Card label | reemplaza | binario | | ------------------ | -------------------------- | -------------------------------------------- | | `tmpfiles-boot` | `systemd-tmpfiles-setup` | `/usr/sbin/ente-tmpfiles-compat --boot` | | `mount-fstab` | `local-fs.target` | `/bin/mount -a` (one-shot) | | `swap-on` | `swap.target` | `/sbin/swapon -a` (one-shot) | | `dbus-system` | `dbus.service` | `/usr/bin/dbus-daemon --system --nofork` | | `compat-*` (×11) | shims D-Bus de systemd | `/usr/sbin/ente-*-compat` | | `network-dhcpcd` | `NetworkManager` / `networkd` | `/usr/sbin/dhcpcd -B` | | `sshd` | `ssh.service` | `/usr/sbin/sshd -D` | | `getty-tty1` | `getty@tty1.service` | `/sbin/agetty --noclear tty1 linux` | 15 entes. Compará: una instalación Debian fresh con GNOME desktop tiene **>180 unidades activas** tras `systemctl list-units --state=running`. ### 3c. Cómo agregar un servicio que falta 1. Encontrá el binario y los argumentos. Mirá el `.service` original: ``` systemctl cat ``` Mirá `ExecStart=` y reproducí. 2. Agregá una Card al `genesis` de `/ente/seed.card.json`: ```json { "schema_version": 1, "id": "", "label": "mi-servicio", "provides": [], "requires": [], "permissions": { "networking": "outbound", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": true }, "soma": { ... idéntico al patrón de los otros ... }, "payload": { "Native": { "exec": "/usr/sbin/mi-bin", "argv": ["--foreground"], "envp": [] } }, "supervision": { "Restart": { "initial": 500, "max": 30000 } }, "lifecycle": "daemon", "priority": "normal", "flow": { "input": [], "output": [] }, "genesis": [] } ``` **Importante**: `argv` tiene que tener el equivalente a `--foreground` o `-D` o `--no-fork`. Si el binario se daemoniza solo (fork+exit), arje no lo puede supervisar y caerá en loop de restart. 3. Validar: ```bash seeds/validate.sh /ente/seed.card.json ``` 4. Reboot a arje. Verificar: ```sh arje# brahman-status ``` ## 4. Diferencias de UX con systemd | acción | systemd | arje | | ---------------------------- | ------------------------------------ | ------------------------------------------------------- | | Ver servicios activos | `systemctl list-units --state=running` | `brahman-status` + `busctl list-entes` | | Ver logs | `journalctl -u foo` | `ente-journalctl` (TODO en CLI; por ahora `dmesg`) | | Restart un servicio | `systemctl restart foo` | matar el PID (`brain` lo reanuda por `Supervision`) | | Habilitar/Deshabilitar | `systemctl enable/disable` | editar `/ente/seed.card.json` + reboot | | Ver dependencias | `systemctl list-dependencies foo` | `brahman-status` muestra references y flow matches | | Detectar fallas reincidentes | `systemctl status foo` → "failed" | `brainctl crystals` muestra patrones `EnteDied → …` | | socket activation | `.socket` unit | (no implementado todavía; ver flow + broker matching) | | user services | `--user` | (no implementado; arje es system-wide por ahora) | ## 5. Cosas que arje todavía NO hace que sí hace systemd - **udev / hotplug**: arje captura uevents (vía `spawn_uevent_stream`), pero no hay reglas declarativas todavía. Para boot inicial, el initramfs nativo ya hizo el cold-plug, así que no es bloqueante. - **Timers** (cron-like): `ente-timer-compat` existe pero no está en la seed host por default. Agregalo si querés `*.timer` units migradas. - **Service generators**: no hay equivalente a `systemd-fstab-generator` ni `systemd-getty-generator`. Tu seed los declara explícitamente. - **Socket activation**: parcialmente — el broker matchea flow consumer↔producer, pero no hay aún listen-on-fd-handoff como `sd_listen_fds()`. - **User instances**: no hay todavía `arje --user`. Los procesos de usuario los lanza un getty/login estándar. ## 6. Checklist pre-primer-boot - [ ] `seeds/arje-host.card.json` ajustada a tu hardware/red/users. - [ ] `seeds/validate.sh` → OK. - [ ] `/usr/bin/dbus-daemon` existe (de lo contrario los shims no se anuncian — `apt install dbus`). - [ ] `/usr/sbin/dhcpcd` o tu network stack preferido está instalado. - [ ] `/usr/sbin/sshd` instalado y `/etc/ssh/sshd_config` ok si querés poder entrar remoto si la consola falla. - [ ] `/sbin/agetty` instalado (`util-linux`) para tty1. - [ ] `sudo scripts/install-arje-as-init.sh` ejecutado. - [ ] `grub-reboot` apuntado a la entrada arje **sólo para el próximo boot** — no `grub-set-default`. - [ ] Listo para revertir vía menú GRUB si algo falla. ## 7. Cuando arje sea estable: hacerlo default Cuando ya hayas booteado arje N veces sin problemas y querés que sea default: ```bash # Listar entradas sudo grep -E "^\s*menuentry " /boot/grub/grub.cfg | nl # Ponerlo como default (usa el índice del menú o el title exacto) sudo grub-set-default "arje (init=/sbin/ente-zero) — kernel $(uname -r)" ``` Mantené la entrada systemd como rescue. Si querés acortar la lista de units que systemd arrancaría si bootea de nuevo: `systemctl disable ModemManager bluetooth cups …` — los nombres de §3a son una guía. ## Apéndice — depurar el primer boot fallido Si arje no levanta el primer boot: 1. Volver a GRUB → entrada systemd → bootea normal. 2. `journalctl --boot=-1` (logs del intento previo). 3. Buscar `ente-zero` o `Tarjeta Semilla`. Si nada → el ejecutable no se lanzó (kernel panic temprano, falta `init=` correcto, etc.). 4. Si arrancó pero falló alguna Card: la próxima vez, antes de reboot: ```bash sudo sed -i 's/console=tty1/console=tty1 ente.log=trace/' /etc/grub.d/40_custom sudo update-grub ``` y revisá `dmesg` desde systemd tras el reintento.