shell-cell 1.6.3

Shell-Cell. CLI app to spawn and manage containerized shell environments
# **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:

| Group | Statements | 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:

| Format | Description |
|---|---|
| `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.