---
name: "darkman"
section: "1"
platform: "linux"
package: "darkman"
version: "2.3.1-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/darkman"
---

# darkman(1)

control dark-mode and light-mode transitions

## NAME

**darkman** – control dark-mode and light-mode transitions

## SYNOPSIS

**darkman** \[*options*\] *command*

## DESCRIPTION

**darkman** runs in the background and turns on dark mode at sundown, and turns it off again at sunrise. **darkman** is not designed to be used interactively: it's designed to be set up once, and run in the background.

It is also possible to trigger manual transitions and it is also possible to disable automatic transitions entirely.

## COMMANDS

- **run** \[**--ready-fd** *fd*\]

  Runs the **darkman** service. This command is intended to be executed by a service manager, init script or alike.

  The optional *fd* is a file descriptor where **darkman** will notify when it is ready to receive connections from clients. The protocol used is compatible with readiness notifications for s6, dinit and systemd.

- **set** ⟨**light** \| **dark**⟩

  Sets the current mode.

- **get**

  Prints the current mode.

- **toggle**

  Toggle the current mode.

## OPTIONS

- **--verbose**

  Print detailed logs. Defaults to **true** for the **run** command and to **false** for all other commands.

## CONFIGURATION

See [darkman.conf(5)](/darkman.conf/5.md) for configuration file format and FILES for configuration file locations.

## INTEGRATIONS

The open source desktop ecosystem is quite heterogeneous and making different applications switch between dark/light requires different mechanisms.

**darkman** seeks to implement the more widely adopted standards, while leaving room for users to hook in custom scripts for other applications.

### Custom executables

**darkman** can run custom executables (which can be simple shell scripts).

Scripts are searched in a directory named *darkman* inside paths defined in the XDG\_DATA\_DIRS as well as XDG\_DATA\_HOME. Each script receives the current mode (“dark or “light””) as its first argument ($1). This allows a single script to handle both modes:

```
#!/bin/sh
case "$1" in
dark) THEME=dark-theme ;;
light) THEME=light-theme ;;
esac
gsettings set org.example.app theme "$THEME"
```

For backwards compatibility, **darkman** also searches *dark-mode.d* and *light-mode.d* directories (legacy format). Scripts in these directories run without arguments. Scripts in the *darkman* directory with the same name will override legacy scripts.

Both of these variables and their fallbacks are defined in the XDG Base Directory Specification: **https://specifications.freedesktop.org/basedir-spec/latest/**

These scripts or executables can perform any actions required like re-write configuration files for a PDF reader, control a notification daemon to switch to another theme, or toggle a DE-specific setting.

Files must have the executable bit set in order to be considered an executable. Scripts must have the proper shebang for the OS to properly execute them.

Typically, the XDG\_DATA\_\* variables mentioned above will resolve to the following set of directories:

- *~/.local/share/*

- */usr/local/share/*

- */usr/share/*

Example scripts (and discussion on how to integrate different applications) are available in the project repository: **https://gitlab.com/WhyNotHugo/darkman**

Packages may also drop-in their own scripts into any of these locations, although application developers are encouraged to use the socket API to determine the current mode and listen for changes (see below for details).

### XDG Settings portal

**darkman** implements the XDG desktop portal's dark mode interface. Applications using this API should switch to dark/light mode based on **darkman**'s current preference. This interface was originally pushed by the GNOME and Elementary teams, and is currently supported by KDE, Firefox and many other projects. You should expect applications from those environments to support it, amongst others.

For more details on this protocol, see: **https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html**

As of xdg-desktop-portal(1) version 1.17.0, portals MUST be configured with per-user configuration [portals.conf(5)](/portals.conf/5.md). To force the usage of **darkman** for dark/light mode setting, use something like the following:

```
[preferred]
org.freedesktop.impl.portal.Settings=darkman
```

When using a desktop-specific configuration (e.g.: *swaywm-portals.conf*), please keep in mind that the environment variable XDG\_CURRENT\_DESKTOP must be set for the xdg-desktop-portal(1).

The xdg-desktop-portal(1) should start after **darkman** has started and is ready. Use **--ready-fd** for readiness notification. This is likely not relevant on systemd-based setups, where the service manager intermediates in taking the named bus.

For a more in-depth explanation, see this article: **https://whynothugo.nl/journal/2024/04/09/darkman-portal-configuration/**

### Socket API

**darkman** listens on a Unix socket for query and control commands. The socket exposes a simple text-based API where commands are followed by a newline, and **darkman** writes a response also followed by a newline.

The **get**, **set** and **toggle** commands use this API. It is also the recommended approach when writing custom tools (e.g.: switching the current mode based on the input from a light sensor).

The following commands are available:

- **get**

  Print the current mode.

- **set** *mode*

  Set the current mode. *mode* must be one of **light** or **dark**.

- **toggle**

  Switch to the opposite mode. The new mode is printed as a response.

- **watch**

  Print mode changes as they occur. The current mode is printed immediately, followed by each subsequent change.

To interact with the socket manually:

```
socat UNIX-CONNECT:${XDG_RUNTIME_DIR}/darkman/control.sock STDIO
```

A **libdarkman** Go package is available to query this interface from other client applications. See its documentation for details: **https://godocs.io/gitlab.com/WhyNotHugo/darkman/libdarkman**

### Third party integrations

For Emacs users, a third party package exists to integrate **darkman** with Emacs: **https://github.com/grtcdr/darkman.el**

There also exists a plugin for neovim users: **https://github.com/4e554c4c/darkman.nvim**

## LOCATION

The current location may be specified in the configuration file. The location is used to calculate what time sundown and sunrise happen.

It is also possible for **darkman** to automatically determine the system's location using geoclue(1). Geoclue's reliability varies depending on distribution and desktop environment, as an agent often needs to be configured for it to work properly.

If no location is known, automatic transitions are disabled.

## ENVIRONMENT

The following environment variables are also read and will override the configuration file:

- DARKMAN\_LAT

  Overrides the latitude for the current location.

- DARKMAN\_LNG

  Overrides the longitude for the current location.

- XDG\_CURRENT\_DESKTOP

  **darkman** does not use this variable; it should be defined for the xdg-desktop-portal(1) instead.

## FILES

**darkman** searches for a configuration file in the following locations, using the first one found:

1. *$XDG\_CONFIG\_HOME/darkman/config.yaml*

2. Each directory in XDG\_CONFIG\_DIRS, with *darkman/config.yaml* appended.

If XDG\_CONFIG\_HOME is not set, it defaults to *~/.config*. If XDG\_CONFIG\_DIRS is not set, it defaults to */etc/xdg*.

See [darkman.conf(5)](/darkman.conf/5.md) for configuration file format.

## PRIVACY

**darkman** will trigger a darkmode/lightmode transition at sundown in the current location. Any application that is running locally can record or transmit the time of these transitions and attempt to extrapolate information related to the current location.

When a web browser applies this transition at the same time, open websites can record this information too.

A potential stalker or tracker can use the above information to infer that you are likely in a region of the world where sunset happened at a specific time. This region is usually a wide area spanning tens of thousands of kilometers, but can be smaller for certain geographical locations.

The author of this tool uses a manually configured location with an integer latitude and longitude to achieve a sensible balance between privacy and convenience.

## DEVELOPMENT

For issues and general development inquiries, see the project home currently hosted at GitLab: **https://gitlab.com/WhyNotHugo/darkman**

## DEBUGGING

To confirm which value is relayed via the xdg-desktop-portal(1) use:

```
gdbus call --session \
    --dest org.freedesktop.portal.Desktop \
    --object-path /org/freedesktop/portal/desktop \
    --method org.freedesktop.portal.Settings.ReadOne \
    org.freedesktop.appearance color-scheme
```

## SEE ALSO

[portals.conf(5)](/portals.conf/5.md), [gammastep(1)](/gammastep/1.md), sd-ready-fd(1)

## AUTHORS

Developed by Hugo O. Barrera ⟨*hugo@whynothugo.nl*⟩, with invaluable contributions from the community.

**darkman** is an open source project licensed under the ISC licence and developed for anyone to use freely. If you would like to sponsor this project, see: **https://whynothugo.nl/sponsor**
