Orbit
A declarative CLI tool to manage tasks and reminders, using systemd as its back-end.
Define your scheduled tasks and reminders in a single TOML file, and Orbit manages the systemd timers and services for you.
Who is this for?
Anyone on a systemd-based Linux system who wants an easier way to manage recurring tasks and reminders without hand-writing unit files.
Quick start
# Build from source
go install github.com/guille/orbit/cmd/orbit@latest
# or with mise
mise use -g github:guille/orbit
# or download a published release
# Create and edit your config
orbit edit
# Preview what will change
orbit plan
# Apply the configuration
orbit apply
# show help
orbit help
Example config
See the example config.
Schedules use systemd's OnCalendar syntax.
Internals
This section goes into a bit more detail of what happens behind the scenes when Orbit is managing units.
orbit maintains its own state file (default location: ~/.local/share/orbit/state.json) tracking last run time, last exit code, retry state, pending reminders, and the applied configuration. This means changes to orbit.toml do not take effect until orbit apply is run. This is intentional, it prevents a half-edited config from breaking running tasks.
There are two supported types of configuration: tasks and reminders.
Tasks
A task is a command defined and ran by systemd on the given frequency, with the configured retries. Orbit manages the systemd entries and gathers some data (last run, exit code, etc.).
Instead of using systemd for the retries, orbit registers itself as the task runner with a hidden command (orbit _run $taskname). When called, it reads the command and retry settings from the applied config in the state store (not from orbit.toml), handles execution and retries, and updates the state store.
Each task becomes two files: a .timer and a .service unit.
orbit-task-NAME.service — runs the command, has Type=oneshot
orbit-task-NAME.timer — with Persistent=true for catch-up
Reminders
Reminders get a service that calls orbit _notify NAME, not the user's command. The user-configured commands are never executed autonomously, it is the user that must run them.
Reminders stack. So if there is a daily reminder that hasn't been acknowledged for a week, the status might show as "7 overdue".
When a reminder fires, a desktop notification is sent via notify-send.
The command orbit ack $reminder_name acknowledges the reminder: marks it done, clears the pending state, and prompts to run the command (if set).
The user may also wish to snooze a reminder. This can be done with orbit snooze. Internally, orbit writes "snoozed until T" to state, and then creates a systemd timer to trigger the reminder again.
A simple sentinel fine (default location ~/.local/share/orbit/pending) is created when there is at least one reminder that needs to be acknowledged. It contains the number of pending reminders as a number. This can be used for scripting or shell integration.
Shell completions
Orbit supports completions for Bash, Zsh, Fish, and PowerShell via Cobra's built-in completion command:
# Bash
orbit completion bash > ~/.local/share/bash-completion/completions/orbit
# Zsh
orbit completion zsh > "${fpath[1]}/_orbit"
# Fish
orbit completion fish > ~/.config/fish/completions/orbit.fish
Restart your shell or source the file to activate.