Skip to content

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:

AxisControlled byConfigurable?
ccpod settings (ports, services, env, claudeArgs, init)merge in .ccpod.ymlyes
CLAUDE.md contentconfig.claudeMd in .ccpod.ymlyes
.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.

SettingWhereValuesDefault
merge.ccpod.ymldeep | overridedeep
config.claudeMd.ccpod.ymlappend | overrideappend
isolationprofile.ymltrue | falsefalse

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.

AssetRule
settings.jsonDeep merge. Project wins on conflicting keys.
CLAUDE.mdProfile 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.
marketplacesObject spread; project keys win.
servicesMerged by key — only if the profile sets allowProjectServices: true; otherwise project services are ignored.
envUnion of both lists. Project bare names (host-var forwarding) need allowProjectEnvForward in the profile.
ports.listConcatenated; project ports bind to 127.0.0.1 only.
networkIgnored. The policy and allow-list are profile-owned; a project that declares network: gets a warning. See Network Policy.

Run-level flags take final precedence:

FlagEffect
--profile <name>Override which profile to use.
--env KEY=VALUEInject an env var (or override one already forwarded).
--rebuildForce image rebuild / repull regardless of cache.
--no-stateForce 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.
Terminal window
ccpod config show

The 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>/.)