Skip to main content

Disposable Anki profile, add-on install, Docker/Xvfb, and GUI workbench tooling for add-on and deck development.

Project description

๐Ÿ”ฌ anki-addon-workbench

Headless, disposable-profile testing & cross-platform GUI tooling for Anki add-on and deck development.

PyPI Python versions CI License: MIT Platforms

Disposable Anki profile, add-on install, Docker/Xvfb, smoke-test, and GUI workbench tooling for Anki add-on and deck development.

It helps an agent or developer launch Anki away from a real profile, install the add-on under test, run a probe add-on, capture marked screenshots, and send mouse or keyboard input โ€” locally on macOS/Linux or inside a virtual display.

The first target users are add-on authors who want to make GUI work less manual without risking their daily Anki profile, and deck authors who need to see how cards actually render inside Anki (where JavaScript and styling can behave differently than in a browser) without manually closing and reopening Anki โ€” which triggers a sync round-trip each time.

How it works

        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚    live Anki     โ”‚  move ยท click ยท type   โ”‚    screenshot    โ”‚
        โ”‚    disposable    โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ โ”‚  cursor-marked   โ”‚
        โ”‚     profile      โ”‚      (pyautogui)       โ”‚   .png + .json   โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                  โ–ฒ                                           โ”‚
                  โ”‚           agent reads & decides           โ”‚
                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

A disposable Anki the agent drives, screenshots, and adjusts โ€” no profile risk, no sync churn.

Install

From PyPI:

# core smoke/profile/Docker tooling only (dependency-light)
uv add anki-addon-workbench

# include the GUI primitives (pyautogui + Pillow) for screenshot/move/click/type
uv add 'anki-addon-workbench[gui]'

(pip install 'anki-addon-workbench[gui]' works too.)

The GUI extra is optional: the core smoke, launch (without screenshots), profile, and dockerfile tooling has no heavy dependencies. The screenshot/pointer/keyboard commands lazy-load pyautogui + Pillow and fail with a clear install hint if the [gui] extra is missing.

Platform notes. GUI primitives are cross-platform via pyautogui:

  • macOS โ€” works against your local /Applications/Anki.app; grant Terminal (or your runner) Screen Recording and Accessibility permission once.
  • Linux/Xvfb โ€” works headless; pyautogui uses scrot + python-xlib (installed by the bundled Docker image).

Configure An Add-On

Add this to the add-on project's pyproject.toml:

[tool.anki-addon-workbench]
project_name = "My Add-on"
addon_package = "my_addon"
source_root = "."
include = ["__init__.py", "manifest.json", "README.md"]
exclude = ["tests", "user_files", ".git", "__pycache__"]
seed_apkgs = []
probe_addon = "tests/gui_smoke/probe_addon"
anki_version = "25.09"
profile = "User 1"
docker_image = "my-addon-anki-gui"
# Optional. Override when dogfooding an unreleased workbench build.
docker_workbench_spec = "anki-addon-workbench[gui]"

If the project does not have a pyproject.toml, place the same keys in anki-workbench.toml.

For deck-only projects, omit addon_package and point seed_apkgs at one or more generated .apkg files:

[tool.anki-addon-workbench]
project_name = "My Deck"
seed_apkgs = ["out/my-deck.apkg"]
probe_addon = "tests/gui_smoke/probe_addon"
anki_version = "25.09"
docker_image = "my-deck-anki-gui"

The workbench imports those packages into the disposable profile before Anki's GUI starts, so probes and agent-driven launches can inspect the generated deck without touching a real collection.

CLI

anki-workbench doctor
anki-workbench smoke
anki-workbench launch --xvfb --pointer 500,180 --keep
anki-workbench screenshot --out .tmp/shot.png --meta .tmp/shot.json
anki-workbench move 500 180
anki-workbench click
anki-workbench key Escape
anki-workbench type "search text"
anki-workbench dockerfile --out tests/gui_smoke/Dockerfile
anki-workbench docker-smoke-local --uv-command "sfw uv"
anki-workbench init-probe --out tests/gui_smoke/probe_addon

smoke installs the configured add-on and optional probe add-on into a disposable base folder, seeds the profile so the first-run language dialog does not appear, launches Anki, waits for the probe to write JSON, prints the JSON, and removes the base folder unless --keep is passed.

launch starts disposable Anki without the probe add-on so an agent can inspect and interact with the live GUI. It can start Xvfb, wait for the Anki window, move the pointer, and capture a cursor-marked screenshot.

All commands print JSON. The screenshot command draws a high-contrast synthetic marker at the pointer (headless screenshots do not include the real cursor), which is far more reliable than depending on the display server to render it.

type is ASCII-oriented. It uses pyautogui's keystroke synthesis, which reliably types ASCII and common keys but cannot reliably type non-ASCII text (e.g. CJK, accented characters) โ€” those need an input method the synthetic keystrokes bypass. For non-Latin search/input, set the field value through Anki/AnkiConnect rather than type. (This is a regression from the old xdotool type backend, traded for cross-platform support.)

The Probe Contract

smoke works by installing a small probe add-on alongside the add-on under test. When Anki finishes starting, the probe writes a JSON result to the path in the ANKI_ADDON_WORKBENCH_RESULT environment variable and then exits Anki. The runner reads that file, prints it, and uses ok for its exit status.

Scaffold one in one command โ€” you rarely need to write a probe by hand:

anki-workbench init-probe --out tests/gui_smoke/probe_addon

This writes a documented, self-contained __init__.py with a run_checks() function to edit. Then point probe_addon at that directory in your config.

The result contract:

Field Type Meaning
ok bool Required. Whether the probe's checks passed.
checks list Optional. [{"name": str, "ok": bool, ...}] per-check detail.
anything else json Optional. Echoed back verbatim in the smoke output.

The runner validates that ok is present and boolean; if a probe forgets it (or never writes / never exits, which times out), the smoke output says exactly what went wrong and points you back to init-probe. A probe may also read ANKI_ADDON_WORKBENCH_SCREENSHOT for a path to capture a screenshot to.

Docker/Xvfb

Render the reusable Anki launcher image template in the add-on project:

anki-workbench dockerfile --out tests/gui_smoke/Dockerfile

Then build it and run it with the add-on project mounted:

docker build -f my-addon/tests/gui_smoke/Dockerfile -t my-addon-anki-gui my-addon
docker run --rm -v "$PWD":/workspace -w /workspace/my-addon my-addon-anki-gui

The image installs the Anki Linux launcher, Xvfb, xdotool, scrot, QtWebEngine runtime libraries, Python, and the configured workbench package spec (anki-addon-workbench[gui] by default). The Anki binary path is provided via the ANKI_BIN environment variable (set in the image), not hardcoded in the library. The workbench itself is installed into the image, so generated Dockerfiles are standalone and do not require a sibling source checkout.

When dogfooding an unreleased workbench build, either set docker_workbench_spec in [tool.anki-addon-workbench] or pass an override:

anki-workbench dockerfile \
  --out tests/gui_smoke/Dockerfile \
  --workbench-spec "anki-addon-workbench[gui] @ https://github.com/elvis-sik/anki-addon-workbench/archive/<commit>.zip"

For workbench maintainers, the higher-level local-wheel path avoids publishing or pushing before testing:

anki-workbench docker-smoke-local --uv-command "sfw uv"

It builds a wheel from --workbench-source (default: .), creates a small Docker build context containing that wheel, renders a Dockerfile that installs the wheel with [gui], builds the configured image with a -local suffix, and runs the configured smoke test with the project mounted at /workspace. Artifacts and command logs are written under .tmp/anki-workbench-local.

Development

make check
make docker-smoke-local

Tests run on pytest (make test) and cover config loading, add-on copy filtering, profile seeding, command construction, Dockerfile rendering, probe scaffolding, and the GUI marker rendering. Docker GUI smoke tests are kept behind explicit CI commands because Anki launcher downloads and QtWebEngine startup are comparatively slow. make docker-smoke-local is the maintainer confidence check for unreleased workbench changes: it installs the local wheel into the generated Docker image instead of pulling the published PyPI package.

Releasing

Releases publish to PyPI via GitHub Actions using Trusted Publishing (OIDC) โ€” no API token is stored. To cut a release:

# 1. bump `version` in pyproject.toml, commit
# 2. tag and push โ€” the tag must match the version
git tag v0.3.1
git push origin v0.3.1

The release.yml workflow checks that the tag matches pyproject.toml, builds the sdist + wheel with uv build, and publishes.

One-time setup on PyPI (Account โ†’ Publishing โ†’ Add a pending publisher):

  • PyPI Project Name: anki-addon-workbench
  • Owner / Repository: your GitHub org/repo
  • Workflow name: release.yml
  • Environment name: pypi

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

anki_addon_workbench-0.3.1.tar.gz (71.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

anki_addon_workbench-0.3.1-py3-none-any.whl (33.2 kB view details)

Uploaded Python 3

File details

Details for the file anki_addon_workbench-0.3.1.tar.gz.

File metadata

  • Download URL: anki_addon_workbench-0.3.1.tar.gz
  • Upload date:
  • Size: 71.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for anki_addon_workbench-0.3.1.tar.gz
Algorithm Hash digest
SHA256 8e4498ee22fa52c0713cd83b83dc81dbed335361ca2ba34c8a67cd44b18fd23e
MD5 bc3f647046f09f6a80670c8c03d9426e
BLAKE2b-256 b7093f70ae78bd064e11c74f65f741fb2e7dd69b5196d44c6130d72221ed47dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for anki_addon_workbench-0.3.1.tar.gz:

Publisher: release.yml on elvis-sik/anki-addon-workbench

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anki_addon_workbench-0.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for anki_addon_workbench-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 854588cf42edafcc7abf0fc02a8a5cdff9a8369f4d0ba2a9d7e953c1dc2448c3
MD5 9b8490c9df6deb771697ffe19229c088
BLAKE2b-256 ed97f1d6d5fd3030b7d2fa89d51e0363b4fd1cb5f38397ca4c4b78eae71b73b0

See more details on using hashes here.

Provenance

The following attestation bundles were made for anki_addon_workbench-0.3.1-py3-none-any.whl:

Publisher: release.yml on elvis-sik/anki-addon-workbench

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page