done: a fish package that notifies you when the long command finishes
A fish-shell package to automatically receive notifications when long processes finish.
At a glance
- What is it?
- done is a fish shell plugin that watches the commands you run and sends a desktop notification when one takes longer than five seconds and your terminal is no longer in the foreground, so a long build tells you when it is over without you watching it. It is MIT licensed, and it has an unusually long settings surface for something this small.
- Who is it for?
- Adopt done if you spend your day in fish and run builds, tests and downloads in a terminal you switch away from, since the whole idea is one small plugin with no daemon and no configuration file to manage. It is the wrong tool if your shell is bash or zsh, because it depends on fish event hooks and universal variables, and it is the wrong tool on a Wayland desktop that is not Kitty, because notifications are unavailable there without a remote control workaround.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 130 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem of a build you cannot watch
The premise is a small irritation that everyone who works in a terminal knows. You start a build, a test suite or a download, you switch to another window because the terminal is not where you want to be, and twenty minutes later you have no idea whether it finished or is still going, because the terminal is in the background and you cannot see the prompt return.
done is a fish shell package that solves exactly that. The README puts it plainly: go on with your normal life, and you will get a notification when a process takes more than five seconds to finish and the terminal window is not in the foreground. The example is `sleep 6`, so you can try it in about six seconds.
The interesting constraint is the second half of that sentence. A notification fires only when the terminal is not in the foreground, which is what separates this from an annoyance generator. You do not want a pop-up for every command that happens to take a moment, and the foreground check is what keeps the noise down.
The implementation is a fish plugin, installed as a conf.d file, and the repository is small accordingly. The top level holds a conf.d directory with the plugin itself, a test directory, a CONTRIBUTING.md, a LICENSE and a README, plus a .travis.yml from the project's earlier years. There is no daemon, no background service and no database. It hooks into the fish shell's own machinery, which is why the whole thing is a handful of lines of shell rather than a program.
The project is by Francisco Lourenço, with Daniel Wehner credited for the proof of concept and Thanh Duc Nguyen for the logo, and it is funded through Open Collective with both individual and organisational contributions. The badge in the README marks it as stable, and the fish version requirement is 2.3.0 or newer.
Installing it three ways
The recommended route is Fisher, the fish plugin manager, and it is a single command:
fisher install franciscolourenco/doneThe manual route downloads the conf.d file directly into your fish configuration directory, creating it if needed:
curl -Lo ~/.config/fish/conf.d/done.fish --create-dirs https://raw.githubusercontent.com/franciscolourenco/done/master/conf.d/done.fishThat second command is worth reading rather than copying, because it shows how the plugin is structured. It is a single .fish file placed in conf.d, which fish loads automatically at startup. There is no build step, no compilation and no runtime directory, which is why the manual installation is a curl rather than a package build.
On Arch Linux there is a package in the AUR called fish-done, installed with:
yay -S fish-doneUpdates go through Fisher as well:
fisher update franciscolourenco/doneThe choice between the two routes is a matter of taste for most people, with one exception. The manual curl pins you to the master branch file at the moment you download it and gives you no update path, whereas Fisher tracks the repository and can update the plugin, and the AUR package gets updates with the rest of your system. If you already use Fisher for anything else, there is no reason to do this by hand.
The threshold, the exclusion list and the universal variables
All configuration is done with fish universal variables, set with set -U, which means a setting persists across sessions without a configuration file. The first one is the threshold:
set -U __done_min_cmd_duration 5000 # default: 5000 msFive seconds is the default, which matches the behaviour described in the README. Raising it is the first thing to do if the notifications feel too eager, and lowering it is a way to catch shorter commands.
The exclusion list is the more interesting one. It accepts a list of regular expression patterns, and it is there to stop commands that you do not want to hear about. The documented example is git:
set -U __done_exclude '^git (?!push|pull|fetch)' # default: all git commands, except push and pull. accepts a regex.The default pattern excludes every git command except push, pull and fetch, and the README explains why. A git commit can open an external editor, and a command that waits for a human is not a command whose completion is worth a notification. The same reasoning applies to commands that are normally run interactively, and the README ties this pattern to another setting, __done_allow_nongraphical, which is about not notifying for interactive commands at all.
The pattern is a regular expression with a negative lookahead, which means it is not the flavour of regex that POSIX grep uses. Any pattern you add has to work in whatever engine fish applies here, so it is worth testing rather than assuming.
Adding to the list rather than replacing it needs the --append option, because set -U on a list variable replaces it:
set -U --append __done_exclude '^emacsclient'That distinction between setting and appending is the one that catches people out, and it applies to every list-valued setting in this plugin.
Replacing the notification itself
The notification is produced by a command, and that command is configurable, which is what makes the plugin work on a desktop that has no notification daemon at all.
The setting takes a command line with the title and the message passed to it:
set -U __done_notification_command "your-command \$title \$message"The escaping matters, since fish expands variables inside double quotes, and the README writes the dollar signs escaped so that the notification command receives the literal names and expands them itself.
A separate switch plays a sound as well:
set -U __done_notify_sound 1On Linux, the urgency level of a notification sent through notify-send can be set, with the levels low, normal and critical, and the default depends on the outcome: normal for a regular command and critical for a failed one.
set -U __done_notification_urgency_level low
set -U __done_notification_urgency_level_failure normalThat default is a nice touch on its own, since a failed command becoming a critical notification is exactly the behaviour you want on a desktop that supports it.
The duration is also configurable, and the default is 3000 milliseconds, three seconds, with 0 meaning the notification never expires:
set -U __done_notification_duration 5000 # 5 secondsThe README notes that this applies on Linux except for Ubuntu's Notify OSD, which has its own behaviour, and that is the kind of platform detail that a small project only documents because somebody reported it.
The combination of a configurable command, an optional sound and a configurable urgency is what turns a notification plugin into something you can fit to a specific desktop, and it is also the reason the plugin works in environments where the usual path is unavailable.
Non-graphical systems, Wayland and the Kitty route
Two situations break the default path, and the README handles both.
The first is a system with no graphical capability at all, a server, a container, a remote session over ssh with no X forwarding. The setting that allows notifications there is __done_allow_nongraphical, and the README is clear that it requires __done_notification_command to be set as well, because there is no notification daemon to call and the custom command has to be the thing that does the work. On a headless box that command might be a terminal bell, a message to a chat webhook or a line appended to a log.
The second is Wayland, where notifications are unavailable. The exception is Kitty, which can be driven through its remote control feature, and that needs jq installed, the same dependency the sway and niri paths need.
In kitty.conf you need two lines, a remote control password and the permission to use it:
remote_control_password "kitty-rc-password" ls
allow_remote_control passwordAnd in fish, two variables to point the plugin at that password:
set -U __done_kitty_remote_control 1
set -U __done_kitty_remote_control_password "kitty-rc-password"The permission line matters: the ls argument scopes the remote control to the ls command, which is a much smaller grant than allowing arbitrary remote commands, and the README says to change the password to your liking.
For sway specifically there is one more setting, __done_sway_ignore_visible, which suppresses notifications for windows that are currently visible, so the notification only appears for work that is happening behind the scenes. The general principle here is sound: a notification about a command you are watching is noise.
Platform support and the dependencies that come with it
The support section lists what the plugin works on, and it is worth reading the list as a statement of what the notification mechanism is on each system.
fish 2.3.0 and newer is the requirement, since the plugin is a fish script and uses fish specific features. On macOS, 10.8 and newer, the notifications go through Notification Center. On Linux they go through notify-send, and where that is not available the README says a bell sound is played instead. On Windows the supported path is Windows 10 through the Windows Subsystem for Linux, using PowerShell.
That last line is the honest one. WSL is a Linux userspace, so a fish shell inside it is a Linux environment, and the notification has to be relayed to the Windows host, which is what the PowerShell dependency is for. The README notes that the utility for that, wslu, may need to be installed but is usually pre-installed.
The other two dependencies are for narrower cases. terminal-notifier is needed on macOS if you want notifications with icons, installed with brew install terminal-notifier. jq is needed for sway and niri users, and for the Kitty remote control path.
The dependency list is a good summary of the plugin's design. It has no required dependencies at all on a normal Linux desktop with notify-send, no daemon, no compiled code and no configuration file, and the extra pieces exist only for the platforms where the standard notification path is missing.
Maintenance, funding and the judgement to make
The licence is MIT, with the LICENSE file at the repository root, and the code is a fish script distributed as a single file, so forking it and changing the behaviour is a matter of editing a shell script rather than maintaining a fork of a program.
The project is funded through Open Collective, with the README showing individual and organisational contributor badges, and it has a CONTRIBUTING.md for code contributions. The stability badge says stable, which for a shell plugin with this much configuration surface is a reasonable claim.
The release record is recent. Version 1.21.1 was published on 2025-12-15, 1.21.0 a few minutes earlier the same day, and 1.20.2 on 2025-12-13, which is the pattern of a project that ships small increments as settings are added. The repository is not archived, and the last push was on 2026-06-14.
The judgement is straightforward. If your shell is fish and you run long commands in a terminal you switch away from, this is a small, well made tool that solves the problem properly, including the parts most such tools get wrong, such as the foreground check, the exclusion list and the configurable notification command. If your shell is bash or zsh, none of it applies, because the plugin depends on fish event hooks and fish universal variables, and the equivalent for other shells is a different project.
The limitations are equally clear. Notifications do not work on Wayland except through the Kitty remote control route, which needs jq and a configured password. The dependency on jq for the sway and niri paths means a shell that had no external dependencies now has one. And the WSL path is a bridge rather than a native implementation, so it depends on wslu and PowerShell behaving as expected.
None of that makes it a poor fit for its audience. It is a good example of a small tool that knows exactly which problem it solves and documents the edges of it.
Editorial conclusion
Adopt done if you spend your day in fish and run builds, tests and downloads in a terminal you switch away from, since the whole idea is one small plugin with no daemon and no configuration file to manage. It is the wrong tool if your shell is bash or zsh, because it depends on fish event hooks and universal variables, and it is the wrong tool on a Wayland desktop that is not Kitty, because notifications are unavailable there without a remote control workaround. Before installing it, decide which commands should never notify, since the default exclusion covers git except push, pull and fetch, and set __done_notification_command if your desktop has no notification daemon.
Frequently asked questions
What does the done fish package do?
It sends a desktop notification when a command you run takes more than five seconds to finish and the terminal window is not in the foreground. The README's example is running sleep 6, switching to another application, and getting a notification six seconds later.
How do I install done for fish?
With Fisher using fisher install franciscolourenco/done, manually by downloading the conf.d file into ~/.config/fish/conf.d with curl, or from the AUR on Arch Linux with the fish-done package. Fisher also updates it with fisher update franciscolourenco/done.
How do I stop certain commands from sending notifications in done?
The __done_exclude universal variable takes a list of regular expression patterns, and the default excludes all git commands except push, pull and fetch. Add to the list with set -U --append __done_exclude followed by your own pattern.
Does done work on Wayland?
Notifications are unavailable on Wayland, with one exception. If you use Kitty you can enable them through its remote control, which needs jq, two lines in kitty.conf for the remote control password and permission, and the __done_kitty_remote_control settings in fish.
Can done notify me on a machine with no graphical interface?
Yes, with the __done_allow_nongraphical setting, but the README states that it also requires __done_notification_command to be set, since there is no notification daemon to call and your own command has to produce the notification.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/franciscolourenco-done)Was this useful?