mirror of
https://github.com/tuxdotrs/tshell.git
synced 2026-09-19 18:49:02 +05:30
4.9 KiB
4.9 KiB
AGENTS.md
Guidance for AI agents working in this repository.
Project Overview
tshell is a personal Wayland desktop shell (top bar + notification OSD) built with Quickshell and QML (Qt 6). It targets wlroots-based compositors via wlr-layer-shell.
Commands
- Enter dev environment:
nix develop - Run the shell:
quickshell(from repo root; entry point isshell.qml) - Format Nix files:
nix fmt(treefmt + nixfmt)
There are no tests or linters beyond the formatter.
Tech Stack
- Quickshell (git, from flake input) patched
withModulesfor qtbase/qtdeclarative/qtmultimedia/qttranslations - QML / QtQuick 6
- cava — external audio visualizer process (config in
assets/cava.conf) - wallust — available in dev shell for palette generation
Architecture
Layered structure
shell.qml Entry point: Scope { Bar {}; Notification {} }
├── windows/ Top-level surfaces (PanelWindow roots)
│ ├── Bar.qml Screen-edge bars + exclusive zones + corners
│ └── Notification.qml Popup notification stack window
├── modules/ Feature widgets, grouped by surface
│ ├── bar/ Widgets placed in the bar (Clock, Workspaces,
│ │ BatteryIndicator, CavaVisualizer, SystemTray,
│ │ LauncherButton, PowerProfileWidget, GhostButton)
│ └── osd/ NotificationCard.qml
├── services/ QML Singletons exposing system state
│ ├── Time.qml SystemClock → formatted time string
│ ├── Battery.qml UPower display device → percentage/icon
│ ├── PowerProfile.qml UPower power profiles → name/icon
│ ├── Cava.qml Spawns `cava`, parses stdout into `values[]`
│ └── Notifications.qml NotificationServer: popups, DND flag, history
├── config/ QML Singletons for configuration/theming
│ ├── Appearance.qml colors, font, margin/radius/spacing/padding/duration
│ └── BarLayout.qml Which widgets go in left/center/right bar sections
├── ui/ Shared reusable primitives
│ ├── BarButton.qml Themed button used by bar widgets
│ ├── RoundedCorner.qml Decorative corner piece
│ └── ExclusionZone.qml Zero-size PanelWindow reserving screen space
└── assets/ icons/, cava.conf, gallery screenshots
Key patterns
- Singletons for state and config: everything in
services/andconfig/ispragma Singleton+ QuickshellSingleton. They are imported by directory alias (import qs.services,import qs.config,import qs.ui,import qs.windows) — never instantiate them directly. - One-way data flow:
services(reactive properties) →modules(presentational widgets) ←config(theme/layout). Windows compose modules. - Config-driven bar layout:
config/BarLayout.qmllists widget names per section; it resolves names to.qmlfile URLs undermodules/bar/.windows/Bar.qmlloads them dynamically through aRepeaterofLoaders inside aFlexboxLayout(left / center / right sections). To add a bar widget: createmodules/bar/<Name>.qml, then addwidget("<Name>")to the desired section list. - Bar rendering model:
Bar.qmlis one fullscreen transparentPanelWindowanchored to all edges. It draws thin colored rectangles on each edge (left/right/bottom = 10px, top = 50px), reserves compositor space via fourExclusionZonelayer-shell windows, and punches out the screen center using a subtractive inputmaskso only the bars/corners are interactive. Rounded corners come fromui/RoundedCorner.qml. - External process service:
services/Cava.qmlrunscava -p assets/cava.confvia QuickshellProcess+SplitParserand republishes each line as a numeric array onCava.values. - Notifications:
services/Notifications.qmlimplements the freedesktopNotificationServer; popups are tracked notifications, rendered newest-first bywindows/Notification.qmlusingmodules/osd/NotificationCard.qml. Critical notifications don't auto-expire; hover pauses the countdown timer.
Code Conventions
- Start every QML file with
pragma ComponentBehavior: Boundwhere bindings reference outer ids. - Indentation is inconsistent across the repo (2-space in newer UI/window files, 4-space in some services); match the surrounding file when editing.
- Prefer
readonly propertyfor derived values; keep widgets presentational and pull all theme values fromAppearance.*rather than hardcoding colors/sizes/fonts. - Access asset paths via
Quickshell.shellPath(...)(seeBattery.qml,NotificationCard.qml) so paths work regardless of install location. - Commit messages follow Conventional Commits style (
feat(notifications): ...,refactor(bar): ...).