# AI Cockpit — New-Machine Setup Guide

            . | .
             \|/
         .--- O ---.
        /    /|\    \
       '    / | \    '
            . | .

      Fresh Linux Mint → Working AI Cockpit

> Step-by-step setup for a Linux Mint 22 / Ubuntu 24.04 machine. Each step has a verification checkpoint. Do not skip steps. If a step fails, the Troubleshooting section at the end has fixes.

## Table of contents

1. Before you start
2. Installing on macOS / Windows
3. Step 1 — System packages
4. Step 2 — Node.js (for Claude Code & Gemini CLI)
5. Step 3 — AI CLI tools
6. Step 4 — Ollama and local models
7. Step 5 — Apache PHP setup
8. Step 6 — Cockpit files
9. Step 7 — Permissions and sudoers
10. Step 8 — Built-in capabilities
11. Step 9 — Tool binaries (optional but recommended)
12. Step 10 — First launch verification
13. Step 11 — Worker provider keys (optional)
14. Step 12 — Personalization
15. Troubleshooting
16. Uninstall

## Before you start

CI-verified — an unattended end-to-end run of `install_cockpit.sh` passes on a real Linux Mint/Ubuntu runner and a real Apple Silicon macOS runner (GitHub Actions).

`install_cockpit.sh` is now one script for every POSIX target — it auto-detects your package manager (`nala`/`apt-get` on Debian/Ubuntu/Mint, `pacman` on Arch, `dnf` on Fedora, `zypper` on openSUSE, `apk` on Alpine, or Homebrew on macOS) and installs the right packages for it. Only the nala/apt-get and Homebrew paths are CI-verified against real hardware — pacman/dnf/zypper/apk are new and shipped untested, in beta, on the theory that offering them and fixing what breaks beats not offering them at all. There is no longer a separate macOS installer — the old `install_cockpit_macos.sh` is retired.

### Required

- Linux Mint 22.x Cinnamon, compatible Ubuntu 24.04 derivative, Arch, Fedora, openSUSE, or Alpine — or macOS on Apple Silicon
- Sudo access on the machine
- At least 16 GB RAM (32 GB recommended)
- 50 GB free disk space (more for Ollama models)
- Internet during setup for v2 (its account + model downloads). v1 can install fully offline — the installer skips downloads when there's no connection. Either way, the app itself runs offline afterwards

### Optional but useful

- A modern AMD/NVIDIA GPU with at least 4 GB VRAM (for Ollama and/or LocalAI on GPU — Dual mode needs enough for both loaded at once) — the app detects your real GPU/VRAM at install time (both AMD and NVIDIA) and raises the local-model auto-load ceiling accordingly, above the conservative 4B default it falls back to when nothing's detected
- A non-default home directory layout — the cockpit assumes paths under `/home/dario/...` by default; if your username differs, edit the installation paths accordingly

### What you should download before running these steps

Download `cockpit_install.tar.gz` from the Download page and extract it — `tar -xzf cockpit_install.tar.gz`. Layout:

    cockpit/
    ├─ install_cockpit.sh     <- run this:  sudo bash install_cockpit.sh
    ├─ install_windows.ps1    <- Windows (Docker Desktop / WSL2)
    ├─ dist/
    │   ├─ cockpit_v2.tar.gz  <- current app (web + scripts + seed combos)
    │   └─ cockpit_v1.tar.gz  <- legacy 1.0.0 app
    ├─ SETUP_GUIDE.html        <- this file
    ├─ USER_GUIDE.html
    └─ README.txt

The app itself lives inside the `dist/` tarballs; the installer unpacks the chosen version for you. To hand-copy files instead (manual install), first extract the app into a working folder — `mkdir -p ~/Downloads/cockpit-app && tar -xzf dist/cockpit_v2.tar.gz --strip-components=1 -C ~/Downloads/cockpit-app` — which gives you `~/Downloads/cockpit-app/web/` and `~/Downloads/cockpit-app/scripts/`; the manual steps below refer to that folder.

The cockpit ships an automated `install_cockpit.sh` script that handles all of these steps end-to-end, on Linux (any of the distros in Requirements above) or macOS. When you run it, it now:

- asks which version to install — v1, v2, or both (both installs them side by side, v2 at `/cockpit` and v1 at `/cockpit-v1`);
- picks the edition for you from that choice — v2/both use the full-account edition (needs at least a free account, no card), v1 runs fully local and standalone;
- can install offline where possible (skips downloads gracefully — ideal for a private, offline v1 setup);
- detects your CPU / RAM / GPU / VRAM and recommends local models that actually fit;
- leaves Ollama at its own default model location (and warns you if you already use a custom one).

Every prompt explains what each option means and shows its default. This guide walks through the manual sequence — useful if you want to understand what's happening or if the auto-installer fails partway.

## Installing on macOS / Windows

Steps 1–12 below are written for Linux Mint/Ubuntu. Cockpit itself is just Apache + PHP + Bash + tmux — it runs the same way on any OS that can provide those, with the caveats below.

### macOS

CI-verified — an unattended end-to-end run of `install_cockpit.sh` (the same script used for Linux — there is no separate macOS installer anymore, the old `install_cockpit_macos.sh` is retired) passes on a real Apple Silicon runner (GitHub Actions). If anything looks different on your own Mac, let us know.

Apple Silicon (M-series) only — Intel Macs are not supported. The script checks `uname -m` at the very start and refuses to run on anything but `arm64`, since the bundled `cockpit_auth` binary only ships an Apple Silicon build.

Genuinely native-capable — no virtualization needed. Apple removed PHP and disabled Apache by default since macOS 12; `install_cockpit.sh` installs both via Homebrew automatically (installing Homebrew itself first, if it's missing), along with tmux, ffmpeg, pandoc, imagemagick, and poppler — and asks whether to also install Codex CLI, Qwen Code CLI, and whisper.cpp (offline voice transcription — installed as a Homebrew formula on macOS, no source compile needed here unlike Linux).

Doing it by hand instead of running the script:

    # 1. Install Homebrew if you don't have it: https://brew.sh
    brew install httpd php tmux ffmpeg pandoc imagemagick poppler

    # 2. whisper.cpp (optional) — Homebrew formula, Metal-accelerated
    brew install whisper-cpp

    # 3. Ollama — official native app, Apple Silicon Metal-accelerated
    #    https://ollama.com/download/mac

    # 4. Start Apache (httpd), point its docroot at the extracted cockpit-app/web folder,
    #    same as Step 5–6 below — paths differ slightly (/opt/homebrew/... on
    #    Apple Silicon vs Intel's /usr/local/..., but Intel isn't a supported
    #    target for this app regardless).

Everything else — Steps 6 through 12 — is identical to the Linux instructions once Apache/PHP/tmux are running.

### Windows — via WSL2 (not native)

NOT TESTED YET Written and reviewed carefully, but `install_windows.ps1` hasn't actually been run on a real Windows machine yet — please let us know how it goes if you try it.

Native Windows can't run this stack as-is — `agent_loop.sh` is built around `tmux`, which has no real Windows equivalent. The supported path is WSL2 (Windows Subsystem for Linux): a real Ubuntu environment running alongside Windows, reachable from your normal Windows browser at `localhost`.

#### Recommended — one-click installer

`install_windows.ps1` (in the download bundle) does the whole Windows-side setup for you: enables WSL2, installs Ubuntu-24.04, creates the Linux user unattended (skips WSL's normal interactive first-run wizard, generates a random password and shows it to you once), installs VS Code if you don't have it, and installs the WSL Remote extension — required, not optional, for comfortably editing project files with native Windows tooling later. Run it from an elevated PowerShell:

    # Right-click PowerShell → "Run as Administrator", then:
    .\install_windows.ps1

It automates the Windows/WSL2 side only — it does not download the bundle or run `install_cockpit.sh` for you. Once it finishes, it prints the exact next steps: open the Ubuntu-24.04 app, download the cockpit bundle inside that WSL session, and run `install_cockpit.sh` yourself — from there it's identical to the Linux instructions.

#### Manual path (if you'd rather not run the script)

    # 1. Install WSL2 + Ubuntu (PowerShell, as Administrator)
    wsl --install -d Ubuntu-24.04

    # 2. Reboot when prompted, then open the new "Ubuntu" Start Menu entry
    #    and finish the Ubuntu first-run (create a Linux username/password —
    #    unrelated to your Windows login).

    # 3. Inside that Ubuntu shell, follow Steps 1–12 of this guide exactly
    #    as written — it's a real Ubuntu 24.04, nothing Windows-specific
    #    from here on. Access the cockpit from your normal Windows browser
    #    at http://localhost/cockpit/ once Apache's running (WSL2 forwards
    #    localhost automatically).

Then install VS Code + its "WSL" (Remote-WSL) extension yourself, and use Ctrl+Shift+P → "WSL: Connect to WSL" to open project folders with full native-tool convenience at full WSL-native filesystem speed — this is the setup we recommend project files live under (inside WSL's own filesystem), not on the Windows side reached via `/mnt/c/...`, which has real I/O overhead for the kind of many-small-file CRUD Cockpit's agents do.

Ollama — run it natively on Windows, not inside WSL. Ollama has a real native Windows installer with full NVIDIA CUDA GPU support — better performance than running it inside the WSL2 virtual machine. Install it normally from ollama.com/download/windows, then point Cockpit's Ollama connection (inside WSL) at the Windows host's IP instead of `localhost`:

    # Inside WSL, find the Windows host IP:
    cat /etc/resolv.conf | grep nameserver
    # → use that IP with Ollama's port, e.g. http://172.x.x.x:11434
    # Set OLLAMA_HOST=0.0.0.0 on the Windows side (System Environment
    # Variables) so it accepts connections from WSL, not just localhost.

#### Optional — stable machine identity across WSL reinstalls

WSL2's own machine identity is not stable — reinstalling the Ubuntu distro (or certain Windows updates) resets it, which would make Cockpit's SaaS licensing think it's a brand-new machine each time. To avoid that, copy the Windows-native `cockpit_auth.exe` build to a fixed path Windows and WSL can both see, and Cockpit will automatically prefer it for machine identification (falls back to the normal Linux binary if this isn't set up — nothing breaks either way):

    # From Windows (PowerShell or File Explorer):
    mkdir C:\CockpitAuth
    copy cockpit_auth.exe C:\CockpitAuth\cockpit_auth.exe
    # That's it — Cockpit (running in WSL) detects WSL automatically and
    # reaches this .exe at /mnt/c/CockpitAuth/cockpit_auth.exe.

### Alternative for Windows or macOS — Docker

NOT TESTED YET Written and reviewed carefully, but this bundle hasn't actually been built/run end-to-end yet — please let us know how it goes if you try it.

One `Dockerfile` + `docker-compose.yml`, same on both OSes — Docker Desktop already runs on WSL2 (Windows) or Apple's virtualization framework (macOS), so this sidesteps writing separate native/WSL2/Homebrew instructions per OS. Ollama and LocalAI both run inside the same container as Cockpit, not as separate ones — the app's PHP backends call both at hardcoded local addresses (`127.0.0.1:11434` / `127.0.0.1:8080`), not a configurable host, so split containers wouldn't be reachable. Both agents' models persist in their own named Docker volumes across rebuilds.

Download the Docker bundle from the download page (separate small zip — Dockerfile, compose file, entrypoint script, and a step-by-step README; it doesn't duplicate the app itself, you extract the main tarball's `web/` folder alongside it). Not yet published to Docker Hub, so you build locally:

    docker compose build      # first time, or after updating web/
    docker compose up -d
    # One-time: authenticate the agent CLIs
    docker compose exec cockpit su - cockpit -c claude
    docker compose exec cockpit su - cockpit -c gemini
    # Then open in your normal browser:
    # http://localhost:8080

GPU passthrough to Ollama only works via Docker on a Linux host with the NVIDIA Container Toolkit (uncomment the `deploy:` block in `docker-compose.yml`) — Docker Desktop on Windows/macOS doesn't pass a GPU through to containers, so Ollama runs CPU-only there, fine for small (1–4B) models.

### Raspberry Pi / ARM Linux

CI-verified — an unattended end-to-end run of `install_cockpit.sh` passes on a real ARM64 runner (GitHub Actions).

A Pi running 64-bit Raspberry Pi OS (Debian-based) is full, real Linux — Apache, PHP, bash, and tmux all work exactly as they do on any x86_64 Linux box. Steps 1–12 of this guide apply unchanged — there's no separate "Pi edition" of the install process. A Pi is also a legitimate, popular way to host Ollama itself as a small always-on local model server, even for other machines on your network to reach.

The one Pi-specific piece is `cockpit_auth` — the compiled SaaS-licensing binary needs its own ARM build (a Pi can't run the x86_64 binary). That build now exists — see the download page for the ARM Linux binary alongside the x86_64/Windows/macOS ones.

Realistic expectations: a Pi 4/5 with 8GB RAM can run small Ollama models (1–4B parameters) at reasonable speed for CRUD-style combo work; it is not going to run anything comparable to a desktop GPU for larger models — treat it as a small-model or remote-Ollama-target machine, not a general-purpose Cockpit workstation replacement.

### Everywhere — remote access from your phone

The Everywhere tier lets a phone or any other browser talk to a Cockpit already running on your home rig, without port-forwarding or a static IP. Your rig has no open port; both sides poll a small queue on `cockpit.ruggi.site` over plain HTTPS — nothing to configure on your router.

Status: built, not yet deployed. The relay server, the home-rig poller, and the phone page all exist in the codebase as of this guide's last update, but the database schema hasn't been run against the live server yet and none of it has been tested end-to-end. Treat this section as "how it will work", not a guarantee it's live right now.

#### One-time setup on your home rig

1. Make sure your account is signed in and has the Everywhere (or Combined) tier — check `Settings → Account`.
2. Create `~/scripts/cockpit_data/relay_poller_credentials.json` with your local Cockpit login (the same username/password you use to open the web UI on this machine):

       {"username": "your-local-username", "password": "your-local-password"}

   This lets the relay poller submit prompts to your own local Cockpit the same way your browser does — it's a local secret file, never uploaded anywhere, same as the Gemini API key file.
3. Start the poller: `~/scripts/relay_start.sh` (stop it with `~/scripts/relay_stop.sh`). It no-ops safely if you're not signed in or not on an Everywhere-capable tier.

#### From your phone

Open `cockpit.ruggi.site/relay.html`, sign in with the same account, pick your rig from the list (skipped automatically if you only have one), and send a message — it runs on your home rig's Claude/Gemini/ Ollama session exactly as if you'd typed it there, and the reply streams back to your phone. A green dot means the rig's poller checked in within the last 30 seconds; grey means it's offline or not started.

### Mobile (Android / iOS)

AI Cockpit runs on Linux, ARM Linux, macOS, and Windows (via WSL2). Every other system — Android, iOS, ChromeOS, anything else — connects through the Everywhere relay page on the site (above) instead: no install, just a browser and a free account with the Everywhere tier.

## Step 1 — System packages

Install Apache, PHP, and the supporting CLI tools that the cockpit depends on:

    sudo apt update
    sudo apt install -y nala
    sudo nala install -y \
        apache2 \
        php8.3 \
        php8.3-cli \
        php8.3-curl \
        php8.3-mbstring \
        php8.3-xml \
        php8.3-zip \
        libapache2-mod-php8.3 \
        tmux \
        jq \
        curl \
        git \
        util-linux \
        xed \
        zsh \
        build-essential \
        ca-certificates

### Verification

    apache2 -v          # Should show 2.4.x
    php -v              # Should show 8.3.x
    tmux -V             # Should show 3.x or higher
    jq --version        # Should show jq-1.6 or 1.7
    which curl          # Should show /usr/bin/curl

If any command says “not found”, re-run the install for that package.

### Why each package?

- apache2 + PHP 8.3 — serves the cockpit web UI and handles all backend logic
- php8.3-curl — needed by `bridge.php`, `workers.php`, `orchestrator.php` for HTTP
- php8.3-mbstring — string handling for non-ASCII content (Hebrew, Spanish)
- php8.3-xml — DOM parser for `search.php` (better than regex for HTML scraping)
- php8.3-zip — chat export/import via ZIP archives
- tmux — runs each AI agent in a persistent session
- jq — JSON parsing in shell scripts (capabilities, workers, tools auto-route)
- xed — your preferred text editor
- zsh — your preferred shell

## Step 2 — Node.js (for Claude Code & Gemini CLI)

Node.js is needed for `npx` (which launches MCP servers) and for the official Claude Code and Gemini CLI tools.

    # NodeSource repository for current LTS
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo nala install -y nodejs

    # Set up a global npm prefix in user-space (avoids sudo for global installs)
    mkdir -p "$HOME/.npm-global"
    npm config set prefix "$HOME/.npm-global"

    # Add to PATH (zsh)
    echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc
    echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc

Reload your shell config or open a fresh terminal.

### Verification

    node --version      # Should show v20.x
    npm --version       # Should show 10.x
    echo $PATH | tr ':' '\n' | grep npm-global
                        # Should show /home/<you>/.npm-global/bin

## Step 3 — AI CLI tools

Install the three CLI tools the cockpit dispatches to by default:

    # Anthropic Claude Code
    npm install -g @anthropic-ai/claude-code

    # Google Gemini CLI
    npm install -g @google/gemini-cli

    # (Ollama is installed in Step 4)

`install_cockpit.sh` installs Claude Code and Gemini CLI unconditionally (no prompt, always on), then separately asks whether to also install two more Card 1 alternatives — answer yes to either and it installs them the same way:

    # OpenAI Codex CLI (optional)
    npm install -g @openai/codex

    # Qwen Code CLI (optional)
    npm install -g @qwen-code/qwen-code

You’ll need to authenticate each one before the cockpit can use it:

    # Claude — opens a browser for OAuth, you sign in to your Anthropic account
    claude

    # Gemini — likewise, OAuth flow with your Google account
    gemini

After both authenticate successfully, you can `Ctrl-D` out of each.

### Verification

    claude --version     # Should show a version string
    gemini --version     # Likewise

    # Sanity smoke tests
    echo "Say hello in one word" | claude --print
    echo "Say hello in one word" | gemini --prompt

Both should return a response within 5–15 seconds.

## Step 4 — Ollama and local models

Note: the automated installer now leaves Ollama at its own default model location — you do not need to set a custom `OLLAMA_MODELS` path or a systemd override. The custom-path steps below are optional, only if you want to store models on a different disk. (If you already have a custom location from a previous setup, the installer detects it and asks before continuing.)

    # Ollama installer — official one-liner
    curl -fsSL https://ollama.com/install.sh | sh

    # Configure non-default model storage location
    mkdir -p "$HOME/ollama/models"
    sudo systemctl edit ollama.service

In the editor that opens, paste:

    [Service]
    Environment="OLLAMA_MODELS=/home/dario/ollama/models"

Save and exit. Then:

    sudo systemctl daemon-reload
    sudo systemctl restart ollama
    sudo systemctl enable ollama

    # Also export for interactive shells
    echo 'export OLLAMA_MODELS="$HOME/ollama/models"' >> ~/.zshrc
    echo 'export OLLAMA_MODELS="$HOME/ollama/models"' >> ~/.bashrc

### Pulling models

The cockpit’s default tier-1 recommendations:

    # Tier 1 — best for CRUD and context (3 GB VRAM)
    ollama pull qwen2.5-coder:3b
    ollama pull qwen2.5-coder:7b

    # Optional — tool-calling fine-tune
    ollama pull MFDoom/deepseek-r1-tool-calling:7b

### Verification

    ollama list                     # Should list pulled models
    ollama show qwen2.5-coder:3b    # Should show model details

    # Smoke test
    echo "Say hello in one word" | ollama run qwen2.5-coder:3b

If `ollama list` shows the storage path is `/usr/share/ollama/...`, the custom path didn’t take effect. Re-check the systemd override file:

    systemctl cat ollama.service | grep OLLAMA_MODELS

### LocalAI (optional — needed for Dual mode)

Skip this if you only plan to use Ollama. Dual mode (Card 3 — both backends genuinely in parallel, for chat and Power Combos) needs LocalAI actually running too. The automated installer does all of this for you; here's the manual equivalent.

    # Download the checksum-verified binary (Linux amd64 shown — see
    # install_cockpit.sh for the arm64 asset/checksum)
    mkdir -p ~/.local/bin
    curl -fL https://github.com/mudler/LocalAI/releases/download/v4.7.1/local-ai-v4.7.1-linux-amd64 \
      -o ~/.local/bin/local-ai
    chmod +x ~/.local/bin/local-ai

    # Verify the checksum before trusting it
    echo "2a4ccf4cd7ecc76fb6dde8d847a6d1448b67d7cf84fdcb4285cd002f42a9c801  $HOME/.local/bin/local-ai" | sha256sum -c -

    mkdir -p ~/localai/models ~/localai/data ~/localai/backends
    sudo systemctl edit --force --full localai.service

In the editor that opens, paste (LocalAI's own paths default to CWD-relative, which breaks under systemd — every path below is explicit so it never depends on the caller's working directory):

    [Unit]
    Description=LocalAI Service
    After=network-online.target

    [Service]
    WorkingDirectory=/home/YOUR_USERNAME
    ExecStart=/home/YOUR_USERNAME/.local/bin/local-ai run --address 127.0.0.1:8080
    Environment="LOCALAI_MODELS_PATH=/home/YOUR_USERNAME/localai/models"
    Environment="LOCALAI_DATA_PATH=/home/YOUR_USERNAME/localai/data"
    Environment="LOCALAI_BACKENDS_PATH=/home/YOUR_USERNAME/localai/backends"
    User=YOUR_USERNAME
    Group=YOUR_USERNAME
    Restart=always
    RestartSec=3

    [Install]
    WantedBy=default.target

Save and exit, replacing `YOUR_USERNAME` above with your actual username first. Then:

    sudo systemctl daemon-reload
    sudo systemctl enable --now localai

    # Wait for it to come up, then confirm
    curl http://127.0.0.1:8080/

### Pulling LocalAI models

LocalAI has no `pull` command — models are requested through its own HTTP API. The cockpit's default suggestions (LocalAI equivalents of the Ollama Tier-1 set above, same job/size class, run through LocalAI's llama.cpp backend instead):

    curl -X POST http://127.0.0.1:8080/models/apply \
      -H "Content-Type: application/json" \
      -d '{"id":"qwen2.5-coder-3b-instruct"}'

    # Returns a job uuid — poll it until "processed":true
    curl http://127.0.0.1:8080/models/jobs/<uuid>

Other suggested ids: `llama-3.2-3b-instruct`, `deepseek-r1-distill-qwen-1.5b`, `qwen2.5-7b-instruct`, `phi-4-mini-instruct`. If an id 404s, browse http://127.0.0.1:8080/models/available on the running instance for the exact current gallery id.

### Verification

    curl http://127.0.0.1:8080/v1/models   # Should list pulled models
    systemctl status localai               # Should be active (running)

    # Smoke test
    curl http://127.0.0.1:8080/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{"model":"qwen2.5-coder-3b-instruct","messages":[{"role":"user","content":"Say hello in one word"}]}'

## Step 5 — Apache PHP setup

The cockpit runs as a normal Apache vhost at `/var/www/html/cockpit/`.

    # Make sure mod_php is enabled
    sudo a2enmod php8.3
    sudo a2enmod rewrite       # Used by some PHP endpoints

    # Set timezone in PHP so dates are correct
    sudo bash -c 'cat > /etc/php/8.3/apache2/conf.d/99-cockpit.ini' << 'EOF'
    date.timezone = Asia/Jerusalem
    upload_max_filesize = 64M
    post_max_size = 64M
    memory_limit = 256M
    max_execution_time = 300
    EOF

    # Same settings for CLI PHP
    sudo cp /etc/php/8.3/apache2/conf.d/99-cockpit.ini /etc/php/8.3/cli/conf.d/

    # Restart Apache
    sudo systemctl restart apache2
    sudo systemctl enable apache2

### Verification

    # Apache should respond
    curl -I http://localhost/   # Should return HTTP/1.1 200 OK

    # PHP should be enabled
    echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/phpinfo.php > /dev/null
    curl -s http://localhost/phpinfo.php | grep "PHP Version"
                                # Should show "PHP Version => 8.3.x"
    sudo rm /var/www/html/phpinfo.php

    # Verify timezone
    php -r 'echo date("c"), "\n";'
                                # Should show current time in your zone

## Step 6 — Cockpit files

Deploy the cockpit’s web files to `/var/www/html/cockpit/`:

    # Web root for cockpit
    sudo mkdir -p /var/www/html/cockpit

    # Copy all PHP files, the HTML, JSON catalogs, and VERSION
    cd ~/Downloads/cockpit-app
    sudo cp \
        index.html \
        bridge.php files.php status.php models.php saver.php \
        session.php config.php library.php paths.json \
        search.php export.php import.php version.php VERSION \
        capabilities.php orchestrator.php workers.php tools.php \
        workers_providers.json \
        /var/www/html/cockpit/

    # Extract built-in capability and tool definitions
    sudo tar -xzf cockpit_builtins.tar.gz -C /var/www/html/cockpit/
    sudo tar -xzf tools_builtins.tar.gz   -C /var/www/html/cockpit/

    # Scripts that run as the user via tmux
    mkdir -p ~/scripts
    cp \
        cockpit_start.sh cockpit_stop.sh \
        agent_loop.sh crud_executor.sh \
        install_capabilities.sh \
        ~/scripts/
    chmod +x ~/scripts/*.sh

    # Cockpit data directory
    mkdir -p ~/scripts/cockpit_data/{library,snippets,sources,code,approvals,capabilities/_builtin,plans,workers_state,tools,tools_outputs,_standalone}

    # Projects root
    mkdir -p ~/Software/Programing/LocalAIProjs

### Verification

    ls /var/www/html/cockpit/   # Should list all .php and .html files
    ls ~/scripts/               # Should list shell scripts
    ls ~/scripts/cockpit_data/  # Should show empty subdirs

## Step 7 — Permissions and sudoers

Apache (running as `www-data`) needs read access to the cockpit data and tmux socket. Your user (running as `dario`) needs write access. The bridge between these is the `www-data` group.

    # Add www-data group membership for shared file access
    sudo chgrp -R www-data /var/www/html/cockpit/
    sudo chmod -R g+rX /var/www/html/cockpit/

    sudo chgrp -R www-data ~/scripts/cockpit_data/
    sudo chmod -R g+rwX ~/scripts/cockpit_data/

    # tmux socket lives in /tmp; needs group access from www-data
    # (cockpit_start.sh creates this on each run with the right perms)

    # Add www-data to your group so it can read your home dir prefix
    sudo usermod -a -G $USER www-data

    # Allow www-data to invoke the cockpit_*.sh scripts without password
    sudo bash -c 'cat > /etc/sudoers.d/cockpit' << EOF
    www-data ALL=(${USER}) NOPASSWD: ${HOME}/scripts/cockpit_start.sh
    www-data ALL=(${USER}) NOPASSWD: ${HOME}/scripts/cockpit_stop.sh
    EOF
    sudo chmod 440 /etc/sudoers.d/cockpit

### Verification

    # As www-data, can it read cockpit_data?
    sudo -u www-data ls ~/scripts/cockpit_data/
                                # Should list directories without error

    # Validate sudoers without breaking the system
    sudo visudo -cf /etc/sudoers.d/cockpit
                                # Should say "/etc/sudoers.d/cockpit: parsed OK"

## Step 8 — Built-in capabilities

Capability definitions ship as a tarball; deploy them to `cockpit_data`:

    cd ~/Downloads/cockpit-app
    BUILTINS_SOURCE="$PWD/cockpit_builtins" ~/scripts/install_capabilities.sh

This copies five built-in capabilities (filesystem, git, web-search, web-fetch, ssh) into:

    ~/scripts/cockpit_data/capabilities/_builtin/

### Verification

    ls ~/scripts/cockpit_data/capabilities/_builtin/
    # Should list 5 directories: filesystem, git, ssh, web-fetch, web-search

    # Each should contain CAP.json + README.md
    for d in ~/scripts/cockpit_data/capabilities/_builtin/*/; do
        echo "$(basename $d):"
        ls "$d"
    done

## Step 9 — Tool binaries (optional but recommended)

Without these binaries, the TOOLS card in the cockpit will show “no tools detected”. Install whichever you’ll use:

    # Audio/video — almost always wanted
    sudo nala install -y ffmpeg

    # Speech-to-text — large download, ~1 GB for the base model
    sudo nala install -y python3-pip
    pip install --user openai-whisper       # Or: nala install whisper

    # Document conversion
    sudo nala install -y pandoc texlive-xetex texlive-fonts-recommended
                                            # texlive needed for md→pdf

### Verification

    ffmpeg -version | head -1   # Should show ffmpeg N.x.x
    whisper --help | head -3    # Should show Whisper usage
    pandoc --version | head -1  # Should show pandoc 3.x

If any are missing, you can still launch the cockpit — Tools will show them as “✗ not found” and you can install later. The cockpit’s Detect button in Tools settings re-scans whenever you click it.

### Optional add-ons for later

imagemagick and poppler-utils are no longer optional add-ons — `install_cockpit.sh` now installs both unconditionally on every OS it supports, no prompt. If you're doing this manual sequence instead of running the script, install them alongside ffmpeg/pandoc above:

    sudo nala install imagemagick poppler-utils

yt-dlp is also now offered by the installer — it asks during Step 3's CLI-tools phase (default: no) instead of being purely manual. By hand:

    sudo curl -fL https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
    sudo chmod a+rx /usr/local/bin/yt-dlp

Still fully manual/optional:

- calibre for ebook conversion: `sudo nala install calibre`

These don’t ship with built-in tool definitions but you can add them via the “+” button in Tools settings. (whisper — see the dedicated whisper.cpp + a model section below, which is the actual supported transcription path and is now also offered by the installer, not the `openai-whisper` pip package shown above.)

## Step 10 — First launch verification

Time to start the cockpit:

    ~/scripts/cockpit_start.sh

You should see output like:

    Starting cockpit sessions...
      Claude session: cockpit_claude
      Gemini session: cockpit_gemini
      Ollama session: cockpit_ollama
      tmux socket: /tmp/cockpit_tmux.sock
      Apache: ready
    Cockpit ready: http://localhost/cockpit/

Open the cockpit in Brave:

    brave-browser http://localhost/cockpit/

### What to verify

1. The topbar shows the brand mark (control-yoke logo + “AI Cockpit” wordmark + version + “by Dario Ruggi”) on the left
2. Five supplier cards appear: CLAUDE, GEMINI, OLLAMA, WORKERS, TOOLS
3. CLAUDE is the default active card (expanded with model dropdown)
4. Stop / Restart buttons appear on the right
5. Info bar below the strip shows project/chat/path
6. The chat console is the large central area
7. Right sidebar has 9 vertical icon tabs

### First prompt smoke test

1. Type “say hello in one word” in the prompt area
2. Press Ctrl-Enter
3. Within a few seconds, “Hello” or similar appears as a streamed response

If this works, you’re done. The next steps are optional personalization.

## Step 11 — Worker provider keys (optional)

If you want to use online LLM providers as workers:

1. Click the gear icon next to WORKERS → settings modal
2. For each provider you want:
   - Click Get key — opens the provider’s key page in a new tab
   - Sign up / log in, create an API key
   - Paste the key into the input field → click Save
   - Click Disabled to toggle to Enabled
3. Close the modal — the workers dropdown is now populated

Recommended starting point: Groq is free with generous limits and makes a good first test. Once you have a key, smoke-test it via:

1. Click the WORKERS card
2. Pick a Groq model (e.g. “Llama 3.3 70B Versatile”)
3. Type a prompt → press Execute
4. Response should appear within a few seconds

## Step 12 — Personalization

### Brave as default browser

    xdg-settings set default-web-browser brave-browser.desktop

### Auto-start cockpit on login

Create a desktop entry that launches `cockpit_start.sh` and opens Brave to the cockpit URL:

    mkdir -p ~/.config/autostart

    cat > ~/.config/autostart/cockpit.desktop << 'EOF'
    [Desktop Entry]
    Type=Application
    Name=AI Cockpit
    Exec=bash -c '$HOME/scripts/cockpit_start.sh && sleep 2 && brave-browser http://localhost/cockpit/'
    Icon=preferences-system
    Hidden=false
    NoDisplay=false
    X-GNOME-Autostart-enabled=true
    StartupNotify=false
    EOF

### Dark theme (you’ve already got this — Linux Mint dark variant)

The cockpit has its own dark theme baked in. No system-level config needed.

### Default project

Edit `~/scripts/cockpit_data/last_project.txt` to set the project that opens by default each time:

    echo "myproject" > ~/scripts/cockpit_data/last_project.txt

## Troubleshooting

### Apache returns 403 Forbidden

    # Permissions on the cockpit directory
    sudo chown -R dario:www-data /var/www/html/cockpit/
    sudo chmod -R g+rX /var/www/html/cockpit/

    # Apache config — make sure /var/www/html is allowed
    grep -A3 "Directory /var/www/" /etc/apache2/apache2.conf
                                # Should include "Require all granted"

### “Bridge.php returned no response”

The PHP error log usually has the answer:

    sudo tail -50 /var/log/apache2/error.log

Common causes:

- php-curl missing: `sudo nala install php8.3-curl && sudo systemctl restart apache2`
- paths.json missing or corrupt: re-copy from the bundle
- bridge.php has a syntax error: `php -l /var/www/html/cockpit/bridge.php`

### “Agent session not found in tmux”

    # Check what sessions exist
    tmux -S /tmp/cockpit_tmux.sock ls 2>&1

    # If empty, restart cockpit
    ~/scripts/cockpit_stop.sh && ~/scripts/cockpit_start.sh

    # If permission denied, the socket has wrong group
    sudo chgrp www-data /tmp/cockpit_tmux.sock
    sudo chmod 660 /tmp/cockpit_tmux.sock

### Claude / Gemini OAuth fails

Both CLIs need a working browser OAuth flow:

    # From a desktop environment with a browser available
    claude   # Will print an auth URL; open it in your browser, sign in
    gemini   # Same flow, separate auth

If you’re SSHing in headlessly, you’ll need to do the auth on the machine’s actual desktop session first.

### Ollama: “no models” in cockpit dropdown

    # Confirm models exist
    ollama list

    # If empty, pull the defaults:
    ollama pull qwen2.5-coder:3b

    # Confirm OLLAMA_MODELS is being honored
    ls ~/ollama/models/  # Should show downloaded blobs

    # If models live in /usr/share/ollama/.ollama/, the systemd override didn't apply
    sudo systemctl edit ollama.service   # Re-set the Environment line
    sudo systemctl daemon-reload && sudo systemctl restart ollama

### LocalAI: “no models” in cockpit dropdown

    # Confirm the service is actually running
    systemctl status localai

    # Confirm models exist
    curl http://127.0.0.1:8080/v1/models

    # If empty, pull a default
    curl -X POST http://127.0.0.1:8080/models/apply \
      -H "Content-Type: application/json" \
      -d '{"id":"qwen2.5-coder-3b-instruct"}'

    # Confirm LOCALAI_MODELS_PATH is being honored
    ls ~/localai/models/  # Should show downloaded files

    # If the service won't start, check the unit for typos in the paths
    systemctl cat localai.service
    journalctl -u localai -n 50 --no-pager

### Tool detection always says “not found”

    # Verify the binaries are in PATH that Apache can see
    sudo -u www-data which ffmpeg
    sudo -u www-data which whisper
    sudo -u www-data which pandoc

    # If www-data can't see them but you can, the binaries are in a path
    # www-data doesn't search. Either:
    #   (a) Use Tools settings to set absolute path
    #   (b) Add the path to /etc/environment so it's system-wide

### Workers HTTP 401 / 403

API key issue. Re-generate the key on the provider’s site, paste it into Workers settings, save.

### Workers HTTP 429

Rate limited. Wait a few minutes or switch providers. The cockpit’s usage tracker shows your call counts per provider in the settings modal.

### Plans tab is empty after Plan-mode submit

Check the chat for system messages like “Plan creation failed”. Most common cause is one of the voter agents being unauthenticated or unreachable. Run `claude --print "test"` and `gemini --prompt "test"` from a terminal to confirm both are working.

### IPv6 / wget bug on Linux Mint

A known bug — `wget` defaults to IPv6 and times out on some Mint installs. Already absorbed into `cockpit_start.sh`, but if you see the symptom elsewhere:

    # Force IPv4 globally for wget
    echo 'inet4_only = on' >> ~/.wgetrc

### Apache logs filling up

The cockpit polls the bridge every 200 ms during streams, which generates a lot of access-log entries. If you don’t need them:

    # Disable access logging for /cockpit/bridge.php specifically
    sudo bash -c 'cat > /etc/apache2/conf-available/cockpit-quiet.conf' << 'EOF'
    SetEnvIf Request_URI "/cockpit/bridge\.php" cockpit_quiet
    CustomLog ${APACHE_LOG_DIR}/access.log combined env=!cockpit_quiet
    EOF
    sudo a2enconf cockpit-quiet
    sudo systemctl reload apache2

## Uninstall

If you ever need to wipe the cockpit:

    # Stop everything
    ~/scripts/cockpit_stop.sh 2>/dev/null

    # Web root
    sudo rm -rf /var/www/html/cockpit/

    # Scripts
    rm -rf ~/scripts/cockpit_*.sh ~/scripts/agent_loop.sh ~/scripts/crud_executor.sh ~/scripts/install_capabilities.sh

    # Data (this is destructive — projects under here are gone forever)
    # Keep this if you want to preserve your chats/library/snippets
    rm -rf ~/scripts/cockpit_data/

    # Sudoers fragment
    sudo rm /etc/sudoers.d/cockpit

    # Apache PHP override (optional — only do this if no other PHP apps need it)
    sudo rm /etc/php/8.3/apache2/conf.d/99-cockpit.ini
    sudo systemctl restart apache2

The Claude / Gemini / Ollama / LocalAI installations stay — they’re independent of the cockpit and you may want them for direct use. LocalAI's systemd service (`localai.service`) also stays enabled; disable it yourself with `sudo systemctl disable --now localai` if you no longer want it running.

That’s it. If you’ve followed all 12 steps, you have a fully working AI Cockpit. The User Guide covers what to do once it’s running.

# Update — June 2026: Additional setup for new features

The base install above is unchanged. These extra steps enable features added later. All are optional — the cockpit runs without them, and each feature degrades gracefully (with a hint) when its tool is missing.

## A. uv / uvx — for MCP capabilities (Claude & Gemini)

Capabilities that run an MCP server (e.g. the bundled `time` capability) launch it via `uvx`, which ships with uv (Astral’s Python tool).

    # Official installer (adds ~/.local/bin to PATH)
    curl -LsSf https://astral.sh/uv/install.sh | sh
    # new shell, then verify:
    uvx --version

- One-time network needed; after that `uvx <server>` is cached.
- Must be on the PATH the agents see — after installing, restart the cockpit (Stop → Start) so the agent sessions pick up the new PATH.
- `npx` (from Node, Step 2) covers npm-based MCP servers and needs no extra setup.

## B. whisper.cpp + a model — for offline voice input

`install_cockpit.sh` now offers this as an install-time prompt (default: no, since it's a real source compile + multi-GB model download on Linux) — say yes and it runs exactly the steps below for you. On macOS the installer uses a Homebrew formula instead (`brew install whisper-cpp`), no compile needed there. The manual sequence below is for Linux, or for adding it later without re-running the installer.

The 🎤 Voice button transcodes mic audio with `ffmpeg` (already installed) and transcribes it locally with whisper.cpp.

    git clone https://github.com/ggerganov/whisper.cpp ~/whisper.cpp
    cd ~/whisper.cpp
    cmake -B build && cmake --build build -j --config Release
    # Grab a model — large-v3-turbo is the best balance and fits a 4 GB GPU:
    ./models/download-ggml-model.sh large-v3-turbo

- The cockpit auto-detects the binary (`whisper-cli`) and the largest installed `ggml-*.bin`. To pin specific paths, set them in `cockpit_data/whisper_config.json` (`bin`, `model`, `language`).
- Build with GPU support to use an AMD/NVIDIA card; CPU is fine for short clips.
- The web tier (www-data) must be able to read the binary + model under your home dir. If transcription says “permission denied”: `chmod -R a+rX ~/whisper.cpp`.

## C. Prism (syntax highlighting) — already vendored

No install needed. `prism.js` ships in the web root (offline, MIT). It is loaded with `Prism.manual = true` so it only highlights the cockpit’s code editor, not the chat console.

## D. New config files (created on first use)

Under `cockpit_data/`: `directives_global*.md`, `directives_config.json`, `claude_controls.json`, `gemini_controls.json`, `whisper_config.json`, `global_caps.json`, `help.json`. All are plain JSON/Markdown and editable in-app (the relevant panel’s edit button opens them in the floating editor).