Skip to main content
This is the full field reference for blueprints. For an introduction to blueprints and how they fit into Devin’s environment, see Declarative environment configuration.
A blueprint defines how Devin’s environment is configured: what tools to install, how to keep dependencies up to date, and what commands Devin should know about.

Overview

A blueprint has three top-level sections:
initialize: ...   # Install tools and runtimes
maintenance: ...  # Install project dependencies
knowledge: ...    # Reference info for Devin (never executed)
SectionPurposeExecuted?
initializeInstall system tools, language runtimes, global CLIsYes, during each build
maintenanceInstall and update project dependenciesYes, during builds + at session start
knowledgeTell Devin how to lint, test, build, and other project-specific infoNo, provided as reference
All three sections are optional. You can include any combination. initialize runs during builds only. Results are saved in the snapshot. maintenance runs during builds (after initialize) and at the start of every session after pulling latest code, so commands should be fast and incremental. Builds run automatically when your blueprint changes and periodically (every ~24 hours).

initialize

Use initialize for installing tools and runtimes that don’t depend on the specific state of your code: language runtimes, system packages, global CLIs.

Simple form

For straightforward shell commands, use a block scalar:
initialize: |
  curl -LsSf https://astral.sh/uv/install.sh | sh
  apt-get update && apt-get install -y build-essential
  npm install -g pnpm

Structured form

For named steps, environment variables, or GitHub Actions, use a list:
initialize:
  - name: "Install Python 3.12"
    uses: github.com/actions/setup-python@v5
    with:
      python-version: "3.12"

  - name: "Install system packages"
    run: |
      apt-get update
      apt-get install -y libpq-dev

  - name: "Install global tools"
    run: pip install uv
    env:
      PIP_BREAK_SYSTEM_PACKAGES: "1"
Both forms can be mixed. The simple form is equivalent to a single step with run.

When to use initialize vs maintenance

Put in initializePut in maintenance
Language runtime installationnpm install / pip install
System packages (apt-get)bundle install
Global CLI toolsgo mod download
One-time configurationDependency cache updates
GitHub Actions (setup-python, etc.)Repo-specific setup scripts
Both sections run during every build, but the separation keeps your configuration readable. Tools and runtimes go in initialize; dependency commands that track your code’s lock files go in maintenance.

maintenance

Use maintenance for dependency installation and other commands that should run after your code is cloned. This is where npm install, pip install, uv sync, and similar commands belong.
maintenance: |
  npm install
  pip install -r requirements.txt
Or in structured form:
maintenance:
  - name: "Install npm dependencies"
    run: npm install

  - name: "Install Python dependencies"
    run: uv sync
    env:
      UV_CACHE_DIR: /tmp/uv-cache
For repo-level blueprints, maintenance commands run from the repository root directory. For org-level blueprints, they run from the home directory (~).

knowledge

The knowledge section is not executed. It provides reference information that Devin uses when working in your project. This is how you tell Devin the correct commands for linting, testing, building, and any other project-specific workflows.
knowledge:
  - name: lint
    contents: |
      Run linting with:
      npm run lint

      For auto-fix:
      npm run lint -- --fix

  - name: test
    contents: |
      Run the full test suite:
      npm test

      Run a single test file:
      npm test -- path/to/test.ts

  - name: build
    contents: |
      npm run build

      Build output goes to dist/
Each knowledge item has:
FieldTypeDescription
namestringIdentifier for this knowledge item (e.g., lint, test, build)
contentsstringFree-form text with commands, instructions, or notes
The name field is a label. By convention, lint, test, and build are the standard names. Devin references these when verifying its work. You can add any additional knowledge items with custom names:
knowledge:
  - name: lint
    contents: ...
  - name: test
    contents: ...
  - name: build
    contents: ...
  - name: deploy
    contents: |
      Deploy to staging:
      npm run deploy:staging
  - name: database
    contents: |
      Run migrations:
      npm run db:migrate

      Seed test data:
      npm run db:seed

Step types

Each step in initialize or maintenance uses one of two types: shell commands (run) or GitHub Actions (uses).

Shell commands (run)

Execute arbitrary shell commands in bash:
- name: "Install dependencies"
  run: |
    npm install
    pip install -r requirements.txt
FieldTypeDescription
namestring (optional)Human-readable label for the step
runstringShell command(s) to execute
envmap (optional)Extra environment variables for this step
Execution details:
  • Commands run in bash. If any command in a multi-line script fails, the entire step stops immediately.
  • Org-level blueprints execute in the home directory (~).
  • Repo-level blueprints execute in the cloned repository root.
  • Each step has a timeout of 1 hour.
  • Secrets are automatically available as environment variables.

GitHub Actions (uses)

Run Node.js-based GitHub Actions directly in your blueprint:
- name: "Install Python"
  uses: github.com/actions/setup-python@v5
  with:
    python-version: "3.12"
FieldTypeDescription
namestring (optional)Human-readable label for the step
usesstringGitHub Action reference
withmap (optional)Input parameters for the action
envmap (optional)Extra environment variables for this step
Action reference format:
github.com/<owner>/<repo>@<ref>
github.com/<owner>/<repo>/<subpath>@<ref>
The github.com/ prefix and @<ref> suffix are both required. The ref is typically a version tag like v5. Commonly used actions:
ActionPurposeExample with
github.com/actions/setup-python@v5Install Pythonpython-version: "3.12"
github.com/actions/setup-node@v4Install Node.jsnode-version: "20"
github.com/actions/setup-go@v5Install Gogo-version: "1.22"
github.com/actions/setup-java@v4Install Java/JDKjava-version: "21", distribution: "temurin"
github.com/gradle/actions/setup-gradle@v4Install Gradle(none)
github.com/ruby/setup-ruby@v1Install Rubyruby-version: "3.3"
Only Node.js-based GitHub Actions are supported. Composite actions and Docker-based actions are not supported.
How with values work: Values passed via with are provided to the action as inputs, following the same conventions as GitHub Actions workflows. All values are converted to strings.
with:
  python-version: "3.12"
  check-latest: true
  cache: "pip"
How actions propagate changes: Actions can modify the environment for subsequent steps. For example, setup-python adds the Python binary to PATH, which remains available for all later steps and in maintenance.

run vs uses: which to use

Use run when…Use uses when…
Installing system packages (apt-get)Setting up language runtimes (Python, Node, Go, Java, Ruby)
Running project-specific scriptsAn official GitHub Action exists for what you need
Configuring files or environmentYou want automatic version management and caching
The command is simple and self-containedYou’d use the same Action in a GitHub Actions workflow
In practice, most configurations use uses for language runtimes and run for everything else.

Environment variables and secrets

Step-level environment variables

Any step can define extra environment variables with the env field:
- run: pip install -r requirements.txt
  env:
    PIP_INDEX_URL: "https://pypi.example.com/simple/"
    PIP_BREAK_SYSTEM_PACKAGES: "1"
These are scoped to the step and don’t persist to subsequent steps.

Cross-step environment variables ($ENVRC)

To propagate environment variables across steps, write them to the $ENVRC file:
- name: "Set shared variables"
  run: |
    echo "DATABASE_URL=postgresql://localhost:5432/myapp" >> $ENVRC
    echo "APP_ENV=development" >> $ENVRC
Variables written to $ENVRC are automatically exported and available to all subsequent steps and the Devin session. This works similarly to $GITHUB_ENV in GitHub Actions.

Secrets

Secrets configured in the Devin UI (Settings > Secrets) are automatically injected as environment variables. You don’t declare them in your blueprint. Just reference them by name (e.g., $MY_SECRET). Secrets are injected before every step runs during builds and re-injected at the start of every session. They are scrubbed from the snapshot image itself, so credentials are never baked into saved machine images.
  • Organization secrets: Available as environment variables in every step across all blueprints in the org. Set these in Settings > Secrets.
  • Enterprise secrets: Merged with org secrets (org secrets take precedence on name collisions). Available across all orgs in the enterprise.
  • Repository secrets: Written to a per-repo file at /run/repo_secrets/{owner/repo}/.env.secrets. During builds, repo secrets are automatically sourced before that repo’s blueprint steps run. At session time, Devin sources them when working in the repo. Configure these in Settings > Secrets with the repo scope.
Build-only secrets: Secrets marked as “build only” are available during snapshot builds but removed before the snapshot is saved. Use these for credentials needed only at build time (e.g., downloading private artifacts during initialize).
maintenance runs both during builds and at session start. If a maintenance step writes secrets into config files (e.g., ~/.m2/settings.xml, ~/.npmrc), those files will be baked into the snapshot. Place credential-writing steps in maintenance (not initialize) so they refresh each session, but be aware the written files persist in the image. For maximum security, use environment variables or $ENVRC instead of writing credentials to disk.

File attachments

You can upload files (like .npmrc, settings.xml, configuration files) through the blueprint editor. Uploaded files are written to ~/.files/ and an environment variable is set pointing to each file’s path:
$FILE_SETTINGS_XML    -> /home/ubuntu/.files/settings.xml
$FILE_NPMRC           -> /home/ubuntu/.files/.npmrc
The variable name is derived from the file name: uppercase, with non-alphanumeric characters replaced by underscores, prefixed with FILE_. Use file attachments in your blueprint steps:
maintenance:
  - name: "Configure Maven"
    run: |
      mkdir -p ~/.m2
      cp "$FILE_SETTINGS_XML" ~/.m2/settings.xml

Git-based blueprints

Git-based blueprints are not currently supported. This feature is coming soon. You’ll be able to store blueprints in your repository and have builds trigger automatically when they change. For now, configure blueprints through the UI at Settings > Environment configuration.

Complete example

For how blueprints compose across tiers (enterprise → org → repo), build statuses, repository states, and what triggers a rebuild, see Builds and sessions on the Declarative configuration page.

Org-wide blueprint

Shared tooling that every repo in the org needs. This runs first (after any enterprise blueprint), in the home directory.
initialize:
  - name: "Install Node.js 20"
    uses: github.com/actions/setup-node@v4
    with:
      node-version: "20"

  - name: "Install Python 3.12 and uv"
    run: |
      curl -LsSf https://astral.sh/uv/install.sh | sh

  - name: "Install shared tools"
    run: |
      npm install -g pnpm turbo
      apt-get update && apt-get install -y jq ripgrep

  - name: "Configure private registry"
    run: |
      echo "//npm.corp.example.com/:_authToken=$NPM_REGISTRY_TOKEN" >> ~/.npmrc

Repo-level blueprint

Project-specific setup for a Node.js + Python monorepo. This runs after the org-wide blueprint, in the repository directory.
initialize:
  - name: "Install Playwright browsers"
    run: npx playwright install --with-deps chromium

  - name: "Set up project environment variables"
    run: |
      echo "DATABASE_URL=postgresql://localhost:5432/myapp_dev" >> $ENVRC
      echo "REDIS_URL=redis://localhost:6379" >> $ENVRC
      echo "APP_ENV=development" >> $ENVRC

maintenance:
  - name: "Install frontend dependencies"
    run: |
      cd frontend
      pnpm install

  - name: "Install backend dependencies"
    run: |
      cd backend
      uv sync

  - name: "Run database migrations"
    run: |
      cd backend
      uv run alembic upgrade head
    env:
      DATABASE_URL: "postgresql://localhost:5432/myapp_dev"

knowledge:
  - name: lint
    contents: |
      Frontend:
      cd frontend && pnpm lint

      Backend:
      cd backend && uv run ruff check .

      Auto-fix:
      cd frontend && pnpm lint --fix
      cd backend && uv run ruff check --fix .

  - name: test
    contents: |
      Frontend unit tests:
      cd frontend && pnpm test

      Backend unit tests:
      cd backend && uv run pytest

      E2E tests (requires dev server running):
      cd frontend && pnpm test:e2e

  - name: build
    contents: |
      Frontend:
      cd frontend && pnpm build

      Backend:
      cd backend && uv run python -m build

  - name: dev-server
    contents: |
      Start the full development stack:
      cd backend && uv run uvicorn main:app --reload &
      cd frontend && pnpm dev

      Frontend: http://localhost:3000
      Backend API: http://localhost:8000
      API docs: http://localhost:8000/docs

  - name: database
    contents: |
      Run migrations:
      cd backend && uv run alembic upgrade head

      Create a new migration:
      cd backend && uv run alembic revision --autogenerate -m "description"

      Reset the database:
      cd backend && uv run alembic downgrade base && uv run alembic upgrade head