Vai al contenuto principale
Questa pagina fornisce esempi autonomi di environment.yaml per scenari comuni. Ogni esempio copre un singolo aspetto — combinali per creare la configurazione completa. Per un’introduzione alla sintassi e ai concetti di environment.yaml, consulta Configurazione dell’ambiente. Per i dettagli sulla sintassi, consulta il Riferimento YAML.
Segreti: Gli esempi fanno riferimento ai segreti tramite $SECRET_NAME. Configurali in Settings → Secrets prima di usare un esempio. Ogni esempio include una sezione comprimibile “Segreti richiesti” che elenca esattamente quali segreti configurare e quali valori devono avere. Non inserire mai credenziali direttamente nel tuo environment.yaml.

Riferimento rapido: configurazioni più comuni

Le configurazioni usate più spesso, tutte in un unico posto. Per l’elenco completo, consulta le sezioni seguenti.
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      Esegui `pnpm lint` per verificare eventuali errori.
  - name: test
    contents: |
      Esegui `pnpm test` per l'intera suite.
initialize:
  - name: Installa uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Sincronizza le dipendenze
    run: uv sync

knowledge:
  - name: lint
    contents: |
      Esegui `uv run ruff check .` per il linting.
  - name: test
    contents: |
      Esegui `uv run pytest` per l'intera suite.
initialize:
  - name: Installa pnpm
    run: npm install -g pnpm
  - name: Installa uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

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

knowledge:
  - name: structure
    contents: |
      - `frontend/` — app React (pnpm)
      - `backend/` — API 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 gestito con i workspace di pnpm.
      - `packages/web` — frontend Next.js
      - `packages/api` — backend Express.js
      - `packages/shared` — utilità condivise
  - name: test
    contents: |
      Esegui `pnpm test` dalla root per tutti i package.
      Esegui `pnpm --filter web test` per un package specifico.

Come funzionano i livelli

Le configurazioni dell’ambiente vengono applicate a livelli. Ogni livello si basa sul precedente:
1

A livello di account (Enterprise)

Certificati, proxy, DNS, VPN, firma dei commit, impostazioni locali, limiti delle risorse, identità git, mirror APT. Si applica a tutte le org e a tutti i repo.
2

A livello di org

Runtime dei linguaggi, configurazione del registry del package manager, container registry, strumenti condivisi. Si applica a tutti i repo all’interno dell’org.
3

Specifico per repo

Comandi di build, installazione delle dipendenze, comandi di test/lint, note specifiche del progetto per Devin. Si applica a una singola repo.
L’esecuzione a livello di account avviene per prima, poi quella a livello di org e infine quella specifica per repo. Configura ciascun esempio nell’ambito appropriato in Settings.

Riferimento dei moduli

Usa questa tabella per trovare l’esempio giusto per le tue esigenze. Ogni modulo è indipendente — combinali liberamente.
ModuloLivelloSezione
Certificati CAEnterpriseCertificato CA aziendale
Certificati CA multipliEnterpriseCertificati CA multipli
Proxy HTTP/HTTPSEnterpriseProxy HTTP/HTTPS
Proxy autenticatoEnterpriseProxy autenticato
Certificato CA + proxyEnterpriseCertificato CA + proxy (combinati)
VPN (OpenVPN / WireGuard)EnterpriseConnessione VPN
DNS personalizzatoEnterpriseRisoluzione DNS personalizzata
Firma dei commit GPGEnterpriseFirma dei commit GPG
Identità Git + chiavi SSHEnterpriseIdentità Git e chiavi SSH
Pacchetti di sistemaEnterpriseInstallare pacchetti di sistema
Variabili d’ambienteEnterpriseVariabili d’ambiente personalizzate
Locale e fuso orarioEnterpriseLocale e fuso orario
Limiti delle risorseEnterpriseLimiti delle risorse (ulimits)
Mirror APTEnterpriseSostituzione del mirror APT
Java + MavenorgJava + Maven con un registry privato
Java + GradleorgJava + Gradle con un registry privato
Python + pip/uvorgPython + pip/uv con un registry privato
Python + PoetryorgPython + Poetry con un registry privato
Node.js + npm (con ambito)orgNode.js + npm con un registry privato con ambito specifico
Node.js + npm (mirror completo)orgNode.js + npm con un mirror completo del registry privato
Node.js + pnpmorgNode.js + pnpm con un registry privato
Node.js + YarnorgNode.js + Yarn con un registry privato
GoorgGo con un proxy di moduli privato
.NET + NuGetorg.NET + NuGet con un feed privato
DockerorgDocker con un container registry privato
Rust + CargoorgRust + Cargo con un registry privato
Ruby + BundlerorgRuby + Bundler con un server privato di gem
PHP + ComposerorgPHP + Composer con un registry privato
AWS CodeArtifactorgRinnovo del token AWS CodeArtifact
Progetto Node.jsrepoProgetto Node.js standard
Progetto PythonrepoProgetto Python standard
Progetto JavarepoProgetto Java standard
Progetto GorepoProgetto Go standard
Progetto RustrepoProgetto Rust standard
MonoreporepoMonorepo con più servizi
Monorepo multi-JDKrepoMonorepo con più versioni di JDK
Voci di KnowledgerepoVoci di Knowledge avanzate
Hook pre-commitrepoHook pre-commit

Esempi Enterprise / a livello di account

Questi esempi configurano un’infrastruttura a livello di macchina che si applica a tutte le org e repo. Impostali in Enterprise Settings (a livello di account) oppure in Settings > Environment > Organization-wide setup (a livello di org).

Certificato CA aziendale

La tua organizzazione utilizza un’autorità di certificazione privata per i servizi interni. Devin ha bisogno del certificato radice per raggiungere registry e strumenti interni tramite HTTPS.
  • CORP_ROOT_CA_B64 — Certificato PEM codificato in base64 della tua CA aziendale. Genera 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

      # Let Node.js trust the corporate CA
      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

Certificati CA multipli

Alcune organizzazioni usano CA separate per diversi servizi interni (ad esempio, una per l’artifact registry e un’altra per un server Git interno).
  • CA_CERT_REGISTRY_B64 — Certificato PEM codificato in Base64 per la CA dell’artifact registry
  • CA_CERT_GIT_B64 — Certificato PEM codificato in Base64 per la CA del server Git
initialize:
  - name: Install corporate CA certificates
    run: |
      # Decodifica e installa ogni certificato
      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: combina i certificati in un unico bundle
      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

La tua organizzazione instrada il traffico in uscita tramite un proxy aziendale.
  • CORP_HTTP_PROXY — URL del proxy HTTP (ad es., http://proxy.corp.internal:8080)
  • CORP_HTTPS_PROXY — URL del proxy HTTPS (ad es., http://proxy.corp.internal:8080)
  • CORP_NO_PROXY — Host separati da virgole per bypassare il proxy (ad es., 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"
Imposta CORP_NO_PROXY su un elenco di host, separati da virgole, che devono ignorare il proxy, ad esempio localhost,127.0.0.1,.corp.internal,10.0.0.0/8.

Proxy autenticato

Se il proxy richiede un nome utente e una password, inserisci le credenziali nell’URL del proxy.
  • PROXY_USER — Nome utente per l’autenticazione del proxy
  • PROXY_PASS — Password per l’autenticazione del proxy
  • PROXY_HOST — Nome host del proxy (ad es. proxy.corp.internal)
  • PROXY_PORT — Porta del proxy (ad es. 8080)
  • CORP_NO_PROXY — Host separati da virgole da escludere dal 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"

Certificato CA + proxy (combinati)

La configurazione di base Enterprise più comune: installare un certificato CA aziendale e configurare un proxy a livello di sistema.
  • CORP_ROOT_CA_B64 — Certificato PEM con codifica Base64 della CA aziendale
  • CORP_HTTP_PROXY — URL del proxy HTTP
  • CORP_HTTPS_PROXY — URL del proxy HTTPS
  • CORP_NO_PROXY — Host separati da virgole per bypassare il 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"

Connessione VPN

I registry privati, i server Git o altri servizi interni sono raggiungibili solo tramite VPN. Questo modulo deve essere eseguito prima degli altri moduli che richiedono accesso di rete alle risorse interne.
OpenVPN:
  • VPN_CONFIG_B64 — File di configurazione OpenVPN (.ovpn) codificato in Base64. Genera con: cat corp.ovpn | base64 -w0
  • VPN_AUTH_USER (opzionale) — Nome utente VPN, se la VPN richiede l’autenticazione con nome utente/password
  • VPN_AUTH_PASS (opzionale) — Password VPN
WireGuard:
  • WG_CONFIG_B64 — File di configurazione WireGuard codificato in Base64. Genera con: cat wg0.conf | base64 -w0
initialize:
  - name: Installa e configura OpenVPN
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openvpn

      # Scrivi la configurazione VPN
      sudo mkdir -p /etc/openvpn/client
      echo "$VPN_CONFIG_B64" | base64 -d \
        | sudo tee /etc/openvpn/client/corp.conf > /dev/null

      # Se la VPN richiede autenticazione con nome utente/password
      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

      # Avvia il tunnel VPN
      sudo systemctl daemon-reload
      sudo systemctl enable --now openvpn-client@corp

      # Attendi che il tunnel sia attivo
      for i in $(seq 1 30); do
        if ip link show tun0 >/dev/null 2>&1; then break; fi
        sleep 1
      done
Per maggiori dettagli sulla configurazione della VPN, consulta Configurazione VPN.

Risoluzione DNS personalizzata

I tuoi servizi interni usano nomi DNS privati che non possono essere risolti dal DNS pubblico.
initialize:
  - name: Configure custom DNS resolution
    run: |
      # Aggiungi hostname interni
      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

      # Configura facoltativamente nameserver personalizzati
      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 dei commit con GPG

La tua organizzazione richiede che tutti i commit Git siano firmati.
  • GPG_PRIVATE_KEY_B64 — Chiave privata GPG codificata in Base64. Generala con: gpg --export-secret-keys <key-id> | base64 -w0
initialize:
  - name: Prepare GPG and git signing config
    run: |
      # Consenti a GPG di funzionare senza un TTY
      echo 'export GPG_TTY=$(tty)' | sudo tee -a /etc/profile.d/gpg.sh > /dev/null

      # Pre-configura git per firmare i commit (chiave importata in 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

      # Imposta l'ID della chiave di 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"

Identità Git e chiavi SSH

Configura l’identità utente di Git e le chiavi SSH per accedere ai repository privati tramite SSH.
  • GIT_USER_NAME — Nome dell’autore Git (ad es. Devin AI)
  • GIT_USER_EMAIL — Email dell’autore Git (ad es. devin@company.com)
  • SSH_PRIVATE_KEY_B64 — Chiave privata SSH codificata in Base64. Genera con: cat ~/.ssh/id_ed25519 | base64 -w0
  • SSH_KNOWN_HOSTS_B64 — Host noti codificati in Base64. Genera con: ssh-keyscan git.corp.internal | base64 -w0
  • SSH_CONFIG_B64 (facoltativo) — File di configurazione SSH codificato in Base64 per alias host personalizzati
initialize:
  - name: Prepare SSH directory and git identity
    run: |
      # Imposta l'identità git
      git config --global user.name "$GIT_USER_NAME"
      git config --global user.email "$GIT_USER_EMAIL"

      # Prepara la directory SSH
      mkdir -p ~/.ssh && chmod 700 ~/.ssh

      # Abilita git-lfs se necessario
      # git lfs install

maintenance:
  - name: Install SSH keys
    run: |
      # Installa la chiave privata SSH (in maintenance così viene ricaricata a ogni session)
      echo "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
      chmod 600 ~/.ssh/id_ed25519

      # Aggiungi gli host noti per il tuo server Git
      echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

      # Facoltativamente, installa una configurazione SSH personalizzata
      if [ -n "${SSH_CONFIG_B64:-}" ]; then
        echo "$SSH_CONFIG_B64" | base64 -d > ~/.ssh/config
        chmod 600 ~/.ssh/config
      fi
Genera la voce known_hosts per il tuo server Git con ssh-keyscan git.corp.internal | base64 -w0.

Installa pacchetti di sistema

Il progetto richiede pacchetti a livello di sistema non inclusi nell’immagine Devin predefinita (ad es., librerie native per l’elaborazione delle immagini o la generazione di 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

Variabili d’ambiente personalizzate

Imposta variabili d’ambiente persistenti da rendere disponibili in ogni sessione. L’approccio consigliato consiste nello scrivere righe KEY=VALUE nel file $ENVRC. Le variabili scritte in $ENVRC vengono esportate automaticamente per tutti i passaggi successivi e per la sessione di Devin (in modo analogo a $GITHUB_ENV di 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
Puoi anche scrivere le variabili d’ambiente negli script in /etc/profile.d/ per renderle disponibili a livello di sistema:
cat << 'ENVVARS' | sudo tee /etc/profile.d/custom-env.sh > /dev/null
export CORPORATE_ENV=production
export DEFAULT_REGION=us-east-1
ENVVARS
Entrambi gli approcci funzionano. $ENVRC è più semplice ed è consigliato nella maggior parte dei casi.

Locale e fuso orario

Le immagini di base predefinite possono avere configurazioni del locale non corrette. Configura il locale e il fuso orario per evitare avvisi dagli strumenti di build, da Java, Python e 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

      # Genera e imposta il locale
      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

      # Imposta il fuso orario
      sudo timedatectl set-timezone UTC 2>/dev/null || \
        sudo ln -sfn /usr/share/zoneinfo/UTC /etc/localtime

Limiti delle risorse (ulimits)

Le build di Java, Gradle e Node.js si scontrano spesso con il limite predefinito di 1024 file aperti. Aumentalo per evitare il fallimento della build.
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

      # Imposta anche il massimo 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

Sostituzione del mirror APT

Negli ambienti isolati o con restrizioni, sostituisci le sorgenti APT predefinite di Ubuntu con un mirror interno.
  • APT_MIRROR_URL — URL del mirror APT interno (ad es. https://artifactory.example.com/artifactory/ubuntu-remote)
initialize:
  - name: Replace APT sources with internal mirror
    run: |
      # Backup delle sorgenti originali
      sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

      # Sostituisci tutti i mirror Ubuntu con il mirror interno
      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

      # Disabilita le sorgenti di terze parti non raggiungibili
      # sudo mv /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/disabled/ 2>/dev/null || true

      sudo apt-get update -qq
Schemi URL comuni per i mirror APT:
  • Artifactory: https://artifactory.example.com/artifactory/ubuntu-remote
  • Nexus: https://nexus.example.com/repository/ubuntu-proxy

Esempi a livello di org

Questi esempi installano i runtime dei linguaggi e configurano i package manager per usare registry privati. Impostali in Settings > Environment > Organization-wide setup.
Se il tuo registry privato usa una CA aziendale, assicurati prima che il certificato della CA sia installato a livello enterprise. La configurazione a livello di org riportata di seguito presuppone che l’attendibilità HTTPS sia già stata stabilita.
La configurazione delle credenziali va in maintenance, non in initialize. I passaggi che scrivono segreti (password del registry, token di autenticazione) nei file di configurazione devono usare maintenance, così le credenziali vengono caricate nuovamente a ogni sessione. Il file dei segreti viene rimosso prima che l’immagine della macchina venga salvata, quindi i file di configurazione scritti durante initialize non avranno credenziali valide quando le sessioni iniziano.

Java + Maven con un registry privato

Installa il JDK e configura Maven in modo che tutta la risoluzione delle dipendenze passi attraverso il tuo registry privato (ad esempio, Artifactory, Nexus).
JDK 17 è preinstallato nell’immagine di base di Devin. Salta il passaggio di installazione seguente se l’OpenJDK 17 predefinito è sufficiente: ti servono solo l’installazione di Maven e la configurazione del registry.
  • MAVEN_REGISTRY_URL — URL del tuo registry Maven (ad esempio, https://artifactory.example.com/artifactory/maven-virtual)
  • REGISTRY_USER — Nome utente del registry
  • REGISTRY_PASS — Password del registry o token 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
Pattern URL comuni del registro per 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 registry privato

Installa il JDK e configura Gradle in modo che risolva tutte le dipendenze tramite il tuo registry privato.
JDK 17 è preinstallato nell’immagine di base di Devin. Salta il passaggio di installazione del JDK se quello predefinito è sufficiente.
  • GRADLE_REGISTRY_URL — URL del tuo registry Gradle/Maven
  • REGISTRY_USER — Nome utente del registry
  • REGISTRY_PASS — Password del registry o token 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 registry privato

Configura pip e uv per recuperare i pacchetti dal tuo registry PyPI privato (ad esempio, Nexus, Artifactory).
  • PYPI_REGISTRY_HOST — Nome host del tuo registry PyPI (ad esempio, artifactory.example.com/artifactory/api/pypi/pypi-virtual)
  • REGISTRY_USER — Nome utente del registry
  • REGISTRY_PASS — Password del registry o token 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 rispetta pip.conf, ma puoi anche impostarlo esplicitamente
      echo "export UV_INDEX_URL=https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
Pattern URL comuni del registro per 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 registry privato

Configura Poetry per recuperare i pacchetti da un registry PyPI privato.
  • PYPI_REGISTRY_HOST — Hostname del tuo registry PyPI
  • REGISTRY_USER — Nome utente del registry
  • REGISTRY_PASS — Password del registry o token 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"

      # Facoltativamente, imposta il registry privato come sorgente predefinita
      # poetry source add --priority=primary private "https://${PYPI_REGISTRY_HOST}/simple"

Node.js + npm con un registry privato per ambito

Configura npm in modo che recuperi i pacchetti con ambito (ad esempio @myorg/*) da un registry privato come GitHub Packages, mentre i pacchetti pubblici continuano a provenire dal registry npm predefinito.
  • GITHUB_PACKAGES_TOKEN — Token di accesso personale o token GitHub App con ambito 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
Sostituisci @myorg con il tuo ambito npm. URL comuni per i registry privati:
  • 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 un mirror completo del registry privato

Instrada tutti i pacchetti npm tramite il tuo registry privato (non solo i pacchetti con ambito).
  • NPM_REGISTRY_URL — URL completo del tuo registry npm (ad es., https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • NPM_REGISTRY_HOST — Solo hostname, senza protocollo (ad es., artifactory.example.com)
  • REGISTRY_TOKEN — token di autenticazione npm per il registry
maintenance:
  - name: Configure npm to use private registry
    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 registry privato

Configura pnpm in modo che recuperi i pacchetti da un registry privato.
pnpm è preinstallato nell’immagine di base di Devin. Puoi saltare il passaggio di installazione e configurare solo il registry.
  • NPM_REGISTRY_URL — URL completo del tuo registry npm
  • NPM_REGISTRY_HOST — Solo hostname, senza protocollo
  • REGISTRY_TOKEN — token di autenticazione npm per il registry
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 registry privato

Configura Yarn (Classic v1 o Berry v2+) per recuperare i pacchetti da un registry privato.
Yarn Classic (v1) è preinstallato nell’immagine di base di Devin. Salta il passaggio di installazione se ti serve solo v1.
  • NPM_REGISTRY_URL — URL completo del tuo registry npm/Yarn
  • REGISTRY_TOKEN — token di autenticazione per il registry (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"
      # Per i pacchetti con ambito:
      # yarn config set @myorg:registry "https://npm.pkg.github.com"

Go con un proxy di moduli privato

Installa Go e configuralo per recuperare i moduli tramite un proxy di moduli privato (ad esempio Athens, Artifactory o un endpoint GOPROXY).
  • GO_PROXY_URL — URL del proxy di moduli Go (ad esempio https://athens.corp.internal)
  • GIT_TOKEN — token di accesso personale per repo Git privati che ospitano moduli 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/"
Pattern URL comuni per i proxy 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 un feed privato

Installa l’SDK .NET e configura NuGet per recuperare i pacchetti da un feed privato (ad esempio, Azure Artifacts, Artifactory).
  • NUGET_FEED_URL — URL del tuo feed NuGet (ad esempio, https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json)
  • REGISTRY_USER — Nome utente del registry
  • REGISTRY_PASS — Password del registry o token 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

      # Facoltativamente disabilita la sorgente predefinita nuget.org
      # dotnet nuget disable source nuget.org
URL più comuni dei feed 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 registry di container privato

Configura Docker per autenticarsi con un registry di container privato.
  • DOCKER_MIRROR_URL (opzionale) — URL del tuo mirror di Docker Hub (ad es., https://mirror.corp.internal)
  • DOCKER_REGISTRY_URL — URL del tuo registry di container privato (ad es., registry.corp.internal:5000)
  • DOCKER_REGISTRY_USER — Nome utente del registry
  • DOCKER_REGISTRY_PASS — Password del registry o token API
initialize:
  - name: Create Docker config directory
    run: sudo mkdir -p /etc/docker

maintenance:
  - name: Configure Docker for private registry
    run: |
      # Configura il mirror del registry (opzionale — instrada i pull di Docker Hub attraverso il tuo registry)
      cat << EOF | sudo tee /etc/docker/daemon.json > /dev/null
      {
        "registry-mirrors": ["$DOCKER_MIRROR_URL"]
      }
      EOF
      sudo systemctl restart docker || true

      # Accedi al registry di container privato
      echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
        --username "$DOCKER_REGISTRY_USER" \
        --password-stdin
URL comuni dei registry di container:
  • 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 registry privato

Installa Rust e configura Cargo per recuperare i crate da un registry privato.
Rust (tramite rustup) e Cargo sono preinstallati nell’immagine di base di Devin. Salta il passaggio di installazione se il toolchain stable predefinito è sufficiente — ti serve solo la configurazione del registry.
  • CARGO_REGISTRY_INDEX — URL dell’indice del registry privato (ad es., sparse+https://cargo.corp.internal/api/v1/crates/)
  • CARGO_REGISTRY_TOKEN — token di autenticazione per il registry privato
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
Se devi solo aggiungere un registry privato senza sostituire crates.io, rimuovi le sezioni [source.crates-io] e [source.private] e usa cargo install --registry private oppure [dependencies] my-crate = { version = "1.0", registry = "private" } in Cargo.toml.

Ruby + Bundler con un server di gem privato

Installa Ruby e configura Bundler per recuperare le gem da un server di gem privato.
  • GEM_SERVER_URL — URL del tuo server di gem privato (ad esempio, https://artifactory.example.com/artifactory/api/gems/gems-virtual)
  • REGISTRY_USER — Nome utente del registry
  • REGISTRY_PASS — Password del registry o token 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"
Pattern di URL comuni per i server di gem:
  • Artifactory: https://artifactory.example.com/artifactory/api/gems/gems-virtual
  • Nexus: https://nexus.example.com/repository/rubygems-proxy
  • Gemfury: https://gem.fury.io/<org>

Rinnovo del token AWS CodeArtifact

I token AWS CodeArtifact scadono dopo 12 ore. Usa maintenance per rinnovare il token all’inizio di ogni sessione. Questo esempio configura npm, pip e Maven per usare CodeArtifact.
awscli è preinstallato nell’immagine di base di Devin. Sono necessari solo il rinnovo del token e la configurazione del registry.
  • AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY — credenziali IAM con le autorizzazioni codeartifact:GetAuthorizationToken e sts:GetServiceBearerToken
  • CA_DOMAIN — Nome del dominio CodeArtifact
  • CA_DOMAIN_OWNER — ID dell’account AWS proprietario del dominio
  • CA_REGION — Regione AWS (ad es. us-east-1)
  • CA_NPM_REPO, CA_PYPI_REPO, CA_MAVEN_REPO — Nomi dei repository per ciascun ecosistema
maintenance:
  - name: Refresh CodeArtifact auth token
    run: |
      # Ottieni un token aggiornato (valido per 12 ore)
      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"

      # Configura 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"

      # Configura 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

      # Configura Maven (opzionale)
      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 registry privato

Installa PHP e configura Composer per recuperare i pacchetti da un registry privato Packagist o Satis.
  • COMPOSER_REGISTRY_URL — URL del registry Composer privato (ad es. https://repo.packagist.com/<org>)
  • REGISTRY_USER — Nome utente del registry
  • REGISTRY_PASS — Password del registry o token 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

      # Installa 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"

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

      # Facoltativamente disabilita il packagist.org predefinito
      # composer config --global repositories.packagist false
Pattern di URL comuni del registry 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

Esempi specifici per repo

Questi esempi configurano i passaggi di build per repo, la gestione delle dipendenze e le voci di Knowledge. Impostali in Settings > Environment > [your repo].

Progetto Node.js standard

Un tipico progetto Node.js con comandi per lint, test e build.
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.

Progetto Python standard

Un progetto Python che usa uv per la gestione delle dipendenze.
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.

Progetto Java standard

Un progetto Java che utilizza Maven per la gestione delle dipendenze.
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.

Progetto Go standard

Un progetto Go con strumenti standard.
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.

Progetto Rust standard

Un progetto Rust che usa 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 più servizi

Un monorepo con servizi frontend e backend separati che utilizzano package manager diversi.
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 le subshell (cd dir && command) invece di cd dir && command, così la directory di lavoro si reimposta tra un passaggio e l’altro.

Monorepo con più versioni del JDK

Un monorepo Java in cui servizi diversi richiedono versioni diverse del JDK. Installa entrambi i JDK durante la configurazione, quindi usa le voci di Knowledge per indicare a Devin quale JAVA_HOME usare per ciascun servizio.
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)

Hook di pre-commit

Se il tuo progetto usa hook pre-commit, installali in maintenance così saranno pronti per ogni sessione.
initialize:
  - name: Install pre-commit
    run: pip install pre-commit

maintenance:
  - name: Install pre-commit hooks
    run: pre-commit install --install-hooks
Se il progetto include già pre-commit tra le dipendenze di sviluppo (ad esempio in pyproject.toml), salta il passaggio initialize e usa invece uv run pre-commit install --install-hooks o pipx run pre-commit install --install-hooks in maintenance.

Voci knowledge dettagliate

Documenta l’architettura, le convenzioni e i flussi di lavoro del tuo progetto nelle voci 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/

Esempi combinati

Questi esempi mostrano come le configurazioni enterprise e quelle a livello di org si combinano. In pratica, le suddivideresti tra diversi ambiti: qui sono mostrate insieme a scopo di riferimento.

Stack enterprise completo

Un ambiente enterprise completo: certificato CA aziendale, proxy, Java (Maven), Python (pip/uv), Node.js (npm) e Docker, tutti configurati per usare una singola istanza di Artifactory.
Rete e attendibilità (a livello di account):
  • CORP_ROOT_CA_B64 — Certificato CA aziendale codificato in Base64
  • CORP_HTTP_PROXY — URL del proxy HTTP
  • CORP_HTTPS_PROXY — URL del proxy HTTPS
  • CORP_NO_PROXY — Host che bypassano il proxy
Credenziali del registry (a livello di org):
  • ARTIFACTORY_USER — Nome utente Artifactory
  • ARTIFACTORY_TOKEN — Token API o password di Artifactory
  • ARTIFACTORY_MAVEN_URL — URL del repository Maven (ad es., https://artifactory.example.com/artifactory/maven-virtual)
  • ARTIFACTORY_PYPI_URL — URL del repository PyPI (ad es., https://user:token@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple)
  • ARTIFACTORY_NPM_URL — URL del repository npm (ad es., https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • ARTIFACTORY_DOCKER_URL — URL del registry Docker (ad es., artifactory.example.com)
In genere, questo verrebbe suddiviso in tre ambiti:
  • A livello di account (initialize): Certificato e proxy
  • A livello di org (initialize): Installazione dei runtime dei linguaggi
  • A livello di org (maintenance): Credenziali del registry (aggiornate a ogni sessione)
Qui sono mostrati insieme come riferimento:
initialize:
  # ── A livello di account: rete e trust ──────────────────────────────────────

  - name: Installa il certificato CA aziendale
    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: Configura il proxy di 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

  # ── A livello di organizzazione: runtime dei linguaggi ──────────────────────────────────────────

  - name: Installa 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: Installa uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  # ── A livello di account: proxy git (aggiornato a ogni sessione) ───────────────────

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

  # ── A livello di organizzazione: credenziali del registro (aggiornate a ogni sessione) ──────────────

  - name: Configura 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: Configura 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: Configura 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: Configura Docker → Artifactory
    run: |
      echo "$ARTIFACTORY_TOKEN" | docker login "$ARTIFACTORY_DOCKER_URL" \
        --username "$ARTIFACTORY_USER" \
        --password-stdin
In questo esempio, tutti i registri puntano alla stessa istanza di Artifactory, ma usano percorsi URL diversi. Ogni ecosistema di pacchetti ha un proprio formato di endpoint: gli URL di Maven, PyPI, npm e Docker sono tutti diversi anche per lo stesso registro.

Più linguaggi con registry diversi

Quando linguaggi diversi usano registry privati diversi (ad es. Maven da Nexus, npm da GitHub Packages, Python da Artifactory).
  • NEXUS_MAVEN_URL — URL del repository Maven di Nexus
  • NEXUS_USER — nome utente di Nexus
  • NEXUS_PASS — password di Nexus
  • GITHUB_PACKAGES_TOKEN — token di accesso personale di GitHub con ambito read:packages
  • ARTIFACTORY_USER — nome utente di Artifactory
  • ARTIFACTORY_TOKEN — token API di Artifactory
  • GIT_TOKEN — token di accesso personale per i moduli Go privati
maintenance:
  # Maven → Nexus
  - name: Configure 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 ambito)
  - name: Configure 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: Configure 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 → private modules via git
  - name: Configure Go private modules
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"

Ambiente air-gapped con mirror privati

In un ambiente completamente air-gapped, Devin non può accedere ad alcun URL pubblico. Tutti gli strumenti, i runtime e i pacchetti devono provenire da mirror interni.
Certificati:
  • CORP_ROOT_CA_B64 — Certificato della CA corporate codificato in Base64
Accesso ai mirror:
  • APT_MIRROR_URL — URL del mirror APT interno di Ubuntu
  • MIRROR_USER — Nome utente per l’autenticazione al mirror
  • MIRROR_PASS — Password per l’autenticazione al mirror
  • JDK_TARBALL_URL — URL per scaricare il tarball del JDK dal mirror interno
  • NODE_TARBALL_URL — URL per scaricare il tarball di Node.js dal mirror interno
Registry dei pacchetti:
  • INTERNAL_MAVEN_URL — URL del registry Maven interno
  • INTERNAL_NPM_URL — URL del registry npm interno
  • INTERNAL_PYPI_URL — URL del registry PyPI interno
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: |
      # Scarica il tarball JDK dall'archivio degli artefatti 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
Negli ambienti air-gapped, tutti gli strumenti di cui Devin ha bisogno (runtime dei linguaggi, strumenti CLI, ecc.) devono essere disponibili sui mirror interni. I registry pubblici e i siti di download non sono raggiungibili.

VPN + certificati + proxy + lingue

Una configurazione aziendale completa che combina la connettività VPN con certificati, proxy e supporto multilingue. Questo è l’ordine operativo consigliato.
VPN:
  • VPN_CONFIG_B64 — File di configurazione OpenVPN codificato in Base64
Rete e attendibilità:
  • CORP_ROOT_CA_B64 — Certificato della CA aziendale codificato in Base64
  • CORP_HTTP_PROXY — URL del proxy HTTP
  • CORP_HTTPS_PROXY — URL del proxy HTTPS
  • CORP_NO_PROXY — Host da escludere dal proxy
Credenziali del registry:
  • MAVEN_REGISTRY_URL — URL del registry Maven
  • NPM_REGISTRY_URL — URL del registry npm
  • PYPI_REGISTRY_HOST — hostname del registry PyPI
  • REGISTRY_USER — Nome utente del registry (per Maven e pip)
  • REGISTRY_PASS — Password del registry (per Maven e pip)
  • REGISTRY_TOKEN — Token di autenticazione npm
initialize:
  # 1. VPN — deve essere il primo in modo che le risorse interne siano raggiungibili
  - 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 — risolve i nomi host interni
  - 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. Certificati — considera attendibili le CA interne
  - 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 — instrada il traffico attraverso il proxy aziendale
  - 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. Language runtimes
  - 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
L’ordine dei passaggi di initialize è importante. La VPN deve venire per prima (così gli host interni sono raggiungibili), poi il DNS (così i nomi vengono risolti), poi i certificati (così HTTPS funziona), poi il proxy (così il traffico viene instradato correttamente) e infine i runtime dei linguaggi (che potrebbero scaricare da mirror interni).

Suggerimenti per scrivere buone configurazioni

  • Testa prima i comandi in una sessione — esegui i comandi manualmente in una sessione di Devin prima di aggiungerli alla configurazione. È più rapido che attendere un ciclo di build completo.
  • Usa initialize per gli strumenti da installare una sola volta, maintenance per le dipendenze — tutto ciò che richiede minuti per l’installazione (compilatori, binari di grandi dimensioni, strumenti globali) va in initialize. I comandi rapidi per le dipendenze (npm install, uv sync) vanno in maintenance.
  • Mantieni rapidi i comandi maintenance — cerca di restare sotto i 2 minuti. Vengono eseguiti all’inizio di ogni sessione.
  • Usa $ENVRC per le variabili d’ambiente — non scrivere in .bashrc o .profile. $ENVRC è il meccanismo supportato per impostare variabili tra passaggi e sessioni.
  • Dai un nome ai tuoi passaggi — la forma estesa con i campi name rende molto più semplice individuare gli errori nei log di build.
  • Usa le subshell per i monorepo(cd packages/foo && npm install) viene eseguito in una subshell, così i passaggi successivi non risentono del cambio di directory.
Per maggiori dettagli sulla sintassi e sull’esecuzione, consulta il Riferimento YAML. Per la risoluzione dei problemi relativi agli errori di build, consulta Risoluzione dei problemi e FAQ.