# **Shell-Cell** Blueprint Reference
**Shell-Cell** builds your environment by reading a set of instructions from a `scell.cue` file.
`scell.cue` - is a [CUE](https://cuelang.org) formatted file that contains everything needed to configure your session.
To learn more about CUE capabilities go to the original [docs](https://cuelang.org/docs/reference/spec/).
> The full formal definition of the blueprint schema is available at [`src/scell/types/scell_schema.cue`](../src/scell/types/scell_schema.cue).
Here is a minimal functional example:
```cue
main: {
from_image: "debian:bookworm"
workspace: "workdir"
shell: "/bin/bash"
hang: "while true; do sleep 3600; done"
}
```
**Shell-Cell** follows a strict logic when building your image.
It parses your target definitions into a *chain*,
moving from your entry point (`main`) down to the base "bottom" target.
The actual image building process, on contrary, happens backwards.
Starts from the "bottom" target and works its way up to your entry point (`main`):
1. `bottom_target`
2. `target_3`
3. `target_2`
4. `target_1`
5. `main`
## **Shell-Cell** target
**Shell-Cell** are comprised of a series of target declarations and recipe definitions.
```cue
"<target-name>": {
<recipe>
...
}
```
A valid target name must start with a lowercase letter and contain only lowercase letters, digits, hyphens, and underscores (pattern: `^[a-z][a-z0-9_-]*$`).
Inside each target, during the **Shell-Cell** image building process,
the instructions are executed in a specific, strict order:
1. `workspace`
2. `from` / `from_image` / `from_docker`
3. `env`
4. `copy`
5. `build`
### Statement groups
Every statement in a target belongs to one of three groups, depending on what it influences:
| **Image** | `from`, `from_image`, `from_docker`, `workspace`, `env`, `copy`, `build`, `hang` | The built Docker image. Any change to an image statement produces a different image and triggers a rebuild. |
| **Container** | `config` | How the container is started and kept alive. Changes here cause the existing container to be replaced. |
| **Session** | `shell` | The interactive shell session attached to the running container. Changes here take effect on the next session without affecting the image or container. |
### `from`, `from_image`, `from_docker`
Similar to the Dockerfile [`FROM`](https://docs.docker.com/reference/dockerfile/#from) instruction,
these statements specify the base of the **Shell-Cell** layer.
Only one of these statements must be present in the **Shell-Cell** target definition.
Either `from_image` or `from_docker` is required somewhere in the target chain — without one of them
there is no way to specify the basis of the image. `from` on its own only delegates to another target
and must eventually resolve to a `from_image` or `from_docker`.
#### `from_image`
Uses a Docker registry image as the base layer.
```cue
from_image: "<image>:<tag>"
```
#### `from_docker`
Uses a Dockerfile on the filesystem as the base layer.
The path is resolved relative to the `scell.cue` file.
```cue
from_docker: "path/to/Dockerfile"
```
#### `from`
References another [**Shell-Cell** target](#shell-cell-target), resolved recursively.
Use `+<target_name>` to reference a target in the same file, or `path/to/dir+<target_name>`
to reference a target in another `scell.cue`.
```cue
from: "+<target_name>"
```
```cue
from: "path/to/dir+<target_name>"
```
### `shell`
A location to the shell, which would be available in the build image and running container.
Such shell would be used for a **Shell-Cell** session.
Only the first `shell` statement encountered in the target chain (starting from the entry point) is used.
```cue
shell: "/bin/bash"
```
### `hang`
This instruction ensures your container stays active and doesn't exit immediately after it starts. This effectively transforms your **Shell-Cell** container into a persistent "shell server" that remains ready for you to jump in at any time.
Only the first `hang` statement encountered in the target chain (starting from the entry point) is used.
To work correctly, you must specify a command that keeps the container running indefinitely.
The most recommended approach is a simple infinite loop:
```cue
hang: "while true; do sleep 3600; done"
```
This command would be placed as a Dockerfile [`ENTRYPOINT`](https://docs.docker.com/reference/dockerfile/#entrypoint) instruction.
### `workspace` (optional)
Similar to the Dockerfile [`WORKDIR`](https://docs.docker.com/reference/dockerfile/#workdir) instruction.
```cue
workspace: "/path/to/workspace"
```
### `copy` (optional)
Copies files into the **Shell-Cell** image.
Similar to the Dockerfile [`COPY`](https://docs.docker.com/reference/dockerfile/#workdir) instruction.
```cue
copy: [
"file1 .",
"file2 .",
"file3 file4 .",
]
```
### `env` (optional)
Sets environment variables in the **Shell-Cell** image.
Similar to the Dockerfile [`ENV`](https://docs.docker.com/reference/dockerfile/#env) instruction.
Each item follows the list format `<KEY>=<VALUE>`:
```cue
env: [
"DB_HOST=localhost",
"DB_PORT=5432",
"DB_NAME=db",
"DB_DESCRIPTION=\"My Database\"",
]
```
### `build` (optional)
Will execute any commands to create a new layer on top of the current image,
during the image building process.
Similar to the Dockerfile [`RUN`](https://docs.docker.com/reference/dockerfile/#run) instruction.
```cue
build: [
"<command_1>",
"<command_2>",
]
```
### `config` (optional)
Runtime configuration for the **Shell-Cell** container.
Unlike `build`, `copy`, and `workspace`, which affect the image building process,
`config` defines how the container behaves when it runs.
All `config` statements are optional.
Only the first `config` statement encountered in the target chain (starting from the entry point) is used.
```cue
config: {
mounts: [
"<host_path>:<container_absolute_path>",
]
ports: [
"<host_port>:<container_port>",
]
services: {
"<service_name>": {
from_image: "<image>:<tag>"
shell: "<shell>"
hang: "<hang_command>"
}
}
}
```
#### `mounts`
Bind-mounts host directories into the running container.
Each mount item follows the format `<host_path>:<container_absolute_path>`.
- The **host path** can be relative (resolved relative to the `scell.cue` file location) or absolute.
Relative host paths are canonicalized during compilation, so the referenced directory must exist.
- The **container path** must be an absolute path.
```cue
config: {
mounts: [
"./src:/app/src",
"/data:/container/data",
]
}
```
#### `ports`
Publishes container ports to the host.
Partially follows the [Docker Compose short form syntax](https://docs.docker.com/reference/compose-file/services/#ports).
Each item can be one of:
| `HOST_PORT:CONTAINER_PORT` | Map a specific host port to a container port |
| `HOST_IP:HOST_PORT:CONTAINER_PORT` | Map with a specific host IP and port |
| `HOST_IP::CONTAINER_PORT` | Bind to a host IP with a random host port |
Append `/tcp` or `/udp` to any format to specify the protocol (default: `tcp`).
```cue
config: {
ports: [
"8080:80",
"127.0.0.1:9000:9000",
"6060:6060/udp",
]
}
```
## Extra Arguments (`.scell_args.cue`)
**Shell-Cell** supports a companion file `.scell_args.cue` placed in the same directory as `scell.cue`.
When present, its CUE values are unified with the blueprint before compilation, allowing you to supply
concrete values for CUE constraints declared in `scell.cue`.
This is useful for parameterize a blueprint — keeping the blueprint generic and checked in, while
supplying environment-specific or personal overrides through a gitignored `.scell_args.cue` file.
Typical uses include machine-specific paths, image tags, and secrets such as API keys or tokens
that should never be committed to version control.
To learn more about CUE capabilities go to the original [docs](https://cuelang.org/docs/reference/spec/).
### How it works
Declare open constraints (string fields) in `scell.cue`:
```cue
_from_image_arg: string
_workspace_arg: string
_env_arg: int
main: {
from_image: _from_image_arg
workspace: _workspace_arg
shell: "/bin/bash"
hang: "while true; do sleep 3600; done"
env: [
"SOME_ENV=\(_env_arg)"
]
}
```
Then provide the concrete values in `.scell_args.cue`. Since the file is full CUE, you can use
all CUE features — including string interpolation to compose values from other fields:
```cue
_from_image_arg:"debian:bookworm"
_workspace_arg: "/app"
_env_arg: 10
```
At compile time, **Shell-Cell** unifies the two files. The result is equivalent to having written
those values directly in `scell.cue`.
```cue
main: {
from_image: "debian:bookworm"
workspace: "/app"
shell: "/bin/bash"
hang: "while true; do sleep 3600; done"
env: ["SOME_ENV=10"]
}
```
### Notes
- `.scell_args.cue` is optional. If it is absent, the blueprint is compiled as-is.
- The file is looked up only in the same directory as `scell.cue`; there is no recursive search.
- Any CUE unification error (e.g. a value that conflicts with a constraint) is reported as a user error.
- Add `.scell_args.cue` to `.gitignore` to keep secrets and personal overrides out of version control.