Clonar styx y sus SDK hermanos en un árbol fijo, comprobar la toolchain exacta y compilar contra clones locales, con un solo comando por nodo.
Implementado.
scripts/dev/bootstrap.sh,scripts/dev/setup.tsy el manifiestoscripts/dev/workspace.ymlestán en el repositorio y se han ejecutado de principio a fin en un nodo cloud Linux x86_64: dos corridas seguidas (la segunda sin cambios),verifyen verde y un--forklocal compilando el daemon. En macOS y en el servidor Linux no se han ejecutado todavía: las notas de esos nodos son lo que el script hace en ellos, no evidencia.
Styx se compila y se prueba en varias máquinas. Para no clonar a mano cada repo ni adivinar qué
versión de cada herramienta hace falta, cada nodo se prepara igual: un árbol de trabajo fijo, un
manifiesto que dice qué va en él y un doctor que compara lo instalado con lo que fija el repo.
git clone https://github.com/MKS2508/styx.git ~/src/styx-ws/styx && sh ~/src/styx-ws/styx/scripts/dev/bootstrap.shPara otro sitio, exporta STYX_WORKSPACE antes (por ejemplo, un SSD externo). Clona master;
STYX_REF elige otra rama.
Después, en cada shell:
. ~/src/styx-ws/env.sh
bun ~/src/styx-ws/styx/scripts/dev/setup.ts verify$STYX_WORKSPACE (por defecto ~/src/styx-ws)
├── env.sh STYX_WORKSPACE y, si hace falta, el bun fijado en el PATH
├── .tools/bun-<versión>/ sólo si el bun del PATH no es el de .bun-version
├── styx/ el monorepo (y su submódulo docs/references/quic-zig)
├── sdk/
│ ├── zkit/ master — primitivas Zig del daemon (dec-0103)
│ ├── spire/ main — spire-zig + @spire/bus (dec-0120)
│ ├── conduit/ master — ingesta: IngestSink y styx-upload (dec-0121)
│ └── quic-zig/ main — fork QUIC; el build usa el submódulo, no este clon (dec-0105)
├── tools/axon/ opcional — el CLI ya llega como @mks2508/axon
└── apps/mks-iptv-app/ opcional — app Swift de la fusión (sólo macOS)Lo declara scripts/dev/workspace.yml: id, URL https, ruta, rama por defecto (comprobada con
git ls-remote --symref), papel, si es opcional, y qué dependencia Zig o paquete npm publica. Un
repo nuevo se añade ahí y no en el script. Los opcionales se clonan con clone --all o
clone --only axon. Un repo inaccesible (privado sin credenciales, borrado) sale como FALTA
con el error de git y los demás siguen.
bootstrap.shEs sh POSIX y no necesita bun:
x86_64 o arm64/aarch64. Otro SO o arquitectura es un error explícito.$STYX_WORKSPACE/styx..bun-version. Si el del PATH es otro, descarga ese release de
GitHub, comprueba su sha256 contra SHASUMS256.txt y lo deja en .tools/. No toca el bun
global. En Linux x86_64 sin AVX2 elige la variante baseline y con musl la musl.env.sh sólo si cambia.setup.ts clone, deps y doctor. Con argumentos (sh bootstrap.sh doctor --libav)
ejecuta sólo eso.Es idempotente: no vuelve a descargar ni a clonar, y no reescribe nada. Un clon que ya existe no se toca, aunque tenga cambios o esté en otra rama; sólo se informa.
setup.ts| Subcomando | Qué hace |
|---|---|
doctor [--libav] [--json] | Compara lo instalado con lo que fija el repo. Sale con 1 si algo está en FALTA |
clone [--all] [--only a,b] | Crea el árbol del manifiesto |
deps | Inicializa docs/references/quic-zig si no lo está (si está en otro commit, avisa y lo deja), ejecuta bun install --frozen-lockfile y, con el Zig fijado, zig build --fetch |
infra up|down|status [--dry-run] | Postgres, Valkey, NATS y OTel de deploy/ con el override de dev (puertos sólo en 127.0.0.1). up crea antes los secretos si faltan, también con --dry-run; status falla si aún no hay deploy/.env |
zig [--fork a,b] [-- args] | zig build en native/zig contra clones locales de los SDK |
link spire / unlink spire | @spire/bus del clon local en lugar del pin publicado, y la vuelta |
verify [--fork a,b] | Ejecuta zig build, bun run typecheck y una prueba de humo: styx-upload sin argumentos sale con su mensaje de uso |
workspace | Imprime la raíz resuelta |
deps, infra, zig, link y verify actúan sobre $STYX_WORKSPACE/styx. Con --repo actúan
sobre otro checkout.
@spire/bus (dependencia github: del lockfile) y conduit/spire de native/zig/build.zig.zon
viven en repos privados, y ni bun install ni zig build --fetch usan las credenciales de git: un
nodo sin acceso recibe un 404. Con SDK_READ_TOKEN exportado (PAT fine-grained con sólo
contents:read sobre MKS2508/spire y MKS2508/conduit), deps instala con
scripts/ci/with-sdk-token.sh y precarga en la caché de Zig, verificadas por su .hash, las
dependencias de GitHub de build.zig.zon con scripts/ci/zig-fetch-private-deps.sh: lo mismo que
hace CI con el secreto de Actions del mismo nombre. El token no se escribe en ningún fichero.
export SDK_READ_TOKEN=<pat> # sólo en la sesión; nunca en env.sh ni en el repo
sh scripts/dev/bootstrap.shdoctorNinguna versión esperada está copiada en el script. Todas se leen del checkout:
| Comprobación | Contra qué |
|---|---|
| bun | .bun-version (en ramas que no lo tienen, packageManager). Tiene que ser exacto |
| zig | minimum_zig_version de native/zig/build.zig.zon, exacto. Avisa si no coincide con el suelo de build.zig. El arreglo trae el tarball de tu SO y arquitectura y, en x86_64-linux, el sha256 fijado en build.zig |
| git, git-lfs | git siempre. git-lfs sólo si .gitattributes usa filter=lfs (hoy no lo usa: N/A) |
| quic-zig | El submódulo está inicializado y en el commit fijado |
| node_modules | Hay bun install hecho |
| docker/podman | Cliente, daemon que responde y docker compose v2. Con sólo podman sale un aviso: los compose no se han probado con él |
| node | Playwright corre con node, no con bun (tools/e2e-harness/*/run.sh) |
| chromium | La revisión que pide el @playwright/test del harness, en PLAYWRIGHT_BROWSERS_PATH o la caché por defecto del SO |
| libav | Sólo con --libav: nasm, compilador C, make y FFmpeg 8 construido en native/zig/libav-bridge/.build/prefix |
| puertos | Cada puerto de deploy/docker-compose.infra.dev.yml, con sus STYX_DEV_*_PORT. Si lo tiene un contenedor deploy-*, la infra ya está arriba y es OK. Si lo tiene otro proceso, falta |
| disco | Por debajo de 5 GiB libres es FALTA. Por debajo de 10 GiB o por encima del 85 % de uso, AVISO |
Cada FALTA y cada AVISO traen el arreglo para el SO en el que se ejecuta. Ejemplo real del
nodo cloud:
OK bun bun 1.4.2
OK zig zig 0.17.0
OK quic-zig submódulo en 07101255
OK puerto 5433 STYX_DEV_PG_PORT ya lo publica deploy-postgres-1 (la infra de dev está arriba)
AVISO disco …: 8.2 GiB libres, 78% usado (aviso por debajo de 10 GiB o por encima del 85%)
→ limpia ~/.cache/zig, .zig-cache/ y zig-out/ viejos
16 OK · 0 FALTA · 2 AVISO · 2 N/Abuild.zig.zon fija zkit, spire y conduit por URL y hash. Para probar un cambio en un SDK sin
tocar el build.zig.zon, Zig 0.17 tiene zig build --fork=<ruta>. Sustituye en todo el grafo
cada paquete que tenga el mismo nombre que el build.zig.zon de esa ruta:
bun scripts/dev/setup.ts zig --fork spire # = zig build --fork=$STYX_WORKSPACE/sdk/spire
bun scripts/dev/setup.ts zig --fork spire,conduit -- test:container
bun scripts/dev/setup.ts verify --fork conduitZig lo dice en cada build (info: fork …/sdk/spire matched 1 spire packages). Sin --fork se
vuelve al pin publicado: no hay nada que deshacer. Para comprobar que el fork compila de verdad el
clon y no el pin, se añadió un @compileError al root.zig del clon de spire: el build con
--fork spire falló en esa línea y el build sin --fork siguió en verde.
Tres límites, comprobados con el Zig fijado:
master ya iba por delante del pin con un cambio de API (server.Completed sin
sha256). Con el clon en el commit del pin, el build es verde.--fork zkit falla mientras dos SDK fijen zkit distintos. zkit entra dos veces en el grafo:
la del daemon (que conduit comparte) y otra de spire. El fork sustituye las dos por la misma ruta
y Zig responde file exists in modules zkit-… and zkit-…. Antes hay que alinear el pin de zkit
en spire. setup.ts lo recuerda cuando se pide --fork zkit..path (el submódulo) y --fork sólo sustituye
paquetes por URL (matched no quic packages). Se trabaja dentro de
styx/docs/references/quic-zig, y sdk/quic-zig queda para ramas y PR al fork.@spire/bus localLos servicios fijan @spire/bus como github:MKS2508/spire#<commit> en sus package.json. Con
el linker aislado de bun, todos los workspaces enlazan una única copia en
node_modules/.bun/@spire+bus@…/node_modules/@spire/bus. bun link sólo cambiaría el enlace de la
raíz. Por eso:
bun scripts/dev/setup.ts link spire # esa copia pasa a ser un enlace a sdk/spire/packages/bus
bun scripts/dev/setup.ts unlink spire # vuelve el pin publicadolink ejecuta bun install --frozen-lockfile en el clon de spire, si hace falta, para que sus
dependencias se resuelvan desde allí, y guarda la copia publicada como ….pinned. No cambia
ningún package.json ni el bun.lock. bun install no deshace el enlace: lo da por bueno
(no changes). La vuelta es unlink. Se probó así: link, @spire/bus resuelto al clon desde
apps/catalog-svc, el typecheck y los tests de packages/bus contra el clon, y después unlink,
la resolución de vuelta al store y git status limpio.
setup.ts deja la toolchain y la infraestructura; los servicios no tienen un dev que arranque
solo, porque cada uno exige su configuración (base de datos, identidad del bus, OIDC, socket del
daemon: la lista está en la cabecera de su src/bootstrap.ts). Por orden:
bun scripts/dev/setup.ts infra up # Postgres :5433, Valkey :6380, NATS :4223, OTLP :14317/:14318 en 127.0.0.1
NATS_URL=nats://localhost:4223 bun run bus:streams # streams del bus, con la identidad de desplieguePara los servicios hay tres caminos, de más a menos completo:
tools/e2e-harness/: web-vod/run.sh levanta daemon, catalog, playback,
identity y la web con identidades del bus efímeras y su propio nats-server con la ACL, y
run-gate.ts levanta los servicios como contenedores. Su cabecera dice qué necesitan.deploy/ con el override de dev:
docker compose -f deploy/docker-compose.infra.yml -f deploy/docker-compose.infra.dev.yml -f deploy/docker-compose.apps.yml -f deploy/docker-compose.apps.dev.yml up -d --build.
docker-compose.apps.dev.yml monta tests/fixtures/ por una ruta absoluta de la máquina en la
que se escribió: hay que cambiarla en otra.bun --watch src/bootstrap.ts desde su carpeta, exportando a mano
las variables de su cabecera. Las semillas del bus están en deploy/secrets/ y el keyring en
deploy/.env tras deploy:secrets; el NATS de dev escucha en el 4223, no en el 4222 por
defecto.Cada servicio sirve su OpenAPI en /openapi/json y la interfaz Scalar en /openapi, sin CDN.
Lo controla STYX_OPENAPI=off|json|ui: ui por defecto fuera de producción, off en
producción, y si se activa en producción exige rol de administrador.
La web, sin mks-dev-session: bun run --cwd apps/web dev:vite. El sitio de documentación:
bun run --cwd apps/docs dev.
bootstrap.sh al empezar cada sesión. Es idempotente,
y la caché de bun y la de Zig, si sobreviven, lo hacen rápido. La primera corrida completa tardó
menos de un minuto con la caché caliente. verify, que incluye compilar el daemon, unos siete.SSL_CERT_FILE, NODE_EXTRA_CA_CERTS); doctor dice si están. El manifiesto usa URLs https
porque el proxy reescribe las de ssh. Un repo que el proxy no deja pasar sale como FALTA en
clone, sin colgarse pidiendo credenciales.bootstrap instala el exacto en .tools/ y
env.sh lo antepone en el PATH.bun run deploy:secrets, que infra up lanza si faltan secretos, se
niega a dejar las semillas del operador a root. Exporta STYX_OPERATOR_UID con un uid no root.deploy (el nombre del directorio), así que infra up desde otro checkout recrea esos
contenedores con sus propios secretos. infra up --dry-run enseña qué haría Compose, pero si
faltan deploy/secrets/ o deploy/.env los genera de verdad antes (no es un simulacro de
deploy:secrets). doctor muestra quién tiene cada puerto.doctor y borra el workspace al acabar si era
temporal.PLAYWRIGHT_BROWSERS_PATH).STYX_WORKSPACE=/Volumes/<disco>/styx-ws antes de bootstrap.sh, y en el perfil del shell. El
volumen tiene que ser APFS: con exFAT no hay enlaces simbólicos ni permisos POSIX, y el linker
aislado de bun, el env.sh y el enlace de @spire/bus los necesitan.zig-aarch64-macos-<versión>.tar.xz de la versión fijada (0.17.0, de
ziglang.org/download/0.17.0/). brew sólo vale si da exactamente esa versión. build.zig fija el
sha256 de x86_64-linux, aarch64-linux, x86_64-macos y aarch64-macos (scripts/pin-zig.ts, que
antes verifica la firma .minisig), y doctor imprime el comando con la comprobación.--libav): brew install nasm make coreutils. build-ffmpeg.sh usa nproc, que en
macOS viene de coreutils.playwright install chromium, sin --with-deps, que es sólo para Linux.apps/mks-iptv-app (opcional) sólo tiene sentido aquí, con Xcode.sudo apt-get install -y git curl unzip xz-utils, Docker desde el repositorio
oficial (docker-ce y docker-compose-plugin) y tu usuario en el grupo docker. Con libav,
además nasm build-essential pkg-config.deploy:secrets con sudo desde ese usuario reparte cada secreto
al uid de su contenedor y usa SUDO_UID como operador.bun-linux-aarch64 y Zig zig-aarch64-linux-…. Esa plataforma
tampoco tiene sha256 fijado: hay que verificar la firma.0.0.0.0.playwright install --with-deps chromium instala también las librerías del sistema.bootstrap.sh y setup.ts sólo se han ejecutado en el nodo cloud Linux x86_64. En macOS y en
el servidor no.infra up real no se lanzó en esa verificación, porque había una infra de otro checkout arriba
con el mismo proyecto de compose. Sólo se probaron --dry-run y la generación de secretos.doctor --libav con FFmpeg construido no se probó.doctor avisa pero no comprueba nada más.Relacionado: Empezar a contribuir para el mapa del repositorio y los comandos del día a día, y Ciclo de vida para el recorrido de desarrollar a publicar.
Empezar a contribuir
Qué instalar, cómo está organizado el repositorio, los comandos del día a día y las reglas de cambio.
Ciclo de vida
De desarrollar a publicar, paso a paso, con la página que manda en cada uno; preparar el nodo, probar, versionar, construir, publicar nightly y stable, instalar y actualizar.