Compare commits
206 Commits
legacy
...
8fded63b10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fded63b10 | ||
|
|
edd0bd38ce | ||
|
|
096440a7d7 | ||
|
|
7d5f091c29 | ||
|
|
90a5104f94 | ||
|
|
39cfe0fb12 | ||
|
|
01ee847490 | ||
|
|
808a3febdd | ||
|
|
4ad564bd80 | ||
|
|
3e49481d46 | ||
|
|
8d54eecd67 | ||
|
|
4e3acbe89c | ||
|
|
8f2e047f4a | ||
|
|
8874a22a37 | ||
|
|
310614bdd2 | ||
|
|
fb75c3dedf | ||
|
|
44d5516191 | ||
|
|
47c8b6f997 | ||
|
|
abc953ea84 | ||
|
|
d1d6a09d9d | ||
|
|
a360bc87ca | ||
|
|
1921839e0e | ||
|
|
9df18261f9 | ||
|
|
e02b4d8200 | ||
|
|
5eadf0cff6 | ||
|
|
26e393b65d | ||
|
|
fb78c814cc | ||
|
|
821032e81c | ||
|
|
b7b51e9354 | ||
|
|
0fe46221ea | ||
|
|
bfb80cb60d | ||
|
|
352c681f48 | ||
|
|
d2ac131b75 | ||
|
|
2a23e82169 | ||
|
|
1b8eccbdca | ||
|
|
3f5e414341 | ||
|
|
774bdad6e4 | ||
|
|
e05e3647e6 | ||
|
|
472d7502b4 | ||
|
|
b0b8a9a09b | ||
|
|
56f1cc3fa9 | ||
|
|
9cd6f5e30c | ||
|
|
a83edb0d36 | ||
|
|
fd6e5f60e9 | ||
|
|
a643391d3d | ||
|
|
63136a8cb1 | ||
|
|
0d80ab272f | ||
|
|
397dd5991a | ||
|
|
274ffc25e1 | ||
|
|
0e6c678835 | ||
|
|
18b854563b | ||
|
|
f70838c5b5 | ||
|
|
1e4427f6af | ||
|
|
a47aa3aff5 | ||
|
|
baab2d3b88 | ||
|
|
5ea4f0c9ac | ||
|
|
938753273d | ||
|
|
46af2f0632 | ||
|
|
bc4e8e1410 | ||
|
|
4c2ad38656 | ||
|
|
6d70bba8e6 | ||
|
|
9726ba3b2f | ||
|
|
4024da791f | ||
|
|
aac678335c | ||
|
|
7d6d74fd7f | ||
|
|
cdd1897b14 | ||
|
|
9976ea06f5 | ||
|
|
cdfe92a089 | ||
|
|
431af618cc | ||
|
|
47526ae6e2 | ||
|
|
86802f244e | ||
|
|
f3325385c1 | ||
|
|
aed41793f8 | ||
|
|
685126ab47 | ||
|
|
c8d0b09044 | ||
|
|
c2f90c7d0a | ||
|
|
5747dc9839 | ||
|
|
d1344712b8 | ||
|
|
37204f5f45 | ||
| 97b5944dc1 | |||
| 0c483f9512 | |||
| dfb57c2e34 | |||
| 995810927d | |||
| e1cf190dd2 | |||
|
|
70334e68bb | ||
|
|
6a4af69b0f | ||
|
|
d9466d6555 | ||
|
|
0e42763aea | ||
|
|
a6d6860054 | ||
|
|
5c43a93285 | ||
|
|
09c308b93c | ||
|
|
bdf20f2d8e | ||
|
|
c57d26864e | ||
|
|
019fdfc8bb | ||
|
|
c2281dbc61 | ||
|
|
b4fe52261b | ||
|
|
82659566ac | ||
|
|
994025f0c8 | ||
|
|
b0b2a4d732 | ||
|
|
964a5c98b7 | ||
|
|
c45fb80b79 | ||
|
|
0c668c2eb1 | ||
|
|
1f4bd3d5fa | ||
|
|
017bb1aa41 | ||
|
|
b856bb93e8 | ||
|
|
e0ee5b9e7e | ||
|
|
f68b245d92 | ||
|
|
fb748c217c | ||
|
|
8d3911de1a | ||
|
|
6ad80c045e | ||
|
|
54c6e100fb | ||
|
|
eb76bd61b4 | ||
|
|
71f37bfc30 | ||
|
|
69f959365e | ||
|
|
aef45b3c8d | ||
|
|
0897391cfb | ||
|
|
5c83b52727 | ||
|
|
0751102915 | ||
|
|
5c59da73e7 | ||
|
|
42801548b7 | ||
|
|
1b0eeeaf6c | ||
| a606c0d498 | |||
| cd495d1720 | |||
| dbcb8efd1e | |||
| 07e467027b | |||
| 9a5473e179 | |||
| db6a0ba455 | |||
| 8c47716f9a | |||
| f60f3655f9 | |||
| afdb928ed7 | |||
| 882ba6646b | |||
| db202f90e4 | |||
| 51c11e1df3 | |||
| 6a22eba0c4 | |||
| c47eb5f688 | |||
| 00f5311499 | |||
|
|
8853f6ae49 | ||
|
|
e0182ae7dd | ||
|
|
58096c09ed | ||
|
|
7da6bb979e | ||
|
|
3f36183021 | ||
|
|
d9301ad954 | ||
|
|
66f58fa228 | ||
|
|
2c8e0b47f9 | ||
|
|
69f7ae9051 | ||
|
|
4017b6cff6 | ||
|
|
cde279af0b | ||
|
|
6513908067 | ||
|
|
fdb0685eec | ||
|
|
e411d35544 | ||
|
|
3757e7d66f | ||
|
|
05d995f8e0 | ||
|
|
f6c4a2a591 | ||
|
|
7c34eed2ca | ||
|
|
d252f01f17 | ||
|
|
28a2f5d5ae | ||
|
|
f06d7f361c | ||
|
|
58d79aad17 | ||
|
|
60138e20d0 | ||
|
|
df7c0ef7ae | ||
|
|
f97054c804 | ||
|
|
520c878bb3 | ||
|
|
084b2a0500 | ||
|
|
20df0d8a60 | ||
|
|
abfe872109 | ||
|
|
961314ea86 | ||
|
|
76582c1ee9 | ||
|
|
d06373b155 | ||
|
|
bd42462291 | ||
|
|
583708d78c | ||
|
|
6763bef73e | ||
|
|
465f013155 | ||
|
|
eda8461304 | ||
|
|
1ba1eeed64 | ||
|
|
c1781f45ca | ||
|
|
ed7be0206d | ||
|
|
009bdbad8f | ||
|
|
a33127cd3c | ||
|
|
dccceb4c48 | ||
| bc5faec6b8 | |||
|
|
77a0e70146 | ||
|
|
37819bb50f | ||
|
|
a50e9793ea | ||
|
|
7b5a22c800 | ||
|
|
134695806c | ||
|
|
727f21005d | ||
|
|
1403ea82b2 | ||
|
|
29818d2fb6 | ||
|
|
77dba7ca5d | ||
|
|
dba349a539 | ||
|
|
3b0b2872aa | ||
|
|
804d708f87 | ||
|
|
8da429d611 | ||
|
|
996fdc28c9 | ||
|
|
609bb7e7dc | ||
|
|
ecf94e84ab | ||
|
|
c813055578 | ||
|
|
8881ad3bae | ||
|
|
7aba5fa0a8 | ||
|
|
479193b10b | ||
|
|
71614fa6ca | ||
|
|
f3707357a6 | ||
|
|
8ded92ea63 | ||
|
|
1f22e996dc | ||
|
|
8a0ec763e0 | ||
|
|
f211ef0d09 |
90
.gitea/workflows/bump.yml
Normal file
90
.gitea/workflows/bump.yml
Normal file
@@ -0,0 +1,90 @@
|
||||
# Nomarchy scheduled lock bump — the automated half of "rock-stable
|
||||
# without rotting": once a week, update flake.lock (inputs track pinned
|
||||
# release branches, so this never jumps a NixOS release — that's a
|
||||
# deliberate hand-edited v2, see agent/GOALS.md), gate it, and land it
|
||||
# on main only on green. `v1` promotion stays human, always.
|
||||
#
|
||||
# Fast lane: workflow_dispatch. For a security fix upstream, run this
|
||||
# workflow manually from the Actions tab instead of waiting for Monday.
|
||||
#
|
||||
# Gate scope: `nix flake check --no-build` — the same eval tier as
|
||||
# check.yml (this runner has no KVM; see item 20 for the VM-suite
|
||||
# upgrade path). The py_compile/bash -n steps are skipped on purpose:
|
||||
# they don't read flake.lock, so a lock bump cannot break them. The
|
||||
# bump commit's own push then triggers check.yml as a second net.
|
||||
# A green bump therefore guards evaluation, not VM behaviour — the
|
||||
# checks.* suite still runs locally / at promotion time.
|
||||
#
|
||||
# Failure mode: a red gate fails this run visibly and pushes nothing;
|
||||
# next schedule retries. A push race (someone landed on main mid-run)
|
||||
# also just fails the final push — rerun or wait a week.
|
||||
#
|
||||
# Container recipe (nixbld users, sandbox=false, pinned Nix, plain-shell
|
||||
# install) inherited from check.yml — the gotchas are documented there.
|
||||
|
||||
name: Lock bump
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '17 5 * * 1' # Mondays 05:17 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
bump:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
NIX_CONFIG: |
|
||||
experimental-features = nix-command flakes
|
||||
sandbox = false
|
||||
NIX_SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
run: |
|
||||
NIX_VERSION=2.31.5
|
||||
groupadd -r nixbld 2>/dev/null || true
|
||||
for i in $(seq 1 10); do
|
||||
useradd -r -g nixbld -G nixbld -d /var/empty \
|
||||
-s /usr/sbin/nologin -c "Nix build user $i" "nixbld$i" 2>/dev/null || true
|
||||
done
|
||||
curl -L "https://releases.nixos.org/nix/nix-${NIX_VERSION}/install" | sh -s -- --no-daemon
|
||||
echo "$HOME/.nix-profile/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Update flake.lock
|
||||
# Inputs track release branches (nixos-26.05, release-26.05), so
|
||||
# the update stays within them by construction. The human-readable
|
||||
# change list goes into the commit body below.
|
||||
run: |
|
||||
nix flake update 2>&1 | tee /tmp/bump-log
|
||||
if git diff --quiet flake.lock; then
|
||||
echo "Lock already up to date — nothing to do."
|
||||
echo "changed=0" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changed=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
id: update
|
||||
|
||||
- name: Gate — nix flake check (eval only)
|
||||
if: steps.update.outputs.changed == '1'
|
||||
run: nix flake check --no-build
|
||||
|
||||
- name: Commit + push on green
|
||||
if: steps.update.outputs.changed == '1'
|
||||
# The checkout step persists the Actions token, so this push
|
||||
# authenticates as the workflow; its push triggers check.yml as
|
||||
# the second net. Only flake.lock is committed — pathspec-limited,
|
||||
# nothing else can ride along.
|
||||
run: |
|
||||
{
|
||||
echo "chore(lock): scheduled upstream bump"
|
||||
echo
|
||||
grep -E '^(• | )' /tmp/bump-log || true
|
||||
echo
|
||||
echo "Gate: nix flake check --no-build (eval tier — see bump.yml header)."
|
||||
} > /tmp/bump-msg
|
||||
git -c user.name="nomarchy-bump" -c user.email="actions@git.bemagri.xyz" \
|
||||
commit --only flake.lock -F /tmp/bump-msg
|
||||
git push origin HEAD:main
|
||||
@@ -1,42 +1,40 @@
|
||||
# Nomarchy CI — eval + lint.
|
||||
# Nomarchy CI — the always-on net under direct-to-main pushes.
|
||||
#
|
||||
# Catches the regressions that hurt today:
|
||||
# 1. Flake stops evaluating (broken option ref, missing import, etc.).
|
||||
# Checked per-output rather than via `nix flake check` so we can skip
|
||||
# packages.allThemeVariants — the 22-generation linkFarm that OOMs the
|
||||
# runner; every palette is validated one-at-a-time by the matrix (4).
|
||||
# 2. A `nomarchy-*` shell script has a syntax error or a shellcheck
|
||||
# error-severity issue.
|
||||
# 3. `docs/SCRIPTS.md` drifts from the repo state because somebody
|
||||
# added / removed / renamed a script and didn't run the generator
|
||||
# (the pre-commit hook handles this, but only when enabled per-clone).
|
||||
# 4. An opt-in nomarchy.* toggle stops evaluating. `nix flake check`
|
||||
# only evaluates the four default configs, so a bug that only fires
|
||||
# when a toggle is flipped sails through (e.g. the impermanence
|
||||
# systemd-stage-1 assertion). nomarchy-eval-matrix layers each toggle
|
||||
# onto the default config and forces system.build.toplevel.
|
||||
# Scope (deliberate): the EVAL tier only. The runner behind this Gitea
|
||||
# instance is act_runner + docker containers (the legacy repo's check.yml
|
||||
# ran 57 times on it) — no systemd, no /dev/kvm — so the checks.* VM
|
||||
# tests and full toplevel builds can't run here. `nix flake check
|
||||
# --no-build` still catches most breakage (type errors, missing options,
|
||||
# bad merges, template/mkFlake drift — see docs/TESTING.md §1); the VM
|
||||
# suite stays a local/promotion gate until a KVM-capable NixOS runner
|
||||
# exists (see the commented vm-checks job at the bottom).
|
||||
#
|
||||
# Doesn't build ISOs — that needs a binary cache. Add a separate job
|
||||
# once Cachix/Attic is in place.
|
||||
# Inherited-from-legacy gotchas (learned over 57 runs, kept verbatim):
|
||||
# - Single-user Nix (--no-daemon): no systemd in the container. The
|
||||
# installer runs as root and honours build-users-group=nixbld from
|
||||
# its bundled nix.conf, aborting unless the group exists AND has
|
||||
# members — create nixbld + users first.
|
||||
# - sandbox=false: Stylix/base16.nix do import-from-derivation; the
|
||||
# single-user Nix in this container can't set up the build sandbox
|
||||
# (no user namespaces), which otherwise surfaces as
|
||||
# "path '…-source' is not valid".
|
||||
# - Pin the Nix version: 2.34's lazy-trees git cache doesn't
|
||||
# materialise flake-input `-source` paths into the store, breaking
|
||||
# the same IFD reads. 2.31.5 matches what wrote flake.lock.
|
||||
# - Plain-shell Nix install, not a JS action: act_runner's bundled act
|
||||
# tops out at node20; a `run:` step has no node-runtime coupling.
|
||||
|
||||
name: Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main, v1]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
eval-and-lint:
|
||||
eval:
|
||||
runs-on: ubuntu-latest
|
||||
# Flakes for every `nix` invocation in the job (the bare `nix flake
|
||||
# check` below relies on this; the scripts pass the flag themselves).
|
||||
# sandbox=false because Stylix/base16.nix do import-from-derivation —
|
||||
# eval realizes fetched `-source` paths mid-check, and the single-user
|
||||
# Nix in this container can't set up the build sandbox (no user
|
||||
# namespaces), which otherwise surfaces as "path '…-source' is not
|
||||
# valid". NIX_SSL_CERT_FILE because we add nix to PATH without sourcing
|
||||
# the installer's profile (which is what normally exports it).
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
NIX_CONFIG: |
|
||||
experimental-features = nix-command flakes
|
||||
@@ -47,22 +45,6 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
# Plain shell install rather than a JS action: act_runner's bundled
|
||||
# `act` only supports up to node20, and nix-installer-action@main
|
||||
# moved to node24 ("runs.using ... got node24"). A run step has no
|
||||
# node-runtime coupling. Single-user (--no-daemon) needs no systemd,
|
||||
# which the catthehacker container doesn't run as PID 1.
|
||||
#
|
||||
# The installer runs as root here and honours build-users-group=
|
||||
# nixbld from its bundled nix.conf, aborting unless that group exists
|
||||
# AND has members. Create the nixbld group + build users (what a
|
||||
# multi-user install does) before running it.
|
||||
#
|
||||
# Pin the Nix version: the latest (2.34) uses lazy-trees / a git
|
||||
# cache that doesn't materialise flake-input `-source` paths into
|
||||
# the store, so Stylix's import-from-derivation reads fail with
|
||||
# "path '…-source' is not valid". 2.31.5 matches the Nix that wrote
|
||||
# flake.lock locally and evaluates the flake cleanly.
|
||||
run: |
|
||||
NIX_VERSION=2.31.5
|
||||
groupadd -r nixbld 2>/dev/null || true
|
||||
@@ -73,118 +55,47 @@ jobs:
|
||||
curl -L "https://releases.nixos.org/nix/nix-${NIX_VERSION}/install" | sh -s -- --no-daemon
|
||||
echo "$HOME/.nix-profile/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Materialize flake-input sources for eval
|
||||
# Walker's flake reads its own source tree during evaluation:
|
||||
# importTOML resources/config.toml in its home-manager module and
|
||||
# lib.fileset.toSource for the package src (cargoLock.lockFile =
|
||||
# "${src}/Cargo.lock"). On a cold store the input source isn't
|
||||
# materialised, so flake check / eval die with "path '…-source' is
|
||||
# not valid" (works locally only because prior builds materialised
|
||||
# it; `nix flake archive` reports the input but doesn't make the
|
||||
# fileset-derived src readable). `nix build` of walker's src
|
||||
# eagerly realises it — and the input it reads from — priming the
|
||||
# store so the later eval steps find every path valid.
|
||||
run: |
|
||||
nix build --no-link --impure --expr 'let f = builtins.getFlake (toString ./.); in f.inputs.walker.packages.${builtins.currentSystem}.default.src'
|
||||
- name: nix flake check (eval only)
|
||||
# Full module-system evaluation of every output — both nixos
|
||||
# configs, the home config, the checks.* derivations (instantiated,
|
||||
# not run) and the downstream template through lib.mkFlake.
|
||||
run: nix flake check --no-build
|
||||
|
||||
- name: Check flake outputs (except the 22-variant pre-cache package)
|
||||
# Stand-in for `nix flake check --no-build`. That also evaluates
|
||||
# packages.allThemeVariants — a linkFarm whose drvPath forces all 22
|
||||
# home generations into memory at once, OOM-killing the runner. The
|
||||
# eval matrix below already validates every palette one-at-a-time, so
|
||||
# that package's CI value is near-zero. Here we force every other
|
||||
# output (all 4 system closures incl. assertions, both standalone
|
||||
# home generations, the installer VM package, the overlay, the app)
|
||||
# and skip only allThemeVariants/default. Each tryEval is GC'd before
|
||||
# the next, so peak memory is one config, not twenty-two.
|
||||
- name: Python syntax (nomarchy-theme-sync)
|
||||
# Via nix shell so the step doesn't depend on the runner image
|
||||
# preinstalling python3.
|
||||
run: |
|
||||
nix eval --impure --raw --expr 'let
|
||||
f = builtins.getFlake (toString ./.);
|
||||
lib = f.inputs.nixpkgs.lib;
|
||||
sys = "x86_64-linux";
|
||||
ok = x: (builtins.tryEval (builtins.seq x true)).success;
|
||||
checks = {
|
||||
"nixos.default" = ok f.nixosConfigurations.default.config.system.build.toplevel.drvPath;
|
||||
"nixos.nomarchy-installer" = ok f.nixosConfigurations.nomarchy-installer.config.system.build.toplevel.drvPath;
|
||||
"nixos.installerVm" = ok f.nixosConfigurations.installerVm.config.system.build.toplevel.drvPath;
|
||||
"nixos.nomarchy-live" = ok f.nixosConfigurations.nomarchy-live.config.system.build.toplevel.drvPath;
|
||||
"home.nomarchy" = ok f.homeConfigurations.nomarchy.activationPackage.drvPath;
|
||||
"home.nixos" = ok f.homeConfigurations.nixos.activationPackage.drvPath;
|
||||
"packages.installerVm" = ok f.packages.${sys}.installerVm.drvPath;
|
||||
"overlays.default" = ok (builtins.isFunction f.overlays.default);
|
||||
"apps.installerVm" = ok f.apps.${sys}.installerVm.program;
|
||||
};
|
||||
failed = builtins.attrNames (lib.filterAttrs (_: v: !v) checks);
|
||||
in if failed == [] then "ALL OK"
|
||||
else throw ("flake-output checks failed: " + builtins.concatStringsSep ", " failed)'
|
||||
nix shell nixpkgs#python3 --command \
|
||||
python3 -m py_compile pkgs/nomarchy-theme-sync/nomarchy-theme-sync.py
|
||||
|
||||
- name: Evaluate opt-in toggle / palette / home matrix
|
||||
# flake check never flips a nomarchy.* toggle; this does. jq is
|
||||
# provided via nix shell so the step doesn't depend on the runner
|
||||
# image preinstalling it.
|
||||
run: nix shell nixpkgs#jq --command ./bin/utils/nomarchy-eval-matrix
|
||||
|
||||
- name: Lint nomarchy-* scripts (bash -n + shellcheck)
|
||||
- name: Shell syntax (tracked scripts)
|
||||
# The distro's user-facing scripts are generated by Nix (their
|
||||
# syntax is exercised by the eval + local builds); this covers the
|
||||
# hand-written .sh files: installer helpers and maintainer tools.
|
||||
run: |
|
||||
# Mirror what .githooks/pre-commit runs locally, but across the
|
||||
# whole tree instead of just changed files. Pre-commit gates
|
||||
# individual commits; CI gates branches (including --no-verify
|
||||
# bypasses).
|
||||
set -e
|
||||
fail=0
|
||||
while IFS= read -r script; do
|
||||
[[ -f "$script" ]] || continue
|
||||
# Python helpers ship under the same nomarchy- prefix
|
||||
# (e.g. nomarchy-haptic-touchpad). Skip non-bash.
|
||||
head -1 "$script" | grep -qE '^#!.*\bbash\b' || continue
|
||||
head -1 "$script" | grep -qE '^#!.*\b(bash|sh)\b' || continue
|
||||
if ! bash -n "$script"; then
|
||||
echo "::error file=$script::bash syntax error"
|
||||
fail=1
|
||||
fi
|
||||
if ! nix shell nixpkgs#shellcheck --command shellcheck \
|
||||
--severity=error --shell=bash "$script"; then
|
||||
echo "::error file=$script::shellcheck error-severity issue"
|
||||
fail=1
|
||||
fi
|
||||
done < <(find features/scripts/utils core/system/scripts \
|
||||
themes/engine/scripts \
|
||||
-maxdepth 1 -type f -name 'nomarchy-*')
|
||||
done < <(git ls-files '*.sh')
|
||||
exit "$fail"
|
||||
|
||||
- name: docs/SCRIPTS.md is up to date
|
||||
run: |
|
||||
# Regenerate to a temp file and compare. If different, the
|
||||
# contributor forgot to run the generator (or skipped the
|
||||
# pre-commit hook). Fail loudly and tell them the fix.
|
||||
./bin/utils/nomarchy-docs-scripts --out /tmp/SCRIPTS.regen.md
|
||||
if ! diff -q docs/SCRIPTS.md /tmp/SCRIPTS.regen.md >/dev/null; then
|
||||
echo "::error::docs/SCRIPTS.md is stale."
|
||||
echo "Run: ./bin/utils/nomarchy-docs-scripts --out docs/SCRIPTS.md"
|
||||
echo "Then commit the regenerated file."
|
||||
echo "--- diff ---"
|
||||
diff -u docs/SCRIPTS.md /tmp/SCRIPTS.regen.md || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: installer/hardware-db.sh references real nixos-hardware modules
|
||||
run: |
|
||||
# Every 4th-pipe-field in HARDWARE_DB is a nixos-hardware module
|
||||
# name. Half the DB used to point at modules that don't exist
|
||||
# (e.g. microsoft-surface-pro-8 — there's only -pro-intel and
|
||||
# -pro-9), which made the install fail at eval time with
|
||||
# cryptic "attribute not found" errors on real laptops. This
|
||||
# step catches that regression class.
|
||||
awk -F'|' '/^ "/ { gsub(/"/,"",$4); gsub(/^[[:space:]]+|[[:space:]]+$/,"",$4); if ($4) print $4 }' \
|
||||
installer/hardware-db.sh | sort -u > /tmp/db-refs.txt
|
||||
nix eval --impure --json --expr '
|
||||
let
|
||||
nh = (builtins.getFlake (toString ./.)).inputs.nixos-hardware.nixosModules;
|
||||
in builtins.attrNames nh' \
|
||||
| nix shell nixpkgs#jq --command jq -r '.[]' | sort -u > /tmp/db-real.txt
|
||||
missing=$(comm -23 /tmp/db-refs.txt /tmp/db-real.txt)
|
||||
if [[ -n "$missing" ]]; then
|
||||
echo "::error::hardware-db.sh references nixos-hardware modules that don't exist:"
|
||||
printf ' - %s\n' $missing
|
||||
echo "Either fix the name (check the actual attr in nixos-hardware) or drop the row."
|
||||
exit 1
|
||||
fi
|
||||
# ── vm-checks (DISABLED until a KVM runner exists) ────────────────────
|
||||
# The real prize: running the checks.* VM suite + a toplevel build in
|
||||
# CI. Needs a runner on a NixOS (or at least nix + /dev/kvm) host —
|
||||
# register one with a dedicated label, then uncomment and set runs-on
|
||||
# to that label. Do NOT enable this against a label that doesn't
|
||||
# exist: Gitea queues such jobs forever instead of failing.
|
||||
#
|
||||
# vm-checks:
|
||||
# runs-on: nix-kvm
|
||||
# timeout-minutes: 120
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - run: nix flake check # builds + runs the VM tests
|
||||
# - run: nix build .#nixosConfigurations.nomarchy.config.system.build.toplevel --no-link
|
||||
# - run: nix build .#homeConfigurations.nomarchy.activationPackage --no-link
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Nomarchy pre-commit hook.
|
||||
#
|
||||
# Enable per-clone with:
|
||||
# git config core.hooksPath .githooks
|
||||
#
|
||||
# Two responsibilities:
|
||||
# 1. Lint changed nomarchy-* scripts (bash -n + shellcheck if available)
|
||||
# so syntax errors and unquoted-var bugs don't ship.
|
||||
# 2. Regenerate docs/SCRIPTS.md when any nomarchy-* script under the three
|
||||
# script directories is added, modified, or deleted in this commit, and
|
||||
# stage the refreshed file so it lands with the change.
|
||||
|
||||
set -e
|
||||
|
||||
repo_root="$(git rev-parse --show-toplevel)"
|
||||
cd "$repo_root"
|
||||
|
||||
script_dirs_re='^(features/scripts/utils|core/system/scripts|themes/engine/scripts)/nomarchy-'
|
||||
|
||||
# 1. Lint changed scripts. bash -n catches syntax errors (always fatal).
|
||||
# shellcheck catches unquoted-var, use-before-define, missing-shebang, etc.
|
||||
# We only fail on severity=error so the long tail of pre-existing warnings
|
||||
# (info / style / warning) doesn't block commits — those can be cleaned up
|
||||
# incrementally without a flag day.
|
||||
changed_scripts=$(git diff --cached --name-only --diff-filter=ACMR \
|
||||
| grep -E "$script_dirs_re" || true)
|
||||
if [[ -n "$changed_scripts" ]]; then
|
||||
while IFS= read -r script; do
|
||||
[[ -f "$script" ]] || continue
|
||||
# Only lint scripts with a bash shebang. nomarchy-* is a name
|
||||
# convention, not a language guarantee — at least one Python helper
|
||||
# ships under the same prefix (nomarchy-haptic-touchpad).
|
||||
head -1 "$script" | grep -qE '^#!.*\bbash\b' || continue
|
||||
if ! bash -n "$script"; then
|
||||
echo "pre-commit: bash syntax error in $script — aborting commit." >&2
|
||||
exit 1
|
||||
fi
|
||||
if command -v shellcheck >/dev/null 2>&1; then
|
||||
if ! shellcheck --severity=error --shell=bash "$script"; then
|
||||
echo "pre-commit: shellcheck found error-level issues in $script — aborting commit." >&2
|
||||
echo "pre-commit: fix the reported issues, or rerun with --no-verify after a deliberate decision to ship." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done <<< "$changed_scripts"
|
||||
fi
|
||||
|
||||
# 2. Regenerate the script audit doc.
|
||||
if git diff --cached --name-only --diff-filter=ACMRD | grep -qE "$script_dirs_re"; then
|
||||
echo "pre-commit: regenerating docs/SCRIPTS.md (script change detected)…"
|
||||
./bin/utils/nomarchy-docs-scripts --out docs/SCRIPTS.md
|
||||
git add docs/SCRIPTS.md
|
||||
fi
|
||||
21
.gitignore
vendored
21
.gitignore
vendored
@@ -1,15 +1,14 @@
|
||||
# ---> Nix
|
||||
# Ignore build outputs from performing a nix-build or `nix build` command
|
||||
# Study material from the previous iteration — not part of the flake.
|
||||
# Delete the directory once everything worth porting has been ported.
|
||||
old_distro/
|
||||
|
||||
# Nix build artifacts
|
||||
result
|
||||
result-*
|
||||
|
||||
# Ignore automatically generated direnv output
|
||||
.direnv
|
||||
__pycache__/
|
||||
.DS_Store
|
||||
|
||||
# Local IDE settings
|
||||
.claude/
|
||||
|
||||
# VM and ISO artifacts
|
||||
*.qcow2
|
||||
*.qcow
|
||||
*.iso
|
||||
# Claude Code machine-local settings (permissions etc.)
|
||||
.claude/settings.local.json
|
||||
.claude/skills/
|
||||
|
||||
42
CLAUDE.md
Normal file
42
CLAUDE.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Nomarchy — agent entry point
|
||||
|
||||
Nomarchy is a NixOS-based distro: rock-stable, fully reproducible, themed
|
||||
from one JSON, configured through a menu that writes into the user's own
|
||||
flake checkout. Read the README for the architecture.
|
||||
|
||||
## If you're here to work autonomously (the loop)
|
||||
Follow **`agent/LOOP.md`** — it defines one iteration: orient
|
||||
(GOALS/BACKLOG/JOURNAL/MEMORY), take the top actionable BACKLOG item,
|
||||
verify up the V0–V3 ladder, commit+push on `main`, record. All loop state
|
||||
is git-tracked in `agent/`.
|
||||
|
||||
## Rules that apply to every session, loop or not
|
||||
- **Honesty rule** (docs/TESTING.md): for visual/interactive changes,
|
||||
evaluation is not rendering — state exactly what you verified and at
|
||||
which tier. Cheap check first, always: `nix flake check --no-build`.
|
||||
- **Conventions** (`agent/CONVENTIONS.md`): in-flake state, menu
|
||||
placement, Waybar parity with the summer whole-swaps, toggle-vs-package
|
||||
discipline, commented template examples for opt-ins.
|
||||
- **Git:** direct commits on `main`, pushed; `v1` is the human-only
|
||||
release pointer — never touch it. Never run `nix flake update` unless
|
||||
the task is a lock bump. No formatter — match the aligned
|
||||
hand-formatting.
|
||||
- Machine-specifics live in `hosts/`, the distro in `modules/`, data in
|
||||
`themes/`, code in `pkgs/`, maintainer tools in `tools/`.
|
||||
|
||||
## Delegation
|
||||
|
||||
The higher your tier, the more you delegate. Push the work down, keep your own context for judgment. Brief every child: the context, the why, what done looks like. It starts blank and inherits nothing.
|
||||
|
||||
| Model | Best for | Delegate? | Effort |
|
||||
|---|---|---|---|
|
||||
| Haiku | bulk mechanical | never | low |
|
||||
| Sonnet | scoped research | when it helps | medium |
|
||||
| Opus 4.8 | multi-step reasoning | on clear benefit | xhigh |
|
||||
| Fable 5 | judgment, taste | by default | medium |
|
||||
|
||||
Fable goes xhigh only for the hardest calls. Skip high.
|
||||
|
||||
## Escalation
|
||||
|
||||
The parent doesn't have to be the top model. An Opus parent spawns a Fable child for the one hard call. The child answers and returns. Work above your tier? Return it, don't burn tokens on it.
|
||||
508
README.md
508
README.md
@@ -1,118 +1,442 @@
|
||||
# 👑 Nomarchy
|
||||
# Nomarchy
|
||||
|
||||
**Nomarchy** is a professional-grade NixOS distribution that ships a highly curated Hyprland desktop on a strictly declarative, flake-based foundation. It provides a highly polished, "it just works" experience for power users who want a beautiful Wayland environment without sacrificing the reliability of NixOS.
|
||||
**The rock-solid reproducibility of NixOS 26.05. The out-of-the-box polish of
|
||||
Omarchy/Omakub.** One JSON file rules the look of the entire desktop; every
|
||||
theme change is a Home Manager generation — atomic, rollbackable, never
|
||||
partial.
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
- **Purely Declarative:** Your entire desktop—themes, fonts, wallpapers, and toolchains—is defined in code.
|
||||
- **Modular Merging Architecture:** Distro code and user code are strictly separated. You can update the distro core without ever touching or breaking your personal configurations.
|
||||
- **Interactive "Smart" Installer:** Detects hardware, sets up networking, localizes timezones/keymaps, and offers multi-select software profiles.
|
||||
- **Erase Your Darlings (Optional):** Optional BTRFS root-wipe on boot ensures your system stays pristine and 100% declarative.
|
||||
- **Dynamic Theming Engine:** 20+ built-in themes with instant UI feedback via IPC (swww, waybar, and stylix).
|
||||
- **Portable State (`nomarchy-sync`):** Easily backup and sync your declarative config and dynamic state (theme/wallpaper choices) to a private Git repo.
|
||||
|
||||
---
|
||||
|
||||
## 📂 Component-Based Architecture
|
||||
|
||||
Nomarchy uses a **Feature-Centric Directory Structure**. For a comprehensive breakdown of the system architecture, folder roles, and module logic, see the [Detailed Architecture Documentation](docs/STRUCTURE.md).
|
||||
|
||||
Configuration, modules, and utilities are strictly organized to maintain sanity as the system grows.
|
||||
|
||||
- **`core/`**: Foundational OS & User defaults (Bootloader, Audio, Bluetooth, core system features).
|
||||
- **`features/`**: Isolated modules containing Nix logic and raw dotfiles.
|
||||
- **`features/apps/`**: App-specific configs (e.g., `features/apps/btop/`, `features/apps/kitty/`), each containing their own `default.nix` and standalone `config/` directory mapped via Home Manager.
|
||||
- **`features/desktop/`**: Desktop environment components (e.g., Hyprland, Waybar).
|
||||
- **`features/scripts/utils/`**: Consolidated repository for all custom Nomarchy bash scripts, centrally packaged and injected into the user's `PATH` with correct dependencies.
|
||||
- **`themes/`**: The global theming engine. It holds pure color data and logic. *Theme-specific app layouts* (like a custom Waybar layout) are stored directly inside the app's feature folder, solving the matrix problem of theming.
|
||||
|
||||
---
|
||||
|
||||
## 📥 Installation
|
||||
|
||||
### 1. Try it in a VM (Recommended)
|
||||
Verify the experience without touching your hardware:
|
||||
```bash
|
||||
./bin/utils/nomarchy-test-installer
|
||||
```
|
||||
This builds a full graphical VM of the installer environment. Once inside, click the **Install Nomarchy** icon or run `nomarchy-install`.
|
||||
|
||||
### 2. Build the Installer ISO
|
||||
To install on physical hardware, generate your own bootable image:
|
||||
```bash
|
||||
./features/scripts/utils/nomarchy-build-iso # Minimal TTY installer
|
||||
./features/scripts/utils/nomarchy-build-live-iso # Graphical try-before-install
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ theme-state.json (single source of truth) │
|
||||
│ lives INSIDE your flake checkout, git-tracked │
|
||||
└───────────────────────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
nomarchy-theme-sync apply gruvbox
|
||||
1. merges the preset into the JSON (atomic write)
|
||||
2. runs `home-manager switch` (no sudo, no system rebuild)
|
||||
│
|
||||
▼ pure read (nomarchy.stateFile)
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ Home Manager bakes EVERYTHING into one read-only generation: │
|
||||
│ Hyprland (colors/gaps/borders) Waybar (palette or whole-swap) │
|
||||
│ Ghostty (full ANSI palette) btop (asset or generated) │
|
||||
│ Stylix → GTK, Qt, cursors, fonts │
|
||||
└───────────────────────────────────┬──────────────────────────────────────┘
|
||||
▼
|
||||
wallpaper via awww (the one runtime piece:
|
||||
applied post-switch + at session start, `bg next` cycles)
|
||||
```
|
||||
The ISO will be located at `./result/iso/nixos-*.iso`. Flash it to a USB drive and boot.
|
||||
|
||||
### 3. Run the Installer
|
||||
Once booted into the Live environment, launch the installer:
|
||||
```bash
|
||||
nomarchy-install
|
||||
## 1. Layout
|
||||
|
||||
Flat on purpose. Two module trees, one options file each, no hidden layers.
|
||||
|
||||
```
|
||||
.
|
||||
├── flake.nix # inputs + the downstream API (exports below)
|
||||
├── lib.nix # nomarchy.lib.mkFlake — one-call downstream wrapper
|
||||
├── theme-state.json # ★ THE single source of truth (git-tracked!)
|
||||
├── themes/ # 21 presets: <slug>.json + optional <slug>/ assets
|
||||
│ ├── nord.json # palette (required, works alone)
|
||||
│ └── nord/ # assets (optional, fixed filenames)
|
||||
│ ├── backgrounds/ # wallpapers (auto-picked, SUPER+SHIFT+T cycles)
|
||||
│ ├── btop.theme # hand-made config drop (else generated)
|
||||
│ └── waybar.css # whole-swap: replaces the generated bar style
|
||||
├── modules/
|
||||
│ ├── nixos/ # the distro, system side
|
||||
│ │ ├── default.nix # Hyprland session, Pipewire, greetd, fonts
|
||||
│ │ ├── options.nix # nomarchy.system.* toggles
|
||||
│ │ ├── plymouth.nix # boot splash, tinted from the JSON
|
||||
│ │ ├── file-manager.nix # Thunar GUI + gvfs/tumbler/udisks2
|
||||
│ │ └── power.nix # power-profiles-daemon/TLP, thermald, charge limit
|
||||
│ └── home/ # the distro, user side
|
||||
│ ├── default.nix # entry point
|
||||
│ ├── options.nix # nomarchy.* option surface
|
||||
│ ├── theme.nix # JSON ingestion + wallpaper hook
|
||||
│ ├── stylix.nix # GTK/Qt/cursors/fonts from the same JSON
|
||||
│ ├── hyprland.nix # all JSON-driven
|
||||
│ ├── waybar.nix
|
||||
│ ├── ghostty.nix
|
||||
│ ├── btop.nix
|
||||
│ ├── rofi.nix # launcher + nomarchy-menu (calc, emoji, clip…)
|
||||
│ ├── keybinds.nix # single source: Hyprland binds + SUPER+? sheet
|
||||
│ ├── swaync.nix # notifications, same JSON
|
||||
│ ├── idle.nix # hyprlock + hypridle, same JSON
|
||||
│ ├── yazi.nix # flagship TUI file manager + plugins
|
||||
│ ├── osd.nix # swayosd volume/brightness OSD
|
||||
│ ├── shell.nix # zsh + starship + bat/eza/zoxide
|
||||
│ ├── keys.nix # gpg-agent fronting SSH, pinentry-qt
|
||||
│ └── fastfetch.nix # themed Nomarchy logo + system info
|
||||
├── hosts/
|
||||
│ ├── default/ # reference machine (thin: boot, user, hostname)
|
||||
│ └── live.nix # bootable live ISO (try the distro, no install)
|
||||
├── pkgs/
|
||||
│ ├── nomarchy-theme-sync/ # state writer + rebuild dispatcher (Python)
|
||||
│ └── nomarchy-install/ # live-ISO installer (gum + disko + mkFlake)
|
||||
├── templates/downstream/ # `nix flake init -t` starter for users
|
||||
├── docs/TESTING.md # how to verify changes (incl. AI-agent rules)
|
||||
├── docs/OVERRIDES.md # how downstream users override defaults
|
||||
├── docs/RECOVERY.md # runbook: broken theme/desktop/boot → undo it
|
||||
├── docs/ROADMAP.md # design/decision records + shipped-fixes log
|
||||
├── agent/ # autonomous-agent loop: protocol (LOOP.md),
|
||||
│ # prioritized BACKLOG, journal, memory
|
||||
└── tools/ # maintainer-only
|
||||
├── import-palettes.py # converts old-distro themes → JSON + assets
|
||||
├── test-live-iso.sh # build the ISO + boot it in QEMU
|
||||
├── test-install.sh # full offline-install regression in QEMU
|
||||
└── vm/ # headless-VM helpers (QMP keys, VNC shots,
|
||||
# offline-pin gap analysis)
|
||||
```
|
||||
The wizard will guide you through:
|
||||
- **Networking:** An interactive wizard to connect to Wi-Fi if needed.
|
||||
- **Hardware:** Optimized profiles for Dell XPS, Framework, Apple T2, and more.
|
||||
- **Storage:** Choice between Standard Ext4 or Encrypted BTRFS with optional **Impermanence**.
|
||||
- **Localization:** Searchable timezones and keyboard layout selection.
|
||||
|
||||
### Already on NixOS?
|
||||
Layer Nomarchy onto an existing 25.11 install without reformatting — see the [Migration Guide](docs/MIGRATION.md).
|
||||
**Rule of thumb:** `modules/` is the distro (reusable, no machine specifics),
|
||||
`hosts/` is a machine, `themes/` is data, `pkgs/` is code, `tools/` is
|
||||
maintainer-only. If a new file doesn't obviously belong to one of those, it
|
||||
probably shouldn't exist.
|
||||
|
||||
---
|
||||
## 2. Try it first (live ISO)
|
||||
|
||||
## 🛠️ Configuration & Usage
|
||||
Boot the full desktop from a USB stick or VM without installing anything:
|
||||
|
||||
Nomarchy uses a "Downstream" model. After installation, your configuration lives in `/etc/nixos/` and is split into three main parts:
|
||||
```sh
|
||||
nix build .#nixosConfigurations.nomarchy-live.config.system.build.isoImage
|
||||
# → result/iso/*.iso — dd to a stick, or boot it in QEMU:
|
||||
tools/test-live-iso.sh
|
||||
```
|
||||
|
||||
### 1. Distro Core (Upstream)
|
||||
Managed via the public Git repository. This is the engine. You should generally not modify files here.
|
||||
The live session auto-logs-in, seeds the flake at `~/.nomarchy`, and pins
|
||||
the locked inputs into the ISO store — so theme switching (including the
|
||||
`home-manager switch` it triggers) works **offline**, exactly like on an
|
||||
installed system. Verification checklist: [docs/TESTING.md](docs/TESTING.md).
|
||||
|
||||
Like what you see? **`nomarchy-install`** (in a terminal) walks you through
|
||||
installing to disk: pick a disk, LUKS2 full-disk encryption **by default**
|
||||
(in exchange the desktop logs in passwordless — the passphrase already
|
||||
gates the machine), user + hostname + timezone, hardware autodetection
|
||||
(DMI → nixos-hardware profile), a hibernation-ready swapfile sized to RAM,
|
||||
then disko partitions (GPT + ESP + BTRFS subvolumes incl. `@snapshots` —
|
||||
snapper timeline snapshots are on) and `nixos-install` runs — **without a
|
||||
network** when the ISO was built from a clean tree (the target's
|
||||
`flake.lock` is composed from the rev the ISO carries). The installed
|
||||
machine gets the standard downstream layout: the flake at `~/.nomarchy`
|
||||
(`/etc/nixos` symlinks to it), one `mkFlake` call, your
|
||||
`system.nix`/`home.nix`. First boot lands in the fully themed desktop —
|
||||
the installer pre-activates the Home Manager generation. UEFI only for now.
|
||||
|
||||
## 3. Using Nomarchy on your machine (downstream)
|
||||
|
||||
Nomarchy is consumed as a flake input — you never fork or edit this repo:
|
||||
|
||||
```sh
|
||||
mkdir my-machine && cd my-machine
|
||||
nix flake init -t "git+https://git.bemagri.xyz/bernardo/nomarchy.git?ref=v1"
|
||||
```
|
||||
|
||||
The template's own README then walks the first-run steps: a real
|
||||
`hardware-configuration.nix`, `git init` (flakes only see tracked
|
||||
files), the two first rebuilds, and landing the checkout at
|
||||
`~/.nomarchy` so the theme CLI finds it. (The installer does all of
|
||||
this for you.)
|
||||
|
||||
You own two files day-to-day: `system.nix` and `home.nix` (plus
|
||||
`theme-state.json`, written by the CLI). Your `flake.nix` is set up once —
|
||||
later by the installer — and never hand-edited; it's a single call:
|
||||
|
||||
### 2. Your System (`system.nix`)
|
||||
Add system-wide packages, services, and hardware tweaks here.
|
||||
*Example: Adding a persistent directory for Docker if using Impermanence:*
|
||||
```nix
|
||||
environment.persistence."/persist" = {
|
||||
directories = [ "/var/lib/docker" ];
|
||||
outputs = { nomarchy, ... }:
|
||||
nomarchy.lib.mkFlake {
|
||||
src = ./.;
|
||||
username = "me";
|
||||
hardwareProfile = "framework-13-7040-amd"; # optional, nixos-hardware name
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Your User Environment (`home.nix`)
|
||||
Add user-level packages, aliases, and dotfiles here.
|
||||
*Example: Overriding the default terminal:*
|
||||
```nix
|
||||
nomarchy.home.terminal = "kitty";
|
||||
| `mkFlake` arg | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `src` | — (required) | Your flake directory (`./.`) |
|
||||
| `username` | — (required) | Login name; flows into `system.nix` and names the HM config |
|
||||
| `hardwareProfile` | `null` | One [nixos-hardware](https://github.com/NixOS/nixos-hardware) module name, or a list of them (pinned + tested by Nomarchy; unknown names fail with suggestions) |
|
||||
| `system` | `"x86_64-linux"` | Platform |
|
||||
|
||||
(Power users can skip `mkFlake` and wire `nixosModules.nomarchy` /
|
||||
`homeModules.nomarchy` / `overlays.default` by hand — the wrapper is sugar.)
|
||||
|
||||
Two deliberately separate rebuild paths:
|
||||
|
||||
```sh
|
||||
sudo nixos-rebuild switch --flake .#default # system: rare
|
||||
home-manager switch --flake .#me # desktop: every theme change, no sudo
|
||||
```
|
||||
|
||||
For the full list of `nomarchy.*` options you can set in `system.nix` and `home.nix`, see the [Options Reference](docs/OPTIONS.md). For custom automation, see [Runtime Hooks](docs/HOOKS.md). Hit a rebuild error? Check [Troubleshooting](docs/TROUBLESHOOTING.md). For where the project is heading next, see the [Roadmap](docs/ROADMAP.md).
|
||||
Day-to-day you'll use the shipped shortcuts instead:
|
||||
|
||||
### Applying Changes
|
||||
After editing your files, apply them instantly. **IMPORTANT:** Nomarchy requires the `--impure` flag for evaluation. You **MUST** use the following aliases rather than standard NixOS commands:
|
||||
|
||||
```bash
|
||||
sys-update # Rebuilds the NixOS system (Runs: sudo nixos-rebuild switch --flake .#default --impure)
|
||||
env-update # Reloads your Home Manager environment (Runs: home-manager switch --flake .#default --impure)
|
||||
```sh
|
||||
sys-update # nix flake update + system rebuild (BTRFS snapshot first when available)
|
||||
sys-rebuild # system rebuild against the CURRENT lock (config changes only, no update)
|
||||
# …both end with a package-level diff of what the rebuild changed (nvd)
|
||||
home-update # home-manager switch (no flake update, no sudo)
|
||||
```
|
||||
|
||||
---
|
||||
**Order matters when pulling distro updates.** `home-update` does *not*
|
||||
touch the lock — it rebuilds the desktop against the **current**
|
||||
`flake.lock`. A new Nomarchy revision (new keybinds, theming, modules)
|
||||
arrives only when the lock is updated, which `sys-update` does
|
||||
(`nix flake update`). So to pull an update that affects the desktop layer:
|
||||
run `sys-update` **first** (updates the lock + rebuilds the system), **then**
|
||||
`home-update` (re-applies the desktop against the new lock). Doing them in
|
||||
the other order rebuilds the desktop against the *old* inputs and silently
|
||||
skips the new home-side changes. After a home-side keybind/config change,
|
||||
also `hyprctl reload` (or relogin) so the running session re-reads it.
|
||||
|
||||
## 🚀 Commands & Keybindings
|
||||
Override anything via the `nomarchy.*` surface or plain NixOS/HM options:
|
||||
appearance (gaps/colors/fonts) changes through `nomarchy-theme-sync`,
|
||||
behaviour (input/misc/monitor/chrome) is `mkDefault` so a plain `home.nix`
|
||||
assignment wins, and bind/exec-once lists concatenate. Full guide with
|
||||
examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**.
|
||||
|
||||
The full list lives in [`docs/KEYBINDINGS.md`](docs/KEYBINDINGS.md) (auto-generated from the Hyprland configs). A few highlights:
|
||||
**Where each option goes.** `nomarchy.system.*`, `nomarchy.hardware.*`, and
|
||||
`nomarchy.services.*` are NixOS options — set them in `system.nix`. Everything
|
||||
else under `nomarchy.*` is a Home Manager option — set it in `home.nix`. The
|
||||
two tables below are split along exactly that line.
|
||||
|
||||
| Keybinding | Action |
|
||||
| :--- | :--- |
|
||||
| `Super + Space` | **App Launcher** (Walker) |
|
||||
| `Super + Shift + Space` | **Nomarchy Menu** (Walker) |
|
||||
| `Super + Alt + Space` | **Toggle Top Bar** (Waybar) |
|
||||
| `Super + Return` | Open Terminal |
|
||||
| `Super + Q` | Close Window |
|
||||
**`home.nix`** (Home Manager — the desktop):
|
||||
|
||||
### Utility Scripts
|
||||
Nomarchy includes dozens of productivity scripts available in your PATH. Some highlights:
|
||||
- `nomarchy-sync push <repo>`: Backup your setup to Git.
|
||||
- `nomarchy-theme-bg-next`: Cycle to the next wallpaper in the current theme.
|
||||
- `nomarchy-menu`: The central hub for all utilities and pickers.
|
||||
| Option | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `nomarchy.stateFile` | — (required) | Path to your theme-state.json |
|
||||
| `nomarchy.terminal` | `"ghostty"` | Terminal for keybinds and `$TERMINAL` |
|
||||
| `nomarchy.keyboard.layout` | `"us"` | XKB layout for the Hyprland session (installer writes the matching `services.xserver.xkb` in system.nix; the console + LUKS prompt follow via the distro default) |
|
||||
| `nomarchy.keyboard.variant` | `""` | XKB variant for the session |
|
||||
| `nomarchy.keyboard.devices` | `{}` | Per-device layout overrides (Hyprland `device` blocks keyed by `hyprctl devices` name) — e.g. an external keyboard with its own layout/variant |
|
||||
| `nomarchy.keyboard.layouts` | `[]` | Extra candidate layouts; when set, a watcher prompts (rofi) for a layout on a newly-connected keyboard and remembers it per-device |
|
||||
| `nomarchy.nightlight.enable` | `false` | Scheduled blue-light filter (hyprsunset) — warm at night (`.temperature`, default 4000K) between `.sunset`/`.sunrise`, no shift by day; off by default — enable it from the menu (System › Night light; the first enable rebuilds), then toggle on/off instantly from the menu or the Waybar moon indicator (writes `settings.nightlight.on` in your flake, no rebuild) and it survives reboot, so it stays reproducible |
|
||||
| `nomarchy.updates.enable` | `false` | Passive update awareness: a background check (`.interval`, default daily) that flags when flake inputs (nixpkgs, the Nomarchy input, …) are behind upstream — and, with Flatpak on, when apps have updates (`.flatpak`) — via a Waybar indicator + notification. Never changes anything; click the indicator to run the upgrade flow |
|
||||
| `nomarchy.hyprland.enable` | `true` | Nomarchy's Hyprland config |
|
||||
| `nomarchy.waybar.enable` | `true` | Nomarchy's Waybar |
|
||||
| `nomarchy.rofi.enable` | `true` | Themed rofi launcher + `nomarchy-menu` dispatcher |
|
||||
| `nomarchy.swaync.enable` | `true` | swaync notifications, themed |
|
||||
| `nomarchy.batteryNotify.enable` | `true` | Low-battery toasts at the bar's thresholds — 25% low, 10% critical (stays up until dismissed); silent no-op on machines without a battery |
|
||||
| `nomarchy.idle.enable` | `true` | hyprlock + hypridle (idle lock 5 min, display off 10, suspend 30) |
|
||||
| `nomarchy.yazi.enable` | `true` | yazi TUI file manager, themed + curated plugins |
|
||||
| `nomarchy.osd.enable` | `true` | swayosd on-screen display for volume/brightness/mute |
|
||||
| `nomarchy.shell.enable` | `true` | zsh + starship prompt + bat/eza/zoxide (zsh is the default login shell) |
|
||||
| `nomarchy.ghostty.enable` | `true` | Nomarchy's Ghostty |
|
||||
| `nomarchy.btop.enable` | `true` | btop with per-theme colors |
|
||||
| `nomarchy.stylix.enable` | `true` | GTK/Qt/cursor theming |
|
||||
| `nomarchy.fastfetch.enable` | `true` | fastfetch fronted by the themed Nomarchy logo |
|
||||
| `nomarchy.keys.enable` | `true` | gpg-agent fronting SSH + pinentry-qt |
|
||||
| `nomarchy.displays.enable` | `true` | nwg-displays interactive monitor arranger (helper for `nomarchy.monitors`) |
|
||||
| `nomarchy.viewers.enable` | `true` | Document/image viewers: zathura (Stylix-themed PDF) + imv |
|
||||
| `nomarchy.mime.enable` | `true` | Default "open with" associations (PDF/image/video/text/browser/directory); entries for apps you removed are skipped, so it degrades with the suite |
|
||||
| `nomarchy.monitors` | `[]` | Declarative per-output layout → Hyprland `monitor` rules (applied on hotplug); `,preferred,auto,1` wildcard kept as fallback |
|
||||
| `nomarchy.displayProfiles` | `{}` | Named layouts for the same outputs (docked/undocked/…), switched from System › Display › Profiles: instant via hyprctl, persisted in-flake (`settings.displayProfile`), baked over `nomarchy.monitors` at the next rebuild. The menu's Auto-switch row (`settings.displayProfileAuto`) makes plugging/unplugging outputs apply the matching profile automatically. A profile can also pin workspaces to outputs (`workspaces = { "1" = "DP-3"; }`) — moved instantly on switch, baked as Hyprland `workspace` rules |
|
||||
| `nomarchy.launchOrFocus` | `[]` | Launch-or-focus binds: `SUPER+<key>` focuses the app's window (case-insensitive class match) or launches it; entries land in the SUPER+? cheatsheet, and a bind whose app was removed notifies instead of failing silently |
|
||||
| `nomarchy.themesDir` | Nomarchy's `themes/` | Where per-theme app overrides are probed |
|
||||
| `nomarchy.package` | overlay's `nomarchy-theme-sync` | The theme/state tool package, overridable if you fork it |
|
||||
|
||||
---
|
||||
*Built with ❤️ using NixOS, Hyprland, Stylix, and the Nomarchy Community.*
|
||||
**`system.nix`** (NixOS — the machine):
|
||||
|
||||
| Option | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `nomarchy.system.plymouth.enable` | `true` | Branded boot splash, background from the theme JSON (recolors on system rebuilds) |
|
||||
| `nomarchy.system.stateFile` | `null` | theme-state.json for the system-side consumers (the Plymouth tint); `lib.mkFlake` wires it for you — set it only when composing the modules by hand |
|
||||
| `nomarchy.system.fileManager.enable` | `true` | Thunar GUI + gvfs/tumbler/udisks2 (the "open folder" handler) |
|
||||
| `nomarchy.system.greeter.enable` | `true` | greetd/tuigreet |
|
||||
| `nomarchy.system.greeter.autoLogin` | `null` | Auto-login this user into Hyprland (installer sets it on LUKS machines) |
|
||||
| `nomarchy.system.audio.enable` | `true` | Pipewire stack |
|
||||
| `nomarchy.system.bluetooth.enable` | `true` | Bluetooth + blueman |
|
||||
| `nomarchy.system.autoTimezone.enable` | `false` | Automatic timezone (geoclue + automatic-timezoned) — the clock follows your location; toggle from System › Auto timezone (a menu enable rebuilds: it has to unset the static `time.timeZone`) |
|
||||
| `nomarchy.system.snapper.enable` | `false` | Hourly/daily BTRFS timeline snapshots + `nixos-rebuild-snap` (installer enables it; no-op unless root is BTRFS) |
|
||||
| `nomarchy.system.power.enable` | `true` | Active power management (see below) |
|
||||
| `nomarchy.system.power.backend` | `"ppd"` | `"ppd"` (power-profiles-daemon + menu/Waybar switcher) or `"tlp"` (deeper battery tuning, no switcher) — mutually exclusive |
|
||||
| `nomarchy.system.power.laptop` | `false` | Marks a laptop, gating battery-only features; the installer sets it when a battery is present |
|
||||
| `nomarchy.system.power.thermal.enable` | `false` | thermald (Intel-only); the installer enables it on a GenuineIntel CPU |
|
||||
| `nomarchy.system.power.batteryChargeLimit` | `null` | Stop charging at this % (e.g. `80`) where the hardware supports it; needs `power.laptop` |
|
||||
| `nomarchy.hardware.intel.enable` | `false` | Intel enablement above nixos-hardware (GuC/HuC firmware via `i915.enable_guc=3` — `.guc` toggles just that; the installer unsets it on `xe`-driver GPUs); the installer sets it on an Intel CPU/GPU |
|
||||
| `nomarchy.hardware.intel.computeRuntime` | `false` | Opt-in: Intel GPU compute — OpenCL/Level-Zero (`intel-compute-runtime`) + oneVPL (`vpl-gpu-rt`) |
|
||||
| `nomarchy.hardware.amd.enable` | `false` | AMD enablement above nixos-hardware (amd-pstate EPP + radeonsi VA-API, each toggleable via `.pstate` / `.vaapi`); installer-set on an AMD CPU/GPU |
|
||||
| `nomarchy.hardware.amd.rocm.enable` | `false` | Opt-in: ROCm HIP/OpenCL GPU compute (multi-GB); pair with `.gfxOverride` (e.g. `"11.0.0"`) for an unlisted iGPU |
|
||||
| `nomarchy.hardware.fingerprint.enable` | `false` | fprintd for a detected fingerprint reader (installer-set); enroll with `fprintd-enroll` |
|
||||
| `nomarchy.hardware.fingerprint.pam` | `false` | Opt-in: use the fingerprint for login + sudo (PAM) |
|
||||
| `nomarchy.hardware.npu.enable` | `false` | Opt-in/experimental: load the on-die NPU driver (`amdxdna`/`intel_vpu`); userspace runtime is BYO |
|
||||
| `nomarchy.hardware.latestKernel` | `false` | Opt-in: ship `linuxPackages_latest` instead of the default kernel — for very new hardware whose drivers landed recently |
|
||||
| `nomarchy.hardware.camera.hideIrSensor` | `false` | Hide a dual-sensor webcam's IR node from PipeWire so apps only ever see the colour camera (the "second, dark Integrated Camera"); installer-set on a paired RGB+IR webcam. `/dev/video*` stays open, so Howdy-style face unlock still works; `.irMatch` overrides the IR-name regex |
|
||||
| `nomarchy.services.tailscale.enable` | `false` | Opt-in: Tailscale mesh VPN (then `sudo tailscale up`) |
|
||||
| `nomarchy.services.syncthing.enable` | `false` | Opt-in: Syncthing file sync as the login user (GUI at `127.0.0.1:8384`) |
|
||||
| `nomarchy.services.podman.enable` | `false` | Opt-in: rootless Podman (`docker` aliased to it) |
|
||||
| `nomarchy.services.flatpak.enable` | `false` | Opt-in: Flatpak + the Flathub remote |
|
||||
| `nomarchy.services.pika.enable` | `false` | Opt-in: Pika Backup (GUI Borg backups) |
|
||||
| `nomarchy.services.steam.enable` | `false` | Opt-in: Steam via `programs.steam` (32-bit libs, controller udev, Remote-Play ports) |
|
||||
| `nomarchy.services.libvirt.enable` | `false` | Opt-in: libvirt/KVM + virt-manager GUI (login user added to `libvirtd`) |
|
||||
| `nomarchy.services.obs.enable` | `false` | Opt-in: OBS Studio + a v4l2loopback virtual camera (selectable as a webcam in Zoom/Teams) |
|
||||
| `nomarchy.services.docker.enable` | `false` | Opt-in: rootful Docker (user in `docker` group); don't enable alongside podman |
|
||||
| `nomarchy.services.kdeconnect.enable` | `false` | Opt-in: KDE Connect phone integration (opens its firewall ports) |
|
||||
| `nomarchy.services.gamemode.enable` | `false` | Opt-in: Feral GameMode performance daemon (`gamemoderun`) |
|
||||
| `nomarchy.services.adb.enable` | `false` | Opt-in: Android adb/fastboot tools (systemd handles device udev rules) |
|
||||
| `nomarchy.services.wireshark.enable` | `false` | Opt-in: Wireshark Qt GUI (user in `wireshark` group, capture without root) |
|
||||
| `nomarchy.services.ollama.enable` | `false` | Opt-in: Ollama local LLM runtime on `127.0.0.1:11434` (CPU; GPU via `services.ollama.acceleration`) |
|
||||
| `nomarchy.services.printing.enable` | `false` | Opt-in: CUPS + Avahi/mDNS network printer discovery |
|
||||
| `nomarchy.services.openrgb.enable` | `false` | Opt-in: OpenRGB daemon for RGB peripheral/motherboard lighting |
|
||||
| `nomarchy.services.restic.enable` | `false` | Opt-in: scheduled daily restic backup (set `.repository` + `.passwordFile`; backs up `.paths`, default `/home`; 7/4/6 retention; list/restore via the `restic-nomarchy` wrapper) |
|
||||
|
||||
Beyond the `nomarchy.*` surface, the system layer turns on the usual
|
||||
desktop services with `lib.mkDefault` (override natively). Two worth
|
||||
calling out: **`services.fwupd.enable`** is on by default for firmware
|
||||
updates via LVFS — it only refreshes metadata, never flashes on its own,
|
||||
so run `fwupdmgr update` to apply; disable with `services.fwupd.enable =
|
||||
false;` on machines without real firmware (VMs/headless). And
|
||||
**`services.earlyoom`** is on by default so running out of memory kills
|
||||
the offending process (with a desktop notification) instead of freezing
|
||||
the desktop — process-level on purpose, since a Hyprland session is one
|
||||
cgroup and systemd-oomd would kill all of it (oomd is disabled
|
||||
accordingly). Opt out with `services.earlyoom.enable = false;`.
|
||||
|
||||
## 4. How theming works
|
||||
|
||||
### Pure JSON ingestion
|
||||
|
||||
The trap with "read a mutable file from Nix" is pure evaluation: flakes
|
||||
cannot read arbitrary `$HOME` paths without `--impure` (the old prototype
|
||||
required it — never again). Nomarchy's convention: **the state file lives
|
||||
inside the consuming flake** and is wired via
|
||||
`nomarchy.stateFile = ./theme-state.json;`. Reading it is pure — it's flake
|
||||
source. It must be git-tracked (`nomarchy-theme-sync` runs
|
||||
`git add --intent-to-add` after every write as a safety net).
|
||||
|
||||
### One change = one generation
|
||||
|
||||
`nomarchy-theme-sync apply <theme>` merges the preset into the JSON and runs
|
||||
`home-manager switch` (override the command with `$NOMARCHY_REBUILD`, or pass
|
||||
`--no-switch` to only write). Everything is baked: Hyprland, Waybar, Ghostty,
|
||||
btop, and — via Stylix, mapped onto base16 roles — GTK, Qt, cursors and
|
||||
fonts. No runtime patching means no partial states, and `home-manager
|
||||
generations` is also your theme history. Waybar even restyles in place: it
|
||||
re-reads `style.css` when the symlink flips.
|
||||
|
||||
The **wallpaper** is the one runtime piece (awww — nixpkgs' swww — is
|
||||
imperative; nothing in Nix consumes the path): applied at session start and
|
||||
after every switch via a tiny activation hook, cycled instantly with
|
||||
`bg next`.
|
||||
|
||||
### Config the menu writes (not just themes)
|
||||
|
||||
The in-flake-state model isn't only for appearance. **Feature toggles you flip
|
||||
from the menu are written into a `settings.*` section of the *same* state file**
|
||||
— git-tracked, reproducible, never stashed in `~/.local/state`. The menu is just
|
||||
an ergonomic writer for your flake, so version-controlling your downstream
|
||||
reproduces the machine, settings and all. Where a toggle can take effect without
|
||||
a rebuild it does: the menu writes the key (`--no-switch`) and flips the running
|
||||
service, which reads the *live* flake state at session start, so the choice is
|
||||
both instant and survives reboot.
|
||||
|
||||
**Night light** is the first to use this — enable it from the menu (System ›
|
||||
Night light; the first enable rebuilds to install hyprsunset), then on/off is
|
||||
instant. Internally it's two keys: `settings.nightlight.installed` (sticky —
|
||||
gates the unit, the first enable rebuilds) and `settings.nightlight.on` (the
|
||||
instant on/off). Expect more `nomarchy.*` toggles to migrate to this pattern.
|
||||
|
||||
**Auto-commit (opt-in):** System › Auto-commit makes every `apply`/`set`
|
||||
mutation also `git commit` theme-state.json in your flake — *only* that
|
||||
file, so unrelated dirty work is never swept up — turning your settings
|
||||
history into `git log`. Off by default; the toggle is instant (nothing in
|
||||
Nix consumes the flag), the off-write is itself committed so history stays
|
||||
consistent, and wallpaper cycling (`bg next`) is deliberately excluded —
|
||||
the current wallpaper rides along with the next real commit.
|
||||
|
||||
### Per-theme app assets (`themes/<slug>/`)
|
||||
|
||||
Recoloring covers 95% of theming; the rest is one optional assets directory
|
||||
per theme — a single place to look, unlike the old distro's split:
|
||||
|
||||
| Asset | Mechanism |
|
||||
|---|---|
|
||||
| `backgrounds/` | wallpapers; empty `wallpaper` in the state means "first one"; `bg next` cycles |
|
||||
| `btop.theme` | baked into the generation (generated from the palette when absent) |
|
||||
| `waybar.css` | **whole-swap**: replaces the generated bar style entirely (probed at eval time, self-contained) |
|
||||
| `waybar.jsonc` | whole-swap for the bar *layout* (must be plain JSON) |
|
||||
| `rofi.rasi` | **whole-swap**: replaces the generated launcher/menu theme entirely |
|
||||
|
||||
Six ported themes ship a `waybar.css` identity (catppuccin, lumon, nord,
|
||||
retro-82, summer-day, summer-night). Custom user themes can live in
|
||||
`$NOMARCHY_PATH/themes/` (preset lookup) and `nomarchy.themesDir` (eval-time
|
||||
asset probe).
|
||||
|
||||
## 5. Day-to-day
|
||||
|
||||
```sh
|
||||
nomarchy-theme-sync list # 21 presets (nord, gruvbox, rose-pine, …)
|
||||
nomarchy-theme-sync apply kanagawa # whole desktop, one generation (~a switch)
|
||||
nomarchy-theme-sync set ui.gapsOut 16 # tweak one knob (also a switch)
|
||||
nomarchy-theme-sync bg next # cycle wallpapers — instant, no rebuild
|
||||
nomarchy-theme-sync bg auto # back to the theme's default wallpaper
|
||||
nomarchy-theme-sync get colors.accent
|
||||
sys-update # update inputs + rebuild the system (snapshots first)
|
||||
sys-rebuild # rebuild the system, current lock (no update)
|
||||
home-update # rebuild just the desktop layer
|
||||
nomarchy-doctor # read-only health sheet (also: menu › System › Doctor)
|
||||
```
|
||||
|
||||
Something broke anyway? Every rebuild is a generation and (on BTRFS)
|
||||
every hour is a snapshot — the undo story, from a bad theme to a
|
||||
machine that won't boot, is **[docs/RECOVERY.md](docs/RECOVERY.md)**.
|
||||
|
||||
Keybinds: `SUPER+Return` terminal · `SUPER+D` launcher · `SUPER+T` theme
|
||||
picker · `SUPER+SHIFT+T` next wallpaper · `SUPER+X` power menu ·
|
||||
`SUPER+E` file manager (yazi) · `SUPER+N` notifications · `SUPER+CTRL+V`
|
||||
clipboard history · `SUPER+Q`
|
||||
close · `SUPER+1..9` workspaces · `Print` region screenshot.
|
||||
|
||||
Shell aliases (zsh, gated on `nomarchy.shell.enable`) — `alias` lists them
|
||||
all; the curated set:
|
||||
|
||||
```sh
|
||||
# navigation
|
||||
.. ... .... # cd up 1 / 2 / 3 levels
|
||||
|
||||
# git
|
||||
g gst # git · git status -sb
|
||||
ga gaa # git add · git add -A
|
||||
gc gcm # git commit · git commit -m
|
||||
gco gsw gb # checkout · switch · branch
|
||||
gd gds # diff · diff --staged
|
||||
gl glg # log graph (last 20 · all branches)
|
||||
gp gpl gf # push · pull · fetch --all --prune
|
||||
|
||||
# nix (system/home rebuilds keep their full sys-update / home-update names)
|
||||
ns nr # nix shell · nix run (e.g. ns nixpkgs#ripgrep)
|
||||
nfu nfc # nix flake update · check
|
||||
nsearch ngc # nix search nixpkgs · nix-collect-garbage -d
|
||||
|
||||
# misc
|
||||
path # print $PATH, one entry per line
|
||||
reload # exec zsh (reload the shell)
|
||||
```
|
||||
|
||||
## 6. Extending
|
||||
|
||||
- **New theme:** drop a JSON into `themes/` (schema = any existing preset),
|
||||
plus an optional `themes/<slug>/` assets directory.
|
||||
- **New themed value:** add the key to `theme-state.json` and consume it in
|
||||
the Nix modules. One place — there is no second renderer to keep in sync.
|
||||
- **Importing more old-distro palettes:**
|
||||
`tools/import-palettes.py <palettes-dir> themes/`.
|
||||
- **New opt-in feature (convention):** when a feature is off by default and
|
||||
needs the user to set `nomarchy.*` options (e.g. night light, per-device
|
||||
keyboard layouts, monitor layout, power management), ship a **commented**
|
||||
example of it in `templates/downstream/home.nix` or `system.nix`. New
|
||||
installs then enable it by uncommenting + tweaking, rather than hunting the
|
||||
docs for the option name.
|
||||
- **Applications:** the starter complete-workstation set (LibreOffice, VS
|
||||
Code, GIMP, Inkscape) lives in the `home.packages` list in your
|
||||
`home.nix` — it's a plain package list, so curate it directly: delete a
|
||||
line to slim the machine, uncomment an extra (a browser, email, full TeX
|
||||
Live), or add your own. No `nomarchy.apps.*` toggles — a package list is
|
||||
already its own opt-out, so the distro doesn't impose these or wrap them.
|
||||
|
||||
## Roadmap & known issues
|
||||
|
||||
The prioritized queue of what's next lives in
|
||||
**[agent/BACKLOG.md](agent/BACKLOG.md)**; the detailed design/decision
|
||||
records and the log of shipped fixes stay in
|
||||
**[docs/ROADMAP.md](docs/ROADMAP.md)**. Development runs on an
|
||||
agent-driven loop — see **[agent/LOOP.md](agent/LOOP.md)**. Kept out of
|
||||
the README so this stays a focused entry point.
|
||||
|
||||
286
agent/BACKLOG.md
Normal file
286
agent/BACKLOG.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Backlog — the prioritized task queue
|
||||
|
||||
The forward-looking half of the old docs/ROADMAP.md, reworked as a queue
|
||||
agents can execute. Detailed design notes and decision records stay in
|
||||
`docs/ROADMAP.md` (referenced as "ROADMAP § <item>"); this file is *what's
|
||||
next, in what order*.
|
||||
|
||||
**Rules:**
|
||||
- Agents take the topmost actionable item (see LOOP.md). Finished items
|
||||
are **deleted** here — the journal + git log are the record; durable
|
||||
design notes get a ✓-entry in docs/ROADMAP.md if worth keeping.
|
||||
- Item numbers are **stable IDs** — never renumbered or reused. A gap in
|
||||
the sequence means shipped (or dropped) work; new items take the next
|
||||
free number regardless of tier.
|
||||
- Tags: `[blocked:hw]` needs real hardware (see HARDWARE-QUEUE.md) ·
|
||||
`[human]` needs Bernardo · `[stuck]` two failed attempts, needs help ·
|
||||
`[big]` must be split before starting.
|
||||
- Agents may append to **PROPOSED** and **Decisions** freely; only
|
||||
Bernardo moves items *out* of PROPOSED into the tiers.
|
||||
|
||||
---
|
||||
|
||||
## NOW
|
||||
|
||||
*(empty — NEXT's top item is the queue head)*
|
||||
|
||||
## NEXT
|
||||
|
||||
### 28. Theme UI review — make every surface stunning `[big]`
|
||||
(Raised by Bernardo, 2026-07-05 — placed at the head of NEXT; reorder
|
||||
freely.) A thorough visual pass over the whole themed UI — Waybar (the
|
||||
generated bar AND the summer whole-swaps), rofi menus, swaync,
|
||||
hyprlock, the cheatsheet, ghostty/btop, GTK/Qt, boot splash, greeter —
|
||||
with the bar set at *stunning*, not merely consistent (pillar 4).
|
||||
Grounded in design theory, not taste alone:
|
||||
- **Color:** palette-role relationships that demonstrably work
|
||||
together — harmony models (analogous/complementary accents),
|
||||
perceptual lightness ordering of base→surface→overlay→text (check in
|
||||
OKLCH, not raw hex), accent/warn/bad distinguishable for color-blind
|
||||
users; extend tools/check-theme-contrast.py to encode the adopted
|
||||
rules (it currently guards legibility pairs only).
|
||||
- **Typography & rhythm:** a consistent type scale across bar/menus/
|
||||
OSD, spacing on the ui.gapsIn/gapsOut grid, aligned paddings (the
|
||||
bar's per-module padding vs rofi rows vs swaync toasts).
|
||||
- **Hierarchy:** what reads first — bar module ordering/weights, menu
|
||||
title vs rows, toast title vs body; icon weights consistent with the
|
||||
adjacent text.
|
||||
Bernardo has offered image-expert models for designed graphics
|
||||
(wallpapers, logos, glyphs, preview/branding art): an agent slice that
|
||||
needs artwork must STOP and ask ("say the word") instead of shipping
|
||||
programmer-art.
|
||||
Slices: (a) ✓ the audit (2026-07-05, iteration #31 — findings below);
|
||||
(b) palette-level fixes + the extended contrast/harmony checker —
|
||||
P1s ✓ shipped 2026-07-05 (iteration #32): summer-day + flexoki-light
|
||||
subtext/surface/overlay/muted retuned (flexoki to its canonical
|
||||
upstream tones), miasma + kanagawa surfaces raised (kanagawa to
|
||||
sumiInk4); `subtext/base ≥ 3` now GATED in check-theme-contrast.py
|
||||
(all 21 pass). P2s ✓ shipped 2026-07-05 (iteration #33): 18 hex
|
||||
retunes across 9 themes (OKLCH hue-preserving minimal raises;
|
||||
canonical where upstream defines one — gruvbox bg4, nord #616e88,
|
||||
latte overlay1, flexoki 600-series statuses for light mode) and the
|
||||
four floors GATED: muted ≥ 2, text/surface ≥ 4.5, accentAlt ≥ 3,
|
||||
warn ≥ 2.5 (21×7 pairings green; audit contrast findings 20 → 1 —
|
||||
miasma's earthy `bad` stays as identity, good/bad floors stay
|
||||
audit-only so no exemption list was needed). Remaining (b): nothing —
|
||||
further palette work graduates from slices (c)/(d) findings;
|
||||
(c) per-surface polish slices — capture harness ✓ shipped 2026-07-05
|
||||
(iteration #34): `tools/theme-shot.nix` boots the themed desktop
|
||||
headlessly at 1080p and screenshots desktop + open root menu (proven
|
||||
on tokyo-night); per-surface punch items from the first full-res
|
||||
review:
|
||||
- ✓ **rofi keybind hints** (shipped iteration #37): dimmed pango
|
||||
hints on root/Tools/System rows, generated from keybinds.nix via
|
||||
the cheatsheet's prettyKeys (single source, can't drift) —
|
||||
capture-verified on tokyo-night.
|
||||
- **Icon weight mix `[human]`:** full-color Papirus icons in the
|
||||
menus vs all-monochrome bar glyphs — pick: symbolic/monochrome
|
||||
menu icons for one system, or color as the menu's identity.
|
||||
A/B captured on lumon (iteration #46, side-by-side:
|
||||
https://claude.ai/code/artifact/1ccd10fe-4b6f-454a-888d-e7fdf2362b03):
|
||||
B (symbolic) matches the bar's weight but Papirus symbolic
|
||||
coverage has holes (preferences-desktop-theme-symbolic missing —
|
||||
Look & Feel lost its icon) and rofi tints symbolics a fixed dim
|
||||
gray, not the theme text color — going B needs an icon audit +
|
||||
recolor slice. A costs nothing. Awaiting the call; A stays until
|
||||
then.
|
||||
- ✓ **Bar right-cluster rhythm** (shipped iteration #36): group
|
||||
margins before pulseaudio/powerprofile/battery — heads that
|
||||
self-hide degrade to the uniform spacing.
|
||||
- ✓ **Semantic dim** (shipped iteration #36): workspaces + dnd +
|
||||
muted-volume now use `@muted` (floor-guaranteed by 28b) instead
|
||||
of `alpha(@text, 0.5)` tints; the CSS comment now documents the
|
||||
new invariant.
|
||||
- ✓ **compositor backdrop** (shipped iteration #35): Hyprland
|
||||
`misc:background_color` now the theme's base — no more black flash
|
||||
behind a missing/slow wallpaper (glaring on light themes in the
|
||||
summer-day capture).
|
||||
- summer-day whole-swap capture reviewed (iteration #35): the
|
||||
authored slate menu + island-pill bar survive the 28b retunes and
|
||||
read as one coherent identity — keep. ✓ placeholder-dim nit fixed
|
||||
(iteration #38: both summer rasi, bg0 at 60% alpha).
|
||||
- latte capture reviewed (iteration #38): the generated menu is
|
||||
fully coherent on light themes (zebra rows, retuned surface, blue
|
||||
selected, dimmed hints) — the audit's "dark terminal on latte"
|
||||
preview concern was a stale preview, not a defect. Backdrop
|
||||
probe: misc:background_color IS applied (hyprctl getoption =
|
||||
0xFFEFF1F5); captures show dark because awww's empty-state layer
|
||||
paints over it in the wallpaper-less VM — on hardware the fix
|
||||
covers its intended window (the pre-awww startup gap).
|
||||
- ✓ Harness gap fixed (iteration #44): guest `~/.nomarchy` seeded
|
||||
via tmpfiles BEFORE greetd starts the session, so the session's
|
||||
own exec-once wallpaper paint runs (a post-boot testScript seed
|
||||
was too late for exec-once, and a manual re-run fails without
|
||||
WAYLAND_DISPLAY — awww's client socket is display-named).
|
||||
Wallpaper-complete summer-night capture reviewed: lakeside night
|
||||
scene + cream inverted bar + menu-over-scene all cohere; the
|
||||
placeholder dim (#2d353b99) renders. Note: summer-night's cream
|
||||
bar/menu on dark backdrop is the authored inverted design (fg as
|
||||
surface), not a rendering bug.
|
||||
- ✓ Identity-theme capture + stub purge (iteration #45): the lumon
|
||||
capture exposed that catppuccin/lumon/nord/retro-82 shipped stub
|
||||
waybar.css files (2–14 lines, from the f211ef0 rewrite import) —
|
||||
and a theme waybar.css whole-swaps the ENTIRE generated
|
||||
stylesheet, so those four ran an unstyled default bar. Stubs
|
||||
deleted; re-capture confirms lumon falls back to the generated
|
||||
styled bar (workspace pill, padded right cluster). Their full
|
||||
~110-line rofi.rasi designs kept. Real whole-swaps remain only
|
||||
summer-day/night (+ nord/retro-82 lost nothing: the stubs had no
|
||||
design).
|
||||
(d) the whole-swap themes brought to the same bar (module parity
|
||||
verified textually 2026-07-05: whole-swaps carry every functional
|
||||
module; omitting cpu/memory is identity). Visual work is
|
||||
V3-bound by nature — screenshots are the review artifact, hardware
|
||||
confirms.
|
||||
|
||||
**Audit findings (slice a — `tools/audit-theme-design.py` over all 21
|
||||
palettes + visual pass over previews; identity-aware curation):**
|
||||
- ~~P1 · invisible-secondary-text palettes~~ ✓ fixed iteration #32
|
||||
(summer-day subtext #6e828a, surface #efe7d0; flexoki-light to
|
||||
canonical Flexoki: surface #E6E4D9, overlay #B7B5AC, subtext
|
||||
#6F6E69, muted #878580). Gate added.
|
||||
- ~~P1 · inverted bg stacks~~ ✓ fixed iteration #32 (miasma surface
|
||||
#2e2e2e; kanagawa surface #2a2a37 = upstream sumiInk4). Note
|
||||
learned: in this palette model `overlay` is a MID-TONE
|
||||
(borders/dim, catppuccin semantics), not a third bg tier — the
|
||||
dark-theme overlay==muted pattern is intentional.
|
||||
- **P2 · muted floor:** muted-on-base < 2.0 on gruvbox (1.27),
|
||||
everforest (1.55), lumon (1.68), nord (1.69), white (1.82), latte
|
||||
(1.91), retro-82 (1.93) — dimmed workspaces/inactive items barely
|
||||
render (visible on the lumon preview). Adopt ≥ 2.0 and retune.
|
||||
- **P2 · warn barely reads:** warn-on-base ≈ 2.0–2.3 on rose-pine,
|
||||
summer-day, latte, flexoki-light — this is the bar's 25%-battery
|
||||
color. Floor 2.5 (or see the color-only rule below).
|
||||
- **P2 · text-on-surface < 4.5:** ristretto 3.88, latte 4.39 (menus
|
||||
and chips draw text on surface).
|
||||
- **P3 · accentAlt-on-base < 3:** latte 2.34, summer-day 2.83.
|
||||
- **Design rule (systemic, beats palette surgery): status is never
|
||||
color-only.** good/warn collapse under protanopia on ~half the
|
||||
themes and good/bad under deuteranopia (59 pair-findings) — that's
|
||||
inherent to red/green/yellow, not fixable per-palette. Battery and
|
||||
recording already carry glyph changes; sweep the remaining
|
||||
color-only indicators (updates count, notification dot, VPN shield
|
||||
states) for shape/glyph redundancy.
|
||||
- **Identity exemptions, made explicit:** vantablack + white
|
||||
(deliberately hueless statuses), lumon (all-blue), hackerman
|
||||
(matrix green statuses), matte-black/retro-82 (off-family hues) are
|
||||
identity, not defects — slice (b)'s checker gets a per-theme
|
||||
exemption list instead of silently lowered floors.
|
||||
- **ANSI / greeter notes:** latte, rose-pine and white ship
|
||||
`ansi[0]` LIGHTER than `ansi[15]` — decide the light-theme ANSI
|
||||
convention (terminals conventionally keep black dark) before the
|
||||
greeter/tty theming ships to them. tokyo-night/summer-night
|
||||
`ansi[7]-on-ansi[0]` ≈ 2.8–3.0 = the greeter's muted text; fine as
|
||||
muted, watch on hardware.
|
||||
- **Visual pass (480×270 previews — too small for type/spacing; the
|
||||
deep per-surface pass needs 1080p captures):** the generated bar's
|
||||
right cluster runs ~9 modules with uniform spacing — no grouping
|
||||
rhythm (consider micro-gaps between tray/net · stats · toggles ·
|
||||
battery/notify groups); latte's preview shows a DARK terminal on
|
||||
the light desktop — verify ghostty consumes the latte palette (or
|
||||
the preview is stale); summer-day's island-pill whole-swap bar and
|
||||
lumon's globe identity are strong — preserve through any polish.
|
||||
|
||||
### 14. Automated lock bumps — confirm the first real run
|
||||
Slices b+c shipped 2026-07-05 (`.gitea/workflows/bump.yml`): weekly
|
||||
schedule (Mon 05:17 UTC) + `workflow_dispatch` as the security
|
||||
fast-lane; `nix flake update` → eval gate → pathspec-limited lock
|
||||
commit pushed to `main` on green (that push triggers check.yml as the
|
||||
second net). Update/commit/push logic simulated locally end-to-end in
|
||||
a scratch clone, incl. a real update; today's bumped lock evals green.
|
||||
Remaining (not confirmable from a session): the first scheduled or
|
||||
dispatched run must land — watch that the runner picks up the cron and
|
||||
that the Actions token can push. Then delete this item. Item 20's KVM
|
||||
runner later upgrades the gate from eval-only to the VM suite.
|
||||
|
||||
### 20. KVM runner → VM suite in CI `[human]`
|
||||
The remaining stretch of the CI item — checks-on-push is live and
|
||||
**green** (run #58; runner = gitea/act_runner docker, eval tier).
|
||||
Register a second runner on a host with `/dev/kvm` + nix (host-mode
|
||||
label `nix-kvm`), then an agent uncomments the workflow's `vm-checks`
|
||||
job: the `checks.*` VM suite + real toplevel/HM builds on every push
|
||||
(also upgrades item 14's bump gate from eval-only to the full suite).
|
||||
|
||||
### 18. "nomarchy" control center + first-boot welcome `[big]`
|
||||
ROADMAP § control center. A single front-end over the common toggles on
|
||||
the same `nomarchy-theme-sync` surface, + a first-boot guided
|
||||
"pick your theme / essentials" flow. Needs a design pass (TUI vs GUI)
|
||||
→ write options into Decisions before implementing. Note: items 9–11
|
||||
(rollback menu, doctor, validation) are natural panels of it — design
|
||||
them as composable commands, not dead ends.
|
||||
|
||||
## LATER
|
||||
|
||||
- **Wallpapers artifact split** (ROADMAP § Faster switches — decided,
|
||||
deferred): pinned `Nomarchy-wallpapers` input so a state write stops
|
||||
re-copying 86 MB. Follow-on: pre-built theme variants if switches are
|
||||
still slow after.
|
||||
- **Installer round 2** (ROADMAP § Installer): multi-disk BTRFS RAID,
|
||||
impermanence, BIOS/legacy boot.
|
||||
- **Boot-from-snapshot**: a systemd-boot equivalent of grub-btrfs.
|
||||
- **Night-light geo mode**: lat/long auto sunset/sunrise (means wlsunset).
|
||||
- **Per-theme icon overrides** / more icon packs (ROADMAP § Icon themes).
|
||||
- **MIPI/IPU software-ISP camera** support (no-UVC machines).
|
||||
- **VPN exit-node richer display** (country/city) (optional).
|
||||
- **NixOS release bump → v2** `[human]`: deliberate, hand-edited, never
|
||||
automated; the previous attempt was discarded (2026-06-22) over a
|
||||
Hyprland OOM blocker — see MEMORY.md before retrying (NOW#3 should
|
||||
also soften that blocker class).
|
||||
|
||||
## PROPOSED (agent suggestions — await human triage)
|
||||
|
||||
*Agents: append here with a one-paragraph pitch (what/why/cost). Do not
|
||||
implement. Bernardo moves accepted items into a tier.*
|
||||
|
||||
- **Menu parity for downstream-flake options** (raised by Bernardo,
|
||||
2026-07-04, from the hardware sweep): anything the docs or the
|
||||
hardware queue ask a user to *hand-edit into the downstream flake*
|
||||
(`keyboard.layout` multi-layout, `power.batteryChargeLimit`,
|
||||
`updates.enable`, `services.printing`, …) should have a menu toggle
|
||||
instead — the in-flake-state philosophy already gives the menu a
|
||||
write-into-the-flake path, and night-light / auto-timezone /
|
||||
auto-commit prove the pattern (incl. rebuild-on-first-enable).
|
||||
Pitch: (a) an audit listing every user-facing `nomarchy.*` option vs
|
||||
its menu surface; (b) menu writers for the gaps, respecting the
|
||||
toggle-vs-package discipline (bare template packages stay hand-edits)
|
||||
and menu-placement convention (right submenu, root stays short).
|
||||
Values beyond booleans (layout lists, charge thresholds) need a small
|
||||
input UI per option. Cost: audit is one iteration; the writers a few
|
||||
more, sliceable per option.
|
||||
|
||||
- **Portal/Flatpak camera picker still lists the internal IR sensor**
|
||||
(ROADMAP § Webcam follow-up). The shipped IR-hide is a *WirePlumber
|
||||
v4l2* rule, but Flatpak/portal apps consume cameras via the
|
||||
**libcamera** path, where both sensors remain visible — a Flatpak
|
||||
Zoom user can still pick the black IR "camera". Options, roughly
|
||||
ascending cost: (a) do nothing — document it (portal camera support
|
||||
is still rare in practice); (b) a WirePlumber *libcamera* monitor
|
||||
rule disabling GREY-only nodes — needs verifying that libcamera
|
||||
monitor rules can match early enough (the v4l2 investigation found
|
||||
only `device.api` binds pre-rule, which is why surgical scoping
|
||||
failed before — same wall likely applies); (c) a libcamera
|
||||
configuration/udev quirk hiding the IR sensor at the libcamera layer
|
||||
itself. Cost: (b)/(c) need a T14s-style RGB+IR machine to verify →
|
||||
pairs with a hardware-queue session. Recommend (a) now, (b)
|
||||
investigated when the T14s is next available.
|
||||
|
||||
## Decisions `[human]`
|
||||
|
||||
Open calls only Bernardo can make; agents add options/evidence but never
|
||||
decide.
|
||||
|
||||
- **Formatter adoption:** repo deliberately has none; `nixfmt-rfc-style`
|
||||
would flatten the aligned hand-formatting of ~33 files. Adopt or
|
||||
declare never?
|
||||
- **Docs site vs Markdown-in-repo** (from the docs-review item).
|
||||
- **Control center form factor:** TUI (gum/ratatui-style) vs GUI vs
|
||||
"the rofi menu *is* the control center, just add a first-boot flow".
|
||||
- **zram swap:** faster under pressure and pairs with NOW#3, but it
|
||||
interacts with the hibernation-swapfile story (resume device/priority
|
||||
ordering) — adopt, adopt-with-hibernation-guard, or skip?
|
||||
- **Default browser:** the template comments Firefox out. The shipped
|
||||
mime defaults (item 8, done) point `text/html`/http(s) at
|
||||
`firefox.desktop` as *inert* entries — they activate the moment
|
||||
Firefox is installed and are skipped otherwise, so the remaining call
|
||||
is only: ship a browser active in the suite, or stay
|
||||
browserless-by-default?
|
||||
70
agent/CONVENTIONS.md
Normal file
70
agent/CONVENTIONS.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Conventions — how Nomarchy code is written
|
||||
|
||||
The standing rules an agent must follow while coding. GOALS.md says what
|
||||
we're building; this says how. Details/rationale live in docs/ROADMAP.md's
|
||||
decision records and the README.
|
||||
|
||||
## Repo layout (the rule of thumb)
|
||||
`modules/` is the distro (reusable, no machine specifics) · `hosts/` is a
|
||||
machine · `themes/` is data · `pkgs/` is code · `tools/` is maintainer-only
|
||||
· `agent/` is loop state. If a new file doesn't obviously belong to one of
|
||||
those, it probably shouldn't exist.
|
||||
|
||||
## Nix style
|
||||
- **No formatter.** Files use deliberate aligned hand-formatting — match
|
||||
the surrounding style exactly; never reflow a file you're only touching
|
||||
a line of.
|
||||
- Distro defaults use `lib.mkDefault` so a plain downstream assignment
|
||||
wins; bind/exec lists concatenate. Behaviour options overridable,
|
||||
appearance flows from the state JSON.
|
||||
- Options live in the existing surfaces: `nomarchy.system.*` /
|
||||
`nomarchy.hardware.*` / `nomarchy.services.*` (NixOS, `system.nix`),
|
||||
everything else `nomarchy.*` (HM, `home.nix`). Update the README tables
|
||||
when the surface changes.
|
||||
|
||||
## Feature design
|
||||
- **In-flake state:** any user-settable config gets a menu writer that
|
||||
lands it in `theme-state.json` (`settings.*`), git-tracked. No
|
||||
`~/.local/state`, no side files. Instant-effect where possible
|
||||
(`--no-switch` + flip the service; the service reads the *live* working
|
||||
tree at start — the night-light `ExecCondition` pattern). Rebuild-baked
|
||||
values graduate via `mkDefault` reads of the settings key.
|
||||
- **Toggle vs package:** a `nomarchy.*` toggle only when there's real
|
||||
config behind it (units, groups, udev, firewall). A bare package goes
|
||||
in the downstream template's `home.packages` — opt-out is deleting the
|
||||
line.
|
||||
- **Opt-in features** ship a commented example in
|
||||
`templates/downstream/home.nix` or `system.nix`.
|
||||
- **Menu:** new entries go in the right submenu (Tools › / System ›; root
|
||||
stays six entries), end lists with the shared `↩ Back`, self-gate on
|
||||
the feature's availability, and add the direct
|
||||
`SUPER+CTRL+<mnemonic>` bind in `keybinds.nix` (single source — it
|
||||
feeds both Hyprland and the SUPER+? cheatsheet).
|
||||
- **Waybar:** new indicators self-gate (hidden when irrelevant), use
|
||||
named `writeShellScriptBin`s on PATH (so static configs can exec them
|
||||
by bare name), and are added to **both** the generated `waybar.nix`
|
||||
config **and** the summer-day/night `waybar.jsonc` whole-swaps (the
|
||||
parity rule).
|
||||
- **Theming:** every new visual surface consumes the palette from the
|
||||
state JSON. There is no second renderer to keep in sync — add the key
|
||||
to the JSON, consume it in the module.
|
||||
|
||||
## Testing
|
||||
- docs/TESTING.md is canonical; LOOP.md's ladder (V0–V3) sets the
|
||||
required tier. Cheap first: `nix flake check --no-build`, `bash -n`,
|
||||
`py_compile`.
|
||||
- Prefer a permanent `checks.*` runNixOSTest over a one-off manual poke;
|
||||
reusable recipes (headless Hyprland with software GL, QMP screenshots,
|
||||
udev-event fakes) are indexed in MEMORY.md and demonstrated by the
|
||||
existing checks (`distro-id`, `hardware-toggles`,
|
||||
`battery-charge-limit`).
|
||||
- The honesty rule: report exactly what you verified and at which tier.
|
||||
|
||||
## Git
|
||||
- `main` is development (direct commits, pushed); `v1` is the release
|
||||
pointer — **human-only, fast-forward-only, never touched by agents**.
|
||||
- Commit style: `feat|fix|test|docs|chore(scope): summary`, body with
|
||||
what/why + verification tier + what remains. Bookkeeping (`agent/`
|
||||
updates) rides in the same commit as the change.
|
||||
- `flake.lock` moves only when the task *is* a lock bump, and only within
|
||||
the pinned release branches.
|
||||
58
agent/GOALS.md
Normal file
58
agent/GOALS.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Goals — what "done" looks like for Nomarchy
|
||||
|
||||
The north star every loop iteration serves. When two options conflict,
|
||||
the earlier pillar wins.
|
||||
|
||||
## The four pillars (in priority order)
|
||||
|
||||
1. **Rock-stable.** A workstation you never fight. Everything is a NixOS/HM
|
||||
generation — atomic, rollbackable, never partial. `nix flake check` is
|
||||
green at every commit on `main`. Regressions are caught by the VM-test
|
||||
suite (`checks.*`), not by users. `v1` only ever advances after human
|
||||
on-hardware QA.
|
||||
2. **Reproducible, with zero hidden state.** The downstream flake checkout
|
||||
*is* the machine. All user-settable config is menu-writable into the
|
||||
git-tracked state file (`theme-state.json` `settings.*`) — never
|
||||
`~/.local/state`, never `~/.config` side files. Re-cloning your flake
|
||||
reproduces the machine, settings and all.
|
||||
3. **Effortless to configure.** The user never has to learn Nix. Every
|
||||
common knob is reachable from `nomarchy-menu` (SUPER+M); the menu is an
|
||||
ergonomic writer for the flake. Where a toggle can take effect without a
|
||||
rebuild, it must (`--no-switch` + flip the running service).
|
||||
4. **Beautiful.** One JSON themes the entire desktop coherently — Hyprland,
|
||||
Waybar, Ghostty, btop, rofi, GTK/Qt, boot splash, greeter. Every new
|
||||
surface follows the palette. Informative, self-gating Waybar modules
|
||||
(they hide when irrelevant). No unthemed corner survives contact with
|
||||
the theme switcher.
|
||||
|
||||
## Quality bars (non-negotiable)
|
||||
|
||||
- **The honesty rule** (docs/TESTING.md): for anything visual, "the Nix
|
||||
evaluates" is not "it renders". Verify at the highest tier you can reach
|
||||
(see LOOP.md's verification ladder) and *state the tier you reached*.
|
||||
Never claim a check you didn't run.
|
||||
- **Parity rule:** any module added to the generated Waybar config must
|
||||
also be added to the summer-day/night `waybar.jsonc` whole-swaps.
|
||||
- **Menu placement:** new menu entries go in the right category submenu
|
||||
(Tools › / System ›), with a direct `SUPER+CTRL+<mnemonic>` bind and
|
||||
self-gating where applicable. The root picker stays six entries.
|
||||
- **Opt-in features** ship a commented example in
|
||||
`templates/downstream/{home,system}.nix`.
|
||||
- **Option surface discipline:** a toggle exists only when there is real
|
||||
config behind it. Bare package installs go in the template's
|
||||
`home.packages` (opt-out = delete the line), never a `nomarchy.apps.*`.
|
||||
|
||||
## Non-goals (do not drift into these)
|
||||
|
||||
- **No binary cache.** Compile-from-source is a deliberate values call;
|
||||
automation targets the config/lock channel, not artifact distribution.
|
||||
- **No second theming pipeline.** The dispatcher owns menu structure; the
|
||||
renderer (rofi) stays swappable. No GTK4 launcher.
|
||||
- **No nixpkgs major bump on `main`.** Lock updates stay within the pinned
|
||||
release branch; a release jump is a deliberate `v2`, hand-edited by the
|
||||
maintainer (the last attempt was discarded over a Hyprland OOM — see
|
||||
agent/MEMORY.md).
|
||||
- **No repo-wide reformat.** The `.nix` files use deliberate aligned
|
||||
hand-formatting; adopting a formatter is an open maintainer decision
|
||||
(BACKLOG.md § Decisions), not a cleanup.
|
||||
- **No multi-DE.** Hyprland is the desktop.
|
||||
249
agent/HARDWARE-QUEUE.md
Normal file
249
agent/HARDWARE-QUEUE.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# Hardware queue — V3 checks only a human can run
|
||||
|
||||
Everything shipped at V1/V2 whose final verification needs real hardware.
|
||||
Agents **append** (newest at the bottom of a section) with exact steps;
|
||||
Bernardo runs them and either checks off (`[x]` + date + verdict) or files
|
||||
the failure as a NOW bug in BACKLOG.md. Machines: the **AMD dev box**
|
||||
(Ryzen AI laptop: AMD + fingerprint + NPU), the **Latitude 5410** (Intel
|
||||
QA machine), the **T14s** (webcam case).
|
||||
|
||||
## Any machine (dev box is fine)
|
||||
- [ ] **Battery charge limit re-apply on unplug** — `sudo nixos-rebuild
|
||||
switch` with `power.batteryChargeLimit = 80`, physically unplug/replug
|
||||
AC, confirm `charge_control_end_threshold` re-reads 80. (udev trigger
|
||||
already VM-verified.)
|
||||
- [ ] **SSH_AUTH_SOCK for GUI clients** — after relogin, launch a GUI git
|
||||
client (or `rofi`-launched terminal-less app) and confirm it reaches
|
||||
gpg-agent's SSH socket without an interactive shell parent.
|
||||
- [x] **Night-light full cycle** — first menu enable rebuilds + hyprsunset
|
||||
starts; later toggles are instant (no rebuild); an *off* survives
|
||||
reboot (ExecCondition); stopping hyprsunset restores gamma.
|
||||
— 2026-07-04 Bernardo: PASS enable/disable on hardware
|
||||
(off-survives-reboot + gamma-restore not explicitly checked).
|
||||
- [x] **Auto-timezone** — enable from the menu; confirm geoclue finds the
|
||||
zone, `/etc/localtime` updates, and the Waybar clock refreshes
|
||||
(SIGUSR2 watcher) — also after a manual `timedatectl set-timezone`.
|
||||
— 2026-07-04 Bernardo: PASS — enabled from the menu, `timedatectl`
|
||||
shows Europe/London (the manual set-timezone re-trigger wasn't
|
||||
exercised).
|
||||
- [ ] **Keyboard layout cycle bind** — with a comma layout (e.g.
|
||||
`nomarchy.keyboard.layout = "us,de"`), SUPER+SHIFT+K cycles the
|
||||
focused keyboard's layout, the Waybar `` indicator follows, and
|
||||
the row shows in the SUPER+? cheatsheet. — 2026-07-04 attempt:
|
||||
no comma layout was configured, so the bind wasn't rendered (the
|
||||
gate working as designed, not a failure) — retest after setting a
|
||||
comma layout + rebuild + relogin. The SUPER+? no-op found en
|
||||
route IS a real bug → BACKLOG item 26 (fix shipped — see the
|
||||
dedicated SUPER+? entry below).
|
||||
- [ ] **SUPER+? opens the cheatsheet** (item 26 fix) — after
|
||||
`home-update` + relogin (or `hyprctl reload`), SUPER+? must open
|
||||
the keybindings cheatsheet, whose row still reads `SUPER + ?`
|
||||
(not `SUPER + SHIFT + ?`).
|
||||
- [ ] **swaync readable on summer-day** (item 25 fix) — on summer-day
|
||||
after `home-update`: `notify-send "title" "body text"` shows
|
||||
readable body text; open the control centre (SUPER+N), hover a
|
||||
notification row and check the Clear button — all text legible
|
||||
(body/buttons now @text on tinted chips, not subtext/surface).
|
||||
- [ ] **Bar + rofi legible on flexoki-light** (item 27 fix) — switch to
|
||||
flexoki-light: every Waybar module readable (window title, tray
|
||||
row, dimmed inactive workspaces / muted volume visible-but-dim),
|
||||
rofi inputbar/alternate rows show text. Spot-check one dark theme
|
||||
(e.g. tokyo-night) for no visual regression in the same spots.
|
||||
- [ ] **Stub-bar themes got the generated bar** (item 28, 90a5104) —
|
||||
switch to catppuccin, lumon, nord and retro-82: each now shows
|
||||
the generated styled bar in its own palette (workspace pill,
|
||||
padded right cluster) instead of the old raw default Waybar.
|
||||
Their rofi menus should look unchanged.
|
||||
- [ ] **Back-audit spot-check** (item 24) — the keybinds cheatsheet
|
||||
(SUPER+? / root menu › Keybindings) now ends in ↩ Back and
|
||||
returns to the root picker; spot a couple of submenus (Display,
|
||||
VPN › Tailscale) still Back correctly after the audit pass.
|
||||
- [ ] **Network menu has no blank rows** (item 22 fix, needs Wi-Fi) —
|
||||
after `home-update`, open Tools › Network: no empty separator
|
||||
rows between the ethernet/wifi/VPN sections (compact = True).
|
||||
KNOWN RESIDUAL: if exactly one nameless wifi row remains showing
|
||||
only security+bars, that's a hidden-SSID AP — config can't filter
|
||||
it; report it and the follow-up is a small source patch skipping
|
||||
empty-name APs in create_ap_list.
|
||||
- [ ] **Keyboard hotplug picker (re-verify after in-flake graduation)** —
|
||||
plug an external keyboard post-login, pick a layout in rofi, confirm
|
||||
it applies per-device only, persists in `settings.keyboard.devices`,
|
||||
and graduates into a `device{}` block on the next rebuild.
|
||||
- [x] **Snapshots restore/rollback** — ⚠ PRECONDITION: update to main ≥
|
||||
a47aa3a and RELOGIN first (the polkit agent starts with the session).
|
||||
Bernardo's 2026-07-04 Latitude findings 5/6 ("btrfs-assistant still
|
||||
crashes", "menu snapshots shows nothing") match the PRE-fix behavior
|
||||
exactly: no agent → pkexec fails silently (= menu does nothing), and
|
||||
a direct unprivileged run crashes (= the libbtrfsutil bug). If either
|
||||
still reproduces ON THE FIXED BUILD after relogin, reopen BACKLOG
|
||||
item 4 as [stuck]. Then: `nomarchy-menu snapshot` now opens
|
||||
the **btrfs-assistant GUI**: a *themed* polkit prompt must appear
|
||||
(hyprpolkitagent — first on-hardware outing) and the GUI must open
|
||||
as root. Also exercise the fzf fallback in a terminal
|
||||
(`sudo nomarchy-snapshots`): browse/diff, restore a file
|
||||
(`undochange`), and a root-config rollback behind the typed-`yes`
|
||||
gate. Bonus check: any other pkexec flow now prompts instead of
|
||||
silently failing. — 2026-07-04 Bernardo: PASS on the fixed build —
|
||||
polkit prompt appears, GUI opens as root, fzf fallback works.
|
||||
Restore/rollback not exercised → residual item below.
|
||||
- [ ] **Snapshots restore + rollback exercise** (residual from the item
|
||||
above — the GUI/polkit half passed 2026-07-04): in
|
||||
`sudo nomarchy-snapshots`, restore a single file (`undochange`)
|
||||
and walk a root-config rollback up to (or through) the
|
||||
typed-`yes` gate.
|
||||
- [ ] **Caffeine toggle (item 13 slice)** — click in the bar → turns
|
||||
(warm tint on the generated bar) and hypridle must NOT lock /
|
||||
blank while it's on (wait past the 5-min lock); click again
|
||||
releases. Also present on both summer bars now.
|
||||
- [ ] **Screen recording (item 12)** — Tools › Capture: Record region
|
||||
(slurp) and Record screen produce a playable .mp4 in
|
||||
~/Videos/Recordings; the red ⏺ REC appears in the bar instantly
|
||||
and CLICKING IT stops + notifies the path; the + audio variants
|
||||
carry sound. While recording, the Capture menu offers only
|
||||
"■ Stop recording". On the AMD box wl-screenrec (VAAPI) should
|
||||
do the work; if it dies at start the wf-recorder fallback kicks
|
||||
in silently — check the notification says which. Summer bars
|
||||
have the same ⏺ (parity).
|
||||
- [ ] **Doctor (item 10)** — menu › System › Doctor opens the sheet in
|
||||
a terminal; `nomarchy-doctor` over SSH shows the same minus user
|
||||
units. On a healthy machine everything is ✔/– (dev-box run
|
||||
2026-07-04 correctly flagged a genuinely failed user unit).
|
||||
- [ ] **Rollback menu (item 9b)** — after a couple of theme changes,
|
||||
menu › System › Rollback: recent desktop generations listed
|
||||
(newest marked current); picking an older one opens a terminal,
|
||||
activates it, and the theme visibly reverts; picking the newer one
|
||||
again rolls forward. The two System rows: Snapshots opens the
|
||||
snapshot flow, "boot an older generation (how)" fires an
|
||||
instruction notification.
|
||||
- [ ] **Open-a-file smoke (viewers + mime defaults, item 8)** — after
|
||||
`home-update`: from yazi/Thunar, open a PDF (→ zathura, themed to
|
||||
the palette), an image (→ imv, NOT GIMP), a video (→ mpv);
|
||||
`xdg-open .` on a directory → Thunar. With no browser installed,
|
||||
clicking a link must still fall through to *something sane* (the
|
||||
firefox.desktop entries are inert); if you've uncommented a
|
||||
browser, links go there.
|
||||
- [ ] **Update awareness** — with `nomarchy.updates.enable`, let the timer
|
||||
fire (or start the unit): indicator appears only when inputs are
|
||||
behind, notification only on count growth, click opens the upgrade
|
||||
flow.
|
||||
- [ ] **VPN menu live paths** — import a real WireGuard `.conf` and an
|
||||
`.ovpn` via System → VPN, toggle up/down (● / ○ state), and the
|
||||
Tailscale block: up/down + exit-node without sudo (operator grant).
|
||||
- [ ] **Printer menu** — with `nomarchy.services.printing`, System →
|
||||
Printers opens system-config-printer; add a printer, test page.
|
||||
- [ ] **GRUB UEFI ISO theme render** — boot the ISO on UEFI hardware:
|
||||
composed splash background, palette menu in the lower third, accent
|
||||
timeout bar.
|
||||
- [ ] **Visual theme pass** — live ISO: all six identity themes (bars) +
|
||||
the four authored rofi `.rasi` (nord/retro-82/lumon/kanagawa) look
|
||||
right, not just parse.
|
||||
- [x] **Auto-commit on a real machine** — System › Auto-commit toggles on
|
||||
(row shows state, notification fires); a theme apply from SUPER+T then
|
||||
shows a `nomarchy: apply theme …` commit in `~/.nomarchy` (`git log`);
|
||||
unrelated dirty files in the checkout stay uncommitted; toggle off is
|
||||
itself the last commit. Also: the "Auto timezone (on/off)" row label
|
||||
now reflects the real state (the `= true` comparison fix).
|
||||
— 2026-07-04 Bernardo: PASS — theme changes committed and the
|
||||
toggle self-committed.
|
||||
- [ ] **Display profiles, slice a (item 15)** — declare two
|
||||
`nomarchy.displayProfiles` (e.g. docked disables eDP-1 + arranges
|
||||
the externals; undocked re-enables it), `home-update`, then:
|
||||
System › Display › Profiles lists them (● marks active); applying
|
||||
is instant (no rebuild) and survives a relogin (the baked
|
||||
overlay); "Base layout" restores; a menu resolution pick made
|
||||
earlier must NOT re-enable a profile-disabled panel after the
|
||||
next rebuild.
|
||||
- [ ] **Display profiles workspace pins, slice c (item 15)** — give the
|
||||
docked profile `workspaces = { "1" = "<ext>"; "9" = "eDP-1"; }`:
|
||||
applying the profile moves open workspaces 1/9 to those outputs
|
||||
immediately, new visits land there too, and the pins survive a
|
||||
relogin (baked `workspace` rules). Switching to a profile without
|
||||
pins leaves workspaces where they are (stale session pins are
|
||||
expected until reload/rebuild — noted in the applier).
|
||||
- [ ] **Display profiles auto-switch, slice b (item 15)** — same setup,
|
||||
then menu › Profiles › Auto-switch on: plugging the dock/monitor
|
||||
applies the matching profile within ~3s (toast names it);
|
||||
unplugging switches back; Auto-switch off stops that; with two
|
||||
profiles naming the same outputs, no flapping (ties do nothing).
|
||||
- [ ] **P2 retunes eyeball (item 28b)** — spot-check on top of the P1
|
||||
entry below: gruvbox/nord/lumon/everforest/retro-82/white dimmed
|
||||
text (inactive workspaces, muted volume) now visible-but-dim;
|
||||
latte + rose-pine(dawn) + summer-day warn/battery tint reads on
|
||||
the light bases; flexoki-light statuses are the deeper canonical
|
||||
600s; latte selected-row/alt-accent pink darker. Anything that
|
||||
lost its "dim" feel → reopen 28b.
|
||||
- [ ] **Retuned palettes eyeball (item 28b P1)** — switch through
|
||||
summer-day, flexoki-light, kanagawa, miasma: chips/menus/toasts
|
||||
now draw on a *raised* surface (summer-day's was slate-on-cream,
|
||||
kanagawa's near-black, miasma's pure black), secondary text
|
||||
(tooltips, fastfetch labels) is visible on summer-day +
|
||||
flexoki-light, kanagawa floats are lighter than the bg (upstream
|
||||
sumiInk4). Anything that reads worse than before → reopen 28b.
|
||||
- [ ] **Clock zone tooltip (LATER item)** — hover the bar clock: the
|
||||
tooltip's first line shows the zone ("BST (UTC+0100)") above the
|
||||
calendar, on the generated AND summer bars; with auto-timezone
|
||||
on, a zone change updates it (the SIGUSR2 reload).
|
||||
- [ ] **Doctor bar tripwire (LATER item)** — with everything healthy
|
||||
the bar shows nothing; `systemctl --user start doomed`-style
|
||||
induced failure → within ~5 min a red appears (tooltip lists
|
||||
the ✖ lines), clicking opens the sheet in a terminal;
|
||||
reset-failed → it disappears on the next poll. Also visible on
|
||||
both summer bars.
|
||||
- [ ] **OCR region (LATER item)** — Tools › Capture › "OCR region →
|
||||
clipboard": select a region with visible text → toast reports
|
||||
the word count and `wl-paste` yields the text; Esc in slurp
|
||||
cancels silently; a text-free region toasts "No text recognized"
|
||||
without clobbering the clipboard.
|
||||
- [ ] **Look & Feel submenu (item 19)** — root menu: "Look & Feel"
|
||||
(replacing Theme, root still six rows) → Theme grid opens, Next
|
||||
wallpaper cycles instantly, Night light toggles (and is GONE
|
||||
from System). SUPER+T / SUPER+SHIFT+T direct binds unchanged.
|
||||
- [ ] **Launch-or-focus (item 17)** — uncomment the template's
|
||||
`nomarchy.launchOrFocus` firefox example (with firefox
|
||||
installed), `home-update` + reload: SUPER+B launches firefox
|
||||
when closed, FOCUSES the existing window when open (also from
|
||||
another workspace); with firefox removed the bind fires a
|
||||
"not installed" toast; the row shows under SUPER+?.
|
||||
- [ ] **Themed greeter + console (item 16)** — after `sys-rebuild` +
|
||||
logout: tuigreet renders in theme colors (dark container, accent
|
||||
border, themed prompt/time) and a raw tty (CTRL+ALT+F2) shows the
|
||||
theme's ANSI palette; on a LUKS machine the passphrase prompt
|
||||
follows too. Then switch theme + `sys-rebuild` + logout → the
|
||||
greeter follows the new palette. (tuigreet can't run under the
|
||||
VM harness — see MEMORY.md — so rendering is hardware-tier.)
|
||||
- [ ] **Color picker (item 13, final slice)** — SUPER+CTRL+P (or Tools ›
|
||||
Color picker): hyprpicker's zoom loupe appears; click a pixel →
|
||||
toast shows the hex and `wl-paste` yields it; Esc cancels with no
|
||||
toast. Row present in the SUPER+? cheatsheet.
|
||||
- [ ] **Low-battery toasts (item 13 slice)** — on battery, drain past
|
||||
25%: one "Battery low" toast; past 10%: a critical "Battery
|
||||
critical" toast that stays up until dismissed (swaync); plug in,
|
||||
drain again → it re-notifies; no repeat toasts while it just keeps
|
||||
draining. (Crossing logic VM-verified — this checks the real
|
||||
swaync rendering in a session.)
|
||||
|
||||
## AMD dev box only
|
||||
- [ ] **AMD runtime bits** — VA-API (`vainfo` → radeonsi), amd-pstate EPP
|
||||
active and PPD switching governors; opt-ins: ROCm (`rocminfo`, a GPU
|
||||
PyTorch/Ollama smoke) and the XDNA NPU driver loading.
|
||||
- [ ] **Fingerprint** — `fprintd-enroll` + (opt-in PAM) login/sudo.
|
||||
|
||||
## Latitude 5410 only
|
||||
- [x] **Waybar theme-switch resilience** (finding #1 re-test, needs main ≥
|
||||
the supervisor commit + relogin) — switch themes repeatedly (incl.
|
||||
summer-day/night whole-swaps): the bar restarts cleanly each time;
|
||||
if anything kills it, it's back within ~a second. `pgrep -f
|
||||
nomarchy-waybar` shows the supervisor. — 2026-07-04 Bernardo:
|
||||
PASS — theme switches clean; pkill respawn so fast the bar never
|
||||
visibly disappears.
|
||||
- [x] **Media keys + gestures** (from dccceb4) — volume/brightness keys
|
||||
drive the OSD; touchpad gestures work. — 2026-07-04 Bernardo:
|
||||
PASS, volume/brightness keys and touchpad gestures all working.
|
||||
- [ ] **v1 QA batch on-hardware pass** (583708d batch was QEMU-verified) —
|
||||
general smoke before the next `main → v1` promotion.
|
||||
|
||||
## T14s only
|
||||
- [ ] **Webcam IR-hide end-to-end on Nomarchy** — installer detects the
|
||||
RGB+IR pair, bakes `hardware.camera.hideIrSensor`; `wpctl status`
|
||||
shows one colour source; an app picker lists one camera; Howdy-style
|
||||
direct `/dev/video2` reads still work.
|
||||
981
agent/JOURNAL.md
Normal file
981
agent/JOURNAL.md
Normal file
@@ -0,0 +1,981 @@
|
||||
# Journal — append-only iteration log
|
||||
|
||||
One entry per iteration, **newest first**. This is the loop's short-term
|
||||
memory: the next session reads the last 3–5 entries to orient. Keep an
|
||||
entry under ~15 lines; durable lessons go to MEMORY.md, not here.
|
||||
|
||||
Template:
|
||||
|
||||
```markdown
|
||||
## YYYY-MM-DD — <task title> (<commit sha, or "no commit">)
|
||||
- **Task:** which BACKLOG item (or QA sweep / bootstrap / escalation)
|
||||
- **Did:** what changed, in 2–4 lines
|
||||
- **Verified:** tier reached (V0/V1/V2) + the actual commands/checks run
|
||||
- **Pending:** V3 queued? follow-ups filed? anything [stuck]?
|
||||
- **Next suggestion:** what the following iteration should probably take
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-05 — display-profile workspace pins (iteration #47, item 15c)
|
||||
- **Task:** item 15 slice (c), the last one — per-profile workspace →
|
||||
output pinning. Item 15 deleted (a/b/c all shipped; V3s queued).
|
||||
- **Did:** a profile is now `{ monitors; workspaces = { "1" = "DP-3"; }; }`
|
||||
(bare list still accepted — either-type + normalization in
|
||||
hyprland.nix; coercedTo refuses list-of-submodule sources). Pins bake
|
||||
as Hyprland `workspace` rules and apply instantly on profile switch
|
||||
(`hyprctl keyword workspace` + `dispatch moveworkspacetomonitor`).
|
||||
monitor-rules.nix gained pure `workspaceRule`; template + README
|
||||
updated.
|
||||
- **Verified:** V1 flake check green (incl. the extended
|
||||
checks.display-profiles assert) + scratch-downstream eval: baked
|
||||
settings render both rule sets, the generated applier carries the
|
||||
keyword+dispatch pairs (bash -n OK), match/list still correct with
|
||||
mixed profile shapes.
|
||||
- **Pending:** V3 queued (workspace-pins entry in HARDWARE-QUEUE, rides
|
||||
the slice-a dock test). Stale-pin note documented in the applier.
|
||||
- **Next suggestion:** backlog is now human/event-gated (28 taste
|
||||
calls, 14 Monday, 18 Decision, 20 KVM) — idle the loop or triage
|
||||
PROPOSED.
|
||||
|
||||
## 2026-07-05 — icon-weight A/B for the human call (iteration #46, item 28)
|
||||
- **Task:** item 28's last `[human]` blocker — make the color-vs-
|
||||
symbolic menu-icon decision cheap.
|
||||
- **Did:** captured the lumon root menu with `-symbolic` icon names
|
||||
(temporary uncommitted rofi.nix edit, reverted after) and published
|
||||
a side-by-side artifact (link in the BACKLOG bullet). Findings:
|
||||
symbolic matches the bar's weight, but Papirus symbolic coverage
|
||||
has holes and rofi tints symbolics fixed gray — B needs an
|
||||
audit+recolor slice; A (color) is the free default.
|
||||
- **Verified:** V2 for the experiment itself (both variants VM-
|
||||
captured); no repo code changed — tree is clean apart from agent/.
|
||||
- **Pending:** Bernardo's call on the artifact. Item 28 is now fully
|
||||
agent-side done: all remaining bullets are `[human]`/hardware.
|
||||
- **Next suggestion:** general loop — item 15 slice (c) (per-profile
|
||||
workspaces) is the topmost actionable code item; 14 fires Monday.
|
||||
|
||||
## 2026-07-05 — purge stub waybar.css whole-swaps (iteration #45, item 28c/d)
|
||||
- **Task:** item 28 — lumon vibe capture exposed four themes shipping
|
||||
an unstyled default bar.
|
||||
- **Did:** deleted the stub waybar.css in catppuccin/lumon/nord/
|
||||
retro-82 (2–14 lines of color defines from the f211ef0 rewrite
|
||||
import; a theme waybar.css replaces the WHOLE generated stylesheet,
|
||||
so the stubs nuked all bar styling). The four themes now get the
|
||||
generated bar in their own palette; their full rofi.rasi designs
|
||||
kept. Whole-swap bars are now only summer-day/night, both authored.
|
||||
- **Verified:** V2 — lumon re-capture shows the generated styling
|
||||
(workspace pill, padded right cluster, no edge clipping); V1 flake
|
||||
check green. catppuccin/nord/retro-82 share the mechanism, not
|
||||
individually captured.
|
||||
- **Pending:** HARDWARE-QUEUE eyeballs; the `[human]` icon-weight call.
|
||||
- **Next suggestion:** item 28 is agent-side done pending Bernardo's
|
||||
taste calls — park it; take the next actionable BACKLOG item.
|
||||
|
||||
## 2026-07-05 — capture harness paints wallpapers (iteration #44, item 28c)
|
||||
- **Task:** item 28c harness gap — captures rendered a bare base-color
|
||||
backdrop because the guest had no `~/.nomarchy` runtime state.
|
||||
- **Did:** tools/theme-shot.nix now seeds theme-state.json via tmpfiles
|
||||
at boot (before greetd), so the session's exec-once
|
||||
`nomarchy-theme-sync wallpaper` paints naturally; dropped the
|
||||
testScript seed+manual-repaint (too late for exec-once; manual runs
|
||||
also lack WAYLAND_DISPLAY, which awww's client needs to find its
|
||||
socket).
|
||||
- **Verified:** V2 — summer-night capture shows wallpaper + cream
|
||||
inverted bar + menu + placeholder dim, all coherent. V1 flake check
|
||||
green.
|
||||
- **Pending:** identity-theme vibe capture (lumon/retro-82); the
|
||||
`[human]` icon-weight call; HARDWARE-QUEUE eyeballs.
|
||||
- **Next suggestion:** item 28c identity capture, or park 28 for
|
||||
Bernardo's taste calls.
|
||||
|
||||
## 2026-07-05 — clock zone tooltip (iteration #43, LATER item)
|
||||
- **Task:** LATER › auto-timezone Waybar tooltip. Bullet deleted.
|
||||
- **Did:** the clock tooltip's first line is now the zone —
|
||||
`{:%Z (UTC%z)}` above the calendar — in the generated bar AND both
|
||||
summer whole-swaps (parity). Under auto-timezone the existing
|
||||
tz-watch SIGUSR2 reload keeps it current, so it shows the detected
|
||||
zone live. (%Z abbreviation, not the IANA name — strftime has no
|
||||
code for that; good enough for an "(optional)" nicety.)
|
||||
- **Verified:** V0; V1 — rendered generated config carries the new
|
||||
tooltip-format; both summer jsonc parse (jq) with %Z present.
|
||||
Hover render → V3 queued.
|
||||
- **Pending:** V3. LATER now holds only deferred/big/hw/human items.
|
||||
- **Next suggestion:** a QA sweep, or stop-and-wait — the queue is
|
||||
effectively drained for unattended work; meaty LATER items
|
||||
(wallpapers split is *deferred by decision*, installer round 2
|
||||
[big]) deserve Bernardo's go-ahead or a fresh session.
|
||||
|
||||
## 2026-07-05 — doctor bar tripwire (iteration #42, LATER item)
|
||||
- **Task:** LATER › doctor Waybar warning. Bullet deleted.
|
||||
- **Did:** nomarchy-doctor-status (named bin, PATH): silent exit 0
|
||||
while the doctor is healthy or absent (self-gate), else JSON with
|
||||
the first ✖ lines jq-escaped into the tooltip, in @bad; click =
|
||||
nomarchy-menu doctor (the sheet). custom/doctor added to the
|
||||
generated bar (after battery, interval 300 — the check is real
|
||||
work, this is a tripwire not a monitor) + CSS, AND both summer
|
||||
whole-swaps (module list, jsonc block, CSS membership + @red rule)
|
||||
per the parity rule.
|
||||
- **Verified:** V0; V1 — template-home builds, status bash -n, config
|
||||
+ CSS each carry the module, both summer jsonc still parse (jq)
|
||||
with the block; FUNCTIONAL — self-gate silent, and a shimmed
|
||||
failing doctor produces valid JSON (jq-verified: class bad, ✖
|
||||
lines in tooltip). Live render → V3 queued.
|
||||
- **Pending:** V3. LATER remaining: wallpapers-artifact split
|
||||
(deferred by decision), installer round 2 [big], boot-from-
|
||||
snapshot, night-light geo, icon overrides, MIPI camera [hw],
|
||||
auto-timezone tooltip, VPN richer display, release bump [human].
|
||||
- **Next suggestion:** auto-timezone Waybar tooltip (small) — or a
|
||||
QA sweep; the meatier LATER items deserve a fresh session.
|
||||
|
||||
## 2026-07-05 — OCR screenshot-to-text (iteration #41, LATER item)
|
||||
- **Task:** LATER › OCR (NEXT is fully human/event-gated, so LATER is
|
||||
in play per LOOP.md). Bullet deleted.
|
||||
- **Did:** Capture › "OCR region → clipboard" (self-gated on
|
||||
tesseract): slurp (Esc = silent cancel, the recording pattern) →
|
||||
grim → tesseract stdin/stdout → wl-copy, whitespace-only results
|
||||
toast instead of clobbering the clipboard; success toasts the word
|
||||
count. tesseract ships eng-only via rofi.nix home.packages
|
||||
(override documented — unscoped it drags every language's
|
||||
traineddata, real cost on a compile-from-source distro).
|
||||
- **Verified:** V0; V1 — template-home builds, menu bash -n, gated
|
||||
row + case present; FUNCTIONAL — the profile's own tesseract read a
|
||||
rendered test image back verbatim ("Nomarchy OCR smoke test 42"),
|
||||
so the OCR half of the pipe is proven; grim/slurp half needs a
|
||||
session → V3 queued.
|
||||
- **Pending:** V3.
|
||||
- **Next suggestion:** LATER: doctor Waybar warning (self-gating bar
|
||||
indicator fed by nomarchy-doctor) or auto-timezone tooltip; both
|
||||
small.
|
||||
|
||||
## 2026-07-05 — Look & Feel menu category (iteration #40, item 19)
|
||||
- **Task:** BACKLOG NEXT#19 — its ≥3-entries gate is met (Theme, Next
|
||||
wallpaper, Night light). Item deleted.
|
||||
- **Did:** root's Theme row → "Look & Feel" (pango-escaped —
|
||||
-markup-rows menus treat & as an entity; matched on *Look*); new
|
||||
lookfeel mode: Theme (SUPER+T hint), Next wallpaper (SUPER+SHIFT+T
|
||||
hint via the new generalized hintForAction), Night light row moved
|
||||
from System (System thins by one). Root stays six. menuHint is now
|
||||
sugar over hintForAction.
|
||||
- **Verified:** V0; V1 — menu bash -n, lookfeel mode + escaped label
|
||||
+ night light relocated (4 occurrences, all in lookfeel/nightlight
|
||||
paths); VISUAL — tokyo-night capture: root renders "Look & Feel"
|
||||
correctly with six rows and intact hints. Submenu flow → V3
|
||||
queued.
|
||||
- **Pending:** V3. NEXT now: 28 (Bernardo-gated) · 14 (Monday watch)
|
||||
· 18 [big, Decision-gated] · 20 [human] — the LATER tier or QA
|
||||
sweeps are next for the loop.
|
||||
- **Next suggestion:** LATER's OCR screenshot-to-text (two-row
|
||||
Capture addition, self-contained) — or a QA sweep.
|
||||
|
||||
## 2026-07-05 — launch-or-focus binds (iteration #39, item 17)
|
||||
- **Task:** BACKLOG NEXT#17 (the UI review is Bernardo-gated; back to
|
||||
the queue head). Item deleted.
|
||||
- **Did:** nomarchy.launchOrFocus (listOf submodule: key/mods/class/
|
||||
command/desc; opt-in, template example) → hyprland.nix generates
|
||||
binds through a shared nomarchy-focus-or-launch script (jq
|
||||
case-insensitive class match → focuswindow "(?i)" regex, else
|
||||
launch; uninstalled command → toast, so binds survive suite edits);
|
||||
rofi.nix renders the same entries into the SUPER+? cheatsheet via
|
||||
prettyKeys (single source). README row.
|
||||
- **Verified:** V0; V1 — scratch downstream with 2 entries: both
|
||||
binds rendered (default command = lowercased class; custom
|
||||
mods/command/desc honored), tool bash -n + usage exit 64,
|
||||
cheatsheet rows present. Focus behaviour needs a session → V3
|
||||
queued.
|
||||
- **Pending:** V3. Queue after this: #18 control center [big, needs
|
||||
the form-factor Decision], #19 Look&Feel menu (gated on ≥3
|
||||
entries), #20 [human], LATER tier.
|
||||
- **Next suggestion:** a QA sweep (#18/#19/#20 are blocked-ish) — or
|
||||
item 19's precondition check (does Look & Feel earn 3 entries
|
||||
yet?).
|
||||
|
||||
## 2026-07-05 — placeholder dim + latte review + backdrop probe (iteration #38, item 28c)
|
||||
- **Task:** item 28 slice (c) — the summer-rasi quickie + the light-
|
||||
theme capture.
|
||||
- **Did:** both summer rasi: placeholder-color @bg0 → bg0 at 60%
|
||||
alpha (#…99), so prompt and placeholder no longer read as one
|
||||
phrase. Captured catppuccin-latte at 1080p: the generated menu is
|
||||
COHERENT on light themes (zebra rows on the 28b-retuned surface,
|
||||
hints dimmed) — closes the audit's "dark terminal on latte"
|
||||
concern as a stale preview. Backdrop suspicion probed with a
|
||||
dedicated VM (hyprctl getoption): misc:background_color IS set
|
||||
(0xFFEFF1F5) — awww's empty-state layer occludes it in the
|
||||
wallpaper-less VM; on hardware the fix covers the startup gap as
|
||||
intended.
|
||||
- **Verified:** rasi edits grep-verified (rasi parses at rofi
|
||||
runtime; visual rides the next summer capture / V3); latte menu
|
||||
capture reviewed; probe output above.
|
||||
- **Pending:** item 28 remaining: icon-weight `[human]`, hardware
|
||||
eyeballs (queued), identity-theme capture (optional), slice (d)
|
||||
needs nothing (parity verified).
|
||||
- **Next suggestion:** item 28 is now Bernardo-gated (taste calls +
|
||||
V3); the loop should return to the general BACKLOG head (item 14
|
||||
watch / item 17 launch-or-focus).
|
||||
|
||||
## 2026-07-05 — rofi keybind hints (iteration #37, item 28c)
|
||||
- **Task:** item 28 slice (c) — the hint column, the audit's biggest
|
||||
remaining UX item.
|
||||
- **Did:** rofi.nix: menuHint builds a dimmed pango span
|
||||
(size small, alpha 55%) from keybinds.nix via the cheatsheet's
|
||||
prettyKeys — single source, hints can't drift from the live binds;
|
||||
applied to root (Apps/Theme/Power/Keybindings; Apps special-cased,
|
||||
it's rofi drun not a menu module), Tools (all eight leaves), System
|
||||
(Network/Bluetooth/DND); those three menus now pass -markup-rows.
|
||||
Contains-glob matching and the exact "↩ Back" match are unaffected
|
||||
(labels keep their prefix; Back stays markup-free).
|
||||
- **Verified:** V0; V1 rendered menu bash -n + hint spans present +
|
||||
3× -markup-rows; VISUAL — tokyo-night capture: hints render dimmed
|
||||
and subordinate on normal AND selected (accent) rows; Tools/System
|
||||
rows correctly bare.
|
||||
- **Pending:** slice-c remainder: summer-rasi placeholder dim,
|
||||
latte/identity captures, icon-weight `[human]`.
|
||||
- **Next suggestion:** the placeholder-dim quickie + a latte capture
|
||||
in one tick; then item 28 pauses for Bernardo's icon-weight call
|
||||
and the hardware eyeballs.
|
||||
|
||||
## 2026-07-05 — bar group rhythm + @muted adoption (iteration #36, item 28c)
|
||||
- **Task:** item 28 slice (c) — the two queued bar polish items.
|
||||
- **Did:** waybar.nix generated CSS: margin-left 14px on the three
|
||||
right-cluster group heads (pulseaudio/powerprofile/battery — media
|
||||
· toggles · status; hidden heads degrade to uniform spacing);
|
||||
workspaces buttons, dnd bell, and muted volume moved from
|
||||
alpha(@text,.5) tints to the semantic @muted role — safe since 28b
|
||||
floor-gates muted/base ≥ 2.0 (the old comment warning against
|
||||
@muted documented the pre-28b world; rewritten to state the new
|
||||
invariant). Whole-swap bars untouched (authored identity).
|
||||
- **Verified:** V0; V1 rendered CSS has 4 @muted uses + the margin
|
||||
rule; VISUAL — tokyo-night re-capture: themed backdrop confirmed
|
||||
(navy base, not black), group gap visible before the volume group,
|
||||
workspace pill legible. Cross-theme minima are guaranteed by the
|
||||
gated checker rather than per-theme eyeballs.
|
||||
- **Pending:** slice-c remainder: rofi hint column, summer-rasi
|
||||
placeholder dim, icon-weight `[human]`, latte/identity captures.
|
||||
- **Next suggestion:** rofi keybind-hint column (the biggest
|
||||
remaining UX win), or the two-line placeholder nit as a quickie.
|
||||
|
||||
## 2026-07-05 — summer-day capture review + themed backdrop (iteration #35, item 28c)
|
||||
- **Task:** item 28 slice (c) — whole-swap capture review + the first
|
||||
cheap polish fix.
|
||||
- **Did:** captured summer-day at 1080p (harness, VM): the authored
|
||||
slate menu + island-pill bar hold up with the 28b retunes —
|
||||
initially misread as polarity soup, but the rasi whole-swap
|
||||
deliberately mirrors the bar's slate strip: identity, keep (nit
|
||||
filed: undimmed entry placeholder). The surviving cross-theme fix:
|
||||
Hyprland `misc:background_color` = theme base (was compositor
|
||||
black — a glitch-looking flash behind missing/slow wallpaper,
|
||||
glaring on light themes). Punch list updated.
|
||||
- **Verified:** V0; V1 — template-home rebuilt, rendered hyprland.conf
|
||||
carries `background_color=rgb(1a1b26)` (theme base). Backdrop
|
||||
visible confirmation rides the next capture run / V3.
|
||||
- **Pending:** captures for latte + one identity theme; polish items
|
||||
queued: bar group margins, @muted adoption, rofi hint column, icon
|
||||
weight `[human]`.
|
||||
- **Next suggestion:** bar polish slice (group margins + @muted) —
|
||||
code-level, verifiable by build + re-capture.
|
||||
|
||||
## 2026-07-05 — 1080p capture harness + first slice-c review (iteration #34, item 28c)
|
||||
- **Task:** item 28 slice (c) prep — full-res captures for the
|
||||
per-surface polish pass.
|
||||
- **Did:** tools/theme-shot.nix (maintainer tool, THEME env-driven):
|
||||
full themed desktop headless at 1920x1080 via the memory recipe +
|
||||
two fixes over the spike — home-manager.useGlobalPkgs (HM submodule
|
||||
otherwise misses the overlay → 'nomarchy-theme-sync missing') and a
|
||||
menu.png shot (hyprctl dispatch exec nomarchy-menu). Proven on
|
||||
tokyo-night; both shots read. Findings → item 28 punch list: rofi
|
||||
root width vs empty space (→ keybind-hint column idea), icon-weight
|
||||
mix (color Papirus vs mono bar) `[human]`, bar group margins
|
||||
confirmed, alpha-tint dim vs @muted role. Whole-swap module parity
|
||||
verified textually (no drift; cpu/memory omission is identity).
|
||||
- **Verified:** harness runs end-to-end (exit 0, screenshots read);
|
||||
eval from tools/ with relative flake path OK. Wallpaper still
|
||||
doesn't paint (theme-sync needs ~/.nomarchy in the guest — fix
|
||||
noted in the header for the next run).
|
||||
- **Pending:** capture summer-day/night (whole-swaps) + latte;
|
||||
then the polish slices; icon-weight call is Bernardo's.
|
||||
- **Next suggestion:** run the retuned-theme captures + start the
|
||||
cheap polish items (group margins, @muted adoption).
|
||||
|
||||
## 2026-07-05 — P2 floors retuned + gated (iteration #33, item 28b done)
|
||||
- **Task:** item 28 slice (b) remainder — the P2 contrast floors.
|
||||
- **Did:** 18 hex retunes across 9 themes: muted raised on lumon/
|
||||
white/retro-82/everforest (OKLCH hue-preserving minimal solve to
|
||||
≥2.05) + gruvbox→bg4 #7c6f64, nord→#616e88 (community standard),
|
||||
latte→overlay1 #8c8fa1; text-on-surface via surface nudges
|
||||
(ristretto darker, latte lighter); accentAlt darkened (latte,
|
||||
summer-day); warn darkened on the light themes (latte, summer-day,
|
||||
rose-pine-dawn) and flexoki-light's four statuses moved to the
|
||||
canonical 600 series. check-theme-contrast.py gates all four
|
||||
adopted floors (muted ≥2, text/surface ≥4.5, accentAlt ≥3, warn
|
||||
≥2.5 — warn is the battery tint); good/bad stay audit-only
|
||||
(identity), so no exemption mechanism was needed. Slice (b) done.
|
||||
- **Verified:** V0 + checks.theme-contrast GREEN (21×7); re-audit:
|
||||
contrast findings 20→1 (miasma bad = identity); flake check green.
|
||||
Rendering is V3 → queued (P2 eyeball entry).
|
||||
- **Pending:** slices (c) per-surface polish (needs 1080p captures)
|
||||
and (d) whole-swap bar parity; ansi[] conventions decision still
|
||||
open (audit notes).
|
||||
- **Next suggestion:** slice (c) prep — 1080p captures via the VM
|
||||
recipe, or hardware captures if Bernardo prefers eyeballing first.
|
||||
|
||||
## 2026-07-05 — P1 palette retunes + gated subtext floor (iteration #32, item 28b)
|
||||
- **Task:** item 28 slice (b), P1s from the #31 audit.
|
||||
- **Did:** summer-day: surface #5c6a72(=text!)→#efe7d0 raised cream,
|
||||
subtext #fdf6e3(=base!)→#6e828a slate; flexoki-light to canonical
|
||||
Flexoki tones: surface #E6E4D9(ui), overlay #B7B5AC, subtext
|
||||
#6F6E69(tx-2), muted #878580(base-500); miasma surface #000→#2e2e2e;
|
||||
kanagawa surface #090618→#2a2a37 (upstream sumiInk4 — old value was
|
||||
sumiInk0, darker than bg). check-theme-contrast.py gains the adopted
|
||||
`subtext/base ≥ 3` pairing (the item-25/27 trap, now impossible).
|
||||
Model note recorded: `overlay` is a mid-tone role, not a bg tier.
|
||||
- **Verified:** V0 + checks.theme-contrast GREEN (21×3 pairings);
|
||||
re-audit: all four P1 findings gone (kanagawa now CVD-only findings);
|
||||
V1 — scratch downstream with summer-day ACTIVE builds, new surface
|
||||
hex present in rendered ghostty config. Looks are V3 → queued
|
||||
(four-theme eyeball).
|
||||
- **Pending:** 28b remainder: P2 floors (muted ≥2, warn ≥2.5,
|
||||
text-on-surface ≥4.5, accentAlt ≥3) + exemption-list mechanism.
|
||||
- **Next suggestion:** 28b P2s (7 muted retunes + 4 warn + 2
|
||||
text-on-surface + 2 accentAlt, then gate with exemptions).
|
||||
|
||||
## 2026-07-05 — theme design audit (iteration #31, item 28 slice a)
|
||||
- **Task:** BACKLOG NEXT#28 slice (a) — the design-theory audit
|
||||
(human-requested; Bernardo asked to run it now).
|
||||
- **Did:** tools/audit-theme-design.py (new, report-only): OKLCH
|
||||
lightness architecture, extended WCAG pairs, status-hue families,
|
||||
accent harmony, Machado protan/deutan simulation, ANSI slot
|
||||
semantics — over all 21 palettes; plus a visual pass over 4
|
||||
representative preview.png captures. Findings curated
|
||||
identity-aware into a P1–P3 punch list appended to item 28: 2
|
||||
invisible-subtext palettes (summer-day, flexoki-light), 2 inverted
|
||||
bg stacks (miasma, kanagawa), 7 muted-floor misses, warn-barely-
|
||||
reads ×4, a systemic "status is never color-only" rule (CVD
|
||||
collapse is inherent, glyph redundancy is the fix), explicit
|
||||
identity exemptions, light-theme ANSI convention decision, bar
|
||||
right-cluster grouping rhythm, latte dark-terminal verify.
|
||||
- **Verified:** V0 (py_compile; report tool, not wired into checks).
|
||||
Analysis is palette-math + thumbnail previews; per-surface
|
||||
spacing/type audit needs 1080p captures (slice c prep).
|
||||
- **Pending:** slice (b) — palette retunes + checker extension w/
|
||||
exemption list; needs Bernardo's eye on the P1 retunes (visual
|
||||
taste calls). Artwork needs none so far — no image-model ask yet.
|
||||
- **Next suggestion:** slice (b) P1s (summer-day/flexoki subtext+
|
||||
surface, miasma/kanagawa stacks) — small hex edits, big payoff.
|
||||
|
||||
## 2026-07-05 — greeter theming from the JSON (iteration #30, item 16)
|
||||
- **Task:** BACKLOG NEXT#16 — tuigreet themed from theme-state.json at
|
||||
system rebuild (the Plymouth model). Item deleted.
|
||||
- **Did:** new modules/nixos/greeter.nix owns the greetd block (moved
|
||||
out of default.nix, one concern one file) + the theming: (1)
|
||||
console.colors = the theme's ansi[] (mkDefault; lands as
|
||||
vt.default_* kernel params — also themes raw ttys + LUKS prompt);
|
||||
(2) tuigreet --theme on NAMED slots (its parser is ratatui
|
||||
Color::from_str, verified in source; names hit the standard indexes
|
||||
the retinted VT palette now serves). Sparse state w/o ansi → skips
|
||||
cleanly.
|
||||
- **Verified:** V0; V1 — template-system toplevel: baked greetd.toml
|
||||
carries the full --theme spec, kernel-params carry all three
|
||||
vt.default_{red,grn,blu}. A checks.greeter VM test was attempted and
|
||||
DROPPED: tuigreet dies under runNixOSTest even bare (harness limit,
|
||||
not our flag — bisected; nixpkgs tests use agreety) → MEMORY.md.
|
||||
- **Pending:** V3 queued (rendering + theme-follows-rebuild).
|
||||
- **Next suggestion:** #17 launch-or-focus, or the new #28 UI-review
|
||||
audit slice once Bernardo confirms its placement.
|
||||
|
||||
## 2026-07-05 — display profiles auto-switch (iteration #29, item 15b)
|
||||
- **Task:** BACKLOG NEXT#15 slice b — opt-in hotplug auto-switch.
|
||||
- **Did:** nomarchy-display-profile gains `match <outputs>` (exact set
|
||||
→ else unambiguous largest subset → ties/none = exit 1);
|
||||
nomarchy-display-profile-watch polls `hyprctl monitors all` every 3s
|
||||
(exec-once, the keyboard-watcher pattern — session units race
|
||||
Hyprland IPC), reacts only to CHANGES, reads settings.displayProfileAuto
|
||||
LIVE each change (instant menu toggle, no rebuild) and applies via
|
||||
the tool, so auto-picks persist concrete profiles that rebuilds
|
||||
bake. Chose a separate boolean over an "auto" pseudo-profile for
|
||||
exactly that bake semantics. Menu: Auto-switch (on/off) row in
|
||||
Profiles. Template + README notes.
|
||||
- **Verified:** V0; V1 — scratch 4-profile downstream builds; both
|
||||
scripts bash -n; match matrix exercised: exact ×3, unambiguous
|
||||
subset, tie → none, no-fit → none; watcher exec-once present; menu
|
||||
renders with the row. Real hotplug needs a session+dock → V3 (rides
|
||||
the slice-a queue entry).
|
||||
- **Pending:** V3. Slice c (workspace binding) remains, tagged
|
||||
optional.
|
||||
- **Next suggestion:** #16 greeter theming — item 15's remaining
|
||||
slice c is optional; a fresh item keeps variety.
|
||||
|
||||
## 2026-07-05 — display profiles slice a (iteration #28, item 15a)
|
||||
- **Task:** BACKLOG NEXT#15 slice a, per the #27 design: option +
|
||||
overlay + applier + menu + template example.
|
||||
- **Did:** nomarchy.displayProfiles (attrsOf (listOf monitorType));
|
||||
monitor logic extracted to pure modules/home/monitor-rules.nix
|
||||
(rule renderer + 3-layer resolve: profile replaces whole-by-name →
|
||||
resolution picks field-level with the disable-guard → wildcard),
|
||||
hyprland.nix consumes it and gains nomarchy-display-profile
|
||||
(list/active/apply/base; apply = baked hyprctl rules + state write
|
||||
--no-switch, base = clear + hyprctl reload) on PATH only when
|
||||
profiles exist; menu: Display gains a gated "Profiles ›" row + new
|
||||
display-profile mode (●/○ active mark, Base layout row); template
|
||||
example + README row. checks.display-profiles unit-tests resolve
|
||||
(incl. junk-state degradation) — the first HM-eval fixture attempt
|
||||
hit "path not valid" (eval store won't realise writeText/toFile
|
||||
under flake check), hence the pure-function extraction.
|
||||
- **Verified:** V0 (check's asserts force at eval); V1 — scratch
|
||||
downstream through lib.mkFlake builds: tool bash -n + correct baked
|
||||
rules (disable, vrr, floats), hyprland.conf shows the exact overlay
|
||||
(wildcard + kept base + disabled panel + profile output), menu bash
|
||||
-n, list/usage smoke. Live switching needs a session+dock → V3.
|
||||
- **Pending:** V3 queued. Slices b (hotplug auto-switch) and c
|
||||
(workspace binding) remain in the item.
|
||||
- **Next suggestion:** #16 greeter theming, or 15b if momentum on
|
||||
displays is preferred.
|
||||
|
||||
## 2026-07-05 — display-profiles design pass (iteration #27, item 15, no code)
|
||||
- **Task:** BACKLOG NEXT#15 — the entry itself demands "design first,
|
||||
write the plan into this entry before coding". Backlog-only iteration.
|
||||
- **Did:** wrote the plan into item 15: `nomarchy.displayProfiles =
|
||||
attrsOf (listOf monitorType)` (reuse the existing submodule),
|
||||
`settings.displayProfile` state via the night-light pattern (instant
|
||||
hyprctl apply + bake on rebuild), whole-entry-by-name overlay with a
|
||||
disable-guard against stale resolution picks, self-gated menu row,
|
||||
three slices (option+overlay+menu / opt-in hotplug auto-switch /
|
||||
per-profile workspace binding), kanshi stays a non-goal.
|
||||
- **Verified:** V0 (docs-only; flake untouched).
|
||||
- **Pending:** nothing — 15a is now directly codeable.
|
||||
- **Next suggestion:** 15a (option + overlay + menu picker), or #16
|
||||
greeter theming if a fresh session prefers a self-contained item.
|
||||
|
||||
## 2026-07-05 — scheduled lock-bump workflow (iteration #26, item 14 b+c)
|
||||
- **Task:** BACKLOG NEXT#14 `[big]` — split: (a) checks-on-push shipped
|
||||
earlier; this ships (b) the weekly bump + (c) the fast-lane as
|
||||
workflow_dispatch on the same job.
|
||||
- **Did:** .gitea/workflows/bump.yml — Mon 05:17 UTC cron + dispatch:
|
||||
nix flake update (pinned branches by construction) → gate `nix flake
|
||||
check --no-build` (py_compile/bash -n skipped: they don't read the
|
||||
lock) → commit --only flake.lock with the update's change list as
|
||||
body → push main (triggers check.yml as second net). Red gate/push
|
||||
race = failed run, nothing lands. Container recipe from check.yml.
|
||||
- **Verified:** V0 (yq parse + bash -n each run block); logic simulated
|
||||
end-to-end in a scratch clone with a REAL nix flake update + bare
|
||||
remote: changed/unchanged branches, bystander file stays uncommitted,
|
||||
push lands; today's bumped lock evals green (Monday's baseline).
|
||||
Gitea 1.25.4 confirmed (schedule supported). The real cron pickup +
|
||||
token push are NOT confirmable from here → item 14 slimmed to
|
||||
"confirm first run".
|
||||
- **Pending:** watch the first scheduled/dispatched bump run.
|
||||
- **Next suggestion:** #16 greeter theming (next codeable item; #15
|
||||
needs its design pass written first).
|
||||
|
||||
## 2026-07-05 — color picker (iteration #25, item 13 final slice → item done)
|
||||
- **Task:** BACKLOG NEXT#13 last slice — hyprpicker → clipboard from
|
||||
the menu + a direct bind. Item 13 complete; deleted from BACKLOG.
|
||||
- **Did:** hyprpicker into systemPackages (next to grim/slurp); rofi.nix
|
||||
`colorpicker` mode (hyprpicker → wl-copy → hex-in-toast, Esc = silent
|
||||
cancel) + self-gated Tools › "Color picker" row + usage line;
|
||||
keybinds.nix SUPER+CTRL+P row (feeds bind + cheatsheet).
|
||||
- **Verified:** V0; V1 — template-home AND template-system build;
|
||||
rendered nomarchy-menu bash -n OK with mode + gated row; cheatsheet
|
||||
txt has the SUPER+CTRL+P row; hyprland conf has the bind; system
|
||||
toplevel ships sw/bin/hyprpicker. Picking needs a compositor → V3.
|
||||
- **Pending:** V3 queued (loupe → click → wl-paste round-trip).
|
||||
- **Next suggestion:** #15 (display profiles) needs a design pass
|
||||
written into the entry first; #16 (greeter theming) is the next
|
||||
directly codeable item — or #14's bump workflow (eval-tier gate).
|
||||
|
||||
## 2026-07-05 — low-battery notifications (iteration #24, item 13 slice)
|
||||
- **Task:** BACKLOG NEXT#13 second slice — the bar colors the battery
|
||||
at 25/10% but nothing *notified*.
|
||||
- **Did:** pkgs/nomarchy-battery-notify (shellcheck-gated watcher:
|
||||
polls the same sysfs the bar reads — type=Battery, scope≠Device —
|
||||
one toast per downward crossing: normal@25, critical@10; re-armed by
|
||||
charging; self-gates on battery presence → desktop no-op) + overlay.
|
||||
HM unit in modules/home/battery-notify.nix behind
|
||||
nomarchy.batteryNotify.enable (default on), graphical-session-bound,
|
||||
libnotify on the unit PATH (notify-send resolved from PATH so the
|
||||
check can shim it). README row. Chose the tiny watcher over
|
||||
poweralertd: its UPower thresholds (20/5) wouldn't match the bar,
|
||||
and it toasts every plug/unplug.
|
||||
- **Verified:** V0; V1 — template-home builds, unit present; V2 GREEN —
|
||||
new checks.battery-notify (test_power fake battery): self-gate exits
|
||||
0 without a battery, silence at 80%, exactly one low toast crossing
|
||||
25, one critical-urgency toast crossing 10, charging re-arms → a
|
||||
second drain toasts again.
|
||||
- **Pending:** V3 queued (real toast through swaync while draining).
|
||||
- **Next suggestion:** item 13 final slice — hyprpicker color picker
|
||||
(Tools › entry + SUPER+CTRL bind).
|
||||
|
||||
## 2026-07-04 — caffeine/idle-inhibit toggle (iteration #23, item 13 slice)
|
||||
- **Task:** BACKLOG NEXT#13 first slice — idle_inhibitor in the
|
||||
generated bar (summer-night had it; reverse parity gap).
|
||||
- **Did:** waybar.nix: idle_inhibitor module (/, tooltips, placed
|
||||
after the ⏺), CSS membership + `.activated { color: @warn; }`.
|
||||
summer-day: module + CSS mirrored from summer-night (same glyphs,
|
||||
no tint — glyph change is the state signal there). keybinds.nix
|
||||
extra row → cheatsheet mentions the bar click.
|
||||
- **Verified:** V0; V1 — template-home built; rendered config has the
|
||||
module second in modules-right with correct glyphs; CSS rules
|
||||
present; cheatsheet row renders. Inhibit behaviour needs a session
|
||||
→ V3 queued (hold past the lock timeout).
|
||||
- **Pending:** V3. Item 13 remaining slices: low-battery
|
||||
notifications, color picker.
|
||||
- **Next suggestion:** item 13 next slice (low-battery notifications,
|
||||
gate on power.laptop) — or #14 lock-bump CI if variety is better.
|
||||
|
||||
## 2026-07-04 — screen recording in Capture (iteration #22, item 12)
|
||||
- **Task:** BACKLOG NEXT#12 — record region/screen from the menu, stop
|
||||
from the bar.
|
||||
- **Did:** modules/home/recording.nix: `nomarchy-record`
|
||||
start/stop/active/status — wl-screenrec first, wf-recorder fallback
|
||||
if it dies at startup (no-VAAPI case), SIGINT-finalized stop,
|
||||
runtime pidfile, signal-8 bar pokes. Capture menu: 4 record rows that
|
||||
self-swap to "■ Stop recording" while one runs. Waybar: self-gating
|
||||
custom/recording (⏺ REC, @bad red), click = stop — the one stop
|
||||
surface. Parity: both summer whole-swap bars got the module + CSS
|
||||
(@red). DEVIATIONS: saves to ~/Videos/Recordings (an .mp4 in
|
||||
Pictures/Screenshots felt wrong — same timestamp naming though);
|
||||
audio = two extra explicit rows, not a toggle state.
|
||||
- **Verified:** V0; V1 — template-home builds; rendered bar config has
|
||||
the module (first in modules-right) + CSS rule; summer jsonc still
|
||||
parse; nomarchy-record dry-run: status empty+exit 0 idle, active
|
||||
exit 1, usage exit 2; both recorders in home-path. Real capture
|
||||
needs a session → V3 (headless GL recipe can't confirm an encoder).
|
||||
- **Pending:** V3 recording exercise (incl. VAAPI-vs-fallback check).
|
||||
- **Next suggestion:** NEXT#13 niceties, one slice: idle-inhibit
|
||||
(caffeine) toggle — reverse-parity gap already noted in the item.
|
||||
|
||||
## 2026-07-04 — state-file validation & friendly errors (iteration #21, item 11)
|
||||
- **Task:** BACKLOG NEXT#11 — hand-edited state must fail with field +
|
||||
problem + fix, never a Nix stack.
|
||||
- **Did:** (a) tool: validate_state() (appearance schema = hard errors;
|
||||
settings.*/unknown keys = warnings), `validate` subcommand,
|
||||
validate-BEFORE-write in write_state (invalid set/apply never touches
|
||||
disk), JSON syntax errors now say line/column/fix. (b) theme.nix:
|
||||
same schema at eval time on `parsed` (post-defaults, so sparse files
|
||||
stay fine); throws a multi-line message naming each field, the got-
|
||||
value, and the three fix paths. Doctor's JSON fix-text now points at
|
||||
`validate`.
|
||||
- **Verified:** V0; V1 — new checks.theme-sync-validate GREEN: good
|
||||
template passes, trailing comma → line/col message, bad hex/type →
|
||||
field named, unknown key → warning only, invalid `set` refused with
|
||||
the file byte-identical (cmp). Negative eval of a broken scratch
|
||||
downstream through mkFlake shows the friendly throw (both fields);
|
||||
good-path template-home still builds.
|
||||
- **Pending:** nothing — no hardware dependency.
|
||||
- **Next suggestion:** NEXT#12 (screen recording) or #13 niceties
|
||||
slice; #12 first (it reshapes the Capture submenu the OCR LATER item
|
||||
waits on).
|
||||
|
||||
## 2026-07-04 — nomarchy-doctor (iteration #20, item 10)
|
||||
- **Task:** BACKLOG NEXT#10 — one-shot read-only health check.
|
||||
- **Did:** pkgs/nomarchy-doctor (writeShellApplication → shellcheck-
|
||||
gated; a package so the VM check runs on a minimal node): failed
|
||||
system+user units (user bus self-skips), disk space on real
|
||||
filesystems only (fstype allowlist skips tmpfs/9p → VM-safe; device
|
||||
dedupe), state-file parses + git-tracked, flake dirty/behind
|
||||
(warn-level), generation age via the profile SYMLINK mtime (store
|
||||
paths are epoch-1), snapper timer when enabled. Every ✖ prints its
|
||||
fix; exit 1 on any ✖. Wired: overlay, systemPackages, System ›
|
||||
Doctor menu row (terminal), README §5.
|
||||
- **Verified:** V0; V1 package build (shellcheck) + real-hardware
|
||||
smoke: correctly flagged a genuinely failed user unit on the dev box;
|
||||
V2 GREEN — VM test: induced failed unit → exit 1 + names it + prints
|
||||
fix; reset-failed → healthy exit 0. Menu rebuild bash -n ok.
|
||||
- **Pending:** V3 menu-row check queued. Waybar-warning follow-up →
|
||||
LATER.
|
||||
- **Next suggestion:** NEXT#11 (state-file validation) — doctor's
|
||||
"parses" check is its little sibling; 11 adds validate-before-write
|
||||
+ eval-time schema messages.
|
||||
|
||||
## 2026-07-04 — System › Rollback menu (iteration #19, item 9b → item 9 done)
|
||||
- **Task:** BACKLOG NEXT#9 half (b) — undo one menu away.
|
||||
- **Did:** new `rollback` case in nomarchy-menu (System submenu row):
|
||||
lists the last 10 `home-manager generations` (newest marked current),
|
||||
picking one activates it in a terminal — HM's supported rollback,
|
||||
reversible, so no typed-yes. System-level undo LINKS OUT by design:
|
||||
Snapshots row → existing flow; "boot an older generation (how)" →
|
||||
instruction notification pointing at docs/RECOVERY.md §3 (no
|
||||
destructive reimplementation in rofi). RECOVERY §1 cross-references
|
||||
the menu path. Item 9 complete → deleted.
|
||||
- **Verified:** V0; V1 — template-home built, generated nomarchy-menu
|
||||
bash -n clean, row-render + pick-parse logic run against a fixture
|
||||
`generations` output (id/path extraction correct). V2 skipped
|
||||
deliberately: the only novel logic is the parsing (fixture-covered);
|
||||
the activate step is HM's own mechanism. V3 queued.
|
||||
- **Pending:** V3 rollback-menu exercise on hardware.
|
||||
- **Next suggestion:** NEXT#10 `nomarchy-doctor` (V2-able in a VM).
|
||||
|
||||
## 2026-07-04 — sys-update/-rebuild what-changed diff (iteration #18, item 9a)
|
||||
- **Task:** BACKLOG NEXT#9 half (a) — a human diff after system rebuilds.
|
||||
- **Did:** both sys-update and sys-rebuild (twins stay twins) capture
|
||||
/run/current-system before, and after the switch print
|
||||
`nvd diff before after` (store-path-pinned ${"$"}{pkgs.nvd}, `|| true`
|
||||
so it can't fail a succeeded rebuild; identical-path fast-path says
|
||||
"no changes"). README §3 shortcut block notes it.
|
||||
- **Verified:** V0; V1 — template-system toplevel rebuilt, generated
|
||||
scripts extracted + bash -n, nvd smoke-run against the real closure
|
||||
(correct output format). Runtime behaviour is a trivial shell path —
|
||||
no VM needed.
|
||||
- **Pending:** half (b) — the System → Rollback menu flow (desktop
|
||||
generations picker; system → boot menu + snapshots pointer).
|
||||
- **Next suggestion:** item 9b — it completes the item; V2 the
|
||||
generation-activate path.
|
||||
|
||||
## 2026-07-04 — viewers + mime defaults (iteration #17, item 8)
|
||||
- **Task:** BACKLOG NEXT#8 — PDF/image viewers + xdg-mime defaults.
|
||||
- **Did:** modules/home/viewers.nix (`nomarchy.viewers.enable`, default
|
||||
on): programs.zathura (Stylix themes it — target added to stylix.nix's
|
||||
explicit list, autoEnable=false bit us first try) + imv.
|
||||
modules/home/mime.nix (`nomarchy.mime.enable`): mkDefault
|
||||
xdg.mimeApps for pdf→zathura, image/*→imv, av→mpv, text→code,
|
||||
dir→thunar, html/http(s)→firefox as INERT entries (browser Decision
|
||||
untouched — absent .desktop entries are skipped by GIO). README rows
|
||||
added (option-docs enforces them now). DEVIATION from the item text:
|
||||
viewers are a module toggle, not template packages — zathura's
|
||||
theming needs its HM module, which is exactly the "real config"
|
||||
boundary of the toggle discipline.
|
||||
- **Verified:** V0; V1 — template-home generation builds; asserted
|
||||
rendered mimeapps.list (all associations), themed zathurarc
|
||||
(Tokyo Night rgb), imv/zathura in home-path. V3 smoke queued.
|
||||
- **Pending:** V3 open-a-file smoke; browser Decision now smaller
|
||||
(inert entries ship; only "active in suite?" remains).
|
||||
- **Next suggestion:** NEXT#9 (update & rollback UX) — or #10 doctor.
|
||||
|
||||
## 2026-07-04 — docs slice (c): install story — item 6 COMPLETE (iteration #16)
|
||||
- **Task:** BACKLOG NOW#6 slice (c), the last one — install/first-run
|
||||
narrative end to end.
|
||||
- **Did:** read README §2 (ISO/installer) → §3 (downstream) → template
|
||||
README as one story; checked the facts en route: mkFlake's arg
|
||||
surface == the §3 table (src/username/hardwareProfile/system, lib.nix),
|
||||
disko really makes @snapshots + the hibernation swapfile, .#default /
|
||||
.#me names consistent. One seam fixed: §3 showed `nix flake init -t`
|
||||
but never handed off to the template README's six first-run steps —
|
||||
connective paragraph added (+ "the installer does all of this").
|
||||
Item 6 done → deleted from BACKLOG (NOW now empty); ROADMAP § Full
|
||||
docs review flipped to ✓ with the slice summary.
|
||||
- **Verified:** V0 (docs-only) — flake check clean pre-commit.
|
||||
- **Pending:** docs-site-vs-Markdown stays a Decision.
|
||||
- **Next suggestion:** NEXT#8 (viewers + mime defaults) is the new queue
|
||||
head; note its "Default browser" Decision dependency — the mime module
|
||||
half can proceed with mkDefault degradation regardless.
|
||||
|
||||
## 2026-07-04 — docs slice (d): recovery runbook (iteration #15, item 6d)
|
||||
- **Task:** BACKLOG NOW#6 slice (d) — write the undo story.
|
||||
- **Did:** docs/RECOVERY.md, symptom-ordered: (1) bad theme/HM change →
|
||||
generations / apply-known-good / git-revert ~/.nomarchy; (2) desktop
|
||||
won't start → Ctrl+Alt+F2, greetd + user journals, VM-GL and
|
||||
preactivate-log pointers; (3) system change → systemd-boot older
|
||||
generation (kept: 10) + make-it-stick via sys-rebuild; (4) files →
|
||||
btrfs-assistant / sudo nomarchy-snapshots (undochange, root rollback,
|
||||
typed-yes); (5) ISO + nixos-enter. Every command checked against the
|
||||
tree (greetd cfg, configurationLimit, snapshots script actions,
|
||||
helper names). Linked from README tree + §5.
|
||||
- **Verified:** V0 (docs-only) — flake check clean pre-commit.
|
||||
- **Pending:** slice (c) install-story read-through — the last of item 6.
|
||||
- **Next suggestion:** finish item 6 with slice (c).
|
||||
|
||||
## 2026-07-04 — docs slice (b): drift pass (iteration #14, item 6b)
|
||||
- **Task:** BACKLOG NOW#6 slice (b) — OVERRIDES.md / TESTING.md /
|
||||
templates/downstream/README.md vs the live tree.
|
||||
- **Did:** spot-checked every factual claim: mkDefault sites (hyprland
|
||||
behaviour knobs, ghostty paddings, waybar mainBar/style), bind-list
|
||||
normal priority, `set ui.gapsOut` CLI key, awww(-daemon) naming,
|
||||
21 presets, tokyo-night's 4 wallpapers, summer-night's light @fg bar,
|
||||
live `,highres` mkForce, .gitea/workflows/check.yml, QEMU gl flags,
|
||||
template `.#me` + ~/.nomarchy/NOMARCHY_PATH. All accurate. Fixed the
|
||||
two real gaps: OVERRIDES §2 predated `nomarchy.monitors` (now routes
|
||||
there + quick-ref row); TESTING §1 lacked the shell-syntax check §1b
|
||||
claims CI runs (added `bash -n`).
|
||||
- **Verified:** V0 (docs-only; flake untouched — check run pre-commit).
|
||||
- **Pending:** slices (c) install story, (d) recovery runbook.
|
||||
- **Next suggestion:** item 6 slice (c) or (d) — (d) is self-contained
|
||||
and ships user value (the runbook).
|
||||
|
||||
## 2026-07-04 — docs slice (a): option-surface reconcile (iteration #13, item 6a)
|
||||
- **Task:** BACKLOG NOW#6, first slice — README tables vs live options.
|
||||
- **Did:** split item 6 into slices (a–d) in BACKLOG. Reconciled: 9
|
||||
undocumented options (autoTimezone.enable!, camera.hideIrSensor +
|
||||
irMatch!, intel.guc, amd.pstate/vaapi, package, system.stateFile,
|
||||
restic.paths) — rows/inline mentions added, no stale rows found.
|
||||
Made it permanent: `checks.option-docs` — flake.nix eval-walks option
|
||||
names from the 4 option files (config halves stay lazy; dummy args)
|
||||
→ tools/check-option-docs.py enforces row-or-`.leaf`-mention + flags
|
||||
stale rows.
|
||||
- **Verified:** V0; V1 — check builds green (78 options); negative test:
|
||||
same script vs the pre-fix README reports exactly the 9 gaps.
|
||||
- **Pending:** slices (b) doc drift pass, (c) install story, (d)
|
||||
recovery runbook.
|
||||
- **Next suggestion:** item 6 slice (b) — or NEXT#8 (viewers+mime) for
|
||||
variety; both fine.
|
||||
|
||||
## 2026-07-04 — Back audit (iteration #12, item 24)
|
||||
- **Task:** BACKLOG NOW#24 — every list menu ends in ↩ Back.
|
||||
- **Did:** audited every `rofi -dmenu` call site in the generated
|
||||
nomarchy-menu + nomarchy-vpn. Already compliant: power, power-profile,
|
||||
theme, clipboard, files, audio, display (both stages), capture,
|
||||
tools, system, VPN main/import/exit-node/tailscale. Fixed: keybinds
|
||||
cheatsheet (Enter was a silent exit) now ends in ↩ Back → root
|
||||
picker. Documented the exceptions in rofi.nix: external modi
|
||||
(calc/emoji/networkmanager_dmenu/rofi-pulse-select) can't take an
|
||||
injected row (Esc = back); free-text prompts (web/ask) have no list.
|
||||
- **Verified:** V0; V1 — built nomarchy-menu, bash -n OK; awk audit
|
||||
over the generated script: only rows lacking back are the root
|
||||
picker (by design) and the free-text prompt. V3 spot-check queued.
|
||||
- **Pending:** V3 spot-check. NOW now holds only item 6 (docs, [big]).
|
||||
- **Next suggestion:** item 6 first slice, or NEXT#8 (viewers+mime).
|
||||
|
||||
## 2026-07-04 — network menu blank rows (iteration #11, item 22)
|
||||
- **Task:** BACKLOG NOW#22 — nameless entries in the network picker.
|
||||
- **Did:** read the pinned networkmanager_dmenu 2.6.2 source: with
|
||||
`compact = False` (our config!) it inserts literal empty rows as
|
||||
section separators (eth/wifi/vpn) — the systematic blank entries.
|
||||
Flipped config.ini to `compact = True` (also unpadded row format,
|
||||
better in rofi's proportional font). Hidden-SSID APs additionally
|
||||
render ONE nameless sec+bars row (dedup keeps one; not config-
|
||||
filterable) — documented, V3-gated, source-patch follow-up if seen.
|
||||
- **Verified:** V0; V1 — rendered config.ini shows compact = True.
|
||||
Behavior needs Wi-Fi hardware → V3 queued.
|
||||
- **Pending:** V3 on the Latitude (no separators; hidden-AP residual?).
|
||||
- **Next suggestion:** item 24 (Back audit) — grep-the-generated-script.
|
||||
|
||||
## 2026-07-04 — waybar/rofi palette-safe pairings (iteration #10, item 27)
|
||||
- **Task:** BACKLOG NOW#27 — generated waybar/rofi CSS invisible on
|
||||
on-surface palettes (flexoki-light runs it; summers whole-swap).
|
||||
- **Did:** waybar.nix generated CSS: module row + #window →
|
||||
alpha(@text, 0.85); inactive workspaces / dnd / pulseaudio.muted →
|
||||
alpha(@text, 0.5) (gruvbox's muted/base was 1.27). rofi.nix: @dim →
|
||||
text+80, @surface → text+1a (#RRGGBBAA fg tints). Contrast check
|
||||
docstring/pairings now cover all three generated surfaces. Status
|
||||
glyphs (good/warn/bad on base, worst 2.05) left as-is — palette
|
||||
design, human call. Generated bar only; whole-swaps untouched.
|
||||
- **Verified:** V0; V1 — checks.theme-contrast green (21 themes),
|
||||
downstream-template-home builds, rendered waybar style has zero
|
||||
@subtext/@muted/@surface, rendered custom.rasi shows fg-derived
|
||||
tints. NOT visually verified — V3 queued (flexoki-light eyeball).
|
||||
- **Pending:** V3 flexoki-light + dark-theme regression spot-check.
|
||||
- **Next suggestion:** item 22 (network menu rows) — V1-actionable.
|
||||
|
||||
## 2026-07-04 — swaync contrast fix + theme-contrast check (iteration #9, item 25)
|
||||
- **Task:** BACKLOG NOW#25 — swaync text invisible on summer-day.
|
||||
- **Did:** swaync.nix now uses only palette-safe pairings: body/summary
|
||||
= @text on @base (worst ratio 5.18 across all 21 themes; subtext/base
|
||||
was 1.00 on summer-day + flexoki-light), hover rows + widget buttons
|
||||
= alpha(@text, 0.1) tints (contrast by construction); dropped the
|
||||
subtext/surface defines. NEW permanent check `checks.theme-contrast`
|
||||
(tools/check-theme-contrast.py) asserts the hex-on-hex text pairings
|
||||
across every theme JSON. Audit found the same mispairing in generated
|
||||
waybar/rofi CSS, live on flexoki-light (no whole-swap) → NOW item 27.
|
||||
- **Verified:** V0; V1 — checks.theme-contrast builds green (21 themes),
|
||||
rendered services.swaync.style contains zero @subtext/@surface.
|
||||
NOT V2/V3-verified visually — queued (Bernardo is at the Latitude).
|
||||
- **Pending:** V3 notify-send readability check on summer-day; item 27.
|
||||
- **Next suggestion:** item 27 (same bug class, waybar/rofi surfaces).
|
||||
|
||||
## 2026-07-04 — SUPER+? bind fix (iteration #8, item 26)
|
||||
- **Task:** BACKLOG NOW#26 — cheatsheet bind never fires on hardware.
|
||||
- **Did:** keybinds.nix: `$mod, question` → `$mod SHIFT, question`
|
||||
(? is Shift+/, Hyprland matches the exact modmask); rofi.nix
|
||||
prettyKeys collapses "SHIFT + ?" → "?" so the row stays SUPER + ?.
|
||||
Gotcha added to MEMORY.md (shifted keysyms need SHIFT in mods).
|
||||
- **Verified:** V0 (flake check --no-build); V1 both surfaces — eval'd
|
||||
hyprland settings.bind renders `$mod SHIFT, question, exec,
|
||||
nomarchy-menu keybinds`, and built nomarchy-menu's cheatsheet file
|
||||
renders `SUPER + ?`. No other shifted keysyms in the bind list.
|
||||
- **Pending:** V3 queued (SUPER+? on the Latitude after home-update +
|
||||
relogin).
|
||||
- **Next suggestion:** item 25 (swaync contrast on summer-day).
|
||||
|
||||
## 2026-07-04 — Latitude hardware sweep #2 (Bernardo; results booked, no code)
|
||||
- **Task:** V3 sweep on the Latitude after pulling ≥18b8545 + reboot.
|
||||
- **PASS:** waybar supervisor (theme switches clean; `pkill -x waybar`
|
||||
respawns instantly); snapshots — themed polkit prompt → GUI as root,
|
||||
fzf fallback works (restore/rollback gate not exercised → residual
|
||||
queued); `sys-rebuild`; night-light enable/disable; auto-commit
|
||||
(theme commits + the toggle self-commit); hibernate single-unlock +
|
||||
suspend-still-locks (1b0eeea CONFIRMED).
|
||||
- **PASS (late confirm):** auto-timezone — `timedatectl` shows
|
||||
Europe/London.
|
||||
- **Bug:** SUPER+? never fires — `$mod, question` misses because a real
|
||||
? carries SHIFT in the modmask → BACKLOG 26 (bind-only: the menu
|
||||
itself opens fine from a terminal). SUPER+SHIFT+K no-op was the
|
||||
comma-layout gate working (none configured) — retest queued.
|
||||
- **Next suggestion:** item 25 (swaync contrast) or 26 (cheatsheet bind).
|
||||
|
||||
## 2026-07-04 — Waybar resilience + sys-rebuild (iteration #7, items 21+23)
|
||||
- **Task:** the two top Latitude findings.
|
||||
- **Did:** (21) `nomarchy-waybar` supervisor (waybar.nix, exec-once'd
|
||||
from hyprland.nix): ANY waybar exit respawns, crash-loop guard (5
|
||||
fast exits → critical notify + stop), TERM trap for a real stop.
|
||||
theme-sync now prefers a clean `pkill -x waybar` when the supervisor
|
||||
is running (restart with fresh config+style — avoids waybar's
|
||||
in-place SIGUSR2 reload entirely, the suspected double-reload race
|
||||
with reload_style_on_change during symlink flips); SIGUSR2 stays as
|
||||
the unsupervised fallback; reload_style_on_change kept for manual
|
||||
home-update restyles. (23) `sys-rebuild` — snapshot-first rebuild
|
||||
against the current lock, no `nix flake update`; README §3/§5 + motd.
|
||||
- **Verified:** V0; V1 (HM renders `exec-once=nomarchy-waybar`,
|
||||
supervisor bash -n; `sys-rebuild` in systemPackages). V2: headless
|
||||
software-GL desktop VM (recipe from memory — gotchas hit: node needs
|
||||
the overlay, users.users.<u>, useGlobalPkgs) — SIGKILL→new pid, clean
|
||||
kill→respawn, SIGUSR2→alive. Result recorded below once green.
|
||||
- **Pending:** V3 on the Latitude: theme switch survives / bar returns.
|
||||
- **Next suggestion:** item 22 (network menu rows) or 24 (Back audit).
|
||||
|
||||
## 2026-07-04 — Keyboard cycle bind + parity (iteration #6) + Latitude triage
|
||||
- **Task:** BACKLOG NOW#5; mid-iteration Bernardo delivered Latitude
|
||||
5410 hardware-QA findings (the machine got a real session!).
|
||||
- **Did:** `multiLayoutBinds` in keybinds.nix (SUPER+SHIFT+K →
|
||||
`switchxkblayout current next`), gated in hyprland.nix AND the rofi
|
||||
cheatsheet on the same comma-in-layout condition; `hyprland/language`
|
||||
+ `#language` CSS added to both summer whole-swaps (shows even
|
||||
single-layout there — static JSON can't gate; deliberate). Reverse
|
||||
parity gap found (summer-night has idle_inhibitor, generated bar
|
||||
doesn't) → folded into item 13. **Triage:** four new NOW items from
|
||||
hardware: #21 Waybar crash on theme switch + no respawn (top),
|
||||
#22 nameless network-menu entries, #23 `sys-rebuild` (no-update
|
||||
rebuild), #24 Back-everywhere audit.
|
||||
- **Verified:** V0 (JSON + flake check) + V1 both directions
|
||||
(single-layout build: no bind; `us,de` via extendModules: bind + the
|
||||
cheatsheet row render; summer JSONs parse).
|
||||
- **Pending:** V3 cycle-bind check queued; items 21/22/24 carry V3
|
||||
re-checks on the Latitude.
|
||||
- **Next suggestion:** #21 (waybar crash — stability pillar, user-hit).
|
||||
|
||||
## 2026-07-04 — Webcam follow-ups (loop iteration #5, quick item)
|
||||
- **Task:** BACKLOG NOW#7 (Bernardo asked for "a quick item").
|
||||
- **Did:** template `home.packages` gains a commented "Webcam tuning"
|
||||
pair (cameractrls GUI, v4l-utils CLI — bare packages, so template not
|
||||
toggle, per the option-surface rule); the portal/Flatpak libcamera IR
|
||||
gap is written up as a PROPOSED item with three options (recommend:
|
||||
document-only now, libcamera-rule investigation when the T14s is
|
||||
available). CI runs #60/#61 confirmed green (earlyoom + snapshot fix).
|
||||
- **Verified:** V0 (flake check — template evals through mkFlake;
|
||||
changes are comments + agent docs).
|
||||
- **Next suggestion:** NOW#5 (keyboard cycle bind + summer parity) —
|
||||
the last code item in NOW besides the docs pass.
|
||||
|
||||
## 2026-07-04 — Snapshot GUI un-broken + polkit agent (loop iteration #4)
|
||||
- **Task:** BACKLOG NOW#4 — btrfs-assistant segfault.
|
||||
- **Did:** re-diagnosed instead of overriding. gdb: crash is in
|
||||
libbtrfsutil's *unprivileged* subvolume iteration (btrfs-progs 6.17.1;
|
||||
upstream fix `886571653` post-6.17.1; symbol versions verified — not
|
||||
ABI drift). VM A/B: root works (exit 0), user crashes (139). The
|
||||
launcher runs it as root → GUI fine *if* pkexec can prompt — and the
|
||||
distro shipped **no polkit agent** (all pkexec silently failed; the
|
||||
actual root cause of "GUI is dead"). Shipped: hyprpolkitagent
|
||||
(exec-once, Stylix-themed Qt), menu re-pointed to the launcher with
|
||||
the fzf flow as fallback, `checks.snapshot-gui` canary (root path +
|
||||
offscreen event loop on real btrfs). No btrfs-progs patch — root-side
|
||||
flows don't hit the bug; the fix arrives with a lock bump.
|
||||
- **Verified:** V0 + V2 (snapshot-gui check, run for real) + V1 (HM
|
||||
generation renders the agent exec-once; menu bash -n).
|
||||
- **Pending:** V3 queued — first on-hardware themed polkit prompt.
|
||||
- **Next suggestion:** NOW#5 (keyboard cycle bind + summer parity).
|
||||
|
||||
## 2026-07-04 — CI is green (run #58) — item 20 main half closed
|
||||
- **Task:** monitor follow-up, no code. Run #58 (the .gitea path fix)
|
||||
**succeeded** — first green CI: the container recipe works on the
|
||||
live runner, eval tier confirmed end to end.
|
||||
- **Did:** BACKLOG item 20 reduced to its stretch (KVM runner → enable
|
||||
vm-checks), moved to NEXT. Run #59 (earlyoom push) monitored.
|
||||
- **Next suggestion:** NOW#4 (btrfs-assistant override attempt).
|
||||
|
||||
## 2026-07-04 — Memory-pressure protection shipped (loop iteration #3)
|
||||
- **Task:** BACKLOG NOW#3 — default-on userspace OOM killer.
|
||||
- **Did:** `modules/nixos/oom.nix`: earlyoom (mkDefault on, desktop
|
||||
notifications, session-plumbing `--avoid` list, no `--prefer`) +
|
||||
`systemd.oomd.enable = false`. Choice rationale: Hyprland session is
|
||||
one cgroup scope → oomd's cgroup-level kill would nuke the desktop;
|
||||
earlyoom is process-level. Found en route: nixpkgs default-enables
|
||||
oomd *inert* (enable=true, all slice toggles false). README "beyond
|
||||
the surface" note added.
|
||||
- **Verified:** V0 (flake check) + **V2** — new `checks.oom-protection`
|
||||
runNixOSTest, run for real: hog (chunked allocator, 686 MB peak in a
|
||||
1 GB VM) SIGTERM'd by earlyoom in 0.1 s, bystander unit survived,
|
||||
oomd asserted inactive. 25 s test, cheap enough for the suite.
|
||||
- **Pending:** nothing hardware-specific (behavior fully VM-provable).
|
||||
- **Next suggestion:** NOW#4 (btrfs-assistant override attempt). Also:
|
||||
CI run #58 (the .gitea fix) was *running* at commit time — check its
|
||||
outcome next tick; this push triggers #59.
|
||||
|
||||
## 2026-07-04 — CI fix: wrong workflow dir (correction to iteration #2)
|
||||
- **Task:** Bernardo reported no run despite an active runner + shared
|
||||
his compose file: the server is **Gitea** (gitea/act_runner), not
|
||||
Forgejo — I'd shipped the workflow to `.forgejo/workflows/`, which
|
||||
Gitea never reads. The legacy repo's `.gitea/workflows/` path was the
|
||||
clue I under-weighted.
|
||||
- **Did:** `git mv` → `.gitea/workflows/check.yml`; corrected the
|
||||
Forgejo references in the workflow header, TESTING.md §1b, BACKLOG
|
||||
item 20 (now: watch the first run; runner was never the problem);
|
||||
MEMORY.md gains the Gitea-not-Forgejo line.
|
||||
- **Verified:** the push of this commit is itself the test — the run
|
||||
must appear; monitoring.
|
||||
- **Pending:** first green run (item 20); runner-container memory
|
||||
headroom is the watch-out.
|
||||
|
||||
## 2026-07-04 — CI checks-on-push shipped (loop iteration #2)
|
||||
- **Task:** BACKLOG NOW#2 — Forgejo Actions workflow.
|
||||
- **Did:** `.forgejo/workflows/check.yml` (push to main/v1 + dispatch):
|
||||
flake check --no-build, theme-sync py_compile, bash -n over tracked
|
||||
.sh. Scoped to the **eval tier** deliberately — API probing +
|
||||
archaeology of the legacy `.gitea/workflows/check.yml` (57 runs on
|
||||
this instance) showed the runner is an act_runner docker container
|
||||
(no KVM/systemd), so the VM suite can't run there; a commented
|
||||
`vm-checks` job documents the KVM-runner upgrade path. Legacy's
|
||||
hard-won container gotchas (nixbld setup, sandbox=false for Stylix
|
||||
IFD, Nix 2.31.5 pin) carried over verbatim. TESTING.md §1b added.
|
||||
- **Verified:** V0 locally (same commands the workflow runs, minus the
|
||||
container Nix install) + yq YAML parse. The real green run needs the
|
||||
runner to be alive — **not confirmable from here** (runners API is
|
||||
401 unauthenticated); watching the run after push.
|
||||
- **Pending:** new `[human]` item 20 — confirm/re-register the runner;
|
||||
stretch: a KVM runner unlocks the vm-checks job.
|
||||
- **Next suggestion:** NOW#3 (memory-pressure protection).
|
||||
|
||||
## 2026-07-04 — Opt-in auto-commit shipped (loop iteration #1)
|
||||
- **Task:** BACKLOG NOW#1 — auto-commit of state mutations (in-flake
|
||||
state Phase 4). First autonomous /loop iteration.
|
||||
- **Did:** `settings.autoCommit` live-read by nomarchy-theme-sync;
|
||||
pathspec-limited commit of theme-state.json on apply/set (fires if flag
|
||||
on before OR after the write → the off-toggle commits too); identity
|
||||
fallback; same-value no-op; `bg` excluded. Menu: System › Auto-commit
|
||||
(instant, self-gated on `.git`). Rider: `get` prints booleans as JSON
|
||||
`true`/`false`, fixing the stuck "Auto timezone (on/off)" menu label.
|
||||
BACKLOG numbering switched to stable IDs (no renumbering).
|
||||
- **Verified:** V0 (py_compile, flake check) + V1 (HM generation builds;
|
||||
generated menu `bash -n`) + a 7-assertion sandbox git-repo round-trip
|
||||
(enable/set/same-value/disable/post-disable/apply/identity-fallback).
|
||||
- **Pending:** V3 queued in HARDWARE-QUEUE (on-machine toggle + apply).
|
||||
- **Next suggestion:** NOW#2 (CI checks-on-push) — but its runner half
|
||||
may need Bernardo to register a Forgejo runner; deliver the workflow
|
||||
regardless.
|
||||
|
||||
## 2026-07-04 — Backlog revision pass (human-requested)
|
||||
- **Task:** Bernardo asked for a philosophy-aligned revision of BACKLOG.md
|
||||
("I'm sure I'm forgetting important items").
|
||||
- **Did:** verified guessed gaps against the tree first (GC/optimise/boot
|
||||
limit + all 21 previews already ship — dropped those ideas). Added the
|
||||
confirmed gaps: CI-on-push promoted to NOW#2 (agents push to main now),
|
||||
memory-pressure protection NOW#3 (nothing mitigates OOM; the release
|
||||
bump died to one), viewers+mime defaults #8, update/rollback UX #9,
|
||||
nomarchy-doctor #10, state-file validation #11, screen recording #12,
|
||||
niceties batch #13 (idle-inhibit, low-battery notify, hyprpicker), OCR
|
||||
in LATER; recovery runbook folded into the docs item; zram + default
|
||||
browser added to Decisions.
|
||||
- **Verified:** V0 (docs-only).
|
||||
- **Pending:** Bernardo to sanity-check the new NOW ordering, esp. CI at
|
||||
#2 and the two new Decisions.
|
||||
- **Next suggestion:** unchanged — NOW#1 (opt-in auto-commit).
|
||||
|
||||
## 2026-07-04 — Bootstrap the loop infrastructure (this commit)
|
||||
- **Task:** create `agent/` (human-requested): LOOP/GOALS/BACKLOG/
|
||||
CONVENTIONS/MEMORY/HARDWARE-QUEUE/JOURNAL, root CLAUDE.md, README +
|
||||
ROADMAP pointers.
|
||||
- **Did:** reworked the forward half of docs/ROADMAP.md into the tiered
|
||||
BACKLOG (5 NOW / 6 NEXT / LATER / Decisions); collected every pending
|
||||
on-hardware check into HARDWARE-QUEUE.md; seeded MEMORY.md from the
|
||||
ROADMAP's decision records.
|
||||
- **Verified:** V0 (docs-only change; `nix flake check --no-build` run to
|
||||
confirm the tree still evaluates).
|
||||
- **Pending:** Bernardo to sanity-read GOALS.md pillars + BACKLOG tiering
|
||||
— reorder freely, the order *is* the instruction.
|
||||
- **Next suggestion:** BACKLOG NOW#1 (opt-in auto-commit — Phase 4 of
|
||||
in-flake state, already the agreed next step).
|
||||
147
agent/LOOP.md
Normal file
147
agent/LOOP.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# The loop — autonomous iteration protocol
|
||||
|
||||
How an AI agent works on Nomarchy unattended. One **iteration** = pick one
|
||||
task, do it, verify it, commit it, record it. The protocol is
|
||||
runner-agnostic; the same iteration works under any of:
|
||||
|
||||
- **Interactive `/loop`** in a Claude Code session in this repo — the agent
|
||||
self-paces iterations until stopped.
|
||||
- **Headless** (`claude -p`, cron/systemd-timer) — one invocation runs one
|
||||
iteration (or a small fixed number) and exits.
|
||||
- **A fresh manual session** — a human says "do a loop iteration"; the
|
||||
files below carry all the state, so any session can pick up where the
|
||||
last left off.
|
||||
|
||||
All loop state lives in this directory, git-tracked. There is no state
|
||||
outside the checkout (the distro's own philosophy, applied to its agents).
|
||||
|
||||
## The files
|
||||
|
||||
| File | Role | Who writes it |
|
||||
|---|---|---|
|
||||
| `GOALS.md` | North star + quality bars + non-goals | Human (agents propose edits) |
|
||||
| `BACKLOG.md` | Prioritized task queue (NOW/NEXT/LATER/PROPOSED/DECISIONS) | Both — see its header rules |
|
||||
| `JOURNAL.md` | Append-only iteration log | Agents |
|
||||
| `MEMORY.md` | Curated durable lessons/gotchas | Agents (curated, not append-only) |
|
||||
| `HARDWARE-QUEUE.md` | Pending on-hardware checks only Bernardo can run | Agents append, human checks off |
|
||||
| `CONVENTIONS.md` | Repo/design conventions to follow while coding | Human (agents propose edits) |
|
||||
|
||||
## Model & token economy
|
||||
|
||||
Spend expensive tokens on judgment, not mechanics.
|
||||
|
||||
- **Plan and reason on the strong model.** Orientation, task selection,
|
||||
design, debugging, Nix eval semantics, verification judgment, and
|
||||
anything that would land in a commit unreviewed stay with the
|
||||
top-tier model running the loop (Fable 5).
|
||||
- **Delegate mechanical subtasks to cheaper models.** When a subtask is
|
||||
fully specified and needs no design judgment — grep/audit sweeps,
|
||||
README-option-table reconciliation, a repeated edit applied across
|
||||
files, summarizing long logs or check output — hand it to a subagent
|
||||
with a `model` override: `haiku` for search/summarize/audit, `sonnet`
|
||||
for routine well-specified edits. The strong model writes the spec,
|
||||
reviews the result, and owns the commit. Only delegate when writing
|
||||
the spec is cheaper than doing the work — a spawned agent starts cold
|
||||
and must re-derive context.
|
||||
- **Read narrowly.** Step 0's list is the whole orientation read (the
|
||||
*last 3–5 entries* of the journal, never the full file). Read large
|
||||
files by section, don't re-read what's already in context, and tail
|
||||
build/check logs instead of dumping them.
|
||||
- **Write tersely.** Journal entries follow the template and no more;
|
||||
commit bodies state what/why/tier, not a narrative.
|
||||
- **Headless runners** may run whole low-stakes iterations (QA sweeps,
|
||||
docs-drift passes) on a cheaper `--model`; iterations touching
|
||||
`modules/` or `pkgs/` behavior keep the strong model.
|
||||
|
||||
## One iteration, step by step
|
||||
|
||||
### 0. Orient
|
||||
1. Read `GOALS.md`, `CONVENTIONS.md`, `MEMORY.md`, the **last 3–5 entries**
|
||||
of `JOURNAL.md`, and `BACKLOG.md`.
|
||||
2. `git pull --ff-only` (skip silently if offline). Confirm you are on
|
||||
`main` with a clean tree. **A dirty tree you didn't create → stop and
|
||||
report; never stash or discard someone else's work.**
|
||||
3. Sanity baseline: if the last journal entry reports a red
|
||||
`nix flake check`, or you have any reason to suspect breakage, run
|
||||
`nix flake check --no-build` first. **A red baseline preempts the
|
||||
backlog — fixing it *is* this iteration's task.**
|
||||
|
||||
### 1. Pick exactly one task
|
||||
- Take the **topmost actionable** item: NOW before NEXT; never LATER
|
||||
unless NOW and NEXT are empty or all blocked.
|
||||
- *Actionable* means: not `[blocked:hw]` (those wait in
|
||||
`HARDWARE-QUEUE.md`), not `[human]` (decisions), and small enough to
|
||||
finish + verify in one iteration. If the top item is too big, **split
|
||||
it in BACKLOG.md** (that edit is part of the iteration) and take the
|
||||
first slice.
|
||||
- Never implement anything from **PROPOSED** — those await human triage.
|
||||
- If nothing is actionable, do a **QA sweep** instead: run the full check
|
||||
suite, hunt drift (README option tables vs the live `nomarchy.*`
|
||||
surface, template drift, dead code), deepen a VM test, or research and
|
||||
write up a PROPOSED item. An iteration that only improves the backlog
|
||||
is a valid iteration. If even that yields nothing, journal it and stop
|
||||
— do not manufacture churn.
|
||||
|
||||
### 2. Work
|
||||
- Keep the diff focused on the task. Unrelated fixes you trip over become
|
||||
PROPOSED/NOW entries, not scope creep.
|
||||
- Mechanical, fully-specified sub-steps go to a cheaper model
|
||||
(see *Model & token economy* above); design and review stay here.
|
||||
- Follow `CONVENTIONS.md`. Match the surrounding hand-formatting; never
|
||||
run a formatter.
|
||||
- New gotcha discovered the hard way → one line in `MEMORY.md` now, while
|
||||
it's fresh.
|
||||
|
||||
### 3. Verify — the ladder
|
||||
Climb as high as the change warrants and your environment allows; **record
|
||||
the tier reached** in the commit body and journal entry.
|
||||
|
||||
| Tier | What | When required |
|
||||
|---|---|---|
|
||||
| **V0** | `nix flake check --no-build` (+ `bash -n` / `py_compile` for scripts) | Every change, no exceptions |
|
||||
| **V1** | Build the touched output: `system.build.toplevel`, the HM generation, the ISO, or the package | Anything beyond docs/comments |
|
||||
| **V2** | VM: a `checks.*` runNixOSTest (add one if the change is guardable), or boot `tools/test-live-iso.sh` / `tools/test-install.sh` | Behavioral changes — services, boot, installer, session |
|
||||
| **V3** | Real hardware | Cannot be done by the agent → append to `HARDWARE-QUEUE.md` with exact test steps |
|
||||
|
||||
The honesty rule governs: a visual/interactive change verified only to V1
|
||||
is **not done** — it ships as "V1-verified, V2/V3 pending" with the pending
|
||||
check queued. Prefer *adding a permanent `checks.*` test* over a one-off
|
||||
manual VM poke when the behavior is testable headlessly (see MEMORY.md for
|
||||
the reusable recipes).
|
||||
|
||||
### 4. Commit + push
|
||||
- Style: match the log — `feat(scope): …`, `fix(scope): …`,
|
||||
`test(scope): …`, `docs(scope): …`. Body explains what/why + the
|
||||
verification tier reached and what remains.
|
||||
- Include the `agent/` bookkeeping updates (backlog/journal/memory/queue)
|
||||
**in the same commit** as the change they describe.
|
||||
- Commit directly on `main` and `git push` (Bernardo's standing workflow).
|
||||
- **Never:** force-push; touch the `v1` branch or any branch/tag you
|
||||
didn't create; commit secrets or binaries; run `nix flake update`
|
||||
unless the task is explicitly a lock bump; delete themes, wallpapers,
|
||||
or user-facing assets without the backlog saying so.
|
||||
|
||||
### 5. Record
|
||||
1. Mark the task in `BACKLOG.md` (move to its ✓ line or delete, per that
|
||||
file's rules).
|
||||
2. Append a `JOURNAL.md` entry (template in that file).
|
||||
3. Queue any V3 checks in `HARDWARE-QUEUE.md`.
|
||||
|
||||
### 6. Pace (self-paced runners only)
|
||||
Under `/loop`, continue to the next iteration while tasks remain
|
||||
actionable and checks stay green. Stop the loop when: nothing is
|
||||
actionable, the same task has failed twice (journal the failure analysis
|
||||
and mark the item `[stuck]`), or a `[human]` decision blocks everything
|
||||
remaining.
|
||||
|
||||
## Stop-and-escalate conditions (any runner)
|
||||
|
||||
Write a journal entry + a BACKLOG note, then stop, when:
|
||||
- A fix would require touching `v1`, force-pushing, or a nixpkgs release
|
||||
jump.
|
||||
- The working tree contains uncommitted work you didn't create.
|
||||
- A task turns out to need a design decision Bernardo hasn't made → move
|
||||
it to **Decisions** in BACKLOG.md with the options laid out.
|
||||
- Two consecutive iterations failed on the same task (`[stuck]`).
|
||||
- Anything would delete or rewrite user data, git history, or the state
|
||||
file schema in a non-backward-compatible way.
|
||||
97
agent/MEMORY.md
Normal file
97
agent/MEMORY.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Memory — durable lessons, learned the hard way
|
||||
|
||||
Curated, not append-only: one line per fact, newest at the top of its
|
||||
section; delete entries that stop being true. Details usually live in a
|
||||
docs/ROADMAP.md decision record — pointer given as (§ item). Add a fact
|
||||
here the moment a debugging session teaches you something a future
|
||||
iteration would otherwise rediscover.
|
||||
|
||||
## Testing & VM recipes
|
||||
- **tuigreet dies silently under runNixOSTest** (even bare, no theme
|
||||
flag: greetd sits as "(greetd)" with no child, nothing in the
|
||||
journal — its stderr goes to the VT) — nixpkgs' own greetd test uses
|
||||
agreety instead. Greeter *rendering* is interactive-ISO/hardware
|
||||
tier; don't burn another session on a checks.greeter VM test.
|
||||
- In VM tests `pgrep -f PATTERN` can match the test backdoor's own
|
||||
`bash -c` wrapper (the pattern is in its cmdline) — use `pgrep -x`
|
||||
or a `[t]uigreet`-style bracket pattern.
|
||||
- A checks.* fixture CANNOT be a writeText/toFile state file read at
|
||||
eval time ("path … is not valid" — flake check's eval store won't
|
||||
realise it): extract the logic into a pure importable file and
|
||||
unit-test THAT (monitor-rules.nix / checks.display-profiles is the
|
||||
pattern).
|
||||
- CI (`.gitea/workflows/check.yml`) is **eval-tier only**: the act_runner
|
||||
is a docker container (no systemd, no /dev/kvm). Container gotchas are
|
||||
documented in the workflow header (single-user Nix + nixbld users,
|
||||
`sandbox=false` for Stylix IFD, Nix pinned 2.31.5 vs lazy-trees, no JS
|
||||
actions past node20) — learned over the legacy repo's 57 runs; read
|
||||
them before touching the workflow.
|
||||
- The Gitea instance is **1.25.4** — `on: schedule` workflows are
|
||||
supported; bump.yml assumes the Actions token can push to `main`
|
||||
(standard Gitea behaviour, but unconfirmed until the first run lands).
|
||||
- The git server is **Gitea** (gitea/act_runner via docker-compose), NOT
|
||||
Forgejo — workflows are read from `.gitea/workflows/` (or `.github/`),
|
||||
never `.forgejo/workflows/` (a whole push cycle was lost to that).
|
||||
- Reusable headless VM harness: `checks.*` via runNixOSTest — existing
|
||||
examples to crib from: `distro-id` (boots + `switch-to-configuration
|
||||
dry-activate`), `hardware-toggles` (kernel cmdline/PAM assertions),
|
||||
`battery-charge-limit` (fake Mains adapter via `test_power`, real udev
|
||||
uevent, `InvocationID` change proves the restart).
|
||||
- Themed-desktop screenshots work headlessly: software-GL Hyprland
|
||||
(`LIBGL_ALWAYS_SOFTWARE` on virtio-gpu) + `machine.screenshot()` QMP
|
||||
dump — prototyped 2026-06-19, kept as the fallback for theme previews
|
||||
(§ Visual theme picker).
|
||||
- Hyprland/Ghostty need guest GL (`virtio-vga-gl`, `gl=on`) in
|
||||
interactive QEMU or the session won't start; black screen ≈ missing GL
|
||||
(docs/TESTING.md § gotchas).
|
||||
- No KVM = slow, not broken; don't read slowness as failure.
|
||||
|
||||
## Known-broken / watchlist
|
||||
- **btrfs-assistant "segfault" was unprivileged-only** (re-diagnosed
|
||||
2026-07-04): libbtrfsutil's unprivileged subvolume iteration crashes on
|
||||
btrfs-progs 6.17.1 (upstream-fixed after); **as root it works**, and the
|
||||
pkexec launcher runs it as root. The real distro bug was **no polkit
|
||||
agent in the session** (every pkexec failed silently) — hyprpolkitagent
|
||||
now ships (hyprland.nix exec-once). `checks.snapshot-gui` guards the
|
||||
root path. Lesson: before "app X is broken", check WHO it runs as — and
|
||||
whether polkit prompts can render at all (§ Snapshot browse/restore).
|
||||
- **NixOS release bump is a trap:** the discarded attempt
|
||||
(branch deleted 2026-06-22) hit a Hyprland OOM blocker; a redo is a
|
||||
deliberate `v2`, never part of routine lock bumps.
|
||||
- `theme-state.json` is git-tracked inside an 86 MB flake tree, so every
|
||||
state write re-copies the source before eval — the wallpapers-artifact
|
||||
split (BACKLOG LATER) is the decided fix (§ Faster switches).
|
||||
|
||||
## Gotchas (cost a debugging session once)
|
||||
- Hyprland binds match the exact modmask: a shifted keysym (`question`)
|
||||
needs SHIFT in `mods` or the bind never fires — the keypress falls
|
||||
through to the focused window (§ item 26; caught on hardware, invisible
|
||||
to eval-tier tests).
|
||||
- Never kill a Wayland session-lock client (hyprlock): its crash
|
||||
failsafe drops to a tty instead of unlocking (§ Hibernate
|
||||
double-unlock).
|
||||
- rofi `element-icon size` is one value = a square cell; `WxH` silently
|
||||
collapses and non-square icons letterbox — pre-crop images square at
|
||||
build (§ Visual theme picker).
|
||||
- WirePlumber 0.5 monitor rules can only early-match `device.api`;
|
||||
`device.product.name` etc. bind *after* the rule runs — surgical
|
||||
libcamera scoping is impossible (§ Webcam).
|
||||
- `hyprctl switchxkblayout` is a *global* layout flip; per-device isolation
|
||||
needs `device[<name>]:kb_layout` keywords (§ Keyboard layouts).
|
||||
- Waybar's clock captures the timezone at construction — a zone change
|
||||
needs SIGUSR2 (watcher in `timezone.nix`) (§ Automatic timezone).
|
||||
- Waybar `persistent_workspaces` (underscore) is dead syntax silently
|
||||
ignored; the hyphen form is honoured and renders phantom workspaces
|
||||
(§ Waybar shows non-existent workspaces).
|
||||
- GTK4/libadwaita/Qt6 read light/dark from the portal's
|
||||
`org.freedesktop.appearance color-scheme` (dconf), not Stylix polarity
|
||||
(§ GTK/Qt ignore the theme's mode).
|
||||
- Update order matters downstream: `sys-update` (lock) before
|
||||
`home-update`, or desktop changes are silently skipped against the old
|
||||
lock (README § 3).
|
||||
- grub `loadfont`s every `.pf2` in a theme dir — reuse a bundled DejaVu
|
||||
rather than shipping fonts (§ Distro branding).
|
||||
- The Claude Code harness drops machine-local files into the repo
|
||||
(`.claude/skills/…`) mid-session — never `git add -A` blindly; check
|
||||
`git status --short` for strangers first (they're gitignored now, but
|
||||
the next surprise won't be) (§ loop hygiene).
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# nomarchy-docs-keybindings
|
||||
#
|
||||
# Regenerates docs/KEYBINDINGS.md from the Hyprland binding files. Run from the
|
||||
# repo root or anywhere — paths are resolved relative to this script.
|
||||
#
|
||||
# nomarchy-docs-keybindings # write to stdout
|
||||
# nomarchy-docs-keybindings --out docs/KEYBINDINGS.md
|
||||
#
|
||||
# Source files in render order. Each entry is "<repo-relative path>|<title>".
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
|
||||
sources=(
|
||||
"core/home/config/nomarchy/default/hypr/bindings/utilities.conf|Utilities"
|
||||
"core/home/config/nomarchy/default/hypr/bindings/tiling-v2.conf|Tiling"
|
||||
"core/home/config/nomarchy/default/hypr/bindings/clipboard.conf|Clipboard"
|
||||
"core/home/config/nomarchy/default/hypr/bindings/media.conf|Media keys"
|
||||
"features/desktop/hyprland/config/bindings.conf|Apps & web shortcuts"
|
||||
)
|
||||
|
||||
prettify_key() {
|
||||
case "$1" in
|
||||
code:10) echo "1" ;; code:11) echo "2" ;; code:12) echo "3" ;;
|
||||
code:13) echo "4" ;; code:14) echo "5" ;; code:15) echo "6" ;;
|
||||
code:16) echo "7" ;; code:17) echo "8" ;; code:18) echo "9" ;;
|
||||
code:19) echo "0" ;;
|
||||
XF86AudioRaiseVolume) echo "Volume Up" ;;
|
||||
XF86AudioLowerVolume) echo "Volume Down" ;;
|
||||
XF86AudioMute) echo "Mute" ;;
|
||||
XF86AudioMicMute) echo "Mic Mute" ;;
|
||||
XF86AudioPlay) echo "Play/Pause" ;;
|
||||
XF86AudioStop) echo "Stop" ;;
|
||||
XF86AudioNext) echo "Next Track" ;;
|
||||
XF86AudioPrev) echo "Previous Track" ;;
|
||||
XF86MonBrightnessUp) echo "Brightness Up" ;;
|
||||
XF86MonBrightnessDown) echo "Brightness Down" ;;
|
||||
XF86KbdBrightnessUp) echo "Kbd Brightness Up" ;;
|
||||
XF86KbdBrightnessDown) echo "Kbd Brightness Down" ;;
|
||||
XF86KbdLightOnOff) echo "Kbd Backlight" ;;
|
||||
*) echo "$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
trim() { sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//'; }
|
||||
|
||||
render_section() {
|
||||
local file="$1" title="$2"
|
||||
[[ ! -f "$repo_root/$file" ]] && return
|
||||
local rows
|
||||
rows=$(grep -E '^[[:space:]]*bind[a-z]*[[:space:]]*=' "$repo_root/$file" || true)
|
||||
[[ -z "$rows" ]] && return
|
||||
|
||||
local body=""
|
||||
while IFS= read -r line; do
|
||||
# Strip the "bindXXX =" prefix.
|
||||
local rhs="${line#*=}"
|
||||
local mods key desc
|
||||
IFS=',' read -r mods key desc _ <<<"$rhs"
|
||||
mods=$(printf '%s' "${mods:-}" | trim)
|
||||
key=$(printf '%s' "${key:-}" | trim)
|
||||
desc=$(printf '%s' "${desc:-}" | trim)
|
||||
[[ -z "$desc" ]] && continue # skip non-descriptive bindings
|
||||
[[ -z "$mods" ]] && mods="—"
|
||||
key=$(prettify_key "$key")
|
||||
body+=$(printf '| %s | %s | %s |\n' "$mods" "$key" "$desc")
|
||||
body+=$'\n'
|
||||
done <<<"$rows"
|
||||
|
||||
[[ -z "$body" ]] && return
|
||||
|
||||
printf '\n## %s\n\n' "$title"
|
||||
printf '_Source: `%s`_\n\n' "$file"
|
||||
printf '| Modifiers | Key | Action |\n'
|
||||
printf '| --- | --- | --- |\n'
|
||||
printf '%s' "$body"
|
||||
}
|
||||
|
||||
main() {
|
||||
cat <<'HEADER'
|
||||
# Nomarchy Keybindings
|
||||
|
||||
Auto-generated from the Hyprland binding files. **Do not edit by hand.**
|
||||
Re-run the generator after changing any `bindings/*.conf`:
|
||||
|
||||
```bash
|
||||
./bin/utils/nomarchy-docs-keybindings --out docs/KEYBINDINGS.md
|
||||
```
|
||||
|
||||
`SUPER` is the Meta / Win key. `code:NN` keys (X11 digit keycodes) are
|
||||
shown as the digit they correspond to. Media keys (`XF86Audio*`,
|
||||
`XF86MonBrightness*`, …) are prettified.
|
||||
HEADER
|
||||
for entry in "${sources[@]}"; do
|
||||
render_section "${entry%|*}" "${entry#*|}"
|
||||
done
|
||||
}
|
||||
|
||||
out=""
|
||||
if [[ "${1:-}" == "--out" ]]; then
|
||||
out="${2:?--out needs a path}"; shift 2
|
||||
fi
|
||||
if [[ -n "$out" ]]; then
|
||||
main >"$out"
|
||||
else
|
||||
main
|
||||
fi
|
||||
@@ -1,288 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Generator tolerates "no matches" exit codes from grep | sort.
|
||||
# pipefail and -e off; -u stays.
|
||||
set -u
|
||||
|
||||
# Deterministic collation regardless of the caller's locale. Without this
|
||||
# `sort` orders rows and caller lists by the ambient LC_COLLATE (UTF-8 on a
|
||||
# dev box, C in the CI container), so the committed doc and CI's regenerated
|
||||
# copy disagree on ordering and the drift check fails on pure noise.
|
||||
export LC_ALL=C
|
||||
|
||||
# nomarchy-docs-scripts
|
||||
#
|
||||
# Regenerates docs/SCRIPTS.md from the repo state. Produces:
|
||||
# 1. Header + status legend + regen instructions.
|
||||
# 2. Table of every nomarchy-* script (location, callers, status).
|
||||
# 3. Table of every menu entry in features/scripts/utils/nomarchy-menu
|
||||
# (submenu, label, target command, status).
|
||||
# 4. Snapshot list of orphaned references (called somewhere, no script).
|
||||
#
|
||||
# Status heuristic in Phase A:
|
||||
# kept — file exists AND is called from at least one *.nix / *.conf /
|
||||
# shell file outside its own directory.
|
||||
# unused? — file exists but no caller found. Phase B decides delete-dead
|
||||
# vs intentional public API.
|
||||
# missing — referenced but no file. Phase B decides port-from-omarchy
|
||||
# vs delete-dead vs stub-with-notify.
|
||||
#
|
||||
# nomarchy-docs-scripts # write to stdout
|
||||
# nomarchy-docs-scripts --out docs/SCRIPTS.md
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$repo_root"
|
||||
|
||||
# --- Inventory -------------------------------------------------------------
|
||||
|
||||
# Where scripts live, in render order.
|
||||
declare -A loc_label=(
|
||||
["features/scripts/utils"]="features/scripts/utils"
|
||||
["core/system/scripts"]="core/system/scripts"
|
||||
["themes/engine/scripts"]="themes/engine/scripts"
|
||||
)
|
||||
script_dirs=(features/scripts/utils core/system/scripts themes/engine/scripts)
|
||||
|
||||
# Build name → location map (associative array of basename → repo-relative dir).
|
||||
declare -A script_loc
|
||||
for dir in "${script_dirs[@]}"; do
|
||||
[[ -d "$dir" ]] || continue
|
||||
while IFS= read -r f; do
|
||||
script_loc["$(basename "$f")"]="$dir"
|
||||
done < <(find "$dir" -maxdepth 1 -type f -name 'nomarchy-*')
|
||||
done
|
||||
|
||||
# Find every nomarchy-* token referenced anywhere outside the script dirs.
|
||||
# (We exclude the script files themselves so they don't list themselves as
|
||||
# their own caller.)
|
||||
# File types we search for references. *.md catches docs and README;
|
||||
# branding/hook/extension files have varied or no extensions.
|
||||
# *.lua catches elephant providers; *.ini catches mako on-button-* hooks;
|
||||
# *.desktop catches MimeType-registered URL handlers.
|
||||
grep_includes=(
|
||||
--include='*.nix' --include='*.conf' --include='*.sh' --include='*.md'
|
||||
--include='nomarchy-*' --include='*.jsonc' --include='*.json'
|
||||
--include='*.toml' --include='*.ini' --include='*.lua'
|
||||
--include='*.desktop' --include='*.txt' --include='*.sample'
|
||||
)
|
||||
search_dirs=(core features themes installer hosts bin lib README.md)
|
||||
|
||||
# Files whose mentions of nomarchy-* are documentation about the scripts,
|
||||
# not real callers. Excluded from caller discovery so they don't promote
|
||||
# every script to `kept`.
|
||||
self_refs=(docs/SCRIPTS.md docs/ROADMAP.md docs/AGENT.md)
|
||||
|
||||
ref_files_per_cmd() {
|
||||
local cmd="$1"
|
||||
local self_pattern
|
||||
self_pattern=$(IFS='|'; echo "${self_refs[*]}")
|
||||
grep -rlE "\\b${cmd}\\b" \
|
||||
"${grep_includes[@]}" \
|
||||
"${search_dirs[@]}" 2>/dev/null \
|
||||
| grep -vE "^(features/scripts/utils|core/system/scripts|themes/engine/scripts)/${cmd}$" \
|
||||
| grep -vE "^(${self_pattern})$" \
|
||||
| sort -u
|
||||
}
|
||||
|
||||
# All distinct nomarchy-* tokens we see anywhere in the repo.
|
||||
# Final char must be alphanumeric — dropping trailing-dash matches like
|
||||
# `nomarchy-pkg-` that come from glob references (`for c in nomarchy-pkg-*`).
|
||||
# Restrict to grep_includes so binaries / tmpfiles don't pollute the set.
|
||||
# The first `grep -vE` drops lines where `nomarchy-*` is a derivation /
|
||||
# tmp file / sudoers basename / systemd unit / flake output / docker
|
||||
# container identifier rather than a shell invocation.
|
||||
# The second `grep -vE` is a token-level safety net for prefix-only
|
||||
# tokens left over from wildcards/expansions (e.g. `nomarchy-pkg-*`).
|
||||
all_refs=$(grep -rhE 'nomarchy-[a-z0-9]([a-z0-9-]*[a-z0-9])?' \
|
||||
"${grep_includes[@]}" \
|
||||
"${search_dirs[@]}" 2>/dev/null \
|
||||
| grep -vE \
|
||||
-e '(pname|name)[[:space:]]*=[[:space:]]*"nomarchy-' \
|
||||
-e '/tmp/nomarchy-' \
|
||||
-e '/etc/sudoers\.d/[^"[:space:]]*nomarchy-' \
|
||||
-e 'nixosConfigurations\.nomarchy-' \
|
||||
-e 'packages\.[^.]+\.nomarchy-' \
|
||||
-e '\./result/bin/run-nomarchy-' \
|
||||
-e 'mktemp[[:space:]]+[^|]*-t[[:space:]]+nomarchy-' \
|
||||
-e '(TIMER_NAME|NOPASSWD_FILE|UNIT_NAME)=.*nomarchy-' \
|
||||
-e '\.services\.nomarchy-' \
|
||||
-e 'docker[[:space:]]+[^|]*nomarchy-' \
|
||||
| grep -oE 'nomarchy-[a-z0-9]([a-z0-9-]*[a-z0-9])?' \
|
||||
| grep -vE '^(nomarchy-launch|nomarchy-brightness|nomarchy-cmd|nomarchy-pkg|nomarchy-restart|nomarchy-toggle|nomarchy-theme|nomarchy-webapp-handler|nomarchy-font-selector|nomarchy-theme-selector|nomarchy-wallpaper-selector|nomarchy-setup|nomarchy-refresh|nomarchy-scripts|nomarchy-system-scripts|nomarchy-theme-engine-scripts)$' \
|
||||
| grep -vE '^(nomarchy-plymouth|nomarchy-sddm-theme|nomarchy-live|nomarchy-rev|nomarchy-windows)$' \
|
||||
| grep -vE '^(nomarchy-eval-matrix|nomarchy-docs-scripts|nomarchy-docs-keybindings)$' \
|
||||
| sort -u)
|
||||
# The second denylist covers identifiers whose ambiguity survives the line
|
||||
# filter: `nomarchy-plymouth` / `nomarchy-sddm-theme` are Nix derivation
|
||||
# names referenced as bare idents in `[...]` lists, `nomarchy-live` is an
|
||||
# ISO label that shows up in comments, `nomarchy-rev` is `/etc/nomarchy-rev`
|
||||
# (written by the ISO), and `nomarchy-windows` is a docker container name
|
||||
# in compose heredocs.
|
||||
# The third denylist: `nomarchy-eval-matrix`, `nomarchy-docs-scripts` (this
|
||||
# generator), and `nomarchy-docs-keybindings` are bin/utils repo tools that
|
||||
# name themselves in their own headers / AGENT.md — not user-facing scripts
|
||||
# that ship in nomarchy-system-scripts.
|
||||
|
||||
# --- Render: header --------------------------------------------------------
|
||||
|
||||
main() {
|
||||
cat <<'HEADER'
|
||||
# Nomarchy Script & Menu Audit
|
||||
|
||||
Auto-generated table for [Pillar 3 of the roadmap](ROADMAP.md#3-pillar-script--menu-audit).
|
||||
**Do not edit by hand.** Regenerate after script or menu changes:
|
||||
|
||||
```bash
|
||||
./bin/utils/nomarchy-docs-scripts --out docs/SCRIPTS.md
|
||||
```
|
||||
|
||||
The status column uses a Phase A heuristic — `kept` / `unused?` / `missing`.
|
||||
Phase B (per-batch PRs) refines those into `port-from-omarchy`,
|
||||
`delete-dead`, or `stub-with-notify` and updates the rows.
|
||||
|
||||
## Status legend
|
||||
|
||||
- `kept` — script exists and is called from somewhere outside its own directory.
|
||||
- `unused?` — script exists but no caller was found. Could be dead, could be
|
||||
intentional public API. Phase B triage decides.
|
||||
- `missing` — referenced from code but no script file exists. Phase B triage
|
||||
decides whether to port from Omarchy upstream, delete the caller, or stub
|
||||
with `notify-send`.
|
||||
- `port-from-omarchy` — Phase B verdict: lift the upstream Omarchy script,
|
||||
rewrite for NixOS paths.
|
||||
- `delete-dead` — Phase B verdict: remove and update callers.
|
||||
- `stub-with-notify` — Phase B verdict: temporary `notify-send` stub.
|
||||
|
||||
HEADER
|
||||
|
||||
# --- Render: scripts table ----------------------------------------------
|
||||
printf '## Scripts (%d)\n\n' "${#script_loc[@]}"
|
||||
printf '| Script | Location | Callers | Status | Notes |\n'
|
||||
printf '| --- | --- | --- | --- | --- |\n'
|
||||
|
||||
# Sort scripts by name.
|
||||
for name in $(printf '%s\n' "${!script_loc[@]}" | sort); do
|
||||
local dir="${script_loc[$name]}"
|
||||
local callers status callers_str
|
||||
callers=$(ref_files_per_cmd "$name")
|
||||
if [[ -z "$callers" ]]; then
|
||||
status='`unused?`'
|
||||
callers_str='—'
|
||||
else
|
||||
status='`kept`'
|
||||
# Trim caller list to 2 entries + count.
|
||||
local count
|
||||
count=$(printf '%s\n' "$callers" | wc -l)
|
||||
if (( count > 2 )); then
|
||||
callers_str=$(printf '%s\n' "$callers" | head -2 | paste -sd, -)
|
||||
callers_str="$callers_str, +$((count - 2)) more"
|
||||
else
|
||||
callers_str=$(printf '%s\n' "$callers" | paste -sd, -)
|
||||
fi
|
||||
fi
|
||||
printf '| `%s` | `%s` | %s | %s | |\n' \
|
||||
"$name" "$dir" "$callers_str" "$status"
|
||||
done
|
||||
echo
|
||||
|
||||
# --- Render: missing references -----------------------------------------
|
||||
printf '## Missing references\n\n'
|
||||
printf 'Tokens grepped from `core/`, `features/`, `themes/`, `installer/`, `hosts/`, `bin/`, `lib/` that have no matching script file.\n\n'
|
||||
printf '| Token | Referenced in | Status |\n'
|
||||
printf '| --- | --- | --- |\n'
|
||||
while IFS= read -r token; do
|
||||
[[ -z "$token" ]] && continue
|
||||
[[ -n "${script_loc[$token]:-}" ]] && continue
|
||||
local refs
|
||||
self_pattern=$(IFS='|'; echo "${self_refs[*]}")
|
||||
refs=$(grep -rlE "\\b${token}\\b" \
|
||||
"${grep_includes[@]}" \
|
||||
"${search_dirs[@]}" 2>/dev/null \
|
||||
| grep -vE "^(${self_pattern})$" \
|
||||
| sort -u)
|
||||
[[ -z "$refs" ]] && continue
|
||||
local count refs_str
|
||||
count=$(printf '%s\n' "$refs" | wc -l)
|
||||
if (( count > 2 )); then
|
||||
refs_str=$(printf '%s\n' "$refs" | head -2 | paste -sd, -)
|
||||
refs_str="$refs_str, +$((count - 2)) more"
|
||||
else
|
||||
refs_str=$(printf '%s\n' "$refs" | paste -sd, -)
|
||||
fi
|
||||
printf '| `%s` | %s | `missing` |\n' "$token" "$refs_str"
|
||||
done <<<"$all_refs"
|
||||
echo
|
||||
|
||||
# --- Render: menu items -------------------------------------------------
|
||||
printf '## Menu items\n\n'
|
||||
printf 'Walked from `features/scripts/utils/nomarchy-menu`. Each `case` arm in a `show_*_menu` function becomes one row.\n\n'
|
||||
printf '| Submenu | Entry | Calls | Status |\n'
|
||||
printf '| --- | --- | --- | --- |\n'
|
||||
|
||||
awk '
|
||||
/^show_[a-z_]+_menu\(\) {/ { sub(/\(\) {/, ""); current=$1; in_func=1; next }
|
||||
/^[a-z_]+\(\) {/ && !/^show_/ { current=""; in_func=0; next }
|
||||
/^}$/ { current=""; in_func=0; next }
|
||||
!in_func { next }
|
||||
/^ case \$\(menu / {
|
||||
# extract the menu title between the first pair of double quotes
|
||||
match($0, /menu "[^"]+" "[^"]+"/);
|
||||
if (RSTART == 0) next;
|
||||
title=substr($0, RSTART, RLENGTH);
|
||||
# second quoted string is the option list
|
||||
n=split(title, parts, "\"");
|
||||
title=parts[2];
|
||||
options=parts[4];
|
||||
# split options on \n
|
||||
split(options, opts, "\\\\n");
|
||||
pending_submenu=current;
|
||||
pending_title=title;
|
||||
for (i=1;i<=length(opts);i++) pending_opts[i]=opts[i];
|
||||
pending_count=length(opts);
|
||||
next
|
||||
}
|
||||
/^ \*[A-Za-z]/ {
|
||||
# case arm — extract pattern between the first * and the closing )
|
||||
match($0, /\*[^)]*\)/);
|
||||
if (RSTART == 0) next;
|
||||
arm=substr($0, RSTART, RLENGTH);
|
||||
gsub(/[*)]/, "", arm);
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", arm);
|
||||
# action follows the )
|
||||
rest=substr($0, RSTART+RLENGTH);
|
||||
sub(/^[[:space:]]+/, "", rest);
|
||||
sub(/[[:space:]]*;;[[:space:]]*$/, "", rest);
|
||||
# match the first nomarchy-* token in the action
|
||||
cmd=""
|
||||
if (match(rest, /nomarchy-[a-z0-9-]+/)) {
|
||||
cmd=substr(rest, RSTART, RLENGTH);
|
||||
}
|
||||
printf "%s|%s|%s\n", pending_submenu, arm, cmd;
|
||||
}
|
||||
' features/scripts/utils/nomarchy-menu > /tmp/nomarchy-menu-rows.$$
|
||||
|
||||
while IFS='|' read -r submenu entry cmd; do
|
||||
[[ -z "$entry" ]] && continue
|
||||
[[ "$entry" =~ ^\) ]] && continue
|
||||
status='`kept`'
|
||||
if [[ -n "$cmd" ]]; then
|
||||
if [[ -z "${script_loc[$cmd]:-}" ]]; then
|
||||
status='`missing`'
|
||||
fi
|
||||
else
|
||||
cmd='_(inline)_'
|
||||
fi
|
||||
printf '| `%s` | %s | `%s` | %s |\n' "$submenu" "$entry" "$cmd" "$status"
|
||||
done < /tmp/nomarchy-menu-rows.$$
|
||||
rm -f /tmp/nomarchy-menu-rows.$$
|
||||
echo
|
||||
}
|
||||
|
||||
out=""
|
||||
if [[ "${1:-}" == "--out" ]]; then
|
||||
out="${2:?--out needs a path}"; shift 2
|
||||
fi
|
||||
if [[ -n "$out" ]]; then
|
||||
main >"$out"
|
||||
else
|
||||
main
|
||||
fi
|
||||
@@ -1,149 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# nomarchy-eval-matrix
|
||||
#
|
||||
# Evaluates the opt-in nomarchy.* surface that the per-output flake check
|
||||
# never touches. flake check only evaluates the default configs, so a bug
|
||||
# that only fires when a toggle is flipped — a renamed option, a failed
|
||||
# assertion, a stale reference — sails straight through. Two such bugs
|
||||
# shipped to main before this existed (the vscode option rename and the
|
||||
# impermanence systemd-stage-1 assertion); both would have been caught
|
||||
# here.
|
||||
#
|
||||
# Cost matters: this runs in CI on a small self-hosted runner, and the
|
||||
# first cut (one full `extendModules` eval per individual toggle, plus one
|
||||
# per palette) did ~39 whole-system evaluations and ran ~3h. So:
|
||||
#
|
||||
# * Compatible toggles are COMBINED into a few configs (a failure means
|
||||
# re-run the offending toggle alone to pinpoint it — see the trace hint
|
||||
# at the end). laptop vs desktop formFactor conflict, so they split;
|
||||
# impermanence's multi-disk variant gets its own config for the alt
|
||||
# mainLuksName.
|
||||
# * Palettes are checked DIRECTLY via the lib — the per-palette risk is
|
||||
# the system-side Plymouth base00 → RGB math (fromHexString of 2-char
|
||||
# slices in themes/engine/plymouth.nix), which is pure and needs no
|
||||
# module-system instantiation. Forcing the whole palette attrset also
|
||||
# catches a missing/garbled palette.
|
||||
# * The standalone homeConfigurations aren't re-checked here — the
|
||||
# per-output flake-check step already forces both.
|
||||
#
|
||||
# Net: a handful of full evals instead of ~39. Results come from
|
||||
# builtins.tryEval so one failure doesn't mask the rest.
|
||||
#
|
||||
# nomarchy-eval-matrix # run the matrix, table + exit code
|
||||
#
|
||||
# Add a new opt-in option's coverage by dropping it into the relevant
|
||||
# combined scenario in the `scenarios` attrset below.
|
||||
|
||||
set -u
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$repo_root"
|
||||
|
||||
NIX=(nix --extra-experimental-features 'nix-command flakes')
|
||||
|
||||
read -r -d '' EXPR <<'NIXEOF' || true
|
||||
let
|
||||
f = builtins.getFlake (toString ./.);
|
||||
lib = f.inputs.nixpkgs.lib;
|
||||
nl = import ./lib { inherit lib; };
|
||||
default = f.nixosConfigurations.default;
|
||||
|
||||
forced = x: (builtins.tryEval (builtins.seq x true)).success;
|
||||
|
||||
# Combined opt-in scenarios. Each enables as many compatible toggles as
|
||||
# possible so CI does ~3 full-system evals, not one per toggle. Home-side
|
||||
# options go under home-manager.users.nomarchy.nomarchy.*.
|
||||
scenarios = {
|
||||
# laptop formFactor + every compatible system/home toggle + impermanence.
|
||||
"laptop-stack" = {
|
||||
nomarchy.system = {
|
||||
formFactor = "laptop";
|
||||
laptop.enable = true;
|
||||
accessibility.enable = true;
|
||||
gaming.enable = true;
|
||||
features.hybridGPU = true;
|
||||
hibernation.enable = true;
|
||||
virtualization.docker.enable = true;
|
||||
impermanence.enable = true;
|
||||
};
|
||||
nomarchy.hardware.fwupd = true;
|
||||
home-manager.users.nomarchy.nomarchy = {
|
||||
accessibility.enable = true;
|
||||
gaming.enable = true;
|
||||
overrides.enable = true;
|
||||
panelPosition = "bottom";
|
||||
keymap = { layout = "de"; variant = "nodeadkeys"; };
|
||||
toggles = { waybar = false; idle = false; nightlight = false; };
|
||||
};
|
||||
};
|
||||
|
||||
# desktop preset — conflicts with the laptop formFactor, so its own eval.
|
||||
"desktop-stack" = {
|
||||
nomarchy.system = { formFactor = "desktop"; desktop.enable = true; };
|
||||
};
|
||||
|
||||
# impermanence multi-disk variant (alternate mainLuksName).
|
||||
"impermanence-multi" = {
|
||||
nomarchy.system.impermanence = { enable = true; mainLuksName = "crypted_main"; };
|
||||
};
|
||||
};
|
||||
|
||||
evalToplevel = mod:
|
||||
forced (default.extendModules { modules = [ mod ]; }).config.system.build.toplevel.drvPath;
|
||||
|
||||
# base00 → the three byte values the Plymouth template substitutes; plus
|
||||
# the whole palette attrset, so a missing/garbled palette is caught.
|
||||
paletteOk = name:
|
||||
let
|
||||
p = nl.getPalette name;
|
||||
b = p.base00;
|
||||
bytes = [
|
||||
(lib.fromHexString (lib.substring 0 2 b))
|
||||
(lib.fromHexString (lib.substring 2 2 b))
|
||||
(lib.fromHexString (lib.substring 4 2 b))
|
||||
];
|
||||
in forced (builtins.deepSeq [ p bytes ] true);
|
||||
in {
|
||||
scenarios = builtins.mapAttrs (_: evalToplevel) scenarios;
|
||||
palettes = builtins.listToAttrs (map (n: { name = n; value = paletteOk n; }) nl.themeNames);
|
||||
}
|
||||
NIXEOF
|
||||
|
||||
echo "Evaluating combined toggle scenarios + per-palette colour math..."
|
||||
json="$("${NIX[@]}" eval --impure --json --expr "$EXPR" 2>/tmp/eval-matrix.err)"
|
||||
status=$?
|
||||
if [[ $status -ne 0 || -z "$json" ]]; then
|
||||
echo "ERROR: the matrix evaluation aborted before producing results." >&2
|
||||
echo "This usually means an uncatchable error (abort/infinite recursion) in one" >&2
|
||||
echo "scenario, or a syntax error in the expression. Full output:" >&2
|
||||
cat /tmp/eval-matrix.err >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Render each section and tally failures.
|
||||
fails=0
|
||||
render() {
|
||||
local section="$1"
|
||||
echo
|
||||
echo "=== $section ==="
|
||||
while IFS=$'\t' read -r name ok; do
|
||||
if [[ "$ok" == "true" ]]; then
|
||||
printf ' ok %s\n' "$name"
|
||||
else
|
||||
printf ' FAIL %s\n' "$name"
|
||||
fails=$((fails + 1))
|
||||
fi
|
||||
done < <(echo "$json" | jq -r --arg s "$section" '.[$s] | to_entries[] | "\(.key)\t\(.value)"' | sort)
|
||||
}
|
||||
|
||||
render scenarios
|
||||
render palettes
|
||||
|
||||
echo
|
||||
if [[ $fails -gt 0 ]]; then
|
||||
echo "$fails scenario(s) failed to evaluate. A combined scenario bundles several"
|
||||
echo "toggles — re-run the suspects individually for the trace, e.g.:"
|
||||
echo " nix eval --impure --show-trace --expr 'let f = builtins.getFlake (toString ./.); in (f.nixosConfigurations.default.extendModules { modules = [ { <the toggle> } ]; }).config.system.build.toplevel.drvPath'"
|
||||
exit 1
|
||||
fi
|
||||
echo "All scenarios evaluated cleanly."
|
||||
@@ -1,16 +0,0 @@
|
||||
# About Nomarchy
|
||||
|
||||
Nomarchy is a highly curated, NixOS-based distribution designed for power users.
|
||||
It features a customized Hyprland desktop environment with a declarative
|
||||
theming engine and a suite of integrated utility scripts.
|
||||
|
||||
Built on a foundation of:
|
||||
- NixOS (Linux)
|
||||
- Hyprland (Window Manager)
|
||||
- Waybar (Status Bar)
|
||||
- Walker (Application Launcher & Menu)
|
||||
- Stylix (Theming Engine)
|
||||
|
||||
Version: 2026.05.04
|
||||
Docs: https://github.com/nomarchy/nomarchy/docs
|
||||
Manual: nomarchy-manual (Command)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
@@ -1,56 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
|
||||
sodipodi:docname="icon.svg"
|
||||
inkscape:export-filename="logo.svg"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="0.82803284"
|
||||
inkscape:cx="215.57116"
|
||||
inkscape:cy="452.27675"
|
||||
inkscape:window-width="1025"
|
||||
inkscape:window-height="1012"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs1" /><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><g
|
||||
id="g4"
|
||||
transform="translate(3.1953242,-22.686801)"
|
||||
style="fill:#000088;fill-opacity:1"><path
|
||||
style="fill:#000088;stroke-width:0.264583;fill-opacity:1"
|
||||
d="M 25.136891,85.823024 25.557592,210.77125 88.452409,174.38061 67.417351,160.49747 57.110174,166.38729 V 105.80633 Z"
|
||||
id="path1" /><path
|
||||
style="fill:#000088;stroke-width:0.264583;fill-opacity:1"
|
||||
d="M 67.728991,112.41131 182.54178,185.60757 153.16137,202.85259 67.830432,148.17947 Z"
|
||||
id="path2" /><path
|
||||
style="fill:#000088;stroke-width:0.264583;fill-opacity:1"
|
||||
d="M 139.74857,145.88014 140.00405,110.4959 54.800856,56.333749 25.675926,73.32329 Z"
|
||||
id="path3" /><path
|
||||
style="fill:#000088;stroke-width:0.264583;fill-opacity:1"
|
||||
d="M 182.2863,172.70573 V 48.286069 l -62.59305,36.406166 20.82177,13.668277 10.21927,-5.74834 0.12774,60.165978 z"
|
||||
id="path4" /></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1,34 +0,0 @@
|
||||
${2},,,
|
||||
${1},, ${2},,,,,,
|
||||
${1},,,,,,,, ${2},,,,,,,,,,
|
||||
${1},,,,,,,,,,,,,, ${2}.,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,,,,,,,,,,,,. ${2},,,,,,,,,,,,,,,,,,,
|
||||
${1}.,,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,,,,,,,,,,,,
|
||||
${1}, ${1},,,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,,,,,,,,,,,,,
|
||||
${1},,, ${1},,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,,,,,,,,,,,,,
|
||||
${1},,,,,, ${1}.,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,,,,,,,,,
|
||||
${1},,,,,,,,,. ${1},,,,,,,,,,,,,,,,,,,,,,,,, ${2},,, ${2}.,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,, ${1}.,,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,,. ${2},,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},, ${1},,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,, ${1},,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,, ${1},,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,, ${1},,,,,,,,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,, ${1},,,,,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,, ${1},,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,, ${1},,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,, ${1},, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,, ${1},,,,,,,,,,,,,,,,,,,,,,,,, ${2},,,,,,,,,
|
||||
${1},,,,,,,,,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,, ${2}.,,,,,
|
||||
${1},,,,,,,,,,,,,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,,, ${2},,,
|
||||
${1},,,,,,,,,,,,,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,,,,,,,, ${1},,,,,,,,,,,,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,,,,, ${1}.,,,,,,,,,,,,,,,,,,,
|
||||
${1},,,,,,,,,,,,, ${1},,,,,,,,,,,,,,
|
||||
${1},,,,,,,,,, ${1},,,,,,,,,.
|
||||
${1},,,,,, ${1},,
|
||||
${1},,,,
|
||||
@@ -1,34 +0,0 @@
|
||||
,,,
|
||||
,, ,,,,,,
|
||||
,,,,,,,, ,,,,,,,,,,
|
||||
,,,,,,,,,,,,,, .,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,,,,,,,,,,,,. ,,,,,,,,,,,,,,,,,,,
|
||||
.,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,
|
||||
, ,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
,,, ,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
,,,,,, .,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,
|
||||
,,,,,,,,,. ,,,,,,,,,,,,,,,,,,,,,,,,, ,,, .,,,,,,,,,,,,
|
||||
,,,,,,,,,,,, .,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,. ,,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,, ,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,, ,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,, ,,,,,,,,,,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,, ,,,,,,,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,, ,,,,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,,,, ,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,, ,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,, ,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,, ,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,
|
||||
,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,, .,,,,,
|
||||
,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,, ,,,
|
||||
,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,,,,, .,,,,,,,,,,,,,,,,,,,
|
||||
,,,,,,,,,,,,, ,,,,,,,,,,,,,,
|
||||
,,,,,,,,,, ,,,,,,,,,.
|
||||
,,,,,, ,,
|
||||
,,,,
|
||||
@@ -1,11 +0,0 @@
|
||||
# Nomarchy Screensaver Configuration
|
||||
|
||||
Nomarchy uses hyprlock for locking and hypridle for idle management.
|
||||
To configure the screensaver/lock screen visuals, edit:
|
||||
~/.config/hypr/hyprlock.conf
|
||||
|
||||
To configure idle timeouts and actions, edit:
|
||||
~/.config/hypr/hypridle.conf
|
||||
|
||||
You can also toggle the screensaver/idle management via the Nomarchy Menu:
|
||||
Trigger > Toggle > Idle Lock
|
||||
@@ -1,5 +0,0 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
imports = [ ./system ];
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.nomarchy.accessibility;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
# Hyprland-side accessibility extras. The system preset
|
||||
# (core/system/accessibility.nix) covers AT-SPI2 + Orca on PATH +
|
||||
# XCURSOR_SIZE; this module adds the bits Hyprland reads directly.
|
||||
#
|
||||
# Loaded via extraConfig (mkAfter) so it merges with — and overrides
|
||||
# — the templated input.conf for the repeat-rate / repeat-delay
|
||||
# fields. The Orca keybinding is additive.
|
||||
wayland.windowManager.hyprland.extraConfig = lib.mkAfter ''
|
||||
# Accessibility — slower key-repeat so holding a key isn't a
|
||||
# runaway machine-gun for users with low-mobility hands.
|
||||
input {
|
||||
repeat_rate = 25
|
||||
repeat_delay = 1000
|
||||
}
|
||||
|
||||
# Launch the Orca screen reader. The system preset puts `orca`
|
||||
# on PATH when nomarchy.system.accessibility.enable = true.
|
||||
bindd = SUPER ALT, S, Launch Orca, exec, orca
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
{
|
||||
programs.bash = {
|
||||
enable = true;
|
||||
|
||||
bashrcExtra = ''
|
||||
if [[ -f ~/.config/nomarchy/default/bash/rc ]]; then
|
||||
source ~/.config/nomarchy/default/bash/rc
|
||||
fi
|
||||
'';
|
||||
|
||||
shellAliases = lib.mkDefault {
|
||||
# File system
|
||||
lsa = "ls -a";
|
||||
|
||||
# Directories
|
||||
".." = "cd ..";
|
||||
"..." = "cd ../..";
|
||||
"...." = "cd ../../..";
|
||||
|
||||
# Tools
|
||||
c = "opencode";
|
||||
d = "docker";
|
||||
r = "rails";
|
||||
t = "tmux attach || tmux new -s Work";
|
||||
|
||||
# Git
|
||||
g = "git";
|
||||
gcm = "git commit -m";
|
||||
gcam = "git commit -a -m";
|
||||
gcad = "git commit -a --amend";
|
||||
|
||||
# NixOS commands
|
||||
sys-update = "nomarchy-sys-update";
|
||||
env-update = "nomarchy-env-update";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
--ozone-platform=wayland
|
||||
--ozone-platform-hint=wayland
|
||||
--enable-features=TouchpadOverscrollHistoryNavigation
|
||||
--load-extension=~/.config/nomarchy/default/chromium/extensions/copy-url
|
||||
@@ -1,4 +0,0 @@
|
||||
--ozone-platform=wayland
|
||||
--ozone-platform-hint=wayland
|
||||
--enable-features=TouchpadOverscrollHistoryNavigation
|
||||
--load-extension=~/.config/nomarchy/default/chromium/extensions/copy-url
|
||||
@@ -1,137 +0,0 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "file",
|
||||
"source": "~/.config/nomarchy/branding/icon.txt",
|
||||
"color": { "1": "green", "2": "blue" },
|
||||
"padding": {
|
||||
"top": 2,
|
||||
"right": 6,
|
||||
"left": 2
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "\u001b[90m┌──────────────────────Hardware──────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "host",
|
||||
"key": " PC",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "│ ├",
|
||||
"showPeCoreCount": true,
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│ ├",
|
||||
"detectionMethod": "pci",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": "│ ├",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": "│ ├",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│ ├",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "swap",
|
||||
"key": "└ └ ",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "\u001b[90m└────────────────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "\u001b[90m┌──────────────────────Software──────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "\ue900 OS",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"key": "│ ├",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "│ ├",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "de",
|
||||
"key": " DE",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "│ ├",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"key": "│ ├",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "wmtheme",
|
||||
"key": "│ ├",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"key": "│ ├",
|
||||
"keyColor": "blue",
|
||||
"text": "theme=$(cat ~/.config/nomarchy/current/theme.name); echo -e \"$theme \\e[38m●\\e[37m●\\e[36m●\\e[35m●\\e[34m●\\e[33m●\\e[32m●\\e[31m●\""
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "└ └",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "\u001b[90m└────────────────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "\u001b[90m┌────────────────Age / Uptime / Update───────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"key": " OS Age",
|
||||
"keyColor": "magenta",
|
||||
"text": "echo $(( ($(date +%s) - $(stat -c %W /)) / 86400 )) days"
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"key": " Uptime",
|
||||
"keyColor": "magenta"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "\u001b[90m└────────────────────────────────────────────────────┘"
|
||||
},
|
||||
"break"
|
||||
]
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
TriggerKey=
|
||||
PastePrimaryKey=
|
||||
@@ -1 +0,0 @@
|
||||
Allow Overriding System XKB Settings=False
|
||||
@@ -1,79 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<match target="pattern">
|
||||
<test name="family" qual="any">
|
||||
<string>sans-serif</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="strong">
|
||||
<string>Liberation Sans</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<match target="pattern">
|
||||
<test name="family" qual="any">
|
||||
<string>serif</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="strong">
|
||||
<string>Liberation Serif</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<match target="pattern">
|
||||
<test name="family" qual="any">
|
||||
<string>monospace</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="strong">
|
||||
<string>JetBrainsMono Nerd Font</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<alias>
|
||||
<family>system-ui</family>
|
||||
<prefer>
|
||||
<family>Liberation Sans</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
|
||||
<alias>
|
||||
<family>ui-monospace</family>
|
||||
<default>
|
||||
<family>monospace</family>
|
||||
</default>
|
||||
</alias>
|
||||
|
||||
<alias>
|
||||
<family>-apple-system</family>
|
||||
<prefer>
|
||||
<family>Liberation Sans</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
|
||||
<alias>
|
||||
<family>BlinkMacSystemFont</family>
|
||||
<prefer>
|
||||
<family>Liberation Sans</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
|
||||
<alias>
|
||||
<family>sans-serif</family>
|
||||
<accept>
|
||||
<family>Noto Color Emoji</family>
|
||||
</accept>
|
||||
</alias>
|
||||
|
||||
<alias>
|
||||
<family>serif</family>
|
||||
<accept>
|
||||
<family>Noto Color Emoji</family>
|
||||
</accept>
|
||||
</alias>
|
||||
|
||||
<alias>
|
||||
<family>monospace</family>
|
||||
<accept>
|
||||
<family>Noto Color Emoji</family>
|
||||
</accept>
|
||||
</alias>
|
||||
</fontconfig>
|
||||
@@ -1,28 +0,0 @@
|
||||
# See https://git-scm.com/docs/git-config
|
||||
|
||||
[alias]
|
||||
co = checkout
|
||||
br = branch
|
||||
ci = commit
|
||||
st = status
|
||||
[init]
|
||||
defaultBranch = master
|
||||
[pull]
|
||||
rebase = true # Rebase (instead of merge) on pull
|
||||
[push]
|
||||
autoSetupRemote = true # Automatically set upstream branch on push
|
||||
[diff]
|
||||
algorithm = histogram # Clearer diffs on moved/edited lines
|
||||
colorMoved = plain # Highlight moved blocks in diffs
|
||||
mnemonicPrefix = true # More intuitive refs in diff output
|
||||
[commit]
|
||||
verbose = true # Include diff comment in commit message template
|
||||
[column]
|
||||
ui = auto # Output in columns when possible
|
||||
[branch]
|
||||
sort = -committerdate # Sort branches by most recent commit first
|
||||
[tag]
|
||||
sort = -version:refname # Sort version numbers as you would expect
|
||||
[rerere]
|
||||
enabled = true # Record and reuse conflict resolutions
|
||||
autoupdate = true # Apply stored conflict resolutions automatically
|
||||
@@ -1,13 +0,0 @@
|
||||
[binds]
|
||||
|
||||
# Print the current image file
|
||||
<Ctrl+p> = exec lp "$imv_current_file"
|
||||
|
||||
# Delete the current image and quit the viewer
|
||||
<Ctrl+x> = exec rm "$imv_current_file"; quit
|
||||
|
||||
# Delete the current image and move to the next one
|
||||
<Ctrl+Shift+X> = exec rm "$imv_current_file"; close
|
||||
|
||||
# Rotate the currently open image by 90 degrees
|
||||
<Ctrl+r> = exec mogrify -rotate 90 "$imv_current_file"
|
||||
@@ -1,84 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from gi import require_version
|
||||
|
||||
require_version("Nautilus", "4.1")
|
||||
|
||||
from gi.repository import GObject, Gio, Nautilus
|
||||
|
||||
|
||||
class SendViaLocalSendAction(GObject.GObject, Nautilus.MenuProvider):
|
||||
def _launch_localsend(self, paths):
|
||||
command = self._resolve_command()
|
||||
if not command:
|
||||
return
|
||||
|
||||
if command[-1] == "@@":
|
||||
command = command + paths + ["@@"]
|
||||
else:
|
||||
command = command + paths
|
||||
|
||||
Gio.Subprocess.new(command, Gio.SubprocessFlags.NONE)
|
||||
|
||||
def _resolve_command(self):
|
||||
localsend = shutil.which("localsend")
|
||||
if localsend:
|
||||
return [localsend, "--headless", "send"]
|
||||
|
||||
flatpak = shutil.which("flatpak")
|
||||
if flatpak and self._has_flatpak_app(flatpak, "org.localsend.localsend_app"):
|
||||
return [
|
||||
flatpak,
|
||||
"run",
|
||||
"--file-forwarding",
|
||||
"org.localsend.localsend_app",
|
||||
"@@",
|
||||
]
|
||||
|
||||
return None
|
||||
|
||||
def _has_flatpak_app(self, flatpak, app_id):
|
||||
process = Gio.Subprocess.new(
|
||||
[flatpak, "info", app_id],
|
||||
Gio.SubprocessFlags.STDOUT_SILENCE | Gio.SubprocessFlags.STDERR_SILENCE,
|
||||
)
|
||||
return process.wait_check()
|
||||
|
||||
def _selected_paths(self, files):
|
||||
paths = []
|
||||
|
||||
for file in files:
|
||||
location = file.get_location()
|
||||
if not location:
|
||||
continue
|
||||
|
||||
path = location.get_path()
|
||||
if path and path not in paths:
|
||||
paths.append(path)
|
||||
|
||||
return paths
|
||||
|
||||
def _make_item(self, paths):
|
||||
label = (
|
||||
"Send via LocalSend" if len(paths) == 1 else "Send selected via LocalSend"
|
||||
)
|
||||
item = Nautilus.MenuItem(
|
||||
name="LocalSendNautilus::send_via_localsend",
|
||||
label=label,
|
||||
icon="localsend",
|
||||
)
|
||||
item.connect("activate", self._on_activate, paths)
|
||||
return item
|
||||
|
||||
def _on_activate(self, _menu, paths):
|
||||
self._launch_localsend(paths)
|
||||
|
||||
def get_file_items(self, *args):
|
||||
files = args[0] if len(args) == 1 else args[1]
|
||||
paths = self._selected_paths(files)
|
||||
|
||||
if not paths or not self._resolve_command():
|
||||
return []
|
||||
|
||||
return [self._make_item(paths)]
|
||||
@@ -1,399 +0,0 @@
|
||||
---
|
||||
name: nomarchy
|
||||
description: >
|
||||
REQUIRED for end-user customization of Linux desktop, window manager, or system config.
|
||||
Use when editing ~/.config/hypr/, ~/.config/waybar/, ~/.config/walker/,
|
||||
~/.config/alacritty/, ~/.config/kitty/, ~/.config/ghostty/, ~/.config/mako/,
|
||||
or ~/.config/nomarchy/. Triggers: Hyprland, window rules, animations, keybindings,
|
||||
monitors, gaps, borders, blur, opacity, waybar, walker, terminal config, themes,
|
||||
wallpaper, night light, idle, lock screen, screenshots, layer rules, workspace
|
||||
settings, display config, and user-facing nomarchy commands. Excludes Nomarchy
|
||||
source development in ~/.local/share/nomarchy/ and repo-internal workflows.
|
||||
---
|
||||
|
||||
# Nomarchy Skill
|
||||
|
||||
Manage [Nomarchy](https://nomarchy.org/) Linux systems - a beautiful, modern, opinionated Arch Linux distribution with Hyprland.
|
||||
|
||||
This skill is for end-user customization on installed systems.
|
||||
It is not for contributing to Nomarchy source code.
|
||||
|
||||
## When This Skill MUST Be Used
|
||||
|
||||
**ALWAYS invoke this skill for end-user requests involving ANY of these:**
|
||||
|
||||
- Editing ANY file in `~/.config/hypr/` (window rules, animations, keybindings, monitors, etc.)
|
||||
- Editing ANY file in `~/.config/waybar/`, `~/.config/walker/`, `~/.config/mako/`
|
||||
- Editing terminal configs (alacritty, kitty, ghostty)
|
||||
- Editing ANY file in `~/.config/nomarchy/`
|
||||
- Window behavior, animations, opacity, blur, gaps, borders
|
||||
- Layer rules, workspace settings, display/monitor configuration
|
||||
- Themes, wallpapers, fonts, appearance changes
|
||||
- User-facing `nomarchy-*` commands (`nomarchy-theme-*`, `nomarchy-refresh-*`, `nomarchy-restart-*`, etc.)
|
||||
- Screenshots, screen recording, night light, idle behavior, lock screen
|
||||
|
||||
**If you're about to edit a config file in ~/.config/ on this system, STOP and use this skill first.**
|
||||
|
||||
**Do NOT use this skill for Nomarchy development tasks** — editing files in `~/.local/share/nomarchy/` or modifying repo internals.
|
||||
|
||||
## Critical Safety Rules
|
||||
|
||||
**For end-user customization tasks, NEVER modify anything in `~/.local/share/nomarchy/`** - but READING is safe and encouraged.
|
||||
|
||||
This directory contains Nomarchy's source files managed by git. Any changes will be:
|
||||
- Lost on next `nomarchy-update`
|
||||
- Cause conflicts with upstream
|
||||
- Break the system's update mechanism
|
||||
|
||||
```
|
||||
~/.local/share/nomarchy/ # READ-ONLY - NEVER EDIT (reading is OK)
|
||||
├── bin/ # Source scripts (symlinked to PATH)
|
||||
├── config/ # Default config templates
|
||||
├── themes/ # Stock themes
|
||||
├── default/ # System defaults
|
||||
├── migrations/ # Update migrations
|
||||
└── install/ # Installation scripts
|
||||
```
|
||||
|
||||
**Reading `~/.local/share/nomarchy/` is SAFE and useful** - do it freely to:
|
||||
- Understand how nomarchy commands work: `cat $(which nomarchy-theme-set)`
|
||||
- See default configs before customizing: `cat ~/.local/share/nomarchy/config/fastfetch/config.jsonc`
|
||||
- Check stock theme files to copy for customization
|
||||
- Reference default hyprland settings: `cat ~/.config/nomarchy/default/hypr/*`
|
||||
|
||||
**Always use these safe locations instead:**
|
||||
- `~/.config/` - User configuration (safe to edit)
|
||||
- `~/.config/nomarchy/themes/<custom-name>/` - Custom themes (must be real directories)
|
||||
- `~/.config/nomarchy/hooks/` - Custom automation hooks
|
||||
|
||||
If the request is to develop Nomarchy itself, this skill is out of scope. Follow repository development instructions instead of this skill.
|
||||
|
||||
## System Architecture
|
||||
|
||||
Nomarchy is built on:
|
||||
|
||||
| Component | Purpose | Config Location |
|
||||
|-----------|---------|-----------------|
|
||||
| **Arch Linux** | Base OS | `/etc/`, `~/.config/` |
|
||||
| **Hyprland** | Wayland compositor/WM | `~/.config/hypr/` |
|
||||
| **Waybar** | Status bar | `~/.config/waybar/` |
|
||||
| **Walker** | App launcher | `~/.config/walker/` |
|
||||
| **Alacritty/Kitty/Ghostty** | Terminals | `~/.config/<terminal>/` |
|
||||
| **Mako** | Notifications | `~/.config/mako/` |
|
||||
| **SwayOSD** | On-screen display | `~/.config/swayosd/` |
|
||||
|
||||
## Command Discovery
|
||||
|
||||
Nomarchy provides ~145 commands following `nomarchy-<category>-<action>` pattern.
|
||||
|
||||
```bash
|
||||
# List all nomarchy commands
|
||||
compgen -c | grep -E '^nomarchy-' | sort -u
|
||||
|
||||
# Find commands by category
|
||||
compgen -c | grep -E '^nomarchy-theme'
|
||||
compgen -c | grep -E '^nomarchy-restart'
|
||||
|
||||
# Read a command's source to understand it
|
||||
cat $(which nomarchy-theme-set)
|
||||
```
|
||||
|
||||
### Command Categories
|
||||
|
||||
| Prefix | Purpose | Example |
|
||||
|--------|---------|---------|
|
||||
| `nomarchy-refresh-*` | Reset config to defaults (backs up first) | `nomarchy-refresh-waybar` |
|
||||
| `nomarchy-restart-*` | Restart a service/app | `nomarchy-restart-waybar` |
|
||||
| `nomarchy-toggle-*` | Toggle feature on/off | `nomarchy-toggle-nightlight` |
|
||||
| `nomarchy-theme-*` | Theme management | `nomarchy-theme-set <name>` |
|
||||
| `nomarchy-install-*` | Install optional software | `nomarchy-install-docker-dbs` |
|
||||
| `nomarchy-launch-*` | Launch apps | `nomarchy-launch-browser` |
|
||||
| `nomarchy-cmd-*` | System commands | `nomarchy-cmd-screenshot` |
|
||||
| `nomarchy-pkg-*` | Package management | `nomarchy-pkg-add <pkg>` |
|
||||
| `nomarchy-setup-*` | Initial setup tasks | `nomarchy-setup-fingerprint` |
|
||||
| `nomarchy-update-*` | System updates | `nomarchy-update` |
|
||||
|
||||
## Configuration Locations
|
||||
|
||||
### Hyprland (Window Manager)
|
||||
|
||||
```
|
||||
~/.config/hypr/
|
||||
├── hyprland.conf # Main config (sources others)
|
||||
├── bindings.conf # Keybindings
|
||||
├── monitors.conf # Display configuration
|
||||
├── input.conf # Keyboard/mouse settings
|
||||
├── looknfeel.conf # Appearance (gaps, borders, animations)
|
||||
├── envs.conf # Environment variables
|
||||
├── autostart.conf # Startup applications
|
||||
├── hypridle.conf # Idle behavior (screen off, lock, suspend)
|
||||
├── hyprlock.conf # Lock screen appearance
|
||||
└── hyprsunset.conf # Night light / blue light filter
|
||||
```
|
||||
|
||||
**Key behaviors:**
|
||||
- Hyprland auto-reloads on config save (no restart needed for most changes)
|
||||
- Use `hyprctl reload` to force reload
|
||||
- Use `nomarchy-refresh-hyprland` to reset to defaults
|
||||
|
||||
### Waybar (Status Bar)
|
||||
|
||||
```
|
||||
~/.config/waybar/
|
||||
├── config.jsonc # Bar layout and modules (JSONC format)
|
||||
└── style.css # Styling
|
||||
```
|
||||
|
||||
**Waybar does NOT auto-reload.** You MUST run `nomarchy-restart-waybar` after any config changes.
|
||||
|
||||
**Commands:** `nomarchy-restart-waybar`, `nomarchy-refresh-waybar`, `nomarchy-toggle-waybar`
|
||||
|
||||
### Terminals
|
||||
|
||||
```
|
||||
~/.config/alacritty/alacritty.toml
|
||||
~/.config/kitty/kitty.conf
|
||||
~/.config/ghostty/config
|
||||
```
|
||||
|
||||
**Command:** `nomarchy-restart-terminal`
|
||||
|
||||
### Other Configs
|
||||
|
||||
| App | Location |
|
||||
|-----|----------|
|
||||
| btop | `~/.config/btop/btop.conf` |
|
||||
| fastfetch | `~/.config/fastfetch/config.jsonc` |
|
||||
| lazygit | `~/.config/lazygit/config.yml` |
|
||||
| starship | `~/.config/starship.toml` |
|
||||
| git | `~/.config/git/config` |
|
||||
| walker | `~/.config/walker/config.toml` |
|
||||
|
||||
## Safe Customization Patterns
|
||||
|
||||
### Pattern 1: Edit User Config Directly
|
||||
|
||||
For simple changes, edit files in `~/.config/`:
|
||||
|
||||
```bash
|
||||
# 1. Read current config
|
||||
cat ~/.config/hypr/bindings.conf
|
||||
|
||||
# 2. Backup before changes
|
||||
cp ~/.config/hypr/bindings.conf ~/.config/hypr/bindings.conf.bak.$(date +%s)
|
||||
|
||||
# 3. Make changes with Edit tool
|
||||
|
||||
# 4. Apply changes
|
||||
# - Hyprland: auto-reloads on save (no restart needed)
|
||||
# - Waybar: MUST restart with nomarchy-restart-waybar
|
||||
# - Walker: MUST restart with nomarchy-restart-walker
|
||||
# - Terminals: MUST restart with nomarchy-restart-terminal
|
||||
```
|
||||
|
||||
### Pattern 2: Make a new theme
|
||||
|
||||
1. Create a directory under ~/.config/nomarchy/themes.
|
||||
2. See how an existing theme is done via ~/.local/share/nomarchy/themes/catppuccin.
|
||||
3. Download a matching background (or several) from the internet and put them in ~/.config/nomarchy/themes/[name-of-new-theme]
|
||||
4. When done with the theme, run nomarchy-theme-set "Name of new theme"
|
||||
|
||||
### Pattern 3: Use Hooks for Automation
|
||||
|
||||
Create scripts in `~/.config/nomarchy/hooks/` to run automatically on events:
|
||||
|
||||
```bash
|
||||
# Available hooks (see samples in ~/.config/nomarchy/hooks/):
|
||||
~/.config/nomarchy/hooks/
|
||||
├── theme-set # Runs after theme change (receives theme name as $1)
|
||||
├── font-set # Runs after font change
|
||||
└── post-update # Runs after nomarchy-update
|
||||
```
|
||||
|
||||
Example hook (`~/.config/nomarchy/hooks/theme-set`):
|
||||
```bash
|
||||
#!/bin/bash
|
||||
THEME_NAME=$1
|
||||
echo "Theme changed to: $THEME_NAME"
|
||||
# Add custom actions here
|
||||
```
|
||||
|
||||
### Pattern 4: Reset to Defaults -- ALWAYS SEEK USER CONFIRMATION BEFORE RUNNING
|
||||
|
||||
When customizations go wrong:
|
||||
|
||||
```bash
|
||||
# Reset specific config (creates backup automatically)
|
||||
nomarchy-refresh-waybar
|
||||
nomarchy-refresh-hyprland
|
||||
|
||||
# The refresh command:
|
||||
# 1. Backs up current config with timestamp
|
||||
# 2. Copies default from ~/.local/share/nomarchy/config/
|
||||
# 3. Restarts the component
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Themes
|
||||
|
||||
```bash
|
||||
nomarchy-theme-list # Show available themes
|
||||
nomarchy-theme-current # Show current theme
|
||||
nomarchy-theme-set <name> # Apply theme (use "Tokyo Night" not "tokyo-night")
|
||||
nomarchy-theme-next # Cycle to next theme
|
||||
nomarchy-theme-bg-next # Cycle wallpaper
|
||||
nomarchy-theme-install <url> # Install from git repo
|
||||
nomarchy-theme-remove <name> # Remove an installed extra theme
|
||||
nomarchy-theme-refresh # Re-apply current theme from templates
|
||||
nomarchy-theme-bg-install # Open backgrounds dir to drop in custom images
|
||||
```
|
||||
|
||||
### Keybindings
|
||||
|
||||
Edit `~/.config/hypr/bindings.conf`. Format:
|
||||
```
|
||||
bind = SUPER, Return, exec, xdg-terminal-exec
|
||||
bind = SUPER, Q, killactive
|
||||
bind = SUPER SHIFT, E, exit
|
||||
```
|
||||
|
||||
View current bindings: `nomarchy-menu-keybindings --print`
|
||||
|
||||
**IMPORTANT: When re-binding an existing key:**
|
||||
|
||||
1. First check existing bindings: `nomarchy-menu-keybindings --print`
|
||||
2. If the key is already bound, you MUST add an `unbind` directive BEFORE your new `bind`
|
||||
3. Inform the user what the key was previously bound to
|
||||
|
||||
Example - rebinding SUPER+F (which is bound to fullscreen by default):
|
||||
```
|
||||
# Unbind existing SUPER+F (was: fullscreen)
|
||||
unbind = SUPER, F
|
||||
# New binding for file manager
|
||||
bind = SUPER, F, exec, nautilus
|
||||
```
|
||||
|
||||
Always tell the user: "Note: SUPER+F was previously bound to fullscreen. I've added an unbind directive to override it."
|
||||
|
||||
### Display/Monitors
|
||||
|
||||
Edit `~/.config/hypr/monitors.conf`. Format:
|
||||
```
|
||||
monitor = eDP-1, 1920x1080@60, 0x0, 1
|
||||
monitor = HDMI-A-1, 2560x1440@144, 1920x0, 1
|
||||
```
|
||||
|
||||
List monitors: `hyprctl monitors`
|
||||
|
||||
### Window Rules
|
||||
|
||||
**CRITICAL: Hyprland window rules syntax changes frequently between versions.**
|
||||
|
||||
Before writing ANY window rules, you MUST fetch the current documentation from the official Hyprland wiki:
|
||||
- https://github.com/hyprwm/hyprland-wiki/blob/main/content/Configuring/Window-Rules.md
|
||||
|
||||
DO NOT rely on cached or memorized window rule syntax. The format has changed multiple times and using outdated syntax will cause errors or unexpected behavior.
|
||||
|
||||
Window rules go in `~/.config/hypr/hyprland.conf` or a sourced file. Always verify the current syntax from the wiki first.
|
||||
|
||||
### Fonts
|
||||
|
||||
```bash
|
||||
nomarchy-font-list # Available fonts
|
||||
nomarchy-font-current # Current font
|
||||
nomarchy-font-set <name> # Change font
|
||||
```
|
||||
|
||||
### System
|
||||
|
||||
```bash
|
||||
nomarchy-update # Full system update
|
||||
nomarchy-version # Show Nomarchy version
|
||||
nomarchy-debug --no-sudo --print # Debug info (ALWAYS use these flags)
|
||||
nomarchy-lock-screen # Lock screen
|
||||
nomarchy-system-shutdown # Shutdown
|
||||
nomarchy-system-reboot # Reboot
|
||||
nomarchy-sudo-passwordless-toggle # Toggle 15-min passwordless sudo
|
||||
nomarchy-sudo-reset # Clear sudo lockout / faillock
|
||||
nomarchy-restart-trackpad # Reload intel_quicki2c (fixes dead THC trackpad)
|
||||
```
|
||||
|
||||
**IMPORTANT:** Always run `nomarchy-debug` with `--no-sudo --print` flags to avoid interactive sudo prompts that will hang the terminal.
|
||||
|
||||
### Custom App Launchers
|
||||
|
||||
```bash
|
||||
nomarchy-webapp-install # Add a web app launcher (interactive)
|
||||
nomarchy-webapp-remove [name...] # Remove web apps (interactive if no name)
|
||||
nomarchy-webapp-remove-all # Bulk-remove every web app
|
||||
nomarchy-tui-install # Add a TUI launcher for a terminal program
|
||||
nomarchy-tui-remove [name...] # Remove TUI launchers
|
||||
nomarchy-tui-remove-all # Bulk-remove every TUI launcher
|
||||
```
|
||||
|
||||
Both families write `.desktop` files into `~/.local/share/applications/` so they appear in the app launcher (walker / rofi).
|
||||
|
||||
### Virtualization
|
||||
|
||||
```bash
|
||||
nomarchy-windows-vm install # Provision a Windows VM via docker-compose
|
||||
nomarchy-windows-vm launch # Connect to the VM (auto-stop on disconnect)
|
||||
nomarchy-windows-vm launch -k # Connect, keep VM running after disconnect
|
||||
nomarchy-windows-vm stop # Shut the VM down
|
||||
nomarchy-windows-vm status # Show current state
|
||||
```
|
||||
|
||||
Requires KVM (`/dev/kvm`) and Docker (enable via `nomarchy.system.virtualization.docker`).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
```bash
|
||||
# Get debug information (ALWAYS use these flags to avoid interactive prompts)
|
||||
nomarchy-debug --no-sudo --print
|
||||
|
||||
# Upload logs for support
|
||||
nomarchy-upload-log
|
||||
|
||||
# Reset specific config to defaults
|
||||
# Examples: nomarchy-refresh-fastfetch, nomarchy-refresh-hyprland, nomarchy-refresh-waybar
|
||||
nomarchy-refresh-<app>
|
||||
|
||||
# Refresh specific config file
|
||||
# config-file path is relative to ~/.config/; the stock copy must exist under
|
||||
# ~/.local/share/nomarchy/config/ (i.e. a core/home/config item).
|
||||
# eg. nomarchy-refresh-config fastfetch/config.jsonc refreshes ~/.config/fastfetch/config.jsonc
|
||||
nomarchy-refresh-config <config-file>
|
||||
|
||||
# Full reinstall of configs (nuclear option)
|
||||
nomarchy-reinstall
|
||||
```
|
||||
|
||||
## Decision Framework
|
||||
|
||||
When user requests system changes:
|
||||
|
||||
1. **Is it a stock nomarchy command?** Use it directly
|
||||
2. **Is it a config edit?** Edit in `~/.config/`, never `~/.local/share/nomarchy/`
|
||||
3. **Is it a theme customization?** Create a NEW custom theme directory
|
||||
4. **Is it automation?** Use hooks in `~/.config/nomarchy/hooks/`
|
||||
5. **Is it a package install?** Use `nomarchy-pkg-add` (adds to `user-packages.json`; rebuild applies it). The AUR does not exist on NixOS — search nixpkgs with `nix search nixpkgs <name>`.
|
||||
6. **Unsure if command exists?** Search with `compgen -c | grep nomarchy`
|
||||
|
||||
## Out of Scope
|
||||
|
||||
This skill intentionally does not cover Nomarchy source development. Do not use this skill for:
|
||||
- Editing files in `~/.local/share/nomarchy/` (`bin/`, `config/`, `default/`, `themes/`, `migrations/`, etc.)
|
||||
- Creating or editing migrations
|
||||
- Modifying Nomarchy's own source tree
|
||||
|
||||
## Example Requests
|
||||
|
||||
- "Change my theme to catppuccin" -> `nomarchy-theme-set catppuccin`
|
||||
- "Add a keybinding for Super+E to open file manager" -> Check existing bindings first, add `unbind` if needed, then add `bind` in `~/.config/hypr/bindings.conf`
|
||||
- "Configure my external monitor" -> Edit `~/.config/hypr/monitors.conf`
|
||||
- "Make the window gaps smaller" -> Edit `~/.config/hypr/looknfeel.conf`
|
||||
- "Set up night light to turn on at sunset" -> `nomarchy-toggle-nightlight` or edit `~/.config/hypr/hyprsunset.conf`
|
||||
- "Customize the catppuccin theme colors" -> Create `~/.config/nomarchy/themes/catppuccin-custom/` by copying from stock, then edit
|
||||
- "Run a script every time I change themes" -> Create `~/.config/nomarchy/hooks/theme-set`
|
||||
- "Reset waybar to defaults" -> `nomarchy-refresh-waybar`
|
||||
@@ -1,11 +0,0 @@
|
||||
[colors.primary]
|
||||
background = "0x000000"
|
||||
|
||||
[colors.cursor]
|
||||
cursor = "0x000000"
|
||||
|
||||
[font]
|
||||
size = 18.0
|
||||
|
||||
[window]
|
||||
opacity = 1.0
|
||||
@@ -1,57 +0,0 @@
|
||||
# File system
|
||||
if command -v eza &> /dev/null; then
|
||||
alias ls='eza -lh --group-directories-first --icons=auto'
|
||||
alias lsa='ls -a'
|
||||
alias lt='eza --tree --level=2 --long --icons --git'
|
||||
alias lta='lt -a'
|
||||
fi
|
||||
|
||||
if [[ "$TERM" == "xterm-kitty" ]]; then
|
||||
alias ff="fzf --preview 'case \$(file --mime-type -b {}) in image/*) kitty icat --clear --transfer-mode=memory --stdin=no --place=\${FZF_PREVIEW_COLUMNS}x\${FZF_PREVIEW_LINES}@0x0 {} ;; *) bat --style=numbers --color=always {} ;; esac'"
|
||||
else
|
||||
alias ff="fzf --preview 'bat --style=numbers --color=always {}'"
|
||||
fi
|
||||
alias eff='$EDITOR "$(ff)"'
|
||||
sff() { if [ $# -eq 0 ]; then echo "Usage: sff <destination> (e.g. sff host:/tmp/)"; return 1; fi; local file; file=$(find . -type f -printf '%T@\t%p\n' | sort -rn | cut -f2- | ff) && [ -n "$file" ] && scp "$file" "$1"; }
|
||||
|
||||
if command -v zoxide &> /dev/null; then
|
||||
alias cd="zd"
|
||||
zd() {
|
||||
if (( $# == 0 )); then
|
||||
builtin cd ~ || return
|
||||
elif [[ -d $1 ]]; then
|
||||
builtin cd "$1" || return
|
||||
else
|
||||
if ! z "$@"; then
|
||||
echo "Error: Directory not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf "\U000F17A9 "
|
||||
pwd
|
||||
fi
|
||||
}
|
||||
fi
|
||||
|
||||
open() (
|
||||
xdg-open "$@" >/dev/null 2>&1 &
|
||||
)
|
||||
|
||||
# Directories
|
||||
alias ..='cd ..'
|
||||
alias ...='cd ../..'
|
||||
alias ....='cd ../../..'
|
||||
|
||||
# Tools
|
||||
alias c='opencode'
|
||||
alias cx='printf "\033[2J\033[3J\033[H" && claude --allow-dangerously-skip-permissions'
|
||||
alias d='docker'
|
||||
alias r='rails'
|
||||
alias t='tmux attach || tmux new -s Work'
|
||||
n() { if [ "$#" -eq 0 ]; then command nvim . ; else command nvim "$@"; fi; }
|
||||
|
||||
# Git
|
||||
alias g='git'
|
||||
alias gcm='git commit -m'
|
||||
alias gcam='git commit -a -m'
|
||||
alias gcad='git commit -a --amend'
|
||||
@@ -1,6 +0,0 @@
|
||||
# Editor used by CLI
|
||||
export SUDO_EDITOR="$EDITOR"
|
||||
export BAT_THEME=ansi
|
||||
|
||||
# Duplicated from .config/uwsm/env so SSH works too
|
||||
export PATH=$PATH:$HOME/.local/bin
|
||||
@@ -1,3 +0,0 @@
|
||||
# Compression
|
||||
compress() { tar -czf "${1%/}.tar.gz" "${1%/}"; }
|
||||
alias decompress="tar -xzf"
|
||||
@@ -1,59 +0,0 @@
|
||||
# Write iso file to sd card
|
||||
iso2sd() {
|
||||
if (( $# < 1 )); then
|
||||
echo "Usage: iso2sd <input_file> [output_device]"
|
||||
echo "Example: iso2sd ~/Downloads/ubuntu-25.04-desktop-amd64.iso /dev/sda"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local iso="$1"
|
||||
local drive="$2"
|
||||
|
||||
if [[ -z $drive ]]; then
|
||||
local available_sds=$(lsblk -dpno NAME | grep -E '/dev/sd')
|
||||
|
||||
if [[ -z $available_sds ]]; then
|
||||
echo "No SD drives found and no drive specified"
|
||||
return 1
|
||||
fi
|
||||
|
||||
drive=$(nomarchy-drive-select "$available_sds")
|
||||
|
||||
if [[ -z $drive ]]; then
|
||||
echo "No drive selected"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
sudo dd bs=4M status=progress oflag=sync if="$iso" of="$drive"
|
||||
sudo eject "$drive"
|
||||
}
|
||||
|
||||
# Format an entire drive for a single partition using exFAT
|
||||
format-drive() {
|
||||
if (( $# != 2 )); then
|
||||
echo "Usage: format-drive <device> <name>"
|
||||
echo "Example: format-drive /dev/sda 'My Stuff'"
|
||||
echo -e "\nAvailable drives:"
|
||||
lsblk -d -o NAME -n | awk '{print "/dev/"$1}'
|
||||
else
|
||||
echo "WARNING: This will completely erase all data on $1 and label it '$2'."
|
||||
read -rp "Are you sure you want to continue? (y/N): " confirm
|
||||
|
||||
if [[ $confirm =~ ^[Yy]$ ]]; then
|
||||
sudo wipefs -a "$1"
|
||||
sudo dd if=/dev/zero of="$1" bs=1M count=100 status=progress
|
||||
sudo parted -s "$1" mklabel gpt
|
||||
sudo parted -s "$1" mkpart primary 1MiB 100%
|
||||
sudo parted -s "$1" set 1 msftdata on
|
||||
|
||||
partition="$([[ $1 == *"nvme"* ]] && echo "${1}p1" || echo "${1}1")"
|
||||
sudo partprobe "$1" || true
|
||||
sudo udevadm settle || true
|
||||
|
||||
sudo mkfs.exfat -n "$2" "$partition"
|
||||
|
||||
echo "Drive $1 formatted as exFAT and labeled '$2'."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
# SSH Port Forwarding Functions
|
||||
fip() {
|
||||
(( $# < 2 )) && echo "Usage: fip <host> <port1> [port2] ..." && return 1
|
||||
local host="$1"
|
||||
shift
|
||||
for port in "$@"; do
|
||||
ssh -f -N -L "$port:localhost:$port" "$host" && echo "Forwarding localhost:$port -> $host:$port"
|
||||
done
|
||||
}
|
||||
|
||||
dip() {
|
||||
(( $# == 0 )) && echo "Usage: dip <port1> [port2] ..." && return 1
|
||||
for port in "$@"; do
|
||||
pkill -f "ssh.*-L $port:localhost:$port" && echo "Stopped forwarding port $port" || echo "No forwarding on port $port"
|
||||
done
|
||||
}
|
||||
|
||||
lip() {
|
||||
pgrep -af "ssh.*-L [0-9]+:localhost:[0-9]+" || echo "No active forwards"
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
# Create a Tmux Dev Layout with editor, ai, and terminal
|
||||
# Usage: tdl <c|cx|codex|other_ai> [<second_ai>]
|
||||
tdl() {
|
||||
[[ -z $1 ]] && { echo "Usage: tdl <c|cx|codex|other_ai> [<second_ai>]"; return 1; }
|
||||
[[ -z $TMUX ]] && { echo "You must start tmux to use tdl."; return 1; }
|
||||
|
||||
local current_dir="${PWD}"
|
||||
local editor_pane ai_pane ai2_pane
|
||||
local ai="$1"
|
||||
local ai2="$2"
|
||||
|
||||
# Use TMUX_PANE for the pane we're running in (stable even if active window changes)
|
||||
editor_pane="$TMUX_PANE"
|
||||
|
||||
# Name the current window after the base directory name
|
||||
tmux rename-window -t "$editor_pane" "$(basename "$current_dir")"
|
||||
|
||||
# Split window vertically - top 85%, bottom 15% (target editor pane explicitly)
|
||||
tmux split-window -v -p 15 -t "$editor_pane" -c "$current_dir"
|
||||
|
||||
# Split editor pane horizontally - AI on right 30% (capture new pane ID directly)
|
||||
ai_pane=$(tmux split-window -h -p 30 -t "$editor_pane" -c "$current_dir" -P -F '#{pane_id}')
|
||||
|
||||
# If second AI provided, split the AI pane vertically
|
||||
if [[ -n $ai2 ]]; then
|
||||
ai2_pane=$(tmux split-window -v -t "$ai_pane" -c "$current_dir" -P -F '#{pane_id}')
|
||||
tmux send-keys -t "$ai2_pane" "$ai2" C-m
|
||||
fi
|
||||
|
||||
# Run ai in the right pane
|
||||
tmux send-keys -t "$ai_pane" "$ai" C-m
|
||||
|
||||
# Run nvim in the left pane
|
||||
tmux send-keys -t "$editor_pane" "$EDITOR ." C-m
|
||||
|
||||
# Select the nvim pane for focus
|
||||
tmux select-pane -t "$editor_pane"
|
||||
}
|
||||
|
||||
# Create multiple tdl windows with one per subdirectory in the current directory
|
||||
# Usage: tdlm <c|cx|codex|other_ai> [<second_ai>]
|
||||
tdlm() {
|
||||
[[ -z $1 ]] && { echo "Usage: tdlm <c|cx|codex|other_ai> [<second_ai>]"; return 1; }
|
||||
[[ -z $TMUX ]] && { echo "You must start tmux to use tdlm."; return 1; }
|
||||
|
||||
local ai="$1"
|
||||
local ai2="$2"
|
||||
local base_dir="$PWD"
|
||||
local first=true
|
||||
|
||||
# Rename the session to the current directory name (replace dots/colons which tmux disallows)
|
||||
tmux rename-session "$(basename "$base_dir" | tr '.:' '--')"
|
||||
|
||||
for dir in "$base_dir"/*/; do
|
||||
[[ -d $dir ]] || continue
|
||||
local dirpath="${dir%/}"
|
||||
|
||||
if $first; then
|
||||
# Reuse the current window for the first project
|
||||
tmux send-keys -t "$TMUX_PANE" "cd '$dirpath' && tdl $ai $ai2" C-m
|
||||
first=false
|
||||
else
|
||||
local pane_id=$(tmux new-window -c "$dirpath" -P -F '#{pane_id}')
|
||||
tmux send-keys -t "$pane_id" "tdl $ai $ai2" C-m
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Create a multi-pane swarm layout with the same command started in each pane (great for AI)
|
||||
# Usage: tsl <pane_count> <command>
|
||||
tsl() {
|
||||
[[ -z $1 || -z $2 ]] && { echo "Usage: tsl <pane_count> <command>"; return 1; }
|
||||
[[ -z $TMUX ]] && { echo "You must start tmux to use tsl."; return 1; }
|
||||
|
||||
local count="$1"
|
||||
local cmd="$2"
|
||||
local current_dir="${PWD}"
|
||||
local -a panes
|
||||
|
||||
tmux rename-window -t "$TMUX_PANE" "$(basename "$current_dir")"
|
||||
|
||||
panes+=("$TMUX_PANE")
|
||||
|
||||
while (( ${#panes[@]} < count )); do
|
||||
local new_pane
|
||||
local split_target="${panes[-1]}"
|
||||
new_pane=$(tmux split-window -h -t "$split_target" -c "$current_dir" -P -F '#{pane_id}')
|
||||
panes+=("$new_pane")
|
||||
tmux select-layout -t "${panes[0]}" tiled
|
||||
done
|
||||
|
||||
for pane in "${panes[@]}"; do
|
||||
tmux send-keys -t "$pane" "$cmd" C-m
|
||||
done
|
||||
|
||||
tmux select-pane -t "${panes[0]}"
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
# Transcode a video to a good-balance 1080p that's great for sharing online
|
||||
transcode-video-1080p() {
|
||||
ffmpeg -i "$1" -vf scale=1920:1080 -c:v libx264 -preset fast -crf 23 -c:a copy "${1%.*}-1080p.mp4"
|
||||
}
|
||||
|
||||
# Transcode a video to a good-balance 4K that's great for sharing online
|
||||
transcode-video-4K() {
|
||||
ffmpeg -i "$1" -c:v libx265 -preset slow -crf 24 -c:a aac -b:a 192k "${1%.*}-optimized.mp4"
|
||||
}
|
||||
|
||||
# Transcode any image to JPG image that's great for shrinking wallpapers
|
||||
img2jpg() {
|
||||
img="$1"
|
||||
shift
|
||||
|
||||
magick "$img" "$@" -quality 85 -strip "${img%.*}-converted.jpg"
|
||||
}
|
||||
|
||||
# Transcode any image to a small JPG (max 1080px wide)
|
||||
img2jpg-small() {
|
||||
img="$1"
|
||||
shift
|
||||
|
||||
magick "$img" "$@" -resize 1080x\> -quality 85 -strip "${img%.*}-small.jpg"
|
||||
}
|
||||
|
||||
# Transcode any image to a 4K JPG (max 2160px wide)
|
||||
img2jpg-medium() {
|
||||
img="$1"
|
||||
shift
|
||||
|
||||
magick "$img" "$@" -resize 2160x\> -quality 85 -strip "${img%.*}-medium.jpg"
|
||||
}
|
||||
|
||||
# Transcode any image to a 6K JPG (max 3160px wide)
|
||||
img2jpg-large() {
|
||||
img="$1"
|
||||
shift
|
||||
|
||||
magick "$img" "$@" -resize 3160x\> -quality 85 -strip "${img%.*}-large.jpg"
|
||||
}
|
||||
|
||||
# Transcode any image to compressed-but-lossless PNG
|
||||
img2png() {
|
||||
img="$1"
|
||||
shift
|
||||
|
||||
magick "$img" "$@" -strip -define png:compression-filter=5 \
|
||||
-define png:compression-level=9 \
|
||||
-define png:compression-strategy=1 \
|
||||
-define png:exclude-chunk=all \
|
||||
"${img%.*}-optimized.png"
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
# Create a new worktree and branch from within current git directory.
|
||||
ga() {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Usage: ga [branch name]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local branch="$1"
|
||||
local base="$(basename "$PWD")"
|
||||
local wt_path="../${base}--${branch}"
|
||||
|
||||
git worktree add -b "$branch" "$wt_path"
|
||||
mise trust "$wt_path"
|
||||
cd "$wt_path"
|
||||
}
|
||||
|
||||
# Remove worktree and branch from within active worktree directory.
|
||||
gd() {
|
||||
if gum confirm "Remove worktree and branch?"; then
|
||||
local cwd base branch root worktree
|
||||
|
||||
cwd="$(pwd)"
|
||||
worktree="$(basename "$cwd")"
|
||||
|
||||
# split on first `--`
|
||||
root="${worktree%%--*}"
|
||||
branch="${worktree#*--}"
|
||||
|
||||
# Protect against accidentally nuking a non-worktree directory
|
||||
if [[ "$root" != "$worktree" ]]; then
|
||||
cd "../$root"
|
||||
git worktree remove "$cwd" --force || return 1
|
||||
git branch -D "$branch"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
for f in $HOME/.config/nomarchy/default/bash/fns/*; do source "$f"; done
|
||||
@@ -1,24 +0,0 @@
|
||||
if command -v mise &> /dev/null; then
|
||||
eval "$(mise activate bash)"
|
||||
fi
|
||||
|
||||
if command -v starship &> /dev/null; then
|
||||
eval "$(starship init bash)"
|
||||
fi
|
||||
|
||||
if command -v zoxide &> /dev/null; then
|
||||
eval "$(zoxide init bash)"
|
||||
fi
|
||||
|
||||
if command -v try &> /dev/null; then
|
||||
eval "$(SHELL=/bin/bash command try init ~/Work/tries)"
|
||||
fi
|
||||
|
||||
if command -v fzf &> /dev/null; then
|
||||
if [[ -f /usr/share/fzf/completion.bash ]]; then
|
||||
source /usr/share/fzf/completion.bash
|
||||
fi
|
||||
if [[ -f /usr/share/fzf/key-bindings.bash ]]; then
|
||||
source /usr/share/fzf/key-bindings.bash
|
||||
fi
|
||||
fi
|
||||
@@ -1,47 +0,0 @@
|
||||
set meta-flag on
|
||||
set input-meta on
|
||||
set output-meta on
|
||||
set convert-meta off
|
||||
set completion-ignore-case on
|
||||
set completion-prefix-display-length 2
|
||||
set show-all-if-ambiguous on
|
||||
set show-all-if-unmodified on
|
||||
|
||||
# Arrow keys match what you've typed so far against your command history
|
||||
"\e[A": history-search-backward
|
||||
"\e[B": history-search-forward
|
||||
"\e[C": forward-char
|
||||
"\e[D": backward-char
|
||||
|
||||
# Immediately add a trailing slash when autocompleting symlinks to directories
|
||||
set mark-symlinked-directories on
|
||||
|
||||
# Do not autocomplete hidden files unless the pattern explicitly begins with a dot
|
||||
set match-hidden-files off
|
||||
|
||||
# Show all autocomplete results at once
|
||||
set page-completions off
|
||||
|
||||
# If there are more than 200 possible completions for a word, ask to show them all
|
||||
set completion-query-items 200
|
||||
|
||||
# Show extra file information when completing, like `ls -F` does
|
||||
set visible-stats on
|
||||
|
||||
# Be more intelligent when autocompleting by also looking at the text after
|
||||
# the cursor. For example, when the current line is "cd ~/src/mozil", and
|
||||
# the cursor is on the "z", pressing Tab will not autocomplete it to "cd
|
||||
# ~/src/mozillail", but to "cd ~/src/mozilla". (This is supported by the
|
||||
# Readline used by Bash 4.)
|
||||
set skip-completed-text on
|
||||
|
||||
# Coloring for Bash 4 tab completions.
|
||||
set colored-stats on
|
||||
|
||||
# Cycle forward and backward through completion candidates (tab/shift+tab)
|
||||
# (completion listing and display behavior configured above)
|
||||
TAB: menu-complete
|
||||
"\e[Z": menu-complete-backward
|
||||
|
||||
# On first Tab, complete the common prefix before cycling candidates
|
||||
set menu-complete-display-prefix on
|
||||
@@ -1,6 +0,0 @@
|
||||
source ~/.config/nomarchy/default/bash/envs
|
||||
source ~/.config/nomarchy/default/bash/shell
|
||||
source ~/.config/nomarchy/default/bash/aliases
|
||||
source ~/.config/nomarchy/default/bash/functions
|
||||
source ~/.config/nomarchy/default/bash/init
|
||||
[[ $- == *i* ]] && bind -f ~/.config/nomarchy/default/bash/inputrc
|
||||
@@ -1,13 +0,0 @@
|
||||
# History control
|
||||
shopt -s histappend
|
||||
HISTCONTROL=ignoreboth
|
||||
HISTSIZE=32768
|
||||
HISTFILESIZE="${HISTSIZE}"
|
||||
|
||||
# Autocompletion
|
||||
if [[ ! -v BASH_COMPLETION_VERSINFO && -f /usr/share/bash-completion/bash_completion ]]; then
|
||||
source /usr/share/bash-completion/bash_completion
|
||||
fi
|
||||
|
||||
# Ensure command hashing is off for mise
|
||||
set +h
|
||||
@@ -1,21 +0,0 @@
|
||||
chrome.commands.onCommand.addListener((command) => {
|
||||
if (command === 'copy-url') {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
||||
const currentTab = tabs[0];
|
||||
|
||||
chrome.scripting.executeScript({
|
||||
target: { tabId: currentTab.id },
|
||||
func: () => {
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
}
|
||||
}).then(() => {
|
||||
chrome.notifications.create({
|
||||
type: 'basic',
|
||||
iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==',
|
||||
title: ' URL copied to clipboard',
|
||||
message: ''
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
../../../../icon.png
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Copy URL",
|
||||
"version": "1.0",
|
||||
"description": "Copy current URL to clipboard, this extension is installed by Nomarchy",
|
||||
"permissions": ["activeTab", "scripting", "notifications"],
|
||||
"icons": {
|
||||
"16": "icon.png",
|
||||
"48": "icon.png",
|
||||
"128": "icon.png"
|
||||
},
|
||||
"commands": {
|
||||
"copy-url": {
|
||||
"suggested_key": {"default": "Alt+Shift+L"},
|
||||
"description": "Copy URL"
|
||||
}
|
||||
},
|
||||
"background": {"service_worker": "background.js"}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
window-padding-x = 0
|
||||
window-padding-y = 0
|
||||
window-padding-color = "extend-always"
|
||||
@@ -1,7 +0,0 @@
|
||||
keyserver hkps://keyserver.ubuntu.com
|
||||
keyserver hkps://pgp.surfnet.nl
|
||||
keyserver hkps://keys.mailvelope.com
|
||||
keyserver hkps://keyring.debian.org
|
||||
keyserver hkps://pgp.mit.edu
|
||||
|
||||
connect-quick-timeout 4
|
||||
@@ -1,19 +0,0 @@
|
||||
# App-specific tweaks. All rules are class- or title-gated, so sourcing
|
||||
# unconditionally is harmless when the app isn't installed or running.
|
||||
source = ~/.config/nomarchy/default/hypr/apps/1password.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/bitwarden.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/browser.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/davinci-resolve.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/geforce.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/hyprshot.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/localsend.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/moonlight.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/pip.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/qemu.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/retroarch.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/steam.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/system.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/telegram.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/terminals.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/walker.conf
|
||||
source = ~/.config/nomarchy/default/hypr/apps/webcam-overlay.conf
|
||||
@@ -1,2 +0,0 @@
|
||||
windowrulev2 = noscreenshare, class:^(1[p|P]assword)$
|
||||
windowrulev2 = tag +floating-window, class:^(1[p|P]assword)$
|
||||
@@ -1,6 +0,0 @@
|
||||
windowrulev2 = noscreenshare, class:^(Bitwarden)$
|
||||
windowrulev2 = tag +floating-window, class:^(Bitwarden)$
|
||||
|
||||
# Bitwarden Chrome Extension
|
||||
windowrulev2 = noscreenshare, class:chrome-nngceckbapebfimnlniiiahkandclblb-Default
|
||||
windowrulev2 = tag +floating-window, class:chrome-nngceckbapebfimnlniiiahkandclblb-Default
|
||||
@@ -1,16 +0,0 @@
|
||||
# Browser types
|
||||
windowrulev2 = tag +chromium-based-browser, class:((google-)?[cC]hrom(e|ium)|[bB]rave-browser|[mM]icrosoft-edge|Vivaldi-stable|helium)
|
||||
windowrulev2 = tag +firefox-based-browser, class:([fF]irefox|zen|librewolf)
|
||||
windowrulev2 = tag -default-opacity, tag:chromium-based-browser
|
||||
windowrulev2 = tag -default-opacity, tag:firefox-based-browser
|
||||
|
||||
# Video apps: remove chromium browser tag so they don't get opacity applied
|
||||
windowrulev2 = tag -chromium-based-browser, class:(chrome-youtube.com__-Default|chrome-app.zoom.us__wc_home-Default)
|
||||
windowrulev2 = tag -default-opacity, class:(chrome-youtube.com__-Default|chrome-app.zoom.us__wc_home-Default)
|
||||
|
||||
# Force chromium-based browsers into a tile to deal with --app bug
|
||||
windowrulev2 = tile, tag:chromium-based-browser
|
||||
|
||||
# Only a subtle opacity change, but not for video sites
|
||||
windowrulev2 = opacity 1.0 0.97, tag:chromium-based-browser
|
||||
windowrulev2 = opacity 1.0 0.97, tag:firefox-based-browser
|
||||
@@ -1,2 +0,0 @@
|
||||
# Focus floating DaVinci Resolve dialog windows
|
||||
windowrulev2 = stayfocused, class:.*[Rr]esolve.*, float:1
|
||||
@@ -1 +0,0 @@
|
||||
windowrulev2 = idleinhibit fullscreen, class:^(GeForceNOW)$
|
||||
@@ -1,2 +0,0 @@
|
||||
# Remove 1px border around hyprshot screenshots
|
||||
layerrule = noanim, namespace:selection
|
||||
@@ -1,4 +0,0 @@
|
||||
# Float LocalSend and fzf file picker
|
||||
windowrulev2 = float, class:(Share|localsend)
|
||||
windowrulev2 = center, class:(Share|localsend)
|
||||
windowrulev2 = size 1100 700, class:localsend
|
||||
@@ -1,2 +0,0 @@
|
||||
windowrulev2 = fullscreen, class:^(com.moonlight_stream.Moonlight)$
|
||||
windowrulev2 = idleinhibit fullscreen, class:^(com.moonlight_stream.Moonlight)$
|
||||
@@ -1,10 +0,0 @@
|
||||
# Picture-in-picture overlays
|
||||
windowrulev2 = tag +pip, title:(Picture.?in.?[Pp]icture)
|
||||
windowrulev2 = tag -default-opacity, tag:pip
|
||||
windowrulev2 = float, tag:pip
|
||||
windowrulev2 = pin, tag:pip
|
||||
windowrulev2 = size 600 338, tag:pip
|
||||
windowrulev2 = keepaspectratio, tag:pip
|
||||
windowrulev2 = bordersize 0, tag:pip
|
||||
windowrulev2 = opacity 1 1, tag:pip
|
||||
windowrulev2 = move (monitor_w-window_w-40) (monitor_h*0.04), tag:pip
|
||||
@@ -1,2 +0,0 @@
|
||||
windowrulev2 = tag -default-opacity, class:qemu
|
||||
windowrulev2 = opacity 1 1, class:qemu
|
||||
@@ -1,4 +0,0 @@
|
||||
windowrulev2 = fullscreen, class:com.libretro.RetroArch
|
||||
windowrulev2 = tag -default-opacity, class:com.libretro.RetroArch
|
||||
windowrulev2 = opacity 1 1, class:com.libretro.RetroArch
|
||||
windowrulev2 = idleinhibit fullscreen, class:com.libretro.RetroArch
|
||||
@@ -1,8 +0,0 @@
|
||||
# Float Steam
|
||||
windowrulev2 = float, class:steam
|
||||
windowrulev2 = center, class:steam, title:Steam
|
||||
windowrulev2 = tag -default-opacity, class:steam.*
|
||||
windowrulev2 = opacity 1 1, class:steam.*
|
||||
windowrulev2 = size 1100 700, class:steam, title:Steam
|
||||
windowrulev2 = size 460 800, class:steam, title:Friends List
|
||||
windowrulev2 = idleinhibit fullscreen, class:steam
|
||||
@@ -1,23 +0,0 @@
|
||||
# Floating windows
|
||||
windowrulev2 = float, tag:floating-window
|
||||
windowrulev2 = center, tag:floating-window
|
||||
windowrulev2 = size 875 600, tag:floating-window
|
||||
|
||||
windowrulev2 = tag +floating-window, class:(org.nomarchy.bluetui|org.nomarchy.impala|org.nomarchy.wiremix|org.nomarchy.btop|org.nomarchy.terminal|org.nomarchy.bash|org.gnome.NautilusPreviewer|org.gnome.Evince|com.gabm.satty|Nomarchy|About|TUI.float|imv|mpv)
|
||||
windowrulev2 = tag +floating-window, class:(xdg-desktop-portal-gtk|sublime_text|DesktopEditors|org.gnome.Nautilus), title:^(Open.*Files?|Open [F|f]older.*|Save.*Files?|Save.*As|Save|All Files|.*wants to [open|save].*|[C|c]hoose.*)
|
||||
windowrulev2 = float, class:org.gnome.Calculator
|
||||
|
||||
# Fullscreen screensaver
|
||||
windowrulev2 = fullscreen, class:org.nomarchy.screensaver
|
||||
windowrulev2 = float, class:org.nomarchy.screensaver
|
||||
windowrulev2 = animation slide, class:org.nomarchy.screensaver
|
||||
|
||||
# No transparency on media windows
|
||||
windowrulev2 = tag -default-opacity, class:^(zoom|vlc|mpv|org.kde.kdenlive|com.obsproject.Studio|com.github.PintaProject.Pinta|imv|org.gnome.NautilusPreviewer)$
|
||||
windowrulev2 = opacity 1 1, class:^(zoom|vlc|mpv|org.kde.kdenlive|com.obsproject.Studio|com.github.PintaProject.Pinta|imv|org.gnome.NautilusPreviewer)$
|
||||
|
||||
# Popped window rounding
|
||||
windowrulev2 = rounding 8, tag:pop
|
||||
|
||||
# Prevent idle while open
|
||||
windowrulev2 = idleinhibit always, tag:noidle
|
||||
@@ -1,2 +0,0 @@
|
||||
# Prevent Telegram from stealing focus on new messages
|
||||
windowrulev2 = focusonactivate off, class:org.telegram.desktop
|
||||
@@ -1,4 +0,0 @@
|
||||
# Define terminal tag to style them uniformly
|
||||
windowrulev2 = tag +terminal, class:(Alacritty|kitty|com.mitchellh.ghostty)
|
||||
windowrulev2 = tag -default-opacity, tag:terminal
|
||||
windowrulev2 = opacity 0.97 0.9, tag:terminal
|
||||
@@ -1,2 +0,0 @@
|
||||
# Application-specific animation
|
||||
layerrule = noanim, namespace:walker
|
||||
@@ -1,6 +0,0 @@
|
||||
# Webcam overlay for screen recording
|
||||
windowrulev2 = float, title:WebcamOverlay
|
||||
windowrulev2 = pin, title:WebcamOverlay
|
||||
windowrulev2 = noinitialfocus, title:WebcamOverlay
|
||||
windowrulev2 = nodim, title:WebcamOverlay
|
||||
windowrulev2 = move (monitor_w-window_w-40) (monitor_h-window_h-40), title:WebcamOverlay
|
||||
@@ -1,17 +0,0 @@
|
||||
exec-once = uwsm-app -- hypridle
|
||||
exec-once = uwsm-app -- mako
|
||||
exec-once = nomarchy-welcome
|
||||
# exec-once = uwsm-app -- waybar
|
||||
# fcitx5 is autostarted by NixOS's i18n.inputMethod when
|
||||
# nomarchy.system.inputMethod.enable = true; no manual exec-once needed.
|
||||
# swaybg is started as a systemd user service (nomarchy-wallpaper.service)
|
||||
# so failures surface in logs and the wallpaper survives Hyprland restarts.
|
||||
exec-once = uwsm-app -- swayosd-server
|
||||
exec-once = nomarchy-on-boot
|
||||
|
||||
# Slow app launch fix -- set systemd vars
|
||||
exec-once = systemctl --user import-environment $(env | cut -d'=' -f 1)
|
||||
exec-once = dbus-update-activation-environment --systemd --all
|
||||
|
||||
# Network Manager
|
||||
exec-once = uwsm-app 'nm-applet --indicator'
|
||||
@@ -1,5 +0,0 @@
|
||||
# Copy / Paste
|
||||
bindd = SUPER, C, Universal copy, sendshortcut, CTRL, Insert,
|
||||
bindd = SUPER, V, Universal paste, sendshortcut, SHIFT, Insert,
|
||||
bindd = SUPER, X, Universal cut, sendshortcut, CTRL, X,
|
||||
bindd = SUPER CTRL, V, Clipboard manager, exec, nomarchy-launch-walker -m clipboard
|
||||
@@ -1,28 +0,0 @@
|
||||
# Only display the OSD on the currently focused monitor
|
||||
$osdclient = swayosd-client --monitor "$(hyprctl monitors -j | jq -r '.[] | select(.focused == true).name')"
|
||||
|
||||
# Laptop multimedia keys for volume and LCD brightness (with OSD)
|
||||
bindeld = ,XF86AudioRaiseVolume, Volume up, exec, $osdclient --output-volume raise
|
||||
bindeld = ,XF86AudioLowerVolume, Volume down, exec, $osdclient --output-volume lower
|
||||
bindeld = ,XF86AudioMute, Mute, exec, $osdclient --output-volume mute-toggle
|
||||
bindeld = ,XF86AudioMicMute, Mute microphone, exec, $osdclient --input-volume mute-toggle
|
||||
bindeld = ,XF86MonBrightnessUp, Brightness up, exec, nomarchy-brightness-display +5%
|
||||
bindeld = ,XF86MonBrightnessDown, Brightness down, exec, nomarchy-brightness-display 5%-
|
||||
bindeld = ,XF86KbdBrightnessUp, Keyboard brightness up, exec, nomarchy-brightness-keyboard up
|
||||
bindeld = ,XF86KbdBrightnessDown, Keyboard brightness down, exec, nomarchy-brightness-keyboard down
|
||||
bindld = ,XF86KbdLightOnOff, Keyboard backlight cycle, exec, nomarchy-brightness-keyboard cycle
|
||||
|
||||
# Precise 1% multimedia adjustments with Alt modifier
|
||||
bindeld = ALT, XF86AudioRaiseVolume, Volume up precise, exec, $osdclient --output-volume +1
|
||||
bindeld = ALT, XF86AudioLowerVolume, Volume down precise, exec, $osdclient --output-volume -1
|
||||
bindeld = ALT, XF86MonBrightnessUp, Brightness up precise, exec, nomarchy-brightness-display +1%
|
||||
bindeld = ALT, XF86MonBrightnessDown, Brightness down precise, exec, nomarchy-brightness-display 1%-
|
||||
|
||||
# Requires playerctl
|
||||
bindld = , XF86AudioNext, Next track, exec, $osdclient --playerctl next
|
||||
bindld = , XF86AudioPause, Pause, exec, $osdclient --playerctl play-pause
|
||||
bindld = , XF86AudioPlay, Play, exec, $osdclient --playerctl play-pause
|
||||
bindld = , XF86AudioPrev, Previous track, exec, $osdclient --playerctl previous
|
||||
|
||||
# Switch audio output with Super + Mute
|
||||
bindld = SUPER, XF86AudioMute, Switch audio output, exec, nomarchy-cmd-audio-switch
|
||||
@@ -1,128 +0,0 @@
|
||||
# Close windows
|
||||
bindd = SUPER, W, Close window, killactive,
|
||||
bindd = CTRL ALT, DELETE, Close all windows, exec, nomarchy-hyprland-window-close-all
|
||||
|
||||
# Control tiling
|
||||
bindd = SUPER, J, Toggle window split, layoutmsg, togglesplit
|
||||
bindd = SUPER, P, Pseudo window, pseudo, # dwindle
|
||||
bindd = SUPER, T, Toggle window floating/tiling, togglefloating,
|
||||
bindd = SUPER, F, Full screen, fullscreen, 0
|
||||
bindd = SUPER CTRL, F, Tiled full screen, fullscreenstate, 0 2
|
||||
bindd = SUPER ALT, F, Full width, fullscreen, 1
|
||||
bindd = SUPER, O, Pop window out (float & pin), exec, nomarchy-hyprland-window-pop
|
||||
bindd = SUPER, L, Toggle workspace layout, exec, nomarchy-hyprland-workspace-layout-toggle
|
||||
|
||||
# Move focus with SUPER + arrow keys
|
||||
bindd = SUPER, LEFT, Move window focus left, movefocus, l
|
||||
bindd = SUPER, RIGHT, Move window focus right, movefocus, r
|
||||
bindd = SUPER, UP, Move window focus up, movefocus, u
|
||||
bindd = SUPER, DOWN, Move window focus down, movefocus, d
|
||||
|
||||
# Switch workspaces with SUPER + [1-9; 0]
|
||||
bindd = SUPER, code:10, Switch to workspace 1, workspace, 1
|
||||
bindd = SUPER, code:11, Switch to workspace 2, workspace, 2
|
||||
bindd = SUPER, code:12, Switch to workspace 3, workspace, 3
|
||||
bindd = SUPER, code:13, Switch to workspace 4, workspace, 4
|
||||
bindd = SUPER, code:14, Switch to workspace 5, workspace, 5
|
||||
bindd = SUPER, code:15, Switch to workspace 6, workspace, 6
|
||||
bindd = SUPER, code:16, Switch to workspace 7, workspace, 7
|
||||
bindd = SUPER, code:17, Switch to workspace 8, workspace, 8
|
||||
bindd = SUPER, code:18, Switch to workspace 9, workspace, 9
|
||||
bindd = SUPER, code:19, Switch to workspace 10, workspace, 10
|
||||
|
||||
# Move active window to a workspace with SUPER + SHIFT + [1-9; 0]
|
||||
bindd = SUPER SHIFT, code:10, Move window to workspace 1, movetoworkspace, 1
|
||||
bindd = SUPER SHIFT, code:11, Move window to workspace 2, movetoworkspace, 2
|
||||
bindd = SUPER SHIFT, code:12, Move window to workspace 3, movetoworkspace, 3
|
||||
bindd = SUPER SHIFT, code:13, Move window to workspace 4, movetoworkspace, 4
|
||||
bindd = SUPER SHIFT, code:14, Move window to workspace 5, movetoworkspace, 5
|
||||
bindd = SUPER SHIFT, code:15, Move window to workspace 6, movetoworkspace, 6
|
||||
bindd = SUPER SHIFT, code:16, Move window to workspace 7, movetoworkspace, 7
|
||||
bindd = SUPER SHIFT, code:17, Move window to workspace 8, movetoworkspace, 8
|
||||
bindd = SUPER SHIFT, code:18, Move window to workspace 9, movetoworkspace, 9
|
||||
bindd = SUPER SHIFT, code:19, Move window to workspace 10, movetoworkspace, 10
|
||||
|
||||
# Move active window silently to a workspace with SUPER + SHIFT + ALT + [1-9; 0]
|
||||
bindd = SUPER SHIFT ALT, code:10, Move window silently to workspace 1, movetoworkspacesilent, 1
|
||||
bindd = SUPER SHIFT ALT, code:11, Move window silently to workspace 2, movetoworkspacesilent, 2
|
||||
bindd = SUPER SHIFT ALT, code:12, Move window silently to workspace 3, movetoworkspacesilent, 3
|
||||
bindd = SUPER SHIFT ALT, code:13, Move window silently to workspace 4, movetoworkspacesilent, 4
|
||||
bindd = SUPER SHIFT ALT, code:14, Move window silently to workspace 5, movetoworkspacesilent, 5
|
||||
bindd = SUPER SHIFT ALT, code:15, Move window silently to workspace 6, movetoworkspacesilent, 6
|
||||
bindd = SUPER SHIFT ALT, code:16, Move window silently to workspace 7, movetoworkspacesilent, 7
|
||||
bindd = SUPER SHIFT ALT, code:17, Move window silently to workspace 8, movetoworkspacesilent, 8
|
||||
bindd = SUPER SHIFT ALT, code:18, Move window silently to workspace 9, movetoworkspacesilent, 9
|
||||
bindd = SUPER SHIFT ALT, code:19, Move window silently to workspace 10, movetoworkspacesilent, 10
|
||||
|
||||
# Control scratchpad
|
||||
bindd = SUPER, S, Toggle scratchpad, togglespecialworkspace, scratchpad
|
||||
bindd = SUPER ALT, S, Move window to scratchpad, movetoworkspacesilent, special:scratchpad
|
||||
|
||||
# TAB between workspaces
|
||||
bindd = SUPER, TAB, Next workspace, workspace, e+1
|
||||
bindd = SUPER SHIFT, TAB, Previous workspace, workspace, e-1
|
||||
bindd = SUPER CTRL, TAB, Former workspace, workspace, previous
|
||||
|
||||
# Move workspaces to other monitors
|
||||
bindd = SUPER SHIFT ALT, LEFT, Move workspace to left monitor, movecurrentworkspacetomonitor, l
|
||||
bindd = SUPER SHIFT ALT, RIGHT, Move workspace to right monitor, movecurrentworkspacetomonitor, r
|
||||
bindd = SUPER SHIFT ALT, UP, Move workspace to up monitor, movecurrentworkspacetomonitor, u
|
||||
bindd = SUPER SHIFT ALT, DOWN, Move workspace to down monitor, movecurrentworkspacetomonitor, d
|
||||
|
||||
# Swap active window with the one next to it with SUPER + SHIFT + arrow keys
|
||||
bindd = SUPER SHIFT, LEFT, Swap window to the left, swapwindow, l
|
||||
bindd = SUPER SHIFT, RIGHT, Swap window to the right, swapwindow, r
|
||||
bindd = SUPER SHIFT, UP, Swap window up, swapwindow, u
|
||||
bindd = SUPER SHIFT, DOWN, Swap window down, swapwindow, d
|
||||
|
||||
# Cycle through applications on active workspace
|
||||
bindd = ALT, TAB, Cycle to next window, cyclenext
|
||||
bindd = ALT SHIFT, TAB, Cycle to prev window, cyclenext, prev
|
||||
bindd = ALT, TAB, Reveal active window on top, bringactivetotop
|
||||
bindd = ALT SHIFT, TAB, Reveal active window on top, bringactivetotop
|
||||
|
||||
# Resize active window
|
||||
bindd = SUPER, code:20, Expand window left, resizeactive, -100 0 # - key
|
||||
bindd = SUPER, code:21, Shrink window left, resizeactive, 100 0 # = key
|
||||
bindd = SUPER SHIFT, code:20, Shrink window up, resizeactive, 0 -100
|
||||
bindd = SUPER SHIFT, code:21, Expand window down, resizeactive, 0 100
|
||||
|
||||
# Scroll through existing workspaces with SUPER + scroll
|
||||
bindd = SUPER, mouse_down, Scroll active workspace forward, workspace, e+1
|
||||
bindd = SUPER, mouse_up, Scroll active workspace backward, workspace, e-1
|
||||
|
||||
# Move/resize windows with mainMod + LMB/RMB and dragging
|
||||
bindmd = SUPER, mouse:272, Move window, movewindow
|
||||
bindmd = SUPER, mouse:273, Resize window, resizewindow
|
||||
|
||||
# Toggle groups
|
||||
bindd = SUPER, G, Toggle window grouping, togglegroup
|
||||
bindd = SUPER ALT, G, Move active window out of group, moveoutofgroup
|
||||
|
||||
# Join groups
|
||||
bindd = SUPER ALT, LEFT, Move window to group on left, moveintogroup, l
|
||||
bindd = SUPER ALT, RIGHT, Move window to group on right, moveintogroup, r
|
||||
bindd = SUPER ALT, UP, Move window to group on top, moveintogroup, u
|
||||
bindd = SUPER ALT, DOWN, Move window to group on bottom, moveintogroup, d
|
||||
|
||||
# Navigate a single set of grouped windows
|
||||
bindd = SUPER ALT, TAB, Next window in group, changegroupactive, f
|
||||
bindd = SUPER ALT SHIFT, TAB, Previous window in group, changegroupactive, b
|
||||
|
||||
# Window navigation for grouped windows
|
||||
bindd = SUPER CTRL, LEFT, Move grouped window focus left, changegroupactive, b
|
||||
bindd = SUPER CTRL, RIGHT, Move grouped window focus right, changegroupactive, f
|
||||
|
||||
# Scroll through a set of grouped windows with SUPER + ALT + scroll
|
||||
bindd = SUPER ALT, mouse_down, Next window in group, changegroupactive, f
|
||||
bindd = SUPER ALT, mouse_up, Previous window in group, changegroupactive, b
|
||||
|
||||
# Activate window in a group by number
|
||||
bindd = SUPER ALT, code:10, Switch to group window 1, changegroupactive, 1
|
||||
bindd = SUPER ALT, code:11, Switch to group window 2, changegroupactive, 2
|
||||
bindd = SUPER ALT, code:12, Switch to group window 3, changegroupactive, 3
|
||||
bindd = SUPER ALT, code:13, Switch to group window 4, changegroupactive, 4
|
||||
bindd = SUPER ALT, code:14, Switch to group window 5, changegroupactive, 5
|
||||
|
||||
# Cycle monitor scaling
|
||||
bindd = SUPER, Slash, Cycle monitor scaling, exec, nomarchy-hyprland-monitor-scaling-cycle
|
||||
@@ -1,59 +0,0 @@
|
||||
# Menus
|
||||
bindd = SUPER, SPACE, Launch apps, exec, nomarchy-launch-walker
|
||||
bindd = SUPER CTRL, E, Emoji picker, exec, nomarchy-menu symbols
|
||||
bindd = SUPER CTRL, C, Capture menu, exec, nomarchy-menu capture
|
||||
bindd = SUPER CTRL, O, Toggle menu, exec, nomarchy-menu toggle
|
||||
bindd = SUPER ALT, SPACE, Toggle top bar, exec, nomarchy-toggle-waybar
|
||||
bindd = SUPER, ESCAPE, System menu, exec, nomarchy-menu system
|
||||
bindld = , XF86PowerOff, Power menu, exec, nomarchy-menu system
|
||||
bindd = SUPER, K, Show key bindings, exec, nomarchy-menu-keybindings
|
||||
bindd = , XF86Calculator, Calculator, exec, gnome-calculator
|
||||
|
||||
# Aesthetics
|
||||
bindd = SUPER SHIFT, SPACE, Nomarchy menu, exec, nomarchy-menu
|
||||
bindd = SUPER CTRL, SPACE, Theme background menu, exec, nomarchy-menu background
|
||||
bindd = SUPER SHIFT CTRL, SPACE, Theme menu, exec, nomarchy-menu theme
|
||||
bindd = SUPER, BACKSPACE, Toggle window transparency, exec, nomarchy-hyprland-active-window-transparency-toggle
|
||||
bindd = SUPER SHIFT, BACKSPACE, Toggle window gaps, exec, nomarchy-hyprland-window-gaps-toggle
|
||||
bindd = SUPER CTRL, BACKSPACE, Toggle single-window square aspect, exec, nomarchy-hyprland-window-single-square-aspect-toggle
|
||||
|
||||
# Notifications
|
||||
bindd = SUPER, COMMA, Dismiss last notification, exec, makoctl dismiss
|
||||
bindd = SUPER SHIFT, COMMA, Dismiss all notifications, exec, makoctl dismiss --all
|
||||
bindd = SUPER CTRL, COMMA, Toggle silencing notifications, exec, nomarchy-toggle-notification-silencing
|
||||
bindd = SUPER ALT, COMMA, Invoke last notification, exec, makoctl invoke
|
||||
bindd = SUPER SHIFT ALT, COMMA, Restore last notification, exec, makoctl restore
|
||||
|
||||
# Toggles
|
||||
bindd = SUPER CTRL, I, Toggle locking on idle, exec, nomarchy-toggle-idle
|
||||
bindd = SUPER CTRL, N, Toggle nightlight, exec, nomarchy-toggle-nightlight
|
||||
|
||||
# Control Apple Display brightness
|
||||
bindd = CTRL, F1, Apple Display brightness down, exec, nomarchy-brightness-display-apple -5000
|
||||
bindd = CTRL, F2, Apple Display brightness up, exec, nomarchy-brightness-display-apple +5000
|
||||
bindd = SHIFT CTRL, F2, Apple Display full brightness, exec, nomarchy-brightness-display-apple +60000
|
||||
|
||||
# Captures
|
||||
bindd = , PRINT, Screenshot, exec, nomarchy-cmd-screenshot
|
||||
bindd = ALT, PRINT, Screenrecording, exec, nomarchy-menu screenrecord
|
||||
bindd = SUPER, PRINT, Color picker, exec, pkill hyprpicker || hyprpicker -a
|
||||
|
||||
# File sharing
|
||||
bindd = SUPER CTRL, S, Share, exec, nomarchy-menu share
|
||||
|
||||
# Waybar-less information
|
||||
bindd = SUPER CTRL ALT, T, Show time, exec, notify-send -u low " $(date +"%A %H:%M · %d %B %Y · Week %V")"
|
||||
bindd = SUPER CTRL ALT, B, Show battery remaining, exec, notify-send -u low "$(nomarchy-battery-status)"
|
||||
|
||||
# Control panels
|
||||
bindd = SUPER CTRL, A, Audio controls, exec, nomarchy-launch-audio
|
||||
bindd = SUPER CTRL, B, Bluetooth controls, exec, nomarchy-launch-bluetooth
|
||||
bindd = SUPER CTRL, W, Wifi controls, exec, nomarchy-launch-wifi
|
||||
bindd = SUPER CTRL, T, Activity, exec, nomarchy-launch-tui btop
|
||||
|
||||
# Zoom
|
||||
bindd = SUPER CTRL, Z, Zoom in, exec, hyprctl keyword cursor:zoom_factor $(hyprctl getoption cursor:zoom_factor -j | jq '.float + 1')
|
||||
bindd = SUPER CTRL ALT, Z, Reset zoom, exec, hyprctl keyword cursor:zoom_factor 1
|
||||
|
||||
# Lock system
|
||||
bindd = SUPER CTRL, L, Lock system, exec, nomarchy-lock-screen
|
||||
@@ -1,12 +0,0 @@
|
||||
# Hyprland Color Configuration (Visual)
|
||||
# This file contains only color-related settings.
|
||||
# It's sourced AFTER theme colors are applied, allowing theme-specific overrides.
|
||||
|
||||
# These are placeholder values - actual colors come from the active theme
|
||||
# via ~/.config/nomarchy/current/theme/hyprland.conf
|
||||
|
||||
# Border colors (set by theme-loader based on active theme)
|
||||
# The theme's hyprland.conf will define $activeBorderColor and $inactiveBorderColor
|
||||
|
||||
# Group bar colors (set by theme)
|
||||
# Themes can override group bar colors in their hyprland.conf
|
||||
@@ -1,29 +0,0 @@
|
||||
# Cursor size
|
||||
env = XCURSOR_SIZE,24
|
||||
env = HYPRCURSOR_SIZE,24
|
||||
|
||||
# Force all apps to use Wayland
|
||||
env = GDK_BACKEND,wayland,x11,*
|
||||
env = QT_QPA_PLATFORM,wayland;xcb
|
||||
env = QT_STYLE_OVERRIDE,kvantum
|
||||
env = SDL_VIDEODRIVER,wayland,x11
|
||||
env = MOZ_ENABLE_WAYLAND,1
|
||||
env = ELECTRON_OZONE_PLATFORM_HINT,wayland
|
||||
env = OZONE_PLATFORM,wayland
|
||||
env = XDG_SESSION_TYPE,wayland
|
||||
|
||||
# Allow better support for screen sharing (Google Meet, Discord, etc)
|
||||
env = XDG_CURRENT_DESKTOP,Hyprland
|
||||
env = XDG_SESSION_DESKTOP,Hyprland
|
||||
|
||||
xwayland {
|
||||
force_zero_scaling = true
|
||||
}
|
||||
|
||||
# Use XCompose file
|
||||
env = XCOMPOSEFILE,~/.XCompose
|
||||
|
||||
# Don't show update on first launch
|
||||
ecosystem {
|
||||
no_update_news = true
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
# Refer to https://wiki.hyprland.org/Configuring/Variables/
|
||||
|
||||
# Variables
|
||||
$activeBorderColor = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
$inactiveBorderColor = rgba(595959aa)
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#general
|
||||
general {
|
||||
gaps_in = 5
|
||||
gaps_out = 10
|
||||
|
||||
border_size = 2
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors
|
||||
col.active_border = $activeBorderColor
|
||||
col.inactive_border = $inactiveBorderColor
|
||||
|
||||
# Set to true enable resizing windows by clicking and dragging on borders and gaps
|
||||
resize_on_border = false
|
||||
|
||||
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||
allow_tearing = false
|
||||
|
||||
layout = dwindle
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#decoration
|
||||
decoration {
|
||||
rounding = 0
|
||||
|
||||
shadow {
|
||||
enabled = true
|
||||
range = 2
|
||||
render_power = 3
|
||||
color = rgba(1a1a1aee)
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#blur
|
||||
blur {
|
||||
enabled = true
|
||||
size = 2
|
||||
passes = 2
|
||||
special = true
|
||||
brightness = 0.60
|
||||
contrast = 0.75
|
||||
}
|
||||
}
|
||||
|
||||
# https://wiki.hypr.land/Configuring/Variables/#group
|
||||
group {
|
||||
col.border_active = $activeBorderColor
|
||||
col.border_inactive = $inactiveBorderColor
|
||||
col.border_locked_active = -1
|
||||
col.border_locked_inactive = -1
|
||||
|
||||
groupbar {
|
||||
font_size = 12
|
||||
font_family = monospace
|
||||
font_weight_active = ultraheavy
|
||||
font_weight_inactive = normal
|
||||
|
||||
indicator_height = 0
|
||||
indicator_gap = 5
|
||||
height = 22
|
||||
gaps_in = 5
|
||||
gaps_out = 0
|
||||
|
||||
text_color = rgb(ffffff)
|
||||
text_color_inactive = rgba(ffffff90)
|
||||
col.active = rgba(00000040)
|
||||
col.inactive = rgba(00000020)
|
||||
|
||||
gradients = true
|
||||
gradient_rounding = 0
|
||||
gradient_round_only_edges = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#animations
|
||||
animations {
|
||||
enabled = yes
|
||||
|
||||
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
|
||||
|
||||
bezier = easeOutQuint,0.23,1,0.32,1
|
||||
bezier = easeInOutCubic,0.65,0.05,0.36,1
|
||||
bezier = linear,0,0,1,1
|
||||
bezier = almostLinear,0.5,0.5,0.75,1.0
|
||||
bezier = quick,0.15,0,0.1,1
|
||||
|
||||
animation = global, 1, 10, default
|
||||
animation = border, 1, 5.39, easeOutQuint
|
||||
animation = windows, 1, 4.79, easeOutQuint
|
||||
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
|
||||
animation = windowsOut, 1, 1.49, linear, popin 87%
|
||||
animation = fadeIn, 1, 1.73, almostLinear
|
||||
animation = fadeOut, 1, 1.46, almostLinear
|
||||
animation = fade, 1, 3.03, quick
|
||||
animation = layers, 1, 3.81, easeOutQuint
|
||||
animation = layersIn, 1, 4, easeOutQuint, fade
|
||||
animation = layersOut, 1, 1.5, linear, fade
|
||||
animation = fadeLayersIn, 1, 1.79, almostLinear
|
||||
animation = fadeLayersOut, 1, 1.39, almostLinear
|
||||
animation = workspaces, 0, 0, ease
|
||||
animation = specialWorkspace, 1, 4, easeOutQuint, slidevert
|
||||
}
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
||||
dwindle {
|
||||
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
||||
preserve_split = true # You probably want this
|
||||
force_split = 2 # Always split on the right
|
||||
}
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
|
||||
master {
|
||||
new_status = master
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
||||
misc {
|
||||
disable_hyprland_logo = true
|
||||
disable_splash_rendering = true
|
||||
disable_scale_notification = true
|
||||
focus_on_activate = true
|
||||
}
|
||||
|
||||
# https://wiki.hypr.land/Configuring/Variables/#cursor
|
||||
cursor {
|
||||
hide_on_key_press = true
|
||||
warp_on_change_workspace = 1
|
||||
}
|
||||
|
||||
# Auto toggle scratchpad on switching workspace from scratchpad
|
||||
binds {
|
||||
hide_special_on_workspace_change = true
|
||||
}
|
||||
|
||||
# Style Gum confirm to match terminal theme
|
||||
env = GUM_CONFIRM_PROMPT_FOREGROUND,6 # Cyan
|
||||
env = GUM_CONFIRM_SELECTED_FOREGROUND,0 # Black
|
||||
env = GUM_CONFIRM_SELECTED_BACKGROUND,2 # Green
|
||||
env = GUM_CONFIRM_UNSELECTED_FOREGROUND,7 # White
|
||||
env = GUM_CONFIRM_UNSELECTED_BACKGROUND,8 # Dark grey
|
||||
# Dark grey
|
||||
@@ -1,15 +0,0 @@
|
||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||
# Hyprland 0.53+ syntax
|
||||
#windowrulev2 = suppressevent maximize, class:.*
|
||||
|
||||
# Tag all windows for default opacity (apps can override with -default-opacity tag)
|
||||
#windowrulev2 = tag +default-opacity, class:.*
|
||||
|
||||
# Fix some dragging issues with XWayland
|
||||
#windowrulev2 = nofocus, class:^$, title:^$, xwayland:1, float:1, fullscreen:0, pin:0
|
||||
|
||||
# App-specific tweaks (may remove default-opacity tag)
|
||||
source = ~/.config/nomarchy/default/hypr/apps.conf
|
||||
|
||||
# Apply default opacity after apps have had a chance to opt out
|
||||
#windowrulev2 = opacity 0.97 0.9, tag:default-opacity
|
||||
@@ -1,37 +0,0 @@
|
||||
anchor=top-right
|
||||
default-timeout=5000
|
||||
width=420
|
||||
outer-margin=20
|
||||
padding=10,15
|
||||
border-size=2
|
||||
max-icon-size=32
|
||||
font=sans-serif 14px
|
||||
|
||||
[app-name=Spotify]
|
||||
invisible=1
|
||||
|
||||
[mode=do-not-disturb]
|
||||
invisible=true
|
||||
|
||||
[mode=do-not-disturb app-name=notify-send]
|
||||
invisible=false
|
||||
|
||||
[urgency=critical]
|
||||
default-timeout=0
|
||||
layer=overlay
|
||||
|
||||
[summary~="Setup Wi-Fi"]
|
||||
on-button-left=exec sh -c 'nomarchy-notification-dismiss "Setup Wi-Fi"; nomarchy-launch-wifi'
|
||||
on-click=exec sh -c 'nomarchy-notification-dismiss "Setup Wi-Fi"; nomarchy-launch-wifi'
|
||||
|
||||
[summary~="Update System"]
|
||||
on-button-left=exec sh -c 'nomarchy-notification-dismiss "Update System"; nomarchy-launch-floating-terminal-with-presentation nomarchy-update'
|
||||
on-click=exec sh -c 'nomarchy-notification-dismiss "Update System"; nomarchy-launch-floating-terminal-with-presentation nomarchy-update'
|
||||
|
||||
[summary~="Learn Keybindings"]
|
||||
on-button-left=exec sh -c 'nomarchy-notification-dismiss "Learn Keybindings"; nomarchy-menu-keybindings'
|
||||
on-click=exec sh -c 'nomarchy-notification-dismiss "Learn Keybindings"; nomarchy-menu-keybindings'
|
||||
|
||||
[summary~="Screenshot copied & saved"]
|
||||
max-icon-size=80
|
||||
format=<b>%s</b>\n%b
|
||||
@@ -1,3 +0,0 @@
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
@@ -1,156 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"></requires>
|
||||
<object class="GtkWindow" id="Window">
|
||||
<style>
|
||||
<class name="window"></class>
|
||||
</style>
|
||||
<property name="resizable">true</property>
|
||||
<property name="title">Walker</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="BoxWrapper">
|
||||
<style>
|
||||
<class name="box-wrapper"></class>
|
||||
</style>
|
||||
<property name="width-request">644</property>
|
||||
<property name="overflow">hidden</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="halign">center</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="Box">
|
||||
<style>
|
||||
<class name="box"></class>
|
||||
</style>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="hexpand-set">true</property>
|
||||
<property name="hexpand">true</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="SearchContainer">
|
||||
<style>
|
||||
<class name="search-container"></class>
|
||||
</style>
|
||||
<property name="overflow">hidden</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="halign">fill</property>
|
||||
<property name="hexpand-set">true</property>
|
||||
<property name="hexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="Input">
|
||||
<style>
|
||||
<class name="input"></class>
|
||||
</style>
|
||||
<property name="halign">fill</property>
|
||||
<property name="hexpand-set">true</property>
|
||||
<property name="hexpand">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="ContentContainer">
|
||||
<style>
|
||||
<class name="content-container"></class>
|
||||
</style>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="spacing">10</property>
|
||||
<property name="vexpand">true</property>
|
||||
<property name="vexpand-set">true</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="ElephantHint">
|
||||
<style>
|
||||
<class name="elephant-hint"></class>
|
||||
</style>
|
||||
<property name="hexpand">true</property>
|
||||
<property name="height-request">100</property>
|
||||
<property name="label">Waiting for elephant...</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="Placeholder">
|
||||
<style>
|
||||
<class name="placeholder"></class>
|
||||
</style>
|
||||
<property name="label">No Results</property>
|
||||
<property name="yalign">0.0</property>
|
||||
<property name="hexpand">true</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="Scroll">
|
||||
<style>
|
||||
<class name="scroll"></class>
|
||||
</style>
|
||||
<property name="hexpand">true</property>
|
||||
<property name="can_focus">false</property>
|
||||
<property name="overlay-scrolling">true</property>
|
||||
<property name="max-content-width">600</property>
|
||||
<property name="max-content-height">300</property>
|
||||
<property name="min-content-height">0</property>
|
||||
<property name="propagate-natural-height">true</property>
|
||||
<property name="propagate-natural-width">true</property>
|
||||
<property name="hscrollbar-policy">automatic</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkGridView" id="List">
|
||||
<style>
|
||||
<class name="list"></class>
|
||||
</style>
|
||||
<property name="max_columns">1</property>
|
||||
<property name="can_focus">false</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="Preview">
|
||||
<style>
|
||||
<class name="preview"></class>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="Keybinds">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="margin-top">10</property>
|
||||
<style>
|
||||
<class name="keybinds"></class>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkBox" id="GlobalKeybinds">
|
||||
<property name="spacing">10</property>
|
||||
<style>
|
||||
<class name="global-keybinds"></class>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="ItemKeybinds">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="spacing">10</property>
|
||||
<style>
|
||||
<class name="item-keybinds"></class>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="Error">
|
||||
<style>
|
||||
<class name="error"></class>
|
||||
</style>
|
||||
<property name="xalign">0</property>
|
||||
<property name="visible">false</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,117 +0,0 @@
|
||||
@import "../../../../../../../.config/nomarchy/current/theme/walker.css";
|
||||
|
||||
* {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: monospace;
|
||||
font-size: 18px;
|
||||
color: @text;
|
||||
}
|
||||
|
||||
scrollbar {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.normal-icons {
|
||||
-gtk-icon-size: 16px;
|
||||
}
|
||||
|
||||
.large-icons {
|
||||
-gtk-icon-size: 32px;
|
||||
}
|
||||
|
||||
.box-wrapper {
|
||||
background: alpha(@base, 0.95);
|
||||
padding: 20px;
|
||||
border: 2px solid @border;
|
||||
}
|
||||
|
||||
.preview-box {
|
||||
}
|
||||
|
||||
.box {
|
||||
}
|
||||
|
||||
.search-container {
|
||||
background: @base;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.input placeholder {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.input {
|
||||
}
|
||||
|
||||
.input:focus,
|
||||
.input:active {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
}
|
||||
|
||||
.scroll {
|
||||
}
|
||||
|
||||
.list {
|
||||
}
|
||||
|
||||
child,
|
||||
child > * {
|
||||
}
|
||||
|
||||
child:hover .item-box {
|
||||
}
|
||||
|
||||
child:selected .item-box {
|
||||
background-color: @selected-background;
|
||||
}
|
||||
|
||||
child:selected .item-box * {
|
||||
color: @selected-text;
|
||||
}
|
||||
|
||||
.item-box {
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.item-text-box {
|
||||
all: unset;
|
||||
padding: 14px 0;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
}
|
||||
|
||||
.item-subtext {
|
||||
font-size: 0px;
|
||||
min-height: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
margin-right: 14px;
|
||||
-gtk-icon-transform: scale(0.9);
|
||||
}
|
||||
|
||||
.current {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.keybind-hints {
|
||||
background: @background;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Name=Walker
|
||||
Comment=Walker Service
|
||||
Exec=walker --gapplication-service
|
||||
StartupNotify=false
|
||||
Terminal=false
|
||||
Type=Application
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if pgrep -x hypridle >/dev/null; then
|
||||
echo '{"text": ""}'
|
||||
else
|
||||
echo '{"text": "", "tooltip": "Idle lock disabled", "class": "active"}'
|
||||
fi
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if makoctl mode | grep -q 'do-not-disturb'; then
|
||||
echo '{"text": "", "tooltip": "Notifications silenced", "class": "active"}'
|
||||
else
|
||||
echo '{"text": ""}'
|
||||
fi
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if pgrep -f "^gpu-screen-recorder" >/dev/null; then
|
||||
echo '{"text": "", "tooltip": "Stop recording", "class": "active"}'
|
||||
else
|
||||
echo '{"text": ""}'
|
||||
fi
|
||||
@@ -1,18 +0,0 @@
|
||||
## Use software volume control for all ALSA devices.
|
||||
## This prevents hardware mixer quirks (like muffled audio on Realtek codecs)
|
||||
## and provides consistent volume behavior across all hardware.
|
||||
|
||||
monitor.alsa.rules = [
|
||||
{
|
||||
matches = [
|
||||
{
|
||||
device.name = "~alsa_card.*"
|
||||
}
|
||||
]
|
||||
actions = {
|
||||
update-props = {
|
||||
api.alsa.soft-mixer = true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
include "%L"
|
||||
|
||||
# Emoji
|
||||
<Multi_key> <m> <s> : "😄" # smile
|
||||
<Multi_key> <m> <c> : "😂" # cry
|
||||
<Multi_key> <m> <l> : "😍" # love
|
||||
<Multi_key> <m> <v> : "✌️" # victory
|
||||
<Multi_key> <m> <h> : "❤️" # heart
|
||||
<Multi_key> <m> <y> : "👍" # yes
|
||||
<Multi_key> <m> <n> : "👎" # no
|
||||
<Multi_key> <m> <f> : "🖕" # fuck
|
||||
<Multi_key> <m> <w> : "🤞" # wish
|
||||
<Multi_key> <m> <r> : "🤘" # rock
|
||||
<Multi_key> <m> <k> : "😘" # kiss
|
||||
<Multi_key> <m> <e> : "🙄" # eyeroll
|
||||
<Multi_key> <m> <d> : "🤤" # droll
|
||||
<Multi_key> <m> <m> : "💰" # money
|
||||
<Multi_key> <m> <x> : "🎉" # xellebrate
|
||||
<Multi_key> <m> <1> : "💯" # 100%
|
||||
<Multi_key> <m> <t> : "🥂" # toast
|
||||
<Multi_key> <m> <p> : "🙏" # pray
|
||||
<Multi_key> <m> <i> : "😉" # wink
|
||||
<Multi_key> <m> <o> : "👌" # OK
|
||||
<Multi_key> <m> <g> : "👋" # greeting
|
||||
<Multi_key> <m> <a> : "💪" # arm
|
||||
<Multi_key> <m> <b> : "🤯" # blowing
|
||||
|
||||
# Typography
|
||||
<Multi_key> <space> <space> : "—"
|
||||
@@ -1,20 +0,0 @@
|
||||
# Overwrite parts of the nomarchy-menu with user-specific submenus.
|
||||
# See $OMARCHY_PATH/bin/nomarchy-menu for functions that can be overwritten.
|
||||
#
|
||||
# WARNING: Overwritten functions will obviously not be updated when Nomarchy changes.
|
||||
#
|
||||
# Example of minimal system menu:
|
||||
#
|
||||
# show_system_menu() {
|
||||
# case $(menu "System" " Lock\n Shutdown") in
|
||||
# *Lock*) nomarchy-lock-screen ;;
|
||||
# *Shutdown*) nomarchy-system-shutdown ;;
|
||||
# *) back_to show_main_menu ;;
|
||||
# esac
|
||||
# }
|
||||
#
|
||||
# Example of overriding just the about menu action: (Using zsh instead of bash (default))
|
||||
#
|
||||
# show_about() {
|
||||
# exec nomarchy-launch-or-focus-tui "zsh -c 'fastfetch; read -k 1'"
|
||||
# }
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This hook is called with the current battery percentage when the low battery
|
||||
# notification is sent. To put it into use, remove .sample from the name.
|
||||
|
||||
SOUND_FILE="/usr/share/sounds/freedesktop/stereo/dialog-warning.oga"
|
||||
|
||||
if nomarchy-cmd-present mpv && [[ -f $SOUND_FILE ]]; then
|
||||
mpv --no-video "$SOUND_FILE" >/dev/null 2>&1
|
||||
fi
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This hook is called with the snake-cased name of the font that has just been set.
|
||||
# To put it into use, remove .sample from the name.
|
||||
|
||||
# Example: Show the name of the theme that was just set.
|
||||
# notify-send -u low "New font" "Your new font is $1"
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This hook is called after the nomarchy-welcome wizard finishes successfully.
|
||||
# Use it to run any custom first-boot logic (e.g. cloning your dotfiles repo,
|
||||
# setting up SSH keys, or launching specific initial apps).
|
||||
|
||||
# Example: Open the manual and show a notification
|
||||
# nomarchy-manual
|
||||
# notify-send "Welcome home" "Your Nomarchy system is ready to use."
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This hook is called after an Nomarchy system update has been performed.
|
||||
# To put it into use, remove .sample from the name.
|
||||
|
||||
# Example: Show notification after the system has been updated.
|
||||
# notify-send -u low "Update Performed" "Your system is now up to date"
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This hook is called with the snake-cased name of the theme that has just been set.
|
||||
# To put it into use, remove .sample from the name.
|
||||
|
||||
# Example: Show the name of the theme that was just set.
|
||||
# notify-send -u low "New theme" "Your new theme is $1"
|
||||
@@ -1,86 +0,0 @@
|
||||
# Nomarchy User Template Example: Alacritty
|
||||
#
|
||||
# This is a sample template file demonstrating how to create custom themed
|
||||
# configurations. Templates use placeholder variables that get replaced with
|
||||
# your current theme's colors when you switch themes.
|
||||
#
|
||||
# HOW TO USE:
|
||||
# 1. Rename this file to: alacritty.toml.tpl (remove the .sample extension)
|
||||
# 2. Customize it as needed
|
||||
# 3. Change your theme to apply the template
|
||||
#
|
||||
# User templates in ~/.config/nomarchy/themed/ take priority over the built-in
|
||||
# templates in the Nomarchy default/themed/ directory. This lets you override
|
||||
# any built-in template or create templates for applications not included
|
||||
# by default.
|
||||
#
|
||||
# AVAILABLE VARIABLES:
|
||||
# {{ background }} - Main background color (e.g., "#1a1b26")
|
||||
# {{ foreground }} - Main foreground/text color
|
||||
# {{ cursor }} - Cursor color
|
||||
# {{ accent }} - Theme accent color
|
||||
# {{ selection_background }} - Selection highlight background
|
||||
# {{ selection_foreground }} - Selection highlight foreground
|
||||
#
|
||||
# {{ color0 }} through {{ color15 }} - Standard 16-color terminal palette
|
||||
# color0-7: Normal colors (black, red, green, yellow, blue, magenta, cyan, white)
|
||||
# color8-15: Bright variants
|
||||
#
|
||||
# VARIABLE MODIFIERS:
|
||||
# {{ variable_strip }} - Hex color without the # prefix (e.g., "1a1b26")
|
||||
# {{ variable_rgb }} - Decimal RGB values (e.g., "26,27,38")
|
||||
#
|
||||
# Example using modifiers:
|
||||
# background = "{{ background }}" -> background = "#1a1b26"
|
||||
# background = "{{ background_strip }}" -> background = "1a1b26"
|
||||
# background = "rgb({{ background_rgb }})" -> background = "rgb(26,27,38)"
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
[colors.primary]
|
||||
background = "{{ background }}"
|
||||
foreground = "{{ foreground }}"
|
||||
|
||||
[colors.cursor]
|
||||
text = "{{ background }}"
|
||||
cursor = "{{ cursor }}"
|
||||
|
||||
[colors.vi_mode_cursor]
|
||||
text = "{{ background }}"
|
||||
cursor = "{{ cursor }}"
|
||||
|
||||
[colors.search.matches]
|
||||
foreground = "{{ background }}"
|
||||
background = "{{ color3 }}"
|
||||
|
||||
[colors.search.focused_match]
|
||||
foreground = "{{ background }}"
|
||||
background = "{{ color1 }}"
|
||||
|
||||
[colors.footer_bar]
|
||||
foreground = "{{ background }}"
|
||||
background = "{{ foreground }}"
|
||||
|
||||
[colors.selection]
|
||||
text = "{{ selection_foreground }}"
|
||||
background = "{{ selection_background }}"
|
||||
|
||||
[colors.normal]
|
||||
black = "{{ color0 }}"
|
||||
red = "{{ color1 }}"
|
||||
green = "{{ color2 }}"
|
||||
yellow = "{{ color3 }}"
|
||||
blue = "{{ color4 }}"
|
||||
magenta = "{{ color5 }}"
|
||||
cyan = "{{ color6 }}"
|
||||
white = "{{ color7 }}"
|
||||
|
||||
[colors.bright]
|
||||
black = "{{ color8 }}"
|
||||
red = "{{ color9 }}"
|
||||
green = "{{ color10 }}"
|
||||
yellow = "{{ color11 }}"
|
||||
blue = "{{ color12 }}"
|
||||
magenta = "{{ color13 }}"
|
||||
cyan = "{{ color14 }}"
|
||||
white = "{{ color15 }}"
|
||||
@@ -1,32 +0,0 @@
|
||||
add_newline = true
|
||||
command_timeout = 200
|
||||
format = "[$directory$git_branch$git_status]($style)$character"
|
||||
|
||||
[character]
|
||||
error_symbol = "[✗](bold cyan)"
|
||||
success_symbol = "[❯](bold cyan)"
|
||||
|
||||
[directory]
|
||||
truncation_length = 2
|
||||
truncation_symbol = "…/"
|
||||
repo_root_style = "bold cyan"
|
||||
repo_root_format = "[$repo_root]($repo_root_style)[$path]($style)[$read_only]($read_only_style) "
|
||||
|
||||
[git_branch]
|
||||
format = "[$branch]($style) "
|
||||
style = "italic cyan"
|
||||
|
||||
[git_status]
|
||||
format = '[$all_status]($style)'
|
||||
style = "cyan"
|
||||
ahead = "⇡${count} "
|
||||
diverged = "⇕⇡${ahead_count}⇣${behind_count} "
|
||||
behind = "⇣${count} "
|
||||
conflicted = " "
|
||||
up_to_date = " "
|
||||
untracked = "? "
|
||||
modified = " "
|
||||
stashed = ""
|
||||
staged = ""
|
||||
renamed = ""
|
||||
deleted = ""
|
||||
@@ -1,13 +0,0 @@
|
||||
# Changes require a restart to take effect.
|
||||
|
||||
# Install other terminals via Install > Terminal
|
||||
export TERMINAL=xdg-terminal-exec
|
||||
|
||||
# Use code for VSCode
|
||||
export EDITOR=nvim
|
||||
|
||||
# Use a custom directory for screenshots (remember to make the directory!)
|
||||
# export OMARCHY_SCREENSHOT_DIR="$HOME/Pictures/Screenshots"
|
||||
|
||||
# Use a custom directory for screenrecordings (remember to make the directory!)
|
||||
# export OMARCHY_SCREENRECORD_DIR="$HOME/Videos/Screencasts"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user