Compare commits
No commits in common. "v2.0" and "main" have entirely different histories.
14
.env.example
14
.env.example
@ -1,14 +0,0 @@
|
|||||||
# Copy to .env (gitignored). Source recommended:
|
|
||||||
# echo "UID=$(id -u)" > .env
|
|
||||||
# echo "GID=$(id -g)" >> .env
|
|
||||||
|
|
||||||
# Match host UID/GID for /workspace permissions
|
|
||||||
UID=1000
|
|
||||||
GID=1000
|
|
||||||
|
|
||||||
# Set MOBILE=1 to activate mobile-optimized prompt + screen autoattach
|
|
||||||
MOBILE=0
|
|
||||||
|
|
||||||
# Git identity used inside the container
|
|
||||||
GIT_NAME=Your Name
|
|
||||||
GIT_EMAIL=you@example.com
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
# Environment / secrets
|
# Environment / secrets
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.*
|
||||||
.env.*.local
|
|
||||||
!.env.example
|
!.env.example
|
||||||
|
|
||||||
# Editor
|
# Editor
|
||||||
|
|||||||
153
CLAUDE.md
153
CLAUDE.md
@ -1,153 +0,0 @@
|
|||||||
# arch-dev — Project Context for Claude Code
|
|
||||||
|
|
||||||
## What this is
|
|
||||||
A portable, stateless Arch Linux development environment running in Docker.
|
|
||||||
Headless, riced, mobile-aware. Built for serious dev work from any box —
|
|
||||||
including from a phone via Termius.
|
|
||||||
|
|
||||||
The tagline that stuck: **"Riced Neovim IDE"**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Human
|
|
||||||
|
|
||||||
Wayne. Works primarily from mobile (Android + Termius).
|
|
||||||
Prefers vim keybindings everywhere. Wants things clean and professional —
|
|
||||||
"Apple good" was the benchmark set early on. Doesn't want walls of text.
|
|
||||||
Will call you out if you guess instead of reading docs.
|
|
||||||
Has a Gitea instance at https://code.waynehayesdevelopment.com
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
arch-dev/
|
|
||||||
├── Dockerfile # Arch rolling release, pacman + AUR (yay)
|
|
||||||
├── docker-compose.yml # Named volume for stateful /home/dev
|
|
||||||
├── entrypoint.sh # First-run seeding + dotfile update detection
|
|
||||||
├── .gitignore
|
|
||||||
├── workspace/ # Bind mount — host-visible project files
|
|
||||||
└── dotfiles/ # Baked into /etc/skel-arch-dev/ in image
|
|
||||||
├── .zshrc # 256-color only, mobile detection, snapshot fns
|
|
||||||
├── .aliases
|
|
||||||
├── .screenrc # Mobile multiplexer
|
|
||||||
├── .config/
|
|
||||||
│ ├── starship.toml # Desktop: 256-color Kanagawa Wave approx
|
|
||||||
│ ├── starship-mobile.toml # Mobile: single line, no icons
|
|
||||||
│ ├── tmux/tmux.conf # Desktop mux, Ctrl+Space prefix
|
|
||||||
│ └── nvim/ # Full LSP/lint/format setup
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Stateful Home System (v1.7)
|
|
||||||
|
|
||||||
`/home/dev` is a **named Docker volume** (`arch-dev-home`). Persists across
|
|
||||||
`--rm` container exits. NOT wiped on exit — only on `docker volume rm`.
|
|
||||||
|
|
||||||
On first run, entrypoint seeds the volume from `/etc/skel-arch-dev/`
|
|
||||||
(baked into the image). Subsequent runs detect if image dotfiles are newer
|
|
||||||
and auto-update (with auto-snapshot first).
|
|
||||||
|
|
||||||
### Git-backed snapshots
|
|
||||||
|
|
||||||
`~/.arch-dev-state/` is a separate-git-dir tracking `/home/dev`.
|
|
||||||
No `.git` folder in `~` — avoids nested git conflicts with project repos.
|
|
||||||
|
|
||||||
Shell functions (defined in .zshrc):
|
|
||||||
- `snapshot <name> [msg]` / `snap` — tag current state
|
|
||||||
- `snapshots` / `snaps` — list tags + recent commits
|
|
||||||
- `rollback <name>` / `snapr` — reset to tag (confirms first, auto-snaps)
|
|
||||||
- `diff-state` / `snapd` — what's changed since last commit
|
|
||||||
- `show-snapshot <name>` — inspect a tag
|
|
||||||
- `unsnapshot <name>` — delete a tag
|
|
||||||
- `_archdev_git` — raw git wrapper (separate git dir)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Color Problem (solved in v1.4+)
|
|
||||||
|
|
||||||
Termius on Android cannot render truecolor RGB escape codes.
|
|
||||||
They show as **purple/magenta backgrounds** on everything.
|
|
||||||
|
|
||||||
**Rules:**
|
|
||||||
- No `COLORTERM=truecolor` in compose or shell
|
|
||||||
- No hex colors (`#7E9CD8`) in starship, zsh-syntax-highlighting, tmux
|
|
||||||
- All shell-visible configs use 256-color ANSI codes (`fg=110` etc.)
|
|
||||||
- `termguicolors` in neovim is conditional: `vim.env.MOBILE ~= "1"`
|
|
||||||
- Mobile colorscheme: `habamax` (built-in, 256-color clean)
|
|
||||||
- Desktop colorscheme: `kanagawa-wave` (needs termguicolors)
|
|
||||||
- Bufferline disabled on mobile (emits RGB for tab backgrounds)
|
|
||||||
- noice.nvim removed entirely (bled colors into terminal)
|
|
||||||
|
|
||||||
**Kanagawa Wave 256-color approximations:**
|
|
||||||
```
|
|
||||||
110 = crystalBlue 106 = springGreen 139 = oniViolet
|
|
||||||
173 = boatYellow 167 = peachRed 66 = waveAqua
|
|
||||||
242 = fujiGray 250 = fujiWhite 236 = waveBlue
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Mobile Detection
|
|
||||||
|
|
||||||
`MOBILE=1` env var (set in Termius host profile) activates:
|
|
||||||
- Minimal single-line starship prompt (no icons)
|
|
||||||
- screen auto-attach instead of tmux
|
|
||||||
- habamax colorscheme in neovim
|
|
||||||
- termguicolors disabled
|
|
||||||
- Bufferline disabled
|
|
||||||
- Compact aliases (`g` for git, etc.)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Plugin API Changes (hard-won knowledge)
|
|
||||||
|
|
||||||
Every one of these bit us. Read docs before touching:
|
|
||||||
|
|
||||||
| Plugin | Issue | Fix |
|
|
||||||
|--------|-------|-----|
|
|
||||||
| `leap.nvim` | Moved GitHub→Codeberg | `url = "https://codeberg.org/andyg/leap.nvim"` |
|
|
||||||
| `leap.nvim` | `add_default_mappings()` removed | Use `<Plug>(leap)` keymaps directly |
|
|
||||||
| `nvim-treesitter` | `.configs` module gone | `require("nvim-treesitter").setup{}`, `branch="main"`, `lazy=false` |
|
|
||||||
| `nvim-surround` | v4 removed `keymaps` table | `require("nvim-surround").setup()` defaults only |
|
|
||||||
| `nvim-lspconfig` | Framework deprecated in 0.11 | `vim.lsp.config()` + `vim.lsp.enable()` |
|
|
||||||
| `vim.lsp.with()` | Deprecated | Handlers in `vim.lsp.config("*", { handlers = {} })` |
|
|
||||||
| `on_attach` | Old pattern | `LspAttach` autocmd |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What's NOT in v1 (coming in v2)
|
|
||||||
|
|
||||||
- nvm + nodejs
|
|
||||||
- Claude CLI
|
|
||||||
- Gemini CLI
|
|
||||||
- Aider
|
|
||||||
- nvim AI plugin (copilot/avante/codecompanion)
|
|
||||||
|
|
||||||
v2 plan: install AI tools in the stateful container, snapshot as `ai-tools`,
|
|
||||||
then layer nodejs on top.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Git / Repo
|
|
||||||
|
|
||||||
- Gitea: https://code.waynehayesdevelopment.com/wayne/neovim-ide
|
|
||||||
- `main` branch = current stable (v1.7)
|
|
||||||
- `v2` branch = active development
|
|
||||||
- `v1.7` tag = frozen reference
|
|
||||||
|
|
||||||
Wayne is new to multi-branch git workflow — be explicit about which branch
|
|
||||||
to be on before any git operations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Tone / Style Notes
|
|
||||||
|
|
||||||
- Short responses. Wayne reads on mobile.
|
|
||||||
- No bullet-point walls. Prose or tight tables.
|
|
||||||
- Don't guess at APIs — fetch the docs first.
|
|
||||||
- When something breaks, ask for the actual error before debugging.
|
|
||||||
- Wayne will test each version and report back with screenshots.
|
|
||||||
- "Apple good" is the visual quality bar.
|
|
||||||
37
Dockerfile
37
Dockerfile
@ -1,11 +1,5 @@
|
|||||||
FROM archlinux:latest
|
FROM archlinux:latest
|
||||||
|
|
||||||
# ── Build args: UID/GID matching for clean /workspace permissions ─────────────
|
|
||||||
# Override at build: UID=$(id -u) GID=$(id -g) docker compose build
|
|
||||||
# Or set in .env file
|
|
||||||
ARG USER_UID=1000
|
|
||||||
ARG USER_GID=1000
|
|
||||||
|
|
||||||
# ── Rolling release: full system update first, always ─────────────────────────
|
# ── Rolling release: full system update first, always ─────────────────────────
|
||||||
RUN pacman -Syu --noconfirm
|
RUN pacman -Syu --noconfirm
|
||||||
|
|
||||||
@ -30,10 +24,6 @@ RUN pacman -S --noconfirm --needed \
|
|||||||
man-db man-pages \
|
man-db man-pages \
|
||||||
jq tree wget \
|
jq tree wget \
|
||||||
rsync \
|
rsync \
|
||||||
imagemagick chafa jp2a \
|
|
||||||
go \
|
|
||||||
github-cli \
|
|
||||||
libnewt \
|
|
||||||
&& pacman -Scc --noconfirm
|
&& pacman -Scc --noconfirm
|
||||||
|
|
||||||
# ── Crown Jewel #2: AUR ───────────────────────────────────────────────────────
|
# ── Crown Jewel #2: AUR ───────────────────────────────────────────────────────
|
||||||
@ -51,41 +41,24 @@ RUN sudo -u aurbuild yay -S --noconfirm --needed \
|
|||||||
eza \
|
eza \
|
||||||
wl-clipboard \
|
wl-clipboard \
|
||||||
trash-cli \
|
trash-cli \
|
||||||
tailscale \
|
|
||||||
&& sudo -u aurbuild yay -Scc --noconfirm
|
&& sudo -u aurbuild yay -Scc --noconfirm
|
||||||
|
|
||||||
# ── Dev user with host-matching UID/GID ───────────────────────────────────────
|
# ── Dev user ──────────────────────────────────────────────────────────────────
|
||||||
# UID/GID match host so /workspace bind mount has clean permissions both sides
|
RUN useradd -m -s /bin/zsh -G wheel dev && \
|
||||||
RUN groupadd -g ${USER_GID} dev && \
|
|
||||||
useradd -m -s /bin/zsh -u ${USER_UID} -g ${USER_GID} -G wheel dev && \
|
|
||||||
echo 'dev ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/dev
|
echo 'dev ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/dev
|
||||||
|
|
||||||
# ── Skeleton: bake dotfiles into /etc/skel-arch-dev/ ──────────────────────────
|
# ── Skeleton: bake dotfiles into /etc/skel-arch-dev/ ──────────────────────────
|
||||||
|
# This is the SOURCE OF TRUTH. The volume gets seeded from here on first run.
|
||||||
COPY --chown=dev:dev dotfiles/ /etc/skel-arch-dev/
|
COPY --chown=dev:dev dotfiles/ /etc/skel-arch-dev/
|
||||||
|
|
||||||
# ── Initial seed of /home/dev so plugin bake works at build time ──────────────
|
# ── Initial seed of /home/dev so plugin bake works at build time ──────────────
|
||||||
RUN cp -an /etc/skel-arch-dev/. /home/dev/ && \
|
RUN cp -an /etc/skel-arch-dev/. /home/dev/ && \
|
||||||
chown -R dev:dev /home/dev
|
chown -R dev:dev /home/dev
|
||||||
|
|
||||||
# ── nvm + LTS Node (as dev user) ──────────────────────────────────────────────
|
|
||||||
# nvm install script writes to ~/.zshrc — we sandbox it then merge cleanly
|
|
||||||
RUN sudo -u dev bash -c '\
|
|
||||||
export PROFILE=/dev/null && \
|
|
||||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash && \
|
|
||||||
export NVM_DIR="/home/dev/.nvm" && \
|
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && \
|
|
||||||
nvm install --lts && \
|
|
||||||
nvm alias default node \
|
|
||||||
'
|
|
||||||
|
|
||||||
# Persist nvm install into the skel template so volume seeding includes it
|
|
||||||
RUN cp -an /home/dev/.nvm /etc/skel-arch-dev/ && \
|
|
||||||
chown -R dev:dev /etc/skel-arch-dev/.nvm
|
|
||||||
|
|
||||||
# ── Python tools ──────────────────────────────────────────────────────────────
|
# ── Python tools ──────────────────────────────────────────────────────────────
|
||||||
RUN pip install --break-system-packages pynvim httpx requests
|
RUN pip install --break-system-packages pynvim httpx requests
|
||||||
|
|
||||||
# ── Bake neovim plugins ───────────────────────────────────────────────────────
|
# ── Bake neovim plugins into /etc/skel-arch-dev so they seed too ─────────────
|
||||||
RUN sudo -u dev HOME=/home/dev XDG_DATA_HOME=/home/dev/.local/share \
|
RUN sudo -u dev HOME=/home/dev XDG_DATA_HOME=/home/dev/.local/share \
|
||||||
nvim --headless +"Lazy! sync" +qa 2>/dev/null; exit 0
|
nvim --headless +"Lazy! sync" +qa 2>/dev/null; exit 0
|
||||||
|
|
||||||
@ -94,7 +67,7 @@ RUN sudo -u dev HOME=/home/dev XDG_DATA_HOME=/home/dev/.local/share \
|
|||||||
+"TSUpdateSync python bash lua json yaml toml markdown vim vimdoc regex" \
|
+"TSUpdateSync python bash lua json yaml toml markdown vim vimdoc regex" \
|
||||||
+qa 2>/dev/null; exit 0
|
+qa 2>/dev/null; exit 0
|
||||||
|
|
||||||
# Copy fully-baked /home/dev back into the skel template
|
# Copy the fully-baked /home/dev back into the skel template
|
||||||
RUN cp -an /home/dev/.local /etc/skel-arch-dev/ && \
|
RUN cp -an /home/dev/.local /etc/skel-arch-dev/ && \
|
||||||
cp -an /home/dev/.cache /etc/skel-arch-dev/ 2>/dev/null || true && \
|
cp -an /home/dev/.cache /etc/skel-arch-dev/ 2>/dev/null || true && \
|
||||||
chown -R dev:dev /etc/skel-arch-dev
|
chown -R dev:dev /etc/skel-arch-dev
|
||||||
|
|||||||
205
README.md
205
README.md
@ -1,85 +1,62 @@
|
|||||||
# arch-dev
|
# arch-dev v1.7
|
||||||
### Riced Neovim IDE · Arch Linux · Stateful · Mobile-Aware
|
### Riced Neovim IDE · Arch Linux · Stateful · Mobile-Aware
|
||||||
|
|
||||||
> *"Like Gentoo without the compiling."*
|
> *"Like Gentoo without the compiling."*
|
||||||
> *I use Arch BTW*
|
> Kanagawa Wave · rolling release · AUR-powered · git-snapshotted home
|
||||||
|
|
||||||
Kanagawa Wave · rolling release · AUR-powered · git-snapshotted home
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Branches
|
## What's new in v1.7
|
||||||
|
|
||||||
| Branch | Purpose |
|
- **Stateful `/home/dev`** — your shell history, plugin state, and config tweaks survive container exit
|
||||||
|---|---|
|
- **Git-backed snapshot system** — commit good states, roll back when things break
|
||||||
| `main` | Latest stable |
|
- **Auto-snapshot on dotfile updates** — image upgrades preserve your history
|
||||||
| `v2` | Active development |
|
- **Mobile improvements** — bufferline disabled on mobile, dashboard uses thin-line ASCII
|
||||||
| `v1.7` (tag) | Frozen v1.7 reference |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What's new in v2.0
|
## The Snapshot System
|
||||||
|
|
||||||
- **Host UID/GID matching** — `/workspace` permissions just work, no more chowning
|
Your `/home/dev` is a git repo (state in `~/.arch-dev-state/`). When something works, snapshot it. When something breaks, roll back.
|
||||||
- **Tailscale** baked in (AUR) with `tun` device + `NET_ADMIN`/`NET_RAW`
|
|
||||||
- **Image tooling** — ImageMagick, chafa, jp2a
|
```bash
|
||||||
- **Go** — for go-based tooling
|
# Working state — save it
|
||||||
- **github-cli** (`gh`) — GitHub from terminal
|
snap node-working "NodeJS env with nvm + pnpm"
|
||||||
- **libnewt** — provides `whiptail` for shell TUI scripts (sysmenu)
|
|
||||||
- **nvm + LTS Node** — lazy-loaded, baked into skel template
|
# List your snapshots
|
||||||
- **Capabilities settled** — pacman/sudo/tailscale all working post-`cap_drop ALL`
|
snaps
|
||||||
|
|
||||||
|
# See what's changed since last snapshot
|
||||||
|
snapd
|
||||||
|
|
||||||
|
# Try something risky, breaks things... no problem
|
||||||
|
snapr node-working
|
||||||
|
|
||||||
|
# Show what's in a snapshot
|
||||||
|
show-snapshot node-working
|
||||||
|
|
||||||
|
# Remove a snapshot you don't need
|
||||||
|
unsnapshot old-thing
|
||||||
|
```
|
||||||
|
|
||||||
|
What's tracked: dotfiles, configs, neovim plugins, anything in `~`.
|
||||||
|
What's ignored: `.cache`, `.zsh_history`, build artifacts, log files.
|
||||||
|
|
||||||
|
Snapshots use real git so you can:
|
||||||
|
- Branch (`_archdev_git checkout -b experimenting`)
|
||||||
|
- Push to remote (`_archdev_git remote add origin git@...`)
|
||||||
|
- Diff between snapshots (`_archdev_git diff snap-a snap-b`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# First time: create .env with your UID/GID
|
|
||||||
cp .env.example .env
|
|
||||||
echo "UID=$(id -u)" >> .env
|
|
||||||
echo "GID=$(id -g)" >> .env
|
|
||||||
|
|
||||||
# Build (UID/GID picked up from .env)
|
|
||||||
docker compose build
|
docker compose build
|
||||||
|
|
||||||
# Run
|
|
||||||
docker compose run --rm arch-dev
|
docker compose run --rm arch-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
First run seeds `/home/dev` from the baked-in skeleton and creates a
|
First run seeds the home volume from a baked-in skeleton and creates a `skeleton` tag you can always roll back to.
|
||||||
`skeleton` snapshot you can always roll back to.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Snapshot System
|
|
||||||
|
|
||||||
Your home is a git repo (state in `~/.arch-dev-state/`). Save good states,
|
|
||||||
roll back when things break.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
snap claude-code "Claude Code installed and authed"
|
|
||||||
snaps # list snapshots
|
|
||||||
snapd # diff vs last snapshot
|
|
||||||
rollback claude-code # reset to snapshot
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Tailscale
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Inside container, first time:
|
|
||||||
sudo tailscaled &
|
|
||||||
sudo tailscale up # follow auth URL
|
|
||||||
snap tailscale "authenticated to tailnet"
|
|
||||||
```
|
|
||||||
|
|
||||||
After that, tailscale state persists in the named volume.
|
|
||||||
|
|
||||||
**Reminder learned the hard way**: Tailscale default-denies all tailnet
|
|
||||||
traffic. ACLs grant exceptions, not restrictions. Check ACLs FIRST when
|
|
||||||
peer connections fail silently. (Also: `tailscale ping <peer>` rules out
|
|
||||||
ACL issues before you start blaming nftables/routes.)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -88,84 +65,54 @@ ACL issues before you start blaming nftables/routes.)
|
|||||||
| Path | Type | Purpose |
|
| Path | Type | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `/workspace` | bind mount → `./workspace` | Project files, host-visible |
|
| `/workspace` | bind mount → `./workspace` | Project files, host-visible |
|
||||||
| `/home/dev` | named volume | Stateful user home |
|
| `/home/dev` | named volume `arch-dev-home` | Stateful user home, survives `--rm` |
|
||||||
| `/etc/skel-arch-dev/` | image layer | Read-only template |
|
| `/etc/skel-arch-dev/` | image layer | Read-only template, used to seed and update |
|
||||||
|
|
||||||
Reset home to factory: `docker volume rm <project>_arch-dev-home`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Container Capabilities
|
|
||||||
|
|
||||||
The container drops ALL capabilities then re-adds only what's needed:
|
|
||||||
|
|
||||||
| Cap | Why |
|
|
||||||
|---|---|
|
|
||||||
| `NET_BIND_SERVICE` | Bind to ports < 1024 (mosh) |
|
|
||||||
| `SETUID` / `SETGID` | sudo |
|
|
||||||
| `AUDIT_WRITE` | sudoers_audit plugin |
|
|
||||||
| `NET_ADMIN` / `NET_RAW` | Tailscale |
|
|
||||||
| `CHOWN` / `DAC_OVERRIDE` / `FOWNER` | pacman |
|
|
||||||
|
|
||||||
Plus device pass-through for `/dev/net/tun` (Tailscale kernel mode).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Multi-Window Workflow
|
|
||||||
|
|
||||||
`docker exec` does NOT inherit cap_add from compose — it gets default
|
|
||||||
capabilities. That means pacman/sudo work in the original `docker compose
|
|
||||||
run` window but not in `docker exec` windows.
|
|
||||||
|
|
||||||
**Best practice:** Use `tmux` inside the container for multiple panes.
|
|
||||||
All panes inherit the original session's full caps.
|
|
||||||
|
|
||||||
|
**Reset home to factory:**
|
||||||
```bash
|
```bash
|
||||||
tmux new -s work
|
docker volume rm arch-dev_arch-dev-home
|
||||||
# Ctrl+Space " split horizontal
|
docker compose run --rm arch-dev
|
||||||
# Ctrl+Space % split vertical
|
|
||||||
# Ctrl+Space d detach (container keeps running)
|
|
||||||
# tmux attach -t work
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Or roll back inside the container:**
|
||||||
|
```bash
|
||||||
|
rollback skeleton
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Image Updates
|
||||||
|
|
||||||
|
When you rebuild the image with new dotfiles:
|
||||||
|
|
||||||
|
1. Container starts, entrypoint compares image dotfiles to home
|
||||||
|
2. If image is newer, takes an auto-snapshot of current home
|
||||||
|
3. Updates dotfiles, leaving user data alone (history, project state)
|
||||||
|
4. You can `rollback` to the auto-snapshot if you don't like the new dotfiles
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known Caveats
|
||||||
|
|
||||||
|
- **AUR/pacman packages** are NOT in snapshots (they live in `/usr/`, not `~`)
|
||||||
|
- **Docker volume size** grows with snapshots — `_archdev_git gc` periodically
|
||||||
|
- First `snap` after major changes can take a few seconds (lots to hash)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Mobile (Termius)
|
## Mobile (Termius)
|
||||||
|
|
||||||
Set `MOBILE=1` in Termius host profile env vars to activate:
|
`MOBILE=1` activates:
|
||||||
- Single-line minimal starship prompt
|
- Minimal starship prompt
|
||||||
- Auto-attach screen on connect
|
- Auto-attach screen on connect
|
||||||
- habamax colorscheme (kanagawa needs truecolor)
|
- Bufferline disabled (was showing as purple bar)
|
||||||
- termguicolors disabled in neovim
|
- Habamax colorscheme (kanagawa needs truecolor which Termius mangles)
|
||||||
- Bufferline disabled
|
|
||||||
|
|
||||||
With Tailscale, you can reach arch-dev from any device on your tailnet
|
|
||||||
without exposing ports — perfect for mobile dev anywhere.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## State Tracking — Two Systems
|
## v2 Roadmap
|
||||||
|
|
||||||
| System | What | Where |
|
- nvm + nodejs (snapshot it after install!)
|
||||||
|---|---|---|
|
- gemini-cli for AI in the terminal
|
||||||
| **git on branch** | Dockerfile, dotfiles, build recipe | Gitea repo |
|
- copilot.nvim or avante.nvim
|
||||||
| **`snap` inside container** | Runtime state, installed tools, auth | Docker volume |
|
- nvim-dap (debugger)
|
||||||
|
|
||||||
Both required for full reproducibility — Dockerfile builds the OS,
|
|
||||||
snapshots restore the user state on top of it.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
|
|
||||||
### v2.1 (next)
|
|
||||||
- ASCIInator integration with chafa workflow refinement
|
|
||||||
- Custom neovim dashboard ASCII (using arch-dev's own logo)
|
|
||||||
|
|
||||||
### v2.2 (in design)
|
|
||||||
- Snapshot auto-push to remote (`snap` does `git push`, with override flag)
|
|
||||||
- Audit-clean .gitignore for credential paths
|
|
||||||
|
|
||||||
### v2.3+ (separate repos)
|
|
||||||
- **tailscale.nvim** — original FOSS neovim plugin for Tailscale interaction
|
|
||||||
- **ASCIInator** — image-to-ASCII tool
|
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
arch-dev:
|
arch-dev:
|
||||||
build:
|
build: .
|
||||||
context: .
|
|
||||||
args:
|
|
||||||
# Match host UID/GID for clean /workspace permissions
|
|
||||||
# Set via: UID=$(id -u) GID=$(id -g) docker compose build
|
|
||||||
# Or .env file in repo root
|
|
||||||
USER_UID: ${UID:-1000}
|
|
||||||
USER_GID: ${GID:-1000}
|
|
||||||
image: arch-dev:latest
|
image: arch-dev:latest
|
||||||
container_name: arch-dev
|
container_name: arch-dev
|
||||||
hostname: arch-dev
|
hostname: arch-dev
|
||||||
@ -15,11 +8,11 @@ services:
|
|||||||
tty: true
|
tty: true
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# Project files — bind mount, host-visible, host-UID-owned
|
# Project files — bind mount, host-visible
|
||||||
- ./workspace:/workspace
|
- ./workspace:/workspace
|
||||||
|
|
||||||
# Stateful home — named volume, survives --rm
|
# Stateful home — named volume, survives --rm
|
||||||
# Reset with: docker volume rm <project>_arch-dev-home
|
# Reset with: docker volume rm arch-dev_arch-dev-home
|
||||||
- arch-dev-home:/home/dev
|
- arch-dev-home:/home/dev
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@ -30,24 +23,10 @@ services:
|
|||||||
- GIT_COMMITTER_NAME=${GIT_NAME:-dev}
|
- GIT_COMMITTER_NAME=${GIT_NAME:-dev}
|
||||||
- GIT_COMMITTER_EMAIL=${GIT_EMAIL:-dev@localhost}
|
- GIT_COMMITTER_EMAIL=${GIT_EMAIL:-dev@localhost}
|
||||||
|
|
||||||
# Capability set built up through testing —
|
|
||||||
# cap_drop ALL then re-add only what's needed.
|
|
||||||
cap_drop:
|
cap_drop:
|
||||||
- ALL
|
- ALL
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_BIND_SERVICE # mosh, bind <1024
|
- NET_BIND_SERVICE
|
||||||
- SETUID # sudo
|
|
||||||
- SETGID # sudo
|
|
||||||
- AUDIT_WRITE # sudoers_audit plugin
|
|
||||||
- NET_ADMIN # tailscale
|
|
||||||
- NET_RAW # tailscale
|
|
||||||
- CHOWN # pacman temp dir ownership
|
|
||||||
- DAC_OVERRIDE # pacman lock files
|
|
||||||
- FOWNER # pacman package ownership
|
|
||||||
|
|
||||||
# Tailscale needs tun device for kernel-mode networking
|
|
||||||
devices:
|
|
||||||
- /dev/net/tun:/dev/net/tun
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
arch-dev-home:
|
arch-dev-home:
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
# ── nvm (added in v2.0) ───────────────────────────────────────────────────────
|
|
||||||
# Lazy-load nvm to keep shell startup fast
|
|
||||||
export NVM_DIR="$HOME/.nvm"
|
|
||||||
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
|
|
||||||
# Stub functions that load nvm on first use
|
|
||||||
nvm() {
|
|
||||||
unset -f nvm node npm npx
|
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
||||||
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
|
|
||||||
nvm "$@"
|
|
||||||
}
|
|
||||||
node() {
|
|
||||||
unset -f nvm node npm npx
|
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
||||||
node "$@"
|
|
||||||
}
|
|
||||||
npm() {
|
|
||||||
unset -f nvm node npm npx
|
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
||||||
npm "$@"
|
|
||||||
}
|
|
||||||
npx() {
|
|
||||||
unset -f nvm node npm npx
|
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
||||||
npx "$@"
|
|
||||||
}
|
|
||||||
# Add default node bin to PATH so node-installed CLIs work without lazy trigger
|
|
||||||
if [[ -d "$NVM_DIR/alias" ]] && [[ -f "$NVM_DIR/alias/default" ]]; then
|
|
||||||
DEFAULT_NODE="$(cat "$NVM_DIR/alias/default" 2>/dev/null)"
|
|
||||||
[[ -d "$NVM_DIR/versions/node/v$DEFAULT_NODE/bin" ]] && \
|
|
||||||
PATH="$NVM_DIR/versions/node/v$DEFAULT_NODE/bin:$PATH"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
Loading…
Reference in New Issue
Block a user