CodePier CLI

The CodePier CLI is a Kubernetes development environment hot-swap tool. It replaces running pods with local development containers, syncs your code in real-time, forwards ports, and proxies traffic — so you can develop against a live cluster as if it were local.

Managed by the App

The CodePier desktop app installs and updates the CLI automatically. You only need manual installation for headless environments (CI, remote servers) or if you prefer to manage it yourself.

Installation

macOS / Linux

curl -fsSL https://get.codepier.dev | sh

Windows (PowerShell)

irm https://get.codepier.dev/install.ps1 | iex

Download binaries

Pre-built binaries for every platform:

  • codepier-darwin-arm64 — macOS Apple Silicon
  • codepier-darwin-x64 — macOS Intel
  • codepier-linux-arm64 — Linux ARM64
  • codepier-linux-x64 — Linux x64
  • codepier-windows-x64.exe — Windows x64

Verify

codepier --version

Configuration

Create a codepier.yaml file in the root of your project. This file tells the CLI how to swap your deployment, what to sync, and how to route traffic.

sync

Paths to synchronize between your local machine and the pod. Each entry maps a local path to a container path separated by a colon.

codepier.yaml
sync:
  - "./src:/app/src"
  - "./package.json:/app/package.json"

image

The development image to use for the swapped pod. Can be a single string or an architecture-specific map.

codepier.yaml
# Single image
image: "node:20-slim"

# Architecture-specific images
image:
  arm64: "myregistry/dev-image:arm64"
  amd64: "myregistry/dev-image:amd64"

forward

Port forwards from your local machine to the pod. Format: local:remote.

codepier.yaml
forward:
  - "3000:3000"
  - "9229:9229"  # Node.js debugger

namespaces

Kubernetes namespace(s) to target. A single string skips the interactive prompt. An array lets you limit the choices.

codepier.yaml
# Single namespace — skips prompt
namespaces: "staging"

# Multiple namespaces — prompts to choose
namespaces:
  - "staging"
  - "development"

workload

Workload name(s) to target. Same behavior as namespaces — a single value skips the prompt. The legacy deployment field is still accepted as an alias.

codepier.yaml
# Single workload — skips prompt
workload: "api-server"

# Multiple workloads — prompts to choose
workload:
  - "api-server"
  - "worker"

kind

The workload kind to target. Defaults to Deployment. For DaemonSet workloads the swap pod is pinned to a single node — you'll be prompted to pick one, or you can pass --node.

codepier.yaml
kind: "StatefulSet"  # or "Deployment" (default), "DaemonSet"

ignore

Gitignore-style patterns to exclude from file sync. Useful for keeping large directories like node_modules or build artifacts out of the sync.

codepier.yaml
ignore:
  - "node_modules"
  - ".git"
  - "dist"
  - "*.log"

supplemental

When true, adds a new sidecar container to the pod instead of replacing the existing one. Useful when you need the original container to keep running alongside your dev environment.

codepier.yaml
supplemental: true

cache

Persistent cache volumes that survive pod restarts. Ideal for package manager caches, build caches, or any directory you want to persist between sessions. You can use a plain path or a name:path format to give the cache a descriptive name.

codepier.yaml
cache:
  # Named caches — the name is used as the volume identifier
  - npm:~/.npm
  - pip:~/.cache/pip

  # Plain path caches
  - /app/node_modules
  - /root/.cache

workdir

The working directory inside the container. This is where the SSH session starts.

codepier.yaml
workdir: "/app"

containers

Restricts which containers can be targeted for hot-swap. Only the containers listed here will be available for selection. If omitted, all containers in the pod are available.

codepier.yaml
containers:
  - "api"

proxy

HTTPS reverse proxy entries. Each entry maps a local hostname to an upstream — either a Kubernetes service (port-forwarded automatically) or, when service is omitted, a port on your local machine. The CLI generates trusted certificates via mkcert and listens on port 443 by default (see proxyPort).

codepier.yaml
proxy:
  # Forward to a Kubernetes service
  - hostname: "api.codepier.local"
    service: "api-server"    # K8s service name
    port: 3000

  # Omit service — forward to a local port instead
  # (e.g. a dev server running on your machine)
  - hostname: "app.codepier.local"
    port: 5173

Hostnames ending in .local are automatically published via mDNS, so they resolve on your machine and across your LAN without editing /etc/hosts. The proxy forwards X-Forwarded-Host, X-Forwarded-Port, and X-Forwarded-Proto headers and supports WebSocket upgrades.

Path-prefix routes

Each entry can declare routes to send specific path prefixes to a different upstream than the host default — useful for mirroring a production ingress locally (e.g. codepier.local/auth → the API service). A prefix matches the exact path and any subpath (/auth matches /auth/github but not /authxyz). First match wins.

codepier.yaml
proxy:
  - hostname: "codepier.local"
    port: 3000               # default upstream: local dev server
    routes:
      - pathPrefix: "/auth"
        service: "api-server" # /auth/* goes to the cluster API instead
        port: 4000

remoteHostname

Overrides the Host header sent upstream. Use it when the local listen name differs from what the cluster ingress or backend expects — e.g. listen on dev.api.codepier.local but forward as api.codepier.local. Available on both top-level entries and path routes.

codepier.yaml
proxy:
  - hostname: "dev.api.codepier.local"
    remoteHostname: "api.codepier.local"
    service: "api-server"
    port: 3000

proxyPort

The HTTPS port the proxy listens on. Defaults to 443, which may require sudo — use a high port like 8443 to avoid that. Can also be set per-run with --port.

codepier.yaml
proxyPort: 8443

env

Environment variables to inject into the dev container. You can set explicit values or forward variables from your local shell with from_env: true.

codepier.yaml
env:
  - name: "NODE_ENV"
    value: "development"

  - name: "DATABASE_URL"
    value: "postgresql://localhost:5432/mydb"

  # Forward from your local shell
  - name: "AWS_ACCESS_KEY_ID"
    from_env: true

  - name: "AWS_SECRET_ACCESS_KEY"
    from_env: true

Commands

codepier up

The core command. Hot-swaps a Kubernetes workload (Deployment, StatefulSet, or DaemonSet) with a local development container. It scales down the original workload, creates a hot-swap pod with your chosen image, starts real-time file sync via Mutagen, and drops you into an SSH session. When you exit, the original workload is restored automatically. DaemonSet swaps are pinned to a single node — pick one interactively or pass --node.

# Interactive — prompts for namespace, workload, and container
codepier up

# Non-interactive — skip all prompts
codepier up --namespace staging --deployment api-server --container api

# DaemonSet swap pinned to a specific node
codepier up --deployment log-agent --node worker-2

codepier down

Stops active hot swaps. Lists all hot-swapped deployments and lets you select which ones to restore. Each selected deployment is scaled back up and the hot-swap pod is removed.

codepier down

codepier ssh

Opens an SSH session directly into a running pod. Works with both regular and hot-swapped pods.

# SSH into the default container
codepier ssh

# SSH into a specific container
codepier ssh --container worker

codepier tail

Streams pod logs to your terminal in real-time. If the pod is hot-swapped, it will notify you that logs aren't available since the container runs a sleep process.

# Tail the default container
codepier tail

# Tail a specific container
codepier tail --container api

codepier proxy

Starts a local HTTPS reverse proxy based on the proxy entries in your codepier.yaml. On first run it installs a local mkcert CA into your system trust store (you'll be prompted for your password), then generates TLS certificates from it — so browsers trust the proxy without warnings. It port-forwards to each Kubernetes service with automatic reconnection, routes traffic by hostname and path prefix, publishes .local hostnames over mDNS, and supports WebSocket upgrades. A live status display shows each route's connection state.

# Start the proxy (listens on 443 by default)
codepier proxy

# Listen on a non-privileged port instead
codepier proxy --port 8443

# Start proxy and run a command once ready.
# Runs in a shell (pipes, && etc. work) and the mkcert CA is passed
# via NODE_EXTRA_CA_CERTS so child processes trust the proxy.
codepier proxy --exec "pnpm run codegen && pnpm dev"

codepier clean

Removes orphaned file sync directories from cluster nodes. Useful for cleaning up after interrupted sessions or stale hot-swaps.

codepier clean

codepier sync-status

Displays the current Mutagen file synchronization status — which sessions are active, their sync state, and any conflicts.

codepier sync-status

codepier mutagen

Direct passthrough to the Mutagen CLI for advanced debugging. Accepts any Mutagen subcommand. Also supports license activation.

# Run any mutagen command
codepier mutagen sync list
codepier mutagen sync monitor

# Activate a Mutagen license
codepier mutagen license activate <license-key>

codepier update

Checks for the latest CLI release and self-updates. Shows version comparison and prompts for confirmation.

codepier update

codepier uninstall

Completely removes the CLI binary and the ~/.codepier config directory from your machine.

codepier uninstall

Global Options

These flags can be passed to any command.

FlagDescription
--config <path>Path to kubeconfig file (default: ~/.kube/codepier)
--context <name>Kubernetes context to use
--namespace <name>Kubernetes namespace (skips interactive prompt)
--deployment <name>Workload name (skips interactive prompt)
--container <name>Container name (skips interactive prompt). If containers is set in your codepier.yaml, must be one of the allowed containers
--pod <name>Pod name to target (skips prompt when multiple match)
--node <name>Node to pin a DaemonSet swap to (skips interactive prompt)
--temp-dirUse emptyDir instead of hostPath for sync volumes

Examples

Getting Started

The simplest possible config. Swaps a deployment with a dev image, syncs your entire project, and caches npm packages between sessions.

codepier.yaml
workload: hello-world
namespaces:
  - hello-world

image: node:24-slim

workdir: /opt/hello-world

sync:
  - ".:/opt/hello-world"

ignore:
  - "node_modules"
  - ".git"

cache:
  - npm:~/.npm

Node.js API with Port Forwarding

A more complete setup for developing a Node.js service. Syncs specific source paths, forwards the app port and debugger, and uses named caches.

codepier.yaml
workload: api-server
namespaces:
  - staging

image: node:20-slim
workdir: /app

sync:
  - "./src:/app/src"
  - "./package.json:/app/package.json"
  - "./tsconfig.json:/app/tsconfig.json"

forward:
  - "3000:3000"
  - "9229:9229"

ignore:
  - "node_modules"
  - "dist"
  - ".git"
  - "*.log"

cache:
  - npm:~/.npm

env:
  - name: "NODE_ENV"
    value: "development"

Multi-Service with HTTPS Proxy

Route local HTTPS traffic to Kubernetes services and a local dev server, mirroring the production ingress with path routes. Run codepier proxy to start the reverse proxy, then access each service via its hostname — the .local names resolve automatically via mDNS.

codepier.yaml
namespaces: "staging"
workload: "api-server"

image: "node:20-slim"
workdir: "/app"

sync:
  - ".:/app"

forward:
  - "3000:3000"

ignore:
  - "node_modules"
  - ".git"

cache:
  - "/app/node_modules"

proxyPort: 8443

proxy:
  # Local dev server, with /auth handled by the cluster API
  - hostname: "app.codepier.local"
    port: 5173
    routes:
      - pathPrefix: "/auth"
        service: "api-server"
        port: 4000

  - hostname: "api.codepier.local"
    service: "api-server"
    port: 3000

  - hostname: "auth.codepier.local"
    service: "auth-service"
    port: 4000

env:
  - name: "NODE_ENV"
    value: "development"
  - name: "API_URL"
    value: "https://api.codepier.local:8443"

Multi-Architecture with Supplemental Container

Use architecture-specific images and add a sidecar container instead of replacing the original. This is useful when you need the original container's processes to keep running alongside your dev environment.

codepier.yaml
namespaces:
  - "staging"
  - "production"

workload:
  - "worker"
  - "scheduler"

kind: "Deployment"
supplemental: true

image:
  arm64: "ghcr.io/myorg/dev-image:arm64"
  amd64: "ghcr.io/myorg/dev-image:amd64"

workdir: "/app"

sync:
  - "./src:/app/src"
  - "./config:/app/config"

forward:
  - "8080:8080"

ignore:
  - "node_modules"
  - ".git"
  - "dist"
  - "coverage"

cache:
  - "/app/node_modules"
  - "/root/.cache"

env:
  - name: "NODE_ENV"
    value: "development"
  - name: "AWS_ACCESS_KEY_ID"
    from_env: true
  - name: "AWS_SECRET_ACCESS_KEY"
    from_env: true