El compositor compiló a la primera en 51m39s (JOBS=1 + lto fat), sin un solo parche a la fuente; lo único que hubo que corregir fue el --bin del gotcha 1. Lo que vale es el enlace, porque es medición y no impresión: ocho NEEDED, y las siete primeras son EXACTAMENTE los backends de smithay que la receta declara (display-info, gbm, seat, udev, input, pixman, xkbcommon). La octava es musl. No hay libgcc_s —el compositor no arrastra la deuda del unwinder— y no aparece nada sin declarar: la clausura de build y la de runtime coinciden. Un compositor Wayland completo (DRM/GBM/EGL/libinput/seat/Vulkan/XWayland, renderer multi-GPU y UI en iced) cerrando con ocho librerías compartidas y cero parches es el resultado más limpio de las cuatro campañas de escritorio. Queda anotado además por qué cosmic-settings-daemon NO se resuelve copiando pipewire: copiar entre colas es gratis sólo si TODA la clausura transitiva resuelve igual, y ahí glib resolvería distinto (sombra de GNOME b3:f6ccdf98 vs corpus b3:93d2cad0) ⇒ un segundo pipewire contra otra glib, que es el cuadro de dos registros de GType que la campaña GNOME ya midió y evitó. Medido con yupana radio antes de tocar nada. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
12 KiB
Runbook — COSMIC, el cuarto escritorio
Estado al 2026-08-03: campaña abierta. Tres piezas selladas (cosmic-session, cosmic-icons,
cosmic-bg) y el compositor en construcción. Este documento se escribe mientras se hace, no después.
COSMIC es el escritorio de System76, en Rust sobre smithay (compositor) e iced/libcosmic (clientes). Es el cuarto de hammer, tras mirada, KDE Plasma 6 y GNOME.
Por qué NO se parece a los dos anteriores
KDE y GNOME costaron lo que costaron por la misma razón: una torre de C con Qt o
glib/GObject/introspección debajo, donde cada capa se paga entera antes de ver un píxel. COSMIC no
tiene esa torre. La primera receta —cosmic-session— salió a la primera y sin una sola dep en C:
ELF estático, cero NEEDED.
Lo que sí hereda es lo que ya está pago:
| lo que COSMIC necesita | de dónde sale | costo |
|---|---|---|
| las deps en C de smithay (drm, gbm, seat, input, udev, xkb, pixman) | mirada-compositor, que ya es un compositor smithay de este lab |
cero — misma lista |
libdisplay-info + hwdata |
copiadas byte a byte de la cola GNOME | cero — mismo hash, artefacto ya sellado |
bash, dbus-run-session, hicolor-icon-theme, mesa-llvmpipe |
corpus | cero |
el andamiaje de arranque en QEMU (run-qemu-desktop.sh, base rootfs, console-getty, screendump) |
campañas KDE/GNOME | cero |
La deuda propia que sí trae, y que ninguna de las otras campañas tocó, es la del unwinder de la std de rustc cuando el enlace no es estático — la misma que ya está documentada para las recetas Cargo del corpus.
El pin es de la SUITE, no de cada paquete
COSMIC versiona todos sus repos en lockstep con el tag epoch-N. Comprobado repo por repo: los
doce componentes están en epoch-1.5.0.
No mezclar epochs entre piezas. Comparten protocolos propios (cosmic-protocols) y el formato de
configuración (cosmic-config); un desajuste ahí no da error de compilación, da un escritorio que
arranca y no se entiende consigo mismo — que es mucho más caro de diagnosticar.
La cola
recipes/incoming-cosmic/, aislada (otro agente comparte el repo; nunca git add -A).
Las deps se resuelven hermano → padre: desde incoming-cosmic/ se ven las recetas de
recipes/, pero no las de incoming-gnome/ ni incoming-kde/. Por eso libdisplay-info y
hwdata entran copiadas. Y copiar es gratis de verdad, no «casi»: el ArtifactHash no depende de la
ruta de la receta, así que un fichero idéntico con deps que resuelven a lo mismo da el mismo hash
⇒ cache hit sobre el artefacto que ya existe. Se verificó antes de copiar (b3:260f0519,
b3:bdc36cf9), no después.
Qué levanta la sesión, y por lo tanto el orden de ataque
cosmic-session/src/main.rs es la lista autoritativa —el mismo método que cerró la capa JS de GNOME:
leé el fichero donde el programa declara lo que arranca, no lo descubras de a uno:
cosmic-comp → cosmic-notifications · cosmic-panel · cosmic-app-library
→ cosmic-launcher · cosmic-workspaces · cosmic-osd · cosmic-bg · cosmic-idle
Más cosmic-settings-daemon y xdg-desktop-portal-cosmic fuera de esa lista.
| pieza | estado | hash |
|---|---|---|
cosmic-session |
✅ sellado | b3:81f02351 |
cosmic-icons |
✅ sellado (671 SVGs) | b3:94d06f77 |
cosmic-bg |
✅ sellado (estático) | b3:7b4962f0 |
dav1d 1.5.4 |
✅ sellado (dep arrastrada, ver gotcha 8) | b3:aab7a874 |
cosmic-comp |
✅ SELLADO — el gate | b3:b8abc52f |
cosmic-idle |
✅ sellado (estático) | b3:175632b7 |
cosmic-osd |
🔨 en construcción | — |
cosmic-panel · cosmic-launcher · cosmic-app-library · cosmic-workspaces-epoch · cosmic-notifications |
receta escrita, sin construir | — |
cosmic-settings-daemon |
ni receta | — |
cosmic-settings-daemon: por qué queda al final y NO se resuelve copiando
Es el único con cadena propia. Su workspace incluye audio-server como dep de path no opcional,
que arrastra cosmic-pipewire → pipewire-sys → libpipewire-0.3 por pkg-config. Y pipewire hoy
vive sólo en las colas GNOME y KDE.
Acá el truco de copiar deja de ser gratis, y eso corrige lo que dice más arriba. La regla completa
es: copiar una receta entre colas es gratis sólo si toda su clausura transitiva resuelve a lo
mismo. Se cumplió con libdisplay-info, hwdata y nasm —sus deps están todas en el corpus—, y
no se cumple con pipewire: de sus catorce deps, cinco viven sólo en colas ajenas
(dbus-shared, alsa-lib, libsndfile, pulseaudio, zlib-shared) y —lo decisivo— glib
resolvería distinto. Desde incoming-gnome, glib es la sombra de esa cola (b3:f6ccdf98); desde
incoming-cosmic sería la del corpus (b3:93d2cad0). Son recetas distintas, no la misma en dos
lugares.
O sea que copiar produciría un segundo pipewire construido contra otra glib, arrastrando su cadena entera. Y eso no es sólo caro: es exactamente el cuadro que la campaña GNOME ya midió y evitó —dos glib distintas con 370 rutas solapadas y dos registros de GType en un proceso—.
Antes de tocar nada se midió con yupana radio (la puerta única, nunca grep): pipewire tiene
radio 1 en GNOME y 2 en KDE, pero glib del corpus tiene 21 dependientes transitivos y afecta la
imagen escritorio-gnome. La decisión correcta no es de esta campaña: es dónde vive pipewire en el
corpus, y es una decisión de catálogo, no de COSMIC. Hasta entonces, el escritorio arranca sin
settings-daemon —se pierden brillo, tema automático y perfiles de audio, no el escritorio—.
El orden no es el de la lista de arranque. cosmic-bg va antes que el panel a propósito: habla
Wayland con smithay-client-toolkit y no toca libcosmic ni iced, mientras que panel, launcher,
osd y workspaces son todos clientes de iced. Con el fondo sellado, «pinta el fondo pero no el panel»
separa la capa de UI del transporte; sin él, las dos preguntas llegan juntas.
🚪 EL GATE PASADO: cosmic-comp compila (2026-08-03)
b3:b8abc52f, 51 min 39 s de cargo con CARGO_BUILD_JOBS=1 y lto = "fat". A la primera, salvo
el --bin del gotcha 1. Sin un solo parche a la fuente.
Lo que dice el enlace es la parte que vale, porque es la medición y no la impresión:
NEEDED: libdisplay-info.so.2 · libgbm.so.1 · libseat.so.1 · libudev.so.1
libinput.so.10 · libpixman-1.so.0 · libxkbcommon.so.0 · libc.so
Ocho, y las siete primeras son exactamente los backends de smithay que la receta declara. La
octava es musl. No hay libgcc_s — o sea que el compositor no arrastra la deuda del unwinder que
sí tienen varias recetas Cargo del corpus, porque acá el enlace es dinámico contra musl y no hay
+crt-static que forzar. Y no aparece nada que no se haya declarado: la clausura de build y la de
runtime coinciden, que es la propiedad que uno quiere y casi nunca se cumple gratis.
Que un compositor Wayland completo —DRM, GBM, EGL, libinput, seat, Vulkan, XWayland, un renderer multi-GPU y una capa de UI en iced— cierre con ocho librerías compartidas y ningún parche es el resultado más limpio de las cuatro campañas de escritorio.
Gotchas medidos (no previstos)
-
cargo rustc --exige UN target. La fase compile del lab pasa flags tras el--, y cualquier paquete con binario + lib + ejemplos corta con «extra arguments torustccan only be passed to one target». Se arregla conflags = ["--bin", "<nombre>"]. Le pasa a cosmic-comp y a cosmic-bg (workspace conconfig/), y le va a pasar a casi todos: ponelo desde el principio. -
start-cosmices bash de verdad, no sh. Usamapfile,[[ ]]y expansión indirecta${!var}; con el busybox del rootfs no arranca.bashya está en el corpus, pero tiene que entrar en la imagen — y no lo pide ningún[deps], así que no lo va a traer nadie por accidente. Lo mismo condbus-run-session(dedbus), que es lo que el script exec-uta al final. -
rust-toolchain.tomlconchannel = "1.93"es inerte acá — es una perilla de rustup, y el sandbox tiene el rustc de Alpine (1.96) pelado. Conviene saberlo antes de «arreglarlo». -
cosmic.desktopexiste DOS veces (en cosmic-session y en cosmic-comp) con contenido distinto y en la misma ruta. El de cosmic-comp es el de la «bare session» y apunta a/usr/bin/cosmic-service, que vive en la rama de systemd que acá no va. Se instala sólo el de cosmic-session; si entraran los dos, quién gana depende del orden de hidratación y el que pierde es el bueno. -
libsystemdno es systemd. La featuredefault = ["systemd"]de cosmic-comp trae el cratelibsystemd, que es una reimplementación en Rust del protocolo, no un binding a la C. Ylogindhablaorg.freedesktop.login1, que acá lo sirvearje-logind-compat. No hay que apagar nada: el nombre de la feature es el del protocolo, no el del programa que lo contesta. -
Las features de smithay que asustan no cuestan deps de build:
backend_vulkan(crateash),backend_x11(x11rbcondl-libxcb) yxwaylandcargan todo por dlopen. Son deuda de RUNTIME —libxcb y vulkan-loader viven hoy sólo en la cola KDE—, no un muro de compilación. -
libxkbcommon+pkgconfvan en TODA la cola, sin excepción — incluso en las piezas sin interfaz. Se aprendió dos veces, con dos razonamientos distintos y los dos equivocados:cosmic-bgfue sin[deps]porque «habla el protocolo en Rust y no toca C». Reventó en elbuild.rsdesmithay-client-toolkitpidiendoxkbcommon.pc: sctk ENLAZA libxkbcommon; el que la dlopea eswinit, que es otra capa. Hablar Wayland en Rust dice cómo viaja el byte, no con qué se interpreta un teclado.cosmic-idlefue sin[deps]porque ese argumento ya no aplicaba —no usa sctk— y un demonio de inactividad no interpreta teclas. Reventó en el ENLACE con-lxkbcommon, arrastrado porcosmic-settings-config: de ahí sale la tabla de atajos y la usa todo componente de la suite. La dep no viene de lo que el paquete hace, sino de la librería de configuración común.
La lección de método vale más que la dep: la dep no se deduce de la función del paquete. Está escrita en el
build.rsque panickea o en la línea de enlace, y las dos veces el error dijo exactamente quién y por qué. Ellink = "static"sobrevive porque el artefacto de libxkbcommon trae.aademás de.so. -
Una feature apagada en el paquete puede estar prendida por otro.
cosmic-bgdeclaraimagecondefault-features = falsey sin AVIF, y aun así compiladav1d-sys: las features de cargo se UNIFICAN en el grafo. Se resolvió trayendodav1d(b3:aab7a874) en vez de parchear el Cargo.toml de upstream — si el grafo dice que sabe decodificar AVIF, que lo sepa de verdad. Mismo modo de falla que un.pc Requiresarrastrando una dep que nadie declaró.
Cómo se construye
cd ~/hammer
./target/release/hammer --store store hash recipes/incoming-cosmic/<pieza>.toml # dry-run, ~2ms
./target/release/hammer build recipes/incoming-cosmic/<pieza>.toml --store store
Lo que falta, en orden
- Cerrar
cosmic-comp. Es el gate: sin compositor no hay escritorio que probar. - El primer cliente de iced (
cosmic-panel), que es la pregunta abierta de verdad — libcosmic conwinit/wgpupuede pedir más de lo que pide cosmic-bg. cosmic-settings-daemon,cosmic-launcher,cosmic-app-library,cosmic-notifications,cosmic-osd,cosmic-workspaces-epoch,cosmic-idle.- Imagen QEMU con
bash+dbus-run-session+hicolor-icon-theme, y validar CON PANTALLA (DISP=gtk+screendump, contar colores distintos) — regla heredada de KDE y GNOME. xdg-desktop-portal-cosmicycosmic-greeter, que son de la etapa siguiente.