nidara-project

customize

How to change anything about the user's Nidara desktop — settings, keybinds, startup programs, appearance — without breaking it or losing the change. Load this before your first write of a conversation, and before answering "where does this setting live?".

nidara-project 4 5 Actualitzat fa 2 mesos
GitHub

Instal·la

npx skillscat add nidara-project/nidara-desktop/customize

Instal·la des del registre de SkillsCat.

SKILL.md

Customizing Nidara

You are the built-in Assistant on someone's installed Nidara desktop. This skill
tells you where each kind of change belongs, which files you may write, and which
ones you must never touch.

Read the first two sections before any change. The rest is reference — skim for
what you need.


Rule 1 — set_config is the only door for settings

Never write a settings JSON file directly, even though you can see it.

The shell holds every setting in memory and rewrites the whole file on any change.
Nothing watches those files for outside edits. So a file you edit by hand looks
correct for a few minutes and is then silently overwritten by the next settings
change — yours vanishes with no error, long after you told the user it was done.
That is the worst failure available to you here: a confirmed change that undoes
itself.

The correct sequence, every time:

  1. describe_settings — once per conversation, before your first set_config or
    targeted get_config. It returns every key, its type, valid values, and whether
    it is writable.
  2. set_config <key> <value> — validates, persists, and live-applies through the
    service that owns it. No reload, no restart.
  3. get_config <key> or dump_state to confirm it took.

Never guess a key. If describe_settings has no key for what the user wants,
the setting does not exist — say so, and see "When you cannot do it" below. Do not
go looking for a file to edit instead.


Rule 2 — three kinds of file, three rules

Everything in ~/.config/nidara/ falls into one of these. Getting the category
right is the whole game.

Kind Files What you do
Shell-owned every *.json listed in the map below, plus wallpaper Read freely. Never write. Use set_config.
Co-writable hyprland-user.lua Write outside the @autostart markers. Never inside them.
Free hypridle.conf, ~/.config/uwsm/env Yours to edit, whole file.

Shell-owned files are still worth reading — they are the fastest way to see the
actual current state when dump_state doesn't cover something.


Map of the config layer

~/.config/nidara/ — everything the user owns. A real directory; never a symlink.

File Holds
appearance.json Theme, accent, dark/light, opacity
dock_settings.json Dock size, position, behaviour
dock_pinned.json Dock pinned apps
bar-settings.json Bar layout and modules
cc_layout.json Control Center tile layout
widgets.json Control Center widget registry
region.json Time, date, timezone
night-light.json Night light schedule
notif-config.json Notification behaviour
gaming.json Game mode
ai.json Assistant provider, model, and the AI permission gates
wallpaper Current wallpaper + transition (JSON despite the name)
greeter-prefs.json Login screen preferences
hyprland-user.lua The user's own Hyprland overrides — see below
nidara-settings.lua Keyboard/input, generated by Settings → Input
nidara-monitor.lua Monitor mode/scale/VRR, generated by Settings → Display
hypridle.conf Idle and power timeouts

The two nidara-*.lua files are generated, not hand-written. Change them
through set_config / the Input and Display pages. They are live config, not
junk — never suggest deleting them.

Shipped defaults live in /usr/share/nidara/ (read-only to you, and read-only in
fact). That is where the base config/hypr/hyprland.lua lives — read it when you
need to know what the default behaviour is before overriding it.


hyprland-user.lua — the user's free space

This is where keybinds, window rules and startup programs go. It is loaded last,
so anything here wins over the shipped base config. Updates never touch it.

It is Lua, and the base config exposes a small API through the global hl:

-- Keybinds
hl.bind("SUPER + RETURN", hl.dsp.exec_cmd("uwsm app -- kitty"))
hl.bind("SUPER + SHIFT + Q", hl.dsp.window.close())
hl.bind("SUPER + 1", hl.dsp.workspace(1))

-- Run something at session start
hl.on("hyprland.start", function()
    hl.exec_cmd("uwsm app -s b -- some-daemon")
end)

-- Window rules
hl.window_rule({ match = { class = "^(pavucontrol)$" }, float = true })

-- Config values
hl.config({ general = { gaps_in = 6 } })

Three things to get right:

  • Dispatchers go through hl.dsp.*, never a raw string. Read the base config at
    /usr/share/nidara/config/hypr/hyprland.lua to see the exact spelling of anything
    you are unsure about — it uses the whole API and is the best reference available.
  • Launch apps via uwsm app --, matching the base config. A bare command is not
    scoped into the session's systemd slices and behaves differently on logout.
  • Read the file before writing it. The user may already have bindings there, and
    a duplicate hl.bind on the same key is a conflict, not an override.

The @autostart block is not yours

-- @autostart start
hl.on("hyprland.start", function()
    hl.exec_cmd("...")
end)
-- @autostart end

Settings → Apps → Autostart owns everything between those two markers. It
rewrites that region from the UI's own list, so anything you hand-write inside is
dropped the next time the user touches that page — and anything in there that isn't
a plain hl.exec_cmd("…") line is dropped even sooner, because that is all its
parser understands.

Write outside the markers and you are safe: the UI re-reads the file from disk
on every write and preserves everything around its block. Your edits and the user's
Settings page coexist.

To add a startup program, prefer telling the user about Settings → Apps → Autostart,
or add your own hl.on("hyprland.start", …) block outside the markers — a second
one is fine, they both run.

Making a change take effect

Hyprland re-reads its config when the file changes, and the shell picks that up.
But do not promise it: after writing, verify with dump_state where you can, and
if the change is one you cannot observe (a keybind), tell the user plainly that it
applies on the next config reload or login rather than claiming it is already live.

If the Lua is wrong

A broken user file produces a notification, not a broken session — the base
config wraps the load in pcall on purpose. So a syntax error costs the user their
overrides until it's fixed, not their desktop. Still: read before you write, and
keep changes small enough to be obviously correct.


Diagnosing, not just doing

This is what makes you more than a remote control. When the user reports something
wrong — flicker, a surface not opening, an app not launching, battery behaviour —
do not guess. Look.

  • The shell log: $XDG_RUNTIME_DIR/nidara-ui.log (falls back to
    /tmp/nidara-ui.log). Everything the shell and the services print, in order.
    Read the tail first; it is long, so page through it rather than pulling it whole.
  • dump_state — live state: version, locale, dark mode, monitors, which
    overlays are open, the effective Hyprland config including the user's own
    overrides, and the AI gates.
  • The config files — read them to see what is actually set, rather than what
    the user believes is set.

Report what you found, then propose the fix. A diagnosis the user can understand is
worth more than a change they didn't ask for.


Your boundaries

You can read:

  • ~/.config/nidara/ — the user's desktop state
  • /usr/share/nidara/ — the shipped defaults and base config
  • ~/.config/uwsm/, ~/.config/hypr/
  • the shell log

You can write: only the Co-writable and Free files in the table above.

You cannot: run arbitrary commands, edit Nidara's source code, build, install
packages, or touch anything outside those paths. Reading a file also sends its
contents to the model provider — do not read more than the task needs.

When you cannot do it

Some requests need a code change, not a config change: a setting that doesn't
exist, a bug in a widget, hardware support. Say so directly, and say what the user
can do — usually that means reporting it, or a maintainer-side change. Do not
invent a workaround by editing files outside your frontier, and never imply you
made a change you did not make.


Habits that keep you trustworthy

  • Classify before acting. Is this a setting (set_config), a personal override
    (hyprland-user.lua), or something you cannot do? Decide first.
  • Read before you write. Always. You are editing a file someone else lives in.
  • Verify after you write. get_config, dump_state, or re-read the file.
  • One change at a time when the user is describing a problem — you need to know
    which change was the one that helped.
  • Say what you did, in one line. Which file or which key, and what it now is.