# Overview

> Cordium documentation. Canonical page: <https://octelium.com/docs/cordium/latest/workspaces/overview>.

A *Workspace*'s behavior is determined by its spec. The same spec structure is used by *Workspaces*, *Templates* and the repository configuration files, and it is what you write in the YAML files that you pass to `cordium run --file`, `cordium create workspace --file` and `cordium create template --file`. This section covers every configuration option of the spec, while this page explains how the spec is structured, how its configuration levels are merged, and how variables work.

> **Note:**
>
> For exact fields, types, and enum values, you can always refer to the [Workspace JSON Schema](https://octelium.com/schemas/cordium/latest/cordium.v1.Workspace.schema.json) and the [Template JSON Schema](https://octelium.com/schemas/cordium/latest/cordium.v1.Template.schema.json), or to the interactive schema viewers at the end of this page.

## Spec Structure

Here is the top-level structure of a spec:

```yaml
spec:
  image: ...                  # The container image (read more in "Images and Devcontainers")
  repository: ...             # The primary repository (read more in "Repositories")
  additionalRepositories: ... # Secondary repositories
  runtime:                    # Read more in "Environment and Tasks"
    envVars: ...
    tasks: ...
    volumeMounts: ...         # Read more in "Volumes"
    network: ...              # Read more in "Network Policies"
    octelium: ...             # Read more in "Secretless Access"
    filesystem: ...
    capabilities: ...
    timeout: ...
    autoStop: ...
    cmd: ...
    entrypoint: ...
    disableInit: ...
    devcontainers: ...
  applications: ...           # Workspaces only (read more in "Applications and Ports")
  limit: ...                  # Read more in "Resources and Timeouts"
  vars: ...                   # Variables (read more below)
  isEphemeral: ...            # Workspaces only
  gitProvider: ...            # Templates only (read more in "Secrets and GitProviders")
```

Here is a complete example of a development *Workspace* for a Go service that uses most of these sections:

```yaml
spec:
  image:
    registry:
      url: golang:1.26-bookworm
  repository:
    url: https://github.com/acme-corp/payments-api
    cloneOptions:
      branch: main
  vars:
    - name: LOG_LEVEL
      value: info
  runtime:
    envVars:
      - key: LOG_LEVEL
        value: ${{ vars.LOG_LEVEL }}
      - key: CGO_ENABLED
        value: "0"
      - key: STRIPE_API_KEY
        fromSecret: stripe-test-key.payments.cordium
    tasks:
      - name: deps
        type: ON_CREATE
        workingDir: /workspace/repo
        run: go mod download
        onFailure: ON_FAILURE_ABORT
      - name: dev-server
        type: POST_START
        workingDir: /workspace/repo
        run: go run ./cmd/server
        isBackground: true
    volumeMounts:
      - volumeRef:
          name: go-cache
        mountPath: /cache
  applications:
    - name: api
      port: 8080
      isDefault: true
  limit:
    cpu:
      millicores: 4000
    memory:
      megabytes: 8192
    storage:
      megabytes: 30000
```

You can run it as follows:

```bash
cordium run --space payments.cordium --file workspace.yaml
# Override a variable for this Workspace
cordium run --space payments.cordium --file workspace.yaml --var LOG_LEVEL=debug
```

## Configuration Levels

The effective configuration of a *Workspace* run is assembled at initialization time from several levels:

```text
Repository configuration file (.cordium.yaml), if any   (the most specific level)
      ↓
Workspace spec
      ↓
Template spec
      ↓
Space runtime configuration and limits
      ↓
UserConfig (personal environment variables, tasks and dotfiles)
      ↓
ClusterConfig defaults and caps   (the least specific level)
```

Here is how each part of the spec is merged:

- **Image, repository and other single values** of the *Workspace* spec override those of the *Template* spec, and those of the repository configuration file override both. Nested objects are merged field by field, which means that you can, for example, only override the `cloneOptions.branch` of the *Template*'s repository.
- **Lists** (e.g. environment variables, tasks, additional repositories, *Volume* mounts, egress rules and capabilities) are concatenated: the *Template*'s entries first, followed by the *Workspace*'s and then the repository configuration file's.
- **Environment variables** with the same key are resolved by precedence: the *Workspace* wins over the *Template*, which wins over the *Space*, which wins over the *UserConfig*.
- **Lifecycle tasks** run in the following order: the *Template*'s tasks, then the *Workspace*'s, then the *UserConfig*'s, and finally the *Space*'s, within each task type (read more [here](https://octelium.com/docs/cordium/latest/workspaces/runtime.md#task-order)).
- **Resource limits** are resolved by precedence (*Workspace* > *Template* > *Space* default > *Cluster* default), where the most specific `limit` is taken as a whole, and then capped by the *Space* and *Cluster* maximums. For example, if a *Workspace* requests 16 CPU cores while its *Space*'s maximum is 8 cores, it gets 8 cores (read more [here](https://octelium.com/docs/cordium/latest/workspaces/resources.md)).
- **Variables** are resolved by precedence (run-specific variables > *Workspace* > *Template*) and substituted after all the levels are merged (read more [below](#variables)).
- **Applications** and **ephemerality** are only defined by the *Workspace* itself, while the **GitProvider** is only defined by its *Template*.

> **Note:**
>
> *Workspace* specs can be updated at any time (e.g. via the web portal or the `UpdateWorkspace` API), and *Template* specs can be updated by the *Space* admins. Changes take effect the next time the *Workspace* starts. Note that `ON_CREATE` tasks and image changes only take effect on fresh runs (i.e. the first run of a persistent *Workspace* and every run of an ephemeral one).

## Variables

Variables let you parameterize *Templates* and *Workspaces*. They are declared in the `vars` list and referenced from string fields via the `${{ vars.NAME }}` syntax (`${{vars.NAME}}` also works). Here is an example of a parameterized *Template* for running a test suite of a monorepo:

```yaml
spec:
  vars:
    - name: REF
      value: main
    - name: SERVICE
      value: services/payments
    - name: RACE
      value: "true"
  image:
    registry:
      url: golang:1.26-bookworm
  repository:
    url: https://github.com/acme-corp/monorepo
  runtime:
    autoStop: true
    tasks:
      - name: checkout
        type: ON_CREATE
        workingDir: /workspace/repo
        onFailure: ON_FAILURE_ABORT
        run: git fetch -q origin "${{ vars.REF }}" && git checkout -q FETCH_HEAD
      - name: test
        type: ON_CREATE
        workingDir: /workspace/repo/${{ vars.SERVICE }}
        onFailure: ON_FAILURE_ABORT
        run: |
          if [ "${{ vars.RACE }}" = "true" ]; then
            go test -race ./...
          else
            go test ./...
          fi
```

Variables can be set or overridden at three levels:

```bash
# 1. In the Template spec (the defaults above)
cordium create template monorepo-test.payments.cordium --file template.yaml

# 2. In the Workspace spec, at creation time
cordium create ws --template monorepo-test.payments.cordium --ephemeral \
  --var SERVICE=services/ledger --var REF=feat/ledger-v2

# 3. For a single run, without modifying the Workspace's spec
cordium start abc --var REF=fix/rounding
```

Variables are substituted after all the configuration levels are merged, in the following fields:

- The registry image URL, the Dockerfile URL, and the URL, checkout, Dockerfile path and context of a git-based image.
- The URL, branch and checkout of the primary and additional repositories.
- The values of the environment variables (but not the names of the referenced *Secrets*).
- The `run` script, the `workingDir` and the environment variable values of the lifecycle tasks.

> **Note:**
>
> Variables are not substituted inside inline Dockerfiles. References to variables that are not declared at any level are replaced by an empty string.

> **Warning:**
>
> The repository and Dockerfile URLs and the git branches and checkouts are validated when a *Workspace* or a *Template* is created or updated, i.e. before the variables are substituted. Currently, this means that variables cannot be used in the `branch` and `checkout` fields, and that variables used in URLs must be written without spaces (e.g. `https://github.com/${{vars.REPO}}`). To parameterize the branch or the commit, check it out in an `ON_CREATE` task as shown above.

## Repository Configuration Files

A repository can carry its own Cordium configuration in a file at its root, so that the configuration lives in version control alongside the code. Cordium looks for the first of the following files in the primary repository after cloning it:

```text
.cordium/workspace.yaml
.cordium/workspace.yml
.cordium.yaml
.cordium.yml
```

The file contains a spec in the same format as above, and it is merged on top of the *Workspace* and *Template* specs as described [above](#configuration-levels). Here is an example `.cordium/workspace.yaml`:

```yaml
spec:
  runtime:
    envVars:
      - key: NODE_ENV
        value: development
    tasks:
      - name: install
        type: ON_CREATE
        workingDir: /workspace/repo
        run: npm ci
        onFailure: ON_FAILURE_ABORT
      - name: dev
        type: POST_START
        workingDir: /workspace/repo
        run: npm run dev -- --host 0.0.0.0
        isBackground: true
```

Applications are not read from the repository configuration file since they belong to the *Workspace* itself. The image defined in the file is only used when neither the *Workspace* nor its *Template* sets an image, or when they explicitly build the image from the repository (read more [here](https://octelium.com/docs/cordium/latest/workspaces/image.md#from-the-workspace-repository)). The file is validated like any other spec, which means that, for example, the *Secrets* it references must exist in the *Workspace*'s *Space*.

## The Workspace Environment

Every *Workspace* provides the following environment regardless of its image:

| Item                                 | Description                                                                                                                                                             |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/workspace`                         | The *Workspace*'s persistent working directory, owned by the *Workspace* user.                                                                                          |
| `/workspace/repo`                    | The primary repository, if any.                                                                                                                                         |
| `/workspace/additional-repos/<NAME>` | The additional repositories, if any.                                                                                                                                    |
| `$HOME`                              | The *Workspace* user's home directory, which is persisted along with the rest of the container's filesystem for persistent *Workspaces*.                                |
| `CORDIUM_NAME`                       | The *Workspace*'s name (e.g. `x7k2`).                                                                                                                                   |
| `CORDIUM_HOSTNAME`                   | The *Workspace*'s public hostname (e.g. `x7k2.cordium.example.com`).                                                                                                    |
| `OCTELIUM_DOMAIN`                    | The *Cluster* domain.                                                                                                                                                   |
| `OCTELIUM_AUTH_PROXY_SOCKET`         | The Unix socket of the *Workspace*'s authentication proxy, used by the `cordium`, `octelium` and `octeliumctl` CLIs.                                                    |
| `SSH_AUTH_SOCK`                      | The SSH agent holding the private keys of your `SSH_KEY` *UserSecrets* (read more [here](https://octelium.com/docs/cordium/latest/workspaces/user-config.md#ssh-keys)). |

The *Workspace* user is chosen as follows: the `octelium` user if the image defines one, otherwise the image's existing user with the UID `1000` (e.g. `ubuntu` in Ubuntu images or `node` in the official Node.js images), otherwise Cordium creates an `octelium` user with the UID `1000`. The *Workspace* user can always escalate to root via passwordless `sudo`, and lifecycle tasks and `cordium exec` commands can run as root via their `runAsRoot` and `--root` options respectively. The hostname of every *Workspace* is `cordium`.

## API Reference

[Workspace JSON Schema (Cordium cordium/v1, latest documentation)](https://octelium.com/schemas/cordium/latest/cordium.v1.Workspace.schema.json)

[Template JSON Schema (Cordium cordium/v1, latest documentation)](https://octelium.com/schemas/cordium/latest/cordium.v1.Template.schema.json)
