Skip to main content
Blueprints prontos para copiar e colar para linguagens e casos de uso comuns. Cada template é independente. Combine-os para montar sua configuração completa. Para ver uma descrição completa de cada campo, consulte a referência de blueprints.
Segredos: Os templates fazem referência a segredos usando $SECRET_NAME. Configure-os em Configurações → Secrets antes de usar um template. Nunca inclua credenciais diretamente no seu blueprint.

Início rápido

Blueprints mínimos para as configurações mais comuns. Copie um, cole no editor de blueprints e pronto.
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      Execute `pnpm lint` para verificar erros.
  - name: test
    contents: |
      Execute `pnpm test` para o conjunto completo de testes.
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance: |
  uv sync

knowledge:
  - name: lint
    contents: |
      Execute `uv run ruff check .` para rodar o lint.
  - name: test
    contents: |
      Execute `uv run pytest` para o conjunto completo de testes.
initialize:
  - name: Instalar pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Dependências do frontend
    run: (cd frontend && pnpm install)
  - name: Dependências do backend
    run: (cd backend && uv sync)

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

Modelos de repositório

Etapas de build por repositório, gerenciamento de dependências e entradas do Knowledge. Defina isso em Configurações > Configuração de ambiente > [seu repositório].

Python

Configuração recomendada para projetos em Python que usam uv para gerenciamento de dependências.
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance: |
  uv sync

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

      Auto-Fix:
      uv run ruff check --fix .

  - name: test
    contents: |
      uv run pytest

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

Node.js

Configuração padrão do Node.js com 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
Use npm install (não npm ci) em maintenance. Ele faz uma atualização incremental, enquanto npm ci exclui node_modules e reinstala tudo do zero a cada sessão.

Go

Configuração padrão de Go com módulos.
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

Configuração do Java com Gradle.
O JDK 17 já vem pré-instalado na imagem base do Devin. Pule a etapa de instalação do JDK se o OpenJDK 17 padrão for suficiente.
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

Configuração do Rails com 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

Configuração padrão do Rust com Cargo.
Rust (via rustup) e Cargo já vêm pré-instalados na imagem base do Devin. Pule a etapa de instalação se a toolchain estável padrão for suficiente. Você só precisa baixar as dependências.
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 com frontend em Node.js e backend em Python. Cada subprojeto recebe suas próprias entradas no Knowledge.
initialize:
  - name: Instalar pnpm
    run: npm install -g pnpm
  - name: Instalar uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Instalar dependências do frontend
    run: (cd packages/frontend && pnpm install)
  - name: Instalar dependências do backend
    run: (cd packages/backend && uv sync)
  - name: Build da biblioteca compartilhada
    run: (cd packages/shared && pnpm install && pnpm build)

knowledge:
  - name: structure
    contents: |
      Este é um monorepo com três pacotes:
      - `packages/frontend` — app React (TypeScript, pnpm)
      - `packages/backend` — API Python (FastAPI, uv)
      - `packages/shared` — utilitários TypeScript compartilhados (o build deve ser feito antes do frontend)
  - name: frontend
    contents: |
      Execute `cd packages/frontend && pnpm dev` para iniciar o servidor de desenvolvimento.
      Execute `cd packages/frontend && pnpm lint` para rodar o lint.
      Execute `cd packages/frontend && pnpm test` para testar.
  - name: backend
    contents: |
      Execute `cd packages/backend && uv run uvicorn app.main:app --reload` para iniciar a API.
      Execute `cd packages/backend && uv run ruff check .` para rodar o lint.
      Execute `cd packages/backend && uv run pytest` para testar.
Use subshells (cd dir && command) em vez de cd dir && command, para que o diretório de trabalho seja redefinido entre as etapas.

Registros privados de pacotes

Configure os gerenciadores de pacotes para resolver dependências usando registros privados. Defina isso em Configurações > Configuração do ambiente > configuração em nível da organização (ou por repositório, se apenas um repositório precisar disso).
A configuração de credenciais deve ser feita em maintenance, não em initialize. Etapas que gravam segredos (senhas de registro, tokens de autenticação) em arquivos de configuração devem usar maintenance para que as credenciais sejam carregadas novamente em cada sessão. Os segredos são removidos antes de o snapshot ser salvo, portanto os arquivos de configuração gravados durante initialize não terão credenciais válidas quando as sessões começarem.
Se o seu registro privado usa uma CA corporativa, primeiro verifique se o certificado de CA está instalado no nível Enterprise. A configuração abaixo pressupõe que a confiança em HTTPS já foi estabelecida.

Registros do Node.js

Configure o npm para resolver pacotes com escopo (por exemplo, @myorg/*) a partir de um registro privado, enquanto os pacotes públicos continuam vindo do registro padrão do npm.
- GITHUB_PACKAGES_TOKEN — Token de acesso pessoal ou token do GitHub App com o escopo 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
Substitua @myorg pelo seu escopo do npm. URLs comuns de registros privados:
  • GitHub Packages: https://npm.pkg.github.com
  • Artifactory: https://artifactory.example.com/artifactory/api/npm/npm-virtual
  • Nexus: https://nexus.example.com/repository/npm-group
  • GitLab: https://gitlab.example.com/api/v4/packages/npm
  • AWS CodeArtifact: https://<domain>.d.codeartifact.<region>.amazonaws.com/npm/<repo>

Registros do Python

Configure o pip e o uv para resolver pacotes do seu registro PyPI privado (por exemplo, Nexus, Artifactory).
  • PYPI_REGISTRY_URL — URL completa do seu índice PyPI, incluindo credenciais, se necessário (por exemplo, https://user:token@nexus.example.com/repository/pypi-proxy/simple)
maintenance:
  - name: Configurar pip/uv para registro privado
    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
Padrões comuns de URL para registros 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

Registros da JVM

Instale o JDK e configure o Maven para usar seu registro privado como espelho para toda a resolução de dependências (por exemplo, Artifactory, Nexus).
O JDK 17 vem pré-instalado na imagem base do Devin. Pule a etapa de instalação se o OpenJDK 17 padrão for suficiente. Você só precisa instalar o Maven e configurar o registro.
  • MAVEN_REGISTRY_URL — URL do seu registro Maven (por exemplo, https://artifactory.example.com/artifactory/maven-virtual) - REGISTRY_USER — Nome de usuário do registro - REGISTRY_PASS — Senha do registro ou token de API
initialize:
  - name: Install JDK 17
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

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

maintenance:
  - name: Configure Maven for private registry
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>private-registry</id>
            <mirrorOf>*</mirrorOf>
            <url>$MAVEN_REGISTRY_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>private-registry</id>
            <username>$REGISTRY_USER</username>
            <password>$REGISTRY_PASS</password>
          </server>
        </servers>
      </settings>
      EOF
Padrões comuns de URL de registro do 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>

Outros registros

Instale o Go e configure-o para resolver módulos por meio de um proxy privado de módulos (por exemplo, Athens, Artifactory ou um endpoint do GOPROXY).
  • GO_PROXY_URL — URL do seu proxy de módulos Go (por exemplo, https://athens.corp.internal) - GIT_TOKEN — Token de acesso pessoal para repositórios Git privados que hospedam módulos 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/"
Padrões comuns de URLs de proxy do Go:
  • Artifactory: https://artifactory.example.com/artifactory/go-virtual
  • Nexus: https://nexus.example.com/repository/go-proxy
  • Athens: https://athens.corp.internal
Configure o NuGet para resolver pacotes a partir de um feed privado.
- NUGET_SOURCE_URL — URL do seu feed do NuGet - NUGET_API_KEY — Chave de API ou PAT para o 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
Configure o Docker para baixar imagens de um registro privado de contêineres.
  • DOCKER_MIRROR_URL (opcional) — URL do seu espelho do Docker Hub (por exemplo, https://mirror.corp.internal) - DOCKER_REGISTRY_URL — URL do seu registro privado de contêineres (por exemplo, registry.corp.internal:5000) - DOCKER_REGISTRY_USER — Nome de usuário do registro - DOCKER_REGISTRY_PASS — Senha do registro ou token de API
initialize:
  - name: Create Docker config directory
    run: sudo mkdir -p /etc/docker

maintenance:
  - name: Configure Docker for private registry
    run: |
      # Configurar mirror de registro (opcional — roteia pulls do Docker Hub pelo seu registro)
      cat << EOF | sudo tee /etc/docker/daemon.json > /dev/null
      {
        "registry-mirrors": ["$DOCKER_MIRROR_URL"]
      }
      EOF
      sudo systemctl restart docker || true

      # Fazer login no registro privado de contêineres
      echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
        --username "$DOCKER_REGISTRY_USER" \
        --password-stdin
URLs comuns de registros de contêineres:
  • 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
Configure o Cargo para resolver crates a partir de um registro privado.
Rust (via rustup) e Cargo vêm pré-instalados na imagem base do Devin. Pule a etapa de instalação se o toolchain estável padrão for suficiente. Você só precisa da configuração do registro.
  • CARGO_REGISTRY_INDEX — URL do índice do registro privado (por exemplo, sparse+https://cargo.corp.internal/api/v1/crates/) - CARGO_REGISTRY_TOKEN — token de autenticação para o registro privado
initialize:
  - name: Install Rust
    run: |
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
        | sh -s -- -y --default-toolchain stable
      echo 'source "$HOME/.cargo/env"' \
        | sudo tee /etc/profile.d/rust.sh > /dev/null

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

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

      [source.private]
      registry = "$CARGO_REGISTRY_INDEX"
      EOF
Se você só precisa adicionar um registro privado sem substituir o crates.io, remova as seções [source.crates-io] e [source.private] e use cargo install --registry private ou [dependencies] my-crate = { version = "1.0", registry = "private" } no Cargo.toml.
Instale o Ruby e configure o Bundler para resolver gems a partir de um servidor privado de gems.
  • GEM_SERVER_URL — URL do seu servidor privado de gems (por exemplo, https://artifactory.example.com/artifactory/api/gems/gems-virtual) - REGISTRY_USER — nome de usuário do registro - REGISTRY_PASS — senha do registro ou token de API
initialize:
  - name: Install Ruby
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ruby-full

maintenance:
  - name: Configure Bundler for private gem server
    run: |
      bundle config set mirror.https://rubygems.org "$GEM_SERVER_URL"
      bundle config set "$GEM_SERVER_URL" "$REGISTRY_USER:$REGISTRY_PASS"
Padrões comuns de URL para servidores 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>
Instale o PHP e configure o Composer para resolver pacotes a partir de um registro privado do Packagist ou do Satis.
  • COMPOSER_REGISTRY_URL — URL do seu registro privado do Composer (por exemplo, https://repo.packagist.com/<org>)
  • REGISTRY_USER — Nome de usuário do registro
  • REGISTRY_PASS — Senha do registro ou token de API
initialize:
  - name: Install PHP and Composer
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
        php-cli php-mbstring php-xml php-curl unzip

      # Instalar o 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"

      # Autenticar no registro
      composer config --global http-basic.$(echo "$COMPOSER_REGISTRY_URL" \
        | sed 's|https\?://||;s|/.*||') "$REGISTRY_USER" "$REGISTRY_PASS"
Padrões comuns de URL de registros do 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
Os tokens do AWS CodeArtifact expiram após 12 horas. Use maintenance para renovar o token no início de cada sessão. Este exemplo configura npm, pip e Maven para usar o CodeArtifact.
awscli vem pré-instalado na imagem base do Devin. Você só precisa renovar o token e configurar o registro.
  • AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY — credenciais do IAM com as permissões codeartifact:GetAuthorizationToken e sts:GetServiceBearerToken - CA_DOMAIN — Nome do seu domínio do CodeArtifact name - CA_DOMAIN_OWNER — ID da conta AWS proprietária do domínio - CA_REGION — Região da AWS (por exemplo, us-east-1) - CA_NPM_REPO, CA_PYPI_REPO, CA_MAVEN_REPO — Nomes dos repositórios para cada ecossistema
maintenance:
  - name: Refresh CodeArtifact auth token
    run: |
      # Obter um token atualizado (válido por 12 horas)
      export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token \
        --domain $CA_DOMAIN \
        --domain-owner $CA_DOMAIN_OWNER \
        --region $CA_REGION \
        --query authorizationToken \
        --output text)

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

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

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

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

Infraestrutura do Enterprise

Infraestrutura no nível da máquina que se aplica a todas as org e repositórios. Configure isso em Configurações > ambiente base do Devin (para toda a Enterprise) ou em Configurações > Configuração do ambiente > Configuração no nível da organização (no nível da organização).

Rede e conectividade

Sua organização usa uma autoridade certificadora privada para serviços internos. Devin precisa do certificado raiz para acessar registros e ferramentas internos via HTTPS.
- CORP_ROOT_CA_B64 — certificado PEM codificado em Base64 da sua CA corporativa. Gere com: 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 a sua organização usar vários certificados de CA (por exemplo, CAs separadas para diferentes serviços internos).
- CORP_ROOT_CA_B64 — certificado de CA principal codificado em Base64 - CORP_INTERMEDIATE_CA_B64 — certificado de CA intermediário codificado em 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

      # Cria um pacote combinado para ferramentas que precisam de um único arquivo de 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
Encaminhe todo o tráfego de rede por meio de um proxy corporativo.
  • CORP_HTTP_PROXY — URL do proxy HTTP (por exemplo, http://proxy.corp.example.com:8080) - CORP_HTTPS_PROXY — URL do proxy HTTPS - CORP_NO_PROXY — Lista de hosts separados por vírgula que devem ignorar o proxy (por exemplo, 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"

      # Configurar proxy do npm
      npm config set proxy "$CORP_HTTP_PROXY"
      npm config set https-proxy "$CORP_HTTPS_PROXY"
Se o seu proxy corporativo exigir autenticação com nome de usuário e senha.
  • PROXY_USER — Nome de usuário do proxy - PROXY_PASS — Senha do proxy - PROXY_HOST — Host e porta do proxy (por exemplo, proxy.corp.example.com:8080) - CORP_NO_PROXY — Hosts que devem ignorar o 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"
Configuração combinada para ambientes que exigem tanto uma CA corporativa quanto um proxy. Isso é comum em ambientes corporativos em que serviços internos usam certificados privados e todo o tráfego precisa passar por um proxy.
  • CORP_ROOT_CA_B64 — certificado de CA corporativa codificado em Base64 - CORP_HTTP_PROXY, CORP_HTTPS_PROXY — URLs do proxy - CORP_NO_PROXY — Hosts que ignoram o 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"
Seus registros privados, servidores Git ou outros serviços internos só podem ser acessados por VPN. Isso precisa ser executado antes de outros módulos que exigem acesso de rede a recursos internos.
OpenVPN:
  • VPN_CONFIG_B64 — Arquivo de configuração do OpenVPN (.ovpn) codificado em Base64. Gere com: cat corp.ovpn | base64 -w0
  • VPN_AUTH_USER (opcional) — Nome de usuário da VPN, caso sua VPN exija autenticação com nome de usuário e senha
  • VPN_AUTH_PASS (opcional) — Senha da VPN
WireGuard:
  • WG_CONFIG_B64 — Arquivo de configuração do WireGuard codificado em Base64. Gere com: 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

      # Escrever a configuração da VPN
      sudo mkdir -p /etc/openvpn/client
      echo "$VPN_CONFIG_B64" | base64 -d \
        | sudo tee /etc/openvpn/client/corp.conf > /dev/null

      # Se a VPN exigir autenticação por usuário/senha
      if [ -n "${VPN_AUTH_USER:-}" ] && [ -n "${VPN_AUTH_PASS:-}" ]; then
        printf '%s\n%s\n' "$VPN_AUTH_USER" "$VPN_AUTH_PASS" \
          | sudo tee /etc/openvpn/client/auth.txt > /dev/null
        sudo chmod 600 /etc/openvpn/client/auth.txt
        echo "auth-user-pass /etc/openvpn/client/auth.txt" \
          | sudo tee -a /etc/openvpn/client/corp.conf > /dev/null
      fi

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

      # Aguardar o túnel ser estabelecido
      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

      # Gravar a configuração do WireGuard
      echo "$WG_CONFIG_B64" | base64 -d \
        | sudo tee /etc/wireguard/wg0.conf > /dev/null
      sudo chmod 600 /etc/wireguard/wg0.conf

      # Iniciar o túnel
      sudo systemctl enable --now wg-quick@wg0
Para mais detalhes sobre a configuração da VPN, consulte Configuração da VPN.
Seus serviços internos usam nomes de DNS privados que não são resolvidos pelo DNS público.
initialize:
  - name: Configure custom DNS resolution
    run: |
      # Adicionar hostnames internos
      cat << 'HOSTS' | sudo tee -a /etc/hosts > /dev/null
      10.0.1.50  nexus.corp.internal
      10.0.1.51  git.corp.internal
      10.0.1.52  artifactory.corp.internal
      HOSTS

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

Identidade e segurança

Sua organização exige que todos os commits do Git sejam assinados, e você quer que o GitHub marque os commits do Devin como Verified.
  • GPG_PRIVATE_KEY_B64 — Chave privada GPG codificada em Base64. Gere com: gpg --export-secret-keys <key-id> | base64 -w0
  • GIT_USER_NAME — Nome do autor no Git (por exemplo, Devin AI)
  • GIT_USER_EMAIL — Email do autor no Git. Deve corresponder a um UID da chave GPG; caso contrário, o GitHub não verificará a assinatura.
Além disso, importe a chave pública correspondente para a conta do GitHub cujas credenciais o Devin usa para fazer push (em Configurações do GitHub > SSH and GPG keys). O GitHub só marca commits como Verified quando a chave pública usada na assinatura está registrada na conta que criou o commit.
initialize:
  - name: Prepare GPG and git signing config
    run: |
      # Permitir que o GPG funcione sem um 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
Configure a identidade do Git e as chaves SSH do Devin para acessar servidores Git privados.
  • GIT_USER_NAME — Nome do autor no Git - GIT_USER_EMAIL — Email do autor no Git - SSH_PRIVATE_KEY_B64 — Chave privada SSH codificada em Base64. Gere com: cat ~/.ssh/id_ed25519 | base64 -w0 - SSH_KNOWN_HOSTS_B64 — Entradas de hosts conhecidos codificadas em Base64. Gere com: ssh-keyscan git.corp.internal | base64 -w0 - SSH_CONFIG_B64 (opcional) — Arquivo de configuração SSH codificado em Base64
initialize:
  - name: Configure git identity
    run: |
      git config --global user.name "$GIT_USER_NAME"
      git config --global user.email "$GIT_USER_EMAIL"

      # Preparar o diretório SSH
      mkdir -p ~/.ssh && chmod 700 ~/.ssh

maintenance:
  - name: Install SSH keys
    run: |
      # Instalar a chave privada SSH (em maintenance para que seja recarregada a cada sessão)
      echo "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
      chmod 600 ~/.ssh/id_ed25519

      # Adicionar hosts conhecidos para seu servidor Git
      echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

      # Opcionalmente, instalar uma configuração SSH personalizada
      if [ -n "${SSH_CONFIG_B64:-}" ]; then
        echo "$SSH_CONFIG_B64" | base64 -d > ~/.ssh/config
        chmod 600 ~/.ssh/config
      fi
Gere a entrada de hosts conhecidos para seu servidor Git com ssh-keyscan git.corp.internal | base64 -w0.

Configuração do sistema

Instale pacotes no nível do sistema que não estão na imagem padrão do Devin (por exemplo, bibliotecas nativas para processamento de imagens ou geração 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
Defina variáveis de ambiente persistentes que devem estar disponíveis em todas as sessões.A abordagem recomendada é gravar linhas KEY=VALUE no arquivo $ENVRC. As variáveis gravadas em $ENVRC são exportadas automaticamente para todas as etapas seguintes e para a sessão do Devin (semelhante ao $GITHUB_ENV do GitHub Actions).
initialize:
  - name: Definir variáveis de ambiente personalizadas
    run: |
      echo "CORPORATE_ENV=production" >> $ENVRC
      echo "DEFAULT_REGION=us-east-1" >> $ENVRC
      echo "MAX_RETRIES=3" >> $ENVRC
Você também pode definir variáveis de ambiente em scripts de /etc/profile.d/ para que fiquem disponíveis em todo o sistema:
cat << 'ENVVARS' | sudo tee /etc/profile.d/custom-env.sh > /dev/null
export CORPORATE_ENV=production
export DEFAULT_REGION=us-east-1
ENVVARS
As duas abordagens funcionam. $ENVRC é mais simples e recomendado na maioria dos casos.
As imagens base padrão podem ter configurações de localidade incorretas. Configure a localidade e o fuso horário para evitar avisos de ferramentas de 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

      # Gerar e definir o 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

      # Definir fuso horário
      sudo timedatectl set-timezone UTC 2>/dev/null || \
        sudo ln -sfn /usr/share/zoneinfo/UTC /etc/localtime
Builds em Java, Gradle e Node.js frequentemente esbarram no limite padrão de 1024 arquivos abertos. Aumente esse limite para evitar falhas de 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

      # Também define o máximo do 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
Em ambientes sem conexão com a internet ou restritos, substitua as fontes APT padrão do Ubuntu por um espelho interno.
- APT_MIRROR_URL — URL do seu espelho APT interno (por exemplo, https://artifactory.example.com/artifactory/ubuntu-remote)
initialize:
  - name: Replace APT sources with internal mirror
    run: |
      # Fazer backup das fontes originais
      sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

      # Substituir todos os mirrors do Ubuntu pelo 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
Padrões comuns de URL de espelhos APT:
  • Artifactory: https://artifactory.example.com/artifactory/ubuntu-remote
  • Nexus: https://nexus.example.com/repository/ubuntu-proxy

Padrões avançados

O ambiente base do Devin inclui direnv. Use initialize para criar arquivos .envrc. O direnv os carrega 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 .
O direnv já vem integrado ao shell do Devin, então as variáveis de .envrc são carregadas automaticamente. Não é preciso executar source manualmente.
Para variáveis de ambiente sensíveis (chaves de API, tokens, senhas de banco de dados), use segredos do repositório em vez de arquivos .envrc. Os segredos do repositório são armazenados com segurança e injetados durante a sessão. Eles nunca aparecem no seu blueprint nem no snapshot.
Use o nvm (pré-instalado) para alternar entre versões do Node.js em cada repositório via .nvmrc.
initialize: |
  nvm install 18
  nvm install 20
  nvm install 22

maintenance: |
  nvm use
nvm use lê o .nvmrc na raiz do repo. Certifique-se de que seu repositório tenha esse arquivo (por exemplo, com 20).
O Devin fornece um navegador Chrome com um endpoint CDP em localhost:29229 durante as sessões. Use scripts do Playwright para automatizar o login no navegador.
O navegador só está disponível durante as sessões, não em builds do snapshot. Instale o Playwright em initialize e mantenha os scripts de login no seu repositório.
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
Exemplo de script de login (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")
Armazene as credenciais de login como segredos, não no código-fonte. Para autenticação de longo prazo, faça commit dos scripts de login em .agents/skills/ para que o Devin possa se reautenticar automaticamente.
Instale pacotes do sistema, binários personalizados e configure o PATH em 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 oferece suporte à execução de GitHub Actions baseadas em Node.js diretamente em blueprints. Isso é útil para instalar versões específicas de ferramentas usando as mesmas actions usadas pela sua 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
Ações como setup-node e setup-python alteram o PATH e as variáveis de ambiente. Os binários instalados por uma ação ficam disponíveis em todas as etapas seguintes e em maintenance. Apenas GitHub Actions baseadas em Node.js são compatíveis. Ações compostas e baseadas em Docker não são.
Você não precisa de GitHub Actions para a configuração básica de ferramentas. Comandos shell diretos (nvm install 20, curl ... | sh, apt-get install) funcionam tão bem quanto e geralmente são mais simples. GitHub Actions são mais úteis quando você quer replicar exatamente sua configuração de CI ou precisa da praticidade de ações como setup-java, que lidam com várias distribuições.

Exemplos full-stack

Estes exemplos mostram como as configurações do Enterprise e no nível da organização se combinam. Na prática, você as dividiria entre diferentes escopos. Elas são apresentadas juntas aqui como referência.
Um ambiente Enterprise completo: certificado de CA corporativo, proxy, Java (Maven), Python (pip/uv), Node.js (npm) e Docker, todos apontando para uma única instância do Artifactory.
Rede e confiança (nível da conta):
  • CORP_ROOT_CA_B64 — certificado de CA corporativa codificado em Base64
  • CORP_HTTP_PROXY — URL do proxy HTTP
  • CORP_HTTPS_PROXY — URL do proxy HTTPS
  • CORP_NO_PROXY — hosts que devem ignorar o proxy
Credenciais do registro (nível da organização):
  • ARTIFACTORY_USER — nome de usuário do Artifactory
  • ARTIFACTORY_TOKEN — token de API ou senha do Artifactory
  • ARTIFACTORY_MAVEN_URL — URL do repositório Maven (por exemplo, https://artifactory.example.com/artifactory/maven-virtual)
  • ARTIFACTORY_PYPI_URL — URL do repositório PyPI (por exemplo, https://user:token@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple)
  • ARTIFACTORY_NPM_URL — URL do repositório npm (por exemplo, https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • ARTIFACTORY_DOCKER_URL — URL do registro do Docker (por exemplo, artifactory.example.com)
Isso normalmente seria dividido em três escopos:
  • Nível da conta (initialize): Certificado e proxy
  • Nível da organização (initialize): Instalação de runtimes de linguagem
  • No nível da organização (maintenance): Credenciais do registro (atualizadas a cada sessão)
Exibido aqui de forma combinada para referência:
initialize:
  # ── Nível da conta: rede e confiança ──────────────────────────────────────

  - 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

  # ── Nível da organização: 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:
  # ── Nível da conta: proxy git (atualizado a cada sessão) ───────────────────

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

  # ── Nível da organização: credenciais de registro (atualizadas a cada sessão) ──────────────

  - 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
Neste exemplo, todos os registros apontam para a mesma instância do Artifactory, mas usam caminhos de URL diferentes. Cada ecossistema de pacotes tem seu próprio formato de endpoint. As URLs de Maven, PyPI, npm e Docker são diferentes entre si, mesmo no mesmo registro.
Quando diferentes linguagens usam registros privados diferentes (por exemplo, Maven no Nexus, npm no GitHub Packages, Python no Artifactory).
  • NEXUS_MAVEN_URL — URL do repositório Maven no Nexus - NEXUS_USER — nome de usuário do Nexus - NEXUS_PASS — senha do Nexus - GITHUB_PACKAGES_TOKEN — token de acesso pessoal do GitHub com escopo read:packages - ARTIFACTORY_USER — nome de usuário do Artifactory - ARTIFACTORY_TOKEN — token de API do Artifactory - GIT_TOKEN — token de acesso pessoal para módulos privados do Go
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 (com escopo)
  - 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 → módulos privados via git
  - name: Configure Go private modules
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
Em um ambiente totalmente isolado, o Devin não consegue acessar URLs públicas. Todas as ferramentas, runtimes e pacotes devem vir de mirrors internos.
Certificados:
  • CORP_ROOT_CA_B64 — certificado de CA corporativa codificado em Base64
Acesso ao mirror:
  • APT_MIRROR_URL — URL do mirror APT interno do Ubuntu
  • MIRROR_USER — nome de usuário para autenticação no mirror
  • MIRROR_PASS — senha para autenticação no mirror
  • JDK_TARBALL_URL — URL para baixar o tarball do JDK do mirror interno
  • NODE_TARBALL_URL — URL para baixar o tarball do Node.js do mirror interno
Registros de pacotes:
  • INTERNAL_MAVEN_URL — URL do registro Maven interno
  • INTERNAL_NPM_URL — URL do registro npm interno
  • INTERNAL_PYPI_URL — URL do registro 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: |
      # Baixar o tarball do JDK do repositório de artefatos 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
Em ambientes isolados da internet, todas as ferramentas de que o Devin precisa (runtimes de linguagem, ferramentas de CLI etc.) devem estar disponíveis nos seus mirrors internos. Registros públicos e sites de download não podem ser acessados.
Uma configuração Enterprise completa que combina conectividade VPN com certificados, proxy e suporte a múltiplos idiomas. Esta é a ordem de operações recomendada.
VPN:
  • VPN_CONFIG_B64 — arquivo de configuração do OpenVPN codificado em Base64
Rede & confiança:
  • CORP_ROOT_CA_B64 — certificado de CA corporativa codificado em Base64
  • CORP_HTTP_PROXY — URL do proxy HTTP
  • CORP_HTTPS_PROXY — URL do proxy HTTPS
  • CORP_NO_PROXY — hosts que devem ignorar o proxy
Credenciais do registro:
  • MAVEN_REGISTRY_URL — URL do registro do Maven
  • NPM_REGISTRY_URL — URL do registro do npm
  • PYPI_REGISTRY_HOST — hostname do registro do PyPI
  • REGISTRY_USER — nome de usuário do registro (para Maven e pip)
  • REGISTRY_PASS — senha do registro (para Maven e pip)
  • REGISTRY_TOKEN — token de autenticação do npm
initialize:
  # 1. VPN — deve vir primeiro para que os recursos internos sejam acessíveis
  - 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 — resolve hostnames internos
  - name: Configure DNS
    run: |
      sudo mkdir -p /etc/systemd/resolved.conf.d
      cat << 'DNS' | sudo tee /etc/systemd/resolved.conf.d/corp.conf > /dev/null
      [Resolve]
      DNS=10.0.0.53
      Domains=corp.internal
      DNS
      sudo systemctl restart systemd-resolved || true

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

  # 4. Proxy — rotear o tráfego pelo proxy corporativo
  - name: Configure proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

  # 5. Runtimes de linguagem
  - 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
A ordem das etapas de initialize importa. A VPN deve vir primeiro (para que os hosts internos fiquem acessíveis), depois o DNS (para que os nomes sejam resolvidos), depois os certificados (para que o HTTPS funcione), depois o proxy (para que o tráfego seja roteado corretamente) e, por fim, os runtimes de linguagem (que podem fazer download de mirrors internos).

Dicas para escrever bons blueprints

  • Teste os comandos primeiro em uma sessão. Execute os comandos manualmente em uma sessão do Devin antes de adicioná-los ao blueprint. Isso é mais rápido do que esperar um ciclo completo de build.
  • Use initialize para ferramentas instaladas uma única vez e maintenance para dependências. Tudo o que leva minutos para instalar (compiladores, binários grandes, ferramentas globais) deve ficar em initialize. Comandos rápidos de dependência (npm install, uv sync) entram em maintenance.
  • Mantenha os comandos de maintenance rápidos. Procure ficar abaixo de 2 minutos. Eles são executados no início de cada sessão.
  • Use $ENVRC para variáveis de ambiente. Não escreva em .bashrc nem em .profile. $ENVRC é o mecanismo suportado para definir variáveis entre etapas e sessões.
  • Dê nomes às suas etapas. A forma expandida com campos name facilita muito identificar falhas nos logs de build.
  • Use subshells para monorepos. (cd packages/foo && npm install) é executado em um subshell, então as etapas seguintes não são afetadas pela mudança de diretório.
  • Use npm install, não npm ci. npm ci apaga node_modules e reinstala tudo do zero em cada sessão, o que é lento para maintenance.
  • Use secrets do repositório para valores sensíveis. Configure-os em Configurações → Secrets com escopo de repositório, em vez de embuti-los nos blueprints.
Para detalhes de sintaxe, consulte a referência de blueprint. Para solucionar problemas de falhas de build, consulte Configuração declarativa > Solução de problemas.