Quick start
git clone https://codeberg.org/oSoWoSo/SysMan
cd SysMan
make build-sysman # builds build/sysman
./build/sysman # GUI (auto-detects display)
./build/sysman --tuiStandalone binaries
Each plugin can also run independently:
| Binary | Description | CGO |
|---|---|---|
sysman |
Full system manager (all plugins, GUI + TUI) | required |
sysman-tui |
Full system manager (TUI entry) | required |
svman |
Services manager (GUI + TUI) | required |
svman-tui |
Services manager (TUI only) | free |
ugman |
Users & Groups manager (GUI + TUI) | required |
ugman-tui |
Users & Groups manager (TUI only) | free |
infoman |
System info (GUI + TUI) | required |
infoman-tui |
System info (TUI only) | free |
srcman |
xbps-src template manager (GUI + TUI) | required |
srcman-tui |
xbps-src template manager (TUI only) | free |
pkgman |
Package manager (GUI + TUI) | required |
pkgman-tui |
Package manager (TUI only) | free |
make build # build all 12 binaries
make build-svman # build/svman only
make build-svman-tui
# … see Makefile targets belowCGO dependencies (required for GUI builds)
# Void Linux
sudo xbps-install gcc pkg-config libX11-devel libXrandr-devel libXinerama-devel libXcursor-devel libXi-devel mesa-devel
# Debian / Ubuntu
sudo apt-get install -y gcc libgl1-mesa-dev xorg-devUsage
sysman # GUI (default when display available)
sysman --tui # TUI
sysman --help
svman # Services GUI
svman --tui # Services TUI
ugman # Users & Groups GUI
ugman-tui # Users & Groups TUI only
infoman # SysInfo GUI
infoman-tui # SysInfo TUI only
srcman # Templates GUI (reads $XBPS_DISTDIR)
srcman-tui # Templates TUI only
pkgman # Packages GUI
pkgman-tui # Packages TUI onlyEnvironment variables
| Variable | Description | Default |
|---|---|---|
SERVICEDIR |
runit service definitions | /etc/sv |
SERVICEDESTDIR |
enabled services directory | /var/service |
SVMAN_LANG |
language override (cs, en) |
auto from LANG |
XBPS_DISTDIR |
path to void-packages clone | — |
PLUGIN_DIR |
directory for dynamic .so plugins |
./plugins |
Controls
TUI — Services tab
| Key | Action |
|---|---|
↑ / k |
Move up |
↓ / j |
Move down |
Enter / Space |
Enable / disable |
s |
Start |
x |
Stop |
t |
Restart |
l |
Reload (HUP) |
p |
Pause (SIGSTOP) |
c |
Continue (SIGCONT) |
K |
Kill (SIGKILL) |
/ |
Search |
Tab |
Cycle filter (All / Enabled / Disabled) |
r |
Reload list |
q / Esc |
Quit |
TUI — Users & Groups tab
| Key | Action |
|---|---|
↑ / k |
Move up |
↓ / j |
Move down |
1 |
Users tab |
2 |
Groups tab |
s |
Toggle system users |
r |
Refresh |
q / Esc |
Quit |
TUI — tab switching (sysman)
| Key | Action |
|---|---|
1 |
SysInfo |
2 |
Packages |
3 |
Templates |
4 |
Services |
5 |
Users & Groups |
Ctrl+C |
Quit |
GUI — all standalone windows
| Key | Action |
|---|---|
Esc |
Quit |
Project structure
SysMan/
├── main.go # svman entry point (Services standalone)
├── Makefile
├── lang/ # Translation files (cs, en)
├── api/
│ └── plugin.go # PluginIF interface
├── plugin/ # Services plugin (runit via sv)
│ ├── plugin.go # Plugin, New, NewRunit, NewWithBackend
│ ├── plugin_gui.go # Content / ShowAbout
│ ├── gui.go # Fyne GUI
│ ├── tui.go # Bubbletea TUI
│ ├── common.go # Service, Backend interface, RunitBackend
│ └── i18n.go # Translations
├── xbps-pkg/ # Packages plugin (xbps)
│ ├── plugin.go
│ ├── common.go # PkgBackend interface, XbpsBackend
│ ├── plugin_gui.go # Content
│ └── tui.go # Bubbletea TUI
├── xbps-src/ # Templates plugin (xbps-src)
├── sysinfo/ # SysInfo plugin (fastfetch)
├── usergroups/ # Users & Groups plugin
│ ├── plugin.go
│ ├── gui.go # Fyne GUI + RunGUI
│ ├── tui.go # Bubbletea TUI + RunTUI
│ └── users.go # User/Group loading
├── cmd/
│ ├── sysmanager/ # sysman / sysman-tui
│ ├── svman-tui/ # svman-tui (CGO-free)
│ ├── ugman-gui/ # ugman
│ ├── ugman-tui/ # ugman-tui (CGO-free)
│ ├── pkgman-gui/ # pkgman
│ ├── infoman-gui/ # infoman
│ ├── infoman-tui/ # infoman-tui (CGO-free)
│ ├── srcman-gui/ # srcman
│ └── srcman-tui/ # srcman-tui (CGO-free)
└── pluginentry/ # Dynamic .so entry points
├── svman/
├── xbps-pkg/
├── xbps-src/
└── sysinfo/
Plugin API
Every plugin implements api.PluginIF:
type PluginIF interface {
Name() string
Content(win fyne.Window) fyne.CanvasObject // GUI
Model() tea.Model // TUI
}Embedding Services in a Fyne application
import svman "codeberg.org/oSoWoSo/SysMan/plugin"
svman.InitI18n()
p := svman.New("/etc/sv", "/var/service") // runit backend
// or with a custom backend:
p = svman.NewWithBackend(&MyOpenRCBackend{})
tabs := container.NewAppTabs(
container.NewTabItem(p.Name(), p.Content(win)),
)Embedding Packages in a Fyne application
import xbpspkg "codeberg.org/oSoWoSo/SysMan/xbps-pkg"
p := xbpspkg.New() // xbps backend
// or with a custom backend:
p = xbpspkg.NewWithBackend(&MyAptBackend{})Embedding Users & Groups in a Fyne application
import "codeberg.org/oSoWoSo/SysMan/usergroups"
p := usergroups.New()
tabs := container.NewAppTabs(
container.NewTabItem(p.Name(), p.Content(win)),
)
// TUI:
_ = p.Model()Custom backend (Services)
type MyOpenRCBackend struct{}
func (b *MyOpenRCBackend) Dirs() (string, string) { return "/etc/init.d", "/etc/runlevels/default" }
func (b *MyOpenRCBackend) List() []plugin.Service { … }
func (b *MyOpenRCBackend) Enable(name string) error { … }
func (b *MyOpenRCBackend) Disable(name string) error { … }
func (b *MyOpenRCBackend) Status(name string) plugin.ServiceStatus { … }
func (b *MyOpenRCBackend) StatusAll(names []string) map[string]plugin.ServiceStatus { … }
func (b *MyOpenRCBackend) Start(name string) error { … }
func (b *MyOpenRCBackend) Stop(name string) error { … }
func (b *MyOpenRCBackend) Restart(name string) error { … }
func (b *MyOpenRCBackend) Reload(name string) error { … }
func (b *MyOpenRCBackend) Pause(name string) error { … }
func (b *MyOpenRCBackend) Continue(name string) error { … }
func (b *MyOpenRCBackend) Kill(name string) error { … }
p := svman.NewWithBackend(&MyOpenRCBackend{})Dynamic plugin loading
make build-plugins # build/plugins/*.so
PLUGIN_DIR=./build/plugins ./build/sysmanCustom .so plugin:
// myplugin/main.go
package main
import "codeberg.org/oSoWoSo/SysMan/api"
func New() api.PluginIF { return &myPlugin{} }go build -buildmode=plugin -o plugins/myplugin.so ./myplugin/Note: Go plugins require the same Go version and module dependencies as the host binary. Dynamic loading is Linux-only.
Makefile targets
| Target | Output |
|---|---|
make build |
all 12 binaries |
make build-sysman |
build/sysman — full system manager |
make build-sysman-tui |
build/sysman-tui — full system manager (TUI entry) |
make build-svman |
build/svman — Services standalone |
make build-svman-tui |
build/svman-tui — Services TUI (CGO-free) |
make build-ugman |
build/ugman — Users & Groups standalone |
make build-ugman-tui |
build/ugman-tui — Users & Groups TUI
(CGO-free) |
make build-infoman |
build/infoman — SysInfo standalone |
make build-infoman-tui |
build/infoman-tui — SysInfo TUI (CGO-free) |
make build-srcman |
build/srcman — Templates standalone |
make build-srcman-tui |
build/srcman-tui — Templates TUI (CGO-free) |
make build-pkgman |
build/pkgman — Packages standalone |
make build-pkgman-tui |
build/pkgman-tui — Packages TUI (CGO-free) |
make build-plugins |
build/plugins/*.so — dynamic plugins |
make test |
run tests with race detector |
make lint |
go vet + golangci-lint |
make fmt |
gofmt -s |
make install |
install all binaries + lang files |
make uninstall |
remove installed files |
make release |
per-binary tarballs with sha256 checksums |
make clean |
remove build/ |
Security
Service operations (sv, symlink enable/disable) require
elevated privileges and are run via pkexec,
doas, or sudo (whichever is available).
Optional passwordless rules (add via visudo or
/etc/doas.conf):
# sudo
%wheel ALL=(ALL) NOPASSWD: /usr/bin/ln -s /etc/sv/* /var/service/*
%wheel ALL=(ALL) NOPASSWD: /usr/bin/rm /var/service/*
%wheel ALL=(ALL) NOPASSWD: /usr/bin/sv * /var/service/*
# doas (/etc/doas.conf)
permit nopass :wheel cmd ln
permit nopass :wheel cmd rm
permit nopass :wheel cmd sv
Dependencies
fyne.io/fyne/v2 GUI framework (CGO required)
github.com/charmbracelet/bubbletea TUI framework
github.com/charmbracelet/lipgloss Terminal styling
github.com/charmbracelet/bubbles TUI components
gopkg.in/yaml.v3 YAML parsing
License
MIT — see LICENSE