diff --git a/AGENTS.md b/AGENTS.md
index 9602cb6..3c1f642 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -32,12 +32,14 @@ shell.qml Entry point: Scope { Bar {}; Notification {} }
│ └── 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)
+│ │ BatteryIndicator, AudioWidget, 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
+│ ├── Audio.qml PipeWire default sink/source → device names/icons
│ ├── PowerProfile.qml UPower power profiles → name/icon
│ ├── Cava.qml Spawns `cava`, parses stdout into `values[]`
│ └── Notifications.qml NotificationServer: popups, DND flag, history
diff --git a/assets/icons/microphone.svg b/assets/icons/microphone.svg
new file mode 100644
index 0000000..9f32151
--- /dev/null
+++ b/assets/icons/microphone.svg
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/assets/icons/speaker.svg b/assets/icons/speaker.svg
new file mode 100644
index 0000000..fd841bd
--- /dev/null
+++ b/assets/icons/speaker.svg
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/config/BarLayout.qml b/config/BarLayout.qml
index 51888d3..e449fcf 100644
--- a/config/BarLayout.qml
+++ b/config/BarLayout.qml
@@ -24,6 +24,7 @@ Singleton {
]
property var right: [
+ root.widget("AudioWidget"),
root.widget("BatteryIndicator"),
root.widget("SystemTrayWidget"),
root.widget("ClockWidget"),
diff --git a/modules/bar/AudioWidget.qml b/modules/bar/AudioWidget.qml
new file mode 100644
index 0000000..65d9001
--- /dev/null
+++ b/modules/bar/AudioWidget.qml
@@ -0,0 +1,24 @@
+pragma ComponentBehavior: Bound
+
+import QtQuick.Layouts
+import qs.ui
+import qs.services
+
+RowLayout {
+BarButton {
+ hoverHighlight: false
+ pointerCursor: false
+ label: Audio.inputName
+ iconSource: Audio.inputIcon
+}
+
+
+BarButton {
+ hoverHighlight: false
+ pointerCursor: false
+ label: Audio.outputName
+ iconSource: Audio.outputIcon
+}
+
+}
+
diff --git a/services/Audio.qml b/services/Audio.qml
new file mode 100644
index 0000000..e6b5d7e
--- /dev/null
+++ b/services/Audio.qml
@@ -0,0 +1,24 @@
+pragma Singleton
+
+import QtQuick
+import Quickshell
+import Quickshell.Services.Pipewire
+
+Singleton {
+ id: root
+
+ readonly property string outputName: root.displayName(Pipewire.defaultAudioSink)
+ readonly property string inputName: root.displayName(Pipewire.defaultAudioSource)
+ readonly property url outputIcon: `${Quickshell.shellPath("assets")}/icons/speaker.svg`
+ readonly property url inputIcon: `${Quickshell.shellPath("assets")}/icons/microphone.svg`
+
+ function displayName(node: PwNode): string {
+ if (!node)
+ return "none";
+ return node.description || node.name;
+ }
+
+ PwObjectTracker {
+ objects: [Pipewire.defaultAudioSink, Pipewire.defaultAudioSource]
+ }
+}