Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.devin.ai/llms.txt

Use this file to discover all available pages before exploring further.

适用于常见语言和使用场景的可直接复制粘贴蓝图。每个模板都可独立使用。组合使用即可构建完整配置。 如需查看每个字段的完整说明,请参阅 蓝图参考
Secrets: 模板使用 $SECRET_NAME 引用 secrets。使用模板前,请先在每个蓝图编辑器的 Secrets 选项卡中配置好这些 secrets。切勿在蓝图中硬编码凭据。

快速开始

适用于最常见配置的精简蓝图。复制其中一个,粘贴到蓝图编辑器中即可。
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      运行 `pnpm lint` 检查错误。
  - name: test
    contents: |
      运行 `pnpm test` 执行完整测试套件。
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance: |
  uv sync

knowledge:
  - name: lint
    contents: |
      运行 `uv run ruff check .` 进行 lint 检查。
  - name: test
    contents: |
      运行 `uv run pytest` 执行完整测试套件。
initialize:
  - name: Install pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: 前端依赖
    run: (cd frontend && pnpm install)
  - name: 后端依赖
    run: (cd backend && uv sync)

knowledge:
  - name: structure
    contents: |
      - `frontend/` — React 应用(pnpm)
      - `backend/` — Python API(uv)
  - name: test
    contents: |
      前端:cd frontend && pnpm test
      后端:cd backend && uv run pytest

仓库蓝图

按仓库设置的构建步骤、依赖管理和 Knowledge 条目。请在 Settings > Environment > Blueprints > [你的仓库] 中进行设置。

Python

适用于使用 uv 进行依赖管理的 Python 项目的推荐设置。
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

使用 npm 的标准 Node.js 配置。
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
maintenance 中使用 npm install (不要用 npm ci) 。前者会执行增量更新,而 npm ci 会在每个会话中删除 node_modules,并从头重新安装。

Go

标准 Go 模块配置。
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

使用 Gradle 配置 Java 环境。
JDK 17 已预装在 Devin 的基础镜像中。如果默认的 OpenJDK 17 已满足需求,可跳过 JDK 安装步骤。
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

基于 PostgreSQL 的 Rails 配置。
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

使用 cargo 的标准 Rust 配置。
Rust (通过 rustup) 和 Cargo预装在 Devin 的基础镜像中。如果默认的稳定工具链已能满足需求,请跳过安装步骤。你只需拉取依赖。
initialize: |
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
  source ~/.cargo/env

maintenance: |
  cargo fetch

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

  - name: test
    contents: |
      cargo test

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

Monorepo

包含 Node.js 前端和 Python 后端的 Monorepo。每个子项目都有各自的 knowledge 条目。
initialize:
  - name: Install pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

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

knowledge:
  - name: structure
    contents: |
      这是一个包含三个软件包的 monorepo:
      - `packages/frontend` — React 应用(TypeScript、pnpm)
      - `packages/backend` — Python API(FastAPI、uv)
      - `packages/shared` — 共享 TypeScript 工具库(必须先于前端构建)
  - name: frontend
    contents: |
      运行 `cd packages/frontend && pnpm dev` 启动开发服务器。
      运行 `cd packages/frontend && pnpm lint` 执行 lint 检查。
      运行 `cd packages/frontend && pnpm test` 运行测试。
  - name: backend
    contents: |
      运行 `cd packages/backend && uv run uvicorn app.main:app --reload` 启动 API。
      运行 `cd packages/backend && uv run ruff check .` 执行 lint 检查。
      运行 `cd packages/backend && uv run pytest` 运行测试。
使用 subshell (cd dir && command),不要使用 cd dir && command,这样每个步骤之间都会重置工作目录。

私有包注册表

将包管理器配置为从私有注册表解析依赖。在 Settings > Environment > Blueprints > 组织范围设置 中进行设置 (如果只有一个 仓库 需要,则可按 仓库 单独设置) 。
凭据配置应放在 maintenance 中,而不是 initialize 中。 将 secrets (注册表密码、身份验证令牌) 写入配置文件的步骤应使用 maintenance,这样每个 session 都会重新加载最新凭据。 secrets 会在保存快照前被移除,因此在 initialize 期间写入的配置文件,在 sessions 启动时将不包含有效凭据。
如果你的私有注册表使用 corporate CA,请先确保已在企业级别安装 CA 证书。以下配置假定 HTTPS 信任 已经建立。

Node.js 注册表

将 npm 配置为从私有 registry 解析带作用域的软件包 (例如 @myorg/*) ,同时公开软件包仍从默认的 npm registry 获取。
- GITHUB_PACKAGES_TOKEN — 具有 read:packages 作用域的 Personal access token 或 GitHub App 令牌
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
@myorg 替换为你的 npm 作用域。常见的私有 registry URL:
  • 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>

Python 软件包注册表

配置 pip 和 uv,使其从你的私有 PyPI registry (例如 Nexus、Artifactory) 解析软件包。
  • PYPI_REGISTRY_URL — 你的 PyPI 索引完整 URL,如有需要请包含凭据 (例如 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
常见的 PyPI registry URL 模式:
  • 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

JVM 软件包注册表

安装 JDK,并将 Maven 配置为通过你的私有 registry (例如 Artifactory、Nexus) 镜像所有依赖解析。
JDK 17 已在 Devin 的基础镜像中预装。如果默认的 OpenJDK 17 足够使用,请跳过安装步骤。你只需安装 Maven 并配置 registry。
  • MAVEN_REGISTRY_URL — 你的 Maven registry URL (例如 https://artifactory.example.com/artifactory/maven-virtual) - REGISTRY_USER — registry 用户名 - REGISTRY_PASS — registry 密码或 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
Maven 常见的注册表 URL 模式:
  • 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>

其他软件包注册表

安装 Go,并将其配置为通过私有模块代理 (例如 Athens、Artifactory 或 GOPROXY 端点) 解析模块。
  • GO_PROXY_URL — 你的 Go 模块代理 URL (例如 https://athens.corp.internal)
  • GIT_TOKEN — 用于托管 Go 模块的私有 Git repo 的 Personal Access Token
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/"
常见的 Go 代理 URL 格式:
  • Artifactory: https://artifactory.example.com/artifactory/go-virtual
  • Nexus: https://nexus.example.com/repository/go-proxy
  • Athens: https://athens.corp.internal
配置 NuGet,以从私有源解析软件包。
  • NUGET_SOURCE_URL — 你的 NuGet 源 URL
  • NUGET_API_KEY — 该源的 API key 或 PAT
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
配置 Docker 从私有容器注册表拉取镜像。
  • DOCKER_MIRROR_URL (可选) — 你的 Docker Hub 镜像源 URL (例如 https://mirror.corp.internal)
  • DOCKER_REGISTRY_URL — 你的私有容器注册表 URL (例如 registry.corp.internal:5000)
  • DOCKER_REGISTRY_USER — 注册表用户名
  • DOCKER_REGISTRY_PASS — 注册表密码或 API 令牌
initialize:
  - name: Create Docker config directory
    run: sudo mkdir -p /etc/docker

maintenance:
  - name: Configure Docker for private registry
    run: |
      # 配置注册表镜像(可选 — 通过你的注册表转发 Docker Hub 拉取请求)
      cat << EOF | sudo tee /etc/docker/daemon.json > /dev/null
      {
        "registry-mirrors": ["$DOCKER_MIRROR_URL"]
      }
      EOF
      sudo systemctl restart docker || true

      # 登录私有容器注册表
      echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
        --username "$DOCKER_REGISTRY_USER" \
        --password-stdin
常见容器注册表 URL:
  • 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
配置 Cargo,以从私有 registry 解析 crates。
Rust (通过 rustup) 和 Cargo预装在 Devin 的基础镜像中。如果默认的 stable 工具链已足够,请跳过安装步骤。你只需要配置 registry。
  • CARGO_REGISTRY_INDEX — 私有 registry index 的 URL (e.g., sparse+https://cargo.corp.internal/api/v1/crates/)
  • CARGO_REGISTRY_TOKEN — 私有 registry 的身份验证令牌
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
如果你只想添加私有注册表,而不替换 crates.io,请删除 [source.crates-io][source.private] 配置段,并使用 cargo install --registry private,或在 Cargo.toml 中使用 [dependencies] my-crate = { version = "1.0", registry = "private" }
安装 Ruby 并配置 Bundler,以便从私有 gem 服务器解析 gem。
  • GEM_SERVER_URL — 你的私有 gem 服务器的 URL (例如:https://artifactory.example.com/artifactory/api/gems/gems-virtual)
  • REGISTRY_USER — Registry 用户名
  • REGISTRY_PASS — Registry 密码或 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"
常见的 gem server URL 格式:
  • Artifactory: https://artifactory.example.com/artifactory/api/gems/gems-virtual
  • Nexus: https://nexus.example.com/repository/rubygems-proxy
  • Gemfury: https://gem.fury.io/<org>
安装 PHP 并配置 Composer,以便从私有 Packagist 或 Satis 注册表解析软件包。
  • COMPOSER_REGISTRY_URL — 你的私有 Composer 注册表的 URL (例如:https://repo.packagist.com/<org>)
  • REGISTRY_USER — 注册表用户名
  • REGISTRY_PASS — 注册表密码或 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

      # 安装 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"

      # 向镜像仓库进行身份验证
      composer config --global http-basic.$(echo "$COMPOSER_REGISTRY_URL" \
        | sed 's|https\?://||;s|/.*||') "$REGISTRY_USER" "$REGISTRY_PASS"
常见的 Composer 注册表 URL 格式:
  • 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
AWS CodeArtifact 令牌会在 12 小时后过期。请使用 maintenance 设置令牌刷新命令,以便 Agent 在需要时可重新运行该命令。此示例会将 npm、pip 和 Maven 配置为使用 CodeArtifact。
awscli 已预装在 Devin 的基础镜像中。你只需要刷新令牌并配置 registry。
  • AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY — 具有 codeartifact:GetAuthorizationTokensts:GetServiceBearerToken 权限的 IAM 凭据
  • CA_DOMAIN — 你的 CodeArtifact 域名
  • CA_DOMAIN_OWNER — 拥有该域的 AWS 账户 ID
  • CA_REGION — AWS 区域 (例如 us-east-1)
  • CA_NPM_REPO, CA_PYPI_REPO, CA_MAVEN_REPO — 各生态对应的仓库名称
maintenance:
  - name: Refresh CodeArtifact auth token
    run: |
      # 获取新令牌(有效期 12 小时)
      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"

      # 配置 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"

      # 配置 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

      # 配置 Maven(可选)
      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

企业基础架构

适用于所有组织和代码仓库的机器级基础架构。可在 Settings > Devin’s base environment (企业范围) 或 Settings > Environment > Blueprints > Org-wide setup (组织范围) 中进行设置。

网络与连接

你的组织为内部服务使用私有证书颁发机构 (CA) 。Devin 需要根证书,才能通过 HTTPS 访问内部制品库和工具。
- CORP_ROOT_CA_B64 — 来自你的企业 CA 的 Base64 编码 PEM 证书。可使用以下命令生成: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
如果你的组织使用多个 CA 证书 (例如,不同的内部服务分别使用不同的 CA) 。
- CORP_ROOT_CA_B64 — Base64 编码的主 CA 证书 - CORP_INTERMEDIATE_CA_B64 — Base64 编码的中间 CA 证书
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

      # 为需要单个 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
使所有网络流量都通过企业代理转发。
  • CORP_HTTP_PROXY — HTTP 代理 URL (例如:http://proxy.corp.example.com:8080) - CORP_HTTPS_PROXY — HTTPS 代理 URL - CORP_NO_PROXY — 以逗号分隔的绕过代理的主机列表 (例如: 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"

      # 配置 npm 代理
      npm config set proxy "$CORP_HTTP_PROXY"
      npm config set https-proxy "$CORP_HTTPS_PROXY"
如果你的企业代理需要通过用户名/密码进行身份验证。
  • PROXY_USER — 代理用户名 - PROXY_PASS — 代理密码 - PROXY_HOST — 代理主机名和端口 (例如 proxy.corp.example.com:8080) - CORP_NO_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"
适用于同时需要 corporate CA 和代理的环境的组合配置。这在 Enterprise 环境中很常见:内部服务使用私有证书,且所有流量都必须通过代理转发。
  • CORP_ROOT_CA_B64 — Base64 编码的 corporate CA certificate - CORP_HTTP_PROXY, CORP_HTTPS_PROXY — 代理 URL - CORP_NO_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"
你的私有仓库、Git 服务器或其他内部服务只能通过 VPN 访问。此模块必须在其他需要通过网络访问内部资源的模块之前运行。
OpenVPN:
  • VPN_CONFIG_B64 — 经过 Base64 编码的 OpenVPN 配置文件 (.ovpn) 。生成方式:cat corp.ovpn | base64 -w0
  • VPN_AUTH_USER (可选) — VPN 用户名 (如果你的 VPN 需要用户名/密码认证)
  • VPN_AUTH_PASS (可选) — VPN 密码
WireGuard:
  • WG_CONFIG_B64 — 经过 Base64 编码的 WireGuard 配置文件。生成方式: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

      # 写入 VPN 配置
      sudo mkdir -p /etc/openvpn/client
      echo "$VPN_CONFIG_B64" | base64 -d \
        | sudo tee /etc/openvpn/client/corp.conf > /dev/null

      # 如果 VPN 需要用户名/密码认证
      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

      # 启动 VPN 隧道
      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
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

      # 写入 WireGuard 配置
      echo "$WG_CONFIG_B64" | base64 -d \
        | sudo tee /etc/wireguard/wg0.conf > /dev/null
      sudo chmod 600 /etc/wireguard/wg0.conf

      # 启动隧道
      sudo systemctl enable --now wg-quick@wg0
有关 VPN 设置的更多信息,请参阅 VPN Configuration
你的内部服务使用公共 DNS 无法解析的私有 DNS 名称。
initialize:
  - name: Configure custom DNS resolution
    run: |
      # 添加内部主机名
      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

      # 可选:配置自定义域名服务器
      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

身份与安全

你的组织要求所有 Git 提交都必须签名,并且你希望 GitHub 将 Devin 的提交标记为 Verified
  • GPG_PRIVATE_KEY_B64 — Base64 编码的 GPG 私钥。生成命令:gpg --export-secret-keys <key-id> | base64 -w0
  • GIT_USER_NAME — Git 作者名称 (例如:Devin AI)
  • GIT_USER_EMAIL — Git 作者邮箱。必须与 GPG 密钥上的某个 UID 匹配,否则 GitHub 不会验证该签名。
此外,还需要将对应的公钥上传到 Devin 用于推送的 GitHub 账户 (位于 GitHub Settings > SSH and GPG keys) 。只有当用于签名的公钥已注册到创建该提交的账户上时,GitHub 才会将提交标记为 Verified。
initialize:
  - name: Prepare GPG and git signing config
    run: |
      # 允许 GPG 在没有 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
配置 Devin 的 Git 身份和 SSH 密钥,以访问私有 Git 服务器。
  • GIT_USER_NAME — Git 作者名称
  • GIT_USER_EMAIL — Git 作者邮箱
  • SSH_PRIVATE_KEY_B64 — Base64 编码的 SSH 私钥。生成命令:cat ~/.ssh/id_ed25519 | base64 -w0
  • SSH_KNOWN_HOSTS_B64 — Base64 编码的 known hosts 条目。生成命令:ssh-keyscan git.corp.internal | base64 -w0
  • SSH_CONFIG_B64 (可选) — Base64 编码的 SSH 配置文件
initialize:
  - name: Configure git identity
    run: |
      git config --global user.name "$GIT_USER_NAME"
      git config --global user.email "$GIT_USER_EMAIL"

      # 准备 SSH 目录
      mkdir -p ~/.ssh && chmod 700 ~/.ssh

maintenance:
  - name: Install SSH keys
    run: |
      # 安装 SSH 私钥(放在 maintenance 中,这样每个 session 都会重新加载)
      echo "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
      chmod 600 ~/.ssh/id_ed25519

      # 为你的 Git 服务器添加 known hosts
      echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

      # 可选:安装自定义 SSH 配置
      if [ -n "${SSH_CONFIG_B64:-}" ]; then
        echo "$SSH_CONFIG_B64" | base64 -d > ~/.ssh/config
        chmod 600 ~/.ssh/config
      fi
使用 ssh-keyscan git.corp.internal | base64 -w0 为你的 Git 服务器生成 known hosts 条目。

系统配置

安装默认 Devin 镜像中不包含的系统级软件包 (例如,用于图像处理或 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
设置在每个会话中都可用的持久环境变量。推荐的做法是将 KEY=VALUE 逐行写入 $ENVRC 文件。写入 $ENVRC 的变量会自动导出到后续所有步骤以及 Devin 会话中 (类似于 GitHub Actions 的 $GITHUB_ENV) 。
initialize:
  - name: 设置自定义环境变量
    run: |
      echo "CORPORATE_ENV=production" >> $ENVRC
      echo "DEFAULT_REGION=us-east-1" >> $ENVRC
      echo "MAX_RETRIES=3" >> $ENVRC
你也可以将环境变量写入 /etc/profile.d/ 脚本,使其在整个系统范围内生效:
cat << 'ENVVARS' | sudo tee /etc/profile.d/custom-env.sh > /dev/null
export CORPORATE_ENV=production
export DEFAULT_REGION=us-east-1
ENVVARS
这两种方式都可以。$ENVRC 更简单,也是大多数情况下推荐的做法。
默认基础镜像的区域设置可能有误。请配置区域设置和时区,以避免构建工具、Java、Python 和 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

      # 生成并设置语言环境
      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

      # 设置时区
      sudo timedatectl set-timezone UTC 2>/dev/null || \
        sudo ln -sfn /usr/share/zoneinfo/UTC /etc/localtime
Java、Gradle 和 Node.js 构建经常会达到默认的 1024 个打开文件数限制。请调高该限制,以避免构建失败。
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

      # 同时设置内核最大值
      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
在隔离或受限环境中,将默认的 Ubuntu APT 软件源替换为内部镜像源。
- APT_MIRROR_URL — 你的内部 APT 镜像源的 URL (例如:https://artifactory.example.com/artifactory/ubuntu-remote)
initialize:
  - name: Replace APT sources with internal mirror
    run: |
      # 备份原始源
      sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

      # 将所有 Ubuntu 镜像替换为你的内部镜像
      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
常见的 APT 镜像 URL 格式:
  • Artifactory: https://artifactory.example.com/artifactory/ubuntu-remote
  • Nexus: https://nexus.example.com/repository/ubuntu-proxy

高级用法

Devin 的基础环境中已包含 direnv。使用 initialize 创建 .envrc 文件后,Direnv 会自动加载它们。
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 已预先集成到 Devin 的 shell 中,因此 .envrc 变量会自动加载。无需手动执行 source。
对于敏感环境变量 (API key、令牌、数据库密码) ,请使用 repo secrets,而不是 .envrc 文件。repo secrets 会被安全存储,并在会话开始时注入。它们绝不会出现在你的 blueprint 或快照中。
使用 nvm (已预装) 通过 .nvmrc 为每个仓库切换 Node.js 版本。
initialize: |
  nvm install 18
  nvm install 20
  nvm install 22

maintenance: |
  nvm use
nvm use 会从仓库根目录读取 .nvmrc。请确保你的仓库中包含该文件 (例如内容为 20) 。
会话期间,Devin 会提供一个 Chrome 浏览器,其 CDP 端点为 localhost:29229。使用 Playwright 脚本可自动完成基于浏览器的登录。
该浏览器仅在会话期间可用,不适用于快照构建。请在 initialize 中安装 Playwright,并将登录脚本保存在你的代码仓库中。
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
示例登录脚本 (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")
将登录凭据以 secrets 的形式存储,不要写入源代码。对于需要长期保持的身份验证,请将登录脚本提交到 .agents/skills/,以便 Devin 自动重新验证身份。
initialize 中安装系统软件包、自定义二进制文件,并配置 PATH。
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 支持在蓝图中直接运行基于 Node.js 的 GitHub Actions。这对于通过 CI 所使用的同一套 actions 安装特定版本的工具非常有用。
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
setup-nodesetup-python 这类 action 会修改 PATH 和环境变量。某个 action 安装的二进制文件在后续所有步骤以及 maintenance 中都可用。仅支持基于 Node.js 的 GitHub Actions。不支持复合型 action 和基于 Docker 的 action。
你无需依赖 GitHub Actions 来完成基础工具设置。直接使用 shell 命令 (nvm install 20curl ... | shapt-get install) 同样有效,而且通常更简单。只有在你希望与 CI 配置完全一致,或者需要 setup-java 这类可处理多个发行版的 action 所带来的便利时,GitHub Actions 才更有用。
通过 HTTPS 使用看起来像真实域名的主机名在后端运行多个服务,例如 app.example.comapi.example.comadmin.example.com。在 initialize 中安装一个反向代理,并将每个主机名路由到不同的本地上游端口。Caddy 可在一个工具中同时处理路由和本地 TLS。Caddyfile 会将每个主机名映射到一个上游,而 tls internal 会通过 Caddy 内置的 CA 为每个主机名自动签发受信任的证书。caddy trust 会将该 CA 根证书安装到系统信任存储中,再将同一个根证书添加到 NSS 数据库后,浏览器也会信任它。通过蓝图编辑器中的 文件附件 部分上传你的 Caddyfile;之后即可通过 $FILE_CADDYFILE 使用它。
Caddyfile
app.example.com {
  tls internal
  reverse_proxy 127.0.0.1:3000
}

api.example.com {
  tls internal
  reverse_proxy 127.0.0.1:3001
}

admin.example.com {
  tls internal
  reverse_proxy 127.0.0.1:3002
}
initialize:
  - name: Install Caddy and NSS tools
    run: |
      sudo apt-get install -y debian-keyring debian-archive-keyring \
        apt-transport-https curl libnss3-tools
      curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
        | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
      curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
        | sudo tee /etc/apt/sources.list.d/caddy-stable.list
      sudo apt-get update -qq
      sudo apt-get install -y caddy

  - name: Install Caddyfile, hosts entries, and trust internal CA
    run: |
      sudo install -m 0644 "$FILE_CADDYFILE" /etc/caddy/Caddyfile

      for host in app.example.com api.example.com admin.example.com; do
        grep -q " $host$" /etc/hosts \
          || echo "127.0.0.1 $host" | sudo tee -a /etc/hosts > /dev/null
      done

      sudo systemctl enable --now caddy
      sudo caddy trust

      mkdir -p ~/.pki/nssdb
      [ -f ~/.pki/nssdb/cert9.db ] \
        || certutil -d sql:$HOME/.pki/nssdb -N --empty-password

      CADDY_ROOT=/var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt
      for _ in $(seq 1 30); do
        sudo test -f "$CADDY_ROOT" && break
        sleep 1
      done

      if sudo test -f "$CADDY_ROOT" \
         && ! certutil -d sql:$HOME/.pki/nssdb -L | grep -q "Caddy Local Authority"; then
        sudo install -o "$USER" -m 0644 "$CADDY_ROOT" /tmp/caddy-root.crt
        certutil -d sql:$HOME/.pki/nssdb -A -t "C,," \
          -n "Caddy Local Authority" -i /tmp/caddy-root.crt
        rm -f /tmp/caddy-root.crt
      fi
/etc/hosts 循环会让 app.example.com 在会话内解析到 127.0.0.1。你在 Caddyfile 中写入的每个 hostname,都要在其中添加一条记录。
要添加一个服务,请在 Caddyfile 中追加一个三行代码块,并在 /etc/hosts 循环中添加一条记录,然后通过 HTTPS 访问对应的 hostname。Caddy 会在首次请求时签发证书,因此无需为每个 app 单独生成证书。

全栈示例

这些示例展示了企业级和组织级配置如何组合使用。实际使用时,通常会按不同作用域拆分。这里将它们集中展示,供参考。
一个完整的企业环境示例:企业 CA 证书、代理、Java (Maven)、Python (pip/uv)、Node.js (npm) 和 Docker,全部指向同一个 Artifactory 实例。
网络与信任 (账户级) :
  • CORP_ROOT_CA_B64 — 经过 Base64 编码的企业 CA 证书
  • CORP_HTTP_PROXY — HTTP 代理 URL
  • CORP_HTTPS_PROXY — HTTPS 代理 URL
  • CORP_NO_PROXY — 不走代理的主机
注册表凭据 (组织级) :
  • ARTIFACTORY_USER — Artifactory 用户名
  • ARTIFACTORY_TOKEN — Artifactory API 令牌或密码
  • ARTIFACTORY_MAVEN_URL — Maven 仓库 URL (例如,https://artifactory.example.com/artifactory/maven-virtual)
  • ARTIFACTORY_PYPI_URL — PyPI 仓库 URL (例如,https://user:token@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple)
  • ARTIFACTORY_NPM_URL — npm 仓库 URL (例如,https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • ARTIFACTORY_DOCKER_URL — Docker 注册表 URL (例如,artifactory.example.com)
这通常会拆分为三个作用域:
  • 账户级 (initialize): 证书与代理
  • 组织级 (initialize): 语言运行时安装
  • 全组织范围 (maintenance): 注册表凭据 (在构建过程中刷新,并在会话开始时提供给 Agent)
以下为合并后的完整参考示例:
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

  # ── Org-wide:语言运行时 ──────────────────────────────────────────

  - 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:
  # ── 账户级:git 代理(每次会话刷新)───────────────────

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

  # ── Org-wide:注册表凭据(每次会话刷新)──────────────────

  - 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
在此示例中,所有仓库都指向同一个 Artifactory 实例,但 URL 路径不同。每种软件包生态系统都有各自的端点格式。即使是同一个仓库,Maven、PyPI、npm 和 Docker 的 URL 也各不相同。
当不同语言分别使用不同的私有仓库时 (例如,Maven 使用 Nexus,npm 使用 GitHub Packages,Python 使用 Artifactory) 。
  • NEXUS_MAVEN_URL — Nexus Maven 仓库 URL
  • NEXUS_USER — Nexus 用户名
  • NEXUS_PASS — Nexus 密码
  • GITHUB_PACKAGES_TOKEN — 具有 read:packages 作用域的 GitHub 个人访问令牌
  • ARTIFACTORY_USER — Artifactory 用户名
  • ARTIFACTORY_TOKEN — Artifactory API 令牌
  • GIT_TOKEN — 用于 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(作用域限定)
  - 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 → 通过 git 使用私有模块
  - name: Configure Go private modules
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
在完全气隙环境中,Devin 无法访问任何公共 URL。所有工具、运行时和软件包都必须来自内部镜像源。
证书:
  • CORP_ROOT_CA_B64 — Base64 编码的企业 CA 证书
镜像访问:
  • APT_MIRROR_URL — 内部 Ubuntu APT 镜像 URL
  • MIRROR_USER — 用于镜像身份验证的用户名
  • MIRROR_PASS — 用于镜像身份验证的密码
  • JDK_TARBALL_URL — 从内部镜像下载 JDK tarball 的 URL
  • NODE_TARBALL_URL — 从内部镜像下载 Node.js tarball 的 URL
软件包注册表:
  • INTERNAL_MAVEN_URL — 内部 Maven 注册表 URL
  • INTERNAL_NPM_URL — 内部 npm 注册表 URL
  • INTERNAL_PYPI_URL — 内部 PyPI 注册表 URL
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: |
      # 从内部制品库下载 JDK 压缩包
      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
在气隙环境中,Devin 所需的所有工具 (语言运行时、CLI 工具等) 都必须能从你的内部镜像源获取。公共软件仓库和下载站点均无法访问。
一个综合性的企业级配置示例,集成了 VPN 连接、证书、代理及多语言支持。以下是推荐的操作顺序。
VPN:
  • VPN_CONFIG_B64 — Base64 编码的 OpenVPN 配置文件
网络与信任:
  • CORP_ROOT_CA_B64 — Base64 编码的企业 CA 证书
  • CORP_HTTP_PROXY — HTTP 代理 URL
  • CORP_HTTPS_PROXY — HTTPS 代理 URL
  • CORP_NO_PROXY — 无需通过代理的主机
注册表凭据:
  • MAVEN_REGISTRY_URL — Maven 注册表 URL
  • NPM_REGISTRY_URL — npm 注册表 URL
  • PYPI_REGISTRY_HOST — PyPI 注册表主机名
  • REGISTRY_USER — 注册表用户名 (用于 Maven 和 pip)
  • REGISTRY_PASS — 注册表密码 (用于 Maven 和 pip)
  • REGISTRY_TOKEN — npm 身份验证令牌
initialize:
  # 1. VPN — 必须首先执行,以确保内部资源可访问
  - 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 — 解析内部主机名
  - 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. 证书 — 信任内部 CA
  - 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. 代理 — 通过企业代理路由流量
  - 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. 语言运行时
  - 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
initialize 步骤的顺序很重要。 必须先配置 VPN (这样才能访问内部主机) ,然后配置 DNS (这样名称才能正确解析) ,再配置证书 (这样 HTTPS 才能正常工作) ,接着配置代理 (这样流量才能正确转发) ,最后配置语言运行时环境 (它们可能会从内部镜像下载) 。

编写优质蓝图的技巧

  • 先在会话中测试命令。 在将命令添加到蓝图之前,先在 Devin 会话中手动运行一遍。这样比等待完整构建周期更快。
  • 一次性安装的工具用 initialize,依赖项用 maintenance 任何安装需要几分钟的内容 (编译器、大型二进制文件、全局工具) 都应放在 initialize 中。较快的依赖命令 (npm installuv sync) 则应放在 maintenance 中。
  • maintenance 命令保持快速。 尽量控制在 2 分钟以内。这些命令会在构建期间运行,并在会话开始时提供给 Agent。
  • 环境变量请使用 $ENVRC 不要写入 .bashrc.profile$ENVRC 是在不同步骤和会话之间设置变量的受支持方式。
  • 给步骤命名。 使用带有 name 字段的展开形式后,构建日志中的失败会更容易定位。
  • monorepo 请使用 subshell。 (cd packages/foo && npm install) 会在 subshell 中运行,因此后续步骤不会受目录变更影响。
  • 使用 npm install,不要使用 npm ci npm ci 会删除 node_modules 并从头重新安装,这对 maintenance 来说太慢。
  • 敏感信息请使用 repo secrets。 请在仓库蓝图编辑器的 Secrets 选项卡中进行配置,而不要将其硬编码到蓝图中。
有关语法细节,请参阅 蓝图参考。有关构建失败的故障排除,请参阅 声明式配置 > 故障排除