Monorepo for Aesthetic.Computer aesthetic.computer
at main 308 lines 20 kB view raw
1// ═══════════════════════════════════════════════════════════════════════════════ 2// AESTHETIC COMPUTER DEVCONTAINER 3// ═══════════════════════════════════════════════════════════════════════════════ 4// This devcontainer powers a creative coding platform with: 5// - Real-time collaborative pieces (WebRTC/WebSocket) 6// - KidLisp interpreter (custom language for generative art) 7// - Emacs daemon for terminal multiplexing (artery-tui) 8// - Multi-service architecture (dev server, session server, edge services) 9// 10// Restored incrementally to isolate VS Code crash causes on Linux/Fedora host. 11// See: .devcontainer/devcontainer.json.backup for original full config 12// ═══════════════════════════════════════════════════════════════════════════════ 13{ 14 "name": "Aesthetic Computer", 15 16 // ───────────────────────────────────────────────────────────────────────────── 17 // BUILD CONFIGURATION 18 // ───────────────────────────────────────────────────────────────────────────── 19 // Uses a custom Fedora-based Dockerfile (~13.6GB) with: 20 // - Node.js (fnm), Deno, Python 3.11, Rust, SBCL (Common Lisp) 21 // - Emacs-nox, Fish shell, Docker CLI 22 // - Tezos tools (SmartPy, PyTezos) for NFT minting 23 // - ffmpeg, imagemagick for media processing 24 "build": { 25 "dockerfile": "Dockerfile" 26 }, 27 28 "remoteUser": "me", 29 "containerUser": "me", 30 "updateRemoteUserUID": true, 31 32 // Override default workspace mount to add SELinux :z label (required on Fedora) 33 "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/aesthetic-computer,type=bind,consistency=cached", 34 "workspaceFolder": "/workspaces/aesthetic-computer", 35 36 // ───────────────────────────────────────────────────────────────────────────── 37 // VOLUME MOUNTS 38 // ───────────────────────────────────────────────────────────────────────────── 39 // These persist data across container rebuilds and share host resources: 40 // 41 // .emacs.d: Emacs configuration (init.el, packages, themes) 42 // Persisted so emacs daemon doesn't re-download packages on rebuild 43 // Contains artery-tui terminal layout config 44 // 45 // envs: Environment/secrets directory (API keys, credentials) 46 // Sourced by entry.fish, kept separate from git-tracked config 47 // 48 // aesthetic-mkcert-ca: mkcert CA root key and certificate 49 // Persisted so the same CA survives rebuilds and the 50 // Windows/macOS host trust store stays valid 51 // 52 // aesthetic-fish-data: Fish shell history, completions cache 53 // Named volume so shell history persists across rebuilds 54 // 55 // aesthetic-mail-data: Local Maildir cache for mu4e/mbsync (~/.mail) 56 // Named volume so synced mail survives rebuilds 57 // 58 // aesthetic-copilot-data: Claude/Copilot CLI session data 59 // Persists auth tokens and conversation history 60 // 61 // .claude: Claude Code session data and configuration 62 // Persists conversation history, memory, and settings 63 // 64 // .codex: Codex CLI session data and configuration 65 // Persists local thread history and auth/state across rebuilds 66 // 67 // VS Code globalStorage/workspaceStorage: extension state and SecretStorage 68 // backing databases for remote server 69 // 70 // keyrings: libsecret keyring files used by VS Code extension secrets 71 // 72 // docker.sock: Host Docker socket for docker-in-docker 73 // Allows running `docker build` inside container 74 // Two mounts: one for VS Code's Docker extension, one for CLI 75 "mounts": [ 76 "source=${localWorkspaceFolder}/.devcontainer/.emacs.d,target=/home/me/.emacs.d,type=bind,consistency=cached", 77 "source=${localWorkspaceFolder}/.devcontainer/envs,target=/home/me/envs,type=bind,consistency=cached", 78 "source=${localEnv:HOME}/.claude,target=/home/me/.claude,type=bind,consistency=cached", 79 "source=${localEnv:HOME}/.claude.json,target=/home/me/.claude.json,type=bind,consistency=cached", 80 "source=${localEnv:HOME}/.codex,target=/home/me/.codex,type=bind,consistency=cached", 81 "source=aesthetic-vscode-globalstorage,target=/home/me/.config/Code/User/globalStorage,type=volume", 82 "source=aesthetic-vscode-workspacestorage,target=/home/me/.config/Code/User/workspaceStorage,type=volume", 83 "source=aesthetic-vscode-keyrings,target=/home/me/.local/share/keyrings,type=volume", 84 "source=aesthetic-mkcert-ca,target=/home/me/.local/share/mkcert,type=volume", 85 "source=aesthetic-fish-data,target=/home/me/.local/share/fish,type=volume", 86 "source=aesthetic-mail-data,target=/home/me/.mail,type=volume", 87 "source=aesthetic-mail-jas-data,target=/home/me/.mail-jas,type=volume", 88 "source=aesthetic-copilot-data,target=/home/me/.copilot,type=volume", 89 "source=/var/run/docker.sock,target=/var/run/docker-host.sock,type=bind", 90 "type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock" 91 ], 92 93 // ───────────────────────────────────────────────────────────────────────────── 94 // PORT FORWARDING 95 // ───────────────────────────────────────────────────────────────────────────── 96 // VS Code automatically forwards these ports from container to host: 97 // 98 // 8888: Main Aesthetic Computer dev server (Vite + Netlify functions) 99 // 8889: Session server (Jamsocket) for multiplayer state sync 100 // 8111: Caddy reverse proxy (SSL termination for local HTTPS) 101 // 8083-8085: Chat system endpoints (system, SOTCE, clock) 102 // 4040: ngrok inspection UI (when tunnel is active) 103 // 12345: Misc dev/debug port 104 // 3478: TURN server for WebRTC NAT traversal (UDP) 105 // 10000-10007: WebRTC media ports for peer connections 106 // 7890: Devcontainer status dashboard 107 // 5555: VS Code extension views dev server (process-tree 3D viz) 108 "forwardPorts": [8888, 8111, 8112, 8889, 8083, 8084, 8085, 4040, 12345, 3478, 7890, 5555, 4177, 3003, 9090, 10000, 10001, 10002, 10003, 10004, 10005, 10006, 10007], 109 110 "portsAttributes": { 111 "8888": { 112 "label": "Aesthetic Computer", 113 "onAutoForward": "notify", 114 "visibility": "public" 115 }, 116 "3478": { 117 "label": "TURN Server", 118 "protocol": "udp", 119 "onAutoForward": "silent" 120 }, 121 "8111": { "label": "Caddy", "onAutoForward": "silent", "visibility": "public" }, 122 "8889": { "label": "Session Server", "onAutoForward": "silent", "visibility": "public" }, 123 "8083": { "label": "Chat System", "onAutoForward": "silent", "visibility": "public" }, 124 "8084": { "label": "Chat SOTCE", "onAutoForward": "silent", "visibility": "public" }, 125 "8085": { "label": "Chat Clock", "onAutoForward": "silent", "visibility": "public" }, 126 "5555": { "label": "Extension Views Dev", "onAutoForward": "silent" }, 127 "4177": { "label": "AT User Pages Dev", "onAutoForward": "notify", "visibility": "public" }, 128 "3003": { "label": "Silo", "onAutoForward": "silent" }, 129 "9090": { "label": "Cockpit", "onAutoForward": "silent" } 130 }, 131 132 // ───────────────────────────────────────────────────────────────────────────── 133 // CONTAINER ENVIRONMENT VARIABLES 134 // ───────────────────────────────────────────────────────────────────────────── 135 // DISPLAY: X11 forwarding for clipboard sharing with host 136 // Requires `xhost +local:docker` on Linux host 137 // Used by: xclip/xsel for copy-paste in emacs terminals 138 // 139 // HOST_IP: Machine's LAN IP for WebRTC TURN server announcements 140 // Multiplayer pieces need this for peer discovery 141 // 142 // WSL_DISTRO_NAME: Detect WSL environment for path translation 143 // 144 // DOCKER_BUILDKIT: Enable BuildKit for faster container builds 145 // Used when building nested containers (rare) 146 "containerEnv": { 147 "TZ": "America/Los_Angeles", 148 "DISPLAY": "${localEnv:DISPLAY}", 149 "HOST_IP": "${localEnv:HOST_IP}", 150 "WSL_DISTRO_NAME": "${localEnv:WSL_DISTRO_NAME}", 151 "DOCKER_BUILDKIT": "1", 152 "COMPOSE_DOCKER_CLI_BUILD": "1", 153 "CODEX_HOME": "/home/me/.codex", 154 "AGENT_MEMORY_KEY": "${localEnv:AGENT_MEMORY_KEY}", 155 "AGENT_DEVICE_ID": "${localEnv:AGENT_DEVICE_ID}", 156 "AGENT_SESSION_ID": "${localEnv:AGENT_SESSION_ID}", 157 "AGENT_MEMORY_PROJECT": "${localEnv:AGENT_MEMORY_PROJECT}", 158 "AGENT_MEMORY_PROVIDER": "${localEnv:AGENT_MEMORY_PROVIDER}", 159 "AGENT_MEMORY_TICKET": "${localEnv:AGENT_MEMORY_TICKET}", 160 "AGENT_MEMORY_REMOTE_ENABLED": "${localEnv:AGENT_MEMORY_REMOTE_ENABLED}", 161 "AGENT_MEMORY_REMOTE_URL": "${localEnv:AGENT_MEMORY_REMOTE_URL}", 162 "AGENT_MEMORY_REMOTE_TOKEN": "${localEnv:AGENT_MEMORY_REMOTE_TOKEN}", 163 "AGENT_MEMORY_MONGODB_CONNECTION_STRING": "${localEnv:AGENT_MEMORY_MONGODB_CONNECTION_STRING}", 164 "AGENT_MEMORY_MONGODB_NAME": "${localEnv:AGENT_MEMORY_MONGODB_NAME}", 165 "AGENT_MEMORY_INGEST_TOKEN": "${localEnv:AGENT_MEMORY_INGEST_TOKEN}" 166 }, 167 168 // ───────────────────────────────────────────────────────────────────────────── 169 // VS CODE CUSTOMIZATIONS 170 // ───────────────────────────────────────────────────────────────────────────── 171 "customizations": { 172 "vscode": { 173 // Extensions auto-installed in container - kept empty to prevent crashes 174 // Extensions run on UI side via remote.extensionKind settings 175 "settings": { 176 // ═══════════════════════════════════════════════════════════════════════ 177 // CRITICAL: FILE WATCHER EXCLUSIONS 178 // ═══════════════════════════════════════════════════════════════════════ 179 // The workspace has 86 top-level directories and massive folders like: 180 // - kidlisp-n64 (19GB N64 SDK) 181 // - feed/ (archived content) 182 // - packed/, archive/, experiments/ 183 // 184 // Without exclusions, VS Code's file watcher hits 99% CPU scanning 185 // millions of files, causing UI freezes and eventual crashes. 186 // 187 // Setting "**": true disables ALL file watching - aggressive but stable. 188 // Trade-off: Must manually refresh explorer, no auto-reload on file change 189 "files.watcherExclude": { 190 "**/node_modules/**": true, 191 "**/kidlisp-n64/**": true, 192 "**/kidlisp-gameboy/**": true, 193 "**/kidlisp-playdate/**": true, 194 "**/feed/**": true, 195 "**/packed/**": true, 196 "**/archive/**": true, 197 "**/experiments/**": true, 198 "**/builds/**": true, 199 "**/target/**": true, 200 "**/.git/objects/**": true, 201 "**/.git/subtree-cache/**": true, 202 "**/dump.rdb": true 203 }, 204 205 // ═══════════════════════════════════════════════════════════════════════ 206 // GIT CONFIGURATION 207 // ═══════════════════════════════════════════════════════════════════════ 208 // Disable git auto-refresh to reduce background I/O 209 // With 86 directories, git status polling compounds watcher issues 210 "git.autorefresh": false, 211 212 // ═══════════════════════════════════════════════════════════════════════ 213 // COPILOT EXTENSION HANDLING 214 // ═══════════════════════════════════════════════════════════════════════ 215 // Force Copilot extensions to run on UI (host) side, not in container. 216 // Installing copilot-chat in container causes crashes - see commit aff03abf 217 // This also keeps API keys on host rather than in container 218 // Don't auto-update extensions - prevents mid-session breakage 219 "extensions.autoUpdate": false, 220 "extensions.ignoreRecommendations": true, 221 "settingsSync.keybindingsPerPlatform": false 222 }, 223 "extensions": [ 224 "mongodb.mongodb-vscode", 225 "Anthropic.claude-code", 226 "ms-python.python", 227 "ms-toolsai.jupyter", 228 "openai.chatgpt" 229 ] 230 } 231 }, 232 233 // ───────────────────────────────────────────────────────────────────────────── 234 // DOCKER RUN ARGUMENTS 235 // ───────────────────────────────────────────────────────────────────────────── 236 // --name/--hostname: Fixed names for scripts (`docker exec aesthetic`) 237 // 238 // -v /tmp/.X11-unix: X11 socket mount for clipboard sharing 239 // Works with DISPLAY env var for xclip/xsel 240 // 241 // --cap-add=SYS_PTRACE: Allow ptrace for debugging (strace, gdb attach) 242 // --security-opt=apparmor=unconfined: Disable AppArmor for debug tools 243 // 244 // --init: Use tini as PID 1 to reap zombie processes 245 // 246 // --memory=12g: Cap container memory (prevents OOM killing host) 247 // --shm-size=2g: Shared memory for Chrome/Puppeteer headless rendering 248 // 249 // --tmpfs: In-memory /tmp for faster temp file operations 250 // 251 // --ulimit nofile: Raise open file limit for Vite's many watchers 252 // --add-host: Force Docker host alias inside the container 253 // Needed when Docker Desktop doesn't inject host.docker.internal 254 // 255 // NOTE: Explicit -p port mappings removed - forwardPorts handles this 256 // and avoids "port already in use" errors on restart 257 "runArgs": [ 258 "-v", "/tmp/.X11-unix:/tmp/.X11-unix", 259 "-q", 260 "--add-host=host.docker.internal:host-gateway", 261 "--cap-add=SYS_PTRACE", 262 "--security-opt=apparmor=unconfined", 263 "--security-opt", "label:disable", 264 "--name", "aesthetic", 265 "--hostname", "aesthetic", 266 "--init", 267 "--memory=12g", 268 "--memory-swap=12g", 269 "--shm-size=2g", 270 "--ulimit", "nofile=131072:131072" 271 ], 272 273 // ───────────────────────────────────────────────────────────────────────────── 274 // LIFECYCLE COMMANDS 275 // ───────────────────────────────────────────────────────────────────────────── 276 // 277 // initializeCommand: Runs on HOST before container starts 278 // - Removes stale "aesthetic" container (prevents rebuild conflicts) 279 // - Creates required directories (.emacs.d, envs, tezos-data) 280 // - Ensures fish_history exists (prevents volume mount failures) 281 // Note: runs as array to avoid shell interpretation issues 282 "initializeCommand": ["sh", "-c", ".devcontainer/scripts/prepare-host.sh"], 283 284 // postStartCommand: Runs INSIDE container after it starts 285 // - Wrapper script that backgrounds entry.fish and returns quickly 286 // - entry.fish sets up: 287 // • Docker daemon (docker-in-docker) 288 // • Emacs daemon with eat-mode terminals (artery, fishy, etc.) 289 // • Fish shell environment (fnm, vault secrets) 290 // • CDP tunnel for VS Code remote control 291 // • Creates .waiter file when ready (for aesthetic-launch.sh) 292 "postStartCommand": "sh .devcontainer/scripts/poststart-wrapper.sh || (echo '[postStart] wrapper failed, using entry fallback'; if [ -r .devcontainer/entry.fish ]; then nohup fish .devcontainer/entry.fish > /tmp/entry-fallback.log 2>&1 & else nohup fish /entry.fish > /tmp/entry-fallback.log 2>&1 & fi)", 293 294 // postAttachCommand: Runs when VS Code attaches to the container 295 // - Lightweight confirmation message 296 // - VS Code's "💻 Aesthetic" task handles actual emacsclient connection 297 "postAttachCommand": "sh .devcontainer/scripts/post-attach.sh" 298 299 // ═══════════════════════════════════════════════════════════════════════════════ 300 // CONFIGURATION COMPLETE 301 // ═══════════════════════════════════════════════════════════════════════════════ 302 // All features restored except: 303 // - --cgroupns=host (causes container exit on this Fedora host) 304 // - --tmpfs=/tmp:noexec,nosuid,size=2g (causes container exit) 305 // - Explicit -p port mappings (conflict with VS Code's forwardPorts) 306 // - codespaces-linux-var-lib-docker volume (not needed for local Docker socket) 307 // ═══════════════════════════════════════════════════════════════════════════════ 308}