Ir al contenido

Instalación self-hosted

Thulu self-hosted es un binario (thulu) que instala y administra el resto: el daemon con el dashboard, Postgres y los servidores MCP que usan los agentes. El binario pesa unos 22 MB y trae adentro los archivos de despliegue, así que no hace falta clonar nada; el daemon corre desde la imagen octopus. thulu init es un asistente de terminal que pregunta, escribe la configuración, crea el primer workspace con una key para la CLI y levanta el stack. El instalador también deja octopus como alias del mismo comando.

Si preferís no instalar nada, mirá Empezar en SaaS: hoy es una beta cerrada por invitación.

Necesitás Para qué
Linux o macOS, amd64 o arm64 Es para lo que se compila la CLI.
Docker con Compose v2 (o un cluster de Kubernetes con Helm) Corre el daemon, Postgres y los MCP. En macOS sirve Colima.
Opcional: una API key de Anthropic y un token de GitHub para los agentes Sin la primera, las corridas fallan al despacharse. Sin el segundo, los agentes sólo leen repos públicos. Se pueden cargar después.

Las imágenes se publican para linux/amd64 y linux/arm64, así que una Mac con Apple Silicon las corre de forma nativa.

Es la forma más corta de ver Thulu andando en tu computadora. El dashboard queda publicado sólo en 127.0.0.1:8585 y se entra con un link que lleva un token.

  1. Instalá el binario. El script detecta tu plataforma, baja la release, verifica el checksum y, si tenés cosign, la firma:

    Ventana de terminal
    curl -fsSL https://github.com/MisterDonnuts/thulu/releases/latest/download/install.sh | sh

    Lo deja en un directorio de tu PATH que se pueda escribir, nunca con sudo. Si no hay ninguno, lo pone en ~/.local/bin e imprime la línea para sumarlo al PATH. --version 0.3.4 instala una release puntual. Si hay una terminal, al final pregunta “¿Configurarlo ahora? (thulu init)”.

  2. Corré el asistente desde cualquier carpeta:

    Ventana de terminal
    thulu init

    Si no estás dentro de un checkout, escribe los archivos de despliegue en ~/.octopus (o en OCTOPUS_HOME). Antes de la primera pregunta revisa la máquina: si Docker responde, si está Compose v2, la arquitectura, si los puertos 8585 y 5433 están libres y el contexto de kubectl. Las preguntas son formularios: flechas para moverte, espacio para marcar y Enter para confirmar. Con -plain pasan a ser texto con opciones numeradas.

  3. En “¿Cómo querés instalar?” dejá la opción por defecto, “Rápida, en esta máquina”: Docker con la imagen publicada, sin login y sólo en 127.0.0.1:8585. Pregunta tres cosas y el resto toma su valor por defecto:

    • Engines: marcá Claude Code y pegá una API key de Anthropic (empieza con sk-ant-api). Enter la saltea y la cargás después en el dashboard. Amazon Bedrock y Google Vertex AI se configuran después, en Configuración → Motores de IA.
    • Runner: dejá “No, los agentes corren en contenedores” (ver Otros flujos).
    • GitHub: el token para que los agentes clonen y pusheen. También se puede saltear.
  4. Revisá el resumen. Muestra la instalación, el acceso, la base de datos, los servidores MCP, los engines y lo que quedó salteado. Nada se escribe antes de este punto. Elegí “Instalar”, “Ver los cambios de deploy/.env y el comando” (muestra el diff, con los secretos recortados, y vuelve a preguntar) o “Cancelar”.

  5. Esperá a que levante. El asistente baja la imagen, detecta el grupo del socket de Docker, levanta Postgres, crea el workspace y la key, arranca el resto del stack y espera a que el daemon responda. El log completo queda en deploy/init.log. Al final imprime el link del dashboard, la key y los próximos pasos:

    Thulu está andando.
    Dashboard http://localhost:8585/?token=…
    sólo 127.0.0.1, sin login: este link es la llave. `thulu open` lo vuelve a abrir.
    Key para la CLI y la API. Se muestra sólo esta vez, guardala:
    oct_…
    Usala con: export OCTOPUS_API_KEY=oct_6b77…
    La key vence el …

    Guardá la key en un gestor de secretos: es la que usa la CLI para hablar con el daemon y no se puede recuperar. Vence a los 90 días, salvo que hayas corrido thulu init con OCTOPUS_API_KEY_MAX_TTL=0 en el entorno. Para otra, thulu keys mint.

  6. Abrí el dashboard con thulu open, o pegando el link del paso anterior. El botón “Configuración inicial” de la barra superior muestra cuántas cosas faltan.

    Panel de Thulu recién instalado: cero tareas, el bloque Primeros pasos, el tablero Principal vacío y el botón Configuración inicial con un número en la barra superior
    Primer acceso a una instalación sin login. El número del botón Configuración inicial son los ítems que todavía faltan.
  7. Completá los pendientes desde “Configuración inicial” (ver más abajo). Para que un agente trabaje hacen falta la key del modelo, un proyecto, un agente y una columna con ese agente. Ningún agente viene instalado.

En “¿Cómo querés instalar?” hay tres modos:

Modo Qué es
“Rápida, en esta máquina” Docker con la imagen publicada, sin login y sólo en 127.0.0.1:8585. Pregunta engines, runner y GitHub.
“Docker personalizado” Elegís cómo se publica, cómo entra la gente, la base de datos y los servidores MCP. Los agentes corren en contenedores de este Docker.
“Kubernetes / k3s” Escribe los values del chart de Helm. Los agentes corren como pods aislados en microVMs (Kata por defecto).

Fuera del modo rápido, el asistente avanza por secciones. Algunas sólo aparecen según lo que respondiste antes.

Sección Qué pregunta Por defecto
¿Cómo entra la gente? “Identidad”: proveedor OIDC, OAuth app de GitHub o “Sin login (sólo local)”. Para OIDC: URL del issuer, Client ID, Client secret, texto del botón, dominios de email permitidos, claim de grupos y mapeo de grupos a roles. “Sin login” en el stack sin dominio; OIDC en el de dominio con HTTPS, donde “Sin login” no se ofrece
Postgres En Docker, si usar el Postgres que trae el stack. Si no, o en Kubernetes, el DSN de una base externa, y prueba si responde. El Postgres del stack
Dirección pública Dominio (sólo el host), las direcciones desde las que se abre el dashboard, la IP del proxy o ingress que tenés adelante y, en el stack sin dominio, la dirección donde escucha. Rechaza un dominio con esquema o ruta y un origen que no sea http(s)://host. Con OIDC u OAuth te da la redirect URI que tenés que registrar en el proveedor. localhost en Docker
Cluster y aislamiento Sólo en Kubernetes: namespace, nombre del release de Helm, aislamiento de los agentes (kata-clh, gvisor o sin RuntimeClass) e imagen de los agentes. Avisa si la RuntimeClass no está instalada. octopus, kata-clh
Servidores MCP para los agentes Un checklist de los MCP nativos (ver abajo). octopus-api, argus-github y argus-browser
Licencia enterprise (opcional) La clave de licencia. Sin ella corre la edición community. En Kubernetes es obligatoria (ver Kubernetes). Se saltea
Primer workspace Nombre del workspace (el slug sale del nombre) y el email del dueño. Con login, también tu email en el proveedor de identidad, para administrar el workspace. Default; sin login, el email de tu git config
Engines Qué CLI corre cada agente y su credencial. Claude Code
Runner en esta máquina Sólo en Docker: si los agentes también pueden correr en esta máquina, fuera de los contenedores. No
GitHub URL de GitHub Enterprise Server si la usás, y el token para que los agentes clonen y pusheen. Se saltea

En Engines la lista también ofrece Codex (con una key de OpenAI) y OpenCode (APIs compatibles con OpenAI). Los dos corren agentes y auditores; los mensajes a un agente mientras trabaja y el runner necesitan Claude Code. Mirá Credenciales y motores.

Dos secretos se generan solos y nunca se preguntan: el que firma las sesiones y el que cifra las credenciales guardadas. Volver a correr thulu init los conserva; si se perdiera el segundo, todas las credenciales guardadas quedarían ilegibles.

En “Docker personalizado” el asistente ofrece dos stacks, los dos con la imagen publicada:

Stack Qué es Cuándo
“Servidor con dominio y HTTPS” (docker-compose.caddy.yml) Daemon, Postgres y Caddy adelante, que saca solo el certificado para tu dominio. Los puertos 80 y 443 tienen que llegar a la máquina. Un servidor con dominio público.
“Sólo en esta máquina, o detrás de tu propio proxy” (docker-compose.standalone.yml) La imagen y Postgres, sin nada adelante, en el puerto 8585. Escucha en 127.0.0.1 salvo que pongas otra dirección. Para probar en tu máquina, o detrás de un reverse proxy tuyo que termine el TLS.

“Sin login” se ofrece sólo en el stack sin dominio, porque ahí el asistente puede dejar el puerto en 127.0.0.1. Si publicás ese stack en otra dirección, el resumen avisa que se sirve HTTP plano y deja pendiente el TLS.

Servidor Qué hace Por defecto
octopus-api El tablero para los agentes: leer y actualizar tareas, comentarios y adjuntos. Actúa con la key propia de la corrida. Marcado
argus-github GitHub: pull requests, commits, ramas, corridas de Actions. Marcado
argus-browser Chromium headless (Playwright): navegar, hacer clic, capturas adjuntas a la tarea. Marcado
argus-cloud Métricas y logs de la nube en sólo lectura (GCP, AWS). Necesita una credencial de nube por entorno. Sin marcar
argus-figma Archivos, frames, renders y comentarios de Figma en sólo lectura. Necesita un token de Figma en Credenciales. Sin marcar

argus-sandbox no está en la lista porque viene dentro del daemon. Cada servidor marcado corre como un contenedor más del stack (en Kubernetes, como un Deployment del chart). Para cambiar la selección, volvé a correr thulu init: el checklist arranca con lo que ya está instalado. Qué tools concede cada servidor a cada agente se decide después, en el dashboard: ver MCPs.

Si desmarcás todos, los agentes sólo tienen las herramientas del sandbox: no pueden comentar en la tarea, ni abrir PRs, ni usar el navegador.

Cómo se entra depende de lo que elegiste en Identidad.

El daemon guarda un token aleatorio. El link http://localhost:8585/?token=… lo cambia por una cookie de sesión que dura 30 días. Para volver a abrirlo:

Ventana de terminal
thulu open

Imprime el link y abre el navegador. Lee el token de deploy/.env, así que corrélo desde la carpeta de la instalación o desde cualquier lugar si la instalación está en ~/.octopus. Si entrás a la dirección sin el token, el dashboard te manda al login con esta indicación:

Tarjeta de Iniciar sesión que dice que la instalación no tiene inicio de sesión y pide abrir el link del daemon o correr thulu open
Sin el token no hay sesión: la página de login indica cómo conseguir el link.

Cualquier pedido con esa cookie se trata como owner. Por eso el puerto queda en 127.0.0.1 y no conviene publicarlo en otra dirección.

La página “Configuración inicial” (/onboarding/) lee el estado real de la instalación y lista lo que falta, qué pasa mientras tanto y dónde se termina. Un ítem que completás a mano después cuenta igual. El botón de la barra superior sólo lo ven los admins y desaparece cuando no queda nada. El Panel muestra los mismos ítems en “Primeros pasos”.

Página Configuración inicial con el workspace tildado y el resto de los ítems pendientes, cada uno con su consecuencia y un link
Una instalación sin login recién hecha. Cada pendiente dice qué pasa mientras tanto y, salvo el de identidad, lleva a la página donde se resuelve.
Ítem Qué falta si no está Dónde se resuelve
Proveedor de identidad Cualquiera que llegue al puerto es owner. Volver a correr thulu init y elegir un proveedor.
Workspace No se puede crear nada. thulu workspace create (ver CLI).
Key del modelo (BYOK) Las corridas fallan al despacharse. Configuración → Motores de IA. Ver Credenciales y motores.
Credencial de git Los agentes sólo leen repos públicos: ni ramas ni PRs. Credenciales o la GitHub App.
Primer proyecto No hay repositorio en el que trabajen los agentes. Proyectos: un repo de GitHub o una carpeta subida.
Definiciones de agentes El tablero no tiene agentes a los que despachar. Agentes, o un JSON desde Workshop → Importar archivo.
Una columna que corre un agente Mover una tarjeta no lanza nada. “Agente por defecto” en el Comportamiento de la columna (Tableros y etapas).
Agentes en la plantilla de cada proyecto Las tareas de ese proyecto nacen sin agente. La “Plantilla de etapas” del proyecto.

Los dos primeros sólo los ve un admin del workspace operador.

  1. Registrá una aplicación en tu proveedor de identidad (Okta, Entra ID, Keycloak, Google…) y anotá el issuer, el Client ID y el Client secret. Si tu proveedor sólo habla SAML, poné adelante un intermediario que hable OIDC, como Keycloak, y usá el issuer de ese intermediario.

  2. Apuntá el DNS del dominio al servidor y dejá que lleguen los puertos 80 y 443.

  3. En el servidor, corré thulu init, elegí “Docker personalizado” y el stack “Servidor con dominio y HTTPS”.

  4. En Identidad elegí el proveedor OIDC. El asistente se conecta al issuer antes de seguir, así un error de tipeo falla en ese momento:

    URL del issuer: ✓ el proveedor responde: login en https://accounts.google.com/o/oauth2/v2/auth
  5. Completá Client ID, Client secret, el texto del botón y los dominios de email permitidos (por ejemplo tuempresa.com). El claim de grupos y el mapeo grupo:rol son opcionales: sin mapeo, cada persona entra con el rol por defecto y a los admins se los promueve a mano.

  6. En Dirección pública poné el dominio, sin https://. El asistente imprime la redirect URI: registrala en el proveedor antes del primer login.

  7. En “Primer workspace” dejá el email del dueño provisorio que propone y, en la pregunta siguiente, poné tu email del proveedor de identidad. Tiene que ser otro: el asistente rechaza el del dueño provisorio.

  8. Terminá el resto como en el flujo recomendado, guardá la key y entrá por https://<dominio> cuando resuelvan el DNS y el certificado.

En Docker, el asistente pregunta si los agentes también pueden correr en tu máquina, fuera de los contenedores, con tu git, tus herramientas y tu sesión de claude. Por ahora el runner corre sólo Claude Code, se configura sólo desde la CLI (no tiene pantalla en el dashboard) y en Kubernetes no se ofrece. Si respondés que sí, elegís las carpetas en las que puede trabajar (cada una tiene que ser un repo git y queda como un proyecto cuyo código no sale de esa máquina) y si dejarlo corriendo como servicio. Ver CLI.

En Kubernetes los agentes corren como pods aislados en microVMs (Kata) y el daemon no toca ningún socket de Docker. Este runtime está validado en un k3s de un solo nodo con Kata. Pide una licencia que incluya kubernetes: sin ella el daemon no arranca. El cluster tiene que estar preparado antes: Kata instalado con su RuntimeClass, los namespaces de tenants y una base Postgres externa (el chart no trae base). La preparación y las variables están en docs/enterprise-setup.md, con la lista para instalaciones sin internet.

Hay dos formas de instalar el chart:

  • Con thulu init, eligiendo “Kubernetes / k3s”. Pregunta lo mismo que en Docker más el namespace, el release y el aislamiento, escribe deploy/values-<release>.yaml y corre helm upgrade --install … --wait --timeout 10m. Ese archivo tiene el secreto JWT, la clave de credenciales y el secreto OIDC en texto plano: dejalo fuera de git.
  • Con helm install directo sobre deploy/helm/octopus, con tus propios values (hay ejemplos en values-production.example.yaml). En ese caso el workspace y la key se crean a mano con la CLI.

Las imágenes de agente publicadas no traen Claude Code: lo instalan desde npm la primera vez. En Kubernetes la instalación construye su propia imagen de agente con Claude Code adentro (un Job de BuildKit, una vez por versión) y hasta que termina los pods lo bajan al arrancar. Sin salida a npm hay que construir la imagen con CLAUDE_CODE_INSTALL=build; los pasos están en docs/enterprise-setup.md. Con los agentes en Kubernetes el token de suscripción de Claude (sk-ant-oat…) queda apagado: usá una API key de Anthropic, Bedrock o Vertex.

thulu init es la forma de cambiar una respuesta: cada pregunta toma como default lo que la instalación ya tiene (de deploy/.env y de deploy/.octopus-init.json, que guarda las respuestas sin secretos). No vuelve a emitir la key si el workspace ya tiene una activa; una vencida no cuenta.

Opción Qué hace
-dry-run Pregunta todo y muestra el resumen sin escribir ni ejecutar nada.
-non-interactive Toma todos los defaults, o las respuestas de la corrida anterior. Para repetir una instalación o en CI.
-plain Preguntas en texto con opciones numeradas, en lugar de formularios.
-stack <archivo> Elige el stack de compose sin preguntarlo.
-root <dir> Dónde vive la instalación. Por defecto se busca hacia arriba desde la carpeta actual, y si no hay ninguna, ~/.octopus.
  • “no se llega desde acá” en la sección Postgres: la configuración se escribe igual, pero el workspace y la key quedan pendientes. El resumen imprime el comando para crearlos desde el contenedor del daemon cuando la base responda (en compose, docker compose -f deploy/<stack>.yml exec octopus ./octopus workspace create … y después … ./octopus keys mint …).
  • Perdiste la key o venció a los 90 días: sólo se guarda su hash. Emití una nueva con thulu keys mint, o desde el contenedor del daemon: docker compose -f deploy/<stack>.yml exec octopus ./octopus keys mint -workspace <id> -role owner -permissions full (más en CLI).
  • La primera corrida tarda más: en Docker, Claude Code se instala desde npm la primera vez que lo usa cada workspace y queda en un volumen. Sin salida a npm hay que construir la imagen de agente con CLAUDE_CODE_INSTALL=build (docs/enterprise-setup.md).
  • Los agentes no tienen acceso al tablero ni a GitHub: revisá que los MCP estén marcados en el checklist y concedidos al agente en MCPs.
  • Después del login con OIDC aparece “Tu cuenta está esperando acceso” y no sos la primera persona: nadie te invitó al workspace. Pedile a un admin que te invite, cerrá sesión y volvé a entrar.