{"id":13671611,"url":"https://github.com/orhun/runst","last_synced_at":"2025-05-15T09:02:45.432Z","repository":{"id":48381753,"uuid":"482642968","full_name":"orhun/runst","owner":"orhun","description":"A dead simple notification daemon 🦡","archived":false,"fork":false,"pushed_at":"2025-03-17T05:58:34.000Z","size":1057,"stargazers_count":314,"open_issues_count":7,"forks_count":8,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-07T03:17:09.601Z","etag":null,"topics":["dbus","dbus-service","desktop-notification","desktop-notifications","desktop-notifier","dunst","dunst-config","dunstrc","notification","notification-daemon","notification-server","notification-service","rust","x11"],"latest_commit_sha":null,"homepage":"https://blog.orhun.dev/introducing-runst","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/orhun.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"orhun","patreon":"orhunp","buy_me_a_coffee":"orhun"}},"created_at":"2022-04-17T22:02:34.000Z","updated_at":"2025-04-01T20:51:29.000Z","dependencies_parsed_at":"2023-12-18T06:25:45.432Z","dependency_job_id":"51db7dcd-89b7-4926-b016-98dd8d73e1a3","html_url":"https://github.com/orhun/runst","commit_stats":{"total_commits":374,"total_committers":3,"mean_commits":"124.66666666666667","dds":"0.37700534759358284","last_synced_commit":"03817acc5bd9856146f901c3d2b31db96972890a"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orhun%2Frunst","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orhun%2Frunst/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orhun%2Frunst/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orhun%2Frunst/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orhun","download_url":"https://codeload.github.com/orhun/runst/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248890631,"owners_count":21178474,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dbus","dbus-service","desktop-notification","desktop-notifications","desktop-notifier","dunst","dunst-config","dunstrc","notification","notification-daemon","notification-server","notification-service","rust","x11"],"created_at":"2024-08-02T09:01:14.482Z","updated_at":"2025-04-14T13:46:56.250Z","avatar_url":"https://github.com/orhun.png","language":"Rust","funding_links":["https://github.com/sponsors/orhun","https://patreon.com/orhunp","https://buymeacoffee.com/orhun"],"categories":["Rust","Projects using Tera"],"sub_categories":["Editor Support"],"readme":"\u003cdiv align=\"center\"\u003e\n\n  \u003ca href=\"https://github.com/orhun/runst\"\u003e\n    \u003cimg src=\"assets/runst-logo.png\" width=\"300\"\u003e\n  \u003c/a\u003e\n\n\u003ch4\u003e\u003cstrong\u003e\u003ccode\u003erunst\u003c/code\u003e\u003c/strong\u003e — A dead simple notification daemon 🦡\u003c/h4\u003e\n\n\u003ca href=\"https://github.com/orhun/runst/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/orhun/runst?style=flat\u0026amp;labelColor=56534b\u0026amp;color=c1c1b6\u0026amp;logo=GitHub\u0026amp;logoColor=white\" alt=\"GitHub Release\"\u003e\u003c/a\u003e\n\u003ca href=\"https://crates.io/crates/runst/\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/runst?style=flat\u0026amp;labelColor=56534b\u0026amp;color=c1c1b6\u0026amp;logo=Rust\u0026amp;logoColor=white\" alt=\"Crate Release\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/orhun/runst/actions?query=workflow%3A%22Continuous+Integration%22\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/orhun/runst/ci.yml?branch=main\u0026amp;style=flat\u0026amp;labelColor=56534b\u0026amp;color=c1c1b6\u0026amp;logo=GitHub%20Actions\u0026amp;logoColor=white\" alt=\"Continuous Integration\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/orhun/runst/actions?query=workflow%3A%22Continuous+Deployment%22\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/orhun/runst/cd.yml?style=flat\u0026amp;labelColor=56534b\u0026amp;color=c1c1b6\u0026amp;logo=GitHub%20Actions\u0026amp;logoColor=white\u0026amp;label=deploy\" alt=\"Continuous Deployment\"\u003e\u003c/a\u003e\n\u003ca href=\"https://docs.rs/runst/\"\u003e\u003cimg src=\"https://img.shields.io/docsrs/runst?style=flat\u0026amp;labelColor=56534b\u0026amp;color=c1c1b6\u0026amp;logo=Rust\u0026amp;logoColor=white\" alt=\"Documentation\"\u003e\u003c/a\u003e\n\n\u003c/div\u003e\n\n[Desktop notifications](https://wiki.archlinux.org/title/Desktop_notifications) are small, passive popup dialogs that notify the user of particular events in an asynchronous manner. These passive popups can automatically disappear after a short period of time.\n\n`runst` is the server implementation of [freedesktop.org](https://www.freedesktop.org/wiki) - [Desktop Notifications Specification](https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html) and it can be used to receive notifications from applications via [D-Bus](https://www.freedesktop.org/wiki/Software/dbus/). As of now, only [X11](https://en.wikipedia.org/wiki/X_Window_System) is supported.\n\n\u003cdiv align=\"center\"\u003e\n\n  \u003ca href=\"https://github.com/orhun/runst\"\u003e\n    \u003cimg src=\"assets/runst-demo.gif\"\u003e\n  \u003c/a\u003e\n\n\u003c/div\u003e\n\n## Features\n\n- Fully customizable notification window (size, location, text, colors).\n- Template-powered ([Jinja2](http://jinja.pocoo.org/)/[Django](https://docs.djangoproject.com/en/3.1/topics/templates/)) notification text.\n- Auto-clear notifications based on a fixed time or estimated read time.\n- Run custom OS commands based on the matched notifications.\n\n## Roadmap\n\n`runst` is initially designed to show a simple notification window. On top of that, it combines customization-oriented and semi-innovative features. In the future, I'm aiming to shape `runst` functionality based on new ideas and feedback.\n\nFeel free to [submit an issue](https://github.com/orhun/runst/issues/new) if you have something in mind or having a problem!\n\n## Installation\n\n### From crates.io\n\n`runst` can be installed from [crates.io](https://crates.io/crates/runst):\n\n```sh\n$ cargo install runst\n```\n\nThe minimum supported Rust version is `1.70.0`.\n\n### Arch Linux\n\n`runst` can be installed from the [extra repository](https://archlinux.org/packages/extra/x86_64/runst/) using [pacman](https://wiki.archlinux.org/title/Pacman):\n\n```sh\n$ pacman -S runst\n```\n\nOr you can install the available [AUR packages](https://aur.archlinux.org/packages?O=0\u0026SeB=nd\u0026K=runst\u0026outdated=\u0026SB=p\u0026SO=d\u0026PP=50\u0026submit=Go) with using an [AUR helper](https://wiki.archlinux.org/title/AUR_helpers). For example:\n\n```sh\n$ paru -S runst-git\n```\n\n### Alpine Linux\n\n`runst` is available for [Alpine Edge](https://pkgs.alpinelinux.org/packages?name=runst\u0026branch=edge). It can be installed via [apk](https://wiki.alpinelinux.org/wiki/Alpine_Package_Keeper) after enabling the [testing repository](https://wiki.alpinelinux.org/wiki/Repositories).\n\n```sh\napk add runst\n```\n\n### Binary releases\n\nSee the available binaries for different operating systems/architectures from the [releases page](https://github.com/orhun/runst/releases).\n\nRelease tarballs are signed with the following PGP key: [AEF8C7261F4CEB41A448CBC41B250A9F78535D1A](https://keyserver.ubuntu.com/pks/lookup?search=0x1B250A9F78535D1A\u0026op=vindex)\n\n### Build from source\n\n#### Prerequisites\n\n- [D-Bus](https://www.freedesktop.org/wiki/Software/dbus)\n- [GLib](https://wiki.gnome.org/Projects/GLib)\n- [Pango](https://pango.gnome.org)\n\n#### Instructions\n\n1. Clone the repository.\n\n```sh\n$ git clone https://github.com/orhun/runst \u0026\u0026 cd runst/\n```\n\n2. Build.\n\n```sh\n$ CARGO_TARGET_DIR=target cargo build --release\n```\n\nBinary will be located at `target/release/runst`.\n\n## Usage\n\n### On Xorg startup\n\nYou can use [xinitrc](#xinitrc) or [xprofile](#xprofile) for autostarting `runst`.\n\n#### xinitrc\n\nIf you are starting Xorg manually with [xinit](https://www.x.org/archive/X11R6.8.0/doc/xinit.1.html), you can `runst` on X server startup via [xinitrc](https://wiki.archlinux.org/title/Xinit#xinitrc):\n\n`$HOME/.xinitrc`:\n\n```sh\nrunst \u0026\n```\n\nLong-running programs such as notification daemons should be started before the window manager, so they should either fork themself or be run in the background via appending `\u0026` sign. Otherwise, the script would halt and wait for each program to exit before executing the window manager or desktop environment.\n\nIn the case of `runst` not being available since it's started at a faster manner than the window manager, you can add a delay as shown in the example below:\n\n```sh\n{ sleep 2; runst; } \u0026\n```\n\n#### xprofile\n\nIf you are using a [display manager](https://wiki.archlinux.org/title/Display_manager), you can utilize an [xprofile](https://wiki.archlinux.org/title/Xprofile) file which allows you to execute commands at the beginning of the X user session.\n\nThe xprofile file, which is `~/.xprofile` or `/etc/xprofile`, can be styled similarly to [xinitrc](#xinitrc).\n\n### As a D-Bus service\n\nYou can create a D-Bus service to launch `runst` automatically on the first notification action. For example, you can create the following service configuration:\n\n`/usr/share/dbus-1/services/org.orhun.runst.service`:\n\n```ini\n[D-BUS Service]\nName=org.freedesktop.Notifications\nExec=/usr/bin/runst\n```\n\nWhenever an application sends a notification by sending a signal to `org.freedesktop.Notifications`, D-Bus activates `runst`.\n\nAlso, see [**#1**](https://github.com/orhun/runst/issues/1) for systemd integration.\n\n## Commands\n\n`runst` can be controlled with sending commands to D-Bus via [`dbus-send(1)`](https://man.archlinux.org/man/dbus-send.1.en).\n\n```sh\ndbus-send --print-reply --dest=org.freedesktop.Notifications /org/freedesktop/Notifications/ctl \"org.freedesktop.Notifications.${command}\"\n```\n\nAvailable commands are:\n\n- `History`: show the last notification.\n- `Close`: close the notification.\n- `CloseAll`: close all the notifications.\n\nFor example:\n\n```sh\n# show the last notification\ndbus-send --print-reply \\\n          --dest=org.freedesktop.Notifications \\\n          /org/freedesktop/Notifications/ctl \\\n          org.freedesktop.Notifications.History\n```\n\nAn example usage for [i3](https://i3wm.org/):\n\n```sh\n# Notification history\nbindsym $mod+grave exec dbus-send --print-reply \\\n        --dest=org.freedesktop.Notifications /org/freedesktop/Notifications/ctl org.freedesktop.Notifications.History\n\n# Close notification\nbindsym $mod+shift+grave exec dbus-send --print-reply \\\n        --dest=org.freedesktop.Notifications /org/freedesktop/Notifications/ctl org.freedesktop.Notifications.Close\n```\n\nAdditionally, to view the server version:\n\n```sh\ndbus-send --print-reply --dest=org.freedesktop.Notifications /org/freedesktop/Notifications org.freedesktop.Notifications.GetServerInformation\n```\n\n## Configuration\n\n`runst` configuration file supports [TOML](https://github.com/toml-lang/toml) format and the default configuration values can be found [here](./config/runst.toml).\n\nIf exists, configuration file is read from the following default locations:\n\n- `$HOME/.config/runst/runst.toml`\n- `$HOME/.runst/runst.toml`\n\nYou can also specify a path via `RUNST_CONFIG` environment variable.\n\n### Global configuration\n\n#### `log_verbosity`\n\nSets the [logging verbosity](https://docs.rs/log/latest/log/enum.Level.html). Possible values are `error`, `warn`, `info`, `debug` and `trace`.\n\n#### `startup_notification`\n\nShows a notification at startup if set to `true`.\n\n#### `geometry`\n\nSets the window geometry. The value format is `\u003cwidth\u003ex\u003cheight\u003e+\u003cx\u003e+\u003cy\u003e`.\n\nFor setting this value, I recommend using a tool like [slop](https://github.com/naelstrof/slop) which helps with querying for a selection and printing the region to stdout.\n\n#### `wrap_content`\n\nIf set to `true`, the window is resized to match the contents.\n\nIf the content is larger than the window size, `geometry` option is used for maximum width and height.\n\n#### `font`\n\nSets the font to use for the window.\n\n#### `template`\n\nSets the template for the notification message. The syntax is based on [Jinja2](http://jinja.pocoo.org/) and [Django](https://docs.djangoproject.com/en/3.1/topics/templates/) templates.\n\nSimply, there are 3 kinds of delimiters:\n\n\u003c!-- {% raw %} --\u003e\n\n- `{{` and `}}` for expressions\n- `{%` or `{%-` and `%}` or `-%}` for statements\n- `{#` and `#}` for comments\n\n\u003c!-- {% endraw %} --\u003e\n\nSee [Tera documentation](https://tera.netlify.app/docs/#templates) for more information about [control structures](https://tera.netlify.app/docs/#control-structures), [built-in filters](https://tera.netlify.app/docs/#built-ins), etc.\n\n##### Context\n\nContext is the model that holds the required data for template rendering. The [JSON](https://en.wikipedia.org/wiki/JSON) format is used in the following example for the representation of a context.\n\n```json\n{\n  \"app_name\": \"runst\",\n  \"summary\": \"example\",\n  \"body\": \"this is a notification 🦡\",\n  \"urgency\": \"normal\",\n  \"unread_count\": 1,\n  \"timestamp\": 1672426610\n}\n```\n\n##### Styling\n\n[Pango](https://pango.gnome.org/) is used for text rendering. The markup documentation can be found [here](https://docs.gtk.org/Pango/pango_markup.html).\n\nA few examples would be:\n\n- `\u003cb\u003ebold text\u003c/b\u003e`: **bold text**\n- `\u003cspan foreground=\"blue\"\u003eblue text\u003c/span\u003e`: \u003cspan style=\"color:blue\"\u003eblue text\u003c/span\u003e\n- `\u003ctt\u003emonospace text\u003c/tt\u003e`: \u003ctt\u003emonospace text\u003c/tt\u003e\n\n### Urgency configuration\n\nThere are 3 levels of urgency defined in the [Freedesktop](https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html) specification and they define the importance of the notification.\n\n1. `low`: e.g. \"joe signed on\"\n2. `normal`: e.g. \"you got mail\"\n3. `critical`: e.g. \"your computer is on fire!\"\n\nYou can configure `runst` to act differently based on these urgency levels. For this, there need to be 3 different sections defined in the configuration file. Each of these sections has the following fields:\n\n```toml\n[urgency_{level}] # urgency_low, urgency_normal or urgency_critical\n    background = \"#000000\" # background color\n    foreground = \"#ffffff\" # foreground color\n    timeout = 10\n    auto_clear = true\n    text = \"normal\"\n    custom_commands = []\n```\n\n#### `timeout`\n\nThis is the default timeout value (in seconds) if the notification has no timeout specified by the sender. If the timeout is 0, the notification is not automatically closed (i.e. it never expires).\n\n#### `auto_clear`\n\nIf set to `true`, the **estimated read time** of the notification is calculated and it is used as the timeout. This is useful if you want the notifications to disappear as you finish reading them.\n\n#### `text`\n\nThis is the custom text for the urgency level and can be used in [template context](#context) as `urgency`. If it is not set, the corresponding urgency level is used (e.g. \"low\", \"normal\" or \"critical\").\n\n#### `custom_commands`\n\nWith using this option, you can run custom OS commands based on urgency levels and the notification contents. The basic usage is the following:\n\n```toml\ncustom_commands = [\n    { command = 'echo \"{{app_name}} {{summary}} {{body}}\"' } # echoes the notification to stdout\n]\n```\n\nAs shown in the example above, you can specify an arbitrary command via `command` which is also processed through the template engine. This means that you can use the same [template context](#context).\n\nThe filtering is done by matching the fields in JSON via using `filter` along with the `command`. For example, if you want to play a custom notification sound for a certain application:\n\n```toml\ncustom_commands = [\n  { filter = '{ \"app_name\":\"notify-send\" }', command = 'aplay notification.wav' },\n  { filter = '{ \"app_name\":\"weechat\" }', command = 'aplay irc.wav' }\n]\n```\n\nThe JSON filter can have the following fields:\n\n- `app_name`: Name of the application that sends the notification.\n- `summary`: Summary of the notification.\n- `body`: Body of the notification.\n\nEach of these fields is matched using regex and you can combine them as follows:\n\n```toml\ncustom_commands = [\n  { filter = '{ \"app_name\":\"telegram|discord|.*chat$\",\"body\":\"^hello.*\" }', command = 'gotify push -t \"{{app_name}}\" \"someone said hi!\"' }\n]\n```\n\nIn this hypothetical example, we are sending a [Gotify](https://gotify.net/) notification when someone says hi to us in any chatting application matched by the regex.\n\n## Why this exists?\n\nI have been a user of [dunst](https://github.com/dunst-project/dunst) for a long time. However, they made some [uncool breaking changes](https://github.com/dunst-project/dunst/issues/940) in [v1.7.0](https://github.com/dunst-project/dunst/releases/tag/v1.7.0) and it completely broke my configuration. That day, I refused to update `dunst` (I was too lazy to re-configure) and decided to write my own notification server using Rust.\n\nI wanted to keep `runst` simple since the way I use `dunst` was really simple. I was only showing an overlay window on top of [i3status](https://github.com/i3/i3status) as shown below:\n\n![runst use case](assets/runst-demo2.gif)\n\nAnd that's how `runst` is born.\n\n## Similar projects\n\n- [wired-notify](https://github.com/Toqozz/wired-notify)\n\n## License\n\nLicensed under either of [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) or [The MIT License](http://opensource.org/licenses/MIT) at your option.\n\n## Copyright\n\nCopyright © 2022-2024, [Orhun Parmaksız](mailto:orhunparmaksiz@gmail.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forhun%2Frunst","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forhun%2Frunst","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forhun%2Frunst/lists"}