Saltar al contenido principal
Esta página ofrece ejemplos autocontenidos de environment.yaml para situaciones habituales. Cada ejemplo abarca un aspecto concreto — combínalos para crear tu configuración completa. Para ver una introducción a la sintaxis y los conceptos de environment.yaml, consulta Configuración del entorno. Para conocer los detalles de la sintaxis, consulta la Referencia de YAML.
Secrets: Los ejemplos hacen referencia a secretos mediante $SECRET_NAME. Configúralos en Settings → Secrets antes de usar un ejemplo. Cada ejemplo incluye una sección desplegable de “secreto requerido” en la que se indica exactamente qué secretos debes configurar y qué valores deben tener. Nunca incluyas credenciales directamente en tu environment.yaml.

Referencia rápida: configuraciones más comunes

Las configuraciones más usadas, en un solo lugar. Para ver la lista completa, consulta las secciones siguientes.
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      Ejecuta `pnpm lint` para comprobar si hay errores.
  - name: test
    contents: |
      Ejecuta `pnpm test` para ejecutar la suite completa.
initialize:
  - name: Instalar uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Sincronizar dependencias
    run: uv sync

knowledge:
  - name: lint
    contents: |
      Ejecuta `uv run ruff check .` para comprobar el linting.
  - name: test
    contents: |
      Ejecuta `uv run pytest` para ejecutar la suite completa.
initialize:
  - name: Instalar pnpm
    run: npm install -g pnpm
  - name: Instalar uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Dependencias del frontend
    run: (cd frontend && pnpm install)
  - name: Dependencias del backend
    run: (cd backend && uv sync)

knowledge:
  - name: structure
    contents: |
      - `frontend/` — aplicación React (pnpm)
      - `backend/` — API de Python (uv)
  - name: test
    contents: |
      Frontend: cd frontend && pnpm test
      Backend: cd backend && uv run pytest
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: structure
    contents: |
      Monorepo gestionado con workspaces de pnpm.
      - `packages/web` — frontend en Next.js
      - `packages/api` — backend en Express.js
      - `packages/shared` — utilidades compartidas
  - name: test
    contents: |
      Ejecuta `pnpm test` desde la raíz para todos los paquetes.
      Ejecuta `pnpm --filter web test` para un paquete específico.

Cómo funcionan las capas

Las configuraciones del entorno se aplican en capas. Cada capa se basa en la anterior:
1

De toda la cuenta (Enterprise)

Certificados, proxy, DNS, VPN, firma de commits, configuración regional, límites de recursos, identidad de git, réplicas de APT. Se aplica a todas las organizaciones y todos los repositorios.
2

De toda la organización

entorno de ejecución de lenguajes, configuración del registro del gestor de paquetes, registro de contenedores, herramientas compartidas. Se aplica a todos los repositorios dentro de la organización.
3

Específico del repositorio

Comandos de compilación, instalación de dependencias, comandos de prueba/lint, notas específicas del proyecto para Devin. Se aplica a un único repositorio.
La configuración de toda la cuenta se ejecuta primero, luego la de toda la organización y después la específica del repositorio. Configura cada ejemplo en el ámbito adecuado en Settings.

Referencia de módulos

Utiliza esta tabla para encontrar el ejemplo adecuado para tus necesidades. Cada módulo es independiente — combínalos libremente.
MóduloCapaSección
Certificados de CAEnterpriseCertificado de CA corporativa
Múltiples certificados de CAEnterpriseMúltiples certificados de CA
Proxy HTTP/HTTPSEnterpriseProxy HTTP/HTTPS
Proxy autenticadoEnterpriseProxy autenticado
Certificado de CA + proxyEnterpriseCertificado de CA + proxy (combinado)
VPN (OpenVPN / WireGuard)EnterpriseConexión VPN
DNS personalizadoEnterpriseResolución DNS personalizada
Firma GPG de commitsEnterpriseFirma GPG de commits
Identidad de Git + claves SSHEnterpriseIdentidad de Git y claves SSH
Paquetes del sistemaEnterpriseInstalar paquetes del sistema
Variables de entornoEnterpriseVariables de entorno personalizadas
Configuración regional y zona horariaEnterpriseConfiguración regional y zona horaria
Límites de recursosEnterpriseLímites de recursos (ulimits)
Réplica de APTEnterpriseSustitución de la réplica de APT
Java + MavenOrgJava + Maven con un registro privado
Java + GradleOrgJava + Gradle con un registro privado
Python + pip/uvOrgPython + pip/uv con un registro privado
Python + PoetryOrgPython + Poetry con un registro privado
Node.js + npm (scoped)OrgNode.js + npm con un registro privado de ámbito específico
Node.js + npm (réplica completa)OrgNode.js + npm con una réplica completa de un registro privado
Node.js + pnpmOrgNode.js + pnpm con un registro privado
Node.js + YarnOrgNode.js + Yarn con un registro privado
GoOrgGo con un proxy de módulos privado
.NET + NuGetOrg.NET + NuGet con un feed privado
DockerOrgDocker con un registro privado de contenedores
Rust + CargoOrgRust + Cargo con un registro privado
Ruby + BundlerOrgRuby + Bundler con un servidor privado de gemas
PHP + ComposerOrgPHP + Composer con un registro privado
AWS CodeArtifactOrgActualización del token de AWS CodeArtifact
Proyecto Node.jsRepoProyecto estándar de Node.js
Proyecto PythonRepoProyecto estándar de Python
Proyecto JavaRepoProyecto estándar de Java
Proyecto GoRepoProyecto estándar de Go
Proyecto RustRepoProyecto estándar de Rust
MonorepoRepoMonorepo con múltiples servicios
Monorepo con múltiples JDKRepoMonorepo con múltiples versiones de JDK
Entradas de KnowledgeRepoEntradas enriquecidas de Knowledge
Hooks pre-commitRepoHooks pre-commit

Ejemplos de Enterprise / de toda la cuenta

Estos ejemplos configuran infraestructura a nivel de máquina que se aplica en todas las organizaciones y repositorios. Configúralos en Enterprise Settings (para toda la cuenta) o en Settings > Environment > Organization-wide setup (para toda la organización).

Certificado de CA corporativa

Tu organización usa una autoridad de certificación privada para servicios internos. Devin necesita el certificado raíz para conectarse a registros y herramientas internas mediante HTTPS.
  • CORP_ROOT_CA_B64 — Certificado PEM codificado en base64 de tu CA corporativa. Genéralo con: cat corp-root-ca.crt | base64 -w0
initialize:
  - name: Install corporate CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates

      # Permitir que Node.js confíe en la CA corporativa
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

Varios certificados de CA

Algunas organizaciones tienen distintas CA para diferentes servicios internos (p. ej., una para el registro de artefactos y otra para un servidor Git interno).
  • CA_CERT_REGISTRY_B64 — Certificado PEM codificado en Base64 para la CA del registro de artefactos
  • CA_CERT_GIT_B64 — Certificado PEM codificado en Base64 para la CA del servidor Git
initialize:
  - name: Install corporate CA certificates
    run: |
      # Decodificar e instalar cada certificado
      echo "$CA_CERT_REGISTRY_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/registry-ca.crt > /dev/null
      echo "$CA_CERT_GIT_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/git-ca.crt > /dev/null

      sudo update-ca-certificates

      # Node.js: combinar certificados en un único paquete
      cat /usr/local/share/ca-certificates/registry-ca.crt \
          /usr/local/share/ca-certificates/git-ca.crt \
        > /tmp/corp-ca-bundle.crt
      echo "export NODE_EXTRA_CA_CERTS=/tmp/corp-ca-bundle.crt" \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

Proxy HTTP/HTTPS

Tu organización dirige el tráfico saliente a través de un proxy corporativo.
  • CORP_HTTP_PROXY — URL del proxy HTTP (p. ej., http://proxy.corp.internal:8080)
  • CORP_HTTPS_PROXY — URL del proxy HTTPS (p. ej., http://proxy.corp.internal:8080)
  • CORP_NO_PROXY — Hosts separados por comas para omitir el proxy (p. ej., localhost,127.0.0.1,.corp.internal,10.0.0.0/8)
initialize:
  - name: Configure system-wide HTTP/HTTPS proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"
Configura CORP_NO_PROXY con una lista de hosts, separados por comas, que deben omitir el proxy, como localhost,127.0.0.1,.corp.internal,10.0.0.0/8.

Proxy con autenticación

Si tu proxy requiere un nombre de usuario y una contraseña, incluye las credenciales en la URL del proxy.
  • PROXY_USER — Nombre de usuario de autenticación del proxy
  • PROXY_PASS — Contraseña de autenticación del proxy
  • PROXY_HOST — Nombre de host del proxy (p. ej., proxy.corp.internal)
  • PROXY_PORT — Puerto del proxy (p. ej., 8080)
  • CORP_NO_PROXY — Hosts separados por comas para omitir el proxy
initialize:
  - name: Configure authenticated HTTP/HTTPS proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"
      export https_proxy="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$http_proxy"
      export HTTPS_PROXY="$https_proxy"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"
      git config --global https.proxy "http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"

Certificado de CA + proxy (combinados)

La configuración básica empresarial más común: instalar un certificado de CA corporativo y configurar un proxy de todo el sistema.
  • CORP_ROOT_CA_B64 — Certificado PEM codificado en Base64 de tu CA corporativa
  • CORP_HTTP_PROXY — URL del proxy HTTP
  • CORP_HTTPS_PROXY — URL del proxy HTTPS
  • CORP_NO_PROXY — Hosts separados por comas para omitir el proxy
initialize:
  - name: Install corporate CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

  - name: Configure system-wide proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"

Conexión VPN

Tus registros privados, servidores Git u otros servicios internos solo son accesibles por VPN. Esto debe ejecutarse antes que otros módulos que necesiten acceso de red a recursos internos.
OpenVPN:
  • VPN_CONFIG_B64 — Archivo de configuración de OpenVPN codificado en Base64 (.ovpn). Genéralo con: cat corp.ovpn | base64 -w0
  • VPN_AUTH_USER (opcional) — Nombre de usuario de la VPN, si tu VPN requiere autenticación con nombre de usuario y contraseña
  • VPN_AUTH_PASS (opcional) — Contraseña de la VPN
WireGuard:
  • WG_CONFIG_B64 — Archivo de configuración de WireGuard codificado en Base64. Genéralo con: cat wg0.conf | base64 -w0
initialize:
  - name: Instalar y configurar OpenVPN
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openvpn

      # Escribir la configuración de la VPN
      sudo mkdir -p /etc/openvpn/client
      echo "$VPN_CONFIG_B64" | base64 -d \
        | sudo tee /etc/openvpn/client/corp.conf > /dev/null

      # Si la VPN requiere autenticación con nombre de usuario y contraseña
      if [ -n "${VPN_AUTH_USER:-}" ] && [ -n "${VPN_AUTH_PASS:-}" ]; then
        printf '%s\n%s\n' "$VPN_AUTH_USER" "$VPN_AUTH_PASS" \
          | sudo tee /etc/openvpn/client/auth.txt > /dev/null
        sudo chmod 600 /etc/openvpn/client/auth.txt
        echo "auth-user-pass /etc/openvpn/client/auth.txt" \
          | sudo tee -a /etc/openvpn/client/corp.conf > /dev/null
      fi

      # Iniciar el túnel VPN
      sudo systemctl daemon-reload
      sudo systemctl enable --now openvpn-client@corp

      # Esperar a que el túnel se establezca
      for i in $(seq 1 30); do
        if ip link show tun0 >/dev/null 2>&1; then break; fi
        sleep 1
      done
Para obtener más información sobre la configuración de VPN, consulta Configuración de VPN.

Resolución personalizada de DNS

Tus servicios internos usan nombres DNS privados que no se pueden resolver mediante DNS públicos.
initialize:
  - name: Configurar resolución DNS personalizada
    run: |
      # Agregar nombres de host internos
      cat << 'HOSTS' | sudo tee -a /etc/hosts > /dev/null
      10.0.1.50  nexus.corp.internal
      10.0.1.51  git.corp.internal
      10.0.1.52  artifactory.corp.internal
      HOSTS

      # Opcionalmente, configurar servidores de nombres personalizados
      sudo mkdir -p /etc/systemd/resolved.conf.d
      cat << 'DNS' | sudo tee /etc/systemd/resolved.conf.d/corp.conf > /dev/null
      [Resolve]
      DNS=10.0.0.53 10.0.0.54
      Domains=corp.internal
      DNS
      sudo systemctl restart systemd-resolved || true

Firma de commits con GPG

Tu organización exige que todos los commits de Git estén firmados.
  • GPG_PRIVATE_KEY_B64 — Clave privada de GPG codificada en Base64. Genérala con: gpg --export-secret-keys <key-id> | base64 -w0
initialize:
  - name: Prepare GPG and git signing config
    run: |
      # Permitir que GPG funcione sin un TTY
      echo 'export GPG_TTY=$(tty)' | sudo tee -a /etc/profile.d/gpg.sh > /dev/null

      # Preconfigurar git para firmar commits (clave importada en maintenance)
      git config --global commit.gpgsign true
      git config --global tag.gpgsign true

maintenance:
  - name: Import GPG signing key
    run: |
      echo "$GPG_PRIVATE_KEY_B64" | base64 -d | gpg --batch --import

      # Establecer el ID de la clave de firma
      KEY_ID=$(gpg --list-secret-keys --keyid-format long 2>/dev/null \
        | grep sec | head -1 | awk '{print $2}' | cut -d'/' -f2)
      git config --global user.signingkey "$KEY_ID"

Identidad de Git y claves SSH

Configure la identidad del usuario de Git y las claves SSH para acceder a repositorios privados mediante SSH.
  • GIT_USER_NAME — Nombre del autor de Git (p. ej., Devin AI)
  • GIT_USER_EMAIL — Correo electrónico del autor de Git (p. ej., devin@company.com)
  • SSH_PRIVATE_KEY_B64 — Clave privada de SSH codificada en Base64. Genérela con: cat ~/.ssh/id_ed25519 | base64 -w0
  • SSH_KNOWN_HOSTS_B64 — Lista de hosts conocidos codificada en Base64. Genérela con: ssh-keyscan git.corp.internal | base64 -w0
  • SSH_CONFIG_B64 (opcional) — Archivo de configuración de SSH codificado en Base64 para alias de host personalizados
initialize:
  - name: Prepare SSH directory and git identity
    run: |
      # Establecer identidad de git
      git config --global user.name "$GIT_USER_NAME"
      git config --global user.email "$GIT_USER_EMAIL"

      # Preparar directorio SSH
      mkdir -p ~/.ssh && chmod 700 ~/.ssh

      # Habilitar git-lfs si es necesario
      # git lfs install

maintenance:
  - name: Install SSH keys
    run: |
      # Instalar clave privada SSH (en mantenimiento para que se cargue de nuevo en cada sesión)
      echo "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
      chmod 600 ~/.ssh/id_ed25519

      # Agregar hosts conocidos para tu servidor Git
      echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

      # Opcionalmente, instalar una configuración SSH personalizada
      if [ -n "${SSH_CONFIG_B64:-}" ]; then
        echo "$SSH_CONFIG_B64" | base64 -d > ~/.ssh/config
        chmod 600 ~/.ssh/config
      fi
Genera la entrada de hosts conocidos para tu servidor Git con ssh-keyscan git.corp.internal | base64 -w0.

Instalar paquetes del sistema

Tu proyecto necesita paquetes del sistema que no están en la imagen predeterminada de Devin (p. ej., bibliotecas nativas para el procesamiento de imágenes o la generación de PDF).
initialize:
  - name: Install system packages
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
        libpq-dev \
        libmagickwand-dev \
        poppler-utils \
        ffmpeg

Variables de entorno personalizadas

Configura variables de entorno persistentes que deben estar disponibles en cada sesión. El método recomendado es escribir líneas KEY=VALUE en el archivo $ENVRC. Las variables escritas en $ENVRC se exportan automáticamente para todos los pasos posteriores y para la sesión de Devin (de forma similar a $GITHUB_ENV de GitHub Actions).
initialize:
  - name: Set custom environment variables
    run: |
      echo "CORPORATE_ENV=production" >> $ENVRC
      echo "DEFAULT_REGION=us-east-1" >> $ENVRC
      echo "MAX_RETRIES=3" >> $ENVRC
También puede escribir variables de entorno en scripts ubicados en /etc/profile.d/ para que estén disponibles en todo el sistema:
cat << 'ENVVARS' | sudo tee /etc/profile.d/custom-env.sh > /dev/null
export CORPORATE_ENV=production
export DEFAULT_REGION=us-east-1
ENVVARS
Ambos enfoques funcionan. $ENVRC es más sencillo y se recomienda en la mayoría de los casos.

Configuración regional y zona horaria

Las imágenes base predeterminadas pueden venir con una configuración regional incorrecta. Es necesario configurar la configuración regional y la zona horaria para evitar advertencias de las herramientas de compilación, Java, Python y Git.
initialize:
  - name: Configure locale and timezone
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq locales

      # Generar y establecer la configuración regional
      sudo sed -i 's/^# *en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen
      sudo locale-gen
      sudo update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8

      cat << 'LOCALE' | sudo tee /etc/profile.d/locale.sh > /dev/null
      export LANG="en_US.UTF-8"
      export LC_ALL="en_US.UTF-8"
      LOCALE

      # Establecer la zona horaria
      sudo timedatectl set-timezone UTC 2>/dev/null || \
        sudo ln -sfn /usr/share/zoneinfo/UTC /etc/localtime

Límites de recursos (ulimits)

Las compilaciones de Java, Gradle y Node.js con frecuencia alcanzan el límite predeterminado de 1024 archivos abiertos. Auméntalo para evitar fallos de compilación.
initialize:
  - name: Raise resource limits
    run: |
      cat << 'LIMITS' | sudo tee /etc/security/limits.d/99-devin.conf > /dev/null
      *    soft    nofile    65536
      *    hard    nofile    65536
      *    soft    nproc     65536
      *    hard    nproc     65536
      LIMITS

      # También establecer el máximo del kernel
      echo "fs.file-max = 65536" | sudo tee /etc/sysctl.d/99-devin-filemax.conf > /dev/null
      sudo sysctl -p /etc/sysctl.d/99-devin-filemax.conf 2>/dev/null || true

Sustitución por una réplica APT

En entornos sin conexión o restringidos, reemplaza los orígenes APT predeterminados de Ubuntu por una réplica interna.
  • APT_MIRROR_URL — URL de tu réplica APT interna (p. ej., https://artifactory.example.com/artifactory/ubuntu-remote)
initialize:
  - name: Replace APT sources with internal mirror
    run: |
      # Hacer copia de seguridad de las fuentes originales
      sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

      # Reemplazar todos los espejos de Ubuntu con tu réplica interna
      sudo sed -i "s|http://archive.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
      sudo sed -i "s|http://security.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list

      # Deshabilitar fuentes de terceros que no serán accesibles
      # sudo mv /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/disabled/ 2>/dev/null || true

      sudo apt-get update -qq
Patrones comunes de URL de réplicas de APT:
  • Artifactory: https://artifactory.example.com/artifactory/ubuntu-remote
  • Nexus: https://nexus.example.com/repository/ubuntu-proxy

Ejemplos de toda la organización

Estos ejemplos instalan entornos de ejecución de lenguajes y configuran gestores de paquetes para usar registros privados. Configúralos en Settings > Environment > Organization-wide setup.
Si tu registro privado usa una CA corporativa, asegúrate primero de que el certificado de CA esté instalado a nivel de Enterprise. La configuración a nivel de organización que aparece a continuación asume que la confianza HTTPS ya está establecida.
La configuración de credenciales corresponde a maintenance, no a initialize. Los pasos que escriben secretos (contraseñas del registro, tokens de autenticación) en archivos de configuración deben usar maintenance para que las credenciales se vuelvan a cargar en cada sesión. El archivo de secretos se elimina antes de guardar la imagen de la máquina, por lo que los archivos de configuración escritos durante initialize no tendrán credenciales válidas cuando comiencen las sesiones.

Java + Maven con un repositorio privado

Instala el JDK y configura Maven para que toda la resolución de dependencias pase por tu repositorio privado (p. ej., Artifactory, Nexus).
JDK 17 viene preinstalado en la imagen base de Devin. Omite el paso de instalación que aparece a continuación si el OpenJDK 17 predeterminado es suficiente; solo necesitas instalar Maven y configurar el repositorio.
  • MAVEN_REGISTRY_URL — URL de tu repositorio Maven (p. ej., https://artifactory.example.com/artifactory/maven-virtual)
  • REGISTRY_USER — Nombre de usuario del repositorio
  • REGISTRY_PASS — Contraseña del repositorio o token de API
initialize:
  - name: Install JDK 17
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Maven
    run: |
      MAVEN_VERSION=3.9.9
      curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
        | sudo tar -xz -C /opt
      sudo ln -sf /opt/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/local/bin/mvn

maintenance:
  - name: Configure Maven for private registry
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>private-registry</id>
            <mirrorOf>*</mirrorOf>
            <url>$MAVEN_REGISTRY_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>private-registry</id>
            <username>$REGISTRY_USER</username>
            <password>$REGISTRY_PASS</password>
          </server>
        </servers>
      </settings>
      EOF
Patrones de URL comunes para repositorios Maven:
  • Artifactory: https://artifactory.example.com/artifactory/maven-virtual
  • Nexus: https://nexus.example.com/repository/maven-public
  • Azure Artifacts: https://pkgs.dev.azure.com/org/project/_packaging/feed/maven/v1
  • GitHub Packages: https://maven.pkg.github.com
  • GitLab: https://gitlab.example.com/api/v4/groups/<group-id>/-/packages/maven
  • AWS CodeArtifact: https://<domain>.d.codeartifact.<region>.amazonaws.com/maven/<repo>

Java + Gradle con un registro privado

Instala el JDK y configura Gradle para resolver todas las dependencias desde tu registro privado.
JDK 17 viene preinstalado en la imagen base de Devin. Omite el paso de instalación del JDK si el predeterminado es suficiente.
  • GRADLE_REGISTRY_URL — URL de tu registro de Gradle/Maven
  • REGISTRY_USER — Nombre de usuario del registro
  • REGISTRY_PASS — Contraseña del registro o token de API
initialize:
  - name: Install JDK 17
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Gradle
    run: |
      GRADLE_VERSION=8.12
      curl -fsSL "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
        -o /tmp/gradle.zip
      sudo unzip -qo /tmp/gradle.zip -d /opt
      sudo ln -sf /opt/gradle-${GRADLE_VERSION}/bin/gradle /usr/local/bin/gradle
      rm /tmp/gradle.zip

maintenance:
  - name: Configure Gradle for private registry
    run: |
      mkdir -p ~/.gradle
      cat > ~/.gradle/init.gradle << EOF
      allprojects {
          repositories {
              maven {
                  url "$GRADLE_REGISTRY_URL"
                  credentials {
                      username = "$REGISTRY_USER"
                      password = "$REGISTRY_PASS"
                  }
                  allowInsecureProtocol = false
              }
          }
      }
      EOF

Python + pip/uv con un registro privado

Configura pip y uv para que resuelvan paquetes desde tu registro privado de PyPI (p. ej., Nexus, Artifactory).
  • PYPI_REGISTRY_HOST — Nombre de host de tu registro de PyPI (p. ej., artifactory.example.com/artifactory/api/pypi/pypi-virtual)
  • REGISTRY_USER — Nombre de usuario del registro
  • REGISTRY_PASS — Contraseña del registro o token de API
initialize:
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Configure pip for private registry
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple
      trusted-host = ${PYPI_REGISTRY_HOST}
      EOF

  - name: Configure uv for private registry
    run: |
      # uv respeta pip.conf, pero también puedes configurarlo explícitamente
      echo "export UV_INDEX_URL=https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
Patrones de URL comunes para registros de PyPI:
  • Artifactory: https://artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple
  • Nexus: https://nexus.example.com/repository/pypi-group/simple
  • Azure Artifacts: https://pkgs.dev.azure.com/org/project/_packaging/feed/pypi/simple/
  • GitLab: https://gitlab.example.com/api/v4/groups/<group-id>/-/packages/pypi/simple
  • AWS CodeArtifact: https://<domain>.d.codeartifact.<region>.amazonaws.com/pypi/<repo>/simple

Python + Poetry con un registro privado

Configura Poetry para resolver paquetes desde un registro privado de PyPI.
  • PYPI_REGISTRY_HOST — Nombre de host de tu registro de PyPI
  • REGISTRY_USER — Nombre de usuario del registro
  • REGISTRY_PASS — Contraseña del registro o token de API
initialize:
  - name: Install Poetry
    run: curl -sSL https://install.python-poetry.org | python3 -

maintenance:
  - name: Configure Poetry for private registry
    run: |
      poetry config repositories.private "https://${PYPI_REGISTRY_HOST}/simple"
      poetry config http-basic.private "$REGISTRY_USER" "$REGISTRY_PASS"

      # Opcionalmente, establecer el registro privado como la fuente predeterminada
      # poetry source add --priority=primary private "https://${PYPI_REGISTRY_HOST}/simple"

Node.js + npm con un registro privado para paquetes con ámbito

Configura npm para resolver paquetes con ámbito (p. ej., @myorg/*) desde un registro privado como GitHub Packages, mientras que los paquetes públicos siguen obteniéndose del registro predeterminado de npm.
  • GITHUB_PACKAGES_TOKEN — token de acceso personal o token de GitHub App con ámbito read:packages
maintenance:
  - name: Configure npm scoped registry
    run: |
      npm config set @myorg:registry https://npm.pkg.github.com
      npm config set //npm.pkg.github.com/:_authToken $GITHUB_PACKAGES_TOKEN
Reemplaza @myorg por tu ámbito de npm. URLs habituales de registros privados:
  • GitHub Packages: https://npm.pkg.github.com
  • Artifactory: https://artifactory.example.com/artifactory/api/npm/npm-virtual
  • Nexus: https://nexus.example.com/repository/npm-group
  • GitLab: https://gitlab.example.com/api/v4/packages/npm
  • AWS CodeArtifact: https://<domain>.d.codeartifact.<region>.amazonaws.com/npm/<repo>

Node.js + npm con una réplica completa de un registro privado

Haz que todos los paquetes de npm pasen por tu registro privado (no solo los paquetes con ámbito).
  • NPM_REGISTRY_URL — URL completa de tu registro de npm (p. ej., https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • NPM_REGISTRY_HOST — Solo el nombre de host, sin protocolo (p. ej., artifactory.example.com)
  • REGISTRY_TOKEN — token de autenticación de npm para el registro
maintenance:
  - name: Configurar npm para usar el registro privado
    run: |
      npm config set registry $NPM_REGISTRY_URL
      npm config set //${NPM_REGISTRY_HOST}/:_authToken $REGISTRY_TOKEN
      npm config set strict-ssl true

Node.js + pnpm con un registro privado

Configura pnpm para que resuelva paquetes desde un registro privado.
pnpm está preinstalado en la imagen base de Devin. Puedes omitir el paso de instalación y solo configurar el registro.
  • NPM_REGISTRY_URL — URL completa de tu registro de npm
  • NPM_REGISTRY_HOST — Solo el nombre del host, sin protocolo
  • REGISTRY_TOKEN — token de autenticación de npm para el registro
initialize:
  - name: Install pnpm
    run: npm install -g pnpm

maintenance:
  - name: Configure pnpm for private registry
    run: |
      pnpm config set registry $NPM_REGISTRY_URL
      pnpm config set //${NPM_REGISTRY_HOST}/:_authToken $REGISTRY_TOKEN

Node.js + Yarn con un registro privado

Configura Yarn (Classic v1 o Berry v2+) para resolver paquetes desde un registro privado.
Yarn Classic (v1) viene preinstalado en la imagen base de Devin. Omite el paso de instalación si solo necesitas v1.
  • NPM_REGISTRY_URL — URL completa de tu registro npm/Yarn
  • REGISTRY_TOKEN — Token de autenticación para el registro (solo Berry)
initialize:
  - name: Install Yarn Classic
    run: npm install -g yarn

maintenance:
  - name: Configure Yarn for private registry
    run: |
      yarn config set registry "$NPM_REGISTRY_URL"
      # Para paquetes con ámbito:
      # yarn config set @myorg:registry "https://npm.pkg.github.com"

Usa un proxy privado para módulos de Go

Instala Go y configúralo para resolver los módulos mediante un proxy privado para módulos (p. ej., Athens, Artifactory o un endpoint de GOPROXY).
  • GO_PROXY_URL — URL de tu proxy de módulos de Go (p. ej., https://athens.corp.internal)
  • GIT_TOKEN — token de acceso personal para repositorios privados de Git que alojan módulos de Go
initialize:
  - name: Install Go
    run: |
      GO_VERSION=1.23.5
      ARCH=$(dpkg --print-architecture)
      curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" \
        | sudo tar -xz -C /usr/local
      echo 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"' \
        | sudo tee /etc/profile.d/golang.sh > /dev/null

  - name: Configure Go for private modules
    run: |
      cat << 'GOENV' | sudo tee /etc/profile.d/go-private.sh > /dev/null
      export GOPROXY="$GO_PROXY_URL,direct"
      export GONOSUMCHECK="corp.internal/*,github.com/myorg/*"
      export GOPRIVATE="corp.internal/*,github.com/myorg/*"
      GOENV

maintenance:
  - name: Authenticate Go private modules
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
Patrones comunes de URL de proxy para Go:
  • Artifactory: https://artifactory.example.com/artifactory/go-virtual
  • Nexus: https://nexus.example.com/repository/go-proxy
  • Athens: https://athens.corp.internal

.NET + NuGet con una fuente privada

Instala el SDK de .NET y configura NuGet para resolver paquetes desde una fuente privada (p. ej., Azure Artifacts, Artifactory).
  • NUGET_FEED_URL — URL de tu feed de NuGet (p. ej., https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json)
  • REGISTRY_USER — Nombre de usuario del registro
  • REGISTRY_PASS — Contraseña del registro o token de API
initialize:
  - name: Install .NET SDK
    run: |
      curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh
      chmod +x /tmp/dotnet-install.sh
      sudo /tmp/dotnet-install.sh --channel 8.0 --install-dir /usr/local/dotnet
      echo 'export DOTNET_ROOT=/usr/local/dotnet' \
        | sudo tee /etc/profile.d/dotnet.sh > /dev/null
      echo 'export PATH="$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH"' \
        | sudo tee -a /etc/profile.d/dotnet.sh > /dev/null
      rm /tmp/dotnet-install.sh

maintenance:
  - name: Configure NuGet for private feed
    run: |
      dotnet nuget add source "$NUGET_FEED_URL" \
        --name private-feed \
        --username "$REGISTRY_USER" \
        --password "$REGISTRY_PASS" \
        --store-password-in-clear-text

      # Opcionalmente, deshabilitar la fuente predeterminada de nuget.org
      # dotnet nuget disable source nuget.org
Direcciones URL habituales de feeds de NuGet:
  • Azure Artifacts: https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json
  • Artifactory: https://artifactory.example.com/artifactory/api/nuget/v3/nuget-virtual
  • GitHub Packages: https://nuget.pkg.github.com/myorg/index.json
  • Nexus: https://nexus.example.com/repository/nuget-hosted/index.json

Docker con un registro privado de contenedores

Configura Docker para autenticarse con un registro privado de contenedores.
  • DOCKER_MIRROR_URL (opcional) — URL de tu réplica de Docker Hub (p. ej., https://mirror.corp.internal)
  • DOCKER_REGISTRY_URL — URL de tu registro privado de contenedores (p. ej., registry.corp.internal:5000)
  • DOCKER_REGISTRY_USER — Nombre de usuario del registro
  • DOCKER_REGISTRY_PASS — Contraseña del registro o token de API
initialize:
  - name: Create Docker config directory
    run: sudo mkdir -p /etc/docker

maintenance:
  - name: Configure Docker for private registry
    run: |
      # Configurar la réplica del registro (opcional — enruta las descargas de Docker Hub a través de tu registro)
      cat << EOF | sudo tee /etc/docker/daemon.json > /dev/null
      {
        "registry-mirrors": ["$DOCKER_MIRROR_URL"]
      }
      EOF
      sudo systemctl restart docker || true

      # Iniciar sesión en el registro de contenedores privado
      echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
        --username "$DOCKER_REGISTRY_USER" \
        --password-stdin
URLs comunes de registros de contenedores:
  • Amazon ECR: <account-id>.dkr.ecr.<region>.amazonaws.com
  • Azure Container Registry: <name>.azurecr.io
  • Google Artifact Registry: <region>-docker.pkg.dev
  • GitHub Container Registry: ghcr.io
  • GitLab Container Registry: registry.gitlab.example.com
  • Nexus: https://nexus.example.com:8443
  • JFrog: <name>.jfrog.io

Rust + Cargo con un registro privado

Instala Rust y configura Cargo para resolver crates desde un registro privado.
Rust (a través de rustup) y Cargo están preinstalados en la imagen base de Devin. Omite el paso de instalación si la toolchain estable predeterminada es suficiente: solo necesitas la configuración del registro.
  • CARGO_REGISTRY_INDEX — URL del índice del registro privado (p. ej., sparse+https://cargo.corp.internal/api/v1/crates/)
  • CARGO_REGISTRY_TOKEN — token de autenticación para el registro privado
initialize:
  - name: Install Rust
    run: |
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
        | sh -s -- -y --default-toolchain stable
      echo 'source "$HOME/.cargo/env"' \
        | sudo tee /etc/profile.d/rust.sh > /dev/null

maintenance:
  - name: Configure Cargo for private registry
    run: |
      mkdir -p ~/.cargo
      cat > ~/.cargo/config.toml << EOF
      [registries.private]
      index = "$CARGO_REGISTRY_INDEX"
      token = "$CARGO_REGISTRY_TOKEN"

      [source.crates-io]
      replace-with = "private"

      [source.private]
      registry = "$CARGO_REGISTRY_INDEX"
      EOF
Si solo necesitas agregar un registro privado sin reemplazar crates.io, elimina las secciones [source.crates-io] y [source.private] y usa cargo install --registry private o [dependencies] my-crate = { version = "1.0", registry = "private" } en Cargo.toml.

Ruby + Bundler con un servidor privado de gemas

Instala Ruby y configura Bundler para resolver gemas desde un servidor privado de gemas.
  • GEM_SERVER_URL — URL de tu servidor privado de gemas (p. ej., https://artifactory.example.com/artifactory/api/gems/gems-virtual)
  • REGISTRY_USER — Nombre de usuario del registro
  • REGISTRY_PASS — Contraseña del registro o token de API
initialize:
  - name: Install Ruby
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ruby-full

maintenance:
  - name: Configure Bundler for private gem server
    run: |
      bundle config set mirror.https://rubygems.org "$GEM_SERVER_URL"
      bundle config set "$GEM_SERVER_URL" "$REGISTRY_USER:$REGISTRY_PASS"
Patrones comunes de URL para servidores de gemas:
  • Artifactory: https://artifactory.example.com/artifactory/api/gems/gems-virtual
  • Nexus: https://nexus.example.com/repository/rubygems-proxy
  • Gemfury: https://gem.fury.io/<org>

Actualización del token de AWS CodeArtifact

Los tokens de AWS CodeArtifact vencen después de 12 horas. Usa maintenance para actualizar el token al inicio de cada sesión. Este ejemplo configura npm, pip y Maven para usar CodeArtifact.
awscli viene preinstalado en la imagen base de Devin. Solo necesitas actualizar el token y configurar el registro.
  • AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY — credenciales de IAM con los permisos codeartifact:GetAuthorizationToken y sts:GetServiceBearerToken
  • CA_DOMAIN — El nombre de tu dominio de CodeArtifact
  • CA_DOMAIN_OWNER — ID de la cuenta de AWS propietaria del dominio
  • CA_REGION — Región de AWS (p. ej., us-east-1)
  • CA_NPM_REPO, CA_PYPI_REPO, CA_MAVEN_REPO — Nombres de repositorio para cada ecosistema
maintenance:
  - name: Refresh CodeArtifact auth token
    run: |
      # Obtener un token nuevo (válido por 12 horas)
      export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token \
        --domain $CA_DOMAIN \
        --domain-owner $CA_DOMAIN_OWNER \
        --region $CA_REGION \
        --query authorizationToken \
        --output text)

      CA_ENDPOINT="https://${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com"

      # Configurar npm
      npm config set registry "${CA_ENDPOINT}/npm/${CA_NPM_REPO}/"
      npm config set "//${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com/npm/${CA_NPM_REPO}/:_authToken" "$CODEARTIFACT_AUTH_TOKEN"

      # Configurar pip
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://aws:${CODEARTIFACT_AUTH_TOKEN}@${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com/pypi/${CA_PYPI_REPO}/simple/
      EOF

      # Configurar Maven (opcional)
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <servers>
          <server>
            <id>codeartifact</id>
            <username>aws</username>
            <password>${CODEARTIFACT_AUTH_TOKEN}</password>
          </server>
        </servers>
        <mirrors>
          <mirror>
            <id>codeartifact</id>
            <mirrorOf>*</mirrorOf>
            <url>${CA_ENDPOINT}/maven/${CA_MAVEN_REPO}/</url>
          </mirror>
        </mirrors>
      </settings>
      EOF

PHP + Composer con un registro privado

Instala PHP y configura Composer para resolver paquetes desde un registro privado de Packagist o Satis.
  • COMPOSER_REGISTRY_URL — URL de tu registro privado de Composer (p. ej., https://repo.packagist.com/<org>)
  • REGISTRY_USER — Nombre de usuario del registro
  • REGISTRY_PASS — Contraseña del registro o token de API
initialize:
  - name: Install PHP and Composer
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
        php-cli php-mbstring php-xml php-curl unzip

      # Instalar Composer
      curl -sS https://getcomposer.org/installer | php
      sudo mv composer.phar /usr/local/bin/composer

maintenance:
  - name: Configure Composer for private registry
    run: |
      composer config --global repositories.private \
        composer "$COMPOSER_REGISTRY_URL"

      # Autenticarse con el registry
      composer config --global http-basic.$(echo "$COMPOSER_REGISTRY_URL" \
        | sed 's|https\?://||;s|/.*||') "$REGISTRY_USER" "$REGISTRY_PASS"

      # Opcionalmente, deshabilitar el packagist.org predeterminado
      # composer config --global repositories.packagist false
Patrones de URL comunes del registry de Composer:
  • Artifactory: https://artifactory.example.com/artifactory/api/composer/packagist-virtual
  • Nexus: https://nexus.example.com/repository/packagist-proxy
  • Private Packagist: https://repo.packagist.com/<org>
  • Satis: https://satis.corp.internal

Ejemplos específicos del repositorio

Estos ejemplos configuran pasos de compilación por repositorio, gestión de dependencias y entradas de Knowledge. Configúralos en Settings > Environment > [your repo].

Proyecto estándar de Node.js

Un proyecto típico de Node.js con comandos de lint, pruebas y compilación.
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      Run `pnpm lint` to check for errors.
      Run `pnpm lint --fix` to auto-fix.
  - name: test
    contents: |
      Run `pnpm test` for the full test suite.
      Run `pnpm test -- --watch` during development.
  - name: build
    contents: |
      Run `pnpm build` to create a production build.
      Output goes to the `dist/` directory.

Proyecto estándar de Python

Un proyecto de Python que usa uv para gestionar dependencias.
initialize:
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Sync dependencies
    run: uv sync

knowledge:
  - name: lint
    contents: |
      Run `uv run ruff check .` to lint.
      Run `uv run ruff format .` to format.
  - name: test
    contents: |
      Run `uv run pytest` for the full test suite.
      Run `uv run pytest -x` to stop on first failure.

Proyecto estándar de Java

Un proyecto de Java que usa Maven para gestionar dependencias.
maintenance:
  - name: Resolve dependencies
    run: mvn dependency:resolve -U -q

knowledge:
  - name: build
    contents: |
      Run `mvn clean package` to build.
      Run `mvn clean package -DskipTests` to build without tests.
  - name: test
    contents: |
      Run `mvn test` for unit tests.
      Run `mvn verify` for integration tests.
  - name: lint
    contents: |
      Run `mvn checkstyle:check` for style checks.
      Run `mvn spotbugs:check` for bug detection.

Proyecto estándar de Go

Un proyecto de Go con herramientas habituales.
maintenance:
  - name: Download dependencies
    run: go mod download

knowledge:
  - name: build
    contents: |
      Run `go build ./...` to build all packages.
      Run `go build -o bin/app ./cmd/app` to build the main binary.
  - name: test
    contents: |
      Run `go test ./...` for all tests.
      Run `go test -race ./...` to include race detection.
      Run `go test -v ./pkg/... -run TestSpecific` for a specific test.
  - name: lint
    contents: |
      Run `golangci-lint run` for linting (if installed).
      Run `go vet ./...` for basic static analysis.

Proyecto estándar de Rust

Un proyecto de Rust con Cargo.
maintenance:
  - name: Fetch dependencies
    run: cargo fetch

knowledge:
  - name: build
    contents: |
      Run `cargo build` for a debug build.
      Run `cargo build --release` for a release build.
  - name: test
    contents: |
      Run `cargo test` for all tests.
      Run `cargo test -- --test-threads=1` for sequential execution.
  - name: lint
    contents: |
      Run `cargo clippy -- -D warnings` for lint checks.
      Run `cargo fmt --check` to verify formatting.

Monorepo con múltiples servicios

Un monorepo con servicios de frontend y backend separados, cada uno con un gestor de paquetes distinto.
initialize:
  - name: Install pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Install frontend dependencies
    run: (cd packages/frontend && pnpm install)
  - name: Install backend dependencies
    run: (cd packages/backend && uv sync)
  - name: Build shared library
    run: (cd packages/shared && pnpm install && pnpm build)

knowledge:
  - name: structure
    contents: |
      This is a monorepo with three packages:
      - `packages/frontend` — React app (TypeScript, pnpm)
      - `packages/backend` — Python API (FastAPI, uv)
      - `packages/shared` — Shared TypeScript utilities (must be built before frontend)
  - name: frontend
    contents: |
      Run `cd packages/frontend && pnpm dev` to start the dev server.
      Run `cd packages/frontend && pnpm lint` to lint.
      Run `cd packages/frontend && pnpm test` to test.
  - name: backend
    contents: |
      Run `cd packages/backend && uv run uvicorn app.main:app --reload` to start the API.
      Run `cd packages/backend && uv run ruff check .` to lint.
      Run `cd packages/backend && uv run pytest` to test.
Usa subshells (cd dir && command) en lugar de cd dir && command para que el directorio de trabajo se restablezca entre cada paso.

Monorepo con múltiples versiones de JDK

Un monorepo de Java en el que distintos servicios requieren diferentes versiones de JDK. Instala ambos JDK durante la configuración y luego usa entradas de Knowledge para indicarle a Devin qué JAVA_HOME debe usar para cada servicio.
initialize:
  - name: Install JDK 17 (primary)
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install JDK 11 (legacy service)
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-11-jdk-headless

maintenance:
  - name: Warm dependency caches
    run: |
      export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
      (cd services/api && ./gradlew dependencies --refresh-dependencies)

      export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
      (cd services/legacy && ./gradlew dependencies --refresh-dependencies)

knowledge:
  - name: build_api
    contents: |
      Build the API service (JDK 17):
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        cd services/api && ./gradlew clean build
  - name: build_legacy
    contents: |
      Build the legacy service (JDK 11):
        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        cd services/legacy && ./gradlew clean build
  - name: test_all
    contents: |
      Run tests for all services:
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        (cd services/api && ./gradlew test)

        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        (cd services/legacy && ./gradlew test)

Hooks de pre-commit

Si tu proyecto usa hooks de pre-commit, instálalos en maintenance para que queden listos en cada sesión.
initialize:
  - name: Install pre-commit
    run: pip install pre-commit

maintenance:
  - name: Install pre-commit hooks
    run: pre-commit install --install-hooks
Si el proyecto ya tiene pre-commit como dependencia de desarrollo (p. ej., en pyproject.toml), omite el paso initialize y, en su lugar, usa uv run pre-commit install --install-hooks o pipx run pre-commit install --install-hooks en maintenance.

Entradas detalladas de Knowledge

Documenta la arquitectura, las convenciones y los flujos de trabajo de tu proyecto en entradas de knowledge.
knowledge:
  - name: architecture
    contents: |
      This is a microservices application:
      - `api-gateway/` — Express.js reverse proxy (port 3000)
      - `auth-service/` — JWT authentication service (port 3001)
      - `user-service/` — User CRUD service (port 3002)
      - `shared/` — Shared protobuf definitions and utilities

      Services communicate via gRPC. The API gateway is the only public-facing service.

  - name: conventions
    contents: |
      - All API responses use the `{ data, error, meta }` envelope format
      - Database migrations are in `migrations/` and run with `npm run migrate`
      - Environment-specific config is in `config/{env}.json`
      - Feature flags are managed via LaunchDarkly (SDK key in $LD_SDK_KEY)

  - name: testing
    contents: |
      Unit tests: `npm test`
      Integration tests: `npm run test:integration` (requires Docker for Postgres)
      E2E tests: `npm run test:e2e` (requires all services running)

      Coverage report: `npm run test:coverage` (must be > 80% for CI to pass)

  - name: deployment
    contents: |
      CI/CD runs on GitHub Actions. Merges to `main` auto-deploy to staging.
      Production deploys require a manual approval step in the Actions UI.
      Docker images are pushed to ECR: 123456789.dkr.ecr.us-east-1.amazonaws.com/

Ejemplos combinados

Estos ejemplos muestran cómo se combinan las configuraciones de Enterprise y de la organización. En la práctica, se separarían por ámbitos; aquí se muestran juntas como referencia.

Stack empresarial completo

Un entorno empresarial completo: certificado de CA corporativa, proxy, Java (Maven), Python (pip/uv), Node.js (npm) y Docker, todo configurado para apuntar a una única instancia de Artifactory.
Red y confianza (a nivel de cuenta):
  • CORP_ROOT_CA_B64 — Certificado de CA corporativa codificado en Base64
  • CORP_HTTP_PROXY — URL del proxy HTTP
  • CORP_HTTPS_PROXY — URL del proxy HTTPS
  • CORP_NO_PROXY — Hosts que omiten el proxy
Credenciales del registro (a nivel de organización):
  • ARTIFACTORY_USER — Nombre de usuario de Artifactory
  • ARTIFACTORY_TOKEN — Token de API o contraseña de Artifactory
  • ARTIFACTORY_MAVEN_URL — URL del repositorio de Maven (p. ej., https://artifactory.example.com/artifactory/maven-virtual)
  • ARTIFACTORY_PYPI_URL — URL del repositorio de PyPI (p. ej., https://user:token@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple)
  • ARTIFACTORY_NPM_URL — URL del repositorio de npm (p. ej., https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • ARTIFACTORY_DOCKER_URL — URL del registro de Docker (p. ej., artifactory.example.com)
Normalmente, esto se dividiría en tres ámbitos:
  • A nivel de cuenta (initialize): Certificado y proxy
  • A nivel de organización (initialize): Instalación de entornos de ejecución de lenguajes
  • A nivel de organización (maintenance): Credenciales del registro (se actualizan en cada sesión)
Aquí se muestran combinados como referencia:
initialize:
  # ── Para toda la cuenta: red y confianza ──────────────────────────────────────

  - name: Instalar certificado CA corporativo
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

  - name: Configurar proxy a nivel de sistema
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

  # ── Para toda la organización: entornos de ejecución de lenguajes ──────────────────────────────────────────

  - name: Instalar JDK 17 + Maven
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

      MAVEN_VERSION=3.9.9
      curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
        | sudo tar -xz -C /opt
      sudo ln -sf /opt/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/local/bin/mvn

  - name: Instalar uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  # ── Para toda la cuenta: proxy de git (se actualiza en cada sesión) ───────────────────

  - name: Configurar proxy de git
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"

  # ── Para toda la organización: credenciales de registro (se actualizan en cada sesión) ──────────────

  - name: Configurar Maven → Artifactory
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>artifactory</id>
            <mirrorOf>*</mirrorOf>
            <url>$ARTIFACTORY_MAVEN_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>artifactory</id>
            <username>$ARTIFACTORY_USER</username>
            <password>$ARTIFACTORY_TOKEN</password>
          </server>
        </servers>
      </settings>
      EOF

  - name: Configurar pip/uv → Artifactory PyPI
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = $ARTIFACTORY_PYPI_URL
      trusted-host = $(echo "$ARTIFACTORY_PYPI_URL" | sed 's|https\?://||;s|/.*||')
      EOF

      echo "export UV_INDEX_URL=$ARTIFACTORY_PYPI_URL" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null

  - name: Configurar npm → Artifactory
    run: |
      npm config set registry "$ARTIFACTORY_NPM_URL"
      REGISTRY_HOST=$(echo "$ARTIFACTORY_NPM_URL" | sed 's|https\?://||;s|/.*||')
      npm config set "//${REGISTRY_HOST}/:_authToken" "$ARTIFACTORY_TOKEN"

  - name: Configurar Docker → Artifactory
    run: |
      echo "$ARTIFACTORY_TOKEN" | docker login "$ARTIFACTORY_DOCKER_URL" \
        --username "$ARTIFACTORY_USER" \
        --password-stdin
En este ejemplo, todos los registros apuntan a la misma instancia de Artifactory, pero usan rutas de URL distintas. Cada ecosistema de paquetes tiene su propio formato de endpoint: las URL de Maven, PyPI, npm y Docker son diferentes incluso para el mismo registro.

Varios lenguajes con distintos registros

Cuando distintos lenguajes usan diferentes registros privados (p. ej., Maven desde Nexus, npm desde GitHub Packages y Python desde Artifactory).
  • NEXUS_MAVEN_URL — URL del repositorio Maven de Nexus
  • NEXUS_USER — nombre de usuario de Nexus
  • NEXUS_PASS — contraseña de Nexus
  • GITHUB_PACKAGES_TOKEN — token de acceso personal de GitHub con ámbito read:packages
  • ARTIFACTORY_USER — nombre de usuario de Artifactory
  • ARTIFACTORY_TOKEN — token de API de Artifactory
  • GIT_TOKEN — token de acceso personal para módulos privados de Go
maintenance:
  # Maven → Nexus
  - name: Configurar Maven → Nexus
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>nexus</id>
            <mirrorOf>*</mirrorOf>
            <url>$NEXUS_MAVEN_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>nexus</id>
            <username>$NEXUS_USER</username>
            <password>$NEXUS_PASS</password>
          </server>
        </servers>
      </settings>
      EOF

  # npm → GitHub Packages (con ámbito)
  - name: Configurar npm → GitHub Packages
    run: |
      npm config set @myorg:registry https://npm.pkg.github.com
      npm config set //npm.pkg.github.com/:_authToken $GITHUB_PACKAGES_TOKEN

  # Python → Artifactory
  - name: Configurar pip → Artifactory
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://$ARTIFACTORY_USER:$ARTIFACTORY_TOKEN@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple
      EOF

  # Go → módulos privados vía git
  - name: Configurar módulos privados de Go
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"

Entorno air-gapped con repositorios espejo privados

En un entorno totalmente air-gapped, Devin no puede acceder a ninguna URL pública. Todas las herramientas, los entornos de ejecución y los paquetes deben provenir de repositorios espejo internos.
Certificados:
  • CORP_ROOT_CA_B64 — Certificado de la CA corporativa codificado en Base64
Acceso al repositorio espejo:
  • APT_MIRROR_URL — URL del repositorio espejo APT interno de Ubuntu
  • MIRROR_USER — Nombre de usuario para la autenticación del repositorio espejo
  • MIRROR_PASS — Contraseña para la autenticación del repositorio espejo
  • JDK_TARBALL_URL — URL para descargar el tarball de JDK desde el repositorio espejo interno
  • NODE_TARBALL_URL — URL para descargar el tarball de Node.js desde el repositorio espejo interno
Registros de paquetes:
  • INTERNAL_MAVEN_URL — URL del registro interno de Maven
  • INTERNAL_NPM_URL — URL del registro interno de npm
  • INTERNAL_PYPI_URL — URL del registro interno de PyPI
initialize:
  - name: Install corporate CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates

  - name: Replace apt sources with internal mirror
    run: |
      sudo sed -i "s|http://archive.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
      sudo sed -i "s|http://security.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
      sudo apt-get update -qq

  - name: Install JDK from internal mirror
    run: |
      # Descargar el tarball de JDK desde el almacén de artefactos interno
      curl -fsSL -u "$MIRROR_USER:$MIRROR_PASS" "$JDK_TARBALL_URL" \
        | sudo tar -xz -C /usr/local
      sudo ln -sf /usr/local/jdk-17.*/bin/java /usr/local/bin/java
      sudo ln -sf /usr/local/jdk-17.*/bin/javac /usr/local/bin/javac
      echo "export JAVA_HOME=$(ls -d /usr/local/jdk-17.*)" \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Node.js from internal mirror
    run: |
      curl -fsSL -u "$MIRROR_USER:$MIRROR_PASS" "$NODE_TARBALL_URL" \
        | sudo tar -xz -C /usr/local --strip-components=1

maintenance:
  - name: Configure all package managers for internal registry
    run: |
      # Maven
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>internal</id>
            <mirrorOf>*</mirrorOf>
            <url>$INTERNAL_MAVEN_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>internal</id>
            <username>$MIRROR_USER</username>
            <password>$MIRROR_PASS</password>
          </server>
        </servers>
      </settings>
      EOF

      # npm
      npm config set registry "$INTERNAL_NPM_URL"

      # pip
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = $INTERNAL_PYPI_URL
      EOF
En entornos aislados de Internet, todas las herramientas que Devin necesita (entornos de ejecución de lenguajes, herramientas de línea de comandos, etc.) deben estar disponibles en sus mirrors internos. No se podrá acceder a repositorios públicos ni a sitios de descarga.

VPN + certificados + proxy + idiomas

Una configuración empresarial integral que combina conectividad VPN con certificados, proxy y compatibilidad con varios idiomas. Este es el orden de operaciones recomendado.
VPN:
  • VPN_CONFIG_B64 — Archivo de configuración de OpenVPN codificado en Base64
Red y confianza:
  • CORP_ROOT_CA_B64 — Certificado de CA corporativa codificado en Base64
  • CORP_HTTP_PROXY — URL del proxy HTTP
  • CORP_HTTPS_PROXY — URL del proxy HTTPS
  • CORP_NO_PROXY — Hosts que omiten el proxy
Credenciales del registro:
  • MAVEN_REGISTRY_URL — URL del registro de Maven
  • NPM_REGISTRY_URL — URL del registro de npm
  • PYPI_REGISTRY_HOST — Nombre de host del registro de PyPI
  • REGISTRY_USER — Nombre de usuario del registro (para Maven y pip)
  • REGISTRY_PASS — Contraseña del registro (para Maven y pip)
  • REGISTRY_TOKEN — Token de autenticación de npm
initialize:
  # 1. VPN — debe ir primero para que los recursos internos sean accesibles
  - name: Establish VPN connection
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openvpn
      sudo mkdir -p /etc/openvpn/client
      echo "$VPN_CONFIG_B64" | base64 -d \
        | sudo tee /etc/openvpn/client/corp.conf > /dev/null
      sudo systemctl daemon-reload
      sudo systemctl enable --now openvpn-client@corp
      for i in $(seq 1 30); do
        if ip link show tun0 >/dev/null 2>&1; then break; fi
        sleep 1
      done

  # 2. DNS — resolver nombres de host internos
  - name: Configure DNS
    run: |
      sudo mkdir -p /etc/systemd/resolved.conf.d
      cat << 'DNS' | sudo tee /etc/systemd/resolved.conf.d/corp.conf > /dev/null
      [Resolve]
      DNS=10.0.0.53
      Domains=corp.internal
      DNS
      sudo systemctl restart systemd-resolved || true

  # 3. Certificados — confiar en las CAs internas
  - name: Install CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

  # 4. Proxy — enrutar el tráfico a través del proxy corporativo
  - name: Configure proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

  # 5. Entornos de ejecución
  - name: Install JDK 17
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Node.js tooling
    run: npm install -g pnpm

  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"

  - name: Configure Maven
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>corp</id>
            <mirrorOf>*</mirrorOf>
            <url>$MAVEN_REGISTRY_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>corp</id>
            <username>$REGISTRY_USER</username>
            <password>$REGISTRY_PASS</password>
          </server>
        </servers>
      </settings>
      EOF

  - name: Configure npm
    run: |
      npm config set registry "$NPM_REGISTRY_URL"
      NPM_HOST=$(echo "$NPM_REGISTRY_URL" | sed 's|https\?://||;s|/.*||')
      npm config set "//${NPM_HOST}/:_authToken" "$REGISTRY_TOKEN"

  - name: Configure pip/uv
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple
      EOF
      echo "export UV_INDEX_URL=https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
El orden de los pasos de initialize importa. La VPN debe ir primero (para que se pueda acceder a los hosts internos), luego DNS (para que los nombres se resuelvan), después los certificados (para que HTTPS funcione), luego el proxy (para que el tráfico se enrute correctamente) y, por último, los entornos de ejecución (que pueden descargar desde réplicas internas).

Consejos para escribir buenas configuraciones

  • Prueba primero los comandos en una sesión — ejecuta los comandos manualmente en una sesión de Devin antes de agregarlos a tu configuración. Es más rápido que esperar un ciclo completo de compilación.
  • Usa initialize para herramientas que se instalan una sola vez y maintenance para las dependencias — todo lo que tarde minutos en instalarse (compiladores, binarios grandes, herramientas globales) debe ir en initialize. Los comandos rápidos de dependencias (npm install, uv sync) van en maintenance.
  • Mantén rápidos los comandos de maintenance — intenta que tarden menos de 2 minutos. Se ejecutan al inicio de cada sesión.
  • Usa $ENVRC para las variables de entorno — no escribas en .bashrc ni en .profile. $ENVRC es el mecanismo admitido para establecer variables entre pasos y sesiones.
  • Pon nombre a tus pasos — la forma expandida con campos name hace que los fallos en los registros de compilación sean mucho más fáciles de identificar.
  • Usa subshells para monorepos(cd packages/foo && npm install) se ejecuta en una subshell para que los pasos posteriores no se vean afectados por el cambio de directorio.
Para obtener más información sobre la sintaxis y los detalles de ejecución, consulta la referencia de YAML. Para solucionar fallos de compilación, consulta Solución de problemas y preguntas frecuentes.