Skip to main content
Des blueprints prêts à l’emploi pour les langages et cas d’usage courants. Chaque modèle est autonome. Combinez-les pour créer votre configuration complète. Pour une présentation détaillée de chaque champ, consultez la Référence des blueprints.
Secrets : Les modèles font référence à des secrets via $SECRET_NAME. Configurez-les dans Settings > Secrets avant d’utiliser un modèle. N’intégrez jamais d’identifiants en dur dans votre blueprint.

Démarrage rapide

Blueprints minimaux pour les configurations les plus courantes. Copiez-en un, collez-le dans l’éditeur de blueprints, et le tour est joué.
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      Exécutez `pnpm lint` pour vérifier les erreurs.
  - name: test
    contents: |
      Exécutez `pnpm test` pour lancer la suite complète.
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance: |
  uv sync

knowledge:
  - name: lint
    contents: |
      Exécutez `uv run ruff check .` pour lancer le lint.
  - name: test
    contents: |
      Exécutez `uv run pytest` pour lancer la suite complète.
initialize:
  - name: Installer pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Dépendances frontend
    run: (cd frontend && pnpm install)
  - name: Dépendances backend
    run: (cd backend && uv sync)

knowledge:
  - name: structure
    contents: |
      - `frontend/` — application React (pnpm)
      - `backend/` — API Python (uv)
  - name: test
    contents: |
      Frontend: cd frontend && pnpm test
      Backend: cd backend && uv run pytest

Blueprints du dépôt

Étapes de build propres à chaque dépôt, gestion des dépendances et entrées Knowledge. Définissez-les dans Settings > Configuration de l’environnement > [votre dépôt].

Python

Configuration recommandée pour les projets Python qui utilisent uv pour la gestion des dépendances.
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance: |
  uv sync

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

      Correction automatique :
      uv run ruff check --fix .

  - name: test
    contents: |
      uv run pytest

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

Node.js

Configuration Node.js par défaut avec 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
Utilisez npm install (et non npm ci) dans maintenance. Cette commande effectue une mise à jour incrémentielle, tandis que npm ci supprime node_modules et réinstalle tout depuis zéro à chaque session.

Go

Configuration Go standard avec modules.
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

Configuration de Java avec Gradle.
JDK 17 est préinstallé sur l’image de base de Devin. Ignorez l’étape d’installation du JDK si l’OpenJDK 17 par défaut vous convient.
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

Configuration de Rails avec 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

Configuration standard de Rust avec Cargo.
Rust (via rustup) et Cargo sont préinstallés sur l’image de base de Devin. Passez l’étape d’installation si la toolchain stable par défaut vous convient. Il vous suffit de récupérer les dépendances.
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

Monorepos

Monorepo avec un frontend Node.js et un backend Python. Chaque sous-projet a ses propres entrées Knowledge.
initialize:
  - name: Installer pnpm
    run: npm install -g pnpm
  - name: Installer uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Installer les dépendances du frontend
    run: (cd packages/frontend && pnpm install)
  - name: Installer les dépendances du backend
    run: (cd packages/backend && uv sync)
  - name: Build de la bibliothèque partagée
    run: (cd packages/shared && pnpm install && pnpm build)

knowledge:
  - name: structure
    contents: |
      Il s'agit d'un monorepo avec trois packages :
      - `packages/frontend` — application React (TypeScript, pnpm)
      - `packages/backend` — API Python (FastAPI, uv)
      - `packages/shared` — utilitaires TypeScript partagés (doivent être buildés avant le frontend)
  - name: frontend
    contents: |
      Exécutez `cd packages/frontend && pnpm dev` pour démarrer le serveur de développement.
      Exécutez `cd packages/frontend && pnpm lint` pour lancer le linting.
      Exécutez `cd packages/frontend && pnpm test` pour lancer les tests.
  - name: backend
    contents: |
      Exécutez `cd packages/backend && uv run uvicorn app.main:app --reload` pour démarrer l'API.
      Exécutez `cd packages/backend && uv run ruff check .` pour lancer le linting.
      Exécutez `cd packages/backend && uv run pytest` pour lancer les tests.
Utilisez des subshells (cd dir && command) plutôt que cd dir && command afin que le répertoire de travail soit réinitialisé entre les étapes.

Registres privés de packages

Configurez les gestionnaires de paquets pour résoudre les dépendances depuis des registres privés. Définissez cela dans Settings > Environment configuration > setup à l’échelle de l’organisation (ou au niveau du dépôt si un seul dépôt est concerné).
La configuration des identifiants doit se faire dans maintenance, pas dans initialize. Les étapes qui écrivent des secrets (mots de passe de registre, jetons d’authentification) dans des fichiers de configuration doivent utiliser maintenance afin que les identifiants soient rechargés au début de chaque session. Les secrets sont supprimés avant l’enregistrement du snapshot, donc les fichiers de configuration écrits pendant initialize n’auront pas d’identifiants valides au démarrage.
Si votre registre privé utilise une autorité de certification d’entreprise, assurez-vous que le certificat d’autorité de certification est d’abord installé au niveau Enterprise. La configuration ci-dessous suppose que la confiance HTTPS est déjà établie.

Registres Node.js

Configurez npm pour récupérer les packages d’un scope (par ex. @myorg/*) à partir d’un registre privé, tandis que les packages publics continuent de provenir du registre npm par défaut.
- GITHUB_PACKAGES_TOKEN — Jeton d’accès personnel ou jeton GitHub App avec le périmètre 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
Remplacez @myorg par votre scope npm. URL courantes de registres privés :
  • 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>

Registres Python

Configurez pip et uv pour récupérer les packages depuis votre registre PyPI privé (p. ex., Nexus, Artifactory).
  • PYPI_REGISTRY_URL — URL complète de votre index PyPI, y compris les identifiants si nécessaire (p. ex., https://user:token@nexus.example.com/repository/pypi-proxy/simple)
maintenance:
  - name: Configure pip/uv for private registry
    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 courantes de registres 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

Registres JVM

Installez le JDK et configurez Maven pour faire transiter toute la résolution des dépendances par votre registre privé (p. ex. Artifactory, Nexus).
Le JDK 17 est préinstallé sur l’image de base de Devin. Passez l’étape d’installation si l’OpenJDK 17 par défaut vous suffit. Vous n’avez besoin que de l’installation de Maven et de la configuration du registre.
  • MAVEN_REGISTRY_URL — URL de votre registre Maven (p. ex. https://artifactory.example.com/artifactory/maven-virtual) - REGISTRY_USER — Nom d’utilisateur du registre - REGISTRY_PASS — Mot de passe du registre ou jeton d’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
Schémas d’URL courants pour les registres 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>

Autres registres

Installez Go et configurez-le pour passer par un proxy de modules privé afin de résoudre les modules (par ex., Athens, Artifactory ou un endpoint GOPROXY).
  • GO_PROXY_URL — URL de votre proxy de modules Go (par ex., https://athens.corp.internal) - GIT_TOKEN — jeton d’accès personnel pour les dépôts Git privés qui hébergent des modules 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/"
Schémas d’URL courants pour les proxys Go :
  • Artifactory: https://artifactory.example.com/artifactory/go-virtual
  • Nexus: https://nexus.example.com/repository/go-proxy
  • Athens: https://athens.corp.internal
Configurez NuGet pour récupérer les packages depuis une source privée.
- NUGET_SOURCE_URL — URL de votre source NuGet - NUGET_API_KEY — clé API ou PAT pour la source
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
Configurez Docker pour récupérer des images depuis un registre de conteneurs privé.
  • DOCKER_MIRROR_URL (facultatif) — URL de votre miroir Docker Hub (par exemple, https://mirror.corp.internal) - DOCKER_REGISTRY_URL — URL de votre registre de conteneurs privé (par exemple, registry.corp.internal:5000) - DOCKER_REGISTRY_USER — Nom d’utilisateur du registre - DOCKER_REGISTRY_PASS — Mot de passe du registre ou jeton d’API
initialize:
  - name: Create Docker config directory
    run: sudo mkdir -p /etc/docker

maintenance:
  - name: Configure Docker for private registry
    run: |
      # Configurer le miroir de registre (facultatif — achemine les pulls Docker Hub via votre registre)
      cat << EOF | sudo tee /etc/docker/daemon.json > /dev/null
      {
        "registry-mirrors": ["$DOCKER_MIRROR_URL"]
      }
      EOF
      sudo systemctl restart docker || true

      # Se connecter au registre de conteneurs privé
      echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
        --username "$DOCKER_REGISTRY_USER" \
        --password-stdin
URL courantes des registres de conteneurs :
  • 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
Configurez Cargo pour utiliser des crates provenant d’un registre privé.
Rust (via rustup) et Cargo sont préinstallés sur l’image de base de Devin. Passez l’étape d’installation si la toolchain stable par défaut suffit. Seule la configuration du registre est nécessaire.
  • CARGO_REGISTRY_INDEX — URL de l’index du registre privé (p. ex., sparse+https://cargo.corp.internal/api/v1/crates/) - CARGO_REGISTRY_TOKEN — jeton d’authentification pour le registre privé
initialize:
  - name: Install Rust
    run: |
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
        | sh -s -- -y --default-toolchain stable
      echo 'source "$HOME/.cargo/env"' \
        | sudo tee /etc/profile.d/rust.sh > /dev/null

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

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

      [source.private]
      registry = "$CARGO_REGISTRY_INDEX"
      EOF
Si vous devez simplement ajouter un registre privé sans remplacer crates.io, supprimez les sections [source.crates-io] et [source.private], puis utilisez cargo install --registry private ou [dependencies] my-crate = { version = "1.0", registry = "private" } dans Cargo.toml.
Installez Ruby et configurez Bundler pour récupérer les gems depuis un serveur de gems privé.
  • GEM_SERVER_URL — URL de votre serveur de gems privé (p. ex., https://artifactory.example.com/artifactory/api/gems/gems-virtual) - REGISTRY_USER — Nom d’utilisateur du registre - REGISTRY_PASS — Mot de passe du registre ou jeton d’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"
Schémas d’URL courants pour les serveurs de gems :
  • Artifactory: https://artifactory.example.com/artifactory/api/gems/gems-virtual
  • Nexus: https://nexus.example.com/repository/rubygems-proxy
  • Gemfury: https://gem.fury.io/<org>
Installez PHP et configurez Composer pour récupérer des packages depuis un registre privé Packagist ou Satis.
  • COMPOSER_REGISTRY_URL — URL de votre registre Composer privé (par ex., https://repo.packagist.com/<org>)
  • REGISTRY_USER — Nom d’utilisateur du registre
  • REGISTRY_PASS — Mot de passe du registre ou jeton d’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

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

      # S'authentifier auprès du registre
      composer config --global http-basic.$(echo "$COMPOSER_REGISTRY_URL" \
        | sed 's|https\?://||;s|/.*||') "$REGISTRY_USER" "$REGISTRY_PASS"
Modèles d’URL courants pour les registres 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
Les jetons AWS CodeArtifact expirent après 12 heures. Utilisez maintenance pour actualiser le jeton au début de chaque session. Cet exemple configure npm, pip et Maven pour utiliser CodeArtifact.
awscli est préinstallé sur l’image de base de Devin. Il vous suffit d’actualiser le jeton et de configurer le registre.
  • AWS_ACCESS_KEY_ID et AWS_SECRET_ACCESS_KEY — Identifiants IAM avec les autorisations codeartifact:GetAuthorizationToken et sts:GetServiceBearerToken - CA_DOMAIN — Nom de votre domaine CodeArtifact
    • CA_DOMAIN_OWNER — ID du compte AWS propriétaire du domaine - CA_REGION — Région AWS (p. ex., us-east-1) - CA_NPM_REPO, CA_PYPI_REPO, CA_MAVEN_REPO — Noms des dépôts pour chaque écosystème
maintenance:
  - name: Refresh CodeArtifact auth token
    run: |
      # Obtenir un token récent (valide pendant 12 heures)
      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"

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

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

      # Configurer Maven (facultatif)
      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

Infrastructure Enterprise

Infrastructure au niveau des machines qui s’applique à l’ensemble des organisations et des dépôts. Définissez ces paramètres dans Settings > environnement de base de Devin (à l’échelle de l’entreprise) ou Settings > configuration de l’environnement > configuration à l’échelle de l’organisation (à l’échelle de l’organisation).

Réseau et connectivité

Votre organisation utilise une autorité de certification privée pour ses services internes. Devin a besoin du certificat racine pour accéder aux dépôts et outils internes via HTTPS.
- CORP_ROOT_CA_B64 — certificat PEM encodé en Base64 issu de votre autorité de certification d’entreprise. Générez-le avec : 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
Si votre organisation utilise plusieurs certificats d’autorité de certification (par exemple, des autorités de certification distinctes pour différents services internes).
- CORP_ROOT_CA_B64 — certificat principal d’autorité de certification encodé en Base64 - CORP_INTERMEDIATE_CA_B64 — certificat intermédiaire d’autorité de certification encodé en 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

      # Créer un bundle combiné pour les outils nécessitant un seul fichier 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
Faites passer tout le trafic réseau par un proxy d’entreprise.
  • CORP_HTTP_PROXY — URL du proxy HTTP (p. ex., http://proxy.corp.example.com:8080) - CORP_HTTPS_PROXY — URL du proxy HTTPS - CORP_NO_PROXY — liste d’hôtes, séparés par des virgules, à ne pas faire passer par le proxy (p. ex., 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"

      # Configurer le proxy npm
      npm config set proxy "$CORP_HTTP_PROXY"
      npm config set https-proxy "$CORP_HTTPS_PROXY"
Si votre proxy d’entreprise nécessite une authentification par nom d’utilisateur et mot de passe.
  • PROXY_USER — Nom d’utilisateur du proxy - PROXY_PASS — Mot de passe du proxy - PROXY_HOST — Nom d’hôte et port du proxy (par ex., proxy.corp.example.com:8080) - CORP_NO_PROXY — Hôtes à exclure du 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"
Configuration combinée pour les environnements nécessitant à la fois une autorité de certification d’entreprise et un proxy. Ce cas est fréquent dans les environnements d’entreprise où les services internes utilisent des certificats privés et où tout le trafic doit transiter par un proxy.
  • CORP_ROOT_CA_B64 — certificat d’autorité de certification d’entreprise encodé en Base64 - CORP_HTTP_PROXY, CORP_HTTPS_PROXY — URL du proxy - CORP_NO_PROXY — hôtes à exclure du 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"
Vos registres privés, serveurs Git ou autres services internes ne sont accessibles que via un VPN. Ce module doit s’exécuter avant les autres modules qui nécessitent un accès réseau aux ressources internes.
OpenVPN :
  • VPN_CONFIG_B64 — Fichier de configuration OpenVPN encodé en Base64 (.ovpn). Générez-le avec : cat corp.ovpn | base64 -w0
  • VPN_AUTH_USER (facultatif) — Nom d’utilisateur du VPN, si votre VPN nécessite une authentification par nom d’utilisateur et mot de passe
  • VPN_AUTH_PASS (facultatif) — Mot de passe du VPN
WireGuard :
  • WG_CONFIG_B64 — Fichier de configuration WireGuard encodé en Base64. Générez-le avec : 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

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

      # Si le VPN requiert une authentification par nom d'utilisateur/mot de passe
      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

      # Démarrer le tunnel VPN
      sudo systemctl daemon-reload
      sudo systemctl enable --now openvpn-client@corp

      # Attendre que le tunnel soit établi
      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

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

      # Démarrer le tunnel
      sudo systemctl enable --now wg-quick@wg0
Pour plus d’informations sur la configuration du VPN, consultez Configuration du VPN.
Vos services internes utilisent des noms DNS privés qui ne sont pas résolubles via le DNS public.
initialize:
  - name: Configure custom DNS resolution
    run: |
      # Ajouter les noms d'hôtes internes
      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

      # Configurer éventuellement des serveurs de noms personnalisés
      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é et sécurité

Votre organisation exige que tous les commits Git soient signés, et vous souhaitez que GitHub marque les commits de Devin comme Verified.
  • GPG_PRIVATE_KEY_B64 — Clé privée GPG encodée en Base64. Générez-la avec : gpg --export-secret-keys <key-id> | base64 -w0
  • GIT_USER_NAME — Nom de l’auteur Git (p. ex., Devin AI)
  • GIT_USER_EMAIL — Adresse e-mail de l’auteur Git. Doit correspondre à un UID de la clé GPG, sinon GitHub ne vérifiera pas la signature.
Importez également la clé publique correspondante dans le compte GitHub dont Devin utilise les identifiants pour effectuer le push (dans GitHub Settings > SSH and GPG keys). GitHub ne marque les commits comme Verified que lorsque la clé publique de signature est enregistrée sur le compte auteur du commit.
initialize:
  - name: Prepare GPG and git signing config
    run: |
      # Permettre à GPG de fonctionner sans 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
Configurez l’identité Git et les clés SSH de Devin pour accéder à des serveurs Git privés.
  • GIT_USER_NAME — Nom de l’auteur Git - GIT_USER_EMAIL — Adresse e-mail de l’auteur Git - SSH_PRIVATE_KEY_B64 — Clé privée SSH encodée en Base64. Générez-la avec : cat ~/.ssh/id_ed25519 | base64 -w0 - SSH_KNOWN_HOSTS_B64 — Entrées du fichier known_hosts encodées en Base64. Générez-les avec : ssh-keyscan git.corp.internal | base64 -w0 - SSH_CONFIG_B64 (facultatif) — Fichier de configuration SSH encodé en Base64
initialize:
  - name: Configure git identity
    run: |
      git config --global user.name "$GIT_USER_NAME"
      git config --global user.email "$GIT_USER_EMAIL"

      # Préparer le répertoire SSH
      mkdir -p ~/.ssh && chmod 700 ~/.ssh

maintenance:
  - name: Install SSH keys
    run: |
      # Installer la clé privée SSH (dans maintenance pour qu'elle soit rechargée à neuf à chaque session)
      echo "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
      chmod 600 ~/.ssh/id_ed25519

      # Ajouter les hôtes connus de votre serveur Git
      echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

      # Installer éventuellement une configuration SSH personnalisée
      if [ -n "${SSH_CONFIG_B64:-}" ]; then
        echo "$SSH_CONFIG_B64" | base64 -d > ~/.ssh/config
        chmod 600 ~/.ssh/config
      fi
Générez l’entrée known_hosts de votre serveur Git avec ssh-keyscan git.corp.internal | base64 -w0.

Configuration du système

Installez les packages système qui ne figurent pas dans l’image Devin par défaut (p. ex., des bibliothèques natives pour le traitement d’images ou la génération de PDF).
initialize:
  - name: Install system packages
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
        libpq-dev \
        libmagickwand-dev \
        poppler-utils \
        ffmpeg
Définissez des variables d’environnement persistantes qui doivent être disponibles dans chaque session.L’approche recommandée consiste à écrire des lignes KEY=VALUE dans le fichier $ENVRC. Les variables écrites dans $ENVRC sont automatiquement exportées pour toutes les étapes suivantes ainsi que pour la session Devin (comme avec le $GITHUB_ENV de GitHub Actions).
initialize:
  - name: Set custom environment variables
    run: |
      echo "CORPORATE_ENV=production" >> $ENVRC
      echo "DEFAULT_REGION=us-east-1" >> $ENVRC
      echo "MAX_RETRIES=3" >> $ENVRC
Vous pouvez également définir des variables d’environnement dans des scripts /etc/profile.d/ afin de les rendre disponibles à l’échelle du système :
cat << 'ENVVARS' | sudo tee /etc/profile.d/custom-env.sh > /dev/null
export CORPORATE_ENV=production
export DEFAULT_REGION=us-east-1
ENVVARS
Les deux approches fonctionnent. $ENVRC est plus simple et recommandé dans la plupart des cas.
Les images de base par défaut peuvent avoir des paramètres régionaux incorrects. Configurez les paramètres régionaux et le fuseau horaire pour éviter les avertissements des outils de build, de Java, de Python et de 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

      # Générer et définir la 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

      # Définir le fuseau horaire
      sudo timedatectl set-timezone UTC 2>/dev/null || \
        sudo ln -sfn /usr/share/zoneinfo/UTC /etc/localtime
Les builds Java, Gradle et Node.js atteignent fréquemment la limite par défaut de 1 024 fichiers ouverts. Augmentez-la pour éviter les build failures.
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

      # Définir aussi le maximum du noyau
      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
Dans les environnements en air gap ou restreints, remplacez les sources APT Ubuntu par défaut par un miroir interne.
- APT_MIRROR_URL — URL de votre miroir APT interne (p. ex., https://artifactory.example.com/artifactory/ubuntu-remote)
initialize:
  - name: Replace APT sources with internal mirror
    run: |
      # Sauvegarder les sources originales
      sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

      # Remplacer tous les miroirs Ubuntu par votre miroir interne
      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
Schémas d’URL courants pour les miroirs APT :
  • Artifactory: https://artifactory.example.com/artifactory/ubuntu-remote
  • Nexus: https://nexus.example.com/repository/ubuntu-proxy

Patterns avancés

L’environnement de base de Devin comprend direnv. Utilisez initialize pour créer des fichiers .envrc. Direnv les charge automatiquement.
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 est intégré d’emblée au shell de Devin, donc les variables .envrc se chargent automatiquement. Aucun chargement manuel n’est nécessaire.
Pour les variables d’environnement sensibles (API keys, jetons, mots de passe de base de données), utilisez les secrets du dépôt plutôt que des fichiers .envrc. Les secrets du dépôt sont stockés de manière sécurisée et injectés au début de la session. Ils n’apparaissent jamais dans votre blueprint ni dans votre snapshot.
Utilisez nvm (préinstallé) pour changer de version de Node.js pour chaque dépôt via .nvmrc.
initialize: |
  nvm install 18
  nvm install 20
  nvm install 22

maintenance: |
  nvm use
nvm use lit .nvmrc à la racine du dépôt. Assurez-vous que votre dépôt en contient un (p. ex. avec 20).
Devin fournit un navigateur Chrome avec un endpoint CDP sur localhost:29229 pendant les sessions. Utilisez des scripts Playwright pour automatiser la connexion via le navigateur.
Le navigateur n’est disponible que pendant les sessions, pas dans les builds du snapshot. Installez Playwright dans initialize et conservez les scripts de connexion dans votre 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
Exemple de script de connexion (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")
Stockez les identifiants de connexion dans les secrets, pas dans le code source. Pour une authentification persistante, versionnez les scripts de connexion dans .agents/skills/ afin que Devin puisse se réauthentifier automatiquement.
Installez des packages système, des binaires personnalisés et configurez le PATH dans 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 prend en charge l’exécution de GitHub Actions basées sur Node.js directement dans les blueprints. Cela est utile pour installer des versions spécifiques d’outils via les mêmes actions que celles utilisées par votre 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
Des actions comme setup-node et setup-python modifient le PATH et les variables d’environnement. Les binaires installés par une action sont disponibles dans toutes les étapes suivantes et dans maintenance. Seules les GitHub Actions basées sur Node.js sont prises en charge. Les actions composites et celles basées sur Docker ne le sont pas.
Vous n’avez pas besoin de GitHub Actions pour la configuration de base des outils. Des commandes shell directes (nvm install 20, curl ... | sh, apt-get install) fonctionnent tout aussi bien et sont souvent plus simples. Les GitHub Actions sont surtout utiles si vous voulez reproduire exactement votre configuration CI ou bénéficier de la praticité d’actions comme setup-java, qui gèrent plusieurs distributions.

Exemples full-stack

Ces exemples montrent comment les configurations Enterprise et celles au niveau de l’org se combinent. En pratique, vous les répartiriez entre plusieurs périmètres. Elles sont regroupées ici à titre de référence.
Un environnement d’entreprise complet : certificat d’autorité de certification d’entreprise, proxy, Java (Maven), Python (pip/uv), Node.js (npm) et Docker, le tout pointant vers une seule instance Artifactory.
Réseau et confiance (échelle du compte) :
  • CORP_ROOT_CA_B64 — certificat d’autorité de certification d’entreprise encodé en Base64
  • CORP_HTTP_PROXY — URL du proxy HTTP
  • CORP_HTTPS_PROXY — URL du proxy HTTPS
  • CORP_NO_PROXY — hôtes à ne pas faire passer par le proxy
Identifiants du registre (échelle de l’organisation) :
  • ARTIFACTORY_USER — nom d’utilisateur Artifactory
  • ARTIFACTORY_TOKEN — jeton d’API Artifactory ou mot de passe
  • ARTIFACTORY_MAVEN_URL — URL du dépôt Maven (p. ex., https://artifactory.example.com/artifactory/maven-virtual)
  • ARTIFACTORY_PYPI_URL — URL du dépôt PyPI (p. ex., https://user:token@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple)
  • ARTIFACTORY_NPM_URL — URL du dépôt npm (p. ex., https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • ARTIFACTORY_DOCKER_URL — URL du registre Docker (p. ex., artifactory.example.com)
Cela serait généralement réparti en trois périmètres :
  • À l’échelle du compte (initialize) : certificat et proxy
  • À l’échelle de l’organisation (initialize) : Installation des runtimes de langage
  • À l’échelle de l’organisation (maintenance) : Identifiants du registre (renouvelés à chaque session)
Présenté ici en version combinée pour référence :
initialize:
  # ── À l'échelle du compte : réseau et confiance ──────────────────────────────────────

  - 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

  # ── À l'échelle de l'organisation : environnements d'exécution ──────────────────────────────────────────

  - 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:
  # ── À l'échelle du compte : proxy git (actualisé à chaque session) ───────────────────

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

  # ── À l'échelle de l'organisation : identifiants de registre (actualisés à chaque 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
Dans cet exemple, tous les registres pointent vers la même instance Artifactory, mais utilisent des chemins d’URL différents. Chaque écosystème de packages a son propre format d’endpoint. Les URL Maven, PyPI, npm et Docker sont toutes différentes, même pour un même registre.
Lorsque différents langages utilisent des registres privés différents (par ex. Maven via Nexus, npm via GitHub Packages, Python via Artifactory).
  • NEXUS_MAVEN_URL — URL du dépôt Maven Nexus - NEXUS_USER — nom d’utilisateur Nexus - NEXUS_PASS — mot de passe Nexus - GITHUB_PACKAGES_TOKEN — jeton d’accès personnel GitHub avec le périmètre read:packages - ARTIFACTORY_USER — nom d’utilisateur Artifactory - ARTIFACTORY_TOKEN — jeton d’API Artifactory - GIT_TOKEN — jeton d’accès personnel pour les modules Go privés
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 (avec périmètre)
  - 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 → modules privés via git
  - name: Configure Go private modules
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
Dans un environnement totalement en air gap, Devin ne peut accéder à aucune URL publique. Tous les outils, environnements d’exécution et packages doivent provenir de miroirs internes.
Certificats :
  • CORP_ROOT_CA_B64 — certificat d’autorité de certification de l’entreprise encodé en Base64
Accès au miroir :
  • APT_MIRROR_URL — URL du miroir APT Ubuntu interne
  • MIRROR_USER — nom d’utilisateur d’authentification au miroir
  • MIRROR_PASS — mot de passe d’authentification au miroir
  • JDK_TARBALL_URL — URL pour télécharger l’archive tar du JDK depuis le miroir interne
  • NODE_TARBALL_URL — URL pour télécharger l’archive tar de Node.js depuis le miroir interne
Registres de packages :
  • INTERNAL_MAVEN_URL — URL du registre Maven interne
  • INTERNAL_NPM_URL — URL du registre npm interne
  • INTERNAL_PYPI_URL — URL du registre PyPI interne
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: |
      # Télécharger l'archive JDK depuis le dépôt d'artefacts interne
      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
Dans les environnements en air gap, tous les outils dont Devin a besoin (environnement d’exécution, outils CLI, etc.) doivent être disponibles sur vos miroirs internes. Les registres publics et les sites de téléchargement ne sont pas accessibles.
Une configuration Enterprise complète combinant la connectivité VPN avec des certificats, un proxy et la prise en charge multilingue. Voici l’ordre des opérations recommandé.
VPN :
  • VPN_CONFIG_B64 — fichier de configuration OpenVPN encodé en Base64
Réseau & confiance :
  • CORP_ROOT_CA_B64 — certificat d’autorité de certification d’entreprise encodé en Base64
  • CORP_HTTP_PROXY — URL du proxy HTTP
  • CORP_HTTPS_PROXY — URL du proxy HTTPS
  • CORP_NO_PROXY — hôtes à contourner via le proxy
Identifiants du registre :
  • MAVEN_REGISTRY_URL — URL du registre Maven
  • NPM_REGISTRY_URL — URL du registre npm
  • PYPI_REGISTRY_HOST — nom d’hôte du registre PyPI
  • REGISTRY_USER — nom d’utilisateur du registre (pour Maven et pip)
  • REGISTRY_PASS — mot de passe du registre (pour Maven et pip)
  • REGISTRY_TOKEN — jeton d’authentification npm
initialize:
  # 1. VPN — doit être configuré en premier pour que les ressources internes soient accessibles
  - 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 — résolution des noms d'hôtes internes
  - 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. Certificats — approuver les autorités de certification internes
  - 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 — acheminer le trafic via le proxy d'entreprise
  - 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. Environnements d'exécution
  - 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’ordre des étapes initialize est important. Le VPN doit venir en premier (pour que les hôtes internes soient accessibles), puis le DNS (pour que la résolution des noms fonctionne), puis les certificats (pour que HTTPS fonctionne), puis le proxy (pour que le trafic soit correctement acheminé), et enfin les environnements d’exécution (qui peuvent télécharger depuis des miroirs internes).

Conseils pour rédiger de bons blueprints

  • Testez d’abord les commandes dans une session. Exécutez-les manuellement dans une session Devin avant de les ajouter à votre blueprint. C’est plus rapide que d’attendre un cycle de build complet.
  • Utilisez initialize pour les outils à installer une seule fois, et maintenance pour les dépendances. Tout ce qui prend plusieurs minutes à installer (compilateurs, gros binaires, outils globaux) doit aller dans initialize. Les commandes de dépendances rapides (npm install, uv sync) vont dans maintenance.
  • Veillez à ce que les commandes maintenance restent rapides. Visez moins de 2 minutes. Elles s’exécutent au début de chaque session.
  • Utilisez $ENVRC pour les variables d’environnement. N’écrivez pas dans .bashrc ou .profile. $ENVRC est le mécanisme pris en charge pour définir des variables entre les étapes et les sessions.
  • Nommez vos étapes. La syntaxe développée avec des champs name permet d’identifier beaucoup plus facilement les échecs dans les journaux de build.
  • Utilisez des subshells pour les monorepos. (cd packages/foo && npm install) s’exécute dans un subshell afin que les étapes suivantes ne soient pas affectées par le changement de répertoire.
  • Utilisez npm install, pas npm ci. npm ci supprime node_modules et réinstalle tout depuis zéro à chaque session, ce qui est trop lent pour maintenance.
  • Utilisez les secrets du dépôt pour les valeurs sensibles. Configurez-les dans Settings > Secrets avec le périmètre du dépôt plutôt que de les coder en dur dans les blueprints.
Pour les détails de syntaxe, consultez la référence des blueprints. Pour résoudre les échecs de build, consultez Configuration déclarative > Dépannage.