Skip to main content

A GNOME desktop theme system: download, apply, switch, and author full-desktop themes from a palette

Project description

gtheme — a GNOME theme manager

ci PyPI Python 3.11+

Download, apply, switch, and author full-desktop GNOME themes from a single palette — wallpaper, GTK, terminal, prompt, editor, monitor, the lot. One declarative manifest per theme; gtheme snapshots everything it touches, so gtheme restore always brings back your exact pre-gtheme desktop. No hand-written undo scripts, no half-reverted configs.

the gtheme interactive menu

gtheme                    # ← just run it: an interactive arrow-key menu
gtheme apply nsx          # back up current state, apply the NSX theme
gtheme switch jojo        # swap themes (your pre-gtheme baseline is kept)
gtheme restore            # revert to the desktop you had before gtheme

Requirements

  • GNOME 47+ (Wayland or X11) — on other desktops gtheme warns and asks before touching anything
  • Python 3.11+ with jinja2 and pydantic (v2)
  • gsettings/dconf (ship with GNOME), git only for installing themes from URLs

Install

Easiest — pipx (works on every distro, no dependency puzzles):

sudo apt install pipx        # Ubuntu/Debian   (Fedora: sudo dnf install pipx)
pipx install gtheme          # or, before the PyPI release:
pipx install git+https://github.com/blyatiful1/gtheme

From a checkout (contributors, or if you prefer git):

git clone https://github.com/blyatiful1/gtheme ~/gtheme
~/gtheme/install.sh --pip    # checks deps; sets up a private venv if needed

The installer explains anything that's missing (including the exact commands for apt/dnf/pacman) and how to put ~/.local/bin on your PATH if it isn't. Keep the cloned folder around — the installed command runs from it.

Distro packages for the dependencies, if you'd rather use them:

sudo apt install python3-jinja2 python3-pydantic   # Debian 13+/Ubuntu 25.04+ (older apt ships pydantic v1 — use pipx there)
sudo dnf install python3-jinja2 python3-pydantic   # Fedora
sudo pacman -S python-jinja2 python-pydantic       # Arch (a PKGBUILD is also included)

The interactive menu

Run gtheme with no arguments and you get a full-screen arrow-key menu that reaches every command — apply/switch with dry-run preview, restore, browse, author (new/build/capture), and manage (install/update/remove/export/ validate/search). Theme pickers show live palette swatches and a description panel; the header wears your applied theme's accent colours.

the theme picker with palette swatches

Move with / (or j/k), enter/ to select, q/esc/ to go back, 1-9 to pick directly. It's pure stdlib — no rich, no curses — runs on the alternate screen (your scrollback survives), adapts to any terminal size, and honours NO_COLOR. Without a TTY it degrades to a plain numbered prompt; set GTHEME_PLAIN=1 or pass --plain to force that mode on a real terminal too (screen-reader friendly).

How a theme works

A theme is a directory with a declarative theme.toml:

[meta]
name = "jojo"
title = "STONE OCEAN"

[palette]                       # or a separate palette.toml
bg = "#0B0E18"
accent = "#7DC75B"
# ...

[[files]]                       # component tag drives --only and per-file backup
component = "gtk"
src  = "files/gtk/gtk.css"
dest = "~/.config/gtk-4.0/gtk.css"

[[settings]]                    # gsettings or dconf; value is GVariant text
component = "desktop"
backend = "gsettings"
key   = "org.gnome.desktop.interface accent-color"
value = "'green'"

[[settings]]                    # {{ runtime }} tokens resolve per-machine
component = "terminal"
backend = "dconf"
key   = "/org/gnome/Ptyxis/Profiles/{{ ptyxis_default_profile }}/palette"
value = "'JoJo'"

[[hooks]]                       # optional scripts for the weird 10%
event = "post"
component = "extras"
script = "hooks/setup.sh"
optional = true

Layout:

themes/<name>/
  theme.toml        palette.toml
  files/            # sources referenced by [[files]].src
  assets/           # non-installed extras (svg sources, etc.)
  hooks/            # scripts referenced by [[hooks]]

schema/theme.schema.json gives you editor validation/completion for theme.toml (taplo / the Even Better TOML VS Code extension).

Backup & restore (the safety net)

The first time gtheme touches a file or a settings key, it snapshots the prior value into a pristine baseline under ~/.local/state/gtheme/. Apply and switch as much as you like — gtheme restore always returns the system to the state it had before gtheme first ran: files the themes introduced are removed (including now-empty directories), overwritten files and settings come back byte-for-byte. After a successful full restore the baseline is consumed, so the next apply re-snapshots your (possibly edited) configs instead of pinning stale copies.

Concurrent runs are locked out, interrupted applies stay recoverable, and apply --only <component> layers a single component without un-theming the rest of your desktop.

{{ runtime }} tokens (ptyxis_default_profile, home) resolve at apply time, so manifests committed to the repo are portable across machines.

Authoring: a palette becomes a desktop

gtheme new ocean --from jojo     # scaffold, seeding the palette from jojo
$EDITOR ~/.local/share/gtheme/themes/ocean/palette.toml
gtheme build ocean               # render alacritty/ptyxis/btop/micro/gtk from it
gtheme apply ocean --dry-run     # preview every file + setting change
gtheme apply ocean

build renders the components listed in [build].managed from shared Jinja templates (src/gtheme/templates/), with filters like lighten, darken, mix, alpha. Define the structural roles and the 6 ANSI hues; brights and surfaces are derived when omitted.

Palette roles

role required? notes
bg, fg, accent recommended everything else can derive from these
surface1..3, fg_dim, fg_bright, accent_bright, selection, comment, cursor derived override to taste
red green yellow blue magenta cyan recommended ANSI hues; bright_* variants derive
ansi_black, ansi_white, bright_black, bright_white derived

Other [[files]] fields worth knowing: template = true runs the source through {{ }} substitution at apply time; mode = "755" sets permissions; a pre hook that fails aborts the whole apply, optional = true hooks only warn. If your palette is dark, set the color-scheme gsetting to 'prefer-dark' — your users may be in light mode.

Already themed your desktop by hand? Freeze and share it:

gtheme capture mydesk            # snapshot the FULL live look into a theme
gtheme export mydesk             # bundle it into a shareable mydesk.zip
gtheme install mydesk.zip        # (on the other machine)

capture records the GNOME interface settings (accent, color-scheme, icon/GTK/cursor themes, fonts), the wallpaper (bundled and made portable), terminal/prompt/shell/monitor/editor configs and the theme files they reference (Ptyxis palettes, btop themes, alacritty imports), plus every supported extension's settings. It warns you about anything that looks like a secret or a machine-specific path before you share the result.

Commands

command what it does
list / search <q> [--remote] browse locally, or search the online collection
install <name|path|.zip|git-url> install a theme (collection, local dir, .zip, or repo)
remove <name> / update [name] uninstall, or refetch from the recorded origin
diff <name> / apply <name> --dry-run preview changes without writing
apply <name> [--only c1,c2] [-y] apply (--no-sudo / --no-hooks to skip hooks)
switch <name> alias of apply — the pristine baseline is kept either way
restore [--only c1,c2] [--wipe] [-y] revert to the pre-gtheme state
current / validate [name] show the active theme; check a manifest
new <name> [--from base] / build <name> author from a palette
capture <name> / export <name> freeze the live desktop; bundle a .zip
publish <name> / index add to the collection + regenerate its index

Global flags: --version, --verbose, --plain. Commands that change things take -y/--yes (assume yes — non-interactive/CI use). Run gtheme <command> --help for the details.

Security & consent

Themes can ship [[hooks]] (arbitrary shell scripts) and write files across your home directory, so gtheme treats anything you downloaded as untrusted:

  • Every hook is previewed and individually confirmed before it runs; --yes approves them all (only for themes you trust). Trusted, non-sudo hooks from your own local themes run without prompts.
  • Themes installed from a git URL or .zip are marked untrusted; their hooks are denied by default in non-interactive runs.
  • File destinations are confined to your home directory; theme sources are confined to the theme's own directory; exports refuse to follow symlinks out of the theme. Path escapes (/etc/..., ~/../...) are refused.
  • --insecure (allow http:// origins) and --allow-unsafe (install despite failed validation) exist for development; leave them off.

Found a boundary escape? See SECURITY.md.

The collection

theme
nsx palette nsx Honda NSX (NA1): Berlina-black cabin, Formula Red, Championship White
jojo palette jojo STONE OCEAN (JoJo Part 6+): Jolyne green, Stand-string blue, the Spin

Contribute yours: gtheme publish <name> prints the exact PR steps, and CONTRIBUTING.md has the submission checklist (validate passes, original/licensed assets, no machine-specific paths).

Troubleshooting

  • gtheme: command not found after install~/.local/bin isn't on your PATH; the installer prints the exact line to add for your shell.
  • pydantic 1.x errors on Debian/Ubuntu — your apt ships pydantic v1; install with pipx or ./install.sh --pip instead.
  • Not on GNOME? — gtheme themes GNOME; it will warn you and ask before writing anything on KDE/XFCE.
  • Something looks wrong after applyinggtheme restore returns your desktop to its pre-gtheme state; then please open an issue with the template's environment details.

License

MIT — see LICENSE. Copyright (c) 2026 blyatiful1.

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

gtheme-0.1.0.tar.gz (1.3 MB view details)

Uploaded Source

Built Distribution

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

gtheme-0.1.0-py3-none-any.whl (1.2 MB view details)

Uploaded Python 3

File details

Details for the file gtheme-0.1.0.tar.gz.

File metadata

  • Download URL: gtheme-0.1.0.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gtheme-0.1.0.tar.gz
Algorithm Hash digest
SHA256 86896ee96596571166a5f5c1e753751b205e259d6fbd899f37f3dfecb08c6aa9
MD5 f49413a3f8852abad026ab04b4530960
BLAKE2b-256 a9e18fb453d5edfda62a869546d4d304360c869d03278148dd8e4a2b06b8857c

See more details on using hashes here.

Provenance

The following attestation bundles were made for gtheme-0.1.0.tar.gz:

Publisher: publish-pypi.yml on blyatiful1/gtheme

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

File details

Details for the file gtheme-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gtheme-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gtheme-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e8704ec3c534b3224a7fc7d0fd2524310ad48d97e834d743d363577b6d1e31f3
MD5 a4fdca66b8025380ae9dee3f7971b406
BLAKE2b-256 5b7401c4c2a074efd47b020982d27e04be6277cc5ed8c7013a8a97b015f30feb

See more details on using hashes here.

Provenance

The following attestation bundles were made for gtheme-0.1.0-py3-none-any.whl:

Publisher: publish-pypi.yml on blyatiful1/gtheme

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