Git y GitHub
Thulu trabaja sobre repos de GitHub. Cada tarea recibe su propia rama, task-<id>, en cada repo que toca, y termina en un pull request por repo. Los agentes hacen los cambios; Thulu publica la rama en GitHub con la credencial del proyecto, que nunca entra al contenedor del agente, y en la tarea te muestra el estado de cada PR. Por default ningún agente mergea ni dispara deploys: un admin decide si se lo concede a un agente, tool por tool.
Funciona con GitHub y GitHub Enterprise Server. Si el código no está en GitHub, el proyecto puede ser una carpeta subida, sin proveedor ni pull requests (ver Proyectos).
Cómo se conecta Thulu a GitHub
Sección titulada «Cómo se conecta Thulu a GitHub»Un proyecto se autentica de una de tres maneras. Las elegís al crearlo, en “Acceso al repositorio”:
| Opción | Qué hace | Cuándo conviene |
|---|---|---|
| “GitHub App” | Thulu pide a GitHub un token de vida corta (alrededor de una hora) para cada operación, limitado al repo del proyecto y a los permisos que esa operación necesita. No guarda nada de larga duración. | Siempre que puedas. En la SaaS la App ya está registrada y sólo tenés que instalarla en tu organización. |
| “Credencial guardada” | Usa un token personal de GitHub guardado en Credenciales. Se valida al guardarlo y se puede rotar o deshabilitar desde ahí. | Self-hosted sin App, o un repo de una cuenta donde no podés instalar la App. |
| “Repo público” | Clona sin credenciales. | Para leer un repo público. Sin credencial, Thulu no puede pushear ni abrir PRs. |
Si un proyecto está vinculado a la App, la App manda: el selector de credencial del proyecto queda deshabilitado y dice “La instalación de la App de arriba es la que clona y pushea. Desvinculala para usar una credencial.”
Flujo recomendado: instalar la App y crear el proyecto
Sección titulada «Flujo recomendado: instalar la App y crear el proyecto»En la SaaS, o en un self-hosted donde el operador ya conectó la App, conectar un repo es esto. Necesitás rol admin en el workspace para crear proyectos e instalar la App, y permiso en GitHub para instalar Apps en la organización (si no lo tenés, GitHub deja pedírselo a un admin).
-
Abrí “Proyectos” en la barra lateral y tocá “Nuevo proyecto” (o la tecla N).
-
En “Acceso al repositorio”, la opción “GitHub App” ya viene elegida. Si no aparece, la App no está conectada en esta instalación: mirá la sección self-hosted más abajo o usá un token. Si la App todavía no está instalada en tu organización, tocá “Conectar GitHub” (con la App ya instalada en alguna organización, el botón dice “Instalar en otra organización”). Thulu te lleva a GitHub, donde elegís la organización, qué repos habilitar (todos o algunos) y confirmás la instalación.
-
GitHub te devuelve a Proyectos con el aviso “GitHub conectado. Elegí un repositorio” y el modal abierto de nuevo, con lo que ya habías escrito. Elegí la organización y el repositorio: el nombre, la URL y la rama por defecto se completan solos.

Al elegir acme/backoffice, el modal completa el nombre, la URL y la rama por defecto (develop) que informa GitHub. -
Escribí una descripción corta (la lee el agente al arrancar), revisá el tablero por defecto y tocá “Crear”. El modal se cierra y Thulu clona el repo en segundo plano con un token de sólo lectura; guarda únicamente el vínculo a la instalación. La tarjeta del proyecto dice “Clonando” hasta que termina.
Desde ese momento, cada tarea que vincule este proyecto trabaja en su propia rama (ver Qué pasa con una tarea). Para que un agente haga el trabajo y abra el PR, la columna tiene que correr un agente que tenga argus-github; eso se arma en Tableros y etapas y Agentes.
Si la conexión falla, el aviso dice por qué: “el link de instalación venció, ya se usó o se abrió en otro navegador”, “esa instalación ya está conectada a otro workspace”, “tu usuario de GitHub no ve esa instalación”, entre otros. Si tu organización exige que un admin apruebe las Apps, vas a ver “Instalación solicitada. Falta que la apruebe el admin de tu organización en GitHub” y el repo aparece recién cuando lo aprueben.
Pasar un proyecto existente a la App
Sección titulada «Pasar un proyecto existente a la App»Si creaste el proyecto con un token o como repo público y después instalaste la App, abrí el proyecto, pestaña “Repositorio”, panel “Acceso a GitHub”. Elegí la instalación en “Instalación de la GitHub App” y tocá “Vincular”: Thulu revisa que la instalación llegue al repositorio antes de guardar. Desde ahí la App manda y el selector de credencial queda deshabilitado. “Desvincular” vuelve a la credencial guardada o al acceso público; la App sigue instalada en GitHub.
Conectar la GitHub App en una instalación self-hosted
Sección titulada «Conectar la GitHub App en una instalación self-hosted»En self-hosted, el operador registra una App propia en GitHub y le pasa sus datos a Thulu. Operador es un owner del workspace que nombra OCTOPUS_OPERATOR_WORKSPACE; thulu init apunta esa variable al primer workspace que crea. Una sola App sirve a todos los workspaces de la instalación. En la SaaS este paso ya está hecho: el panel se ve de sólo lectura y lo único que queda activo es “Instalar en una organización”.
Crear la App en GitHub (recomendado)
Sección titulada «Crear la App en GitHub (recomendado)»En “Configuración” → “Credenciales”, el panel “GitHub App” ofrece “Crear la App en GitHub”. GitHub abre su formulario con los permisos, el webhook y las direcciones de esta instalación ya cargados: elegís la “Organización” (vacía, la App queda en tu cuenta personal), tildás si los agentes van a disparar workflows o aprobar deploys (suma Actions y Deployments en escritura), confirmás el nombre en GitHub y volvés con la App conectada. El nombre que propone es “Thulu” seguido del host de la instalación.
GitHub tiene que llegar a la dirección de la instalación para mandar los webhooks. Si abriste Thulu desde una dirección local o privada, el modal lo avisa: abrilo desde su dirección pública antes de crear la App.
Conectar una App que ya registraste
Sección titulada «Conectar una App que ya registraste»-
En GitHub, registrá una App en tu organización (Settings → Developer settings → GitHub Apps → New GitHub App).
Permisos de repositorio obligatorios: Contents y Pull requests en lectura y escritura, y Actions en lectura. Cada token que Thulu pide para pushear, abrir PRs o leer su estado incluye Actions en lectura; sin ese permiso GitHub rechaza el token. Opcionales: Checks en lectura (para ver todo el CI en la tarea), Actions en escritura si los agentes van a disparar, reintentar o cancelar workflows, y Deployments en escritura sólo si vas a conceder
deployment_approve.Como Setup URL poné
https://<tu-thulu>/github/setupy tildá “Redirect on update”. Si preferís que GitHub identifique a quien instala, activá “Request user authorization (OAuth) during installation”: GitHub deja de usar la Setup URL y vuelve a la Callback URL,https://<tu-thulu>/github/oauth/callback, y en Thulu vas a cargar Client ID y Client secret. Para el webhook,https://<tu-thulu>/github/webhookcon un secreto, suscripto a los eventos que vas a usar (pull request, reviews y comentarios, push, check suite, deployment status). Si la App se va a instalar en otra organización, elegí “Any account” en dónde se puede instalar.Al final, generá una clave privada: GitHub baja un archivo
.pem. -
En Thulu, entrá a “Configuración” → “Credenciales”. El panel “GitHub App” dice “Sin conectar”. Tocá “Conectar una App existente”.

Sin App, cada proyecto usa un token personal de la lista de credenciales. -
Completá “App ID” (está en la configuración de la App, debajo de About) y pegá el
.pemcompleto en “Clave privada”. Si activaste OAuth o el webhook, abrí “OAuth y webhook” y completá “Client ID” y “Client secret” (están en la página de la App en GitHub) o el “Secreto del webhook” que elegiste. Tocá “Verificar y conectar”: Thulu valida contra GitHub que la clave corresponda a ese App ID antes de guardar. Si a la App le falta un permiso obligatorio, el panel lo nombra (“A la App le faltan permisos que Thulu necesita…”); si le falta Checks en lectura, avisa que la sección de pull requests sólo va a ver los checks de GitHub Actions.
El texto de arriba del modal pide Contents y Pull requests en escritura y Actions en lectura. OAuth y webhook son opcionales: el webhook alimenta las automatizaciones y Evidencia con eventos de GitHub y refresca la sección de PRs al instante. -
Con la App conectada, tocá “Instalar en una organización”. GitHub te devuelve a Proyectos con el modal “Nuevo proyecto” abierto, como en el flujo recomendado. Cada instalación aparece en la tabla del panel con su organización, si cubre todos los repos o sólo los elegidos, y su estado.

“Desvincular” corta los tokens de esa instalación en el acto; la App sigue instalada en GitHub.
Si la App se configura por variables de entorno (OCTOPUS_GITHUB_APP_ID, OCTOPUS_GITHUB_APP_PRIVATE_KEY y las demás), el panel lo dice y no deja cambiarla desde la UI. Para GitHub Enterprise Server, el operador apunta OCTOPUS_GITHUB_URL y OCTOPUS_GITHUB_API_URL a su servidor. Los detalles de despliegue están en Operación self-hosted.
Proyecto con un token personal
Sección titulada «Proyecto con un token personal»-
Generá el token en GitHub. Un token clásico necesita el scope
repo, y ademásworkflowsi los agentes van a disparar Actions. -
En “Nuevo proyecto”, elegí “Credencial guardada” y tocá “Nueva credencial…”. Poné un nombre (por ejemplo “GitHub — deploys”), pegá el token en “Token de acceso personal” y tocá “Guardar credencial”. Thulu lo valida contra api.github.com y lo guarda en Credenciales; si GitHub lo rechaza, queda guardado igual con el aviso de que no va a poder clonar.
-
Completá “Nombre”, “URL del repositorio” y, si querés otra que la del repo, “Rama por defecto”, y tocá “Crear”.
Para cambiar la credencial de un proyecto que ya existe, abrilo, andá a la pestaña “Repositorio” y elegí otra en “Acceso a GitHub”. El botón “Administrar” te lleva a Credenciales, donde se crean, rotan y comparten entre proyectos. Ese recorrido está en Credenciales y motores.

Qué pasa con una tarea: rama, worktree y push
Sección titulada «Qué pasa con una tarea: rama, worktree y push»Vos no creás ramas a mano. Esto es lo que hace Thulu con cada tarea que tiene proyectos vinculados:
- Cuando la tarea sale de su primera columna, Thulu trae la última versión de la rama por defecto desde GitHub y crea la rama
task-<id>con un worktree (una copia de trabajo propia) en cada proyecto vinculado. Si no pudo traerla, deja un comentario en la tarea con el commit desde el que arrancó, que puede estar atrasado. - Una tarea con dos repos tiene dos worktrees y termina en dos PR, uno por repo, sobre la misma rama
task-<id>. - Las subtareas trabajan en la rama de la tarea madre y entran en su pull request. En la subtarea, “Rama y PR” dice “Compartida con la tarea madre”.
- “Bifurcar la tarea” (menú “…” de la tarea) saca un worktree nuevo desde la rama de la original. “Clonar la tarea” copia sólo título, descripción, repos y asignaciones, sin rama.
- Una columna con “Pushear la rama” publica la rama en GitHub cuando la corrida termina bien. En el tablero de fábrica, “In progress” la trae activada; corre el agente que le asignes a la tarea (el workspace arranca sin agentes).
Cómo llegan los commits a GitHub depende de dónde corren los agentes. No tenés que configurarlo, pero explica algunos comentarios que vas a ver en la tarea:
Desde 0.3.3, el agente trabaja en su propia copia del repo y usa git como cualquier persona: git commit, git fetch origin && git rebase origin/main y git push. El push llega a Thulu, que mueve la rama de la tarea a lo que mandó el agente y la publica en GitHub antes de devolverle el control, así el agente ya puede abrir el PR. git fetch trae lo que GitHub tiene en main (Thulu lo refresca como mucho cada 20 segundos por proyecto).
Si main avanzó, el agente rebasea y resuelve los conflictos en su copia, y Thulu publica la historia nueva con --force-with-lease. Si la rama de la tarea tiene un commit que la copia del agente no trae, Thulu no lo pisa: no publica ese proyecto y deja un comentario que empieza con “No se pudieron traer a la rama de la tarea los commits del agente…”. El token de GitHub nunca entra al pod del agente ni al sandbox.
El agente ve el .git del worktree en sólo lectura: git log, git diff y git status funcionan, git commit no. Thulu commitea el worktree al final de cada corrida y lo pushea si la columna tiene “Pushear la rama”. Si el agente necesita guardar antes, le pide a Thulu que commitee (tool commit) y que pushee (tool branch_push), y Thulu lo hace con la credencial del proyecto. Sólo deja pushear a la rama de la propia tarea.
El agente ve en su .git todas las ramas del proyecto, incluidas las de otras tareas.
Un commit que toca .github/workflows/ no se puede pushear con la App salvo que el operador active OCTOPUS_GITHUB_ALLOW_WORKFLOW_WRITES=1 y la App tenga el permiso Workflows en escritura: un workflow pusheado corre en los runners con los secretos del repo. Sin esa variable, GitHub rechaza el push y el error la nombra.
Los pull requests de una tarea
Sección titulada «Los pull requests de una tarea»El agente abre el PR con su tool pr_create y la tarea lo registra en el acto (“El agente abrió un PR: …”).

Hay otras dos maneras de que se abra:
- Una columna con “Abrir un pull request” abre el PR de cada repo que todavía no lo tiene cuando una tarea entra a ella. El tablero de fábrica no tiene ninguna columna con esa opción. Para activarla, en el tablero tocá “Editar tablero”, abrí el menú ⋯ de la columna, elegí “Comportamiento” y tildá “Abrir un pull request”; se guarda al tocarla. El detalle está en Tableros y etapas.
- “Forzar PR” hace lo mismo a mano, en cualquier etapa.

Ver el estado
Sección titulada «Ver el estado»Abrí la tarea. En la columna de propiedades, “Rama y PR” muestra la rama (con un botón para copiar el nombre). Los PR tienen su propia sección, “Pull requests”, a todo el ancho de la tarea debajo de la descripción, con una fila por PR. En una subtarea la sección muestra los PR de la tarea madre. La fila resume, de izquierda a derecha: número, título, el CI como pasaron/total (con un ícono que gira mientras corre), el estado del review (ojo: revisión pendiente; tilde: aprobado; alerta: pidieron cambios) y “Listo” cuando está aprobado, el CI pasó y GitHub lo puede mergear. El borde izquierdo toma el color de lo más urgente: rojo si falló el CI, hay conflictos o pidieron cambios.

Al tocar una fila se expande con estos datos:
| Dato | Qué muestra |
|---|---|
| Proyecto | El proyecto de Thulu al que pertenece el PR. |
| Archivos, Líneas, Commits | Cantidad de archivos cambiados, líneas agregadas y quitadas, y commits. |
| Rama | task-<id> → rama base. |
| CI | Cuántos checks pasaron, fallaron y siguen corriendo, sobre el total del último commit. |
| Revisión | “Sin revisión pedida”, “Revisión pendiente”, “Aprobado” o “Pidieron cambios”. |
| Merge | “Se puede mergear”, “Bloqueado por las reglas de la rama”, “Atrasado respecto de la rama base”, “Tiene conflictos con la rama base” o “GitHub todavía no lo calculó”. |
| Actualizado | Cuándo cambió por última vez en GitHub. |

Debajo está “Abrir en GitHub”. Thulu lee estos datos con la credencial del proyecto, los guarda 30 segundos y los vuelve a pedir cada 20 segundos mientras algo se mueve (CI corriendo o review pendiente) y cada minuto si no. Con el webhook de la App activo, un evento de GitHub los refresca antes.
Si el proyecto no tiene credencial, la fila conserva el link al PR y avisa “Este proyecto no tiene credencial de GitHub.” con un link para agregar una. Si la App no tiene el permiso Checks: read, el CI cuenta sólo los jobs de GitHub Actions y la fila lo aclara.
Forzar PR
Sección titulada «Forzar PR»Cuando la tarea tiene rama y ningún PR, “Rama y PR” muestra el botón “Forzar PR”. También está en el menú “…” del panel, que abrís con la tecla punto; con ese menú abierto, la P lo ejecuta. Thulu pushea la rama si hace falta y abre un PR en cada repo vinculado que no tenga uno, con el título de la tarea y, en el cuerpo, la descripción, las notas de los agentes y una línea que dice que lo abrió Thulu desde Forzar PR. Si el agente ya había abierto uno, lo vincula a la tarea.

Un proyecto subido desde una carpeta no pasa por GitHub. Si todos los proyectos de la tarea son subidos, “Forzar PR” no aparece y la fila “Rama y PR” ofrece “Integrar en…”, que lleva la rama de la tarea a la rama que elijas. Está explicado en Proyectos.
Qué puede hacer un agente en GitHub
Sección titulada «Qué puede hacer un agente en GitHub»Los agentes hablan con GitHub por el MCP argus-github. Lo cablea un admin por etapa en el editor del agente (pestaña “MCP”); el detalle de esa pantalla está en MCPs y Agentes. El token se resuelve del lado del servidor en cada llamada: el agente nunca lo ve.
| Se concede con | Qué incluye |
|---|---|
argus-github@read |
Leer PRs, su diff, archivos, comentarios, hilos de review, reviewers y CI; listar labels; ver el estado de la rama; listar workflows y corridas de Actions, sus jobs, logs y artefactos. |
argus-github@write |
Todo lo de read, más commitear y pushear la rama de la tarea, abrir PRs, comentar, revisar, contestar y resolver hilos, manejar labels, reviewers y asignados, editar el PR, y reintentar o cancelar corridas de Actions. Es lo que necesita un agente que implementa. |
| Sólo por nombre | pr_merge (mergear un PR), run_dispatch (disparar un workflow) y deployment_approve (aprobar un deploy que espera revisión). Ningún scope las incluye, ni write. |
Por default ningún agente mergea ni deploya: un admin decide si concede pr_merge o las de deploy, y las marca una por una. Si argus-github no aparece en la pestaña “MCP” del agente, no está habilitado en el workspace: ver MCPs.
Dejar que un agente mergee
Sección titulada «Dejar que un agente mergee»-
Abrí “Agentes”, elegí el agente y entrá a la pestaña “MCP”.
-
En la etapa donde querés que mergee, con argus-github activado, tocá el botón de tools de argus-github. Se abre la lista de 42 tools de esa etapa, agrupadas en Lectura, Escritura y “Deploy · se conceden por nombre”.
-
En el grupo Deploy, tildá
pr_mergey tocá “Listo”. Después, “Guardar” en el editor del agente. La etapa queda conargus-github@write+pr_merge: todo lo de write más esa tool.
Con argus-github tildado en la etapa quedan 39 de 42: las del grupo Deploy no las cubre ningún scope y se marcan una por una.
La casilla de arriba del panel dice “Todas, menos las que se conceden por nombre”: marca todo lo que cubre un scope y deja afuera pr_merge, run_dispatch y deployment_approve.
En una corrida de tarea, el agente mergea con el token de la tarea. En un chat con “Actuar por mí”, pr_merge no se ejecuta enseguida: queda esperando que la persona lo confirme en Thulu, y el daemon lo corre con un token para esa sola llamada (ver Chat).
Deploy por GitHub Actions desde un agente
Sección titulada «Deploy por GitHub Actions desde un agente»Un agente puede disparar un workflow, seguirlo hasta que termine y leer los logs si falla. Hace falta:
-
Un workflow en el repo que acepte disparo manual (
on: workflow_dispatch, con sus inputs si los tiene). Esto se hace en el repo, fuera de Thulu. -
Permiso para Actions: con la App, Actions en escritura; con un token clásico, el scope
workflow. Thulu sólo pideactions:writepara una corrida cuya etapa concederun_dispatch,run_rerunorun_cancel. -
Una etapa (por ejemplo una columna “Deploy” en tu tablero) donde el agente tenga
run_dispatchpor nombre, además de las tools de lectura de Actions. En la pestaña “MCP” del editor del agente, “Plantilla Deploy” concede en esa etapaargus-github@readmásrun_dispatch,run_watchyrun_logs. A mano:argus-github@read+run_dispatch, oargus-github@write+run_dispatchsi también tiene que reintentar. -
En el prompt de esa etapa, qué workflow disparar y con qué inputs. El agente usa
workflow_viewpara leer los inputs,run_dispatchpara dispararlo,run_watchpara esperar el resultado yrun_jobsconrun_logspara diagnosticar una falla.
Con el webhook de la App activo, los entornos de Evidencia pueden escuchar estos deploys (el evento deployment status) y correr los casos grabados después de uno exitoso; ver Evidencia. Y los eventos de GitHub (comentario en el PR, comentario de review, review, PR, push, check suite) pueden arrancar una receta en Automatizaciones.
Problemas comunes
Sección titulada «Problemas comunes»| Lo que ves | Qué pasa y cómo salir |
|---|---|
| “Este proyecto no tiene credencial de GitHub.” en la fila del PR | El proyecto no tiene App ni credencial que pueda leer el repo. Vinculá una en el proyecto → “Repositorio” → “Acceso a GitHub”. Si el proyecto sí está vinculado a la App, mirá si el panel “GitHub App” de Credenciales avisa un permiso que falta (Actions en lectura es obligatorio): agregalo en GitHub y aceptá el permiso nuevo en la instalación. |
| Comentario “No se pudo traer de GitHub la última versión de la rama por defecto…” | El fetch inicial falló (credencial vencida, App suspendida). La rama arrancó de un commit posiblemente viejo. Revisá la conexión y, si hace falta, bifurcá la tarea cuando esté arreglado. |
| Comentario “Falló el push automático de la rama del proyecto…” | GitHub rechazó el push. Si el error nombra OCTOPUS_GITHUB_ALLOW_WORKFLOW_WRITES, el agente tocó un workflow. Si no, revisá la credencial; el agente o vos pueden reintentar con “Forzar PR”. |
| Comentario “No se pudieron traer a la rama de la tarea los commits del agente…” (Kubernetes) | La rama de la tarea tiene un commit que la copia del agente no tiene, por ejemplo porque alguien pusheó a mano o el agente reescribió la historia con un squash. Thulu no publica ese proyecto hasta que el agente traiga ese commit. |
| La fila dice “Sólo GitHub Actions: agregá Checks: read a la GitHub App…” | Aceptá el permiso nuevo en la configuración de la instalación en GitHub. |
| “Falló la conexión con GitHub (esa instalación ya está conectada a otro workspace…)” | Una instalación pertenece a un solo workspace. Pedile al operador que la mueva. |