Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/workflows/desktop.yml
Original file line number Diff line number Diff line change
@@ -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]==<version>` 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Rename the AppImage name that python-appimage actually emits

I checked python-appimage's build code and appimagetool behavior: when no explicit destination is supplied, the output name is derived from the bundled desktop entry's Name= field (this recipe sets Name=vouch), so this build produces vouch-x86_64.AppImage, not desktop-x86_64.AppImage. Because this mv is allowed to fail, the following smoke test and release upload still look for vouch-review-ui-x86_64.AppImage, causing the desktop workflow/tag release to fail before publishing the artifact.

Useful? React with 👍 / 👎.

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 &

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Install FUSE before executing the AppImage

On ubuntu-latest (now Ubuntu 24.04), the runner image's documented apt package list does not include libfuse2/libfuse2t64, while AppImages still require FUSE/libfuse to execute normally. After the filename issue is fixed, this direct smoke-test launch will fail on the hosted runner with the usual libfuse.so.2/FUSE error unless the workflow installs the FUSE 2 compatibility package or runs the extracted AppRun instead.

Useful? React with 👍 / 👎.

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
83 changes: 83 additions & 0 deletions desktop/README.md
Original file line number Diff line number Diff line change
@@ -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.
19 changes: 19 additions & 0 deletions desktop/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -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" "$@"
28 changes: 28 additions & 0 deletions desktop/requirements.txt
Original file line number Diff line number Diff line change
@@ -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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid unquoted version specifiers in AppImage requirements

For python-appimage recipes, each requirement is passed through python_appimage.utils.system(), which joins arguments into a shell command and runs it with shell=True; as a result fastapi>=0.115 is parsed by the shell as the package name fastapi with stdout redirected to =0.115. This means the AppImage build silently ignores the intended version bounds for these dependencies and can bundle future incompatible releases even though the requirements file appears constrained.

Useful? React with 👍 / 👎.

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
11 changes: 11 additions & 0 deletions desktop/vouch-review-ui.desktop
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions desktop/vouch-review-ui.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/vouch/__main__.py
Original file line number Diff line number Diff line change
@@ -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()
Loading