Cordium documentation · Latest
Environment and Tasks
The spec.runtime field controls the environment variables, lifecycle tasks and the container behavior of a Workspace.
Environment Variables
Environment variables are injected into the Workspace container and are therefore available to its lifecycle tasks, terminals, cordium exec commands and SSH sessions. Values can be static strings or resolved from the Secrets of the Workspace's Space, which are referred to by their full name:
If the same key is defined at several levels, the most specific level wins (i.e. Workspace > Template > Space > UserConfig). You can also set them via the CLI:
A Secret-sourced environment variable is readable by every process running inside the Workspace, including AI agents. Whenever the credential protects a resource that can be exposed as an Octelium Service (e.g. an HTTP API, an LLM provider, a database or an SSH server), prefer secretless access, which keeps the credential entirely out of the Workspace (read more here).
Lifecycle Tasks
Tasks are shell commands that run at defined points of the Workspace lifecycle. Every task supports the following fields:
| Field | Description |
name | A name for the task, used in the logs and in failure reports. |
run | The script to execute via the Workspace user's login shell (e.g. bash, zsh or sh). Multi-line scripts are supported. |
type | ON_CREATE, POST_START or PRE_STOP. Required. |
workingDir | The working directory (e.g. /workspace/repo). It is recommended to always set it explicitly. |
isBackground | Starts the task without waiting for it to complete (e.g. dev servers and daemons). |
runAsRoot | Runs the task as root instead of the Workspace user. |
onFailure | ON_FAILURE_ABORT fails the Workspace run if the task fails, while ON_FAILURE_CONTINUE (the default) logs the failure and continues the initialization. |
envVars | Task-specific environment variables (key and value), merged with the Workspace's. |
Task Types
ON_CREATE tasks run on fresh runs only, i.e. the first run of a persistent Workspace and every run of an ephemeral one. They do not run again on the subsequent starts of a persistent Workspace, nor in Workspaces that are restored from a Template pre-build or a WorkspaceSnapshot, since their effects are already part of the restored storage. Use them for one-time setup: installing dependencies, compiling, running database migrations and seeding data.
POST_START tasks run on every start of the Workspace, after the ON_CREATE tasks. Use them for starting background services and dev servers, and for any work that needs secretless access to Octelium Services (see below).
PRE_STOP tasks run when the Workspace is stopping, before its container is stopped, and they must complete within 10 minutes. Use them for graceful shutdowns, flushing buffers or uploading results.
Here is an example:
Task Order
Within each task type, the foreground tasks run sequentially in the following order: the Template's tasks, the Workspace's tasks, the repository configuration file's tasks, the UserConfig's tasks and finally the Space's tasks. Background tasks are started in the same order but are not waited for. The Workspace becomes RUNNING once all the ON_CREATE and foreground POST_START tasks complete.
Every Workspace runs octelium connect as the very first POST_START task in the background, which is what provides its secretless access to Octelium Services. Therefore, tasks that access Octelium Services (e.g. a migration against a database Service or an AI agent that uses an LLM Service) must be POST_START tasks. Since the connection is established asynchronously, such tasks should wait for the Service to become reachable first, for example:
Timeouts and Failures
All the foreground ON_CREATE and POST_START tasks of a run must complete within 60 minutes on fresh runs and within 20 minutes on the subsequent runs of a persistent Workspace. Longer jobs (e.g. long-running AI agent sessions) should run as background tasks.
When a task with onFailure: ON_FAILURE_ABORT fails, the Workspace run fails with a Task failure that reports the task's name and exit code, and the Workspace is stopped. You can inspect the task output via cordium logs and the web portal. Tasks without ON_FAILURE_ABORT only log their failures. Since scripts run via the Workspace user's login shell, which is sh in some images, write portable scripts or explicitly invoke bash -c when you need Bash-specific features.
Auto-Stop
Setting autoStop: true causes the Workspace to stop automatically as soon as all of its ON_CREATE and foreground POST_START tasks complete. Background tasks are not waited for. This is designed for CI/CD runs, batch jobs and unattended AI agent runs:
You can wait for such a Workspace to finish via the SDKs' WaitUntilStopped/wait_until_stopped() helpers, which also report whether the run failed. For jobs that may exceed the foreground task timeout, run the job as a background task that stops its own Workspace once done via cordium stop, which stops the current Workspace when no name is given:
Container Command and Entrypoint
By default, the Workspace container keeps the image's entrypoint and runs sleep infinity as its command, with a minimal init process as PID 1 that reaps zombie processes. You can override them as follows:
Only set disableInit: true if the image already includes its own init system.
Filesystem and Capabilities
You can make the container's root filesystem read-only. /workspace, the home directory, /tmp, /var/tmp and mounted Volumes stay writable:
You can also add and drop Linux capabilities. They are merged with the capabilities set at the Space and ClusterConfig levels:
Or via the CLI:
Capabilities only apply inside the Workspace's own user namespace, which is mapped to an unprivileged user on the host. In other words, even CAP_SYS_ADMIN inside a Workspace does not grant any privilege outside of it.
Nested Containers
Workspaces can run their own containers via rootless Podman, which is useful for running databases and other dependencies of integration tests, or for building and pushing container images. Install Podman (e.g. apt-get install -y podman) via the image or a task, and use it as root via sudo (read the complete example here):