Profile Configuration
A profile is a YAML file at ~/.ccpod/profiles/<name>/profile.yml. ccpod validates it with Zod at load time — invalid files fail fast with a readable error.
Full example
Section titled “Full example”name: personaldescription: My personal Claude environment
config: source: local # "local" | "git" path: ~/.my-claude-config # local path to config dir # source: git # repo: https://github.com/org/claude-config # sync: daily # "always" | "daily" | "pin" # ref: main
image: use: ghcr.io/yorch/ccpod:latest # use: build # dockerfile: "{{profile_dir}}/Dockerfile"
auth: type: api-key # "api-key" | "oauth" keyEnv: ANTHROPIC_API_KEY # env var to read from # keyFile: ~/.ccpod/credentials/default/api-key # must be under ~/.ccpod
state: ephemeral # "ephemeral" (default) | "persistent"
ssh: agentForward: true # forward SSH_AUTH_SOCK mountSshDir: false # mount ~/.ssh read-only
network: policy: full # "full" | "restricted" allow: [] # domains/IPs allowed in restricted mode
ports: list: - "3000:3000" # host:container autoDetectMcp: true # expose HTTP/SSE MCP ports from .mcp.json
plugins: - mcp-server-brave-search # delta-installed on first run
env: - DATABASE_URL # host env vars to forward
services: postgres: image: postgres:17 env: POSTGRES_PASSWORD: dev volumes: - ccpod-pg-data:/var/lib/postgresql/dataField reference
Section titled “Field reference”name (required)
Section titled “name (required)”/^[a-zA-Z0-9_-]{1,64}$/. Used as a directory name and Docker label. Validated at parse time.
config (required)
Section titled “config (required)”| Field | Type | Notes |
|---|---|---|
source | local | git | Where to read the Claude config tree. |
path | string | Required when source: local. Tilde-expanded. |
repo | string | Required when source: git. HTTPS or SSH URL. |
sync | always | daily | pin | When to refresh the clone. pin never re-pulls. |
ref | string | Branch, tag, or commit to check out. Defaults to remote HEAD. |
image (required)
Section titled “image (required)”| Field | Type | Notes |
|---|---|---|
use | string | Image reference (e.g. ghcr.io/yorch/ccpod:latest) or the literal build. |
dockerfile | string | Required when use: build. Absolute path, path relative to $PWD, or {{profile_dir}}/Dockerfile to reference a Dockerfile inside the profile directory. |
When use: build, both ccpod run and ccpod image build use the same tag ccpod-local-<profile>-<hash>:latest (hash derived from Dockerfile contents). Running ccpod image build pre-builds the image so ccpod run reuses it without rebuilding. Override the tag with --tag. Force a rebuild with ccpod run --rebuild.
auth (required)
Section titled “auth (required)”| Field | Type | Notes |
|---|---|---|
type | api-key | oauth | |
keyEnv | string | Env var name to read on the host (api-key only). |
keyFile | string | File on the host to read (api-key only). Must be a path under ~/.ccpod/ (no .., no escape via symlink); use keyEnv for keys stored elsewhere. |
For oauth, ccpod manages tokens in ~/.ccpod/credentials/<name>/.
ephemeral (default) wipes Claude history and session state when the container exits. persistent binds ~/.ccpod/state/<name>/ on the host into the container — history, projects, and todos survive across runs. Override per run with --no-state.
plugins
Section titled “plugins”A list of Claude Code plugin names to install on first run. ccpod passes them to the container entrypoint, which delta-installs only the ones not already present — subsequent runs are fast.
plugins: - mcp-server-brave-search - mcp-server-filesystem| Field | Default | Notes |
|---|---|---|
agentForward | true | Forwards SSH_AUTH_SOCK into the container. Rejected if the value contains :. Not supported with Podman (skipped with a warning). |
mountSshDir | false | Mounts ~/.ssh read-only. |
network
Section titled “network”| Field | Notes |
|---|---|
policy | full (bridge with internet) or restricted (allow-list only). |
allow | Hostnames/IPs to allow in restricted mode. Resolved at container start. |
See Network Policy.
| Field | Notes |
|---|---|
list | Manual host:container mappings. |
autoDetectMcp | Default true. If .mcp.json exists at $PWD, HTTP/SSE MCP ports are exposed automatically. |
A list of entries describing env vars to expose in the container. Three forms are supported:
| Form | Behaviour |
|---|---|
KEY | Forward the host value of KEY (skipped if unset on host). |
KEY=value | Set a literal value. |
KEY=${HOST_VAR} / KEY=${HOST_VAR:-default} | Interpolate a host variable into the value at run time. Missing vars without a :-default substitute an empty string and emit a warning. |
env: - DATABASE_URL # forward host DATABASE_URL - NODE_ENV=development # literal - GH_TOKEN=${GITHUB_TOKEN} # interpolate - REGION=${AWS_REGION:-us-east-1} # interpolate with defaultInterpolation syntax follows POSIX shell: ${NAME} and ${NAME:-default} only (no :?, :+, command substitution, or nesting). Names match [A-Za-z_][A-Za-z0-9_]*. The :-default portion is a literal string — variable references inside it (e.g. ${REGION:-us-${ZONE}}) are not expanded. Following POSIX semantics, a host var set to the empty string is still considered “set” and wins over :-default; only an unset var triggers the default. Interpolation is currently scoped to env values only; other string fields (image, binds, claudeArgs, etc.) take their values literally. Project .ccpod.yml env: entries and --env KEY=VALUE CLI overrides accept the same syntax.
claudeArgs
Section titled “claudeArgs”A list of extra CLI flags passed verbatim to the claude command on every run. These are appended before any claudeArgs in the project config.
claudeArgs: - "--dangerously-skip-permissions"A list of shell commands run inside the container as the node user in /workspace after config is seeded and before Claude starts. Commands execute with set -e (exit on error).
init: - npm install - git config --global user.email "dev@example.com"Merge behaviour: in deep mode (default) profile commands run first, project commands appended. In override mode, project commands replace profile commands entirely. When isolation: true, project init is ignored.
isolation
Section titled “isolation”Default false. When true, the profile ignores all project-level config for this run:
.ccpod.ymlsettings (network, claudeArgs, services, env, ports, merge strategy)- Project
CLAUDE.md - Project
.claude/settings.jsonand other.claude/assets - Project
.mcp.json(MCP port auto-detection)
The profile config is used as-is. Useful for security-sensitive profiles where you want a guaranteed, unmodifiable environment regardless of the repo being run.
isolation: trueNote:
isolationdoes not prevent profile selection — a project’s.ccpod.ymlcan still specifyprofile: my-isolated-profileto opt into it. CLI flags (--no-state,--env,--rebuild) continue to work.
permissions
Section titled “permissions”Default: none (no preset injected). Sets a Claude Code permissions.allow preset as the lowest-priority layer — your profile and project settings.json always override it.
| Preset | Effect |
|---|---|
conservative | Auto-allow Edit and Write — file edits skip prompts, Bash still prompts |
moderate | Auto-allow Bash, Edit, Write — no prompts for typical dev work |
permissive | Sets defaultMode: bypassPermissions — skips all prompts (Docker is the trust boundary) |
permissions: moderateRead, Glob, and Grep require no permission in Claude Code and are always free — no need to list them. permissive uses Claude Code’s bypassPermissions mode rather than listing individual tools, so it covers all current and future tools automatically.
The preset is injected as the lowest-priority layer. If your profile or project settings.json already sets permissions.allow, those entries are unioned with the preset (deduplicated). Explicit entries always survive.
services
Section titled “services”Sidecar containers (Postgres, Redis, queues, anything with a Docker image). Reachable from the Claude container by service name on a shared network. See Sidecar Services.
Validate it
Section titled “Validate it”ccpod config validateccpod config show # print resolved merged config