Docker Compose Skill
Installation
The skill invokes docker compose . Easiest: install Docker Desktop (includes Docker Engine + Compose):
-
Windows: Docker Desktop for Windows (WSL 2 or Hyper-V)
-
Mac: Docker Desktop for Mac (Apple Silicon or Intel)
-
Linux: Docker Desktop for Linux or Docker Engine + Compose plugin from Docker's repo
Verify: docker compose version
Cheat Sheet & Best Practices
Commands: docker compose up -d / down ; docker compose ps / logs -f <service> ; docker compose exec <service> sh ; docker compose build --no-cache ; docker compose -f compose.prod.yaml config — validate.
YAML: Use named volumes for DBs (postgres_data:/var/lib/postgresql/data ). Use healthchecks (healthcheck: with test , interval , timeout , retries ). One network default; reference services by name (e.g. http://api:3000 ). Use env_file or environment ; keep secrets in secrets: .
Hacks: -f compose.yaml -f override.yaml merges files (later overrides). Use --project-name for isolation. Prefer build: context: . dockerfile: Dockerfile for dev; pin image tags in prod. Run docker compose config before up to catch errors.
Certifications & Training
Docker Certified Associate (DCA): Orchestration 25%, Image/Registry 20%, Install/Config 15%, Networking 15%, Security 15%, Storage 10%. Free: Official DCA Study Guide, Coursera DCA Prep (audit). Skill data: Compose YAML (services, volumes, networks, healthchecks), CLI (up/down/ps/logs/exec).
Hooks & Workflows
Suggested hooks: Pre-up: docker compose config (validate). Post-down: optional cleanup. Use when devops or devops-troubleshooter is routed.
Workflows: Use with devops (primary), devops-troubleshooter (primary). Flow: validate compose → up/down/exec per task. See operations/incident-response for container debugging.
Overview
This skill provides comprehensive Docker Compose management, enabling AI agents to orchestrate multi-container applications, manage services, inspect logs, and troubleshoot containerized environments with progressive disclosure for optimal context usage.
Context Savings: ~92% reduction
-
MCP Mode: ~25,000 tokens always loaded (multiple tools + schemas)
-
Skill Mode: ~700 tokens metadata + on-demand loading
When to Use
-
Managing local development environments
-
Orchestrating multi-container applications
-
Debugging service connectivity and networking
-
Monitoring container logs and health
-
Building and updating service images
-
Testing containerized application stacks
-
Troubleshooting service failures
-
Managing application lifecycle (start, stop, restart)
Requirements
-
Docker Engine installed and running
-
Docker Compose V2 (docker compose plugin — V1 docker-compose is end-of-life)
-
Valid compose.yaml (preferred) or compose.yml / docker-compose.yml in project
-
Appropriate permissions for Docker socket access
Quick Reference
List running services
docker compose ps
View service logs
docker compose logs <service>
Start services
docker compose up -d
Stop services
docker compose down
Rebuild services
docker compose build
Execute command in container
docker compose exec <service> <command>
Live development reloading (Compose Watch)
docker compose watch
Start with a profile active
docker compose --profile debug up -d
Validate merged config
docker compose config
2026 Feature Highlights
compose.yaml — Canonical Filename
Docker Compose V2 prefers compose.yaml (and compose.yml ) over the legacy docker-compose.yml . The version: top-level field is deprecated and should be omitted entirely in new files.
compose.yaml (preferred — no version: field needed)
services: web: build: . ports: - '8080:80' db: image: postgres:16-alpine environment: POSTGRES_PASSWORD: example volumes: - postgres_data:/var/lib/postgresql/data
volumes: postgres_data:
Compose Watch — Live Development Reloading
Compose Watch (GA as of Compose 2.22+) replaces the manual rebuild-restart cycle during development. Configure a develop.watch block per service. Three actions are available:
Action Behavior
sync
Instantly copies changed files into the running container
rebuild
Triggers docker compose build
- recreates the container
sync+restart
Syncs files then restarts the container process (no full rebuild)
services: api: build: . ports: - '3000:3000' develop: watch: # Sync source instantly — no rebuild needed for interpreted code - action: sync path: ./src target: /app/src ignore: - node_modules/ # Rebuild when dependency manifest changes - action: rebuild path: package.json # Restart only when config changes - action: sync+restart path: ./config target: /app/config
Start with:
Watch mode (keeps output in foreground)
docker compose watch
Or combined with up
docker compose up --watch
When to use each action:
-
sync — interpreted languages (Node.js, Python, Ruby) where the runtime picks up changes
-
sync+restart — config or template files that require a process restart but not a full rebuild
-
rebuild — dependency manifest changes (package.json , requirements.txt , go.mod )
Profiles — Environment-Specific Services
Profiles allow a single compose.yaml to serve multiple environments. Services without a profile always start. Services with profiles only start when that profile is activated.
services:
Always starts — no profile
api: build: . ports: - '3000:3000' depends_on: db: condition: service_healthy
db: image: postgres:16-alpine healthcheck: test: ['CMD-SHELL', 'pg_isready -U postgres'] interval: 5s timeout: 3s retries: 5 volumes: - db_data:/var/lib/postgresql/data
Only with --profile debug
pgadmin: image: dpage/pgadmin4:latest profiles: ['debug'] ports: - '5050:80' environment: PGADMIN_DEFAULT_EMAIL: admin@admin.com PGADMIN_DEFAULT_PASSWORD: admin
Only with --profile monitoring
prometheus: image: prom/prometheus:latest profiles: ['monitoring'] ports: - '9090:9090'
grafana: image: grafana/grafana:latest profiles: ['monitoring'] ports: - '3001:3000'
volumes: db_data:
Default: api + db only
docker compose up -d
Debug: api + db + pgadmin
docker compose --profile debug up -d
Monitoring: api + db + prometheus + grafana
docker compose --profile monitoring up -d
Multiple profiles
docker compose --profile debug --profile monitoring up -d
Via environment variable
COMPOSE_PROFILES=debug,monitoring docker compose up -d
Profile naming rules: [a-zA-Z0-9][a-zA-Z0-9_.-]+ — lowercase kebab-case recommended.
Include — Composable Configs
The include top-level key (introduced in Compose 2.20) allows you to split large compose files into modular, team-owned pieces. Each included file is loaded with its own project directory context, resolving relative paths correctly.
compose.yaml (root — application layer)
include:
- ./infra/compose.yaml # DB, Redis, message broker
- ./monitoring/compose.yaml # Prometheus, Grafana
services: api: build: . depends_on: - db # defined in infra/compose.yaml - redis # defined in infra/compose.yaml
infra/compose.yaml (infrastructure layer — owned by platform team)
services: db: image: postgres:16-alpine healthcheck: test: ['CMD-SHELL', 'pg_isready -U postgres'] interval: 5s timeout: 3s retries: 5 volumes: - db_data:/var/lib/postgresql/data
redis: image: redis:7-alpine healthcheck: test: ['CMD', 'redis-cli', 'ping'] interval: 5s timeout: 3s retries: 5
volumes: db_data:
include is recursive — included files can themselves include other files. Conflicts between resource names cause an error (no silent merging).
Healthcheck Best Practices
Always define healthchecks on stateful services so that depends_on: condition: service_healthy works correctly. Without healthchecks, dependent services may start before their dependency is ready.
services: db: image: postgres:16-alpine healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-postgres}'] interval: 10s # How often to check timeout: 5s # Time to wait for response retries: 5 # Failures before marking unhealthy start_period: 30s # Grace period during container startup
redis: image: redis:7-alpine healthcheck: test: ['CMD', 'redis-cli', 'ping'] interval: 10s timeout: 3s retries: 3
api: build: . depends_on: db: condition: service_healthy # waits until db passes healthcheck redis: condition: service_healthy
Healthcheck guidelines:
-
Use CMD (array form) not CMD-SHELL (string form) where possible — avoids shell injection risk
-
Use CMD-SHELL only when you need shell features (pg_isready , curl -f , etc.)
-
Set start_period for services with slow startup (JVM apps, first-run migrations)
-
Avoid curl in Alpine-based images unless explicitly installed; prefer wget -q --spider or native checks
-
For HTTP services: test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/health || exit 1"]
Multi-Stage Build Pattern
Use multi-stage Dockerfiles to keep production images minimal and secure. Reference the specific build stage in compose.yaml for development.
Dockerfile
Stage 1: deps — install dependencies
FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ci
Stage 2: builder — compile/transpile
FROM deps AS builder COPY . . RUN npm run build
Stage 3: runner — minimal production image
FROM node:20-alpine AS runner
RUN addgroup -g 1001 -S appgroup && adduser -S -u 1001 -G appgroup appuser
WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=deps --chown=appuser:appgroup /app/node_modules ./node_modules
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --retries=3
CMD wget -q --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/index.js"]
compose.yaml — dev targets the builder stage for faster iteration
services: api: build: context: . dockerfile: Dockerfile target: builder # Stop at builder stage in dev (includes devDeps) develop: watch: - action: sync path: ./src target: /app/src ignore: - node_modules/ - action: rebuild path: package.json
compose.prod.yaml — production uses the full runner stage
services: api: build: context: . dockerfile: Dockerfile target: runner # Minimal, non-root production image restart: unless-stopped
Resource Limits (Best Practice)
Always define resource limits to prevent container resource exhaustion:
services: api: image: myapp:latest deploy: resources: limits: cpus: '1.0' memory: 512M reservations: cpus: '0.25' memory: 128M restart: unless-stopped
Tools
The skill provides 15 tools across service management, monitoring, build operations, and troubleshooting categories:
Service Management (5 tools)
up
Start services defined in compose.yaml.
Parameter Type Description Default
detached
boolean Run in detached mode true
build
boolean Build images before starting false
force_recreate
boolean Recreate containers false
project_name
string Project name override directory name
services
array Specific services to start all services
profiles
array Profiles to activate none
watch
boolean Enable Compose Watch mode false
Example:
docker compose up -d docker compose up --build docker compose up web api docker compose --profile debug up -d docker compose up --watch
Safety: Requires confirmation for production environments.
down
Stop and remove containers, networks, volumes.
Parameter Type Description Default
volumes
boolean Remove volumes (BLOCKED) false
remove_orphans
boolean Remove orphaned containers false
project_name
string Project name override directory name
Example:
docker compose down docker compose down --remove-orphans
Safety: Volume removal (-v flag) is BLOCKED by default. Requires confirmation.
start
Start existing containers without recreating them.
Parameter Type Description Default
services
array Specific services to start all services
project_name
string Project name override directory name
Example:
docker compose start docker compose start web
stop
Stop running containers without removing them.
Parameter Type Description Default
timeout
number Shutdown timeout (seconds) 10
services
array Specific services to stop all services
project_name
string Project name override directory name
Example:
docker compose stop docker compose stop --timeout 30 web
restart
Restart services (stop + start).
Parameter Type Description Default
timeout
number Shutdown timeout (seconds) 10
services
array Specific services to restart all services
project_name
string Project name override directory name
Example:
docker compose restart docker compose restart api
Status & Logs (3 tools)
ps
List containers with status information.
Parameter Type Description Default
all
boolean Show all containers (including stopped) false
services
array Filter by services all services
project_name
string Project name override directory name
Example:
docker compose ps docker compose ps --all
Output Fields: NAME, IMAGE, STATUS, PORTS
logs
View service logs with streaming support.
Parameter Type Description Default
services
array Services to view logs for all services
follow
boolean Follow log output (stream) false
tail
number Number of lines to show 100
timestamps
boolean Show timestamps false
since
string Show logs since timestamp/duration none
project_name
string Project name override directory name
Example:
docker compose logs web docker compose logs --tail 50 --follow api docker compose logs --since "2026-01-01T10:00:00"
Note: Follow mode automatically terminates after 60 seconds to prevent indefinite streaming.
top
Display running processes in containers.
Parameter Type Description Default
services
array Services to inspect all services
project_name
string Project name override directory name
Example:
docker compose top docker compose top web
Output: Process list with PID, USER, TIME, COMMAND
Build & Images (3 tools)
build
Build or rebuild service images.
Parameter Type Description Default
no_cache
boolean Build without cache false
pull
boolean Pull newer image versions false
parallel
boolean Build in parallel true
services
array Services to build all services
project_name
string Project name override directory name
Example:
docker compose build docker compose build --no-cache web docker compose build --pull
Safety: Requires confirmation for no-cache builds (resource-intensive).
pull
Pull service images from registry.
Parameter Type Description Default
ignore_pull_failures
boolean Continue if pull fails false
services
array Services to pull all services
project_name
string Project name override directory name
Example:
docker compose pull docker compose pull web api
Safety: Requires confirmation for production environments.
images
List images used by services.
Parameter Type Description Default
project_name
string Project name override directory name
Example:
docker compose images
Output Fields: CONTAINER, REPOSITORY, TAG, IMAGE ID, SIZE
Execution (2 tools)
exec
Execute a command in a running container.
Parameter Type Description Required
service
string Service name Yes
command
array Command to execute Yes
user
string User to execute as container default
workdir
string Working directory container default
env
object Environment variables none
project_name
string Project name override directory name
Example:
docker compose exec web bash docker compose exec -u root api ls -la /app docker compose exec db psql -U postgres
Safety:
-
Destructive commands (rm -rf , dd , mkfs ) are BLOCKED
-
Root user execution requires confirmation
-
Default timeout: 30 seconds
run
Run a one-off command in a new container.
Parameter Type Description Default
service
string Service to run Required
command
array Command to execute service default
rm
boolean Remove container after run true
no_deps
boolean Don't start linked services false
user
string User to execute as container default
env
object Environment variables none
project_name
string Project name override directory name
Example:
docker compose run --rm web npm test docker compose run --no-deps api python manage.py migrate
Safety: Requires confirmation for commands that modify data.
Configuration (2 tools)
config
Validate and view the Compose file configuration.
Parameter Type Description Default
resolve_image_digests
boolean Pin image tags to digests false
no_interpolate
boolean Don't interpolate env vars false
project_name
string Project name override directory name
Example:
docker compose config docker compose config --resolve-image-digests
Output: Parsed and merged Compose configuration
port
Print the public port binding for a service port.
Parameter Type Description Required
service
string Service name Yes
private_port
number Container port Yes
protocol
string Protocol (tcp/udp) tcp
project_name
string Project name override directory name
Example:
docker compose port web 80 docker compose port db 5432
Output: <host>:<port> binding
Common Workflows
Start a Development Environment
1. Validate configuration
docker compose config
2. Pull latest images
docker compose pull
3. Build custom images
docker compose build
4. Start services in detached mode
docker compose up -d
5. Check service status
docker compose ps
6. View logs
docker compose logs --tail 100
Live Development with Compose Watch
1. Ensure develop.watch blocks are configured in compose.yaml
2. Start with watch mode (foreground, shows sync events)
docker compose watch
3. Or start detached then watch
docker compose up -d docker compose watch --no-up
Troubleshoot a Failing Service
1. Check container status
docker compose ps --all
2. View service logs
docker compose logs --tail 200 failing-service
3. Inspect running processes
docker compose top failing-service
4. Check configuration
docker compose config
5. Restart the service
docker compose restart failing-service
6. If needed, recreate container
docker compose up -d --force-recreate failing-service
Update Service Images
1. Pull latest images
docker compose pull
2. Stop services
docker compose down
3. Rebuild if using custom Dockerfiles
docker compose build --pull
4. Start with new images
docker compose up -d
5. Verify services
docker compose ps
Debug Service Connectivity
1. Check running services
docker compose ps
2. Inspect port mappings
docker compose port web 80 docker compose port api 3000
3. Exec into container
docker compose exec web sh
4. Test connectivity (from inside container)
docker compose exec web curl api:3000/health
5. Check logs for errors
docker compose logs web api
Clean Up Environment
1. Stop all services
docker compose down
2. Remove orphaned containers
docker compose down --remove-orphans
3. View images
docker compose images
4. Clean up (manual - volume removal BLOCKED)
Volumes require manual cleanup with explicit confirmation
Use Profiles for Environment-Specific Services
Development: default services only
docker compose up -d
Development + debug tools
docker compose --profile debug up -d
Start monitoring stack
docker compose --profile monitoring up -d
Via env var (useful in CI)
COMPOSE_PROFILES=monitoring docker compose up -d
Stop and clean a specific profile
docker compose --profile debug down
Configuration
Environment Variables
Variable Description Default
COMPOSE_PROJECT_NAME
Default project name directory name
COMPOSE_FILE
Compose file path compose.yaml
COMPOSE_PROFILES
Comma-separated active profiles (none)
COMPOSE_PATH_SEPARATOR
Path separator for multiple files : (Linux/Mac), ; (Windows)
DOCKER_HOST
Docker daemon socket unix:///var/run/docker.sock
COMPOSE_HTTP_TIMEOUT
HTTP timeout for API calls 60
COMPOSE_PARALLEL_LIMIT
Max parallel operations unlimited
Setup
Install Docker Engine:
macOS
brew install --cask docker
Linux (Ubuntu/Debian)
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Windows
Download Docker Desktop from docker.com
Verify Docker Compose:
Check Docker version
docker --version
Check Compose version (must be V2, e.g. 2.24+)
docker compose version
Create compose.yaml (no version: field — V2 does not require it):
services: web: build: . ports: - '8080:80' depends_on: db: condition: service_healthy db: image: postgres:16-alpine environment: POSTGRES_PASSWORD: example healthcheck: test: ['CMD-SHELL', 'pg_isready -U postgres'] interval: 10s timeout: 5s retries: 5
Test the skill:
docker compose config docker compose ps
Safety Features
Blocked Operations
The following operations are BLOCKED by default to prevent accidental data loss:
-
Volume removal: docker compose down -v (BLOCKED - requires manual confirmation)
-
Full cleanup: docker compose down -v --rmi all (BLOCKED - extremely destructive)
-
Destructive exec: rm -rf , dd , mkfs , sudo rm inside containers (BLOCKED)
-
Force removal: docker compose rm -f (BLOCKED - use stop then rm)
Confirmation Required
These operations require explicit confirmation:
-
Building with --no-cache (resource-intensive)
-
Pulling images in production environments
-
Starting services with --force-recreate
-
Executing commands as root user
-
Running commands that modify databases
-
Stopping services with very short timeouts
Auto-Terminating Operations
The following operations auto-terminate to prevent resource issues:
-
Log following (--follow ): 60-second timeout
-
Service execution (exec ): 30-second timeout
-
One-off commands (run ): 60-second timeout
Error Handling
Common Errors:
Error Cause Fix
docker: command not found
Docker not installed Install Docker Engine
Cannot connect to Docker daemon
Docker not running Start Docker service
network ... not found
Network cleanup issue Run docker compose down then up
port is already allocated
Port conflict Change port mapping or stop conflicting service
no configuration file provided
Missing compose file Create compose.yaml
service ... must be built
Image not built Run docker compose build
service unhealthy
Healthcheck failing Check docker compose logs <service>
include path not found
Missing included file Verify paths in include: block
Recovery:
-
Validate configuration: docker compose config
-
Check Docker status: docker info
-
View service logs: docker compose logs
-
Force recreate: docker compose up -d --force-recreate
-
Clean restart: docker compose down && docker compose up -d
Integration with Agents
This skill integrates with the following agents:
Primary Agents
-
devops: Local development, CI/CD integration, container orchestration
-
developer: Application development, testing, debugging
Secondary Agents
-
qa: Integration testing, test environment setup
-
incident-responder: Debugging production issues, service recovery
-
cloud-integrator: Cloud deployment, migration to Kubernetes
-
performance-engineer: Performance testing, resource optimization
Progressive Disclosure
The skill uses progressive disclosure to minimize context usage:
-
Initial Load: Only metadata and tool names (~700 tokens)
-
Tool Invocation: Specific tool schema loaded on-demand (~100-150 tokens)
-
Result Streaming: Large outputs (logs) streamed incrementally
-
Context Cleanup: Old results cleared after use
Context Optimization:
-
Use --tail to limit log output
-
Use service filters to target specific containers
-
Prefer ps over ps --all for active services only
-
Use --since for time-bounded log queries
Troubleshooting
Skill Issues
Docker Compose not found:
Check Docker Compose version
docker compose version
V1 (docker-compose) is end-of-life — upgrade to V2
Docker Compose V2 is integrated into Docker CLI as a plugin
Permission denied:
Add user to docker group (Linux)
sudo usermod -aG docker $USER newgrp docker
Verify permissions
docker ps
Compose file issues:
Validate syntax
docker compose config
Check for errors (quiet mode — exit code only)
docker compose config -q
View resolved configuration
docker compose config --resolve-image-digests
Network issues:
List networks
docker network ls
Remove unused networks
docker network prune
Recreate services
docker compose down docker compose up -d
Healthcheck failures:
Inspect healthcheck status
docker inspect <container_id> | grep -A 10 Health
View healthcheck output
docker compose logs <service>
Manually run the healthcheck command
docker compose exec <service> pg_isready -U postgres
Compose Watch not syncing:
Verify develop.watch block is present in compose.yaml
docker compose config | grep -A 20 develop
Ensure Compose version is 2.22+
docker compose version
Watch requires build: attribute (not image: only)
Performance Considerations
-
Build caching: Use layer caching for faster builds; avoid --no-cache unless necessary
-
Multi-stage builds: Dramatically reduce production image size (often 80%+)
-
Parallel operations: Docker Compose V2 parallelizes by default; use COMPOSE_PARALLEL_LIMIT to control
-
Resource limits: Define CPU/memory limits in compose file to prevent resource exhaustion
-
Log rotation: Use logging drivers to prevent disk space issues
-
Volume cleanup: Regularly clean unused volumes (requires manual confirmation)
-
Compose Watch vs bind mounts: Prefer develop.watch for cross-platform development; bind mounts have I/O performance issues on macOS/Windows
Related
-
Docker Compose Documentation: https://docs.docker.com/compose/
-
Compose File Reference: https://docs.docker.com/compose/compose-file/
-
Compose Watch Docs: https://docs.docker.com/compose/how-tos/file-watch/
-
Compose Profiles Docs: https://docs.docker.com/compose/how-tos/profiles/
-
Compose Include Docs: https://docs.docker.com/compose/how-tos/multiple-compose-files/include/
-
Docker CLI: https://docs.docker.com/engine/reference/commandline/cli/
-
Kubernetes Migration: .claude/skills/kubernetes-flux/ (Kubernetes orchestration)
Sources
-
Docker Compose Documentation
-
Docker Compose V2
-
Compose Specification
-
Docker Best Practices
-
Use Compose Watch
-
Use Compose Profiles
-
Compose Include Directive
Related Skills
- cloud-devops-expert
- Cloud platforms (AWS, GCP, Azure) and Terraform infrastructure
Iron Laws
-
ALWAYS use docker compose (V2 plugin) — never use docker-compose (V1 standalone), which is deprecated and will be removed.
-
NEVER include secrets or credentials directly in compose files or committed .env files — use external secret management or .env.example templates for documentation only.
-
ALWAYS define health checks on services that other services depend on — without health checks, dependent services start before their dependencies are actually ready.
-
NEVER expose a service port to the host unless it must be accessed from outside the compose network — unnecessary host port exposure increases attack surface.
-
ALWAYS specify resource limits (CPU and memory) on services intended for production — unlimited containers can starve other services and crash the host.
Anti-Patterns
Anti-Pattern Why It Fails Correct Approach
Using docker-compose V1 command V1 is deprecated; missing V2 features (profiles, merge, watch) and will be removed Use docker compose (space, not hyphen); verify docker compose version
Hardcoded secrets in compose file Secrets committed to git are permanently exposed in history Use environment variable references (${SECRET} ) loaded from untracked .env
No health checks on database/cache services App containers start before DB is ready; causes startup race conditions and crashes Add healthcheck: with appropriate test commands; use depends_on: condition: service_healthy
Exposing all ports to host (0.0.0.0 ) Services accessible from any network interface including public interfaces Bind to 127.0.0.1 for dev; use internal networks for service-to-service communication
No restart policy Containers stay down after crash or host reboot in production Use restart: unless-stopped for services that should auto-recover
Memory Protocol (MANDATORY)
Before starting: Read .claude/context/memory/learnings.md
After completing:
-
New pattern -> .claude/context/memory/learnings.md
-
Issue found -> .claude/context/memory/issues.md
-
Decision made -> .claude/context/memory/decisions.md
ASSUME INTERRUPTION: If it's not in memory, it didn't happen.