Tu primer relay: instalación desde el código fuente

Por: Artiko
buzznostrrelayinstalaciondockerrustjusthermit

Tu primer relay: instalación desde el código fuente

En el capítulo 2 viste el mapa de crates y el pipeline de eventos. Ahora toca ponerlo a correr. Este capítulo es la ruta que el propio README.md llama “the developer / self-host path”: clonar, activar la toolchain, levantar la infraestructura y comprobar que el relay responde.

Lo que vas a montar aquí es un entorno de desarrollo. El relay corre en tu host con cargo run, no dentro de un contenedor. El despliegue real en un servidor usa otro bundle completamente distinto, que se ve en el capítulo 5. El propio README lo dice sin rodeos: “The root docker-compose.yml is for day-to-day development only.”

El mapa mental antes de teclear

flowchart TD
    subgraph host["Tu maquina - procesos nativos"]
        relay["buzz-relay<br/>cargo run<br/>puertos 3000 / 8080 / 9102"]
        desktop["App desktop Tauri<br/>pnpm exec tauri dev"]
    end
    subgraph docker["docker-compose.yml - red buzz-net"]
        pg["postgres:17-alpine<br/>5432"]
        redis["redis:7-alpine<br/>6379"]
        adminer["adminer<br/>8082"]
        keycloak["keycloak 26.0<br/>8180"]
        minio["minio<br/>9000 y 9001"]
        prom["prometheus<br/>9090"]
    end
    desktop -->|WebSocket| relay
    relay --> pg
    relay --> redis
    relay --> minio
    prom -->|scrape| relay

Tres cosas importantes de este diagrama, todas verificables en docker-compose.yml:

  1. El relay no está en el Compose de desarrollo. No hay servicio relay en ese archivo. Se compila y se ejecuta en tu máquina.
  2. No hay contenedor de búsqueda. Aunque .env.example declara TYPESENSE_API_KEY y TYPESENSE_URL=http://localhost:8108 en su cabecera de puertos, no existe ningún servicio Typesense en docker-compose.yml. La búsqueda full-text de Buzz vive en Postgres: el crate buzz-search consulta una columna search_tsv TSVECTOR GENERATED ALWAYS con índice GIN sobre la tabla events. Esas dos variables son residuo histórico; no levantes nada en 8108.
  3. Keycloak y Prometheus vienen incluidos aunque el flujo básico no los necesite: Keycloak para pruebas locales de OAuth, Prometheus para scrapear las métricas del relay en el host.

Requisitos previos

El README es explícito: “You’ll need Docker and Hermit (or Rust 1.88+, Node 24+, pnpm 10+, just).”

RequisitoPara quéNota
DockerPostgres, Redis, MinIO, Adminer, Keycloak, PrometheusObligatorio. just bootstrap aborta si docker no está en el PATH
HermitDescarga y fija todas las demás herramientasRecomendado. Vive dentro del repo, en bin/
Rust 1.88+Compilar el workspaceSolo si no usas Hermit
Node 24+Frontend desktop y webSolo si no usas Hermit
pnpm 10+Gestor de paquetes JSSolo si no usas Hermit
justTask runner del repoSolo si no usas Hermit

Qué es exactamente Hermit aquí

bin/ es un entorno Hermit: un directorio lleno de symlinks que descargan e instalan sus paquetes la primera vez que los invocas. Las versiones están fijadas en los propios nombres de los archivos .pkg:

HerramientaPinHerramientaPin
rustup1.28.2biome2.4.7
node24.15.0lefthook2.1.3
pnpm11.4.0cargo-deny0.19.0
just1.46.0cmake4.3.1
pgschema1.7.4flutter3.41.7

Fíjate en el desfase: el README pide “pnpm 10+”, pero el pin real es pnpm 11.4.0. Cuando activas Hermit obtienes exactamente esa versión, no la que tengas instalada globalmente. Ese es justamente el punto: nadie discute versiones.

Clonar y activar la toolchain

git clone https://github.com/block/buzz.git && cd buzz
. ./bin/activate-hermit

El punto inicial no es decorativo. El script arranca con una guarda que compara BASH_SOURCE con $0: si lo ejecutas como ./bin/activate-hermit imprime You must source this script y sale con código 33 sin hacer nada. Tiene que ser . ./bin/activate-hermit o source ./bin/activate-hermit. Cuando funciona, imprime Hermit environment ... activated y añade bin/ al frente de tu PATH. Para fish hay un script aparte, bin/activate-hermit.fish.

Cada terminal nueva necesita su propia activación. Es la razón por la que el README repite . ./bin/activate-hermit en la sección “Every day”.

just setup: qué hace exactamente

just setup && just build

setup está definido en el Justfile en dos líneas: depende de la receta bootstrap y luego ejecuta ./scripts/dev-setup.sh. Vale la pena desglosar ambos porque concentran casi todos los problemas de instalación.

flowchart TD
    B1["bootstrap: cargo, node y pnpm --version en paralelo<br/>fuerza la descarga de la toolchain Hermit"]
    B2["bootstrap: comprueba que docker exista, si no aborta"]
    B3["bootstrap: cp .env.example .env solo si .env no existe"]
    C1["dev-setup: preflight docker instalado y daemon corriendo"]
    C2["dev-setup: carga .env y exporta DATABASE_URL, PG*, REDIS_URL"]
    C3["dev-setup: limpia contenedores legacy sprout-*"]
    C4["dev-setup: aborta si un Redis local ocupa el 6379"]
    C5["_ensure-services: docker compose up -d y espera healthy"]
    C6["dev-setup: espera a que Postgres acepte conexiones"]
    C7["cargo run -p buzz-admin -- migrate"]
    C8["scripts/seed-local-community.sh"]
    C9["pnpm install en desktop/ y en web/"]
    C10["lefthook install --force"]
    B1 --> B2 --> B3 --> C1 --> C2 --> C3 --> C4 --> C5 --> C6 --> C7 --> C8 --> C9 --> C10

bootstrap en detalle

La receta invoca cargo --version, node --version y pnpm --version en paralelo. No es un chequeo cosmético: los symlinks de bin/ solo descargan el binario cuando se invocan por primera vez, así que esa línea es la que fuerza la descarga de la toolchain. Después comprueba Docker y, si falta, imprime Error: Docker is required but not installed. y sale.

La copia de .env es condicional: if [[ ! -f .env ]]. Si ya tienes un .env con tus ajustes, no lo pisa. Si quieres regenerarlo, bórralo y vuelve a correr just bootstrap. El mensaje que imprime al crearlo — “Created .env from .env.example — review it before running just dev” — no es retórico: la referencia completa de esas variables es el capítulo 4.

bootstrap es dependencia de setup, relay, relay-web, admin y dev, así que se ejecuta solo en casi cualquier flujo.

dev-setup.sh en detalle

Este script es donde ocurre lo interesante:

  • Preflight doble: comprueba command -v docker y además docker info. El segundo detecta el caso “Docker instalado pero el daemon apagado”, con el mensaje Docker daemon is not running. Start Docker Desktop and try again.
  • Herencia del nombre antiguo: el proyecto se llamó sprout. El script reescribe los valores por defecto sprout de tu .env a los de buzz — solo los defaults, no los personalizados — y para y elimina cualquier contenedor sprout-* que esté ocupando los puertos estándar. Los volúmenes se preservan.
  • Guardia de Redis local: si lsof detecta un proceso redis-ser escuchando en 6379 y no existe el contenedor buzz-redis, el script falla con el pid concreto y la sugerencia brew services stop redis. Es el fallo de instalación más común en máquinas de desarrollo.
  • Arranque de servicios: delega en just _ensure-services.
  • Espera de Postgres: hasta 10 intentos con pg_isready dentro del contenedor, con 2 segundos entre intentos.
  • Migraciones: cargo run -p buzz-admin -- migrate. Las migraciones SQL van embebidas en el binario.
  • Seed de comunidad local: scripts/seed-local-community.sh. Esto es crítico y suele malinterpretarse — lo explico abajo.
  • Dependencias JS: pnpm install en desktop/ y en web/. Si pnpm no está en el PATH, advierte y sigue en vez de fallar.
  • Hooks de git: fija core.hooksPath a una ruta absoluta derivada de git rev-parse --path-format=absolute --git-common-dir y corre lefthook install --force. El uso de ruta absoluta es deliberado, para que los worktrees enlazados hereden los mismos hooks.

Al terminar imprime un resumen con las URLs de Postgres, Redis, Adminer (http://localhost:8082) y Keycloak (http://localhost:8180, credenciales admin / admin).

Por qué existe seed-local-community.sh

El comentario del script lo explica textualmente:

El relay falla cerrado a propósito cuando el header Host de la petición no está en communities. El desarrollo local usa hosts de loopback, así que el bootstrap debe crear esas filas después de las migraciones, antes de que las llamadas HTTP del puente de desktop/Tauri puedan funcionar.

Es el “row-zero host binding” que viste en el capítulo 2: la URL es autoritativa para la comunidad. El script deriva los hosts a sembrar desde RELAY_URL (por defecto ws://localhost:3000). Si cambias RELAY_URL y no vuelves a sembrar, el relay responderá 404 a las peticiones con el host viejo.

_ensure-services: la receta que casi todo invoca

_ensure-services:
    # docker inspect buzz-postgres y buzz-redis -> .State.Health.Status
    # si ambos == healthy -> exit 0
    # si no -> docker compose up -d y esperar
    for i in $(seq 1 40); do ... sleep 3; done

Si ambos contenedores ya están healthy, imprime Services already healthy y sale de inmediato. Si no, hace docker compose up -d y sondea hasta 40 iteraciones de 3 segundos, es decir unos 120 segundos, antes de rendirse con timed out.

Encima de ella se apila _ensure-migrations:

_ensure-migrations: _ensure-services
    cargo run -p buzz-admin -- migrate
    ./scripts/seed-local-community.sh

Y just migrate es simplemente un alias sin cuerpo que depende de _ensure-migrations. Por eso just relay levanta Docker y migra sin que tengas que pedírselo.

just build

build es cargo build --workspace: compila todo en modo debug, y la primera vez es una compilación grande. just build-release hace lo mismo con --release, y just check-compile corre cargo check --workspace --all-targets si solo quieres verificar que compila sin producir binarios.

Arrancar: dos flujos

Flujo A — todo junto con just dev

. ./bin/activate-hermit
just dev

just dev depende de bootstrap, _ensure-sidecar-stubs y _ensure-migrations, y después hace algo bastante más elaborado que un simple cargo run:

  1. Resuelve el puerto del relay desde BUZZ_BIND_ADDR (default 0.0.0.0:3000), el de salud desde BUZZ_HEALTH_PORT (default 8080) y el de métricas desde BUZZ_METRICS_PORT (default 9102).
  2. Con lsof, comprueba que los tres puertos estén libres. Si alguno está ocupado aborta con Error: <nombre> port <n> is already in use; refusing to launch desktop against a stale relay. y te imprime el proceso culpable.
  3. Compila explícitamente buzz-acp, buzz-agent, buzz-backend-kubernetes, buzz-dev-mcp, buzz-cli, git-credential-nostr y buzz-relay.
  4. Exporta BUZZ_GIT_PROBE_WRITERS=8 y BUZZ_GIT_PROBE_ROUNDS=2 (los defaults del binario son 32 y 3). El comentario del Justfile explica por qué: “Docker Desktop’s forwarded MinIO port can stall under the deployment probe’s 32 concurrent writers.”
  5. Lanza ./target/debug/buzz-relay en background y hace polling de http://127.0.0.1:${health_port}/_readiness durante 120 intentos de 0,5 s, o sea 60 segundos. Si el relay muere durante el arranque, o no llega a healthy en ese plazo, aborta sin lanzar la app.
  6. Carga scripts/instance-env.sh y arranca pnpm exec tauri dev.

instance-env.sh deriva el puerto de Vite haciendo un hash SHA-256 de la raíz del worktree (10000 + h % 55000), de modo que cada worktree obtiene siempre el mismo puerto y varias instancias de desarrollo pueden convivir. BUZZ_RELAY_PORT sí queda fijo en 3000.

Flujo B — terminales separadas

El README lo recomienda cuando quieres los logs del relay separados de la salida de Vite: en la terminal 1, . ./bin/activate-hermit && just relay; en la terminal 2, . ./bin/activate-hermit && just desktop-dev.

  • just relay = bootstrap + _ensure-migrations + cargo run -p buzz-relay. Nada más. Es el camino limpio para operar solo el relay.
  • just desktop-dev no depende de nada: entra en desktop/, corre pnpm install si falta node_modules, carga instance-env.sh y lanza pnpm exec vite --port "${BUZZ_VITE_PORT}" --strictPort. Es solo el servidor de frontend, sin ventana nativa.

Existe además just relay-release (cargo run -p buzz-relay --release), que depende de _ensure-migrations pero no de bootstrap.

Servicios y puertos del Compose de desarrollo

Con el proyecto Compose buzz y la red buzz-net:

ServicioContenedorImagenPuerto host:contenedorHealthcheckLímite de memoria
postgresbuzz-postgrespostgres:17-alpine5432:5432pg_isready -U buzz512m
redisbuzz-redisredis:7-alpine6379:6379redis-cli ping128m
adminerbuzz-admineradminer:latest8082:808064m
keycloakbuzz-keycloakquay.io/keycloak/keycloak:26.08180:8080/health/ready512m
miniobuzz-miniominio/minio:latest9000:9000 y 9001:9001/minio/health/live256m
minio-initbuzz-minio-initminio/mc:latestone-shot, restart: "no"
prometheusbuzz-prometheusprom/prometheus:latest9090:9090128m

Credenciales de desarrollo, tal como están escritas en el archivo: Postgres buzz / buzz_dev / base buzz; MinIO buzz_dev / buzz_dev_secret; Keycloak admin / admin. Son valores de desarrollo y solo de desarrollo.

minio-init es un contenedor efímero que crea el bucket con mc mb --ignore-existing local/buzz-media y le aplica mc anonymous set none. Volúmenes con nombre: buzz-postgres-data, buzz-minio-data y buzz-prometheus-data. Redis no tiene volumen: sus datos son efímeros por diseño en desarrollo.

Y los puertos que abre el relay, que corre fuera de Docker:

PuertoQué sirveVariable
3000WebSocket NIP-01, REST, documento NIP-11BUZZ_BIND_ADDR
8080/_liveness, /_readiness, /_status, /_meshBUZZ_HEALTH_PORT
9102/metrics para PrometheusBUZZ_METRICS_PORT

Verificar que el relay responde

Con el relay corriendo, cuatro comprobaciones en orden creciente de exigencia.

1. Liveness. El handler devuelve texto plano ok sin tocar nada:

curl -i http://127.0.0.1:8080/_liveness

2. Readiness. Aquí sí se comprueban las dependencias: el handler hace db.ping() y pide una conexión al pool de Redis en paralelo, con timeout de 2 segundos.

curl -s http://127.0.0.1:8080/_readiness
# sano:     {"status": "ready"}
# con fallo: {"status": "not_ready", "postgres": false, "redis": true}
# apagandose (HTTP 503): {"status": "shutting_down"}

Ese desglose por dependencia es todo el valor del endpoint: te dice cuál de las dos falló.

3. Status. Nombre de servicio, versión del crate y uptime:

curl -s http://127.0.0.1:8080/_status
# {"service": "buzz-relay", "version": "...", "uptime_seconds": 42}

4. El documento NIP-11. Esta es la prueba de que el puerto principal habla Nostr:

curl -s -H "Accept: application/nostr+json" http://localhost:3000/

El handler / decide qué devolver según cabeceras: si el Accept contiene application/nostr+json sirve el documento NIP-11; si es un upgrade de WebSocket válido, hace el binding de comunidad y abre la conexión; si no es ninguna de las dos, cae de vuelta al documento NIP-11. También existe GET /info, que sirve el mismo documento sin negociación de contenido.

Un detalle de seguridad que conviene entender ahora, porque explica errores confusos más adelante: el documento NIP-11 se sirve antes del binding de comunidad y falla abierto, precisamente para que no se pueda deducir qué hosts están mapeados. El upgrade a WebSocket, en cambio, falla cerrado:

HTTP 404
relay: no community is configured for this host

Ese mensaje genérico aparece cuando el header Host no tiene fila en communities. Si te sale en local, el arreglo casi siempre es volver a ejecutar ./scripts/seed-local-community.sh con el RELAY_URL correcto.

En el puerto 3000 también están disponibles /health, /_liveness y /_readiness; /_status y /_mesh solo existen en el router de salud del 8080.

Catálogo de targets útiles del Justfile

just sin argumentos ejecuta la receta default, que es just --list. Estos son los que usarás a diario como operador.

Entorno

TargetQué hace
just bootstrapDescarga la toolchain Hermit, verifica Docker, crea .env si falta
just setupbootstrap + scripts/dev-setup.sh
just hooksConfigura core.hooksPath y lefthook install --force
just psdocker compose ps
just logs *ARGSdocker compose logs -f {{ARGS}}
just downdocker compose down, conserva los volúmenes
just migrateAlias de _ensure-migrations
just cleancargo clean en el workspace y en desktop/src-tauri

Ejecución

TargetQué hace
just relayRelay en debug, con servicios y migraciones garantizados
just relay-releaseRelay en release
just relay-webCompila web/ y arranca el relay con BUZZ_WEB_DIR=./web/dist
just devRelay en background + app desktop Tauri
just desktop-devSolo el servidor Vite del frontend desktop
just adminDashboard de administración de solo lectura, en admin.localhost:3000
just desktop-standaloneSolo la app desktop, sin relay, base de datos, Docker ni .env

Verificación y tests

TargetQué haceNecesita infra
just checkfmt-check, clippy, desktop-check, checks de Tauri, web-check, mobile-checkNo
just fmt / just fmt-checkcargo fmt --all con y sin --checkNo
just clippycargo clippy --workspace --all-targets -- -D warningsNo
just test-unitTests unitariosNo
just test-integration./scripts/run-tests.sh integration
just test./scripts/run-tests.sh allSí, los levanta si hace falta
just ciTodo lo que corre CINo

just test-unit tiene una particularidad: si encuentra cargo-nextest en el PATH, corre paquetes enumerados uno por uno — buzz-core, buzz-auth, buzz-voice, buzz-cli, buzz-db --lib, buzz-conformance, buzz-push-gateway, buzz-backend-kubernetes — y si no, cae a ./scripts/run-tests.sh unit. Los paquetes están enumerados explícitamente porque, según el propio comentario del Justfile, “nothing in CI runs cargo test --workspace: pertenecer al workspace te compra clippy y check, no un solo test ejecutado.

just ci es la cadena completa sin infraestructura: check test-unit desktop-test desktop-build desktop-tauri-check desktop-tauri-test web-build mobile-test. Es lo que conviene correr antes de un push.

just reset: la receta destructiva

reset lleva el atributo [confirm("This will DELETE all development data and preserve installed Buzz. Continue? (y/N)")], que obliga a una confirmación interactiva antes de ejecutar ./scripts/dev-reset.sh --yes.

dev-reset.sh borra el estado de desarrollo del desktop con scripts/reset-desktop-dev-state.sh, hace docker compose down -v --remove-orphans — la -v borra todos los volúmenes: Postgres, MinIO y Prometheus — y luego exec scripts/dev-setup.sh para recrear todo. Advertencia literal del script: “This will DELETE all development data (desktop state, postgres, minio volumes). Installed Buzz app state and its production keyring are preserved. Redis data is ephemeral and always wiped on restart.”

Traducido a la práctica: reset preserva tu Buzz instalado y su keyring de producción, pero se lleva por delante toda la base de datos local. Si solo quieres parar los servicios sin perder datos, el comando es just down.

Prerrequisitos de Windows

El README dedica una sección propia a esto. El motivo es concreto: la herramienta de shell del agente ejecuta comandos bajo bash. En macOS y Linux bash ya está; en Windows hay que traerlo.

La instalación de Git for Windows incluye Git Bash, que es lo que Buzz resuelve en tiempo de ejecución. Con eso instalado, todo funciona igual que en las demás plataformas. Si prefieres apuntar a otro shell compatible con bash, defines BUZZ_SHELL con su ruta (por ejemplo BUZZ_SHELL=C:\path\to\bash.exe); la descripción de la herramienta que ve el agente se actualiza automáticamente para reflejar el shell activo.

Un detalle del Justfile que también afecta a Windows: la receta _ensure-sidecar-stubs genera binarios placeholder para buzz-acp, buzz-agent, buzz-dev-mcp, git-credential-nostr y buzz; buzz-backend-kubernetes se añade a la lista solo cuando el target no es Windows.

Troubleshooting de instalación

Los tres fallos de arranque más frecuentes

MensajeOrigenQué hacer
Error: Docker is required but not installed.just bootstrap, check command -v dockerInstalar Docker, o arreglar el PATH si ya está
Docker daemon is not running. Start Docker Desktop and try again.dev-setup.sh, check docker infoArrancar el daemon
Local Redis is already listening on port 6379 (pid(s): ...)dev-setup.shParar el Redis nativo: brew services stop redis en macOS, sudo systemctl stop redis en Linux

El check de Redis solo se dispara si lsof está disponible y si el contenedor buzz-redis no está ya corriendo. Es el fallo de instalación más común en máquinas de desarrollo con Redis nativo.

El activate-hermit “no hace nada”

Lo ejecutaste en vez de sourcearlo. Sale con código 33. Usa el punto: . ./bin/activate-hermit.

_ensure-services termina en “timed out”

Los healthchecks de buzz-postgres y buzz-redis no llegaron a healthy en 120 segundos. Diagnostica con:

docker compose ps
docker compose logs -f postgres
docker inspect --format '{{.State.Health.Status}}' buzz-postgres

La causa habitual es un volumen buzz-postgres-data corrupto o de una versión incompatible. just reset lo resuelve, a costa de borrar los datos.

”Postgres did not accept connections after 10 attempts”

El contenedor está healthy pero pg_isready dentro del contenedor sigue rechazando con el usuario y la base concretos. Revisa que PGUSER, PGPASSWORD y PGDATABASE en tu .env coincidan con lo que declara docker-compose.yml (buzz / buzz_dev / buzz).

just dev aborta con “port … is already in use”

Hay un relay viejo vivo. El propio error imprime la salida de lsof con el pid. Mátalo y repite. Es un fallo deliberado: la receta se niega a lanzar el desktop contra un relay obsoleto.

”buzz-relay did not become healthy within 60 seconds”

El relay arrancó pero /_readiness nunca devolvió 200 en 60 segundos. Corre just relay a solas para ver sus logs sin la interferencia de Tauri. Los sospechosos habituales son Postgres, Redis o la sonda de conformidad de git.

El relay muere al arrancar mencionando la “conformance probe”

Antes de abrir el listener, el relay ejecuta una sonda de conformidad A3 contra el backend de almacenamiento de objetos, para admitir escrituras condicionales linealizables. El comentario del código es explícito: “Failure is fatal: a backend that cannot satisfy pointer CAS invalidates the manifest-pointer protocol.”

La sonda está activa por defecto: se lee BUZZ_GIT_CONFORMANCE_PROBE y cualquier valor distinto de "false" la habilita. Sus defaults en el binario son 32 escritores concurrentes (BUZZ_GIT_PROBE_WRITERS) y 3 rondas (BUZZ_GIT_PROBE_ROUNDS). Como el puerto MinIO reenviado por Docker Desktop puede atascarse con esa concurrencia, just dev baja los valores a 8 y 2. Si arrancas el relay a mano y la sonda falla, prueba el mismo perfil acotado:

BUZZ_GIT_PROBE_WRITERS=8 BUZZ_GIT_PROBE_ROUNDS=2 cargo run -p buzz-relay

Y comprueba antes que MinIO esté vivo: curl -f http://localhost:9000/minio/health/live.

404 “relay: no community is configured for this host”

El binding de comunidad falló cerrado. La fila del host no existe en communities. Vuelve a correr ./scripts/seed-local-community.sh, y verifica que tu RELAY_URL sea el mismo con el que sembraste.

”pnpm not found — skipping desktop dependency install”

dev-setup.sh advirtió y siguió. El script te da la receta exacta: . ./bin/activate-hermit para obtener pnpm y luego just desktop-install.

Ventana en blanco o transparente al abrir la app en Linux

Esto no es del relay, pero se topa en el mismo primer arranque. docs/linux-rendering-troubleshooting.md documenta tres casos:

SíntomaCausa probableArreglo
Ventana en blanco o transparente y SIGABRT con colrv1_configure_skpaintFuente de emoji COLRv1, solo en AppImageActualizar al AppImage v0.5.2+
Ventana en blanco al arrancar, sin crashIncompatibilidad del renderer dmabuf, NVIDIA o AppImageWEBKIT_DISABLE_DMABUF_RENDERER=1 o --safe-rendering
Ventana en blanco en cualquier hardware, sin crashCombinación GPU/driver desconocida--safe-rendering

Desde v0.5.1, Buzz fija WEBKIT_DISABLE_DMABUF_RENDERER=1 por sí mismo cuando detecta una GPU NVIDIA — vendor ID 0x10de en /sys/class/drm — o cuando corre como AppImage. El flag --safe-rendering fuerza además WEBKIT_DISABLE_COMPOSITING_MODE=1 y aplica solo a ese lanzamiento; si defines tú una variable de WebKit y además pasas el flag, Buzz se niega a arrancar e imprime cuál entra en conflicto. Para AMD RDNA4 con driver radv el workaround verificado son tres variables: GDK_BACKEND=x11, WEBKIT_DISABLE_DMABUF_RENDERER=1 y WEBKIT_SKIA_ENABLE_CPU_RENDERING=1.

Ojo con el piso de glibc del AppImage: hasta v0.5.1 era 2.35 (Ubuntu 22.04 LTS, Debian 12); desde v0.5.2 es 2.39 (Ubuntu 24.04 LTS, Fedora 40+). En Ubuntu 22.04 o Debian 12, el documento recomienda los paquetes nativos .deb o .rpm, que usan el WebKit del sistema.

Resumen

  • El entorno de desarrollo separa dos mundos: la infraestructura corre en Docker (docker-compose.yml, proyecto buzz, red buzz-net) y el relay corre nativo en tu host con cargo run. No hay servicio relay en el Compose de desarrollo.
  • Hermit fija toda la toolchain dentro del repo: rustup 1.28.2, node 24.15.0, pnpm 11.4.0, just 1.46.0, entre otros. Se activa con . ./bin/activate-hermit en cada terminal; ejecutarlo en vez de sourcearlo sale con código 33.
  • just setup es bootstrap más scripts/dev-setup.sh: descarga toolchain, verifica Docker, copia .env.example a .env solo si falta, levanta y espera los servicios, migra con buzz-admin migrate, siembra la comunidad local e instala dependencias JS y hooks.
  • Los puertos de desarrollo son Postgres 5432, Redis 6379, Adminer 8082, Keycloak 8180, MinIO 9000/9001, Prometheus 9090; y del relay, 3000 para WS y REST, 8080 para salud y 9102 para métricas.
  • No existe contenedor de Typesense pese a que .env.example lo menciona: la búsqueda full-text vive en Postgres.
  • Verificas el relay con /_liveness y /_readiness en el 8080 — este último te dice cuál dependencia falla — y con el documento NIP-11 pidiendo Accept: application/nostr+json en el 3000.
  • El binding de comunidad falla cerrado: un host sin fila en communities recibe un 404 genérico. seed-local-community.sh es lo que crea esas filas en local.
  • just down conserva los datos; just reset pide confirmación y borra todos los volúmenes locales.
  • En Windows hace falta Git Bash porque la herramienta de shell del agente ejecuta bajo bash; BUZZ_SHELL permite apuntar a otro shell compatible.

Siguiente: Configuración: referencia de variables de entorno