---
title: OS Package
description: Run commands and construct isolated task environments.
---

# OS Package

The OS package runs commands and creates dependencies that change a task environment. Its current API version is `1`:

```python
load(
    "@os@1",
    "env_append",
    "env_get",
    "env_prepend",
    "env_set",
    "env_unset",
    "run",
)
```

## Task Environments

xx does not pass the invoking shell's full environment to tasks. Each task starts from a clean operating-system environment containing system-provided values and standard utility paths. It also inherits `HOME` and every `XDG_*` variable from the invoking process. This avoids accidental dependencies on shell startup files, user-installed tools, and unrelated variables while preserving standard user directories.

When `HOME` is absent, empty, or relative, xx uses the operating system's user home directory. Missing, empty, or relative standard XDG Base Directory variables receive platform-appropriate defaults. On Linux and macOS these follow the XDG defaults below `HOME`, `/etc/xdg`, `/usr/local/share`, and `/usr/share`. `XDG_RUNTIME_DIR` has no standard fallback, so xx only sets it when inherited with an absolute path.

Each task receives its own clone. Dependencies passed through `deps` modify only that clone and are applied in list order.

Environment values created by `env_append` and `env_prepend` are joined with the host's path-list separator when passed to a process: `:` on Linux and macOS, `;` on Windows. This makes functions useful for `PATH` and other list-like variables.

Variable names are case-insensitive on Windows and case-sensitive on Linux and macOS.

## `run`

```python
run(command, deps=[])
```

Runs a command from the project root.

`command` must be a tuple of strings. Its first item is the executable and remaining items are arguments. A trailing comma is required for a one-item Starlark tuple:

```python
run(("tool",))
run(("go", "test", "./..."), deps=[go])
```

A bare executable name is resolved only through the task's virtual `PATH`. A relative path containing `/` or `\` is resolved from the project root. Absolute executable paths are also accepted. Standard output and standard error are forwarded to xx's output.

The returned dependency is also registered as a root task, so declaring `run(...)` is enough to execute it. It preserves environment changes from its dependencies for downstream tasks. Independent root tasks may run concurrently.

## `env_get`

```python
env_get(key)
```

Reads a variable from the entrypoint's clean base environment while the Starlark file is evaluated. It returns a string when present and `None` when absent.

It does not read changes created by `env_set`, `env_append`, or other dependencies because those changes are activated later for an individual task.

```python
load("@os@1", "env_get")

system_path = env_get("PATH")
```

## `env_set`

```python
env_set(key, value)
```

Returns a dependency that replaces the variable with one value:

```python
run(("go", "test", "./..."), deps=[env_set("GOFLAGS", "-trimpath")])
```

## `env_unset`

```python
env_unset(key)
```

Returns a dependency that removes the variable:

```python
run(("tool",), deps=[env_unset("TOOL_CONFIG")])
```

## `env_append`

```python
env_append(key, value, unique=False)
```

Returns a dependency that appends one item. Set `unique=True` to leave the variable unchanged when it already contains an equivalent item:

```python
run(
    ("project-linter", "check"),
    deps=[env_append("PATH", "tools/bin", unique=True)],
)
```

Uniqueness uses exact string comparison on Linux and macOS. On Windows, `PATH` entries are compared without case sensitivity; other variables use exact value comparison. xx does not clean or resolve paths for this comparison.

## `env_prepend`

```python
env_prepend(key, value, unique=False)
```

Works like `env_append`, but inserts the item at the beginning:

```python
run(
    ("my-tool", "check"),
    deps=[env_prepend("PATH", "tools/bin", unique=True)],
)
```

Relative `PATH` entries are resolved from the project root when xx looks up an executable.

## Ordering and Composition

Order matters. Later dependencies see and can replace earlier results:

```python
deps = [
    env_set("MODE", "check"),
    env_set("MODE", "release"),
]
```

The command receives `MODE=release`.

Combine environment dependencies with `+` for reusable groups:

```python
release_env = env_set("MODE", "release") + env_set("CGO_ENABLED", "0")

run(("tool", "build"), deps=[release_env])
```

Both forms preserve left-to-right application.

## Validation

Keys cannot be empty or contain `=` or a NUL byte. Values cannot contain a NUL byte. `run` rejects non-string command items and commands that cannot be found in the declared environment.

<!--
Sitemap

URL: https://withxx.dev/index.md
Title: xx
Description: Practical, reproducible builds without build-system ceremony

URL: https://withxx.dev/examples/commands.md
Title: Command Examples
Description: General command, environment, and entrypoint patterns.

URL: https://withxx.dev/examples/go.md
Title: Go Examples
Description: Common Go build patterns with managed SDKs.

URL: https://withxx.dev/examples/index.md
Title: Examples
Description: Common xx build and task patterns.

URL: https://withxx.dev/examples/nodejs.md
Title: Node.js Examples
Description: Common Node.js task patterns with a managed distribution.

URL: https://withxx.dev/load.md
Title: Loading Files
Description: Split xx configuration into local Starlark modules.

URL: https://withxx.dev/packages/go.md
Title: Go Package
Description: Provision an official Go SDK, run or install Go tools, and build Go binaries.

URL: https://withxx.dev/packages/nodejs.md
Title: Node.js Package
Description: Provision official Node.js distributions and run npm and npx tasks.

URL: https://withxx.dev/packages/os.md
Title: OS Package
Description: Run commands and construct isolated task environments.
-->
