Skip to main content
Blueprint pronti da copiare e incollare per linguaggi e casi d’uso comuni. Ogni template è autonomo. Combinali per comporre la configurazione completa. Per una panoramica completa di ogni campo, consulta il riferimento dei blueprint.
Secrets: I template fanno riferimento ai secret tramite $SECRET_NAME. Configurali in Settings > Secrets prima di usare un template. Non inserire mai credenziali in chiaro nel blueprint.

Guida rapida

Blueprint essenziali per le configurazioni più comuni. Copiane uno, incollalo nell’editor dei blueprint e il gioco è fatto.
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 la suite completa.
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance: |
  uv sync

knowledge:
  - name: lint
    contents: |
      Esegui `uv run ruff check .` per il linting.
  - name: test
    contents: |
      Esegui `uv run pytest` per la suite completa.
initialize:
  - name: Install pnpm
    run: npm install -g pnpm
  - name: Install 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

Blueprint dei repository

Passaggi di build per ciascun repo, gestione delle dipendenze e voci di Knowledge. Configurali in Settings > Configurazione dell’ambiente > [il tuo repo].

Python

Configurazione consigliata per i progetti Python che usano uv per la gestione delle dipendenze.
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance: |
  uv sync

knowledge:
  - name: lint
    contents: |
      uv run ruff check .

      Correzione automatica:
      uv run ruff check --fix .

  - name: test
    contents: |
      uv run pytest

  - name: build
    contents: |
      uv run python -m build

Node.js

Configurazione Standard di Node.js con npm.
initialize: |
  nvm install 20
  nvm use 20

maintenance: |
  npm install

knowledge:
  - name: lint
    contents: |
      npx eslint .

  - name: test
    contents: |
      npm test

  - name: build
    contents: |
      npm run build
Usa npm install (non npm ci) in maintenance. Esegue un aggiornamento incrementale, mentre npm ci elimina node_modules e reinstalla tutto da zero a ogni sessione.

Go

Configurazione standard di Go con moduli.
initialize: |
  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

  go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

maintenance: |
  go mod download

knowledge:
  - name: lint
    contents: |
      golangci-lint run

  - name: test
    contents: |
      go test ./...

  - name: build
    contents: |
      go build ./...

Java

Configurazione di Java con Gradle.
JDK 17 è preinstallato nell’immagine di base di Devin. Salta il passaggio di installazione del JDK se OpenJDK 17 predefinito è sufficiente.
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: |
  ./gradlew dependencies

knowledge:
  - name: lint
    contents: |
      ./gradlew check

  - name: test
    contents: |
      ./gradlew test

  - name: build
    contents: |
      ./gradlew build

Ruby on Rails

Configurazione di Rails con PostgreSQL.
initialize:
  - name: Install Ruby 3.3
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ruby-full libpq-dev postgresql-client

maintenance: |
  bundle install
  rails db:migrate

knowledge:
  - name: lint
    contents: |
      bundle exec rubocop

  - name: test
    contents: |
      bundle exec rspec

  - name: build
    contents: |
      rails assets:precompile

Rust

Configurazione Rust standard con Cargo.
Rust (tramite rustup) e Cargo sono preinstallati nell’immagine di base di Devin. Salta il passaggio di installazione se la toolchain stabile predefinita è sufficiente. Devi solo scaricare le dipendenze.
initialize: |
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
  source ~/.cargo/env

maintenance: |
  cargo fetch

knowledge:
  - name: lint
    contents: |
      cargo clippy -- -D warnings

  - name: test
    contents: |
      cargo test

  - name: build
    contents: |
      cargo build --release

Monorepo

Monorepo con frontend Node.js e backend Python. Ogni sottoprogetto ha le proprie voci di Knowledge.
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: |
      Questo è un monorepo con tre package:
      - `packages/frontend` — app React (TypeScript, pnpm)
      - `packages/backend` — API Python (FastAPI, uv)
      - `packages/shared` — utilità TypeScript condivise (da buildare prima del frontend)
  - name: frontend
    contents: |
      Esegui `cd packages/frontend && pnpm dev` per avviare il server di sviluppo.
      Esegui `cd packages/frontend && pnpm lint` per eseguire il lint.
      Esegui `cd packages/frontend && pnpm test` per eseguire i test.
  - name: backend
    contents: |
      Esegui `cd packages/backend && uv run uvicorn app.main:app --reload` per avviare l'API.
      Esegui `cd packages/backend && uv run ruff check .` per eseguire il lint.
      Esegui `cd packages/backend && uv run pytest` per eseguire i test.
Usa le subshell (cd dir && command) invece di cd dir && command, così la directory di lavoro viene reimpostata tra un passaggio e l’altro.

Registry privati di pacchetti

Configura i gestori di pacchetti per risolvere le dipendenze tramite registry privati. Impostali in Settings > Configurazione dell’ambiente > Configurazione a livello di org (oppure a livello di repo, se serve solo per una repo).
La configurazione delle credenziali deve stare in maintenance, non in initialize. I passaggi che scrivono segreti (password del registry, auth token) nei file di configurazione devono usare maintenance, in modo che le credenziali vengano ricaricate a ogni sessione. I segreti vengono rimossi prima che lo snapshot venga salvato, quindi i file di configurazione scritti durante initialize non avranno credenziali valide all’avvio delle sessioni.
Se il tuo registry privato usa una CA aziendale, assicurati prima che il certificato CA sia installato a livello Enterprise. La configurazione seguente presuppone che l’attendibilità HTTPS sia già configurata.

Registry Node.js

Configura npm per risolvere i pacchetti con ambito (ad es. @myorg/*) da un registry privato, 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 scope npm. URL comuni dei 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>

Registry Python

Configura pip e uv per recuperare i pacchetti dal tuo registry PyPI privato (ad es. Nexus, Artifactory).
  • PYPI_REGISTRY_URL — URL completo del tuo indice PyPI, incluse le credenziali se richieste (ad es. https://user:token@nexus.example.com/repository/pypi-proxy/simple)
maintenance:
  - name: Configura pip/uv per il registry privato
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = $PYPI_REGISTRY_URL
      EOF

      echo "export UV_INDEX_URL=$PYPI_REGISTRY_URL" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
URL comuni dei registry PyPI:
  • Artifactory: https://artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple
  • Nexus: https://nexus.example.com/repository/pypi-proxy/simple
  • AWS CodeArtifact: https://aws:TOKEN@domain-owner.d.codeartifact.region.amazonaws.com/pypi/repo/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

Registry JVM

Installa il JDK e configura Maven in modo che tutta la risoluzione delle dipendenze passi attraverso il tuo registry privato (ad es., Artifactory, Nexus).
JDK 17 è preinstallato nell’immagine di base di Devin. Salta il passaggio di installazione 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 es., 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 di URL comuni dei registry 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>

Altri registry

Installa Go e configuralo per risolvere i moduli tramite un proxy privato per i moduli (ad es. Athens, Artifactory o un endpoint GOPROXY).
  • GO_PROXY_URL — URL del tuo proxy per i moduli Go (ad es. https://athens.corp.internal) - GIT_TOKEN — token di accesso personale per repo Git private 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
Configura NuGet per usare un feed privato come origine dei pacchetti.
- NUGET_SOURCE_URL — URL del tuo feed NuGet - NUGET_API_KEY — API key o PAT per il feed
initialize:
  - name: Install .NET SDK
    run: |
      curl -fsSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 8.0
      echo 'export PATH="$HOME/.dotnet:$PATH"' \
        | sudo tee /etc/profile.d/dotnet.sh > /dev/null

maintenance:
  - name: Configure NuGet for private feed
    run: |
      dotnet nuget add source "$NUGET_SOURCE_URL" \
        --name private \
        --username any \
        --password "$NUGET_API_KEY" \
        --store-password-in-clear-text 2>/dev/null || \
      dotnet nuget update source private \
        --source "$NUGET_SOURCE_URL" \
        --username any \
        --password "$NUGET_API_KEY" \
        --store-password-in-clear-text
Configura Docker per scaricare da un registry di container privato.
  • DOCKER_MIRROR_URL (facoltativo) — URL del mirror 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 container registry privato
      echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
        --username "$DOCKER_REGISTRY_USER" \
        --password-stdin
URL comuni dei container registry:
  • 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
Configura Cargo in modo che risolva i crate da un registry privato.
Rust (tramite rustup) e Cargo sono già preinstallati nell’immagine di base di Devin. Salta il passaggio di installazione se la toolchain stabile predefinita è sufficiente. È necessaria 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.
Installa Ruby e configura Bundler per risolvere le dipendenze gem da un server Gem privato.
  • GEM_SERVER_URL — URL del tuo server Gem privato (ad es., 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 URL comuni per i server 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>
Installa PHP e configura Composer per recuperare i pacchetti da un registry privato Packagist o Satis.
  • COMPOSER_REGISTRY_URL — URL del tuo 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"

      # Autenticazione con il registry
      composer config --global http-basic.$(echo "$COMPOSER_REGISTRY_URL" \
        | sed 's|https\?://||;s|/.*||') "$REGISTRY_USER" "$REGISTRY_PASS"
Pattern URL comuni per i 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
I token AWS CodeArtifact scadono dopo 12 ore. Usa maintenance per aggiornare 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. Devi solo configurare l’aggiornamento del token e il 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: |
      # Recupera 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

Infrastruttura Enterprise

Infrastruttura a livello di macchina valida per tutte le org e repo. Impostala in Settings > ambiente di base di Devin (a livello di Enterprise) oppure in Settings > configurazione dell’ambiente > configurazione a livello di org (a livello di org).

Rete e connettività

La tua organizzazione utilizza un’autorità di certificazione privata per i servizi interni. Devin richiede il certificato radice per accedere ai registry interni e agli strumenti 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
      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
Se la tua organizzazione utilizza più certificati CA (ad es. CA distinte per diversi servizi interni).
- CORP_ROOT_CA_B64 — certificato CA principale codificato in Base64 - CORP_INTERMEDIATE_CA_B64 — certificato CA intermedio codificato in Base64
initialize:
  - name: Install corporate CA certificates
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      echo "$CORP_INTERMEDIATE_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-intermediate-ca.crt > /dev/null
      sudo update-ca-certificates

      # Crea un bundle combinato per gli strumenti che richiedono un singolo file CA
      cat /usr/local/share/ca-certificates/corp-*.crt \
        | sudo tee /usr/local/share/ca-certificates/corp-bundle.crt > /dev/null

      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-bundle.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null
Instrada tutto il traffico di rete tramite un proxy aziendale.
  • CORP_HTTP_PROXY — URL del proxy HTTP (ad es. http://proxy.corp.example.com:8080) - CORP_HTTPS_PROXY — URL del proxy HTTPS - CORP_NO_PROXY — elenco di host, separati da virgole, da escludere dal proxy (ad es. localhost,127.0.0.1,.corp.example.com)
initialize:
  - 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"

      # Configura il proxy npm
      npm config set proxy "$CORP_HTTP_PROXY"
      npm config set https-proxy "$CORP_HTTPS_PROXY"
Se il proxy aziendale richiede l’autenticazione tramite nome utente/password.
  • PROXY_USER — Nome utente del proxy - PROXY_PASS — Password del proxy - PROXY_HOST — hostname e porta del proxy (ad es. proxy.corp.example.com:8080) - CORP_NO_PROXY — host da escludere dal proxy
initialize:
  - name: Configure authenticated proxy
    run: |
      PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}"

      cat << PROXY | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$PROXY_URL"
      export https_proxy="$PROXY_URL"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$PROXY_URL"
      export HTTPS_PROXY="$PROXY_URL"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

maintenance:
  - name: Configure git for authenticated proxy
    run: |
      PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}"
      git config --global http.proxy "$PROXY_URL"
      git config --global https.proxy "$PROXY_URL"
Configurazione combinata per ambienti che richiedono sia una CA aziendale sia un proxy. Questa configurazione è comune negli ambienti enterprise in cui i servizi interni usano certificati privati e tutto il traffico deve passare tramite un proxy.
  • CORP_ROOT_CA_B64 — certificato CA aziendale codificato in Base64 - CORP_HTTP_PROXY, CORP_HTTPS_PROXY — URL del proxy - CORP_NO_PROXY — host da escludere dal 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"
I tuoi 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 l’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 (facoltativo) — nome utente VPN, se la VPN richiede l’autenticazione con nome utente/password
  • VPN_AUTH_PASS (facoltativo) — password VPN
WireGuard:
  • WG_CONFIG_B64 — file di configurazione WireGuard codificato in Base64. Genera con: cat wg0.conf | base64 -w0
OpenVPN:
initialize:
  - name: Install and configure 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 username/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
WireGuard:
initialize:
  - name: Install and configure WireGuard
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq wireguard-tools

      # Scrivi la configurazione WireGuard
      echo "$WG_CONFIG_B64" | base64 -d \
        | sudo tee /etc/wireguard/wg0.conf > /dev/null
      sudo chmod 600 /etc/wireguard/wg0.conf

      # Avvia il tunnel
      sudo systemctl enable --now wg-quick@wg0
Per maggiori dettagli sulla configurazione della VPN, consulta Configurazione della VPN.
I tuoi servizi interni utilizzano 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

      # Facoltativamente configura 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

Identità e sicurezza

La tua organizzazione richiede che tutti i commit Git siano firmati e vuoi che GitHub contrassegni i commit di Devin come Verified.
  • GPG_PRIVATE_KEY_B64 — chiave privata GPG codificata in Base64. Genera con: gpg --export-secret-keys <key-id> | base64 -w0
  • GIT_USER_NAME — nome autore Git (ad es. Devin AI)
  • GIT_USER_EMAIL — email autore Git. Deve corrispondere a un UID della chiave GPG, altrimenti GitHub non verificherà la firma.
Carica anche la chiave pubblica corrispondente nell’account GitHub le cui credenziali Devin usa per eseguire il push (in GitHub Settings > SSH and GPG keys). GitHub contrassegna i commit come Verified solo quando la chiave pubblica usata per la firma è registrata nell’account autore del commit.
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

maintenance:
  - name: Import GPG key and configure git signing
    run: |
      echo "$GPG_PRIVATE_KEY_B64" | base64 -d | gpg --batch --import 2>/dev/null

      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"
      git config --global commit.gpgsign true
      git config --global tag.gpgsign true
      git config --global gpg.program gpg
Configura l’identità Git e le chiavi SSH di Devin per accedere a server Git privati.
  • GIT_USER_NAME — nome autore Git - GIT_USER_EMAIL — email autore Git - SSH_PRIVATE_KEY_B64 — chiave privata SSH codificata in Base64. Genera con: cat ~/.ssh/id_ed25519 | base64 -w0 - SSH_KNOWN_HOSTS_B64 — voci known_hosts codificate in Base64. Genera con: ssh-keyscan git.corp.internal | base64 -w0 - SSH_CONFIG_B64 (facoltativo) — file di configurazione SSH codificato in Base64
initialize:
  - name: Configure git identity
    run: |
      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

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

      # Aggiungi i known hosts per il tuo server Git
      echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

      # Installa facoltativamente 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.

Configurazione del sistema

Installa pacchetti di sistema che non sono presenti 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
Imposta variabili d’ambiente persistenti da rendere disponibili in ogni sessione.L’approccio consigliato è 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.
Le immagini di base predefinite potrebbero avere impostazioni del locale non corrette. Configura il locale e il fuso orario per evitare avvisi da strumenti di build, 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
Le build Java, Gradle e Node.js raggiungono spesso il limite predefinito di 1024 file aperti. Aumentalo per evitare errori di 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
In ambienti air-gapped o soggetti a restrizioni, sostituisci i repository APT predefiniti di Ubuntu con un mirror interno.
- APT_MIRROR_URL — URL del tuo 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

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

Pattern avanzati

L’ambiente di base di Devin include direnv. Usa initialize per creare i file .envrc. Direnv li carica automaticamente.
initialize: |
  cat <<'EOF' > .envrc
  export DATABASE_URL=postgresql://localhost:5432/myapp_dev
  export REDIS_URL=redis://localhost:6379
  export APP_ENV=development
  EOF

maintenance: |
  direnv allow .
direnv è già configurato nella shell di Devin, quindi le variabili di .envrc vengono caricate automaticamente. Non serve eseguire il source manualmente.
Per le variabili d’ambiente sensibili (API key, token, password del database), usa i segreti del repo invece dei file .envrc. I segreti del repo sono archiviati in modo sicuro e vengono iniettati all’avvio della sessione. Non compaiono mai nel blueprint o nello snapshot.
Usa nvm (preinstallato) per cambiare versione di Node.js per ciascun repository tramite .nvmrc.
initialize: |
  nvm install 18
  nvm install 20
  nvm install 22

maintenance: |
  nvm use
nvm use legge .nvmrc dalla directory radice della repo. Assicurati che il repository ne abbia uno (ad es., contenente 20).
Devin mette a disposizione un browser Chrome con un endpoint CDP su localhost:29229 durante le sessioni. Usa script Playwright per automatizzare il login nel browser.
Il browser è disponibile solo durante le sessioni, non nelle build snapshot. Installa Playwright in initialize e conserva gli script di login nella tua repo.
initialize: |
  pip install playwright
  playwright install chromium

maintenance: |
  npm install

knowledge:
  - name: browser-auth
    contents: |
      This project requires browser authentication.
      Run the login script before interacting with the app:
      python scripts/login.py

      Devin's Chrome browser is accessible via CDP at:
      http://localhost:29229
Esempio di script di accesso (scripts/login.py):
from playwright.sync_api import sync_playwright
import os

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp("http://localhost:29229")
    context = browser.contexts[0]
    page = context.pages[0] if context.pages else context.new_page()

    page.goto("https://internal-tool.example.com/login")
    page.fill("#username", os.environ["TOOL_USERNAME"])
    page.fill("#password", os.environ["TOOL_PASSWORD"])
    page.click('button[type="submit"]')
    page.wait_for_url("**/dashboard")
Conserva le credenziali di accesso come secrets, non nel codice sorgente. Per un’autenticazione a lungo termine, esegui il commit degli script di accesso in .agents/skills/ in modo che Devin possa riautenticarsi automaticamente.
Installa pacchetti di sistema, binari personalizzati e configura il PATH in initialize.
initialize:
  - name: Install system packages
    run: |
      apt-get update
      apt-get install -y \
        jq \
        ripgrep \
        fd-find \
        protobuf-compiler \
        libssl-dev

  - name: Install custom CLI tool
    run: |
      curl -L https://github.com/example/tool/releases/download/v1.0/tool-linux-amd64 \
        -o /usr/local/bin/mytool
      chmod +x /usr/local/bin/mytool

  - name: Add custom bin directory to PATH
    run: |
      mkdir -p ~/bin
      echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc

knowledge:
  - name: tools
    contents: |
      Custom tools available:
      - mytool: installed at /usr/local/bin/mytool
      - Additional binaries can be placed in ~/bin
Devin supporta l’esecuzione diretta nei blueprint di GitHub Actions basate su Node.js. Questo è utile per installare versioni specifiche degli strumenti tramite le stesse azioni usate dalla tua CI.
initialize:
  - name: "Install Node.js 20"
    uses: github.com/actions/setup-node@v4
    with:
      node-version: "20"

  - name: "Install Python 3.12"
    uses: github.com/actions/setup-python@v5
    with:
      python-version: "3.12"

  - name: "Install Go 1.22"
    uses: github.com/actions/setup-go@v5
    with:
      go-version: "1.22"

  - name: "Install Java 21"
    uses: github.com/actions/setup-java@v4
    with:
      java-version: "21"
      distribution: "temurin"

  - name: "Install Gradle"
    uses: github.com/gradle/actions/setup-gradle@v4

  - name: "Install Ruby 3.3"
    uses: github.com/ruby/setup-ruby@v1
    with:
      ruby-version: "3.3"

  - name: "Install additional tools"
    run: |
      pip install uv
      npm install -g pnpm turbo
      go install golang.org/x/tools/gopls@latest

maintenance: |
  echo "All runtimes are available:"
  node --version
  python --version
  go version
  java --version
Azioni come setup-node e setup-python modificano il PATH e le variabili d’ambiente. I binari installati da un’azione sono disponibili in tutti i passaggi successivi e in maintenance. Sono supportate solo le GitHub Actions basate su Node.js. Le azioni composite e quelle basate su Docker non sono supportate.
Non servono GitHub Actions per la configurazione di base degli strumenti. I comandi shell diretti (nvm install 20, curl ... | sh, apt-get install) funzionano altrettanto bene e spesso sono più semplici. Le GitHub Actions sono particolarmente utili quando vuoi replicare esattamente la configurazione della tua CI o sfruttare la comodità di azioni come setup-java, che gestiscono più distribuzioni.

Esempi full-stack

Questi esempi mostrano come si combinano le configurazioni Enterprise e quelle a livello di org. In pratica, le divideresti tra diversi ambiti. Qui sono riunite a scopo di riferimento.
Un ambiente enterprise completo: certificato CA aziendale, proxy, Java (Maven), Python (pip/uv), Node.js (npm) e Docker, tutti puntati a una singola istanza di Artifactory.
Rete e attendibilità (per l’intero 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 da escludere dal proxy
Credenziali del registry (per l’intera 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
  • Org-wide (initialize): Installazione del runtime del linguaggio
  • A livello di org (maintenance): credenziali del registry (aggiornate a ogni sessione)
Di seguito il codice completo per riferimento:
initialize:
  # ── Account-wide: rete e attendibilità ──────────────────────────────────────

  - 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

  # ── Org-wide: language runtimes ──────────────────────────────────────────

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

maintenance:
  # ── Account-wide: git proxy (aggiornato ad ogni session) ───────────────────

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

  # ── Org-wide: registry credentials (aggiornate ad ogni session) ──────────────

  - name: Configure 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: Configure 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: Configure 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: Configure Docker → Artifactory
    run: |
      echo "$ARTIFACTORY_TOKEN" | docker login "$ARTIFACTORY_DOCKER_URL" \
        --username "$ARTIFACTORY_USER" \
        --password-stdin
In questo esempio, tutti i registry puntano alla stessa istanza di Artifactory, ma utilizzano percorsi URL diversi. Ogni ecosistema di pacchetti ha il proprio formato di endpoint. Gli URL di Maven, PyPI, npm e Docker sono tutti diversi, anche per lo stesso registry.
Quando linguaggi diversi usano registri privati differenti (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 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 → moduli privati tramite git
  - name: Configure Go private modules
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
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 CA aziendale 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 da cui scaricare il tarball JDK dal mirror interno
  • NODE_TARBALL_URL — URL da cui scaricare il tarball 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 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 necessari a Devin (runtime dei linguaggi di programmazione, strumenti CLI, ecc.) devono essere disponibili sui vostri mirror interni. I registry pubblici e i siti di download non sono raggiungibili.
Una configurazione Enterprise completa che combina connettività VPN con certificati, proxy e supporto multilingua. Questo è l’ordine delle operazioni consigliato.
VPN:
  • VPN_CONFIG_B64 — file di configurazione OpenVPN codificato in Base64
Rete & attendibilità:
  • 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 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 per npm
initialize:
  # 1. VPN — deve essere il primo affinché 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 gli hostname 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 — attendibilità delle 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 initialize è importante. La VPN deve venire per prima (in modo che gli host interni siano raggiungibili), poi il DNS (in modo che i nomi vengano risolti), poi i certificati (in modo che HTTPS funzioni), poi il proxy (in modo che il traffico venga instradato correttamente) e infine i runtime dei linguaggi (che potrebbero scaricare da mirror interni).

Suggerimenti per scrivere blueprint efficaci

  • Prova prima i comandi in una sessione. Esegui i comandi manualmente in una sessione di Devin prima di aggiungerli al blueprint. È più veloce che aspettare 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 essere installato (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.
  • Assegna un nome ai 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.
  • Usa npm install, non npm ci. npm ci elimina node_modules e reinstalla tutto da zero a ogni sessione, rallentando maintenance.
  • Usa i secrets del repo per i valori sensibili. Configurali in Settings > Secrets con ambito repo invece di inserirli direttamente nei blueprint.
Per i dettagli sulla sintassi, consulta il riferimento dei blueprint. Per risolvere gli errori di build, consulta Configurazione dichiarativa > Risoluzione dei problemi.