Skip to main content

ctenv is a tool for running a program in a container as current user

Project description

ctenv

GitHub repo PyPI Changelog Tests License

Run commands in any container image while preserving your user identity and file permissions.

Install

# Install with pip
$ pip install ctenv

# Install with uv
$ uv tool install ctenv

# Or run directly without installing
$ uv tool run ctenv --help

Recommend installing uv.

Usage

# Interactive shell in ubuntu container
$ ctenv run --image ubuntu

# Run specific command
$ ctenv run -- npm test

# Run Claude Code in a container
$ ctenv run --image node:20 --volume ~/.claude.json --volume ~/.claude \
    --post-start-command "npm install -g @anthropic-ai/claude-code"

Why ctenv?

When running containers with mounted directories, files created inside often have root ownership or wrong permissions. ctenv solves this by:

  • Creating a matching user (same UID/GID) dynamically in existing images at runtime
  • Mounting your current directory with correct permissions
  • Using gosu to drop privileges after container setup

This works with any existing Docker image without modification - no custom Dockerfiles needed. Provides similar functionality to Podman's --userns=keep-id but works with Docker. Also similar to Development Containers but focused on running individual commands rather than persistent development environments.

Under the hood, ctenv starts containers as root for file ownership setup, then drops privileges using bundled gosu binaries before executing your command. It generates bash entrypoint scripts dynamically to handle user creation and environment setup.

Highlights

  • Works with existing images without modifications
  • Files created have your UID/GID (preserves permissions)
  • Convenient volume mounting like -v ~/.gitconfig (mounts to same path in container)
  • Simple configuration with reusable .ctenv.toml setups

Requirements

  • Python 3.10+
  • Docker (tested on Linux/macOS)

Features

  • User identity preservation (matching UID/GID in container)
  • Volume mounting with shortcuts like -v ~/.gitconfig (mounts to same path)
  • Volume ownership fixing with custom :chown option (similar to Podman's :U and :chown)
  • Post-start commands for running setup as root before dropping to user permissions
  • Template variables with environment variables, like ${env.HOME}
  • Configuration file support with reusable container definitions
  • Cross-platform support for linux/amd64 and linux/arm64 containers
  • Bundled gosu binaries for privilege dropping
  • Interactive and non-interactive command execution

Configuration

Create .ctenv.toml for reusable container setups:

[defaults]
command = "zsh"

[containers.python]
image = "python:3.11"
volumes = ["~/.cache/pip"]

# Run Claude Code in isolation
[containers.claude]
image = "node:20"
post_start_commands = ["npm install -g @anthropic-ai/claude-code"]
volumes = ["~/.claude.json", "~/.claude"]

Then run:

$ ctenv run python -- python script.py
$ ctenv run claude

Common Use Cases

Claude Code

Run Claude Code in a container for isolation:

$ ctenv run --image node:20 -v ~/.claude.json -v ~/.claude/ --post-start-command "npm install -g @anthropic-ai/claude-code"

Or write as config in ~/.ctenv.toml:

[containers.claude]
image = "node:20"
volumes = ["~/.claude.json", "~/.claude/"]
post_start_commands = ["npm install -g @anthropic-ai/claude-code"]

And then use with: ctenv run claude

Development Tools

Run linters, formatters, or compilers from containers:

$ ctenv run --image rust:latest -- cargo fmt
$ ctenv run --image node:20 -- eslint src/

Build Systems

Use containerized build environments:

[containers.build]
image = "some-build-system:v17"
volumes = ["build-cache:/var/cache:rw,chown"]

Detailed Examples

Claude Code with Network Restrictions

For running Claude Code in isolation with network limitations:

[containers.claude]
image = "node:20"
network = "bridge"
run_args = ["--cap-add=NET_ADMIN"]
post_start_commands = [
    "apt update && apt install -y iptables",
    "iptables -A OUTPUT -d 192.168.0.0/24 -j DROP",
    "npm install -g @anthropic-ai/claude-code"
]
volumes = ["~/.claude.json", "~/.claude"]

Note: On macOS, Claude Code stores credentials in the keychain by default. When run in a container, it will create ~/.claude/.credentials.json instead, which persists outside the container due to the volume mount.

Build System with Caching

Complex build environment with shared caches:

[containers.build]
image = "registry.company.internal/build-system:v1"
env = [
    "BB_NUMBER_THREADS",
    "CACHE_MIRROR=http://build-cache.company.internal/",
    "BUILD_CACHES_DIR=/var/cache/build-caches/image-${image|slug}",
]
volumes = [
    "build-caches-user-${env.USER}:/var/cache/build-caches:rw,chown",
    "${env.HOME}/.ssh:/home/builduser/.ssh:ro"
]
post_start_commands = ["source /venv/bin/activate"]

This setup ensures the build environment matches the user's environment while sharing caches between different repository clones.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ctenv-0.5.tar.gz (1.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ctenv-0.5-py3-none-any.whl (1.9 MB view details)

Uploaded Python 3

File details

Details for the file ctenv-0.5.tar.gz.

File metadata

  • Download URL: ctenv-0.5.tar.gz
  • Upload date:
  • Size: 1.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for ctenv-0.5.tar.gz
Algorithm Hash digest
SHA256 1cc02c9fadaa1cde45446027c4df2975602c7b837763e9af41bf5b3321e8b39c
MD5 6222f3bbd89e6a1a64d590e970bab9ec
BLAKE2b-256 a0e81c8b2a8586fb366de28f2d98cd5391df7df52cfe431ba56f65343636bb74

See more details on using hashes here.

Provenance

The following attestation bundles were made for ctenv-0.5.tar.gz:

Publisher: publish.yml on osks/ctenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ctenv-0.5-py3-none-any.whl.

File metadata

  • Download URL: ctenv-0.5-py3-none-any.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for ctenv-0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 4bba7e7c70e492c6d8dc1d05507d69876c878296d3f989c217965f33062abba0
MD5 102494677a37699a11f949c5346c7f38
BLAKE2b-256 0b57bab3ceb5ad2e5398da1a63e1820c2ffac98d1584413767af7af6d8522b1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for ctenv-0.5-py3-none-any.whl:

Publisher: publish.yml on osks/ctenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page