No description
Find a file
2026-09-04 22:45:06 +02:00
assistants Update assistant rules for workstation operations 2026-09-04 22:44:34 +02:00
docs Add LLM development roadmap 2026-07-27 19:44:37 +00:00
home Replace code-server and T3 with the native Debian workstation 2026-09-04 22:44:55 +02:00
host Install Graphify and its assistant skills with pipx 2026-09-04 22:45:06 +02:00
scripts Install Graphify and its assistant skills with pipx 2026-09-04 22:45:06 +02:00
.gitignore Initialize ai-development workstation configuration 2026-07-12 22:19:59 +02:00
AGENTS.md Replace code-server and T3 with the native Debian workstation 2026-09-04 22:44:55 +02:00
README.md Install Graphify and its assistant skills with pipx 2026-09-04 22:45:06 +02:00

AI development workstation

Reproducible configuration for the browser development workstation. Projects live on a TrueNAS NFS export mounted at /mnt/data. Persistent Codex and Claude Code sessions run inside tmux.

Layout

assistants/
  claude/             Claude Code global instructions and status line
  codex/              Codex global instructions
home/
  bin/                Agent notification, clipboard, and session helpers
  bash/               Interactive shell additions
  tmux/               tmux configuration
host/
  agents/             Host Node.js, Codex, and Claude Code installer
  development/        Host Go, Orca, and Docker Engine installer
  nfs/                VM-side NFS mount template
  desktop/            Native XFCE and GPU-accelerated Selkies desktop
scripts/
  install.sh           Install user configuration with backups
  verify.sh            Check commands, links, and the project mount

The repository intentionally does not track credentials, histories, logs, databases, ~/.codex/config.toml, or ~/.claude/settings.json. Those files mix authentication, per-machine trust, installed plugins, and mutable application state. Only durable instructions and workstation behavior belong here. The installer makes one targeted, idempotent edit to settings.json — pointing statusLine at the managed script — but never tracks or overwrites the file.

Current topology

The state reconciled on 2026-08-30 is:

  • Debian 13 VM on Proxmox node px03
  • dedicated Intel Iris Xe GPU through PCI passthrough
  • native XFCE X.Org desktop at https://code.home.step1.ro
  • workspace root at /mnt/data
  • NFSv4.2 source 192.168.20.20:/mnt/fast-pool/coding-vm
  • NFS ownership mapped to UID/GID 1000:1000
  • Node.js 24.20.0, Codex CLI 0.151.0, and Claude Code 2.1.251
  • Go 1.27.0, Orca 1.4.192, and Docker Engine 29.7.2 with Buildx and Compose
  • up to 8 GiB of compressed zram swap and the Europe/Vienna timezone
  • Selkies source pinned by commit under host/desktop/install.sh

The runtime versions are pins under host/agents/, host/development/, and host/desktop/.

Rebuild

Terraform and cloud-init create the VM, mount the workspace, and install the Intel firmware. The first boot then restarts before repository provisioning. The repository installs native XFCE, X.Org, Selkies, and the development tools. For a manual repair, start with the base host packages:

sudo apt update
sudo apt install ca-certificates curl firmware-intel-graphics git intel-media-va-driver-non-free jq linux-image-amd64 nfs-common qemu-guest-agent sudo

jq is used by the installer to wire the Claude Code status line into settings.json; without it the installer prints the block to add by hand.

Create /mnt/data, copy the entry from host/nfs/fstab.example into /etc/fstab, then mount and verify it before starting the desktop:

sudo mkdir -p /mnt/data
sudo mount /mnt/data
findmnt -T /mnt/data
touch /mnt/data/.write-test && rm /mnt/data/.write-test

The TrueNAS dataset and VM user must agree on UID/GID 1000:1000. Do not start the desktop against an unmounted /mnt/data. Projects could otherwise be written to the VM's local filesystem under the empty mount point.

Clone this repository anywhere on the mounted workspace and install the user configuration:

git clone ssh://git@git.step1.ro:2222/stanta/ai-development.git
cd ai-development
./scripts/install.sh
./scripts/verify.sh
sudo ./host/agents/install.sh
sudo ./host/development/install.sh
sudo ./host/desktop/install.sh

The installer creates symlinks for the managed files and installs pinned tmux-resurrect, tmux-yank, and tmux-continuum revisions under ~/.config/ai-development/tmux/plugins/. If a destination already exists, it is moved beside itself with a timestamped .pre-ai-development-* suffix. It adds one guarded source line to ~/.bashrc; it does not replace the distribution-provided file.

Restart Codex and Claude Code after changing their global instruction files.

host/agents/install.sh verifies the Node.js archive checksum. It installs the agent CLIs under /opt/agent-runtime/npm-global and links them through /usr/local/bin. Authentication and mutable agent state remain in /home/step/.codex and /home/step/.claude. The installer does not read or copy credentials.

host/development/install.sh verifies the Go and Orca download checksums. It installs the pinned Orca AppImage and XFCE launcher for step. It also installs the pinned Docker packages from Docker's signed Debian repository and adds step to the docker group. Start a new login session after the first install so the desktop inherits that group. Docker is available for development workloads; the native desktop and Selkies services do not depend on it.

The development installer also installs Debian's python3, python3-venv, and pipx. It installs graphifyy from the 0.9 release series in an isolated pipx environment for step, exposes graphify in ~/.cargo/bin, and registers its skills for Claude Code and Codex. Re-running the installer selects the newest patch in that series. Restart the assistants after installation.

To add these tools to an existing workstation, run sudo ./host/development/install.sh, then ./scripts/verify.sh as step. The custom homelab Graphify backend is not part of the upstream package or this repository. Its configuration and any custom backend code must be restored separately before using --backend homelab.

Browser desktop

XFCE runs as a native X.Org session on Debian. LightDM logs in the step user automatically. The passed-through Intel GPU is the primary X.Org device and drives the laptop panel. It also provides VAAPI encoding and accelerated OpenGL. The Proxmox console uses serial0, so recovery does not depend on the GPU. The installer discovers the Intel render node instead of relying on a fixed device number.

Traefik exposes only https://code.home.step1.ro and protects it with the normal homelab authentication middleware. Selkies listens on 192.168.20.205:3000. TLS terminates at Traefik, so browser clipboard, pointer lock, and file transfer APIs run in a secure browser context. Selkies supports text and image clipboard transfer plus uploads and downloads rooted at /mnt/data.

The desktop and agent tools run as the native step user. Authentication state remains in /home/step. Code and other durable data must remain under /mnt/data.

The Selkies launcher disables X11 screen blanking and display power management. The remote desktop therefore remains available after long idle periods.

Inspect the desktop with:

systemctl status lightdm selkies
journalctl -u selkies -n 100 --no-pager
vainfo --display drm --device /dev/dri/renderD128

Status line

assistants/claude/statusline-combined.sh renders the Claude Code status line by concatenating two plugin status lines onto a single row: the caveman mode indicator and claude-hud (context, path, usage, weekly). It reads the session JSON once from stdin and feeds it to each. Plugin paths are resolved from the cache at runtime, so the script survives plugin version bumps; a missing plugin is skipped rather than fatal.

The installer symlinks the script into ~/.claude/ and sets settings.json's statusLine.command to bash ~/.claude/statusline-combined.sh. The status line still depends on the caveman and claude-hud plugins being installed, which — like the rest of settings.json — is not tracked here.

tmux quick guide

Ctrl-b is the tmux prefix: press it, release it, then press the next key. New agent sessions start with agent and shell tabs in the current directory.

Action Command or keys Result
Start Codex cdev or cdev -s NAME Create or attach to a Codex session.
Start Claude ccdev or ccdev -s NAME Create or attach to a Claude session.
List work dagents Show sessions and tabs, with attention states first.
Pick session dattach or Ctrl-b f Open the fzf session picker.
Detach Ctrl-b d Leave the session running in the background.
New tab Ctrl-b c Create a tab in the current directory.
Change tab Alt-1 to Alt-9, or Ctrl-b n / Ctrl-b p Select a numbered, next, or previous tab.
Split left/right Ctrl-b, then the vertical bar key Create a pane beside the current pane.
Split top/bottom Ctrl-b - Create a pane below the current pane.
Change pane Ctrl-b then an arrow key Focus an adjacent pane.
Close pane Ctrl-b x, then y Remove the current pane. exit alone leaves an EXITED pane.
Zoom pane Ctrl-b z Toggle the current pane between full-screen and tiled.
Copy text Ctrl-b [, select text, then y Copy through tmux-yank to the browser clipboard.
Clear alert Ctrl-b a Clear APPROVAL, DONE, or FAILED from the tab.
Save layout Ctrl-b Ctrl-s Save sessions, tabs, panes, and working directories.
Restore layout Ctrl-b Ctrl-r Restore the last saved tmux layout.
Full help dhelp Show all managed commands and bindings.

The top bar shows tabs and attention states: APPROVAL, DONE, FAILED, and EXITED.

Codex turn completion and approval events and Claude notification, stop, and failure hooks feed agent-notify. The helper updates tmux, rings the terminal bell, and can publish a generic message to a self-hosted ntfy endpoint. To enable ntfy without tracking its token:

cp ~/.config/ai-development/notifications.env.example \
  ~/.config/ai-development/notifications.env
chmod 600 ~/.config/ai-development/notifications.env
# Edit NTFY_URL, NTFY_TOPIC, and optionally NTFY_TOKEN.

Notifications contain only the agent name, tmux session/tab, and repository basename. Prompt and response text is never forwarded.

tmux-yank uses OSC 52 to write to the connected client clipboard. Ctrl-b y copies the current command line and Ctrl-b Y copies the pane working directory.

Tmux layouts are saved every 15 minutes and restored after the tmux server restarts. Pane contents are deliberately excluded because they may contain source or secrets. Restoring a layout does not resume an AI conversation; use codex resume or claude --resume explicitly in the restored agent tab.

ccdev preserves the current workstation behavior and launches Claude Code with --dangerously-skip-permissions. Use it only inside the isolated development environment.