clawdie-iso/ADMIN-PANEL.md
Sam & Claude 1bffa175c8 Unify ISO and fix GPU installation gap (Sam & ZAI)
BREAKING CHANGE: Removes --target and --gpu-driver flags, unified ISO for all use cases

## Phase 0: GPU Fix + Unified ISO

### Core Changes

**GPU Package Installation (FIXES CRITICAL GAP):**
- Add clawdie_shell_nvidia_install() function to shell-nvidia.sh
- NVIDIA drivers now installed after detection (previously only configured)
- Works offline (USB packages) or online (pkg install)
- Resolves issue where rc.conf was set but driver not installed

**Unified ISO Architecture:**
- Remove --target flag from build.sh (no more vps/baremetal branching)
- Remove --gpu-driver flag from build.sh (runtime detection instead)
- All packages included on every ISO (desktop + all GPU drivers)
- Single image works on VPS, baremetal, and cloud

**Runtime Detection:**
- Add shell-desktop.sh for display detection at firstboot
- VPS/cloud: no display → lightdm disabled (headless)
- Baremetal: display detected → lightdm enabled (Lumina desktop)
- GPU detection always runs, installs correct driver version

**Sudo Unification:**
- Replace all doas references with sudo across entire codebase
- Update AGENTS.md with system configuration guidelines
- Update all documentation (BUILD.md, README.md, REQUIREMENTS.md, etc.)
- Admin panel now uses sudo for privileged operations

### Files Modified

**Core System:**
- build.sh: Remove target/gpu-driver logic, unified package selection
- firstboot/firstboot.sh: Add desktop detection module
- firstboot/shell-nvidia.sh: Add package installation function (+33 lines)

**New Files:**
- firstboot/shell-desktop.sh: Display detection and desktop enablement
- packages/pkg-list-nvidia-all.txt: All three NVIDIA driver versions (390/470/590)
- .opencode/plans/phase0-gpu-fix-unified-iso.md: Implementation plan

**Documentation:**
- PLAN-UNIFY.md: Update Step 3 for unified approach
- REQUIREMENTS.md: Simplify (no target choice), update for sudo
- BUILD.md: Update for unified ISO, sudo commands
- README.md: Update installation instructions
- AGENTS.md: Add system configuration section (sudo standardization)
- ADMIN-PANEL.md: Update privileged operations to use sudo
- CLAWDIE-SHELL.md: Update example commands to sudo
- CLAWDIE-ISO-REFACTORED.md: Update access paths to sudo
- REFACTOR-SUMMARY.md: Update permissions section to sudo

### Benefits

**Simplicity:**
- One build command: ./build.sh (no flags needed)
- One ISO to test and maintain
- No wrong choices for users
- No documentation explaining target differences

**Flexibility:**
- VPS can use GUI via VNC (wayvnc always available)
- Baremetal can run headless (disable lightdm)
- Repurpose hardware without reinstall
- All GPU drivers available for any hardware

**Technical:**
- Fixes critical GPU driver installation gap
- Runtime detection replaces build-time decisions
- Disk overhead: ~650MB (1-2% of 50GB - acceptable)
- No runtime overhead on VPS (services disabled by detection)

### Testing Required

- [ ] Build unified ISO: ./build.sh
- [ ] Test on VPS (no display): lightdm disabled, packages installed
- [ ] Test on baremetal (display): lightdm enabled, Lumina boots
- [ ] Test on NVIDIA hardware: driver installed and loaded
- [ ] Test sudo commands work without password prompts
- [ ] Verify all doas references removed
2026-06-04 20:04:22 +02:00

22 KiB

Clawdie Admin Panel — System Management UI

Purpose: bsddialog-based system administration interface for Lumina desktop users

Philosophy: Pure shell + bsddialog (no external GUI toolkits), inspired by PC-BSD warden's CLI approach


Overview

clawdie-admin is a lightweight terminal UI that lets users manage:

  • Clawdie service — start/stop, view status
  • Jails — list, start/stop, open console (jexec)
  • ZFS snapshots — create, list, restore (inspired by Life-Preserver)
  • System health — CPU, RAM, disk usage, pool status
  • Logs — tail service and jail logs
  • Configuration — change assistant name, timezone, LLM provider

Entry Points

1. Lumina Panel Applet (Right-click)

Right-click system tray
  └─ "Clawdie Admin"
      └─ Launches /usr/local/bin/clawdie-admin

2. CLI (Terminal)

$ clawdie-admin
# Opens interactive menu

3. Desktop Launcher

Double-click ~/.local/share/applications/clawdie-admin.desktop in Lumina file manager.


Menu Structure

Main Menu

┌─ Clawdie Admin Panel ──────────────────────────────────────┐
│                                                             │
│  Quick Status                                               │
│  ├─ Clawdie service:    ✓ Running (pid 42315)              │
│  ├─ ZFS pool (zroot):   15.2 GB / 100 GB (15% used)        │
│  ├─ Memory:             2.3 GB / 8.0 GB (29%)              │
│  ├─ CPU Load:           0.24 (1 min avg)                   │
│  ├─ Audio:              ✓ OSS (Intel HDA)                  │
│  └─ Network:            ✓ em0 (DHCP, 192.168.1.100)        │
│                                                             │
│  [  System Health  ]  [  Jails  ]  [  Snapshots  ]          │
│  [  Hardware  ]       [  Config  ]  [  Quit  ]              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

System Health Submenu

┌─ System Health ────────────────────────────────────────┐
│                                                        │
│  CPU  Load                                             │
│  │   1-min: 0.24                                      │
│  │   5-min: 0.18                                      │
│  │   15-min: 0.12                                     │
│  │                                                    │
│  Memory Usage                                         │
│  │   Used: 2.3 GB                                     │
│  │   Free: 5.7 GB                                     │
│  │   Cache: 0.8 GB                                    │
│  │                                                    │
│  ZFS Pool: zroot                                      │
│  │   Used: 15.2 GB                                    │
│  │   Free: 84.8 GB                                    │
│  │   Pool health: ✓ ONLINE                            │
│  │                                                    │
│  Clawdie Service                                      │
│  │   Status: ✓ Running                                │
│  │   PID: 42315                                       │
│  │   Memory: 145 MB                                   │
│  │                                                    │
│  [  Back  ]                                            │
│                                                        │
└────────────────────────────────────────────────────────┘

Hardware Submenu

┌─ Hardware Detection ───────────────────────────────────────┐
│                                                            │
│  Audio Card                                                │
│  │   Device: Intel HDA (pci0:27:0:0)                      │
│  │   Status: ✓ Working (OSS)                              │
│  │   Mixer: /dev/mixer0                                   │
│  │                                                         │
│  Network Interfaces                                        │
│  │   em0: Ethernet (DHCP) — 192.168.1.100                │
│  │   re0: Ethernet (not configured)                       │
│  │   Wireless: None detected                              │
│  │   Note: WiFi firmware can be installed post-boot       │
│  │                                                         │
│  Other Devices                                             │
│  │   USB: 3 devices detected                              │
│  │   Bluetooth: Not found (optional feature, v1.0+)       │
│  │                                                         │
│  [  Configure Audio  ]  [  Network Setup  ]  [  Back  ]    │
│                                                            │
└────────────────────────────────────────────────────────────┘

Post-Install Suggestions:

If WiFi detected but no firmware:

⚠️ WiFi Device Detected: Intel AC 8260
→ Install firmware: sudo pkg install iwm-firmware-8260
→ Then restart: sudo service netif restart

If audio not working:

⚠️ No audio output detected
→ Check: cat /dev/sndstat
→ Install: pkg install snd-hda-generic (for Intel/AMD)
→ Install: pkg install snd-usb-audio (for USB headsets)

Jails Submenu

┌─ Clawdie Jails ────────────────────────────────────────┐
│                                                        │
│  (N) Name      Status     Process Count   IP Address  │
│  1) worker     Running    4               10.0.0.101  │
│  2) db         Running    ✓ Healthy       10.0.0.102  │
│  3) cms        Running    ✓ Ready         10.0.0.103  │
│  4) mgmt       Stopped    --              10.0.0.104  │
│                                                        │
│  Manage jail:                                          │
│  [  Boot All  ]  [  Stop All  ]  [  Back  ]            │
│                                                        │
│  Select jail number (1-4) to manage:                  │
│  >_                                                    │
│                                                        │
└────────────────────────────────────────────────────────┘

# After selecting jail (e.g., "1" for worker):

┌─ Jail: worker ──────────────────────────────────────────┐
│                                                         │
│  Status:       ✓ Running                               │
│  IPv4:         10.0.0.101                              │
│  PID:          42350                                   │
│  Memory:       234 MB                                  │
│                                                         │
│  [  Start  ]  [  Stop  ]  [  Restart  ]                │
│  [  Console (jexec)  ]  [  Back  ]                     │
│                                                         │
└─────────────────────────────────────────────────────────┘

Snapshots Submenu

┌─ ZFS Snapshots ────────────────────────────────────────┐
│                                                        │
│  Snapshot Management                                   │
│  [  Create Snapshot  ]                                 │
│  [  List Snapshots  ]                                  │
│  [  Restore Snapshot  ]                                │
│                                                        │
│  Auto-Backup Status                                    │
│  │   Last backup: 2026-03-23 18:45 UTC                │
│  │   Interval: Daily at 02:00                         │
│  │   Retention: 7 days                                │
│  │   Status: ✓ Enabled                                │
│                                                        │
│  [  Back  ]                                            │
│                                                        │
└────────────────────────────────────────────────────────┘

# After selecting "List Snapshots":

┌─ ZFS Snapshots on zroot ──────────────────────────────┐
│                                                        │
│  Snapshot                    Created        Size       │
│  zroot@auto-2026-03-23       2026-03-23 02:00  2.3 GB  │
│  zroot@auto-2026-03-22       2026-03-22 02:00  2.1 GB  │
│  zroot@manual-20260323_1842  2026-03-23 18:42  1.8 GB  │
│  zroot@manual-20260323_1200  2026-03-23 12:00  1.7 GB  │
│                                                        │
│  Total snapshots: 4                                    │
│  Total space: 7.9 GB                                   │
│                                                        │
│  Select snapshot to restore: (or press Back)           │
│  >_                                                    │
│                                                        │
└────────────────────────────────────────────────────────┘

# After selecting snapshot:

┌─ Restore zroot@manual-20260323_1842 ──────────────────┐
│                                                        │
│  ⚠ WARNING: This will rollback ZFS to the snapshot     │
│  point. All changes since creation will be lost.       │
│                                                        │
│  Created:    2026-03-23 18:42 UTC                      │
│  Size:       1.8 GB                                    │
│  Systems affected: postgres, apps                      │
│                                                        │
│  [  Confirm Restore  ]  [  Cancel  ]                   │
│                                                        │
└────────────────────────────────────────────────────────┘

Logs Submenu

┌─ System Logs ──────────────────────────────────────────┐
│                                                        │
│  View logs from:                                       │
│  [  Clawdie Service (syslog)  ]                        │
│  [  Clawdie Service (stdout/stderr)  ]                 │
│  [  Worker Jail Console  ]                             │
│  [  Database Jail Console  ]                           │
│  [  System Messages (/var/log/messages)  ]             │
│                                                        │
│  [  Back  ]                                            │
│                                                        │
└────────────────────────────────────────────────────────┘

# After selecting log:

┌─ Clawdie Service Log (last 50 lines) ──────────────────┐
│                                                        │
│  [2026-03-23 23:15:22] Agent startup complete         │
│  [2026-03-23 23:15:21] Jails ready: worker, db, cms  │
│  [2026-03-23 23:15:18] PostgreSQL health check: OK    │
│  [2026-03-23 23:15:15] Nginx config validated         │
│  ...                                                   │
│  [2026-03-23 23:15:01] rc.d clawdie service start    │
│                                                        │
│  [  Refresh  ]  [  Tail (follow mode)  ]  [  Back  ]  │
│                                                        │
└────────────────────────────────────────────────────────┘

Config Submenu

┌─ Configuration ────────────────────────────────────────┐
│                                                        │
│  Current Settings                                      │
│  ├─ Assistant Name:  Clawdie                           │
│  ├─ Domain:         clawdie.local                      │
│  ├─ Timezone:       Europe/Ljubljana                   │
│  ├─ LLM Provider:   Anthropic                          │
│  └─ Telegram:       ✓ Configured                       │
│                                                        │
│  [  Change Assistant Name  ]                           │
│  [  Change Timezone  ]                                 │
│  [  Change LLM Provider  ]                             │
│  [  Export .env  ]                                     │
│  [  View .env (sensitive)  ]                           │
│  [  Back  ]                                            │
│                                                        │
└────────────────────────────────────────────────────────┘

Implementation (clawdie-admin.sh)

File Locations

/usr/local/bin/clawdie-admin           ← wrapper script (user-callable)
/usr/local/libexec/clawdie-admin.sh    ← main menu logic (sourced)
/usr/local/libexec/clawdie-lib-admin.sh ← helper functions (jail, snap, log ops)

Wrapper Script

#!/bin/sh
# /usr/local/bin/clawdie-admin

# Make sure we're running as clawdie user (or via sudo for root ops)
if [ "$(id -u)" != 1001 ]; then
  # If run as root, switch to clawdie user
  if [ "$(id -u)" = 0 ]; then
    exec su - clawdie -c "clawdie-admin"
  fi
  echo "Error: must run as clawdie user or root"
  exit 1
fi

# Source main menu
. /usr/local/libexec/clawdie-admin.sh

# Start menu
clawdie_admin_main_menu

Main Menu Function

#!/bin/sh
# /usr/local/libexec/clawdie-admin.sh

. /usr/local/libexec/clawdie-lib-admin.sh

clawdie_admin_main_menu() {
  while true; do
    # Refresh status each iteration
    STATUS=$(clawdie_admin_quick_status)

    CHOICE=$(bsddialog --title "Clawdie Admin Panel" \
      --menu "Quick Status:\n$STATUS" 20 70 0 \
      "1" "System Health" \
      "2" "Jails" \
      "3" "Snapshots" \
      "4" "Logs" \
      "5" "Configuration" \
      "0" "Quit" \
      2>&1 >/dev/tty)

    case $CHOICE in
      1) clawdie_admin_health ;;
      2) clawdie_admin_jails ;;
      3) clawdie_admin_snapshots ;;
      4) clawdie_admin_logs ;;
      5) clawdie_admin_config ;;
      0) break ;;
      *)  ;;
    esac
  done
}

clawdie_admin_quick_status() {
  # Returns 4-line status string for main menu display

  # Check if clawdie service running
  if service clawdie status > /dev/null 2>&1; then
    PID=$(service clawdie status | grep -oP 'pid \K\d+' || echo "?")
    SERVICE_STATUS="✓ Running (pid $PID)"
  else
    SERVICE_STATUS="✗ Stopped"
  fi

  # ZFS pool usage
  POOL_USAGE=$(zfs list -H -o used,available zroot 2>/dev/null | awk '{
    used = $1 / 1024 / 1024 / 1024
    avail = $2 / 1024 / 1024 / 1024
    total = used + avail
    pct = int(used / total * 100)
    printf "%.1f GB / %.1f GB (%d%%)", used, total, pct
  }')

  # Memory usage
  MEM=$(free -m | grep "^Mem:" | awk '{
    used = $3
    total = $2
    pct = int(used / total * 100)
    printf "%.1f GB / %.1f GB (%d%%)", used/1024, total/1024, pct
  }')

  # CPU load
  LOAD=$(uptime | sed 's/.*load average: //' | awk '{print $1}')

  echo "Clawdie: $SERVICE_STATUS"
  echo "ZFS pool (zroot): $POOL_USAGE"
  echo "Memory: $MEM"
  echo "CPU Load: $LOAD (1 min)"
}

Helper Library Functions

#!/bin/sh
# /usr/local/libexec/clawdie-lib-admin.sh

# Jail operations
clawdie_jail_list() {
  jls -N name hostname state ip4.addr 2>/dev/null | grep -E "^(worker|db|cms|mgmt)" || echo "No jails found"
}

clawdie_jail_status() {
  local jail=$1
  jls -j "$jail" state 2>/dev/null || echo "unknown"
}

clawdie_jail_start() {
  local jail=$1
  service jail onestart "$jail" 2>&1 | tail -5
}

clawdie_jail_stop() {
  local jail=$1
  service jail onestop "$jail" 2>&1 | tail -5
}

clawdie_jail_console() {
  local jail=$1
  jexec "$jail" /bin/sh
}

# ZFS operations
clawdie_snapshot_create() {
  local label=$1
  local snapshot="zroot@manual-$(date +%Y%m%d_%H%M)"
  zfs snapshot "$snapshot" 2>&1
  echo "Created: $snapshot"
}

clawdie_snapshot_list() {
  zfs list -t snapshot -r zroot 2>/dev/null | grep "^zroot" || echo "No snapshots"
}

clawdie_snapshot_restore() {
  local snapshot=$1
  bsddialog --title "Confirm Restore" \
    --yesno "Restore $snapshot? This will rollback all changes since creation." 0 0

  if [ $? -eq 0 ]; then
    zfs rollback "$snapshot" 2>&1 | head -20
    echo "Rollback complete. System restart recommended."
  fi
}

# Log operations
clawdie_log_service() {
  tail -50 /var/log/clawdie.log 2>/dev/null || echo "No log found"
}

clawdie_log_jail() {
  local jail=$1
  jexec "$jail" tail -50 /var/log/messages 2>/dev/null || echo "No jail log"
}

# Config operations
clawdie_config_read_env() {
  # Read current .env without exposing secrets
  grep -E "^(ASSISTANT_NAME|AGENT_DOMAIN|TZ|LLM_PROVIDER)" \
    /home/clawdie/clawdie-ai/.env 2>/dev/null || echo "Config not found"
}

clawdie_config_change_name() {
  bsddialog --title "Change Assistant Name" \
    --inputbox "Enter new assistant name:" 0 0 "$CURRENT_NAME" 2>&1 | \
    xargs -I {} sed -i '' "s/^ASSISTANT_NAME=.*/ASSISTANT_NAME={}/" \
    /home/clawdie/clawdie-ai/.env
}

Usage Examples

Example 1: Start Worker Jail

# User: Jails → select "1" (worker) → [Start]
clawdie_jail_start worker
# Output: "Jail worker started"

Example 2: View Recent Logs

# User: Logs → [Clawdie Service] → shows tail -50 /var/log/clawdie.log
tail -50 /var/log/clawdie.log

Example 3: Create Manual Snapshot

# User: Snapshots → [Create Snapshot]
clawdie_snapshot_create "manual"
# Output: "Created: zroot@manual-20260323_2145"

Integration with Lumina

Tray Applet

Binary: /usr/local/libexec/clawdie-tray-applet (shell script)

#!/bin/sh
# Updates tray icon every 5 seconds

RUNNING_ICON="/usr/local/share/icons/clawdie-running.png"
STOPPED_ICON="/usr/local/share/icons/clawdie-stopped.png"

while true; do
  if service clawdie status > /dev/null 2>&1; then
    echo "ICON:$RUNNING_ICON"
    echo "LABEL:Clawdie"
  else
    echo "ICON:$STOPPED_ICON"
    echo "LABEL:Clawdie (offline)"
  fi
  sleep 5
done

Right-click binding: Exec=/usr/local/bin/clawdie-admin


Permissions & Security

User (clawdie) Operations

  • Jail status queries: via jls (unprivileged)
  • Logs: read /var/log/clawdie.log (user-owned)
  • Config: read .env (user-owned)

Privileged Operations (via sudo)

  • Jail start/stop: requires root via sudo service jail ...
  • ZFS snapshot/rollback: requires root via sudo zfs ...
  • System restart: requires root via sudo shutdown ...

sudo Setup (automatic in firstboot.sh):

# /usr/local/etc/sudoers.d/clawdie-admin
# Clawdie admin operations
%wheel ALL=(ALL) NOPASSWD: /usr/local/libexec/clawdie-lib-admin.sh
%wheel ALL=(ALL) NOPASSWD: /usr/sbin/service
%wheel ALL=(ALL) NOPASSWD: /usr/sbin/zfs
%wheel ALL=(ALL) NOPASSWD: /usr/sbin/jail
%wheel ALL=(ALL) NOPASSWD: /usr/bin/killall

Accessibility

  • Keyboard navigation: bsddialog supports tab/arrow keys, Enter
  • High contrast: Inherits Lumina theme settings
  • No mouse required: All functions accessible via keyboard
  • Screen reader: Standard bsddialog output readable by screen readers

Performance Considerations

  • Startup: <200 ms (pure shell, no Java/Python startup overhead)
  • Refresh rate: 5-second poll for status (minimal CPU)
  • Memory: <5 MB footprint
  • Concurrency: Lock file prevents multiple instances (/tmp/clawdie-admin.lock)

Testing Checklist

  • clawdie-admin launches from Lumina tray
  • clawdie-admin launches from terminal
  • System Health displays correct CPU/memory/disk stats
  • Jails submenu lists all jails (worker, db, cms)
  • Can toggle jail start/stop with sudo confirmation
  • Can open jail console via jexec
  • Snapshots create/list/restore work with sudo
  • Logs display correctly (tailed, not truncated)
  • Config display matches current .env
  • No secrets logged to console
  • Multiple concurrent instances prevented (lock file)
  • Menu navigation works with keyboard only

Future Enhancements

  1. Backup scheduling UI — configure daily/weekly backups
  2. Network config — change IP addresses, DNS
  3. Service management — start/stop nginx, PostgreSQL within jails
  4. Metrics export — export system stats to Grafana
  5. Terminal multiplexing — tmux split for multiple jails open simultaneously