From e8890f2364af007895145616354dd6a34eb8e0c6 Mon Sep 17 00:00:00 2001 From: plind-junior <59729252+plind-junior@users.noreply.github.com> Date: Fri, 12 Jun 2026 09:00:50 +0900 Subject: [PATCH] feat(desktop): vouch review-ui AppImage for ubuntu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bundles a relocatable cpython 3.12 + the [web] extra + the working-tree vouch source into a single ~33 mb .AppImage that double-clicks to launch the review-ui in the browser. first-run auto-inits ~/.vouch/ if absent. uses python-appimage as the builder; appdir lives at desktop/ alongside adapters/. ships .github/workflows/desktop.yml that builds and smoke-tests the AppImage on every push to main / release branch + attaches it as a release asset on version tags. adds src/vouch/__main__.py so the appimage entrypoint can call `python -m vouch review-ui` without depending on the console-script shim being on PATH. stacks on top of feat/194-review-ui (#195) — the review-ui module is the thing the desktop launcher wraps. --- .github/workflows/desktop.yml | 95 +++++++++++++++++++++++++++++++++ desktop/README.md | 83 ++++++++++++++++++++++++++++ desktop/entrypoint.sh | 19 +++++++ desktop/requirements.txt | 28 ++++++++++ desktop/vouch-review-ui.desktop | 11 ++++ desktop/vouch-review-ui.svg | 32 +++++++++++ src/vouch/__main__.py | 11 ++++ 7 files changed, 279 insertions(+) create mode 100644 .github/workflows/desktop.yml create mode 100644 desktop/README.md create mode 100644 desktop/entrypoint.sh create mode 100644 desktop/requirements.txt create mode 100644 desktop/vouch-review-ui.desktop create mode 100644 desktop/vouch-review-ui.svg create mode 100644 src/vouch/__main__.py diff --git a/.github/workflows/desktop.yml b/.github/workflows/desktop.yml new file mode 100644 index 00000000..2243c41d --- /dev/null +++ b/.github/workflows/desktop.yml @@ -0,0 +1,95 @@ +name: desktop + +# Build the vouch review-ui AppImage for Ubuntu/x86_64. +# +# Triggers: +# * push to main / a release branch — builds the AppImage so we know the +# desktop recipe stays buildable (artifact retained 7 days). +# * version tag (v*) — builds the AppImage and uploads it as a release +# asset alongside the wheel/sdist that `release.yml` already publishes. +# * manual dispatch — same as push. +# +# Note: `desktop/requirements.txt` currently uses `local+vouch` so the +# AppImage bundles the working-tree source. Once vouch-kb is published on +# PyPI with the [web] extra, swap to `vouch-kb[web]==` to pin the +# desktop artifact to a published release. + +on: + push: + branches: [main, release/*] + tags: ["v*"] + paths: + - "desktop/**" + - "src/vouch/**" + - ".github/workflows/desktop.yml" + pull_request: + paths: + - "desktop/**" + - "src/vouch/**" + - ".github/workflows/desktop.yml" + workflow_dispatch: + +permissions: + contents: write # only used by the release-upload step on tag events + +jobs: + build-appimage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + # python-appimage shells out to appimagetool, which needs FUSE on + # most distros — but ubuntu-latest images ship libfuse2 these days, + # so we just install python-appimage itself. + - name: install python-appimage + run: | + python -m pip install --upgrade pip + python -m pip install python-appimage + + # `local+vouch` in desktop/requirements.txt looks for an importable + # `vouch` module on the host Python — install the package editable so + # the bundler can find it. + - name: install vouch from working tree (for local+vouch) + run: python -m pip install -e . + + - name: build AppImage + run: | + python -m python_appimage build app desktop/ \ + --python-version 3.12 \ + --linux-tag manylinux2014_x86_64 + # python-appimage names the output after the appdir basename: + mv desktop-x86_64.AppImage vouch-review-ui-x86_64.AppImage || true + ls -la *.AppImage + + - name: smoke test (boots and serves /healthz) + run: | + ./vouch-review-ui-x86_64.AppImage --no-open-browser --bind 127.0.0.1:8851 & + APP_PID=$! + for i in 1 2 3 4 5 6 7 8 9 10; do + sleep 1 + if curl -sf http://127.0.0.1:8851/healthz; then + echo + echo "smoke test ok" + kill $APP_PID || true + exit 0 + fi + done + echo "smoke test failed: AppImage did not respond on /healthz" + kill $APP_PID || true + exit 1 + + - uses: actions/upload-artifact@v7 + with: + name: vouch-review-ui-x86_64.AppImage + path: vouch-review-ui-x86_64.AppImage + retention-days: 7 + + - name: attach to release + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v2 + with: + files: vouch-review-ui-x86_64.AppImage diff --git a/desktop/README.md b/desktop/README.md new file mode 100644 index 00000000..e825dde8 --- /dev/null +++ b/desktop/README.md @@ -0,0 +1,83 @@ +# vouch — desktop AppImage + +Self-contained Ubuntu (x86_64) launcher for `vouch review-ui`. One file. No +`apt install`. Double-click to start the browser-based review console. + +## What this directory is + +``` +desktop/ + requirements.txt # vouch-kb[web] (default) or local+vouch for pre-release + vouch-review-ui.desktop # Linux menu entry — Terminal=false, Categories=Development + vouch-review-ui.svg # scalable monograph icon + entrypoint.sh # auto-inits ~/.vouch/ on first run, hands off to `vouch review-ui` +``` + +The bundler is [`python-appimage`](https://github.com/niess/python-appimage), +which downloads a relocatable CPython, pip-installs the requirements into it, +wraps the `entrypoint.sh` in an AppRun, and emits a single `.AppImage`. + +## Build (release, from PyPI) + +```bash +pip install python-appimage +python -m python_appimage build app desktop/ \ + --python-version 3.12 \ + --linux-tag manylinux2014_x86_64 +# → desktop-x86_64.AppImage in cwd +mv desktop-x86_64.AppImage vouch-review-ui-x86_64.AppImage +chmod +x vouch-review-ui-x86_64.AppImage +``` + +Requires `vouch-kb[web]` to be published on PyPI — that lands once PR #195 +ships the `[web]` extra in the next vouch-kb release. + +## Build (pre-release, from local source tree) + +Until the next vouch-kb release, swap the requirements entry to bundle the +working-tree source: + +```bash +# in desktop/requirements.txt, replace `vouch-kb[web]` with: +local+vouch +# (plus any deps the [web] extra would pull): +fastapi>=0.115,<1 +jinja2>=3,<4 +python-multipart>=0.0.9 +uvicorn>=0.30,<1 + +# then build as above +python -m python_appimage build app desktop/ +``` + +## Launch + +```bash +./vouch-review-ui-x86_64.AppImage +# or double-click in the file manager +``` + +First launch creates `~/.vouch/` if it doesn't exist (an empty KB with the +starter claim), binds `127.0.0.1:7780`, and opens the browser to the review +queue. Override the KB location with `VOUCH_KB_PATH=/path/to/parent` in the +environment. + +## Stop + +The AppImage runs a foreground uvicorn process. Close the launching +terminal, or `pkill -f vouch-review-ui`. A system-tray quit menu is a +natural follow-up but out of scope for the first release. + +## What's not in this release (yet) + +- `.deb` package — the AppImage covers the Ubuntu story for now. +- Snap / Flatpak — needs separate confinement work; deferred. +- System-tray quit / auto-start on login — needs a native shell (Tauri/Electron); deferred. +- Auto-update — once the GH Actions release workflow lands, [AppImageUpdate](https://github.com/AppImage/AppImageUpdate) can sit on top. +- ARM64 / aarch64 builds — `--linux-tag manylinux2014_aarch64` once we have a runner. + +## How the install + run resembles `pipx install vouch-kb` + +Same Python, same `vouch` command, same `.vouch/` layout — the AppImage is +just a bundled CPython + entry-point. Power users keep using `pipx`; the +AppImage is for users who want a single download and a menu entry. diff --git a/desktop/entrypoint.sh b/desktop/entrypoint.sh new file mode 100644 index 00000000..3d94bda5 --- /dev/null +++ b/desktop/entrypoint.sh @@ -0,0 +1,19 @@ +#! /bin/bash +# vouch review-ui desktop launcher. +# +# When the AppImage is started from a .desktop entry there is no shell +# context, no project cwd, no `.vouch/` to discover — so on first launch we +# init a KB in $HOME (or VOUCH_KB_PATH if set) and then hand off to the +# normal `vouch review-ui` command, which opens the browser to the queue. + +set -e + +KB_ROOT="${VOUCH_KB_PATH:-$HOME}" +PYTHON="{{ python-executable }}" + +if [ ! -d "$KB_ROOT/.vouch" ]; then + mkdir -p "$KB_ROOT" + "$PYTHON" -I -m vouch init --path "$KB_ROOT" >/dev/null +fi + +exec "$PYTHON" -I -m vouch review-ui --kb "$KB_ROOT" "$@" diff --git a/desktop/requirements.txt b/desktop/requirements.txt new file mode 100644 index 00000000..caffb6e1 --- /dev/null +++ b/desktop/requirements.txt @@ -0,0 +1,28 @@ +# python-appimage installs these into the bundled CPython at build time. +# +# This file currently uses the PRE-RELEASE pattern: `local+vouch` bundles +# the working-tree source so the AppImage builds even before vouch-kb cuts +# a release that ships the [web] extra (PR #195). The explicit [web] +# dependencies below match what `pip install vouch-kb[web]` would pull. +# +# Once vouch-kb is published on PyPI with the [web] extra, swap to: +# vouch-kb[web] +# and delete the explicit lines below. +# +# Note: avoid `<` in version specifiers — python-appimage runs pip via +# shell=True with unquoted args, so `<1` would be parsed as a redirect. + +local+vouch + +# [web] extra (explicit until vouch-kb's published version ships it) +fastapi>=0.115 +jinja2>=3 +python-multipart>=0.0.9 +uvicorn>=0.30 + +# vouch core runtime deps (normally pulled by `vouch-kb`, but `local+vouch` +# bypasses the wheel metadata) +pydantic>=2.13.4 +click>=8.4.0 +pyyaml>=6 +mcp>=1.0 diff --git a/desktop/vouch-review-ui.desktop b/desktop/vouch-review-ui.desktop new file mode 100644 index 00000000..93a8397b --- /dev/null +++ b/desktop/vouch-review-ui.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +Name=vouch +GenericName=Knowledge Base Review Console +Comment=Review agent-proposed claims and pages in the browser +Exec=AppRun +Icon=vouch-review-ui +Categories=Development;Office;Utility; +Keywords=knowledge-base;mcp;llm;agent;review;vouch; +Terminal=false +StartupNotify=false diff --git a/desktop/vouch-review-ui.svg b/desktop/vouch-review-ui.svg new file mode 100644 index 00000000..aa487070 --- /dev/null +++ b/desktop/vouch-review-ui.svg @@ -0,0 +1,32 @@ + + + vouch + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vouch/__main__.py b/src/vouch/__main__.py new file mode 100644 index 00000000..f16f3432 --- /dev/null +++ b/src/vouch/__main__.py @@ -0,0 +1,11 @@ +"""Enable ``python -m vouch``. + +The console-script entry-point (`vouch = vouch.cli:cli`) is the canonical +surface, but the desktop AppImage launcher (and any environment that +shadows entry points) needs `python -m vouch` to work too. One-liner shim. +""" + +from .cli import cli + +if __name__ == "__main__": + cli()