isard
Manage your IsardVDI virtual desktops on the Gencat educational platform
(elmeuescriptori.gestioeducativa.gencat.cat) from the command line.
isard login # authenticate (SAML + JWT)
isard list # your desktops
isard create dev # a desktop from a template
isard start dev # power on
isard view dev # open in virt-viewer
isard ssh dev # ssh into it
Install
uv tool install isard # recommended
pipx install isard
pip install isard
Requires Python 3.11 or newer. uv tool install fetches a suitable
Python for you if the system one is older.
Upgrade the same way you installed:
uv tool upgrade isard
pipx upgrade isard
pip install --upgrade isard
Authenticate
Running any command prompts for your credentials. To skip the prompt, set them in the environment:
export GENCAT_USERNAME="12345678a" # @edu.gencat.cat is added for you
export GENCAT_PASSWORD="your-password"
…or drop a .env file in your working directory:
GENCAT_USERNAME=12345678a
GENCAT_PASSWORD=your-password
Sessions are cached in ~/.config/isard/ (%APPDATA%\isard\ on
Windows) with chmod 600, and refresh themselves when they expire.
isard logout clears them.
Commands
| Command | Description | Options |
|---|---|---|
login |
Authenticate and display session info | — |
logout |
Delete cached sessions | — |
version |
Show the installed version | — |
list |
List desktops with state/IP/OS | --hardware/-H, --name/-n |
template / template list |
List available templates | --category/-c, --hardware/-H, --filter |
template create |
Pick a Fedora source, download the ISO, create fedora-<variant>-<version>, then detach + delete the media after install |
--seed-url |
template promote |
Promote a stopped desktop into a template | --name/-n, --description/-d, --disabled |
build <profile.yaml> |
Build a template from a YAML profile: fetch the newest Ubuntu/Fedora ISO, hand you the installer in a viewer, then configure over SSH and promote | --identity/-i, --keep-media, --no-promote, --no-viewer, --dry-run, --install-timeout |
media / media list |
List your media (ISO library) | --filter |
media add <name> |
Register a new media by HTTPS URL | --url, --description/-d, --no-wait, --timeout |
media delete <name> |
Delete a media | --yes/-y |
seed cidata |
Build a NoCloud (CIDATA) seed ISO | --user-data, --meta-data, --output/-o |
seed oemdrv |
Build an Anaconda (OEMDRV) seed ISO | --kickstart, --output/-o |
create <name> |
Create a desktop from a template | --template/-t, --description/-d, --category/-c, --filter |
start <name> |
Start a stopped desktop | --wait/-w, --timeout, --book/-b, --book-minutes |
stop <name> |
Stop a running desktop | --wait/-w, --timeout |
delete <name> |
Delete a desktop (trash or permanent) | --permanent, --yes/-y |
view <name> |
Open the desktop in virt-viewer over SPICE | --install/--no-install, --auto-resize, --debug |
ssh <name> |
SSH in via the bastion | --user/-l, --identity/-i, --password, --timeout, --dry-run |
vpn / vpn status |
Is the WireGuard tunnel up? | — |
vpn config |
Download this account's WireGuard config | --output/-o, --show |
vpn up / vpn down |
Join or leave the desktop network (installs wireguard-tools if missing) |
--refresh/--no-refresh, --install/--no-install, --dry-run |
Full reference with every flag and behaviour:
docs/commands.md, also published at
https://isard.xtec.dev/commands.
Examples
isard list --hardware # add CPU + memory columns
isard template --filter fedora # narrow the template list
isard create dev --template fedora # fuzzy: resolves to fedora-server-44
isard start dev --wait --timeout 300 # block until it's running
isard start gpu-box --book # book a vGPU slot first, then start
isard delete dev --permanent --yes # skip the trash and the prompt
isard media add ubuntu-24 --url https://releases.ubuntu.com/24.04/…-amd64.iso
Name resolution
Desktop and template names resolve by exact match first, then Jaro-Winkler fuzzy matching, then substring. A typo still finds the right desktop; an ambiguous name opens a picker. In scripts (no TTY) an ambiguous name is an error rather than a guess.
SSH
isard ssh handles the plumbing: it resolves your private key
(--identity, ~/.ssh/id_ed25519, ~/.ssh/id_rsa, or generates a new
ed25519 key), registers the public key with the IsardVDI bastion, starts
the desktop if it's stopped, and connects through port 443.
The first connection to a desktop shows its guest credentials
half-masked and asks you to confirm them. Confirmed desktops are
remembered in ~/.config/isard/desktop-creds.json, which holds ids
only — no passwords. Use --password to set new guest credentials (the
desktop is stopped, updated, and restarted).
If OpenSSH isn't installed, an embedded pure-Python client takes over.
virt-viewer
isard view installs remote-viewer if it's missing:
| Platform | Method |
|---|---|
| Windows | Downloads and extracts the MSI from GitLab releases (no admin needed) |
| macOS | Homebrew via the jeffreywildman/homebrew-virt-manager tap (builds from source — takes several minutes) |
| Fedora | dnf install virt-viewer |
| Ubuntu/Debian | apt install virt-viewer |
Pass --no-install to skip that.
Building a template from a file
isard build takes one YAML file and gives back a finished template —
newest ISO, a short manual install in a viewer, then packages and commands
applied over the SSH bastion, and promote:
# ubuntu.yaml
image: { distro: ubuntu, variant: server, release: lts }
template: { name: ubuntu-lts-base, memory_gb: 8, disk_gb: 100 }
user:
name: isard
password_env: ISARD_TEMPLATE_PASSWORD
ssh_key: ~/.ssh/id_ed25519.pub
packages: [git, curl, docker.io]
run:
- systemctl enable --now docker
isard build ubuntu.yaml --dry-run # see the plan without touching the API
isard build ubuntu.yaml
One step is yours: when the viewer opens, install the OS with the
profile's username and password and an SSH server — three fields on the
installer's own screens. Shut the machine down and the CLI takes over
again. Full reference: docs/build-profiles.md,
examples in examples/build/.
Unattended templates, by hand
The lower-level path is still there: build a seed ISO whose volume label
the installer auto-discovers (CIDATA for cloud-init, OEMDRV for
Anaconda), host it over HTTPS, and hand the URL to template create:
isard seed oemdrv --kickstart my-ks.cfg -o seed.iso
# host seed.iso somewhere IsardVDI can reach it
isard template create --seed-url https://your-host/seed.iso
Starter configs are in examples/seed/; the
end-to-end runbook is
docs/phase3-verification.md.
Use it as a library
Everything the CLI does is importable:
from isard import get_desktops, login_to_isardvdi
session = login_to_isardvdi("12345678a@edu.gencat.cat", "…")
for desktop in get_desktops(session):
print(desktop.name, desktop.state)
See docs/library-api.md.
Development
git clone git@github.com:ddemingo/isard.git
cd isard
uv sync --dev
uv run pytest # no network needed
uv run ruff check .
uv run isard --help
Design notes and invariants:
docs/architecture.md. Every IsardVDI endpoint
we call: docs/api-endpoints.md.
License
Licensed under either of MIT or Apache-2.0, at your option. Unless you state otherwise, any contribution you submit for inclusion is dual-licensed on those same terms.
Copyright © 2026 Optersoft, S.L.
Built for the Gencat educational platform — you'll need valid IsardVDI credentials to use it.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file isard-0.3.0.tar.gz.
File metadata
- Download URL: isard-0.3.0.tar.gz
- Upload date:
- Size: 173.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c0844541e438b3c30a9a81bbd11a21205ba4211f5fbbf20b8aad81993bc1765
|
|
| MD5 |
72dda7a010857c92bf095f1ef29fb13e
|
|
| BLAKE2b-256 |
19c882ff005c1a17a36bda59c17748c2d6e17e2fbb122e6b736682c7189dcf34
|
File details
Details for the file isard-0.3.0-py3-none-any.whl.
File metadata
- Download URL: isard-0.3.0-py3-none-any.whl
- Upload date:
- Size: 113.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
390e63bc4b221704b55548f0fb3646695ce8b9cc8b6020b80408e79056e62a67
|
|
| MD5 |
166c946e1cc2d2bbfefee3af104f3617
|
|
| BLAKE2b-256 |
bc914729b2941744b26fa50901c26fb983fb844ca2db8ae21a869093cd3ca973
|