From 2dc502dd5c72404e1f64f9f629a619794a4fb189 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 21 Jun 2026 06:03:27 +0000 Subject: [PATCH] Restructure nvim sandbox into "devcube" IDE with zellij + workmux Turn the single-purpose nvim-dev sandbox into a containerized IDE that can run multiple AI agents in parallel, each in its own git worktree, inside one container. Adds zellij (multiplexer) + workmux (git-worktree orchestration) and a baked fish + starship shell, behind a single `devc` command. - Move the container project dot_files/nvim -> dot_files/devcube (Containerfile, entrypoint, Justfile, README, wrapper). dot_files/nvim now holds only the nvim config dotfile. - Build context moves up to dot_files/ so fish/starship/zellij/workmux/nvim configs (top-level dotfiles) can be baked in; add dot_files/.dockerignore. - New wrapper devcube.sh dispatches on its first arg (`devc` -> workmux, `devc nvim|claude|codex|agy|zellij`), replacing the per-tool symlinks that shadowed host installs. Orchestrators get a per-project worktree volume mounted at /worktrees (path-derived name, persists across restarts, isolated per project) with workmux state redirected there via XDG_STATE_HOME. - New baked configs: zellij Tokyo Night Moon theme + workmux layout, workmux config (worktree_dir: /worktrees). - Full rename: image -> devcube, workflow -> build-devcube.yml, ujust recipes -> devcube-*, just file -> 61-devcube.just, env -> DEVCUBE_*, sentinel -> DEVCUBE, state volume -> hypercube-devcube-home. - Update nvim-launcher/desktop to open `devc nvim`, plus docs and the build test reference. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01K44UxeGUD7Peow4F4ipmXz --- .../{build-nvim-dev.yml => build-devcube.yml} | 36 ++-- CONTRIBUTING.md | 5 +- README.md | 2 +- build_files/hypercube/03-hypercube-configs.sh | 6 +- build_files/hypercube/99-tests.sh | 2 +- dot_files/.dockerignore | 23 +++ dot_files/{nvim => devcube}/Containerfile | 48 ++++-- dot_files/{nvim => devcube}/Justfile | 48 +++--- dot_files/{nvim => devcube}/LICENSE.md | 0 dot_files/devcube/README.md | 154 ++++++++++++++++++ dot_files/{nvim => devcube}/entrypoint.sh | 0 dot_files/devcube/scripts/devcube.sh | 117 +++++++++++++ dot_files/nvim/.dockerignore | 19 --- dot_files/nvim/README.md | 113 ------------- .../nvim/config/lua/hypercube/config.lua | 4 +- dot_files/nvim/scripts/sandbox.sh | 73 --------- dot_files/workmux/config.yaml | 14 ++ dot_files/zellij/config.kdl | 32 ++++ dot_files/zellij/layouts/workmux.kdl | 16 ++ .../shared/etc/distrobox/distrobox.ini | 6 +- system_files/shared/usr/bin/nvim-launcher | 29 ++-- .../usr/share/ublue-os/just/61-devcube.just | 79 +++++++++ .../usr/share/ublue-os/just/61-nvim.just | 75 --------- .../shared/usr/share/ublue-os/justfile | 2 +- 24 files changed, 551 insertions(+), 352 deletions(-) rename .github/workflows/{build-nvim-dev.yml => build-devcube.yml} (79%) create mode 100644 dot_files/.dockerignore rename dot_files/{nvim => devcube}/Containerfile (80%) rename dot_files/{nvim => devcube}/Justfile (55%) rename dot_files/{nvim => devcube}/LICENSE.md (100%) create mode 100644 dot_files/devcube/README.md rename dot_files/{nvim => devcube}/entrypoint.sh (100%) create mode 100755 dot_files/devcube/scripts/devcube.sh delete mode 100644 dot_files/nvim/.dockerignore delete mode 100644 dot_files/nvim/README.md delete mode 100755 dot_files/nvim/scripts/sandbox.sh create mode 100644 dot_files/workmux/config.yaml create mode 100644 dot_files/zellij/config.kdl create mode 100644 dot_files/zellij/layouts/workmux.kdl create mode 100644 system_files/shared/usr/share/ublue-os/just/61-devcube.just delete mode 100644 system_files/shared/usr/share/ublue-os/just/61-nvim.just diff --git a/.github/workflows/build-nvim-dev.yml b/.github/workflows/build-devcube.yml similarity index 79% rename from .github/workflows/build-nvim-dev.yml rename to .github/workflows/build-devcube.yml index 61898d0..d661352 100644 --- a/.github/workflows/build-nvim-dev.yml +++ b/.github/workflows/build-devcube.yml @@ -1,8 +1,8 @@ -# Build and publish nvim-dev container image -# Triggered on changes to dot_files/nvim/ or manual dispatch -# Image published to: ghcr.io/binarypie-dev/nvim-dev:latest +# Build and publish the devcube container image +# Triggered on changes to the baked dot_files configs or manual dispatch +# Image published to: ghcr.io/binarypie-dev/devcube:latest -name: Build nvim-dev Image +name: Build devcube Image concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -13,20 +13,30 @@ on: branches: - main paths: - # Config is baked into the image, so any config change must rebuild. + # Configs are baked into the image, so any config change must rebuild. + - 'dot_files/devcube/**' - 'dot_files/nvim/**' - - '.github/workflows/build-nvim-dev.yml' + - 'dot_files/fish/**' + - 'dot_files/starship/**' + - 'dot_files/zellij/**' + - 'dot_files/workmux/**' + - '.github/workflows/build-devcube.yml' pull_request: paths: + - 'dot_files/devcube/**' - 'dot_files/nvim/**' - - '.github/workflows/build-nvim-dev.yml' + - 'dot_files/fish/**' + - 'dot_files/starship/**' + - 'dot_files/zellij/**' + - 'dot_files/workmux/**' + - '.github/workflows/build-devcube.yml' workflow_dispatch: schedule: # Rebuild daily to get updated packages - cron: '0 6 * * *' env: - IMAGE_NAME: nvim-dev + IMAGE_NAME: devcube IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} jobs: @@ -85,8 +95,8 @@ jobs: - name: Build and push uses: docker/build-push-action@v7 with: - context: dot_files/nvim - file: dot_files/nvim/Containerfile + context: dot_files + file: dot_files/devcube/Containerfile platforms: ${{ matrix.platform }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} @@ -129,12 +139,12 @@ jobs: - name: Generate build summary run: | - echo "## nvim-dev Image Built" >> $GITHUB_STEP_SUMMARY + echo "## devcube Image Built" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Image:** \`${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:latest\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Usage" >> $GITHUB_STEP_SUMMARY echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY - echo "ujust nvim-setup # pull image + install the 'nvim' wrapper" >> $GITHUB_STEP_SUMMARY - echo "nvim # launch the AI-first editor" >> $GITHUB_STEP_SUMMARY + echo "ujust devcube-setup # pull image + install the 'devc' wrapper" >> $GITHUB_STEP_SUMMARY + echo "devc # launch the parallel-agent workspace (workmux)" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7340d56..428d01b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,9 +33,12 @@ hypercube/ │ │ ├── hyprlock.conf # Lock screen │ │ ├── hypridle.conf # Idle management │ │ └── hyprpaper.conf # Wallpaper +│ ├── devcube/ # devcube IDE image (Containerfile, devc wrapper) │ ├── lazygit/ # Lazygit config -│ ├── nvim/ # Neovim/LazyVim setup +│ ├── nvim/ # Neovim/LazyVim config (baked into devcube) │ ├── qt6ct/ # Qt6 theming +│ ├── workmux/ # workmux parallel-agent config (baked into devcube) +│ ├── zellij/ # zellij multiplexer config (baked into devcube) │ ├── quickshell/ # App launcher │ └── starship/ # Shell prompt │ diff --git a/README.md b/README.md index ca0442a..d66b41a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ > Cloud-native development environment with vim keybindings [![Build](https://github.com/binarypie-dev/hypercube/actions/workflows/build.yml/badge.svg)](https://github.com/binarypie-dev/hypercube/actions/workflows/build.yml) -[![nvim-dev](https://github.com/binarypie-dev/hypercube/actions/workflows/build-nvim-dev.yml/badge.svg)](https://github.com/binarypie-dev/hypercube/actions/workflows/build-nvim-dev.yml) +[![devcube](https://github.com/binarypie-dev/hypercube/actions/workflows/build-devcube.yml/badge.svg)](https://github.com/binarypie-dev/hypercube/actions/workflows/build-devcube.yml) [![Copr](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/datacube/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/) [![GHCR](https://img.shields.io/badge/GHCR-ghcr.io%2Fbinarypie--dev%2Fhypercube-blue)](https://ghcr.io/binarypie-dev/hypercube) diff --git a/build_files/hypercube/03-hypercube-configs.sh b/build_files/hypercube/03-hypercube-configs.sh index 44a399a..cc3f6fb 100755 --- a/build_files/hypercube/03-hypercube-configs.sh +++ b/build_files/hypercube/03-hypercube-configs.sh @@ -55,9 +55,9 @@ source = /usr/share/hypercube/config/hypr/hyprland.conf EOF -### Neovim - AI-first sandbox overrides -# The editor config + AI agents ship baked into the podman image -# (ujust nvim-setup). Users keep ONLY personal plugin overrides here; this +### Neovim - devcube sandbox overrides +# The editor config + AI agents ship baked into the devcube podman image +# (ujust devcube-setup). Users keep ONLY personal plugin overrides here; this # directory is bind-mounted into the container's baked LazyVim config and # layered on top of it. mkdir -p /etc/skel/.config/hypercube/nvim/lua/plugins diff --git a/build_files/hypercube/99-tests.sh b/build_files/hypercube/99-tests.sh index 7ad8c11..a728ffc 100755 --- a/build_files/hypercube/99-tests.sh +++ b/build_files/hypercube/99-tests.sh @@ -57,7 +57,7 @@ REQUIRED_FILES=( # DX config "/etc/distrobox/distrobox.ini" "/usr/share/ublue-os/just/60-hypercube.just" - "/usr/share/ublue-os/just/61-nvim.just" + "/usr/share/ublue-os/just/61-devcube.just" ) for file in "${REQUIRED_FILES[@]}"; do diff --git a/dot_files/.dockerignore b/dot_files/.dockerignore new file mode 100644 index 0000000..a5027f0 --- /dev/null +++ b/dot_files/.dockerignore @@ -0,0 +1,23 @@ +# Build context for the devcube image is dot_files/. Exclude everything by +# default and re-include only the dirs the Containerfile bakes, so the heavy +# desktop configs (hypr backgrounds, quickshell assets, ...) never enter the +# build context. +* +!devcube/ +!nvim/ +!fish/ +!starship/ +!zellij/ +!workmux/ + +# Noise inside the kept dirs. +**/.git +**/.DS_Store +**/Thumbs.db +**/*.log +**/*.swp +**/*.swo +**/*~ + +# Neovim lock/runtime data shouldn't be baked (mounted/managed at runtime). +nvim/lazy-lock.json diff --git a/dot_files/nvim/Containerfile b/dot_files/devcube/Containerfile similarity index 80% rename from dot_files/nvim/Containerfile rename to dot_files/devcube/Containerfile index 37a7e56..46a251a 100644 --- a/dot_files/nvim/Containerfile +++ b/dot_files/devcube/Containerfile @@ -1,11 +1,15 @@ -# Hypercube AI-first Neovim sandbox +# Hypercube devcube — containerized IDE + parallel-agent orchestration # -# A self-contained, portable podman image: LazyVim (baked in), the full dev -# toolchain (LSPs/formatters/linters), and AI coding agents (Claude Code, OpenAI -# Codex, Antigravity, GitHub CLI). Agents are launched from inside nvim. +# A self-contained, portable podman image: Neovim/LazyVim (baked in), the full +# dev toolchain (LSPs/formatters/linters), AI coding agents (Claude Code, OpenAI +# Codex, Antigravity, GitHub CLI), plus zellij + workmux for running multiple +# agents in parallel (each in its own git worktree) and a fish + starship shell. # -# Build: podman build -t nvim-dev . -# Run: podman run --rm -it nvim-dev (see scripts/sandbox.sh for mounts) +# The build context is the parent dot_files/ dir so the fish/starship/zellij/ +# workmux/nvim configs (top-level dotfiles) can be baked in. +# +# Build: cd dot_files && podman build -t devcube -f devcube/Containerfile . +# Run: devc (see devcube/scripts/devcube.sh for mounts + dispatch) FROM registry.fedoraproject.org/fedora-toolbox:44 @@ -131,11 +135,17 @@ RUN brew install \ # ============================================================================= # LAYER 6: Infrastructure tools via Homebrew # ============================================================================= +# zellij (terminal multiplexer) + workmux (git-worktree -> multiplexer +# orchestration; a brew tap, auto-tapped by the fully-qualified name) power the +# parallel-agent workflow. starship renders the fish prompt baked in below. RUN brew install \ opentofu \ helm \ sqlfluff \ - fish + fish \ + starship \ + zellij \ + raine/workmux/workmux # ============================================================================= # LAYER 7: Rust toolchain (as linuxbrew user) @@ -251,21 +261,35 @@ RUN mkdir -p /etc/profile.d /etc/fish/conf.d \ # The full LazyVim config is baked into $HOME/.config/nvim. Personal overrides # are bind-mounted at runtime from the host (~/.config/hypercube/nvim) and # layered on top via the runtimepath (see lua/config/lazy.lua). -COPY config/ /root/.config/nvim/ +# NOTE: the build context is dot_files/, so the nvim config lives under nvim/. +COPY nvim/config/ /root/.config/nvim/ # Pre-install all plugins + build treesitter parsers so first launch is fast and # offline. HOME=/root and PATH already include the brew nvim binary. RUN nvim --headless "+Lazy! sync" +qa +# ============================================================================= +# LAYER 14b: Bake the shell / multiplexer / orchestrator configs +# ============================================================================= +# fish + starship give a good in-container shell/prompt; zellij + workmux drive +# the parallel-agent workflow. These seed into the persisted home volume on +# first run (podman copy-up), like the nvim config above. starship.toml lands at +# the exact path dot_files/fish/config.fish hardcodes for STARSHIP_CONFIG, so +# fish needs no edits (and it lives outside /root, so it's always present). +COPY fish/ /root/.config/fish/ +COPY zellij/ /root/.config/zellij/ +COPY workmux/ /root/.config/workmux/ +COPY starship/ /usr/share/hypercube/config/starship/ + # ============================================================================= # LAYER 15: Entrypoint # ============================================================================= -COPY entrypoint.sh /usr/local/bin/hypercube-nvim-entrypoint -RUN chmod +x /usr/local/bin/hypercube-nvim-entrypoint -ENTRYPOINT ["/usr/local/bin/hypercube-nvim-entrypoint"] +COPY devcube/entrypoint.sh /usr/local/bin/devcube-entrypoint +RUN chmod +x /usr/local/bin/devcube-entrypoint +ENTRYPOINT ["/usr/local/bin/devcube-entrypoint"] CMD ["nvim"] # Labels for GitHub Container Registry LABEL org.opencontainers.image.source="https://github.com/binarypie/hypercube" -LABEL org.opencontainers.image.description="AI-first Neovim sandbox: LazyVim + dev toolchain + Claude Code, Codex, Antigravity, gh" +LABEL org.opencontainers.image.description="devcube: containerized IDE (Neovim/LazyVim + dev toolchain + Claude Code, Codex, Antigravity, gh) with zellij + workmux parallel-agent orchestration" LABEL org.opencontainers.image.licenses="MIT" diff --git a/dot_files/nvim/Justfile b/dot_files/devcube/Justfile similarity index 55% rename from dot_files/nvim/Justfile rename to dot_files/devcube/Justfile index e93ee2f..f02ab93 100644 --- a/dot_files/nvim/Justfile +++ b/dot_files/devcube/Justfile @@ -1,9 +1,13 @@ -# Hypercube Neovim sandbox — local development and testing commands +# Hypercube devcube — local development and testing commands +# +# The build context is the parent dot_files/ dir (so fish/starship/zellij/ +# workmux/nvim configs can be baked), hence `-f Containerfile ..` below. -local_image := "localhost/nvim-dev" -remote_image := "ghcr.io/binarypie-dev/nvim-dev:latest" -# Throwaway volume so local testing never touches the real hypercube-nvim-home. -test_volume := "hypercube-nvim-test" +local_image := "localhost/devcube" +remote_image := "ghcr.io/binarypie-dev/devcube:latest" +# Throwaway volumes so local testing never touches the real per-project state. +test_volume := "hypercube-devcube-test" +test_wt_prefix := "devcube-wt-test" # Default recipe - show help default: @@ -13,16 +17,16 @@ default: # Image Building # ============================================================================= -# Build the container image locally +# Build the container image locally (context is the parent dot_files/ dir) build: - @echo "Building nvim-dev image locally..." - podman build -t {{local_image}} . + @echo "Building devcube image locally..." + podman build -t {{local_image}} -f Containerfile .. @echo "Done! Image: {{local_image}}" # Build without cache build-no-cache: - @echo "Building nvim-dev image (no cache)..." - podman build --no-cache -t {{local_image}} . + @echo "Building devcube image (no cache)..." + podman build --no-cache -t {{local_image}} -f Containerfile .. @echo "Done! Image: {{local_image}}" # Push to GHCR (requires: podman login ghcr.io) @@ -34,22 +38,19 @@ push: # Usage (against the LOCAL image) # ============================================================================= -# Launch the sandbox (nvim) from the local image, using a throwaway test volume +# Launch devcube from the local image (e.g. `just run` for workmux, `just run nvim`), +# using throwaway test volumes. run *args: - HYPERCUBE_NVIM_IMAGE={{local_image}} HYPERCUBE_NVIM_VOLUME={{test_volume}} ./scripts/sandbox.sh {{args}} + DEVCUBE_IMAGE={{local_image}} DEVCUBE_VOLUME={{test_volume}} DEVCUBE_WT_PREFIX={{test_wt_prefix}} ./scripts/devcube.sh {{args}} -# Launch an agent directly (e.g. `just run-agent claude`) from the local image +# Launch a specific tool directly (e.g. `just run-agent claude`) from the local image run-agent agent *args: - #!/usr/bin/bash - set -euo pipefail - link="$(mktemp -d)/{{agent}}" - ln -s "$(pwd)/scripts/sandbox.sh" "$link" - HYPERCUBE_NVIM_IMAGE={{local_image}} HYPERCUBE_NVIM_VOLUME={{test_volume}} "$link" {{args}} + DEVCUBE_IMAGE={{local_image}} DEVCUBE_VOLUME={{test_volume}} DEVCUBE_WT_PREFIX={{test_wt_prefix}} ./scripts/devcube.sh {{agent}} {{args}} # Open a shell in the local image shell: podman run --rm -it --init --user 0:0 --security-opt label=disable \ - -e HYPERCUBE_NVIM=1 -e TERM \ + -e DEVCUBE=1 -e TERM \ -v {{test_volume}}:/root \ {{local_image}} bash @@ -57,7 +58,7 @@ shell: # Tests # ============================================================================= -# Verify the image: nvim config loads and the toolchain + AI CLIs are present +# Verify the image: nvim config loads and the toolchain + AI CLIs + orchestrators are present test-build: build @echo "Testing container..." podman run --rm {{local_image}} nvim --headless +qa @@ -70,6 +71,10 @@ test-build: build podman run --rm {{local_image}} claude --version podman run --rm {{local_image}} codex --version podman run --rm {{local_image}} agy --version + podman run --rm {{local_image}} zellij --version + podman run --rm {{local_image}} workmux --version + podman run --rm {{local_image}} starship --version + podman run --rm {{local_image}} fish --version @echo "" @echo "All tests passed!" @@ -81,6 +86,7 @@ test-build: build clean-image: -podman rmi {{local_image}} -# Remove the throwaway test volume +# Remove the throwaway test volumes (home + any per-project worktree volumes) clean-volume: -podman volume rm -f {{test_volume}} + -podman volume ls -q | grep '^{{test_wt_prefix}}-' | xargs -r podman volume rm -f diff --git a/dot_files/nvim/LICENSE.md b/dot_files/devcube/LICENSE.md similarity index 100% rename from dot_files/nvim/LICENSE.md rename to dot_files/devcube/LICENSE.md diff --git a/dot_files/devcube/README.md b/dot_files/devcube/README.md new file mode 100644 index 0000000..58ef869 --- /dev/null +++ b/dot_files/devcube/README.md @@ -0,0 +1,154 @@ +# devcube — containerized IDE + parallel-agent orchestration + +A self-contained, **portable** development environment baked into one podman +image: [LazyVim](https://github.com/LazyVim/LazyVim), the full dev toolchain +(LSPs/formatters/linters), the AI coding agents, **and** +[zellij](https://github.com/zellij-org/zellij) + +[workmux](https://github.com/raine/workmux) for running multiple agents in +parallel — each in its own git worktree, all inside a single container (no +nested podman). + +A single wrapper installed as `devc` runs it. Runs identically on the Hypercube +Linux desktop, a remote box, and macOS — no distrobox required. + +## What's baked in + +- **Editor:** Neovim + LazyVim with Hypercube customizations. +- **AI agents:** Claude Code (`claude`), OpenAI Codex (`codex`), Antigravity + (`agy`), GitHub CLI (`gh`). Wired into nvim via `claudecode.nvim` and + `sidekick.nvim`. +- **Parallel agents:** zellij (terminal multiplexer) + workmux (git-worktree → + multiplexer orchestration). +- **Shell:** fish + starship prompt (Tokyo Night Moon, matching nvim/Ghostty). +- **Languages & runtimes:** Go, Python 3.12, Node.js, Ruby, Lua, Rust. +- **Formatters:** stylua, prettier, shfmt, gofumpt, goimports, black, isort, ruff. +- **Linters:** shellcheck, hadolint, eslint, golangci-lint. +- **Language servers:** lua-language-server, gopls, pyright, + typescript-language-server, vtsls, rust-analyzer, bash-language-server, + dockerfile-language-server, yaml-language-server, tailwindcss-language-server. +- **CLI tools:** ripgrep, fd, fzf, lazygit, bat, eza, delta, jq, yq, just, + tree-sitter; Ghostty terminfo. + +## Usage + +`devc` dispatches on its first argument (extra args pass through): + +| Command | What it does | +|---|---| +| `devc` | the workmux parallel-agent workspace (a zellij session) — the default | +| `devc zellij` | a plain zellij multiplexer session | +| `devc nvim [file]`| the editor | +| `devc claude` | Claude Code CLI, run directly | +| `devc codex` | OpenAI Codex CLI, run directly | +| `devc agy` | Antigravity CLI, run directly | + +All entry points share one home volume, so an AI login from any of them works in +all of them. + +### Parallel agents + +Run `devc` (or `devc workmux`) to open the workmux workspace, then from any pane: + +```bash +workmux add "" # new git worktree + a zellij tab running the agent +workmux list # show worktrees + agent status +workmux merge # merge and clean up +workmux remove # remove without merging +``` + +Worktrees are created on a **per-project named volume** mounted at `/worktrees`, +so they persist across restarts and stay isolated from other projects. The +volume name is derived from the launch path, so `~/Code/myrepo` always gets the +same worktrees back. (Worktrees live on the volume, not on the host — manage +them from inside `devc`, not via `git worktree` on the host.) + +## How it works + +`scripts/devcube.sh` runs the image as an ephemeral `podman` container and mounts +only what's needed. The mounts: + +| Mounted in | Purpose | +|---|---| +| named volume `hypercube-devcube-home` → `/root` | plugin/mason updates, sessions, shada, **and AI-CLI auth** — seeded from the image on first run, persisted after | +| current directory | the project you're editing | +| per-project volume `devcube-wt--` → `/worktrees` | worktrees + workmux state (orchestrators only) | +| `~/.config/hypercube/nvim` | **your** plugin overrides, layered on top of the baked config | +| `~/.gitconfig` (ro) | commit identity | +| `$SSH_AUTH_SOCK` (Linux) | SSH agent for git/gh | + +Everything else (the LazyVim config, plugins, AI CLIs, zellij/workmux/fish/ +starship config) lives in the image. The container runs as `--user 0:0` so files +you edit are owned by your host user under rootless podman. Multiple sessions run +concurrently. + +Clipboard uses **OSC 52** through the terminal, so yank/paste works locally +(Ghostty) and over SSH without forwarding a Wayland/pbcopy socket. + +## Setup (Hypercube) + +```bash +ujust devcube-setup # pull image + install the 'devc' wrapper to ~/.local/bin +devc # open the parallel-agent workspace +devc nvim file.rs # ...or just the editor +``` + +| Command | Description | +|---------|-------------| +| `ujust devcube-setup` | pull image + install the `devc` wrapper | +| `ujust devcube-upgrade` | pull the latest image + refresh the wrapper | +| `ujust devcube-reset` | drop the home volume to re-seed (clears plugin state + AI logins); optionally prune per-project worktree volumes | +| `ujust devcube-shell` | debug shell inside a throwaway container | + +## Setup (macOS / any podman host) + +No `ujust` needed — install the wrapper by hand: + +```bash +podman pull ghcr.io/binarypie-dev/devcube:latest +install -m 0755 dot_files/devcube/scripts/devcube.sh ~/.local/bin/devc +devc +``` + +macOS notes: +- Edit projects under your home directory (the path podman's VM shares). +- The host SSH agent isn't reachable from the podman VM, so run `gh auth login` + once inside (e.g. from `devc nvim`'s terminal) — it persists in the home volume + and authenticates git over HTTPS. + +## Personal overrides + +Drop LazyVim plugin specs in `~/.config/hypercube/nvim/lua/plugins/*.lua`. They're +bind-mounted in and layered on top of the baked config — add plugins, change +options, or disable defaults without rebuilding the image. Example: + +```lua +-- ~/.config/hypercube/nvim/lua/plugins/mine.lua +return { + { "folke/snacks.nvim", opts = { dashboard = { preset = { header = "hi" } } } }, +} +``` + +## AI keymaps + +- `a…` — Claude Code (claudecode.nvim, LazyVim defaults) +- `A…` — sidekick.nvim agents: `Ac` Claude, `Ax` Codex, `Aa` toggle + last, `As` send selection, `Ap` ask with prompt +- `` — apply/jump sidekick Next Edit Suggestion (falls through to `` + when Copilot isn't signed in) + +## Local development (editing the image) + +The build context is the parent `dot_files/` dir (so the fish/starship/zellij/ +workmux/nvim configs can be baked), which the recipes handle for you: + +```bash +cd dot_files/devcube + +just build # build localhost/devcube +just test-build # verify nvim + toolchain + AI CLIs + zellij/workmux/fish/starship run +just run # launch the workmux workspace from the local image (throwaway volumes) +just run nvim . # ...or a specific tool +just shell # bash in the local image +just clean-image # remove the local image +just clean-volume # remove the throwaway test volumes +``` diff --git a/dot_files/nvim/entrypoint.sh b/dot_files/devcube/entrypoint.sh similarity index 100% rename from dot_files/nvim/entrypoint.sh rename to dot_files/devcube/entrypoint.sh diff --git a/dot_files/devcube/scripts/devcube.sh b/dot_files/devcube/scripts/devcube.sh new file mode 100755 index 0000000..0f73c50 --- /dev/null +++ b/dot_files/devcube/scripts/devcube.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +# devcube — containerized IDE + parallel-agent launcher. +# +# One podman image bakes Neovim (LazyVim) + the AI coding agents + the dev +# toolchain + zellij/workmux + a fish/starship shell. This single wrapper is +# installed as `devc`; the first argument selects what runs inside the +# (otherwise identical) container: +# +# devc -> workmux parallel-agent workspace (a zellij session) -- default +# devc zellij -> a plain zellij multiplexer session +# devc nvim -> the editor (launch agents from inside it) +# devc claude -> Claude Code CLI, run directly +# devc codex -> OpenAI Codex CLI, run directly +# devc agy -> Antigravity CLI, run directly +# +# Extra args after the tool are passed through (e.g. `devc nvim file.rs`, +# `devc claude --resume`). All entry points share the same home volume, so +# AI-CLI logins persist across them -- log in once and every tool is authed. +# +# zellij/workmux run the parallel-agent flow: each `workmux add ` +# creates a git worktree on a PER-PROJECT named volume mounted at /worktrees, +# so worktrees (and workmux's state) persist across restarts and never collide +# with another project's. Everything else mounts only the current project, your +# personal overrides, and a few host facts. Portable across Linux and macOS. +# +# Env overrides: +# DEVCUBE_IMAGE container image (default ghcr.io/binarypie-dev/devcube:latest) +# DEVCUBE_VOLUME named volume holding state + AI auth (default hypercube-devcube-home) +# DEVCUBE_WT_PREFIX prefix for the per-project worktree volume (default devcube-wt) +set -euo pipefail + +# The tool to run is the first argument; default to the workmux workspace. +TOOL="${1:-workmux}" +case "$TOOL" in +nvim | claude | codex | agy | zellij | workmux) + if [ $# -gt 0 ]; then shift; fi + ;; +*) + echo "devc: unknown command '$TOOL'" >&2 + echo "usage: devc [nvim|claude|codex|agy|zellij|workmux] [args...] (no args -> workmux)" >&2 + exit 1 + ;; +esac + +IMAGE="${DEVCUBE_IMAGE:-ghcr.io/binarypie-dev/devcube:latest}" +VOLUME="${DEVCUBE_VOLUME:-hypercube-devcube-home}" +OVERRIDE_DIR="$HOME/.config/hypercube/nvim" + +# Personal overrides are layered on top of the baked config. Ensure the dir +# exists so the bind mount and `{ import = "plugins" }` always resolve. +mkdir -p "$OVERRIDE_DIR/lua/plugins" + +# Physical path so symlinks resolve identically on host and in the container. +workdir="$(pwd -P)" + +# Default: run the tool with only the project mounted. The orchestrators +# (zellij/workmux) additionally get a per-project worktree volume + the zellij +# backend, and run inside a project-named zellij session. +container_cmd=("$TOOL") +extra=() +case "$TOOL" in +zellij | workmux) + # Stable, path-derived names so a project's worktrees + workmux state + # persist across restarts and never collide with another project's. + # cksum is available on both Linux and macOS (the wrapper stays portable). + slug="$(basename "$workdir" | tr -c 'a-zA-Z0-9_.-' '-')" + phash="$(printf '%s' "$workdir" | cksum | cut -d' ' -f1)" + wt_volume="${DEVCUBE_WT_PREFIX:-devcube-wt}-${slug}-${phash}" + extra=( + # Worktrees live here (podman auto-creates the volume on first mount). + -v "${wt_volume}:/worktrees:rw" + -e WORKMUX_BACKEND=zellij + # Keep workmux's agent state on the per-project volume too, so it's + # isolated from other projects and survives restarts. + -e XDG_STATE_HOME=/worktrees/.local/state + ) + if [ "$TOOL" = workmux ]; then + container_cmd=(zellij --layout workmux --session "${slug}-${phash}") + else + container_cmd=(zellij --session "${slug}-${phash}") + fi + ;; +esac + +args=( + run --rm --interactive --tty --init + --user 0:0 + --security-opt label=disable + --hostname "$TOOL" + -e DEVCUBE=1 + -e TERM + -e COLORTERM + "${extra[@]}" + # State + plugin updates + AI auth. Empty volume is seeded from the image's + # /root on first run (podman copy-up); never use a fixed container --name so + # multiple sessions can run concurrently. + -v "${VOLUME}:/root" + # The project being edited, at the same path inside the container. + -v "${workdir}:${workdir}:rw" + # Personal plugin overrides (nested over the home volume). + -v "${OVERRIDE_DIR}:/root/.config/hypercube/nvim:rw" + -w "${workdir}" +) + +# Read-only git identity (name/email/aliases) from the host. +if [ -f "$HOME/.gitconfig" ]; then + args+=(-v "$HOME/.gitconfig:/root/.gitconfig:ro") +fi + +# SSH agent forwarding on Linux. On macOS podman runs in a VM and the host +# agent socket isn't reachable, so we skip it there and rely on `gh auth login` +# (run once inside; persisted in the home volume) for git-over-HTTPS. +if [ "$(uname -s)" = "Linux" ] && [ -n "${SSH_AUTH_SOCK:-}" ] && [ -S "${SSH_AUTH_SOCK}" ]; then + args+=(-v "${SSH_AUTH_SOCK}:${SSH_AUTH_SOCK}:rw" -e "SSH_AUTH_SOCK=${SSH_AUTH_SOCK}") +fi + +exec podman "${args[@]}" "$IMAGE" "${container_cmd[@]}" "$@" diff --git a/dot_files/nvim/.dockerignore b/dot_files/nvim/.dockerignore deleted file mode 100644 index d8ddcba..0000000 --- a/dot_files/nvim/.dockerignore +++ /dev/null @@ -1,19 +0,0 @@ -# Ignore Neovim runtime data (will be mounted separately) -.git -*.md -!README.md -LICENSE - -# Ignore local plugin data -plugin/ -spell/ - -# Ignore caches and generated files -*.log -*.swp -*.swo -*~ - -# Ignore OS files -.DS_Store -Thumbs.db diff --git a/dot_files/nvim/README.md b/dot_files/nvim/README.md deleted file mode 100644 index 748e7c7..0000000 --- a/dot_files/nvim/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# Hypercube Neovim — AI-first sandbox - -A self-contained, **portable** Neovim environment: [LazyVim](https://github.com/LazyVim/LazyVim) -plus the full dev toolchain (LSPs/formatters/linters) **and** AI coding agents, -all baked into one podman image. Launch the agents from inside nvim — or run -`claude` / `codex` / `agy` directly when you just want the agent. - -Runs identically on the Hypercube Linux desktop, a remote box, and macOS — no -distrobox required. - -## What's baked in - -- **Editor:** Neovim + LazyVim with Hypercube customizations. -- **AI agents:** Claude Code (`claude`), OpenAI Codex (`codex`), Antigravity - (`agy`), GitHub CLI (`gh`). Wired into nvim via `sidekick.nvim`. -- **Languages & runtimes:** Go, Python 3.12, Node.js, Ruby, Lua, Rust. -- **Formatters:** stylua, prettier, shfmt, gofumpt, goimports, black, isort, ruff. -- **Linters:** shellcheck, hadolint, eslint, golangci-lint. -- **Language servers:** lua-language-server, gopls, pyright, - typescript-language-server, vtsls, rust-analyzer, bash-language-server, - dockerfile-language-server, yaml-language-server, tailwindcss-language-server. -- **CLI tools:** ripgrep, fd, fzf, lazygit, bat, eza, delta, jq, yq, just, - tree-sitter; Ghostty terminfo; fish. - -## How it works - -`scripts/sandbox.sh` runs the image as an ephemeral `podman` container and -mounts only what's needed. It dispatches on the name it's invoked as: installed -as `nvim` it launches the editor, and it's symlinked to `claude`, `codex`, and -`agy` so those run the matching agent directly in the same container. All share -the home volume below, so an AI login from any one entry point works in all of -them. The mounts: - -| Mounted in | Purpose | -|---|---| -| named volume `hypercube-nvim-home` → `/root` | plugin/mason updates, sessions, shada, **and AI-CLI auth** — seeded from the image on first run, persisted after | -| current directory | the project you're editing | -| `~/.config/hypercube/nvim` | **your** plugin overrides, layered on top of the baked config | -| `~/.gitconfig` (ro) | commit identity | -| `$SSH_AUTH_SOCK` (Linux) | SSH agent for git/gh | - -Everything else (the LazyVim config, plugins, AI CLIs) lives in the image. The -container runs as `--user 0:0` so files you edit are owned by your host user -under rootless podman. Multiple sessions run concurrently — there's no fixed -container name, and nvim safely shares shada/swap. - -Clipboard uses **OSC 52** through the terminal, so yank/paste works locally -(Ghostty) and over SSH without forwarding a Wayland/pbcopy socket. - -## Setup (Hypercube) - -```bash -ujust nvim-setup # pull image + install the nvim + agent wrappers to ~/.local/bin -nvim file.rs # launch the editor -claude # ...or run an agent directly (also: codex, agy) -``` - -| Command | Description | -|---------|-------------| -| `ujust nvim-setup` | pull image + install the `nvim`, `claude`, `codex`, `agy` wrappers | -| `ujust nvim-upgrade` | pull the latest image + refresh the wrappers | -| `ujust nvim-reset` | drop the home volume to re-seed (clears plugin state + AI logins) | -| `ujust nvim-shell` | debug shell inside a throwaway sandbox container | - -## Setup (macOS / any podman host) - -No `ujust` needed — install the wrapper by hand: - -```bash -podman pull ghcr.io/binarypie-dev/nvim-dev:latest -install -m 0755 dot_files/nvim/scripts/sandbox.sh ~/.local/bin/nvim -# Symlink the agent wrappers (the script dispatches on its invoked name): -for agent in claude codex agy; do ln -sf nvim ~/.local/bin/$agent; done -nvim -``` - -macOS notes: -- Edit projects under your home directory (the path podman's VM shares). -- The host SSH agent isn't reachable from the podman VM, so run `gh auth login` - once inside nvim's terminal — it persists in the home volume and authenticates - git over HTTPS. - -## Personal overrides - -Drop LazyVim plugin specs in `~/.config/hypercube/nvim/lua/plugins/*.lua`. They're -bind-mounted in and layered on top of the baked config — add plugins, change -options, or disable defaults without rebuilding the image. Example: - -```lua --- ~/.config/hypercube/nvim/lua/plugins/mine.lua -return { - { "folke/snacks.nvim", opts = { dashboard = { preset = { header = "hi" } } } }, -} -``` - -## AI keymaps - -- `a…` — sidekick.nvim agents: `ac` Claude, `ax` Codex, `ag` - Antigravity, `aa` toggle last, `as` send selection, `ap` ask with prompt -- `` — apply/jump sidekick Next Edit Suggestion (falls through to `` - when Copilot isn't signed in) - -## Local development (editing the image) - -```bash -cd dot_files/nvim - -just build # build localhost/nvim-dev -just test-build # verify nvim + toolchain + AI CLIs run -just run . # launch the local image (uses a throwaway test volume) -just shell # bash in the local image -just clean-image # remove the local image -``` diff --git a/dot_files/nvim/config/lua/hypercube/config.lua b/dot_files/nvim/config/lua/hypercube/config.lua index bef9fe7..50f010f 100644 --- a/dot_files/nvim/config/lua/hypercube/config.lua +++ b/dot_files/nvim/config/lua/hypercube/config.lua @@ -15,8 +15,8 @@ function M.setup() -- Inside the Hypercube container we can't reach the host Wayland/pbcopy -- socket, so route yanks/pastes through the terminal escape sequence. This -- works locally on Ghostty and over SSH, keeping the sandbox portable. - -- Gated on HYPERCUBE_NVIM so a host-native nvim keeps its own clipboard. - if vim.env.HYPERCUBE_NVIM == "1" then + -- Gated on DEVCUBE so a host-native nvim keeps its own clipboard. + if vim.env.DEVCUBE == "1" then local ok, osc52 = pcall(require, "vim.ui.clipboard.osc52") if ok then vim.g.clipboard = { diff --git a/dot_files/nvim/scripts/sandbox.sh b/dot_files/nvim/scripts/sandbox.sh deleted file mode 100755 index c4beb2f..0000000 --- a/dot_files/nvim/scripts/sandbox.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash -# Hypercube AI-first sandbox launcher. -# -# One podman image bakes Neovim (LazyVim) + the AI coding agents + the dev -# toolchain. This single wrapper is installed under several names; the name it -# is invoked as selects what runs inside the (otherwise identical) container: -# -# nvim -> the editor (launch agents from inside it) -- the default -# claude -> Claude Code CLI, run directly -# codex -> OpenAI Codex CLI, run directly -# agy -> Antigravity CLI, run directly -# -# All four share the same home volume, so AI-CLI logins persist across them -- -# log in once (from nvim or any agent wrapper) and every entry point is authed. -# -# Mounts only the current project, your personal overrides, and a few host -# facts (git identity, SSH agent, terminal). Portable across Linux and macOS. -# -# Env overrides: -# HYPERCUBE_NVIM_IMAGE container image (default ghcr.io/binarypie-dev/nvim-dev:latest) -# HYPERCUBE_NVIM_VOLUME named volume holding state + AI auth (default hypercube-nvim-home) -set -euo pipefail - -# What to run is chosen by the name we were invoked as (symlinks point here). -CMD="$(basename "$0")" -case "$CMD" in - nvim | claude | codex | agy) ;; - *) CMD=nvim ;; -esac - -IMAGE="${HYPERCUBE_NVIM_IMAGE:-ghcr.io/binarypie-dev/nvim-dev:latest}" -VOLUME="${HYPERCUBE_NVIM_VOLUME:-hypercube-nvim-home}" -OVERRIDE_DIR="$HOME/.config/hypercube/nvim" - -# Personal overrides are layered on top of the baked config. Ensure the dir -# exists so the bind mount and `{ import = "plugins" }` always resolve. -mkdir -p "$OVERRIDE_DIR/lua/plugins" - -# Physical path so symlinks resolve identically on host and in the container. -workdir="$(pwd -P)" - -args=( - run --rm --interactive --tty --init - --user 0:0 - --security-opt label=disable - --hostname "$CMD" - -e HYPERCUBE_NVIM=1 - -e TERM - -e COLORTERM - # State + plugin updates + AI auth. Empty volume is seeded from the image's - # /root on first run (podman copy-up); never use a fixed container --name so - # multiple sessions can run concurrently. - -v "${VOLUME}:/root" - # The project being edited, at the same path inside the container. - -v "${workdir}:${workdir}:rw" - # Personal plugin overrides (nested over the home volume). - -v "${OVERRIDE_DIR}:/root/.config/hypercube/nvim:rw" - -w "${workdir}" -) - -# Read-only git identity (name/email/aliases) from the host. -if [ -f "$HOME/.gitconfig" ]; then - args+=(-v "$HOME/.gitconfig:/root/.gitconfig:ro") -fi - -# SSH agent forwarding on Linux. On macOS podman runs in a VM and the host -# agent socket isn't reachable, so we skip it there and rely on `gh auth login` -# (run once inside; persisted in the home volume) for git-over-HTTPS. -if [ "$(uname -s)" = "Linux" ] && [ -n "${SSH_AUTH_SOCK:-}" ] && [ -S "${SSH_AUTH_SOCK}" ]; then - args+=(-v "${SSH_AUTH_SOCK}:${SSH_AUTH_SOCK}:rw" -e "SSH_AUTH_SOCK=${SSH_AUTH_SOCK}") -fi - -exec podman "${args[@]}" "$IMAGE" "$CMD" "$@" diff --git a/dot_files/workmux/config.yaml b/dot_files/workmux/config.yaml new file mode 100644 index 0000000..7675798 --- /dev/null +++ b/dot_files/workmux/config.yaml @@ -0,0 +1,14 @@ +# Hypercube workmux configuration (global; ~/.config/workmux/config.yaml). +# +# Worktrees are created on a per-project named volume that devcube mounts at +# /worktrees, so they persist across container restarts and stay isolated from +# other projects. (See dot_files/devcube/scripts/devcube.sh.) +mode: window +worktree_dir: /worktrees + +# Default panes for each worktree window: the agent + a plain shell. Override +# per-project by committing a .workmux.yaml in the repo root. +panes: + - command: claude + focus: true + - split: horizontal diff --git a/dot_files/zellij/config.kdl b/dot_files/zellij/config.kdl new file mode 100644 index 0000000..085c789 --- /dev/null +++ b/dot_files/zellij/config.kdl @@ -0,0 +1,32 @@ +// Hypercube zellij configuration. +// +// Tokyo Night Moon theme to match Neovim/Ghostty. Palette source of truth: +// dot_files/ghostty/config ("TOKYO NIGHT MOON COLOR SCHEME"). +// +// zellij keeps its own default keybindings (no seamless vim/zellij nav by +// design) — only quality-of-life defaults are set below. + +themes { + tokyo-night-moon { + fg "#c8d3f5" + bg "#222436" + black "#1e2030" + red "#ff757f" + green "#c3e88d" + yellow "#ffc777" + blue "#82aaff" + magenta "#c099ff" + cyan "#86e1fc" + // Dim white so UI chrome stays distinct from the foreground. + white "#828bb8" + // Tokyo Night Moon spec (Ghostty has no dedicated orange slot). + orange "#ff966c" + } +} + +theme "tokyo-night-moon" + +default_shell "fish" +scrollback_editor "nvim" +pane_frames true +default_layout "compact" diff --git a/dot_files/zellij/layouts/workmux.kdl b/dot_files/zellij/layouts/workmux.kdl new file mode 100644 index 0000000..ff36419 --- /dev/null +++ b/dot_files/zellij/layouts/workmux.kdl @@ -0,0 +1,16 @@ +// workmux workspace layout: a working shell beside a live `workmux sidebar` +// status pane. Launched by `devc` / `devc workmux` (zellij --layout workmux). +// From any pane: `workmux add ""` spins up a git worktree + +// a new tab running the configured agent. +layout { + tab name="workmux" { + pane split_direction="vertical" { + // Working shell (focus). + pane + pane size="30%" { + command "workmux" + args "sidebar" + } + } + } +} diff --git a/system_files/shared/etc/distrobox/distrobox.ini b/system_files/shared/etc/distrobox/distrobox.ini index ec98d04..f1130cc 100644 --- a/system_files/shared/etc/distrobox/distrobox.ini +++ b/system_files/shared/etc/distrobox/distrobox.ini @@ -1,8 +1,8 @@ # Hypercube Distrobox Configuration # -# No pre-configured containers. The Neovim + AI development environment now -# ships as a standalone, portable podman image instead of a distrobox container -# (set up with 'ujust nvim-setup', launched via the 'nvim' wrapper). +# No pre-configured containers. The devcube IDE (Neovim + AI agents + zellij/ +# workmux) now ships as a standalone, portable podman image instead of a +# distrobox container (set up with 'ujust devcube-setup', launched via 'devc'). # # distrobox itself remains installed for ad-hoc toolboxes; add your own # [container] sections here as needed. diff --git a/system_files/shared/usr/bin/nvim-launcher b/system_files/shared/usr/bin/nvim-launcher index 5cd5113..6a801df 100755 --- a/system_files/shared/usr/bin/nvim-launcher +++ b/system_files/shared/usr/bin/nvim-launcher @@ -1,37 +1,38 @@ #!/bin/bash -# nvim-launcher - Launch the Hypercube AI-first Neovim sandbox +# nvim-launcher - Open files in the Hypercube devcube editor # -# The editor + AI agents ship as a podman image run via ~/.local/bin/nvim. -# On first use this installs the wrapper (pulling the image), then execs it. +# The editor + AI agents ship as a podman image run via ~/.local/bin/devc. +# On first use this installs the wrapper (pulling the image), then opens nvim +# inside it (`devc nvim`). -NVIM_BIN="$HOME/.local/bin/nvim" +DEVC_BIN="$HOME/.local/bin/devc" -if [ ! -x "$NVIM_BIN" ]; then - echo "Neovim Sandbox" - echo "==============" +if [ ! -x "$DEVC_BIN" ]; then + echo "devcube" + echo "=======" echo "" - echo "The Neovim sandbox is not set up yet." + echo "The devcube IDE is not set up yet." echo "" echo "This will pull the image (several GB on first run) and install the" - echo "'nvim' launcher to ~/.local/bin." + echo "'devc' launcher to ~/.local/bin." echo "" read -p "Set up now? [Y/n] " -n 1 -r echo "" if [[ $REPLY =~ ^[Nn]$ ]]; then - echo "Setup cancelled. Run 'ujust nvim-setup' when ready." + echo "Setup cancelled. Run 'ujust devcube-setup' when ready." read -p "Press Enter to close..." exit 0 fi echo "" - ujust nvim-setup + ujust devcube-setup fi -if [ -x "$NVIM_BIN" ]; then - exec "$NVIM_BIN" "$@" +if [ -x "$DEVC_BIN" ]; then + exec "$DEVC_BIN" nvim "$@" else - echo "Setup may have failed. Try running 'ujust nvim-setup' manually." + echo "Setup may have failed. Try running 'ujust devcube-setup' manually." read -p "Press Enter to close..." exit 1 fi diff --git a/system_files/shared/usr/share/ublue-os/just/61-devcube.just b/system_files/shared/usr/share/ublue-os/just/61-devcube.just new file mode 100644 index 0000000..34bceca --- /dev/null +++ b/system_files/shared/usr/share/ublue-os/just/61-devcube.just @@ -0,0 +1,79 @@ +# vim: set ft=make : +# Hypercube devcube — containerized IDE + parallel-agent orchestration +# +# Neovim/LazyVim, the AI agents (Claude Code, Codex, Antigravity, gh), the dev +# toolchain, and zellij + workmux ship as a single portable podman image. A thin +# wrapper at ~/.local/bin/devc runs it: `devc` opens the workmux parallel-agent +# workspace, and `devc nvim` / `devc claude` / `devc codex` / `devc agy` / +# `devc zellij` launch a single tool. One home volume is shared across them, so +# AI logins persist. Personal plugin overrides live in +# ~/.config/hypercube/nvim/lua/plugins/. + +image := "ghcr.io/binarypie-dev/devcube:latest" +wrapper := "/usr/share/hypercube/config/devcube/scripts/devcube.sh" +volume := "hypercube-devcube-home" + +# Pull the image and install the devc wrapper to ~/.local/bin +devcube-setup: + #!/usr/bin/bash + set -euo pipefail + + echo "Pulling devcube image ({{image}})..." + echo "(several GB on first run)" + podman pull {{image}} + + mkdir -p "$HOME/.local/bin" "$HOME/.config/hypercube/nvim/lua/plugins" + install -m 0755 {{wrapper}} "$HOME/.local/bin/devc" + + echo "" + echo "Setup complete! Run 'devc' for the parallel-agent workspace (workmux)," + echo "or 'devc nvim' / 'devc claude' / 'devc codex' / 'devc agy' / 'devc zellij'" + echo "to launch a single tool." + echo "Personal nvim overrides go in: ~/.config/hypercube/nvim/lua/plugins/" + +# Pull the latest image and refresh the wrapper +devcube-upgrade: + #!/usr/bin/bash + set -euo pipefail + + echo "Pulling latest devcube image..." + podman pull {{image}} + install -m 0755 {{wrapper}} "$HOME/.local/bin/devc" + + echo "Done!" + echo "Tip: run ':Lazy update' inside nvim to update plugins. Baked config" + echo "updates (zellij/workmux/fish) only apply to a fresh home volume — run" + echo "'ujust devcube-reset' to re-seed (this clears AI logins)." + +# Reset persisted state so the next launch re-seeds from the image. +# WARNING: removes plugin state, sessions, AND AI CLI logins stored in the volume. +devcube-reset: + #!/usr/bin/bash + set -euo pipefail + + read -p "Remove the {{volume}} volume (plugin state + AI logins)? [y/N] " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + podman volume rm -f {{volume}} 2>/dev/null || true + echo "Volume removed. The next 'devc' launch will re-seed from the image." + fi + + read -p "Also remove ALL per-project worktree volumes (devcube-wt-*)? [y/N] " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + podman volume ls -q | grep '^devcube-wt-' | xargs -r podman volume rm -f + echo "Worktree volumes removed." + else + echo "Kept per-project worktree volumes." + fi + +# Open a debug shell inside a throwaway devcube container +devcube-shell: + #!/usr/bin/bash + set -euo pipefail + exec podman run --rm -it --init \ + --user 0:0 --security-opt label=disable \ + -e DEVCUBE=1 -e TERM \ + -v {{volume}}:/root \ + -v "$(pwd):$(pwd):rw" -w "$(pwd)" \ + {{image}} bash diff --git a/system_files/shared/usr/share/ublue-os/just/61-nvim.just b/system_files/shared/usr/share/ublue-os/just/61-nvim.just deleted file mode 100644 index 8c5640b..0000000 --- a/system_files/shared/usr/share/ublue-os/just/61-nvim.just +++ /dev/null @@ -1,75 +0,0 @@ -# vim: set ft=make : -# Hypercube AI-first Neovim sandbox commands -# -# The editor and AI agents (Claude Code, Codex, Antigravity, gh) ship as a -# single portable podman image. A thin wrapper at ~/.local/bin/nvim runs it; -# the same wrapper is symlinked to claude/codex/agy so you can launch an agent -# directly (they share the image's home volume, so logins are shared too). -# Personal plugin overrides live in ~/.config/hypercube/nvim/lua/plugins/. - -image := "ghcr.io/binarypie-dev/nvim-dev:latest" -wrapper := "/usr/share/hypercube/config/nvim/scripts/sandbox.sh" -volume := "hypercube-nvim-home" - -# Pull the image and install the nvim + agent wrappers to ~/.local/bin -nvim-setup: - #!/usr/bin/bash - set -euo pipefail - - echo "Pulling Neovim sandbox image ({{image}})..." - echo "(several GB on first run)" - podman pull {{image}} - - mkdir -p "$HOME/.local/bin" "$HOME/.config/hypercube/nvim/lua/plugins" - install -m 0755 {{wrapper}} "$HOME/.local/bin/nvim" - # The wrapper dispatches on the name it's invoked as; symlink the agents to it. - for agent in claude codex agy; do - ln -sf nvim "$HOME/.local/bin/$agent" - done - - echo "" - echo "Setup complete! Run 'nvim' to launch the AI-first editor," - echo "or 'claude' / 'codex' / 'agy' to run an agent directly." - echo "Personal overrides go in: ~/.config/hypercube/nvim/lua/plugins/" - -# Pull the latest image and refresh the wrappers -nvim-upgrade: - #!/usr/bin/bash - set -euo pipefail - - echo "Pulling latest Neovim sandbox image..." - podman pull {{image}} - install -m 0755 {{wrapper}} "$HOME/.local/bin/nvim" - for agent in claude codex agy; do - ln -sf nvim "$HOME/.local/bin/$agent" - done - - echo "Done!" - echo "Tip: run ':Lazy update' inside nvim to update plugins, or" - echo "'ujust nvim-reset' to re-seed plugins from the new image." - -# Reset persisted state so the next launch re-seeds from the image. -# WARNING: removes plugin state, sessions, AND AI CLI logins stored in the volume. -nvim-reset: - #!/usr/bin/bash - set -euo pipefail - - read -p "Remove the {{volume}} volume (plugin state + AI logins)? [y/N] " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - podman volume rm -f {{volume}} 2>/dev/null || true - echo "Volume removed. The next 'nvim' launch will re-seed from the image." - else - echo "Cancelled." - fi - -# Open a debug shell inside a throwaway sandbox container -nvim-shell: - #!/usr/bin/bash - set -euo pipefail - exec podman run --rm -it --init \ - --user 0:0 --security-opt label=disable \ - -e HYPERCUBE_NVIM=1 -e TERM \ - -v {{volume}}:/root \ - -v "$(pwd):$(pwd):rw" -w "$(pwd)" \ - {{image}} bash diff --git a/system_files/shared/usr/share/ublue-os/justfile b/system_files/shared/usr/share/ublue-os/justfile index f1446be..2383c95 100644 --- a/system_files/shared/usr/share/ublue-os/justfile +++ b/system_files/shared/usr/share/ublue-os/justfile @@ -25,6 +25,6 @@ import "/usr/share/ublue-os/just/50-akmods.just" # Hypercube commands # ============================================================================= import? "/usr/share/ublue-os/just/60-hypercube.just" -import? "/usr/share/ublue-os/just/61-nvim.just" +import? "/usr/share/ublue-os/just/61-devcube.just" import? "/usr/share/ublue-os/just/63-migrate.just"