Skip to content

Runtimes configuration

The runtimes field configures language environments that are installed before the agent runs. Unlike tools (which are agent capabilities like edit, bash, memory), runtimes are execution environments that the compiler auto-installs via pipeline steps.

Aligned with gh-aw’s runtimes: front matter field.

Lean 4 theorem prover runtime. Auto-installs the Lean toolchain via elan, extends the bash command allow-list, adds Lean-specific domains to the network allowlist, and appends a prompt supplement informing the agent that Lean is available.

# Simple enablement (installs latest stable toolchain)
runtimes:
lean: true
# With options (pin specific toolchain version)
runtimes:
lean:
toolchain: "leanprover/lean4:v4.29.1"

When enabled, the compiler:

  • Injects an elan installation step into {{ prepare_steps }} (runs before AWF network isolation)
  • Defaults to the stable toolchain; if a lean-toolchain file exists in the repo, elan overrides to that version automatically
  • Auto-adds lean, lake, and elan to the bash command allow-list
  • Adds Lean-specific domains to the network allowlist: elan.lean-lang.org, leanprover.github.io, lean-lang.org
  • Mounts $HOME/.elan into the AWF container via --mount flag so the elan toolchain is accessible inside the chroot (AWF replaces $HOME with an empty overlay for security)
  • Appends a prompt supplement informing the agent about Lean 4 availability and basic commands
  • Emits a compile-time warning if tools.bash is empty (Lean requires bash access)

Note: In the 1ES target, the bash command allow-list is updated but elan installation must be done manually via steps: front matter. The 1ES target handles network isolation separately.

Python runtime. Auto-installs Python via UsePythonVersion@0, emits PipAuthenticate@1 for internal feed access, adds Python ecosystem domains to the AWF network allowlist, extends the bash command allow-list, and optionally injects feed URL env vars for pip and uv.

# Simple enablement (installs default Python 3.x)
runtimes:
python: true
# With options (pin version, configure feed)
runtimes:
python:
version: "3.12"
feed-url: "https://pkgs.dev.azure.com/myorg/_packaging/myfeed/pypi/simple/"

Fields:

FieldTypeDescription
versionstringPython version to install (e.g., "3.12", "3.11"). Passed to UsePythonVersion@0 versionSpec. Defaults to latest 3.x.
feed-urlstringInternal PyPI feed URL. Injects PIP_INDEX_URL and UV_DEFAULT_INDEX env vars into the agent environment.
configstringPath to a pip/uv config file. Accepted with a warning — the file will not be available inside the AWF agent environment until proxy-auth support lands.

When enabled, the compiler:

  • Injects UsePythonVersion@0 into {{ prepare_steps }} (runs before AWF)
  • If feed-url is set, also injects PipAuthenticate@1 to authenticate the ADO build service identity for internal feeds
  • Auto-adds python, python3, pip, pip3, uv to the bash command allow-list
  • Adds Python ecosystem domains to the network allowlist (pypi.org, pythonhosted.org, etc.)
  • If feed-url is set, injects PIP_INDEX_URL and UV_DEFAULT_INDEX env vars into the agent environment
  • Appends a prompt supplement informing the agent about Python availability
  • No AWF mounts or PATH prepends needed — UsePythonVersion@0 installs to /opt/hostedtoolcache (auto-mounted by AWF) and publishes PATH entries that AWF merges via $GITHUB_PATH

Note: PipAuthenticate@1 is currently emitted with an empty artifactFeeds input, which configures credentials for all feeds accessible to the build service identity. If your internal feed requires scoped authentication to a specific Azure Artifacts feed, this may need future refinement.

Node.js runtime. Auto-installs Node.js via NodeTool@0, emits npmAuthenticate@0 for internal feed access, adds Node ecosystem domains to the AWF network allowlist, extends the bash command allow-list, and optionally injects feed URL env vars for npm.

# Simple enablement (installs default Node LTS)
runtimes:
node: true
# With options (pin version, configure feed)
runtimes:
node:
version: "22.x"
feed-url: "https://pkgs.dev.azure.com/ORG/PROJECT/_packaging/FEED/npm/registry/"

Fields:

FieldTypeDescription
versionstringNode.js version to install (e.g., "22.x", "20.x"). Passed to NodeTool@0 versionSpec. Defaults to "22.x".
feed-urlstringInternal npm registry URL. Injects NPM_CONFIG_REGISTRY env var into the agent environment.
configstringPath to an .npmrc config file. Accepted with a warning — the file will not be available inside the AWF agent environment until proxy-auth support lands.

When enabled, the compiler:

  • Injects NodeTool@0 into {{ prepare_steps }} (runs before AWF)
  • If feed-url or config is set, also injects npmAuthenticate@0 (and an ensure-.npmrc step) to authenticate the ADO build service identity for internal feeds
  • Auto-adds node, npm, npx to the bash command allow-list
  • Adds Node ecosystem domains to the network allowlist (npmjs.org, nodejs.org, etc.)
  • If feed-url is set, injects NPM_CONFIG_REGISTRY env var into the agent environment
  • Appends a prompt supplement informing the agent about Node.js availability
  • No AWF mounts or PATH prepends needed — NodeTool@0 installs to /opt/hostedtoolcache (auto-mounted by AWF) and publishes PATH entries that AWF merges via $GITHUB_PATH
  • Note: AWF overlays ~/.npmrc with /dev/null for credential security — the NPM_CONFIG_REGISTRY env var approach avoids conflicting with this overlay

.NET runtime. Auto-installs the .NET SDK via UseDotNet@2, emits NuGetAuthenticate@1 for internal feed access, adds .NET ecosystem domains to the AWF network allowlist, and extends the bash command allow-list with dotnet.

# Simple enablement (installs default .NET SDK, currently 8.0.x)
runtimes:
dotnet: true
# With options (pin version, configure internal feed)
runtimes:
dotnet:
version: "8.0.x"
feed-url: "https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json"
# Or point at a checked-in nuget.config
runtimes:
dotnet:
version: "8.0.x"
config: "nuget.config"
# Pin SDK from the repo's global.json (UseDotNet@2 useGlobalJson mode)
runtimes:
dotnet:
version: "global.json"

Fields:

FieldTypeDescription
versionstring.NET SDK version to install (e.g., "8.0.x", "9.0.x"). Passed to UseDotNet@2 version with packageType: 'sdk'. Defaults to "8.0.x". The special value "global.json" (case-insensitive) emits useGlobalJson: true instead, which discovers and installs every SDK referenced by global.json files in the workspace.
feed-urlstringInternal NuGet feed URL (typically the v3 index.json of an Azure Artifacts feed). When set, the compiler creates a minimal nuget.config if none exists and runs NuGetAuthenticate@1.
configstringPath to a checked-in nuget.config in the repo. When set, the compiler runs NuGetAuthenticate@1 (which auto-discovers nuget.config files in the workspace). Mutually exclusive with feed-url.

global.json precedence. A global.json file in the repo is the canonical way to pin the .NET SDK. The compiler enforces a single source of truth:

  • If a global.json exists at the agent’s compile directory and the front matter sets a concrete version, compilation errors out. Either remove the front-matter version or set it to the literal string "global.json" to opt into UseDotNet@2’s useGlobalJson: true mode.
  • If version: "global.json" is set, the compiler emits useGlobalJson: true (no explicit version: input) so the install task walks the workspace for global.json files itself.
  • If no version is set and a global.json exists, the compiler does not auto-promote — the default "8.0.x" is used. Opt in explicitly with the sentinel.

When enabled, the compiler:

  • Injects UseDotNet@2 into {{ prepare_steps }} (runs before AWF)
  • If feed-url is set, injects an ensure-nuget.config step (writes a minimal nuget.config referencing the feed only when one doesn’t already exist) and NuGetAuthenticate@1
  • If config is set (and feed-url is not), injects NuGetAuthenticate@1 only — the user-checked-in nuget.config is assumed to be present in the workspace
  • Auto-adds dotnet to the bash command allow-list
  • Adds .NET ecosystem domains to the network allowlist (nuget.org, dotnet.microsoft.com, pkgs.dev.azure.com, etc.)
  • Appends a prompt supplement informing the agent about .NET availability
  • No AWF mounts or PATH prepends needed — UseDotNet@2 installs to /opt/hostedtoolcache (auto-mounted by AWF) and publishes PATH entries that AWF merges via $GITHUB_PATH

Differences from the Python and Node runtimes (called out for clarity, since this runtime intentionally diverges):

  • No agent env var is injected for feed-url. Unlike pip (PIP_INDEX_URL) and npm (NPM_CONFIG_REGISTRY), NuGet has no first-class environment-variable equivalent for selecting a package source. Feed configuration always goes through a nuget.config file.
  • config: is functional, not a deferred warning. AWF only overlays files in $HOME (e.g., ~/.npmrc -> /dev/null); workspace files such as nuget.config are preserved inside the agent sandbox, so a checked-in nuget.config works today.
  • NuGetAuthenticate@1 requires no workingFile: input. It auto-discovers nuget.config files anywhere in the workspace, unlike npmAuthenticate@0 which needs an explicit path.

Multiple runtimes can be enabled simultaneously:

runtimes:
python:
version: "3.12"
node:
version: "22.x"
dotnet:
version: "8.0.x"
lean: true

All runtime extensions are sorted into ExtensionPhase::Runtime and execute before tool extensions (ExtensionPhase::Tool), ensuring language toolchains are available before any tools that depend on them.