Skip to content

Custom Module Scripts

The custom module runs an external script on a configurable interval and displays its output on the bar. This is the quickest way to add a module without writing Python — the script can be in any language.

Configuration

KeyTypeDefaultDescription
execfilePath to the script (supports arguments)
return-typechoicejsonjson or text
intervalinteger60Seconds between executions
on-click-middlestringCommand to run on middle click
on-click-rightstringCommand to run on right click

Text output

With return-type set to text, the module displays whatever the script prints to stdout as-is:

#!/usr/bin/env bash
echo "hello"

JSON output

With return-type set to json (the default), the script must print a single JSON object. The top-level keys mirror the standard fields from fetch_data:

KeyDescription
textLabel shown on the bar
iconFont Awesome icon character
classCSS class added to the bar widget
#!/usr/bin/env bash
echo '{"text": "hello", "icon": "\uf000", "class": "green"}'

Popovers

A script can also define a popover by including a widget key in its JSON output. The value is a schema that describes the popover’s widget tree. This only needs to be returned once — the module caches the schema and only rebuilds the popover when it changes.

Widget schema

The widget value is a dict with a children list. Each child describes a widget using a type key and additional properties. Available types are:

TypeKey properties
box / hbox / vboxorientation, spacing, children
labeltext, id
buttonlabel, id
separatororientation
levelbarmin, max, value, id
pillbarheight, radius, segments, id
graphdata, height, width, min, max, id
slidermin, max, value, id
scrollwidth, height, children
imagepath, width, height

All types also accept style, ha, va, he, and ve for CSS classes and alignment, mirroring the common widget helpers.

Assign an id to any widget that needs to be updated after the initial build. Widgets without an id are static.

A minimal popover with a label:

{
  "text": "42%",
  "widget": {
    "children": [
      {
        "type": "label",
        "text": "My Module",
        "style": "heading"
      },
      {
        "type": "label",
        "id": "value_label",
        "text": "42%"
      }
    ]
  }
}

Updating widget values in place

Once the popover is built, individual widgets can be updated without rebuilding the whole structure. Include a widget_updates key in the JSON output alongside (or instead of) widget. Its value is a dict mapping widget id strings to new values:

Widget typeAccepted value
labelstring
buttonstring (updates label text)
levelbarnumber
slidernumber
pillbarlist of segment dicts
graphnumber (appended to history) or list (replaces history)
{
  "text": "43%",
  "widget_updates": {
    "value_label": "43%"
  }
}

For graphs, passing a single number appends it to an internal history buffer (capped at 50 points). Passing a list replaces the history entirely:

{
  "text": "43%",
  "widget_updates": {
    "my_graph": 43
  }
}

Environment variables

The following environment variables are set when the script runs:

VariableValue
PYBAR_MODULE_NAMEThe module’s name from the config
PYBAR_MODULE_TYPEAlways custom

Click commands (on-click-middle, on-click-right) receive the same variables when executed.

Script requirements

  • The script must be executable (chmod +x).
  • It must exit with code 0. Any other exit code is treated as an error and the module will fall back to its last cached data.
  • Execution is terminated after 30 seconds if the script has not exited.
  • stdout is captured; stderr is ignored.

Example

A minimal Python script that reports CPU usage:

#!/usr/bin/env python3
import json
import psutil

percent = round(psutil.cpu_percent(interval=0.5))
print(json.dumps({
    "text": f"{percent}%",
    "icon": "\uf2db",
    "widget": {
        "children": [
            {"type": "label", "text": "CPU", "style": "heading"},
            {"type": "label", "id": "value", "text": f"{percent}%"},
            {
                "type": "graph",
                "id": "graph",
                "data": [percent],
                "height": 120,
                "width": 300,
                "min": 0,
                "max": 100,
            }
        ]
    },
    "widget_updates": {
        "value": f"{percent}%",
        "graph": percent,
    }
}))