| Crates.io | catfood-bar |
| lib.rs | catfood-bar |
| version | 0.3.0 |
| created_at | 2025-12-22 15:46:06.438771+00 |
| updated_at | 2025-12-30 17:12:05.837025+00 |
| description | A system bar component of the catfood utility suite |
| homepage | https://github.com/thombruce/catfood |
| repository | https://github.com/thombruce/catfood |
| max_upload_size | |
| id | 1999890 |
| size | 212,336 |

A customizable system status bar built with Rust and extensible with Lua. Part of the catfood utility suite.
kitten panel to render the bar)[!NOTE] You may wish to try using catfood without the Kitty terminal emulator. Functionality is not guaranteed in this case, but you are free to experiment using the
--no-kittencommand line flag.
# Install the bar component
cargo install catfood-bar
# Build and install
cargo install --path crates/bar
# Or build and run locally
cargo run --release --bin catfood-bar
Run the system bar:
catfood-bar
When run through the main catfood CLI, it automatically spawns in a kitty panel:
# Top of screen (default)
catfood bar
For other purposes, you can still run the catfood-bar binary independently:
# Bottom of screen
kitten panel --edge=bottom catfood-bar
Configuration is stored in ~/.config/catfood/bar.json. The first run creates a default config with all components enabled.
{
"bars": {
"left": ["workspaces"],
"middle": ["time", "separator", "weather"],
"right": [
"temperature",
"cpu",
"ram",
"separator",
"wifi",
"separator",
"brightness",
"volume",
"separator",
"battery"
]
},
"colorize": true
}
Components can be specified as either strings or objects with additional options:
{
"bars": {
"right": ["cpu", "ram", "wifi"]
}
}
{
"bars": {
"right": [
{
"name": "cpu",
"sparkline": true,
"sparkline_length": 8,
"sparkline_update_freq": 2
}
]
}
}
workspaces - Hyprland workspace switchingwindows - Window management infocpu - CPU usage percentage (supports sparkline)ram - Memory usage percentage (supports sparkline)temperature - CPU temperaturebattery - Battery status and percentagewifi - WiFi connection status and signal strength (supports sparkline)weather - Current weather informationvolume - System volume levelbrightness - Screen brightnesstime - Current date and timeseparator - Visual separator (" | ")space - Single space character for fine spacingThe following components support sparkline visualization:
cpu - Real-time CPU usage graphram - Memory usage over timewifi - WiFi signal strength historysparkline (default: false) - Enable sparkline modesparkline_length (default: 10) - Graph width in characterssparkline_update_freq (default: varies) - Update frequency in seconds
sparkline_logarithmic (default: false) - Use logarithmic scalingCreate custom components in ~/.config/catfood/components/*.lua:
Each Lua component should return a table with the following structure:
return {
-- Optional configuration
config = {
-- Component-specific settings
},
-- Optional update function (called periodically)
update = function()
-- Update internal state or fetch external data
end,
-- Required render function
-- Returns text to display, optionally with color
render = function(colorize)
-- colorize: boolean indicating if colors should be used
-- Returns either:
-- 1. A string: "text"
-- 2. A table: {"text", "color"}
return {"12:34", "yellow"}
end
}
Lua components can use the following color names:
red, green, yellow, blue, magenta, cyan, white, blackgray/grey, dark_red, dark_green, dark_yellow, dark_blue, dark_magenta, dark_cyan, dark_gray![NOTE] Color support is a work in progress. Not all of these colors may work. In future, user-defined colors may be supported along with fallback values for more restricted terminal color-spaces.
return {
config = {
show_seconds = true
},
render = function(colorize)
local time = os.date("%H:%M")
if true then -- show_seconds from config
time = os.date("%H:%M:%S")
end
if colorize then
local hour = tonumber(os.date("%H"))
local color = "yellow"
if hour < 6 or hour >= 18 then
color = "magenta"
end
return {time, color}
else
return {time, nil}
end
end
}
return {
update = function()
-- Store uptime in component state (simplified)
_uptime = io.open("/proc/uptime"):read("*a"):match("(%d+)")
end,
render = function(colorize)
local uptime = tonumber(_uptime) or 0
local hours = math.floor(uptime / 3600)
local minutes = math.floor((uptime % 3600) / 60)
local text = string.format("Uptime: %dh %dm", hours, minutes)
if colorize then
return {text, "green"}
else
return {text, nil}
end
end
}
Create the components directory:
mkdir -p ~/.config/catfood/components
Add your Lua component files (.lua extension)
Reference them in config.json by filename (without extension)
Restart catfood_bar or wait for automatic config reload
❌ component_nameupdate() may affect UI responsiveness{
"bars": {
"left": ["workspaces"],
"middle": ["time"],
"right": ["battery"]
}
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time", "separator", "temperature"],
"right": [
{"name": "cpu", "sparkline": true, "sparkline_length": 8},
"space",
{"name": "ram", "sparkline": true, "sparkline_length": 8},
"separator",
{"name": "wifi", "sparkline": true, "sparkline_length": 10}
]
}
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time"],
"right": [
{"name": "cpu", "sparkline": true, "sparkline_length": 4},
"space",
{"name": "ram", "sparkline": true, "sparkline_length": 4},
"space",
{"name": "wifi", "sparkline": true, "sparkline_length": 4}
]
}
}
kitty_tabs - Kitty terminal tabs with program icons
kitty --single-instance flag for proper detection{
"name": "kitty_tabs",
"socket_path": "/tmp/custom-kitty-socket"
}
separator - Visual separator (" | ") space - Single space character for fine spacing
The cpu, ram, and wifi components support sparkline mode with these options:
sparkline (default: false) - Enable sparkline modesparkline_length (default: 10) - Graph width in characterssparkline_update_freq (default: varies) - Update frequency in secondssparkline_logarithmic (default: varies by component) - Use logarithmic scalingLinear Scaling (default for CPU/RAM)
Logarithmic Scaling (default for WiFi)
// CPU with linear scaling (default)
{
"name": "cpu",
"sparkline": true,
"sparkline_length": 10,
"sparkline_update_freq": 3
}
// WiFi with logarithmic scaling (default)
{
"name": "wifi",
"sparkline": true,
"sparkline_length": 15,
"sparkline_update_freq": 2
}
// Override: CPU with logarithmic scaling
{
"name": "cpu",
"sparkline": true,
"sparkline_length": 10,
"sparkline_update_freq": 3,
"sparkline_logarithmic": true
}
// Override: WiFi with linear scaling
{
"name": "wifi",
"sparkline": true,
"sparkline_length": 15,
"sparkline_update_freq": 2,
"sparkline_logarithmic": false
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time", "separator", "weather"],
"right": ["wifi", "separator", "battery"]
}
}
{
"bars": {
"left": ["workspaces", "separator", "kitty_tabs"],
"middle": ["time"],
"right": ["wifi", "separator", "battery"]
}
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time", "separator", "weather"],
"right": [
{
"name": "cpu",
"sparkline": true,
"sparkline_length": 8,
"sparkline_update_freq": 2
},
"space",
{
"name": "ram",
"sparkline": true,
"sparkline_length": 8
},
"separator",
{
"name": "wifi",
"sparkline": true,
"sparkline_length": 10
},
"separator",
"battery"
]
}
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time"],
"right": [
{
"name": "cpu",
"sparkline": true,
"sparkline_length": 12
},
"separator",
"ram",
"separator",
"wifi"
]
}
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time", "separator", "weather"],
"right": [
"temperature", "cpu", "ram",
"separator", "separator",
"wifi",
"separator",
"brightness", "volume", "battery"
]
}
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time", "space", "separator", "space", "weather"],
"right": [
"temperature", "space", "cpu", "space", "ram",
"separator",
"wifi", "space",
"separator",
"brightness", "space", "volume", "space", "battery"
]
}
}
{
"bars": {
"left": ["workspaces"],
"middle": ["time", "space", "weather"],
"right": ["wifi", "space", "battery"]
}
}
Configuration changes are applied automatically:
~/.config/catfood/bar.jsonErrors are logged to ~/.local/share/catfood/logs/bar.log:
2025-12-21T03:45:12Z [ERROR] [COMPONENT_WORKSPACES] Error: Failed to get workspaces
2025-12-21T03:45:13Z [ERROR] [CONFIG] Failed to reload configuration: ...
The log maintains the last 1000 lines.
Copyright (c) Thom Bruce thom@thombruce.com
Licensed under the MIT license.