Copy-paste blueprints for common languages, private registries, and enterprise infrastructure.
Copy-paste blueprints for common languages and use cases. Each template is self-contained. Combine them to build your full configuration.For a full breakdown of every field, see the Blueprint reference.
Secrets: Templates reference secrets via $SECRET_NAME. Configure these in Settings > Secrets before using a template. Never hardcode credentials in your blueprint.
Minimal blueprints for the most common setups. Copy one, paste it into the blueprint editor, and you’re done.
Node.js project
initialize: | npm install -g pnpmmaintenance: | pnpm installknowledge: - name: lint contents: | Run `pnpm lint` to check for errors. - name: test contents: | Run `pnpm test` for the full suite.
Python project
initialize: | curl -LsSf https://astral.sh/uv/install.sh | shmaintenance: | uv syncknowledge: - name: lint contents: | Run `uv run ruff check .` to lint. - name: test contents: | Run `uv run pytest` for the full suite.
initialize: | nvm install 20 nvm use 20maintenance: | npm installknowledge: - name: lint contents: | npx eslint . - name: test contents: | npm test - name: build contents: | npm run build
Use npm install (not npm ci) in maintenance. It does an incremental update, while npm ci deletes node_modules and reinstalls from scratch every session.
Rust (via rustup) and Cargo are pre-installed on Devin’s base image. Skip the install step if the default stable toolchain is sufficient. You only need the dependency fetch.
Monorepo with a Node.js frontend and Python backend. Each subproject gets its own knowledge entries.
initialize: - name: Install pnpm run: npm install -g pnpm - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | shmaintenance: - 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: | This is a monorepo with three packages: - `packages/frontend` — React app (TypeScript, pnpm) - `packages/backend` — Python API (FastAPI, uv) - `packages/shared` — Shared TypeScript utilities (must be built before frontend) - name: frontend contents: | Run `cd packages/frontend && pnpm dev` to start the dev server. Run `cd packages/frontend && pnpm lint` to lint. Run `cd packages/frontend && pnpm test` to test. - name: backend contents: | Run `cd packages/backend && uv run uvicorn app.main:app --reload` to start the API. Run `cd packages/backend && uv run ruff check .` to lint. Run `cd packages/backend && uv run pytest` to test.
Use subshells (cd dir && command) instead of cd dir && command so the working directory resets between steps.
A Java monorepo where different services require different JDK versions. Install both JDKs at setup, then use knowledge entries to tell Devin which JAVA_HOME to use for each service.
Configure package managers to resolve dependencies from private registries. Set these in Settings > Environment configuration > Org-wide setup (or per-repo if only one repo needs it).
Credential configuration belongs in maintenance, not initialize. Steps that write secrets (registry passwords, auth tokens) into config files should use maintenance so credentials are freshly loaded each session. Secrets are removed before the snapshot is saved, so config files written during initialize won’t have valid credentials when sessions start.
If your private registry uses a corporate CA, make sure the CA certificate is installed at the enterprise level first. The configuration below assumes HTTPS trust is already established.
Configure npm to resolve scoped packages (e.g., @myorg/*) from a private registry, while public packages continue to come from the default npm registry.
Required secrets
GITHUB_PACKAGES_TOKEN — Personal access token or GitHub App token with read:packages scope
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
Replace @myorg with your npm scope. Common private registry URLs:
Configure pip and uv to resolve packages from your private PyPI registry (e.g., Nexus, Artifactory).
Required secrets
PYPI_REGISTRY_URL — Full URL of your PyPI index, including credentials if required (e.g., https://user:token@nexus.example.com/repository/pypi-proxy/simple)
Install JDK and configure Maven to mirror all dependency resolution through your private registry (e.g., Artifactory, Nexus).
JDK 17 is pre-installed on Devin’s base image. Skip the install step if the default OpenJDK 17 is sufficient. You only need the Maven install and registry configuration.
Required secrets
MAVEN_REGISTRY_URL — URL of your Maven registry (e.g., https://artifactory.example.com/artifactory/maven-virtual)
Configure Cargo to resolve crates from a private registry.
Rust (via rustup) and Cargo are pre-installed on Devin’s base image. Skip the install step if the default stable toolchain is sufficient. You only need the registry configuration.
Required secrets
CARGO_REGISTRY_INDEX — URL of the private registry index (e.g., sparse+https://cargo.corp.internal/api/v1/crates/)
CARGO_REGISTRY_TOKEN — Auth token for the private registry
If you only need to add a private registry without replacing crates.io, remove the [source.crates-io] and [source.private] sections and use cargo install --registry private or [dependencies] my-crate = { version = "1.0", registry = "private" } in Cargo.toml.
Ruby / Bundler
Install Ruby and configure Bundler to resolve gems from a private gem server.
Required secrets
GEM_SERVER_URL — URL of your private gem server (e.g., https://artifactory.example.com/artifactory/api/gems/gems-virtual)
REGISTRY_USER — Registry username
REGISTRY_PASS — Registry password or API token
initialize: - name: Install Ruby run: | sudo apt-get update -qq sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ruby-fullmaintenance: - 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"
AWS CodeArtifact tokens expire after 12 hours. Use maintenance to refresh the token at the start of every session. This example configures npm, pip, and Maven to use CodeArtifact.
awscli is pre-installed on Devin’s base image. You only need the token refresh and registry configuration.
Required secrets
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY — IAM credentials with codeartifact:GetAuthorizationToken and sts:GetServiceBearerToken permissions
CA_DOMAIN — Your CodeArtifact domain name
CA_DOMAIN_OWNER — AWS account ID that owns the domain
CA_REGION — AWS region (e.g., us-east-1)
CA_NPM_REPO, CA_PYPI_REPO, CA_MAVEN_REPO — Repository names for each ecosystem
Machine-level infrastructure that applies across all orgs and repos. Set these in Settings > Devin’s base environment (for enterprise-wide) or Settings > Environment configuration > Org-wide setup (for org-wide).
Your organization uses a private certificate authority for internal services. Devin needs the root certificate to reach internal registries and tools over HTTPS.
Required secrets
CORP_ROOT_CA_B64 — Base64-encoded PEM certificate from your corporate CA. Generate with: cat corp-root-ca.crt | base64 -w0
Combined setup for environments that need both a corporate CA and a proxy. This is common in enterprise environments where internal services use private certificates and all traffic must route through a proxy.
Required secrets
CORP_ROOT_CA_B64 — Base64-encoded corporate CA certificate
Your private registries, Git servers, or other internal services are only reachable over VPN. This must run before other modules that need network access to internal resources.
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 # Write the VPN config sudo mkdir -p /etc/openvpn/client echo "$VPN_CONFIG_B64" | base64 -d \ | sudo tee /etc/openvpn/client/corp.conf > /dev/null # If VPN requires username/password auth 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 # Start the VPN tunnel sudo systemctl daemon-reload sudo systemctl enable --now openvpn-client@corp # Wait for the tunnel to come up for i in $(seq 1 30); do if ip link show tun0 >/dev/null 2>&1; then break; fi sleep 1 done
GIT_USER_EMAIL — Git author email. Must match a UID on the GPG key, otherwise GitHub will not verify the signature.
Also upload the matching public key to the GitHub account whose credentials Devin uses to push (under GitHub Settings > SSH and GPG keys). GitHub only marks commits as Verified when the signing public key is registered on the account that authored the commit.
initialize: - name: Prepare GPG and git signing config run: | # Allow GPG to work without a TTY echo 'export GPG_TTY=$(tty)' | sudo tee -a /etc/profile.d/gpg.sh > /dev/nullmaintenance: - 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
Git identity and SSH keys
Configure Devin’s Git identity and SSH keys for accessing private Git servers.
Set persistent environment variables that should be available in every session.The recommended approach is to write KEY=VALUE lines to the $ENVRC file. Variables written to $ENVRC are automatically exported for all subsequent steps and the Devin session (similar to GitHub Actions’ $GITHUB_ENV).
direnv is pre-hooked into Devin’s shell, so .envrc variables load automatically. No manual sourcing needed.
For sensitive environment variables (API keys, tokens, database passwords), use repo secrets instead of .envrc files. Repo secrets are stored securely and injected at session time. They never appear in your blueprint or snapshot.
Per-repository Node version switching
Use nvm (pre-installed) to switch Node.js versions per repository via .nvmrc.
nvm use reads .nvmrc from the repo root. Make sure your repository has one (e.g., containing 20).
Browser authentication (Playwright)
Devin provides a Chrome browser with a CDP endpoint at localhost:29229during sessions. Use Playwright scripts to automate browser-based login.
The browser is only available during sessions, not snapshot builds. Install Playwright in initialize and keep login scripts in your repo.
initialize: | pip install playwright playwright install chromiummaintenance: | npm installknowledge: - 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
Example login script (scripts/login.py):
from playwright.sync_api import sync_playwrightimport oswith 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")
Store login credentials as secrets, not in source code. For long-lived authentication, commit login scripts to .agents/skills/ so Devin can re-authenticate automatically.
Custom system tools and PATH
Install system packages, custom binaries, and configure PATH in initialize.
Devin supports running Node.js-based GitHub Actions directly in blueprints. This is useful for installing specific tool versions via the same actions your CI uses.
Actions like setup-node and setup-python modify PATH and environment variables. Binaries installed by one action are available in all subsequent steps and in maintenance. Only Node.js-based GitHub Actions are supported. Composite and Docker-based actions are not.
You don’t need GitHub Actions for basic tool setup. Direct shell commands (nvm install 20, curl ... | sh, apt-get install) work just as well and are often simpler. GitHub Actions are most useful when you want to match your CI setup exactly or need the convenience of actions like setup-java which handle multiple distributions.
These examples show how enterprise and org-level configurations combine. In practice, you’d split these across scopes. They’re shown together here for reference.
Full enterprise stack (Artifactory)
A complete enterprise environment: corporate CA certificate, proxy, Java (Maven), Python (pip/uv), Node.js (npm), and Docker, all pointed at a single Artifactory instance.
Required secrets
Network & trust (account-wide):
CORP_ROOT_CA_B64 — Base64-encoded corporate CA certificate
CORP_HTTP_PROXY — HTTP proxy URL
CORP_HTTPS_PROXY — HTTPS proxy URL
CORP_NO_PROXY — Hosts to bypass proxy
Registry credentials (org-wide):
ARTIFACTORY_USER — Artifactory username
ARTIFACTORY_TOKEN — Artifactory API token or password
In this example, all registries point at the same Artifactory instance but use different URL paths. Each package ecosystem has its own endpoint format. Maven, PyPI, npm, and Docker URLs are all different even for the same registry.
Multi-language with different registries
When different languages use different private registries (e.g., Maven from Nexus, npm from GitHub Packages, Python from Artifactory).
Required secrets
NEXUS_MAVEN_URL — Nexus Maven repository URL
NEXUS_USER — Nexus username
NEXUS_PASS — Nexus password
GITHUB_PACKAGES_TOKEN — GitHub personal access token with read:packages scope
ARTIFACTORY_USER — Artifactory username
ARTIFACTORY_TOKEN — Artifactory API token
GIT_TOKEN — Personal access token for Go private modules
In air-gapped environments, all tools Devin needs (language runtimes, CLI tools, etc.) must be available on your internal mirrors. Public registries and download sites are unreachable.
VPN + certificates + proxy + languages
A comprehensive enterprise setup combining VPN connectivity with certificates, proxy, and multi-language support. This is the recommended order of operations.
Order matters for initialize steps. VPN must come first (so internal hosts are reachable), then DNS (so names resolve), then certificates (so HTTPS works), then proxy (so traffic routes correctly), and finally language runtimes (which may download from internal mirrors).
Test commands in a session first. Run commands manually in a Devin session before adding them to your blueprint. This is faster than waiting for a full build cycle.
Use initialize for install-once tools, maintenance for deps. Anything that takes minutes to install (compilers, large binaries, global tools) belongs in initialize. Quick dependency commands (npm install, uv sync) go in maintenance.
Keep maintenance commands fast. Aim for under 2 minutes. These run at the start of every session.
Use $ENVRC for environment variables. Don’t write to .bashrc or .profile. $ENVRC is the supported mechanism for setting variables across steps and sessions.
Name your steps. The expanded form with name fields makes build log failures much easier to identify.
Use subshells for monorepos.(cd packages/foo && npm install) runs in a subshell so subsequent steps aren’t affected by the directory change.
Use npm install, not npm ci.npm ci deletes node_modules and reinstalls from scratch every session, which is slow for maintenance.
Use repo secrets for sensitive values. Configure them in Settings > Secrets with repo scope instead of hardcoding in blueprints.