dockernecontainer (dnc)
Containerized per-project development environments with TUI and GPU support.
Dependencies
Required:
- Linux with rootful Docker (≥20.10). Rootless Docker is detected and rejected.
- Project directory you want to containerize
GPU (choose what applies):
- NVIDIA:
nvidia-smion PATH +nvidia-container-toolkitinstalled - Intel/AMD DRI:
/dev/dripresent on host (auto-detected) - AMD compute (KFD):
/dev/kfdpresent on host (auto-detected)
Usage
# Create container from an image with your tools
dnc setup --image ghcr.io/lstmnemodel/dnc-test-arch:latest
# Launch bundled kitty terminal (all tabs/splits exec into container)
dnc
# Non-graphical fallback (useful for SSH sessions without display)
dnc -- /bin/bash
# Run a command in container (non-interactive or interactive)
dnc -- pacman -Syu
# Show container details
dnc info
# List all containers
dnc list
# Remove container
dnc rm
Each project directory gets its own container. A .dnc file in the project root tracks the container name. dnc walks up the directory tree to find it.
How It Works
When you run dnc with no arguments:
- Finds your project: Walks up from
$PWDto find.dncfile - Extracts kitty config: Copies
~/.config/kitty/from INSIDE your project container - Launches kitty: Bundled kitty terminal with config from container
- Every new tab/window: Automatically calls
docker exec -itinto your container
Kitty runs on your host (for GPU rendering and display), but every shell you open in it runs inside your project container via docker exec.
What gets forwarded
| Category | What |
|---|---|
| Network | --network=host, --pid=host, --ipc=host |
| GPU | --gpus all (NVIDIA), /dev/dri bind-mount (Intel/AMD DRI), /dev/kfd (AMD compute) |
| Runtime dirs | /tmp, /run/user/$UID (for clipboard, temp files) |
| Git / SSH | SSH agent socket forwarded; ~/.ssh/, ~/.gitconfig, ~/.git-credentials mounted at /run/host/ssh, /run/host/gitconfig, /run/host/git-credentials |
| User config | ~/.config/dnc/ mounted read-write at /run/host/config/ — images can read dnc.toml for colors, keybinds, IDE settings |
| Shell history | Per-container history persists across rebuilds (HISTFILE set for bash/zsh, fish) |
| nvim state | Per-container swap/undo persists across rebuilds (~/.local/state/nvim) |
| Home | Fresh container home (not host bind-mount). Host home mounted read-only at /run/host/home |
| Host env | All host environment variables dumped to /run/host/env (shell-sourceable) |
| Project dir | Bind-mounted read-write at its host path |
| Sudo | Installed automatically via pacman/dnf/apt/etc., NOPASSWD for the container user |
Kitty Configuration
Kitty config lives inside your project container, not on the host:
Inside container: ~/.config/kitty/kitty.conf
This way:
- Different projects can have different kitty configs
- Config travels with your container image
- New tabs automatically exec into your container (dnc overrides the
shelldirective)
If no config is found in the container, kitty runs with defaults plus the dnc exec wrapper.
Extensibility via /run/host
dnc provides host data at well-known paths inside the container for optional integration:
| Path | Description |
|---|---|
/run/host/home |
Read-only bind-mount of host $HOME |
/run/host/env |
Shell-sourceable dump of all host environment variables |
/run/host/config |
Read-write bind-mount of ~/.config/dnc/ — user IDE config |
/run/host/ssh |
Read-only bind-mount of ~/.ssh/ |
/run/host/gitconfig |
Read-only bind-mount of ~/.gitconfig (if present) |
/run/host/git-credentials |
Read-only bind-mount of ~/.git-credentials (if present) |
/run/host/kitty |
Read-only mount of bundled kitty bundle — provides kitten binary, terminfo, and kitten run-shell for shell integration |
/run/host/state/history |
Per-container shell history (persists across rebuilds) |
/run/host/state/nvim |
Per-container nvim swap/undo files (persists across rebuilds) |
Config convention
Images are expected to read /run/host/config/dnc.toml (if present) to generate native config files for the IDE. This lets you swap images while keeping your colors, keybinds, and preferences — write once in TOML, use across any compliant image.
Git / SSH
SSH agent socket is forwarded automatically via $SSH_AUTH_SOCK. Git operations (clone, push, pull) work inside the container without additional setup if your host has SSH keys loaded and gitconfig configured.
Kitty shell integration
When TERM=xterm-kitty and the bundled kitty bundle is available, entry.sh automatically delegates to kitten run-shell. This gives you:
- Correct terminfo (
xterm-kitty) — neovim and TUIs get true color, italics, styled underlines, cursor shapes - Shell integration — directory tracking in window title, clickable file paths, scroll marks
- Clean shutdown — processes exit properly on window close (no warning dialog)
No image-side configuration needed. The fallback (when TERM is not xterm-kitty or the bundle is absent) launches the user's login shell directly.
Limitations
- Rootful Docker only: Rootless lacks the
--pid=hostcapabilities dnc relies on. - Container user = host uid: UID 1:1 mapping (required for rootful Docker). The container user gets
NOPASSWDsudo so package installs still work. - No
--initor systemd: PID 1 isinit.sh, not init/systemd.systemctlwon't work.
Commands
dnc Launch kitty (bundled) with container context
dnc -- Non-graphical interactive shell (docker exec)
dnc -- <cmd> Run command in container
dnc setup [--image IMG] Create container for this project
dnc rm Remove container + .dnc
dnc list List all dnc containers
dnc info Show container details
dnc web Show web IDE URL (if web_port set in .dnc)
dnc agent [--opencode] [--cursor] Create DNC.md + agent rules
dnc version Show version
dnc help Show this help