Compose Environments

Compose environments use podman-compose for multi-container orchestration. Unlike the single-container container type, compose environments support sidecar containers for network filtering and future MCP server integration.

Compose environments are project-local. All generated orchestration files live in a .cc-deck/ subdirectory within the project directory. The project directory is bind-mounted at /workspace by default, providing immediate bidirectional file synchronization.

Walkthrough: Your First Compose Environment

This walkthrough takes you from an empty project directory to a running, network-filtered Claude Code session in about two minutes.

Step 1: Navigate to your project

cd ~/projects/my-api
ls
# go.mod  main.go  internal/  README.md

Step 2: Create the environment

cc-deck env create dev --type compose --gitignore

You will see output similar to:

WARNING: no image specified, using default quay.io/cc-deck/cc-deck-demo:latest
Environment "dev" created (type: compose)

The --gitignore flag automatically adds .cc-deck/ to your .gitignore so the generated files stay out of version control.

Take a look at what was generated:

ls -la .cc-deck/
# compose.yaml   .env

The compose.yaml defines the session container with your project directory mounted at /workspace. The .env file contains any auto-detected credentials from your host.

Step 3: Attach to the session

cc-deck env attach dev

This opens a Zellij session inside the container with the cc-deck sidebar plugin loaded. Your project files are immediately available:

# Inside the container:
ls /workspace
# go.mod  main.go  internal/  README.md

Edit a file on either side (host or container) and the change appears instantly on the other side.

Step 4: Add network filtering

If you want to restrict which domains the session container can access, delete and recreate with filtering:

# Detach from Zellij first (Ctrl+o d)
cc-deck env delete dev --force
cc-deck env create dev --type compose \
  --allowed-domains anthropic,github \
  --gitignore

Now the environment includes a tinyproxy sidecar. Attach and verify filtering works:

cc-deck env attach dev

# Inside the container:
curl -s https://api.anthropic.com -o /dev/null -w "%{http_code}"
# 200 (or 401 without valid key, but the connection succeeds)

curl -s https://example.com -o /dev/null -w "%{http_code}"
# Connection refused (blocked by proxy)

Step 5: Manage the lifecycle

# Detach from Zellij (Ctrl+o d)

# Check status
cc-deck env status dev

# Stop to free resources
cc-deck env stop dev

# Start again later
cc-deck env start dev

# Re-attach
cc-deck env attach dev
# Your files and Zellij session state are preserved.

Step 6: Clean up

cc-deck env delete dev
# Environment "dev" deleted

This removes all containers, the .cc-deck/ directory, and the state records. Your project files are untouched.

What you built

~/projects/my-api/              <-- your project (untouched)
  .cc-deck/                     <-- generated, gitignored
    compose.yaml                <-- container orchestration
    .env                        <-- credentials
    proxy/                      <-- only with --allowed-domains
      tinyproxy.conf
      whitelist

The session container runs your project at /workspace with full Claude Code tooling. The optional proxy sidecar enforces a domain allowlist for network security.


Creating a Compose Environment

cd ~/projects/my-api
cc-deck env create mydev --type compose

This command performs several steps automatically:

  1. Detects the compose runtime (podman-compose or docker compose).

  2. Generates orchestration files in .cc-deck/ (compose.yaml, .env, optional proxy config).

  3. Detects host credentials and writes them to .cc-deck/.env.

  4. Starts the compose project with podman-compose up -d.

  5. Records the environment in both the definition and state stores.

Storage Options

Type Behavior

host-path (default)

Bind-mounts the project directory at /workspace. Changes are bidirectional and immediate.

named-volume

Creates a Podman named volume mounted at /workspace. Use --storage named-volume when isolation is preferred.

Project Directory

The --path flag specifies which directory to use as the project root. When omitted, the current working directory is used.

cc-deck env create mydev --type compose --path /home/user/projects/my-api

Network Filtering

The --allowed-domains flag adds a tinyproxy sidecar container that filters outbound network traffic. The session container can only reach domains in the allowlist.

cc-deck env create filtered --type compose --allowed-domains anthropic,github,npm

Domain groups are expanded using the built-in domain resolver. You can specify built-in groups (e.g., anthropic, github), user-defined groups, or literal domain patterns.

When filtering is active:

  • The session container has no direct internet access.

  • All outbound traffic routes through the proxy sidecar.

  • Requests to allowed domains succeed normally.

  • Requests to unlisted domains are blocked.

Credential Passthrough

Compose environments auto-detect host credentials and inject them into the session container. The detection logic matches the container environment type.

Supported credential sources:

  • ANTHROPIC_API_KEY for direct API access

  • Google Vertex AI credentials (environment variables and ADC file)

  • Amazon Bedrock credentials (access keys, session token, profile)

  • Explicit credentials via --credential KEY=VALUE

Environment variable credentials are written to .cc-deck/.env. File-based credentials (like the Google ADC file) are copied to .cc-deck/secrets/ and mounted at /run/secrets/ inside the container.

Lifecycle Management

All standard environment lifecycle commands work with compose environments.

# Stop the environment (frees resources, preserves state)
cc-deck env stop mydev

# Start a stopped environment
cc-deck env start mydev

# Delete the environment and all artifacts
cc-deck env delete mydev

# Force-delete a running environment
cc-deck env delete mydev --force

Stopping and starting preserves all files in the project directory (bind mount mode) and in the named volume (if used).

Deleting an environment removes all containers, cleans up secrets, and removes the .cc-deck/ directory from the project.

Project Hygiene

When creating a compose environment in a git-tracked project, the system warns if .cc-deck/ is not in .gitignore. Use the --gitignore flag to add it automatically.

cc-deck env create mydev --type compose --gitignore

The .cc-deck/ directory contains only generated artifacts. It should not be committed to version control.

Command Reference

# Create with all options
cc-deck env create mydev --type compose \
  --image quay.io/cc-deck/cc-deck-demo:latest \
  --allowed-domains anthropic,github \
  --port 8080:8080 \
  --path /path/to/project \
  --credential KEY=VALUE \
  --auth auto \
  --gitignore

# Attach to the environment
cc-deck env attach mydev

# Run a command inside the session container
cc-deck env exec mydev -- ls /workspace

# Check status
cc-deck env status mydev