PROJECT MAMBO
Change colour theme

Command reference

script/mambodot.sh is the guarded entry point for GNU Stow operations:

./script/mambodot.sh link hypr kitty zsh
./script/mambodot.sh unlink hypr kitty zsh
./script/mambodot.sh link all
./script/mambodot.sh unlink all

At least one package name or the exact word all is required. The command rejects unknown packages and path traversal, previews the complete selection, and applies it only after a successful preview. It uses leaf symlinks, ignores user Stow resource files, and never adopts an existing file. See Installation and safety for conflict handling.

Machine doctor

Compare the current host with the reviewed package and enabled-service manifests:

./script/mambodot.sh doctor

The command reads manifest/packages.tsv and manifest/services.tsv, checks Arch and foreign package provenance, checks Flatpak applications, and checks system and user service enablement. It also performs a bounded managed-dotfile check: it flags known retired MamboColour links and simulates Stow for packages it can infer are currently or partially linked, reporting missing or wrong links for those packages. Intentionally unlinked packages and packages with no surviving link are not assumed. It prints only missing, disabled, or drifted entries and exits non-zero when the machine drifts. Extra packages and services are intentionally ignored.

doctor is read-only: it does not install, remove, enable, start, or stop anything. The two-column TSV files are the reviewable machine profile; use the reported rows to decide which changes are appropriate for the target host. After changing the repository layout, rerun ./script/mambodot.sh link <package> for each affected package, then run doctor again.

Exit status

script/mambodot.sh accepts exactly doctor, link, and unlink. It returns 0 after a successful command, 1 for operational failures such as missing tools, unsafe targets, or detected machine drift, and 2 for invalid command syntax, package names, arguments, or manifest vocabulary. A failed child command may propagate its own non-zero status. No success status means that a requested link or unlink completed.

Colour API and adapter refresh

MamboDot vendors the MamboColour Lua API and its four mamboorche CSV files at exact provider revision c703092a619b3ee9b05503eaf2a553ae52595d35. vendor/mambocolour/REVISION records that source revision, and vendor/mambocolour/LICENSE preserves the upstream MIT terms. Provider 0.3 eagerly reads and validates all four files together: both UI files must use the exact role sequence, and the light and dark accent files must have matching keys in matching order. get(index) provides zero-based direct colour access without exposing private names, while random_seeded(seed) accepts the shared unsigned 32-bit range 0 through 4294967295. Ordinary desktop startup does not require an adjacent MamboColour checkout or an installed provider command.

Hyprland loads vendor/mambocolour/lua/mambocolour.lua directly from variables.lua, selects the dark theme, and gives the remaining Lua modules both ui and colour palettes. MamboDot owns the desktop-specific mapping: a normal active border uses interactive_hover(), a normal inactive border uses border(), a floating override uses interactive(), and a pinned override uses warning(). Group borders and groupbar backgrounds use interactive() and border(), with fg() for titles. These are generic provider roles mapped locally; MamboColour does not define normal, floating, pinned, or Hyprland-specific roles.

When a semantic role is not appropriate, Lua consumers can use theme.colour:get(index) for a direct zero-based position or the random methods for decorative selection. Descriptive CSV keys remain private. The active window-border mappings intentionally use UI roles rather than fixed colour positions.

Consumers that cannot load Lua use two committed, MamboDot-owned adapters:

ConsumerAdapter
Hyprlockdot/hypr/.config/hypr/themes/mambocolour.conf
AGSdot/ags/.config/ags/_mambocolour.scss

Refresh or check those adapters with the consumer-owned script:

lua script/sync_mambocolour.lua
lua script/sync_mambocolour.lua --check

The script renders the dark UI roles plus 12 deterministic numbered accents, accent_01 through accent_12, selected with seeds 0 through 11. AGS uses UI roles for surfaces, text, interaction, and status, then uses numbered colour-palette accents for decorative widget identity such as network, audio, hardware, and battery indicators. The script does not fetch or update MamboColour, and --check writes nothing; it reports a missing or stale adapter and exits non-zero. The former four palette families, their format-specific files, the mbcolor command dependency, and mambodot.sh update no longer exist.

To update the pinned provider manually:

  1. Review the desired MamboColour commit and its public Lua API.

  2. Replace vendor/mambocolour/lua/mambocolour.lua, vendor/mambocolour/palettes/mamboorche/*.csv, and vendor/mambocolour/LICENSE with the exact files from that one commit.

  3. Replace the single hash in vendor/mambocolour/REVISION with that commit ID.

  4. Run lua script/sync_mambocolour.lua and then ./script/test.sh.

  5. Inspect the vendored snapshot, both adapters, and their embedded revision before committing.

Run the regression suite after changing the provider snapshot, adapter script, or its consumers:

./script/test.sh

The check verifies the exact vendored revision, rejects invalid adapter arguments, checks that both committed adapters are current, validates stable roles and deterministic accent parity, and runs focused Hyprland Lua regressions alongside the guarded Stow suite. It is not currently run by CI.

AGS desktop shell

Hyprland first propagates its session environment, then starts mambodot-shell.target; its shutdown event stops the target again. The systemd user manager supervises the standalone Astal notification daemon, the Stow-managed AGS shell, and separate text and image Cliphist watchers. The target is session-started rather than enabled, so it cannot run before WAYLAND_DISPLAY reaches the user manager.

systemctl --user status mambodot-shell.target mambodot-ags.service mambodot-notifd.service 'mambodot-cliphist@*.service'
systemctl --user restart mambodot-ags.service
journalctl --user -u mambodot-ags.service -b

Long-lived applications launched by AGS, including Apps and Run selections, enter transient app.slice scopes. Restarting mambodot-ags.service therefore neither terminates those applications nor leaves their resource accounting attached to the shell service. The Astal daemon discards standard output so notification bodies are not persisted in the user journal; standard error remains journaled for diagnosis.

Before suspend or hibernate, Hypridle locks the session and stops AGS so GTK and D-Bus state cannot freeze across sleep. Resume starts a fresh supervised AGS instance; clean early exits are retried, and a stuck old process is force-stopped after three seconds. Astal and the Cliphist watchers remain supervised throughout. Hyprlock stays as the authenticated lock client and refreshes its clock every second instead of being replaced.

The standalone daemon remains the notification owner while AGS restarts, and AGS acts as its visual frontend. Control the bar, launcher, sidebars, or instance from a terminal with:

ags toggle launcher
ags toggle keybinds
ags toggle sidebar-left
ags toggle sidebar-right
ags request bar toggle
ags list

Open a specific launcher mode through the validated request interface:

ags request launcher apps
ags request launcher apps prime
ags request launcher run
ags request launcher windows
ags request launcher power
ags request launcher clipboard

Apps opens the complete sorted list of visible desktop entries and refreshes it whenever the launcher opens; prime launches the selected application with the dedicated-GPU environment. Run parses a command into an argument vector and does not invoke a shell, so pipes, redirects, globs, and substitutions are not expanded. Windows focuses a mapped Hyprland client. Power exposes only the fixed actions documented below. Clipboard searches every newest-first Cliphist entry and copies the selected bytes unchanged, including images. Apps and Clipboard use a virtualized scrolling list, so the shell does not create one GTK widget for every stored result. Use Alt-Shift-1 through Alt-Shift-5 to change mode, Up/Down or Page Up/Page Down to move through results, Enter to activate the selection, and Alt-1 through Alt-9 to activate the first nine results; every result remains clickable.

The two supervised Cliphist watchers retain up to 5,000 text or image entries in Cliphist's own database. MamboDot does not duplicate that history or silently prune it in AGS. Existing entries remain intact when the watchers restart.

The 40-pixel bar exposes larger launcher, sidebar, status, and eye-shaped idle-inhibitor glyphs without reserving more screen space. Click the eye to allow or prevent automatic idle locking; its warm background means AGS owns a live logind idle inhibitor descriptor. Hypridle honors that inhibitor while remaining active. The control defaults to on whenever AGS starts, including after resume, retries failed acquisition, and remains visibly off until logind grants the descriptor. Turning it off closes the descriptor and lasts until the next AGS restart. Explicit lock, suspend, and hibernate actions still lock the session.

Each bar's ten buttons map to that monitor's ID-based workspace block. A newly joined output starts on the first workspace in its block without taking focus or moving the pointer away from the existing output. A background workspace that receives an application urgency request—such as a browser handling an external sign-in link—keeps a warm attention state until that workspace becomes active. Applications that do not request urgency cannot be inferred safely by the bar.

The keybind sheet, launcher, and sidebars follow the focused monitor, exclude one another, and close with Escape or an outside click. Launcher content stays on the focused monitor while its click-to-close dimming surface covers every active output. The sheet renders the maintained tables from docs/Keybinds.md; toggle it with SUPER / or the command above. Sidebar telemetry refreshes only while its panel is visible. The forced GTK backend is intentional because an XWayland-launched terminal may otherwise make GTK layer-shell unavailable.

The left panel is a two-column, no-scroll dashboard at 1080p. It shows battery health, voltage, cycles and charge/drain rate; CPU load, temperature, frequency and policy; both fan speeds and curve ownership; iGPU and active-dGPU load, temperature, clocks, VRAM and power; memory, NVMe read/write rate, and storage/DIMM temperatures. Safe controls cover persistent 60/80-percent care limits or unrestricted full charging, ASUS thermal profiles, confirmed graphics modes, panel and keyboard brightness, and panel overdrive. Full charging is the current default. AGS sends one critical warning while a discharging battery is at or below 10 percent, rearming only after recovery above 12 percent, and warns when two AC-state changes occur within 15 seconds; the connection warning has a one-minute cooldown. Advanced fan curves open the installed ROG Control Center; AGS never writes raw PWM, CPU governor, or TDP values. The right panel reads today's Obsidian ## Schedule section without writing to the vault and shows the five newest notifications retained by the current AGS process.

Top-right notification popups support sender actions and dismissal. Do-not-disturb suppresses and clears popups while notifications continue into active state and session history. Resolved notifications cannot be restored because their sender context may no longer exist, and history intentionally resets with AGS rather than persisting notification contents.

Power actions

After the script Stow package is linked, the shared backend accepts one fixed action:

~/.local/bin/powermenu.sh <shutdown|hibernate|reboot|windows|suspend|logout|lock>

Exactly one action is required. Missing, unknown, or extra arguments fail with a usage error, and action strings are selected by case rather than evaluated. The AGS Power mode confirms suspend, hibernate, logout, restart, restart-to-Windows, and shutdown before invoking this backend; Lock runs immediately. Direct command-line action calls are immediate.

The Hibernate action closes the Bitwarden Flatpak and waits up to ten seconds for /sys/power/disk to leave its disabled state before asking logind to hibernate. Bitwarden's current memfd_secret key container deliberately removes kernel hibernation support while the app is running; closing it releases that protection without moving vault keys into this host's unencrypted swap. If hibernation remains unavailable, the action fails clearly instead of racing logind. Bitwarden remains closed after resume and must be reopened. A direct systemctl hibernate still fails while Bitwarden is running.

The windows action asks Polkit to run only /usr/bin/grub-reboot for the reviewed Windows entry, then reboots only if that command succeeds. Cancelling or failing authorization leaves the current boot target and session unchanged. If setting the one-shot entry succeeds but reboot fails, the backend clears next_entry before returning an error.

Code OSS extensions

Install the reviewed extension list explicitly:

./script/code-oss/install_extensions.sh

The command accepts no arguments, compares extension IDs case-insensitively, installs only missing entries, and stops if listing or installation fails. It is intentionally separate from linking configuration.

tp

tp is a Zsh function for jumping to directories and maintaining named bookmarks. It is defined by the managed Zsh configuration, so it is available after that configuration is linked and loaded.

tp <name-or-path>
tp -a <name> <path>
tp -d <name>
tp -l
FormResult
tp <name>Change to the bookmarked directory
tp <path>Change directly to an existing directory
tp -a <name> <path>Add or replace a bookmark using the absolute target path
tp -d <name>Remove a bookmark
tp -lList saved bookmarks
tpShow built-in help

Bookmark names are stored in lowercase and matched case-insensitively.

Examples

tp -a docs ~/Documents
tp -l
tp docs
tp -d docs

Storage

Bookmarks live in .config/zsh/tp_bookmarks.txt beside the managed .zshrc. Both the Stow ignore rules and Git ignore rules exclude that machine-local file.

A bookmark record uses a whitespace-separated name and path. Paths containing spaces are therefore not represented safely by the current format.