Merge Strategies for Profile and Project Config
ccpod merges configuration in layers. Each asset has a documented strategy so the result is predictable.
Merging happens across three independent axes — each has its own control:
| Axis | Controlled by | Configurable? |
|---|---|---|
| ccpod settings (ports, services, env, claudeArgs, init) | merge in .ccpod.yml | yes |
CLAUDE.md content | config.claudeMd in .ccpod.yml | yes |
.claude/settings.json | — | no — always deep-merged, project wins on conflicts |
They are separate flags because the assets have different merge semantics: CLAUDE.md is text (append vs. replace), settings.json is always deep-merged, and ccpod settings vary per asset type.
Strategy switches
Section titled “Strategy switches”| Setting | Where | Values | Default |
|---|---|---|---|
merge | .ccpod.yml | deep | override | deep |
config.claudeMd | .ccpod.yml | append | override | append |
isolation | profile.yml | true | false | false |
merge: override makes the project config replace the profile entirely for the listed sections. merge: deep (default) layers the project on top of the profile per asset, with the rules below.
When the profile sets isolation: true, all project config is ignored — merge strategy, CLAUDE.md, settings.json, env keys, MCP ports, and .claude/ assets. The profile config is used as-is. See Profile Configuration.
Per-asset rules (deep merge)
Section titled “Per-asset rules (deep merge)”| Asset | Rule |
|---|---|
settings.json | Deep merge. Project wins on conflicting keys. |
CLAUDE.md | Profile content first, then project appended. Set config.claudeMd: override to replace. |
skills/ | Union. Symlinks are skipped. |
enabledPlugins (in settings.json) | Deep-merged with the rest of settings.json. The plugins: install list lives in the profile only. |
hooks/ | Arrays merged by event type. |
marketplaces | Object spread; project keys win. |
services | Merged by key — only if the profile sets allowProjectServices: true; otherwise project services are ignored. |
env | Union of both lists. Project bare names (host-var forwarding) need allowProjectEnvForward in the profile. |
ports.list | Concatenated; project ports bind to 127.0.0.1 only. |
network | Ignored. The policy and allow-list are profile-owned; a project that declares network: gets a warning. See Network Policy. |
CLI overrides
Section titled “CLI overrides”Run-level flags take final precedence:
| Flag | Effect |
|---|---|
--profile <name> | Override which profile to use. |
--env KEY=VALUE | Inject an env var (or override one already forwarded). |
--rebuild | Force image rebuild / repull regardless of cache. |
--no-state | Force state: ephemeral for this run only. |
--file <path> | Headless mode: the prompt is read from this file (relative to the project; absolute paths and .. are rejected) and run with claude -p. |
"prompt text" | Headless mode via inline prompt. Mutually exclusive with --file. |
-- <args> | Flags appended verbatim to the claude command. Appended after claudeArgs from profile/project. |
Inspecting the result
Section titled “Inspecting the result”ccpod config showThe output shows the fully resolved ResolvedConfig: image, env (keys only), ports, services, and the the allowProject* flags and which project entries were ignored. (The merged config directory itself lives under a private per-user dir, ${TMPDIR}/ccpod-u<uid>/.)