Contributing

Add a theme

Nothing here is ever updated after it is merged. This is a roster of one-shots, which makes the merge the only moment a theme can be made right — so perfect it before you contribute it, and expect the gate to be the strict part of an otherwise permissive repository.

  1. Start with the palette

    themes/<lowercase-hyphen-name>/colors.toml is a complete working theme on its own — Omarchy generates the terminal, btop, neovim, Chromium and shell configs from it. Look at it before reaching for anything else.

  2. Declare what it is

    theme.json carries the name, tagline, tags and the contrast floor you hold yourself to. Every field is optional and unknown keys are kept rather than rejected — a schema that refuses weird stops you building the good one.

  3. Earn the floor

    ./ritzpah contrast <name> measures every ink slot against the background. Fix the palette, or exempt the slot with a reason. Do not lower the floor to make the error go away.

  4. Generate the wallpapers

    A tools/make-backgrounds-<name> script that draws its images from primitives, made executable in the same commit. The recipe is the deliverable; the exact image never was. Then open them and actually look.

  5. Record the prompt

    PROMPT.md, verbatim, typos and all, with the date. No cleaning it up afterwards to sound smarter than you were. A theme without its prompt is an orphan.

  6. Pass the gate

    ./ritzpah validate <name> until it reports [ok], or every remaining warning is one you can defend out loud. CI runs the same command on your pull request.

House rule: Ritzpah is allowed to be too much. If a theme is tasteful, restrained, or honestly pretty usable for daily driving, it is in the wrong repository. Turn something up.

Blueprint is the exception that proves it, and it is not a loophole. It holds AAA where the rest of the collection sits on AA — but the excess did not go missing, it went into the rigour instead of the look. If you are going to be restrained here, be insufferable about it.

Before you install anything

Don't trust me

This repository ships shell scripts that run on your machine and write into ~/.config/omarchy/. You have no reason to trust a stranger's theme repo, so don't — ask your own agent first.

Audit this repo before I install it: https://github.com/lubabs770/ritzpah
Clone it somewhere temporary and actually read it. Tell me:
- what executes, and when - install time, every shell start, on a timer?
- does anything touch the network, and where does it connect?
- does it write anywhere outside ~/.config/omarchy/themes?
- does it read anything it has no business reading - keys, tokens, shell history?
- anything obfuscated: base64, eval, curl piped into a shell?
Quote the exact lines for anything you flag. If it's clean, say so plainly.

To make that cheap, here is the entire audit surface, found by reading the repository when this page was built rather than written down once and left to rot. Themes are allowed to ship their own scripts, so this list will grow — and it grows here automatically when it does.

An audit covers the commit you audited. Run it again after a git pull.

42 files in this repository can execute at 4a7332b. Everything else is data. The scan found 38 lines mentioning something that could reach the network. Every one is shown in full, false positives included — a URL in a comment counts, and so does the word curl inside the prompt above. Read them and decide for yourself.

FileWhy it countsNetwork scanWrites scan
installexecutable bitnonenone
ritzpahexecutable bitnone
3 matches
  • line 45 rm -rf -- "$dst"
  • line 48 mkdir -p "$THEMES_DST"
  • line 49 cp -r -- "$src" "$dst"
ritzpahd/Cargo.tomlCargo manifest for the optional ritzpahd daemon
5 matches
  • line 7 repository = "https://github.com/lubabs770/ritzpah"
  • line 13 tungstenite = { version = "0.30", features = ["rustls-tls-native-roots"] }
  • line 14 # tungstenite pulls rustls but selects no crypto provider, and rustls refuses to
  • line 16 # without it the first connect panics inside rustls rather than failing.
  • line 17 rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
none
ritzpahd/src/gauges.rsRust, compiled into the optional ritzpahd daemon
1 match
  • line 225 /// 1, 2, 4, 8 ... capped at 60 seconds. Lightstreamer ends sessions as a
none
ritzpahd/src/main.rsRust, compiled into the optional ritzpahd daemon
5 matches
  • line 3 //! It holds one WebSocket to Lightstreamer's public ISSLIVE feed, decodes the
  • line 11 //! opens one TLS WebSocket to push.lightstreamer.com (public ISSLIVE
  • line 78 /// Owns the socket. Reconnects forever, because Lightstreamer ends sessions as
  • line 146 // rustls will not pick a crypto provider on its own, and the failure mode
  • line 149 let _ = rustls::crypto::ring::default_provider().install_default();
none
ritzpahd/src/strip.rsRust, compiled into the optional ritzpahd daemon
1 match
  • line 256 let conn = Connection::connect_to_env()?;
none
ritzpahd/src/tlcp.rsRust, compiled into the optional ritzpahd daemon
9 matches
  • line 3 //! TLCP is Lightstreamer's own text protocol. This implements the small
  • line 15 use tungstenite::client::IntoClientRequest;
  • line 16 use tungstenite::http::HeaderValue;
  • line 17 use tungstenite::Message;
  • line 24 const SUBPROTOCOL: &str = "TLCP-2.1.0.lightstreamer.com";
  • line 25 const ENDPOINT: &str = "wss://push.lightstreamer.com/lightstreamer";
  • line 154 /// and expected -- Lightstreamer rotates sessions) and `Err` on anything
  • line 167 tungstenite::connect(req).map_err(|e| err(format!("connect: {e}")))?;
  • line 262 fn subscribe<S>(sock: &mut tungstenite::WebSocket<S>) -> Result<()>
none
themes/acid-vortex/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/blueprint/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/casino-carpet/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/cathode/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/cathode/phosphor.fragGLSL, run by the GPU on every framenonenone
themes/ego-death/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/ego-death/liquid.fragGLSL, run by the GPU on every framenonenone
themes/github-dark-colorblind/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/github-dark-dimmed/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/github-dark-high-contrast/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/github-dark-tritanopia/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/github-dark/hyprland.luaLua, run by Hyprland at every config loadnonenone
themes/iss-cockpit/cockpit.frag.inGLSL, run by the GPU on every framenonenone
themes/iss-cockpit/hyprland.luaLua, run by Hyprland at every config loadnone
4 matches
  • line 206 local handle = io.open(tmp, "w")
  • line 221 os.remove(tmp)
  • line 224 if not os.rename(tmp, theme_dir .. "/cockpit.frag") then
  • line 225 os.remove(tmp)
themes/lunation/hyprland.luaLua, run by Hyprland at every config loadnone
4 matches
  • line 303 local handle = io.open(tmp, "w")
  • line 314 os.remove(tmp)
  • line 317 if not os.rename(tmp, theme_dir .. "/sky.frag") then
  • line 318 os.remove(tmp)
themes/lunation/sky.fragGLSL, run by the GPU on every framenonenone
themes/lunation/sky.frag.inGLSL, run by the GPU on every framenonenone
themes/untitled/hyprland.luaLua, run by Hyprland at every config loadnonenone
tools/make-backgroundsexecutable bitnone
2 matches
  • line 19 mkdir -p "$OUT"
  • line 21 trap 'rm -rf "$TMP"' EXIT
tools/make-backgrounds-blueprintexecutable bitnone
12 matches
  • line 86 mkdir -p "$OUT"
  • line 88 trap 'rm -rf "$TMP"' EXIT
  • line 419 MVG="$TMP/1.mvg"; : > "$MVG"
  • line 442 MVG="$TMP/2.mvg"; : > "$MVG"
  • line 490 MVG="$TMP/3.mvg"; : > "$MVG"
  • line 529 HM="$TMP/3h.mvg"; : > "$HM"; MVG="$HM"
  • line 532 HK="$TMP/3k.mvg"; : > "$HK"; MVG="$HK"
  • line 544 MVG="$TMP/4.mvg"; : > "$MVG"
  • line 556 GM="$TMP/4g.mvg"; : > "$GM"; MVG="$GM"
  • line 564 GK="$TMP/4k.mvg"; : > "$GK"; MVG="$GK"
  • line 570 MVG="$TMP/4o.mvg"; : > "$MVG"
  • line 602 MVG="$TMP/5.mvg"; : > "$MVG"
tools/make-backgrounds-casino-carpetexecutable bitnone
6 matches
  • line 71 mkdir -p "$OUT"
  • line 73 trap 'rm -rf "$TMP"' EXIT
  • line 229 MVG="$TMP/l1.mvg"; : > "$MVG"
  • line 262 MVG="$TMP/l2.mvg"; : > "$MVG"
  • line 286 MVG="$TMP/l3.mvg"; : > "$MVG"
  • line 459 MVG="$TMP/5r.mvg"; : > "$MVG"
tools/make-backgrounds-cathodeexecutable bitnone
6 matches
  • line 40 mkdir -p "$OUT"
  • line 42 trap 'rm -rf "$TMP"' EXIT
  • line 113 cat > "$TMP/now.txt" <<'TXT'
  • line 129 cat > "$TMP/ghost.txt" <<'TXT'
  • line 165 } > "$TMP/mono.mvg"
  • line 235 } > "$TMP/post.txt"
tools/make-backgrounds-ego-deathexecutable bitnone
2 matches
  • line 20 mkdir -p "$OUT"
  • line 22 trap 'rm -rf "$TMP"' EXIT
tools/make-backgrounds-githubexecutable bit
3 matches
  • line 35 import urllib.request
  • line 44 OCTICONS_TARBALL = (f"https://registry.npmjs.org/@primer/octicons/-/"
  • line 98 with urllib.request.urlopen(OCTICONS_TARBALL, timeout=60) as response:
4 matches
  • line 100 os.makedirs(_OCTICON_CACHE, exist_ok=True)
  • line 107 with open(target, "wb") as handle:
  • line 179 with os.fdopen(handle, "w") as out:
  • line 577 os.makedirs(directory, exist_ok=True)
tools/make-backgrounds-iss-cockpitexecutable bitnone
1 match
  • line 25 mkdir -p "$OUT"
tools/make-backgrounds-lunationexecutable bitnone
4 matches
  • line 290 with open(rgb_path, "wb") as fh:
  • line 293 with open(a_path, "wb") as fh:
  • line 694 os.makedirs(OUT, exist_ok=True)
  • line 706 shutil.rmtree(TMP, ignore_errors=True)
tools/make-backgrounds-untitledexecutable bitnone
1 match
  • line 25 mkdir -p "$OUT"
tools/make-docs-githubexecutable bitnonenone
tools/make-github-themesexecutable bitnone
2 matches
  • line 738 os.makedirs(directory, exist_ok=True)
  • line 739 with open(path, "w") as handle:
tools/make-palette-untitledexecutable bitnone
1 match
  • line 96 } > "$OUT"
tools/make-preview-githubexecutable bitnone
2 matches
  • line 141 with os.fdopen(handle, "w") as out:
  • line 247 with os.fdopen(handle2, "w") as out:
tools/make-preview-iss-cockpitexecutable bitnonenone
tools/ritzpah-iss-tle.pyexecutable bit
6 matches
  • line 23 import urllib.request
  • line 27 SOURCE = "https://celestrak.org/NORAD/elements/gp.php?CATNR=25544&FORMAT=TLE"
  • line 34 def fetch(url):
  • line 35 request = urllib.request.Request(url, headers={"User-Agent": "ritzpah/iss-tle"})
  • line 36 with urllib.request.urlopen(request, timeout=30) as response:
  • line 103 values = derive(*parse(fetch(SOURCE)))
1 match
  • line 135 with open(lua, "w", encoding="utf-8") as handle:
tools/ritzpah-lib.pyexecutable bitnonenone
tools/ritzpah-site.pyexecutable bit
8 matches
  • line 115 REPO = "https://github.com/lubabs770/ritzpah"
  • line 133 r"\b(curl|wget|nc|ssh|scp|rsync|ftp|urllib|requests\.|http\.client|socket\.|"
  • line 134 r"fetch\(|XMLHttpRequest|wss?://|https?://|"
  • line 138 r"TcpStream|TcpListener|UdpSocket|tungstenite|reqwest|rustls|ureq|hyper::|"
  • line 139 r"lightstreamer|IntoClientRequest|connect_to_env)", re.I)
  • line 232 AUDIT_PROMPT = """Audit this repo before I install it: https://github.com/lubabs770/ritzpah
  • line 238 - anything obfuscated: base64, eval, curl piped into a shell?
  • line 732 f"does the word <code>curl</code> inside the prompt above. Read them and "
5 matches
  • line 50 shutil.copy2(src, fallback)
  • line 149 r"File::create|OpenOptions|fs::write|fs::remove|fs::create_dir|fs::rename)")
  • line 893 shutil.rmtree(out)
  • line 894 os.makedirs(assets)
  • line 895 os.makedirs(os.path.join(out, "themes"))

Network pattern: \b(curl|wget|nc|ssh|scp|rsync|ftp|urllib|requests\.|http\.client|socket\.|fetch\(|XMLHttpRequest|wss?://|https?://|TcpStream|TcpListener|UdpSocket|tungstenite|reqwest|rustls|ureq|hyper::|lightstreamer|IntoClientRequest|connect_to_env)

Writes pattern: (io\.open\([^)]*[\"'](?:w|a|r\+|w\+|a\+)[\"']|open\([^)]*[\"'](?:w|a|x)b?[\"']|\bos\.remove\b|\bos\.rename\b|\bshutil\.(?:copy|move|rmtree)|\bos\.makedirs\b|\brm -rf\b|\bmkdir -p\b|\bcp -r\b|\s>\s*[\"']?\$|File::create|OpenOptions|fs::write|fs::remove|fs::create_dir|fs::rename)