How to configure workspaces
This guide shows how to define and tune workspaces in jailoc's configuration file. For a full reference of every field and its type, see Configuration reference.
Config file location
jailoc stores its configuration at:
~/.config/jailoc/config.toml
The file is created automatically on first run with a default workspace already in place. You can edit it with any text editor.
Automatic workspace detection
Most commands accept an explicit --workspace flag. When omitted, jailoc selects the workspace automatically using this resolution order:
- Explicit
--workspaceflag — if set, use that workspace. - Longest-prefix CWD match — compare the current working directory against every workspace's configured
paths. The workspace whose path is the longest matching prefix wins. Equal-length matches break alphabetically. defaultfallback — if no path matches, thedefaultworkspace is used.
Given these two workspaces:
[workspaces.broad]
paths = ["/home/you/projects"]
[workspaces.specific]
paths = ["/home/you/projects/api"]
Running jailoc up from /home/you/projects/api/src selects specific (longer prefix match). Running from /home/you/projects/other selects broad.
jailoc add uses the path being added (not the raw CWD) for detection. If --workspace is set explicitly and the path being added is not under any of that workspace's configured paths, jailoc returns an error.
Define a workspace
Each workspace is a [workspaces.<name>] section. The only required field is paths.
[workspaces.default]
paths = ["/home/you/projects/myproject"]
The first entry in paths becomes the container's working directory. All paths are bind-mounted inside the container at their original absolute path, so /home/you/projects/myproject is accessible at the same path inside the container.
Note
~ is expanded to your home directory. Paths under system directories (/usr, /etc, /var, /home/agent, and similar) are rejected.
Define multiple workspaces
Add as many [workspaces.<name>] sections as you need:
[workspaces.api]
paths = ["/home/you/projects/api", "/home/you/projects/shared-libs"]
[workspaces.frontend]
paths = ["/home/you/projects/frontend"]
Each workspace gets its own isolated container environment.
Port allocation
jailoc assigns ports starting at 4096, sorted alphabetically by workspace name. Given the example above:
| Workspace | Port |
|---|---|
api |
4096 |
frontend |
4097 |
Adding a workspace with a name that sorts earlier shifts the ports of those that follow.
Add multiple paths
Pass more than one directory to paths when an agent needs access to several repositories at once:
[workspaces.api]
paths = [
"/home/you/projects/api",
"/home/you/projects/shared-libs",
]
All listed paths are mounted read-write. The first is the working directory.
Allow specific hosts or networks
By default, containers cannot reach private networks. To grant access to specific services, use allowed_hosts or allowed_networks.
[workspaces.api]
paths = ["/home/you/projects/api"]
allowed_hosts = ["internal-registry.example.com"]
allowed_networks = ["10.10.5.0/24"]
See How to allow specific hosts or networks for step-by-step instructions.
Set a custom image
To use a pre-built image directly, set image in the workspace block:
[workspaces.myproject]
paths = ["/home/you/projects/myproject"]
image = "myregistry.example.com/myteam/myimage:v1.2.3"
To build from a custom Dockerfile instead, use dockerfile:
[workspaces.myproject]
paths = ["/home/you/projects/myproject"]
dockerfile = "https://git.example.com/team/dockerfiles/-/raw/main/myproject.Dockerfile"
See How to use a custom Docker image for all image customization options.
Set a build context
When building a workspace-specific image layer, jailoc uses the parent directory of the workspace dockerfile as the Docker build context by default. Override it with build_context:
[workspaces.myproject]
paths = ["/home/you/projects/myproject"]
build_context = "/home/you/projects/myproject/docker"
Set a connection mode
Control how jailoc connects to the running container:
[workspaces.myproject]
paths = ["/home/you/projects/myproject"]
mode = "remote" # or "exec", or omit for auto-detect
See How to switch between remote and exec mode for details.
Set environment variables
Pass environment variables to the agent container using the env field:
[workspaces.api]
paths = ["/home/you/projects/api"]
env = ["MY_TOKEN=abc123", "LOG_LEVEL=debug"]
To load variables from a file, use env_file. The file must exist at config load time and follow Docker .env format (KEY=VALUE, # comments, quoted values):
[workspaces.api]
paths = ["/home/you/projects/api"]
env_file = ["~/.config/jailoc/api.env"]
Both can be combined. env entries override env_file entries with the same key.
To apply env vars to all workspaces, use the [defaults] section:
[defaults]
env = ["GOPRIVATE=*.example.com"]
env_file = ["~/.config/jailoc/shared.env"]
Note
Several keys are reserved and cannot be set: OPENCODE_LOG, OPENCODE_SERVER_PASSWORD, DOCKER_HOST, DOCKER_TLS_CERTDIR, DOCKER_CERT_PATH, DOCKER_TLS_VERIFY, SSH_AUTH_SOCK. Setting any of these causes a config validation error. OPENCODE_SERVER_PASSWORD is managed automatically by jailoc. Setting it in env or env_file is rejected, but it can be set as an OS environment variable to override the automatic cascade (useful for CI/CD).
Configure mounts
jailoc mounts several host directories into the container by default (OpenCode config, session transcripts, agent tooling). To add extra mounts or override the defaults, use the mounts field.
Add a host directory to the container:
[workspaces.my-project]
paths = ["/home/you/projects/my-project"]
mounts = ["~/.local/share/opencode:/home/agent/.local/share/opencode"]
Each entry follows host:container[:mode] format. The mode is ro (read-only) or rw (read-write, the default).
To remove a default mount, set an empty host source for that container path:
[workspaces.my-project]
paths = ["/home/you/projects/my-project"]
mounts = [":/home/agent/.opencode:ro"]
This removes the ~/.opencode mount for the my-project workspace.
Mounts set in [defaults] apply to all workspaces. Per-workspace mounts override defaults for the same container path:
[defaults]
mounts = ["~/.local/share/opencode:/home/agent/.local/share/opencode:ro"]
[workspaces.my-project]
paths = ["/home/you/projects/my-project"]
mounts = ["~/.local/share/opencode:/home/agent/.local/share/opencode:rw"]
Pass through OpenCode auth credentials
The container's ~/.local/share/opencode is a named Docker volume by default — your host auth.json is not available inside. To pass it through without replacing the entire volume, mount just the file:
[defaults]
mounts = ["~/.local/share/opencode/auth.json:/home/agent/.local/share/opencode/auth.json:ro"]
The bind mount overlays the single file on top of the named volume. The rest of the data directory (sessions, state) stays in the named Docker volume.
Share additional paths
To make additional host directories (e.g. shared AI instruction files consumed by both Copilot and OpenCode) available inside the container, mount the directory read-only:
[defaults]
mounts = ["~/.config/ai-instructions:/home/agent/.config/ai-instructions:ro"]
~ on the host side expands to your home directory. The container path must use an absolute path — the agent's home is /home/agent.
Note
Dangerous host paths are forbidden in mounts: /, /boot, /dev, /etc, /private, /proc, /sys, /run, /var, ~/.ssh, ~/.gnupg, ~/.aws. Container destinations under /home/agent/... are allowed; other system directories (/usr, /etc, /var, etc.) are forbidden.
See Configuration reference for the full mount format, merge semantics, and validation rules.
Forward SSH agent and Git config
To let the agent clone private repositories or push over SSH, enable SSH agent forwarding. Git configuration is mounted by default.
[defaults]
ssh_auth_sock = true
These can also be set per-workspace. See How to pass through SSH and Git config for details.
Set resource limits
Control the CPU and memory allocated to the opencode container with cpu and memory:
[defaults]
cpu = 2.0
memory = "4g"
[workspaces.heavy-agent]
cpu = 8.0
memory = "16g"
Both fields are optional. Workspace values override defaults; when neither is set, the fallback is 2.0 CPU cores and "4g" memory. The memory field accepts Docker memory format: a positive integer optionally followed by k, m, or g (e.g. 512m, 4g, 1024).