netlinux-ai

Package Build & Deployment Infrastructure for packages.netlinux.co.uk

Overview

packages.netlinux.co.uk is a Debian APT repository serving custom-built amd64 packages. Source code lives in GitHub repos under the netlinux-ai organisation. Packages are built automatically by GitHub Actions on every push to main, published as GitHub Releases, then pulled into the server's reprepro repository via a webhook.

Suites

The repository serves two suites with distinct target distributions:

CodenameTargetapt line
stable Debian 12 (bookworm) — used by NetLinux Desktop / Server deb https://packages.netlinux.co.uk/debian stable main
resolute Ubuntu 26.04 LTS (“Resolute Raccoon”) deb https://packages.netlinux.co.uk/debian resolute main

Packages reach these suites by two complementary pipelines:

Developer pushes to main
github.com/netlinux-ai/*
GitHub Actions
ubuntu-24.04 runner — .github/workflows/release-deb.yml
  1. Install build dependencies
  2. Build from source (cmake / make / meson)
  3. checkinstall.deb
  4. Repack zstd → xz (reprepro compatibility)
  5. Create GitHub Release with .deb asset
  6. POST HMAC-SHA256 signed webhook
Webhook
HTTPS POST → Apache ProxyPass → listener.py :9090
update-repo.sh
packages.netlinux.co.uk
  1. Download .deb from GitHub Release API
  2. Repack zstd → xz if needed (safety net)
  3. reprepro remove old version
  4. reprepro includedeb → GPG signs & indexes
  5. Update HTML index pages
Available via APT
sudo apt update && sudo apt install <package>

Server

Host
packages.netlinux.co.uk
Provider
DigitalOcean
OS
Debian (amd64)
Web Server
Apache2 + Let's Encrypt
Repo Tool
reprepro
SSH
root@packages.netlinux.co.uk

Apache vhost (relevant section)

apache<VirtualHost *:80 *:443>
    ServerName packages.netlinux.co.uk
    ServerAlias packages.netlinux.org.uk
    DocumentRoot /Sites/netlinux/packages

    <Directory "/Sites/netlinux/packages">
        Options +Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ProxyPass /webhook/ http://127.0.0.1:9090/
    ProxyPassReverse /webhook/ http://127.0.0.1:9090/

    SSLCertificateFile /etc/letsencrypt/live/packages.netlinux.co.uk/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/packages.netlinux.co.uk/privkey.pem
</VirtualHost>

Directory layout

/Sites/netlinux/packages/
├── index.html                          # Landing page with package table
├── netlinux-ai.md                      # This document (markdown)
├── netlinux-ai.html                    # This document (HTML)
├── webhook/
│   ├── listener.py                     # Python webhook HTTP server
│   └── update-repo.sh                  # Downloads .deb, adds to reprepro
└── debian/                             # reprepro repository root
    ├── conf/
    │   ├── distributions              # reprepro config
    │   └── options
    ├── repo-key.gpg                    # Exported GPG public key
    ├── db/                             # reprepro database
    ├── dists/stable/                # Debian bookworm-targeted indexes
    │   ├── Release / Release.gpg / InRelease
    │   └── main/binary-amd64/
    │       └── Packages / Packages.gz
    ├── dists/resolute/              # Ubuntu 26.04-targeted indexes
    │   ├── Release / Release.gpg / InRelease
    │   └── main/binary-amd64/
    │       └── Packages / Packages.gz
    └── pool/main/                    # shared by both suites
        ├── g/gimp/
        ├── k/kio-extras/
        ├── k/kio-rsync/
        ├── k/konqueror/
        ├── l/linux-upstream/
        ├── p/pavucontrol/
        ├── q/qpwgraph/
        ├── r/rsync/
        ├── s/simplescreenrecorder/
        ├── t/tightvnc/
        └── x/xfce4-panel/

Reprepro Configuration

conf/distributions

iniOrigin: NetLinux
Label: NetLinux
Codename: stable
Architectures: amd64
Components: main
Description: NetLinux custom packages repository
SignWith: default

Origin: NetLinux
Label: NetLinux
Codename: resolute
Suite: resolute
Architectures: amd64
Components: main
Description: NetLinux packages for Ubuntu 26.04 LTS (Resolute Raccoon)
SignWith: default

Both suites share the same pool/ directory on disk. Because bookworm and resolute builds use different Debian version suffixes (~bookworm1 / ~resolute1), two targeted builds of the same upstream coexist in the pool without collision.

conf/options

verbose
basedir /Sites/netlinux/packages/debian

GPG signing key

🔑
pub   rsa4096/3F9A57A88A3D96CA  2026-02-17  [SCEA]
      EA339EE150E13D30D568F9353F9A57A88A3D96CA
uid   [ultimate] NetLinux Packages <packages@netlinux.org.uk>

Public key served at /debian/repo-key.gpg. reprepro auto-signs Release files on every includedeb.

NetLinux Desktop

NetLinux Desktop is a Debian bookworm-based live ISO that bundles all NetLinux packages into a ready-to-use desktop distribution.

DetailValue
Current releasev0.1 (25 February 2026)
BaseDebian 12 (bookworm)
DesktopXfce 4 with LightDM
Kernel6.19.0 (custom NetLinux build)
InstallerCalamares graphical installer
ISO size~1.3 GB
Build toolDebian live-build
Meta-packagenetlinux-desktop
Sourcenetlinux-ai/netlinux-desktop
Release pagepackages.netlinux.co.uk/netlinux.html

The ISO is built with live-build using the scripts in the netlinux-desktop repo. It pulls packages from both the Debian bookworm repos and the NetLinux APT repository. APT pinning ensures NetLinux packages take priority where available.

Build: sudo ./build.sh (requires Debian/Ubuntu host, ~20 GB free space).

NetLinux Server

NetLinux Server is a minimal headless Debian bookworm-based live ISO with Docker, firewall, monitoring, and SSH pre-configured for server deployments.

DetailValue
BaseDebian 12 (bookworm)
DesktopNone (headless)
Kernel6.19.0 (custom NetLinux build)
ServicesOpenSSH, Docker, UFW, fail2ban, unattended-upgrades
ISO size~532 MB
Build toolDebian live-build
Meta-packagenetlinux-server
Sourcenetlinux-ai/netlinux-server
Release pagepackages.netlinux.co.uk/netlinux.html

No desktop environment, no GUI — just a hardened server baseline with SSH, Docker, and firewall enabled out of the box. The netlinux-server meta-package can also be installed on any Debian bookworm system via apt.

Build: sudo ./build.sh (requires Debian/Ubuntu host, ~15 GB free space).

Current Packages

PackageGitHub RepoPool DirDescription
kio-extras netlinux-ai/kio-extras k/kio-extras KDE KIO workers (sftp, smb, mtp, rsync, etc.)
kio-rsync netlinux-ai/kio-rsync k/kio-rsync KIO worker for rsync:// in KDE
gimp netlinux-ai/gimp g/gimp GIMP 3.0 image editor (bundled babl/GEGL)
konqueror netlinux-ai/konqueror k/konqueror KDE web browser and file manager
linux-image-* netlinux-ai/linux l/linux-upstream Custom upstream kernel image
linux-headers-* netlinux-ai/linux l/linux-upstream Kernel headers
pavucontrol netlinux-ai/pavucontrol p/pavucontrol PulseAudio Volume Control
qpwgraph netlinux-ai/qpwgraph q/qpwgraph PipeWire graph manager
rsync netlinux-ai/rsync r/rsync Fast file synchronisation utility (3.4.x)
simplescreenrecorder netlinux-ai/ssr s/simplescreenrecorder Screen recorder for X11/OpenGL
tightvnc netlinux-ai/tightvnc t/tightvnc TightVNC server and viewer
xfce4-panel netlinux-ai/xfce4-panel x/xfce4-panel Xfce4 desktop panel

GitHub Actions Workflow

Every repo under netlinux-ai that produces a .deb has a workflow at .github/workflows/release-deb.yml. The structure is the same across all repos, with build steps varying per project.

Template workflow

yamlname: Build .deb package

on:
  push:
    branches: [main]

permissions:
  contents: write

jobs:
  build:
    runs-on: ubuntu-24.04

    steps:
      - uses: actions/checkout@v4

      - name: Install build dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y <project-specific-deps>

      - name: Build
        run: |
          # Project-specific build commands
          # e.g. cmake -B build -DCMAKE_INSTALL_PREFIX=/usr && cmake --build build

      - name: Determine version
        id: version
        run: |
          rev=${{ github.run_number }}
          echo "version=<base>-${rev}netlinux1" >> "$GITHUB_OUTPUT"
          echo "tag=v<base>-${rev}netlinux1" >> "$GITHUB_OUTPUT"

      - name: Package with checkinstall
        run: |
          sudo apt-get install -y checkinstall
          sudo checkinstall --default \
            --pkgname=<package-name> \
            --pkgversion="${{ steps.version.outputs.version }}" \
            --maintainer="graham@netlinux.co.uk" \
            --requires="<runtime-deps>" \
            --pakdir=. --install=no --fstrans=no \
            <install-command>

      - name: Repack .deb for reprepro compatibility
        run: |
          DEB=$(ls <package-name>_*.deb)
          sudo chmod 666 "$DEB"
          mkdir repack && cd repack
          ar x "../$DEB"
          for f in *.zst; do
            [ -f "$f" ] || continue
            zstd -d "$f"; xz "${f%.zst}"; rm "$f"
          done
          rm "../$DEB"
          ar rcs "../$DEB" debian-binary control.tar.xz data.tar.xz

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ steps.version.outputs.tag }}
          name: <package-name> ${{ steps.version.outputs.version }}
          files: <package-name>_*.deb
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Notify package repository
        run: |
          sleep 5
          SIGNATURE=$(echo -n '...' \
            | openssl dgst -sha256 -hmac "${{ secrets.WEBHOOK_SECRET }}" \
              -binary | xxd -p -c 256)
          curl -sf -X POST \
            -H "Content-Type: application/json" \
            -H "X-Webhook-Signature: sha256=${SIGNATURE}" \
            -d '{"repo":"netlinux-ai/<repo>","tag":"..."}' \
            https://packages.netlinux.co.uk/webhook/update-repo

Key details

Required GitHub secrets

SecretPurpose
GITHUB_TOKENAutomatic — used by action-gh-release to create releases
WEBHOOK_SECRETShared HMAC secret for authenticating webhook calls
bashgh secret set WEBHOOK_SECRET --repo netlinux-ai/<repo>

The same shared secret is used across all repos. Its value is configured in the systemd service on the server.

Webhook System

Systemd service

ini# /etc/systemd/system/repo-webhook.service
[Unit]
Description=Package repository webhook listener
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /Sites/netlinux/packages/webhook/listener.py
Environment=WEBHOOK_SECRET=<shared-secret>
Environment=PORT=9090
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Manage with: systemctl {start,stop,restart,status} repo-webhook

listener.py

A minimal Python HTTP server on 127.0.0.1:9090 (not exposed directly — Apache proxies /webhook/ to it).

EndpointMethodPurpose
/update-repoPOSTValidates HMAC-SHA256 signature, runs update-repo.sh <tag> <repo>
/healthGETReturns 200 OK (monitoring)

Signature verified by computing HMAC-SHA256(request_body, WEBHOOK_SECRET) and comparing against the X-Webhook-Signature: sha256=<hex> header. Logs to /var/log/repo-webhook.log.

update-repo.sh

The main deployment script. Called as: update-repo.sh <tag> <github-repo>

  1. Maps github-repo to PKG_NAME and POOL_DIR via a case statement
  2. Fetches release metadata from GitHub API to find the .deb asset URL
  3. Downloads the .deb
  4. If the .deb contains zstd members, repacks to xz (safety net)
  5. Removes any old version: reprepro remove stable <pkg>
  6. Adds the new version: reprepro includedeb stable <deb>
  7. Looks up the actual filename in the pool (handles checkinstall's -1 suffix)
  8. Updates the pool's index.html with the new version/filename
  9. Updates the main /Sites/netlinux/packages/index.html

Repo whitelist (case statement)

Must be updated when adding a new package:

bashcase "$GITHUB_REPO" in
    netlinux-ai/ssr|"")        PKG_NAME="simplescreenrecorder"; POOL_DIR="s/simplescreenrecorder" ;;
    netlinux-ai/qpwgraph)      PKG_NAME="qpwgraph";             POOL_DIR="q/qpwgraph" ;;
    netlinux-ai/tightvnc)      PKG_NAME="tightvnc";             POOL_DIR="t/tightvnc" ;;
    netlinux-ai/pavucontrol)   PKG_NAME="pavucontrol";          POOL_DIR="p/pavucontrol" ;;
    netlinux-ai/xfce4-panel)   PKG_NAME="xfce4-panel";          POOL_DIR="x/xfce4-panel" ;;
    netlinux-ai/kio-rsync)     PKG_NAME="kio-rsync";            POOL_DIR="k/kio-rsync" ;;
    netlinux-ai/rsync)         PKG_NAME="rsync";                POOL_DIR="r/rsync" ;;
    netlinux-ai/kio-extras)    PKG_NAME="kio-extras";           POOL_DIR="k/kio-extras" ;;
    netlinux-ai/konqueror)     PKG_NAME="konqueror";            POOL_DIR="k/konqueror" ;;
    netlinux-ai/gimp)          PKG_NAME="gimp";                 POOL_DIR="g/gimp" ;;
    netlinux-ai/linux)         IS_KERNEL=true;                   POOL_DIR="l/linux-upstream" ;;
    *)                         log "ERROR: Unknown repo"; exit 1 ;;
esac
⚠️
Kernel packages (netlinux-ai/linux) are handled specially because they produce multiple .deb files (linux-image, linux-headers, linux-libc-dev) with version numbers embedded in the package name.
📝
Note on suites: update-repo.sh currently publishes every webhook-triggered build into the stable suite only. resolute is populated by the nightly pipeline below. If you need a just-pushed package in resolute before the next nightly, either re-run the nightly manually on dev2 or run reprepro -b /Sites/netlinux/packages/debian copy resolute stable <pkg> to copy the existing bookworm-compat .deb into resolute as a temporary stand-in.

Nightly Dual-Build Pipeline

A second pipeline runs on dev2 (147.182.205.211) at 03:00 UTC via cron and is the only source of resolute suite builds. It lives at /home/graham/nightly/ (see README.md there for the full runbook).

Flow

Developer pushes to main
         |
         └─────> GitHub Actions (as documented above) → stable suite


dev2 cron @ 03:00 UTC
         |
         v
nightly-packages.sh
         |
         ├──> build-images.sh     (refresh netlinux-build:{bookworm,resolute}
         |                       Docker images if >14 days old)
         |
         v
  For each repo in repos.conf (if GitHub has new commits):
         |
         ├──> Clone once into build/<repo>/src/
         |
         ├──> docker run --rm --network host \
         |        -v src:/src -v output:/output \
         |        netlinux-build:bookworm \
         |        brain-code-agent --prompt "..."
         |                → .deb tagged ~bookworm1
         |                → publish_deb to suite=stable
         |
         └──> docker run --rm --network host \
                  -v src:/src -v output:/output \
                  netlinux-build:resolute \
                  brain-code-agent --prompt "..."
                          → .deb tagged ~resolute1
                          → publish_deb to suite=resolute

Key properties

Configuring the server side (one-time)

On dev2 (in /home/graham/nightly):

bash./add-resolute-suite.sh      # ssh's to packages server, appends resolute
                             # codename to conf/distributions, reprepro export
./build-images.sh            # docker builds netlinux-build:{bookworm,resolute}
./prepare-resolute-vm.sh     # downloads + customises the test VM image

After these, ./nightly-packages.sh dual-builds and dual-publishes.

Adding a New Package

  1. Create the GitHub repo under netlinux-ai:
    gh repo create netlinux-ai/<name> --public --description "<description>"
  2. Add source code and .github/workflows/release-deb.yml following the template. Customise: build dependencies, build commands, --pkgname, --requires, install command, version base string, and repo name in the webhook payload.
  3. Set the webhook secret on the repo:
    gh secret set WEBHOOK_SECRET --repo netlinux-ai/<name>
    Use the same shared secret as other repos.
  4. On the server, add the new package to update-repo.sh:
    ssh root@packages.netlinux.co.uk
    vi /Sites/netlinux/packages/webhook/update-repo.sh
    # Add a new case entry:
    netlinux-ai/<name>)
        PKG_NAME="<package-name>"
        POOL_DIR="<first-letter>/<package-name>"
        ;;
  5. Create the pool directory and index page on the server:
    mkdir -p /Sites/netlinux/packages/debian/pool/main/<first-letter>/<package-name>/

    Create an index.html in that directory. Every pool index page must include the following sections:

    • Breadcrumb — link back to the main packages page
    • Package name and description — what this package is
    • “Why this build?” box — a green highlighted box (.why class) explaining why someone should use the NetLinux version instead of the distro package. This is the most important section. It should include:
      • What version the distro ships and what version NetLinux provides
      • Specific improvements: security fixes, new features, bug fixes, or patches unique to the NetLinux build
      • For entirely new packages (no distro equivalent), explain what gap this fills and what capabilities it provides
    • Comparison table (where applicable) — a side-by-side feature comparison between the distro version and the NetLinux version, using the .compare class
    • Package details table — version, architecture, component, download link, upstream/source links
    • Install instructionssudo apt install command and link to the main page for repository setup

    Use an existing pool page (e.g. rsync) as a template. The .why box uses background: #e8f5e9; border: 1px solid #a5d6a7 styling and a <h3>Why this build?</h3> heading in color: #2e7d32. The version and download filename will be updated automatically by update-repo.sh on every successful build.

  6. Add a row to the main index.html at /Sites/netlinux/packages/index.html.

    The main index page has the following structure (in order):

    • Title and description — “NetLinux Packages” heading with tagline
    • “Why NetLinux?” box — green .why box explaining the value of the repository: upstream tracking, security-first approach, restored packages, and the AI-assisted development model with security/stability guardrails
    • Quick setupcurl + apt commands to add the repo and install
    • Available packages table — one row per package with columns: Package (linking to pool index page), Version (linking to .deb), Description, Source (linking to GitHub repo)
    • Repository details — URL, architectures, signing key, browse links
    • Disclaimer note — packages provided as-is, not affiliated with Debian

    Add a new row to the “Available packages” table. The version and filename will be updated automatically by update-repo.sh on the first successful build.

  7. Push to main — the GitHub Action will build, release, and trigger the webhook. The package will appear in the repo within seconds.
  8. Verify:
    sudo apt update
    apt policy <package-name>
    sudo apt install <package-name>

Client Setup

Pick the suite that matches your host distribution. The signing key and install flow are identical — only the deb line's codename differs.

Common: import the signing key

bashcurl -fsSL https://packages.netlinux.co.uk/debian/repo-key.gpg \
  | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/netlinux.gpg

Debian bookworm / NetLinux Desktop / NetLinux Server

bashecho "deb https://packages.netlinux.co.uk/debian stable main" \
  | sudo tee /etc/apt/sources.list.d/netlinux.list

sudo apt update
sudo apt install <package-name>
📌
APT source line: deb https://packages.netlinux.co.uk/debian stable main

Ubuntu 26.04 LTS (Resolute Raccoon)

bashecho "deb https://packages.netlinux.co.uk/debian resolute main" \
  | sudo tee /etc/apt/sources.list.d/netlinux.list

sudo apt update
sudo apt install <package-name>
📌
APT source line: deb https://packages.netlinux.co.uk/debian resolute main

Other distributions (Debian 13, Ubuntu 24.04, etc.)

Start with the stable suite — most packages link only against Debian bookworm's libraries and will install on Debian 13 / recent Ubuntu releases without issue. If you hit a dependency version mismatch, file an issue; the nightly pipeline can be extended with an additional target.

Useful Commands

On the server

bash# List all packages in a suite (swap 'stable' for 'resolute' as needed)
reprepro -b /Sites/netlinux/packages/debian list stable
reprepro -b /Sites/netlinux/packages/debian list resolute

# Manually add a .deb to a specific suite
reprepro -b /Sites/netlinux/packages/debian includedeb stable /path/to/file.deb
reprepro -b /Sites/netlinux/packages/debian includedeb resolute /path/to/file.deb

# Remove a package from a specific suite
reprepro -b /Sites/netlinux/packages/debian remove stable <package-name>
reprepro -b /Sites/netlinux/packages/debian remove resolute <package-name>

# Copy a package version across suites (e.g. promote stable → resolute as stand-in)
reprepro -b /Sites/netlinux/packages/debian copy resolute stable <package-name>

# Regenerate Release/InRelease for both suites
reprepro -b /Sites/netlinux/packages/debian export

# Check webhook service
systemctl status repo-webhook
journalctl -u repo-webhook -f

# View webhook log
tail -f /var/log/repo-webhook.log

# Manually trigger an update (from anywhere) — publishes to 'stable' only
curl -sf -X POST \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Signature: sha256=$(echo -n '{"repo":"netlinux-ai/<repo>","tag":"latest"}' \
    | openssl dgst -sha256 -hmac '<secret>' -binary | xxd -p -c 256)" \
  -d '{"repo":"netlinux-ai/<repo>","tag":"latest"}' \
  https://packages.netlinux.co.uk/webhook/update-repo

On dev2 (nightly pipeline)

bash# Run the nightly dual-build immediately
/home/graham/nightly/nightly-packages.sh

# Just refresh the build-env containers
/home/graham/nightly/build-images.sh

# Smoke-test only (without rebuilding)
/home/graham/nightly/test-packages.sh \
    --build-num N --repos-conf /home/graham/nightly/repos.conf \
    --output /tmp/test.json --log-dir /tmp/logs

On GitHub

bash# Check latest release
gh release list --repo netlinux-ai/<repo>

# View workflow runs
gh run list --repo netlinux-ai/<repo>

# Set webhook secret on a new repo
gh secret set WEBHOOK_SECRET --repo netlinux-ai/<repo>

Known Issues & Gotchas

zstd vs xz

Ubuntu 24.04's checkinstall produces zstd-compressed .deb files. The server's reprepro requires xz. Both the GitHub Actions workflow and update-repo.sh include a repack step, but if you're manually adding a .deb, you must repack it first.

checkinstall -1 suffix

checkinstall appends -1 as a Debian release number to the version, so 1.0-2netlinux1 becomes 1.0-2netlinux1-1 in the filename. update-repo.sh handles this by looking up the actual filename in the pool with ls rather than constructing it.

First push after creating a repo

The WEBHOOK_SECRET must be set before the first push, otherwise the webhook notification step will fail (the build and release still succeed). If this happens, push again or manually trigger the webhook.

Pool directory naming

The pool directory path uses the package name (e.g. s/simplescreenrecorder), not the GitHub repo name (which may differ, e.g. ssr). The POOL_DIR in the case statement must match exactly.

Dual-build version collision

bookworm and resolute builds of the same upstream must carry different Debian version suffixes (~bookworm1 vs ~resolute1) so both .debs coexist in the shared pool. The nightly pipeline enforces this via the build prompt; a manual dpkg-deb invocation must do the same.

GHA-only packages won't reach resolute

Webhook-triggered builds only publish to stable. Until the nightly runs, apt update on a resolute client won't see a just-pushed upstream change. Run the nightly manually or reprepro copy resolute stable <pkg> to bridge.

Architecture Diagram

Two pipelines feed the same reprepro repo: GitHub Actions (push-triggered, publishes to stable) and the dev2 nightly (cron, dual-builds inside per-distro containers and publishes to both stable and resolute). Clients pick the suite that matches their host distro.

GitHub (netlinux-ai) kio-rsync tightvnc pavucontrol qpwgraph linux / ssr / ... push to main git clone (nightly 03:00 UTC) GitHub Actions (ubuntu-24.04) .github/workflows/release-deb.yml 1. apt install build-deps 2. cmake / make / meson build 3. checkinstall → .deb 4. repack zstd → xz 5. GitHub Release with .deb asset 6. HMAC-SHA256 signed webhook → publishes to: stable dev2 nightly (cron @ 03:00 UTC) /home/graham/nightly/nightly-packages.sh 1. check GitHub API for new commits 2. git clone → build/<repo>/src/ 3. docker run netlinux-build:bookworm 4. docker run netlinux-build:resolute     → brain-code-agent inside each 5. scp+reprepro includedeb <suite> → publishes to: stable + resolute HMAC POST /webhook/update-repo ssh root@packages.netlinux.co.uk scp .deb + reprepro includedeb packages.netlinux.co.uk Apache2 :443 TLS ProxyPass listener.py :9090 subprocess update-repo.sh curl API • download .deb • repack reprepro includedeb (→ stable only) /Sites/netlinux/packages/debian/ — reprepro repo (GPG-signed, xz-compressed) dists/stable/ Release / Packages.gz • GHA + nightly (bookworm) Target: Debian 12 • NetLinux Desktop/Server dists/resolute/ Release / Packages.gz • nightly (resolute) only Target: Ubuntu 26.04 LTS "Resolute Raccoon" shared pool/main/ — bookworm/resolute .debs coexist via ~bookworm1 / ~resolute1 version suffixes apt: stable main apt: resolute main Debian 12 / NetLinux Desktop • Server • bookworm hosts deb … stable main Ubuntu 26.04 LTS Resolute Raccoon hosts deb … resolute main Apache serves https://packages.netlinux.co.uk/debian/ to both client variants

Also available as netlinux-ai.md (plain markdown) • NetLinux DesktopNetLinux Servergithub.com/netlinux-aipackages.netlinux.co.uk