table of contents
- NAME
- HOW EXOSPHERE WORKS
- INSTALLATION
- UPDATING EXOSPHERE
- QUICKSTART GUIDE
- SUPPORTED REMOTE PLATFORMS
- WHAT'S NEW?
- COMMAND LINE INTERFACE (CLI)
- TEXT USER INTERFACE (TUI)
- REPORTING AND JSON EXPORT
- CONNECTIONS AND AUTHENTICATION
- THE CONFIGURATION FILE
- SUDO POLICIES AND PRIVILEGES
- MANAGING CACHE
- TROUBLESHOOTING GUIDE
- FREQUENTLY ASKED QUESTIONS
- GETTING HELP
- PROVIDERS
- CLI COMMAND REFERENCE
- GLOSSARY AND COMMON TERMS
- RELEASE NOTES
- EXOSPHERE API REFERENCE
- Author
- Copyright
| EXOSPHERE(1) | Exosphere | EXOSPHERE(1) |
NAME¶
exosphere - Exosphere 3.0.0
Exosphere offers aggregated patch and security update reporting as well as basic system status across multiple Unix-like hosts via SSH.
It is targeted at small to medium sized networks.
It is meant to be simple to deploy and use, requiring no central server, agents or complex dependencies on remote hosts.
If you have SSH access to the hosts with an agent <https://en.wikipedia.org/wiki/Ssh-agent>, you are good to go!
Key Features
- Rich interactive command line interface (CLI)
- Text-based user interface (TUI) offering menus, tables and dashboards
- Consistent view across different platforms and package managers
- See everything in one spot, at a glance, without complex automation or enterprise solutions.
- Document-based reporting in HTML, text or markdown format
- JSON output available for integration with other tools
Compatibility
- Exosphere: Linux, BSDs, macOS, Windows (and more!)
- Remote: Debian/Ubuntu-likes, RedHat-Likes, FreeBSD, OpenBSD
Note:
Exosphere is written in Python and abstracts away the technical details of collecting this information across platforms, allowing you to focus on management of your systems.
You can get started with Installation <> and then follow up with the Quickstart Guide <> to get an overview of how to use Exosphere.
The Configuration File <> details are also available, alongside the Exosphere API Reference <> if you wish to implement your own providers.
HOW EXOSPHERE WORKS¶
Exosphere runs entirely from your own machine. There is no agent to install, no server to keep running, and nothing extra living on the remote hosts --- everything happens over plain SSH, driven by the Command Line Interface (CLI) <> or Text User Interface (TUI) <> on your workstation or laptop.
This page offers a quick overview of how the pieces fit together, so the commands in the Quickstart Guide <> (and everywhere else) make sense.
Overview¶
Your machine connects to each host over SSH, runs a handful of ordinary, mostly read-only commands (the kind you could type yourself), and brings the results back home. The hosts need nothing installed beyond what they already ship with: an SSH server and a POSIX shell.
See Supported Remote Platforms <> for the specifics of what is required on each end, as well as the Connections and Authentication <> page for details on SSH access.
Concepts¶
Three concepts carry most of the weight:
- Host
- One remote system Exosphere connects to.
- Inventory
- The full collection of hosts, defined in your The Configuration File <>. Most commands operate on the whole inventory unless you name specific hosts.
- Provider
- The platform-specific adapter (apt, dnf/yum, pkg, pkg_add) that knows how to ask a given host about its updates. The right one is detected automatically during discovery --- you never pick one by hand.
The full vocabulary lives in the Glossary and Common Terms <>, but most of it should be fairly self-explanatory. Details about the providers are available in the Providers <> section.
Usage Lifecycle¶
Working with your hosts follows a simple loop:
- 1.
- Discover: connect once and detect the operating system, version, flavor and package manager, then assign the right provider. You only repeat this if something fundamental changes on the host.
- 2.
- Refresh: ask the provider what updates are available, sort out which ones are security-related, and note whether a reboot is pending. This is entirely read-only.
- 3.
- Repository Sync (optional): refresh the host's own package metadata first, so the next Refresh sees the very latest. This is the one step that may require Sudo Policies and Privileges <> on some platforms.
- 4.
- View / Report: look at the results, via the Command Line Interface (CLI) <> status tables, the interactive Text User Interface (TUI) <>, or generated reports <>.
Everything Discover and Refresh learn is saved to a local cache, so viewing status and generating reports never needs to touch the hosts again. This is handy for scheduled reports, or simply running from a context where your SSH agent is not available. See Managing Cache <> for more details.
What Exosphere Is Not¶
Exosphere reports --- it does not act. It will happily tell you what needs patching, where, and how urgently, but it will never apply an update or change a host's configuration on your behalf. Pushing those changes out is left to existing tooling built for the job, such as Ansible <https://www.ansible.com/> and similar automation frameworks, or unattended-upgrades <https://wiki.debian.org/UnattendedUpgrades> and similar.
See the Frequently Asked Questions <> for more on this distinction, and why it is a deliberate one.
INSTALLATION¶
Exosphere is written in Python, and can easily be installed using a handful of methods. This guide will walk you through the installation process for each of them.
Supported Platforms¶
Exosphere is designed to be platform agnostic, and can be run nearly everywhere Python runs. This guide can be used to install Exosphere on the following platforms:
- Linux (any)
- FreeBSD
- macOS
- Windows
Platform specific notes will appear whenever relevant, but the process should be the same across all platforms.
Exosphere technically supports more platforms than the ones listed above, but these are the ones we have explicitly tested. You can still follow the instructions below in most cases, but your mileage may vary.
Installing from PyPI¶
Exosphere is available on the Python Package Index <https://pypi.org/project/exosphere-cli/> (PyPI) for convenience, and can be installed using various methods.
The package name is exosphere-cli.
- Note
-
Exosphere requires Python 3.13 or later to run. If you do not have it available on your system, you can still install Exosphere using uv <https://docs.astral.sh/uv/getting-started/installation/>, which will download and manage the necessary Python runtime and dependencies for you.
pipx This is the recommended way to install Exosphere, as it creates a virtual environment and isolates the application. You can install pipx from your distribution's repositories.
pipx install exosphere-cli
uv <https://docs.astral.sh/uv/getting-started/installation/>
If you do not have Python 3.13 or later available, you can use uv <https://docs.astral.sh/uv/getting-started/installation/> to install Exosphere. Click the link above to see how to install uv <https://docs.astral.sh/uv/getting-started/installation/> for your platform, and then simply run:
uv tool install exosphere-cli
uv tool will handle downloading and installing the necessary Python runtime and dependencies for you, and then make the exosphere command available in your PATH.
The pipx or uv tool methods are recommended as they create a virtual environment and isolate the application, making it readily available without having to contend with potential conflicts with other Python packages.
The main difference is that uv tool will also download and manage the necessary Python runtime for you, if you do not have a suitable version available.
pip install is not recommended outside of a venv, as it will interfere with other Python packages and system versions of the libraries, and many distributions will in fact not allow you to install it that way.
Once installed, you can run Exosphere using the exosphere command, like so:
exosphere --help
Installing from Git Repository¶
This is likely the easiest method if you want to track the latest development version, or are simply more comfortable with using Git.
The project is set up with uv <https://docs.astral.sh/uv/getting-started/installation/>, which will download and install the necessary Python runtime and dependencies for you, so you don't have to worry about any of this.
You will require the following tools installed:
- git <https://git-scm.com/> - to clone the repository
- uv <https://docs.astral.sh/uv/getting-started/installation/> - to install the application and manage its dependencies
First, clone the repository into a directory of your choice. HTTPS
SSH
git clone git@github.com:mrdaemon/exosphere.git
Then, change into the cloned directory:
cd exosphere
If you want the stable version, you can switch to the latest tag. Stable Release This will fetch the code for the latest stable release of Exosphere. This is recommended for most users.
git checkout v3.0.0
You can substitute v3.0.0 with a specific tag or version to use a specific release, e.g., v0.8.1.
You can find the list of tags on the GitHub releases page <https://github.com/mrdaemon/exosphere/releases>. Latest Development If you want the latest development version, you can switch to the main branch. This is not recommended for most users, as it may contain unstable or untested code.
If you want to hack on Exosphere, or get the latest features even if they are not fully tested, you should use the main branch.
git checkout main
Once that is done, you can simply set up Exosphere using uv <https://docs.astral.sh/uv/getting-started/installation/>:
uv sync --no-dev
This will download and install the necessary Python runtime and dependencies.
You can then either run Exosphere through uv <https://docs.astral.sh/uv/getting-started/installation/>:
uv run --no-dev exosphere
Or, you can activate the virtual environment created by uv <https://docs.astral.sh/uv/getting-started/installation/> and run Exosphere directly: Unix/macOS
source .venv/bin/activate exosphere
Windows/PowerShell
. .venv\Scripts\activate.ps1 exosphere
Windows/cmd
.venv\Scripts\activate.bat exosphere
From that point on, you can run Exosphere using the exosphere command.
UPDATING EXOSPHERE¶
Exosphere often receives bug fix releases and new features. You can easily check if you have the latest available version of Exosphere by running:
exosphere> version check
or, from your operating system's shell:
$ exosphere version check
The output will tell you what version you are on, and what new version is available, if any.
Updating Exosphere is generally as simple as installing it, depending on the installation method you used.
Release Notes¶
You can (and should) consult the release notes on the GitHub releases page <https://github.com/mrdaemon/exosphere/releases> to see what has changed in each release, and if there are any special instructions or considerations for updating.
Generally, you should be able to update without any issues, however.
From PyPI¶
pipx If you installed Exosphere using pipx, you can update it with:
pipx upgrade exosphere-cli
uv If you installed Exosphere using uv, you can update it with:
uv tool upgrade exosphere-cli
From Git Repository¶
If you installed Exosphere from the Git repository, you can update it by pulling the latest changes and then syncing with uv <https://docs.astral.sh/uv/getting-started/installation/>: Stable Release If you are on a stable release, you can update it with:
git fetch --tags git checkout v3.0.0 uv sync --no-dev
You can substitute v3.0.0 with the latest tag or specific version you want to use, e.g., v0.8.1.
You can find the list of tags on the GitHub releases page <https://github.com/mrdaemon/exosphere/releases>. Latest Development If you are on the main branch, you can update it with:
git pull --rebase uv sync --no-dev
That's it! Your installation of Exosphere is now up to date.
QUICKSTART GUIDE¶
After Installing Exosphere <>, you can quickly get started by following this guide and adapting the simple scenario it presents to your needs.
Create the Configuration File
$ exosphere config paths
Create config.yaml in the Config directory shown here.
Tip:
Basic configuration
Add your hosts <#config-inventory> and options <#config-options> to the configuration file.
# Username for SSH connections, optional # If not specified, the current user will be used. # The entire "options" section can be omitted if you # don't need to set any global options. options:
default_username: admin # Hosts to manage hosts: - name: dbhost1
ip: dbhost1.example.com
description: Database Server - name: web1
ip: web1.example.com
description: Frontend Web Server - name: fileserver
ip: 192.168.0.28 # ip is fine too
port: 2222 # Optional port if not 22
username: alice # This one has a special login
# description is optional
- Note
-
This assumes your private keys are loaded in your SSH agent. See Connections and Authentication <> for more details.
Run Exosphere
$ exosphere
At the exosphere prompt, you can run commands to manage your hosts. You can also explore the interactive help system in the CLI by running:
exosphere> help
Discover Hosts
exosphere> inventory discover
This will detect the platform and package manager for each host. It only needs to be done once, or if something changes on the host.
If you encounter issues at this step, see the Connections and Authentication <> and Supported Remote Platforms <> pages for more details.
Refresh Hosts
exosphere> inventory refresh
This will refresh the state of each host and collect information about available updates.
View Status and Host Details
exosphere> inventory status exosphere> host show hostname
There you go! You are now set up with a basic Exosphere configuration and can aggregate your updates all in one place.
Next Steps¶
For more fundamental details, you could have a look at How Exosphere Works <>.
To go further, you can:
- Explore the various commands in the Command Line Interface (CLI) <>
- Explore the Reporting and JSON Export <> features to generate reports and json data
Or start the full Text User Interface (TUI) <> for a more interactive experience:
$ exosphere ui
Tip:
The Frequently Asked Questions <> section may also be helpful for common questions and issues.
SUPPORTED REMOTE PLATFORMS¶
While Exosphere itself is generally as platform agnostic as possible, it is limited in what operating systems and platforms it can manage and query. This is broadly limited to Unix-like platforms, including Linux and BSD variants.
There are two tiers of effective support in Exosphere.
- 1.
- Full Support: Allows connectivity checks, update and patch reporting, and detailed host information gathering.
- 2.
- Limited Support: For unsupported platforms that are still Unix-like, Exosphere is limited to basic SSH connectivity checks and presence in the dashboard.
Platform support for Patches and Updates is implemented via an extensible provider system, which allows for new platforms to be added in the future.
If your remote operating system does not have a provider, you can still use Exosphere for the basic SSH ping connectivity checks and Dashboard. They will show up in the inventory, but no patch and update reporting features will be available, as long as it is a Unix-like operating system and obeys basic POSIX standards.
Unfortunately, this excludes exotic things such as Windows, routers with SSH enabled but proprietary, non-Unix-like operating systems, etc. Discovery will not work at all for these systems, and they should probably not be added to the inventory.
Compatibility List¶
✅ Exosphere fully supports the following platforms:
- Debian (all versions)
- Ubuntu and derivatives (Mint, Pop!_OS, etc.)
- Package Manager: apt only
- Red Hat Enterprise Linux (RHEL)
- CentOS / CentOS Stream
- AlmaLinux / Rocky Linux
- Fedora
- Package Managers: yum (RHEL/CentOS 7 and earlier) or dnf (modern systems)
- FreeBSD (all supported versions and minor variants)
- OpenBSD (all supported versions)
- Package Managers: pkg (FreeBSD), pkg_add (OpenBSD)
- note
-
FreeBSD optionally requires the sudo package for repository sync operations. Unfortunately doas is not supported at this time.
☑️ Exosphere has limited support for the following platforms:
- Other Linux distributions (e.g., Arch Linux, Gentoo, NixOS, etc.)
- Other BSD systems (e.g. NetBSD)
- Other Unix-like systems (e.g., Solaris, AIX, IRIX, Mac OS)
The bar for entry is fairly low to fit this description, as long as it can be connected to via SSH, has a POSIX shell available [1] and returns something useful via uname -s, it will work here.
❌ Exosphere explicitly does not support the following platforms:
- Windows (all versions, but WSL over SSH is supported)
- Network Equipment with proprietary operating systems (e.g., Cisco IOS, Juniper JunOS)
- Other non-Unix-like operating systems that support SSH
Tip:
Common Prerequisites¶
All supported platforms share the same basic requirements, as Exosphere operates entirely through SSH connections and standard system utilities.
Essential Requirements
- SSH access to the remote host (with an SSH agent <https://en.wikipedia.org/wiki/Ssh-agent> for authentication)
- Package manager binaries installed and available in $PATH (typically pre-installed)
- A POSIX Shell [1] (present on every supported platform)
- Standard UNIX utilities such as grep, awk, and cut (POSIX-compliant, typically available by default)
- [1]
- Exosphere runs all remote queries through the POSIX standard
/bin/sh shell, which is present on all supported platforms,
ensuring consistent behavior across them.
Optional Requirements
- Elevated privileges for certain operations on some platforms (i.e. root)
- sudo installed on the remote host (if needed) and configured properly <>
See below for more details.
Network Requirements
- Outbound internet access from managed hosts, at least to the package repositories
- SSH connectivity between your workstation and managed hosts
Some providers may require elevated privileges to perform certain operations, but this is entirely optional.
More details about all of this are available in the Connections and Authentication <> and Sudo Policies and Privileges <> sections.
Note:
WHAT'S NEW?¶
The highlights of the current Exosphere release are below. For the complete history of past releases, see the Release Notes <> in the Reference section.
3.0.0 - Reboots, Palettes, Sorting and refreshed CLI¶
The first major version release actually backed by a major set of changes. This release lands several long overdue features, refactors a lot of internals, swaps out the entire CLI engine and provides a much more polished help and documentation experience.
It has been cooking for a while, and the release notes are correspondingly long. Most of these changes are transparent, but there are some unavoidable incompatibilities. Make sure to read User Actions Required and Incompatible Changes before upgrading.
Feature Highlights¶
Pending Reboot Detection¶
[image: image] [image]
Exosphere can now tell you when a host is waiting on a reboot to finish applying updates --- a running kernel that no longer matches the installed one, a distro's reboot-required flag, and so on.
This is another feature grown out of a question that comes up frequently when managing updates across a fleet of hosts: "Has everyone been rebooted?". It felt only natural for Exosphere to attempt to answer that question.
This is presented in several places across the application interfaces:
- The CLI and inventory TUI status tables, as a small ! marker in the Status column --- much like the existing * marker for stale data
- Detailed host views (host show, the TUI host details panel)
- Reports of every format (text, Markdown, HTML) and JSON output
The feature is implemented for all supported platforms where this information is available (Debian/Ubuntu, RHEL and derivatives, FreeBSD) and is entirely best-effort. None of the reboot checks require elevated privileges, so there is no sudoers change. If a provider cannot determine the status --- a missing tool, an unexpected error --- it is simply reported as unknown rather than failing the operation, so it will never block you from doing anything else.
TUI Command Palette Operations¶
For a long time the only way to perform targeted operations on a specific host was to use the CLI host commands, or specify hosts in bulk inventory operations.
The TUI was previously limited to bulk operations, and on specific screens.
To resolve this, the TUI now makes use of the command palette (Accessible via Ctrl+P) to allow you to run any of the host operations (sync, refresh, ping, etc) from any screen, and targeting any host.
[image: image] [image]
Selecting hosts also conveniently presents as a fuzzy search list, making the whole process light in keystrokes, and high in discoverability.
[image: image] [image]
The palette will also preselect the currently highlighted host in the Inventory screen, further lubricating the process.
[image: image] [image]
The palette and its operations can be invoked from any screen, and with this, there is finally functional parity between the CLI and TUI for host operations.
Inventory Sorting¶
[image: image] [image]
[image: image] [image]
Inventories can now be sorted, in both the CLI and the TUI.
- On the CLI, status and the inventory listing gained sort options, including a compound sort by flavor and a --full view that includes the description for hosts.
- In the TUI, a sort modal lets you pick a field with quick-select keys and reverse the order with r.
Undiscovered and unsupported hosts always sort last, so the interesting hosts stay at the top regardless of the chosen field.
Reworked Built-in Help and CLI Polish¶
Exosphere has swapped out its CLI framework internals, and with that came the perfect opportunity to give a polish pass to the built-in help system.
[image: image] [image]
Multiple help panels, especially for the most complex commands like sudo or report, have been rewritten to be more helpful, explain what they do, and most importantly, group their copious options and flags into logical, meaningful sections.
[image: image] [image]
Additionally, unknown commands or verbs will now display a helpful message, with fuzzy suggestions for what you might have meant, leading to a friendlier experience when exploring the CLI or REPL.
The CLI engine change also brings a lot of internal improvements and better behavior for both the CLI and REPL.
New Commands¶
A few small but helpful new commands have been added:
- config edit -- opens the current configuration file in your text editor, with proper validation and waits. The editor is determined by configuration, $EDITOR, or falls back to a platform default.
- report schema -- exports the current JSON schema for the reporting system, to use as a reference or for validation in external tools.
- report status -- a very short, two or three lines summary of the current state of the inventory. Suitable for inclusion in scripts or system MOTD.
All of these are documented more extensively in the Command Line Interface (CLI) <> docs as well as the Reporting and JSON Export <> docs.
The Web UI has been removed¶
It had always been more of an experimental curiosity than a real feature, and had not been actively developed since 1.0.0. Newer features (such as instance/cache locking) had begun to clash with it, and on balance it had become more of a maintenance burden than a useful capability.
As a result:
- The ui webstart command has been removed.
- The web optional dependency extra (textual-serve) is gone.
- A bare ui command now launches the TUI directly.
- ui start remains as a compatibility alias for launching the TUI, so existing muscle memory and scripts are not broken.
See the User Actions Required section for details.
Other Improvements¶
- Task Dispatch Logic Improvements -- the subsystem responsible for dispatching tasks to hosts has been refactored and unified across the CLI and TUI. This includes better handling of unsupported hosts, and preemptively skipping them in bulk operations where they would otherwise do nothing.
- Remote command robustness -- all remote commands now setup a POSIX-compliant, deterministic environment for execution. This includes running all provider commands under /bin/sh, and pinning the locale to a known value. This makes reliability across login shells and localized server environments much more predictable.
- Cache file locking -- Exosphere now takes a lock on the state cache to prevent two concurrent instances from writing to it at the same time.
- Stricter configuration validation -- malformed configuration files (non-mapping documents, and other structural problems) now produce clear, actionable errors instead of confusing downstream failures. Empty config files are handled gracefully.
- Logging polish -- Package Manager Providers now automatically prefix their log messages with the host that produced them, making the logs much more useful.
- Non-TTY Handling -- Exosphere now actively guards interactive-only features when running in a non-TTY environment, such as script, cronjob or similar. The primary side effect is that it prevents Exosphere from hanging while trying to read input it will never receive, and instead produces a clear error message.
Bugfixes¶
Exosphere¶
- CLI and TUI now use the same descriptors for undiscovered hosts, instead of "(unknown)".
- Fixed latent config load issue with paths, which could result in environment variables not being applied correctly or ignored, in rare cases.
- --version flag no longer goes through the entire initialization process, and now prints the version immediately.
- TUI Inventory Screen now correctly preserves the cursor position when refreshing
- Fixed issue where Dashboard host would fall back to "(unknown)" instead of "(unsupported)" when detected as Offline.
- Cancelling a TUI Sync operation now also correctly aborts the follow-up Refresh, instead of infuriatingly continuing to run the next step of the chain.
- Removed a spurious notification when a filter matched no hosts after an operation triggered a refresh in the TUI.
Providers¶
- OpenBSD -- Correctly handle flavors, quirks renames. All scenarios should now parse correctly.
- RHEL -- Fix issue parsing post-release snapshots, especially on Fedora and derivatives. Parsing has been lined up with upstream package name specs, and should be more robust from hereon.
User Actions Required¶
Shell completion must be reinstalled. The new CLI engine generates completion differently, so re-run exosphere --install-completion to install the updated scripts. On everything except PowerShell the new scripts take precedence and the old ones are harmless leftovers. If you do not use the shell completion feature at all, you have nothing to do. If you would like to remove the old scripts, see the FAQ <#faq-completion-upgrade> for the full details.
PowerShell completion is no longer supported and its leftovers must be cleaned up by hand, unfortunately, as there is no way around it. See the FAQ <#faq-completion-upgrade> for the full details and cleanup steps.
Web UI has been removed. The ui webstart command and the web install extra no longer exist. If you installed Exosphere as exosphere-cli[web], drop the [web] extra from your install. Existing installations will automatically resolve this on their own during upgrade, so there is no need to reinstall. Use the TUI instead, which is now the default ui command.
Incompatible Changes¶
- CLI Return Codes: The CLI now returns 1 for input errors, and 2 for runtime errors. This is a change from the previous behavior where this was reversed. Scripts that depended on the old behavior will need to be updated. The behavior of special status code 3 remains unchanged.
- Multiple instances of Exosphere are no longer supported. This was never a supported configuration, given the semantics of the cache file, but it also was never explicitly protected against. The cache file is now locked to prevent concurrent access and a second instance will fail to start with a clear error message.
Project and Documentation¶
- Licensing -- the repository's licensing was cleaned up into a REUSE-style layout, with a top-level COPYRIGHT, per-license files under LICENSES/, and an explicit LLM contribution policy added to the README.
- Changelog system -- release notes are now maintained in-repo as Markdown files under changelog/, rendered into the docs by a small Sphinx extension that manages the index and "What's New" page automatically. All 26 prior releases were backfilled.
- Docs refresh -- the table of contents was reorganized with a new Concepts section, the CLI reference was reformatted, screenshots were refreshed for the new features, and most importantly, a significant polish pass was made, making this version of the online documentation the best so far. Many dense sections were split and reorganized for better legibility, including the FAQ.
What's Changed¶
- Add ability to sort inventory (CLI and TUI)
- Unify undiscovered display, fix dashboard bug
- TUI: Add Command Palette entries for Host Operations
- Remove Typer, Replace with Cyclopts
- Improve UI logging, cleanup loglevels
- Improve CLI help formatting and validation logic
- CLI: Skip unsupported hosts during sync and refresh
- REPL: Fix help behavior for invalid subcommands
- CLI: Add --install-completion support
- UI: Add quick-select keys for sorting options
- Add log caps to Application logs, REPL History
- Main: Fix latent config load issue with paths
- UI: Select Sort Modal entries via quick key
- Add file locking to prevent concurrent cache use
- Add config edit command, refactor CLI internals
- Config: Add stricter schema validation
- Cleanup Project Licensing
- Add pending reboot detection feature
- Remove Exosphere Web UI feature
- redhat: Fix issue parsing post-release snapshots
- Core: Enforce locale and shell for remote commands
- TUI DataTable Improvements, preserve cursor position during refresh
- CLI: Cleanup and improve help text for commands
- docs: Reformat CLI reference docs
- OpenBSD: Correctly handle flavors, quirks renames
- Docs: Reorganize TOC, add Concepts, docs refresh
- Docs: Add Changelog and Changelog Accessories
- Reporting: Add schema export and status commands
- Core: Cleanup task dispatch for unsupported hosts
- Tests: Consolidate Host factory fixtures
COMMAND LINE INTERFACE (CLI)¶
The primary mode of interaction with Exosphere is through its rich command line interface (CLI). The CLI is designed to be reasonably intuitive, but also discoverable, allowing users to explore available commands and options interactively.
Basic Usage¶
The CLI itself has two main modes of operation:
- Normal Mode
- This is the default mode where you can run exosphere commands directly as arguments to the exosphere command.
- Interactive Mode
- You can enter an interactive shell by running exosphere without any arguments. In this mode, the prompt will change to exosphere> and you can run commands interactively. Exosphere will function like a REPL or Shell. You can exit with exit or quit.
Tip:
Getting help¶
You can explore the root commands available by running exosphere --help or typing help in the interactive shell. This will show you a list of available commands and their descriptions.
For a complete list of commands and options, see the CLI Command Reference <> page.
Initial Inventory Discovery¶
The first time you run Exosphere after populating your configuration file with options and hosts, you should perform a Discovery operation.
This operation will connect to each host and attempt to detect what platform, operating system, flavor, version and package manager it is using.
It will then assign the appropriate provider to that host, which will allow Exosphere to query and refresh its package update status from here on.
If a host is present in the inventory, but not currently supported by Exosphere, it will be marked as such, and left available for Online checks. You will not be able to perform refresh or repo sync operations on them, and display panels will omit update information for them.
If a host is present in the inventory, not supported by Exosphere and also fails discovery due to not being a Unix-like operating system, it will return an explicit error, and should be removed for smooth operation.
For more details, see the Supported Remote Platforms <> page.
Inventory discovery can be done by running:
exosphere> inventory discover
Any errors will be printed to the console as well as the log file.
Tip:
exosphere> config paths
You can find the path under the Log: section of the output.
Refreshing Host State¶
Once you have discovered your hosts, you can refresh their state by running:
exosphere> inventory refresh
This will connect to each host in parallel, and fetch what updates are available, categorizing them, and storing the metadata in the cache file.
As part of the process, Exosphere will also attempt to check if the host has a pending reboot - for example, following a previously applied kernel or core library update.
If you want to also synchronize the repositories on each host to ensure the latest package lists are available, you can run:
exosphere> inventory refresh --sync
This will run the appropriate package manager command to update the repositories on each host, before fetching the update status.
- Note
-
The --sync option may require elevated privileges (sudo) on some platforms. See the Sudo Policies and Privileges <> page for more details on how to configure this. This operation may also take quite a long time, depending on the number of hosts and their specifications, as well as the network speed.
You can also do it all at the same time, including discovery, by running:
exosphere> inventory refresh --discover --sync
For details on how any of this is implemented, see the Providers <> page.
Viewing Inventory Status¶
The main command for viewing the status of your inventory is:
exosphere> inventory status
This will display a table of all hosts, their status and how many updates they have available. [image: Example output of `exosphere inventory status`] [image]
- Status indicators
-
Two markers may appear in the table, as noted in its legend:
- * next to the update counts marks stale data --- the host has not been refreshed in a while (configurable, see stale_threshold <#cmdoption-arg-stale_threshold>).
- ! next to a host's status marks a pending reboot --- the host needs to be rebooted (for example after a kernel update).
You can also select one or more specific hosts by providing their names as arguments:
exosphere> inventory status host1 host2
This will show the status for only those hosts, allowing you to focus on specific systems.
You can also filter the output to only show hosts with available updates by using the --updates-only or --security-only flags:
exosphere> inventory status --updates-only exosphere> inventory status --security-only
If this results in no hosts matching the criteria, Exosphere will print a message and exit with code 3.
By default, hosts are listed in the order they are defined in the configuration file. You can sort the table by any column using --sort, optionally reversing the order with --reverse:
exosphere> inventory status --sort updates --reverse exosphere> inventory status --sort os
The available sort columns are host, os, flavor, version, updates, security and status.
Sorting and filtering can be combined freely.
A useful filter and sort combo you might find useful out of the box would be:
exosphere> inventory status --updates-only --sort security --reverse
Or, in short form:
exosphere> inventory status -u -o security -r
It will show hosts with updates, sorted by amount of security updates, descending, which is a great at-a-glance view of what to patch first.
- Note
-
Sorting by version groups hosts by flavor first, then orders versions within each flavor, since version numbers are not directly comparable across different flavors (e.g. Debian 12 versus Ubuntu 22.04). Likewise, sorting by flavor groups hosts by OS first, keeping OS families together.
Additionally, hosts with no meaningful data for the selected sort column always sort to the bottom of the list, regardless of the requested order. Within that bottom tier, Undiscovered hosts sort above Unsupported ones.
You can include additional columns, such as each host's description, with the --full flag:
exosphere> inventory status --full
Viewing Host Details and Updates¶
To view detailed information about a specific host, including a detailed list of available updates, you can run:
exosphere> host show <hostname>
This will display detailed information about the host, including all of the useful metadata. This includes the last refresh timestamp, which provider it is using, whether a reboot is pending, etc.
It also will display a table of all available updates. [image: Example output of `exosphere host show`] [image]
Security updates are highlighted by default. You can also filter the updates via --security-only to only show security updates, or --no-updates to refrain from showing the table entirely.
Tip:
Online Checks¶
You can perform a quick online check to see if all your hosts are responding by running:
exosphere> inventory ping
This will attempt to SSH into each host and check if it is online. If a host is not reachable, it will be marked as offline and an error will be printed.
This is not an ICMP ping, but rather a full SSH connectivity check. It will only return "Online" if the host can be connected to successfully, and a trivial test command can be executed.
It can be a good way of validating connectivity to hosts. If ping returns "Online" for all hosts, you can be certain your SSH connectivity is working within the context of Exosphere.
This is by design to avoid scenarios where a host is reachable but not fully operational, for instance mid-startup or mid-shutdown, which would cause subsequent queries or operations to fail.
Hosts marked as Offline will be skipped in most operations such as refresh for performance reasons. You can invoke Ping to refresh this status at any time. [image: Example output of `exosphere inventory ping`] [image]
Viewing Configuration details¶
Exosphere makes it easy to answer questions about where it sourced its configuration from, what the current active configuration is, and what has been changed from the defaults.
You can view the path to the configuration file that was loaded by running:
exosphere> config source
You can view the currently active configuration for Exosphere by running:
exosphere> config show
If you also wish to see the contents of the inventory, you can supply the --full option.
You can also show exclusively the configuration options that have been changed:
exosphere> config diff
The output will include what the default value originally was.
Editing the configuration file¶
The config command has a friendly edit helper subcommand that allows you to easily open the configuration file in your preferred text editor, without needing to consult config paths or config show first.
exosphere> config edit
This launches your editor against the currently loaded configuration file. If no configuration file exists yet, the default platform path is opened instead, so you can create one from scratch.
The editor used is determined from the editor <#cmdoption-arg-editor> configuration option. In its absence, it will fallback to the VISUAL and EDITOR environment variables, and finally a platform default (notepad on Windows, vi elsewhere).
The command may include arguments: for graphical editors that detach immediately, pass the appropriate "wait" flag (for example code --wait) so Exosphere can wait until you are done.
Note:
After you close the editor, the file is validated. If it is invalid, the error is shown and you are offered the chance to re-open the editor and fix it. Pass --no-validate to skip this check.
Viewing the state of SSH connections¶
If you have SSH Pipelining <#ssh-pipelining-docs> enabled, you can view the current state of the SSH connection pool by running:
exosphere> connections show
This will display the currently open SSH connections, their age, and which hosts they are connected to, as well as tell you when they will be reaped.
You can manually close them with the following command:
exosphere> connections close
Both of these commands can take arguments, including specifying particular hosts. See the built in --help argument output for details.
If you do not have SSH Pipelining enabled (the default), connections are automatically closed after each operation, so these commands will have no effect.
Launching the Text-based User Interface¶
You can launch the text-based user interface (TUI) by running:
exosphere> ui
This will start the TUI, which provides a more interactive way to view and manage your inventory. You can navigate through the menus and perform operations using friendly shortcut keys displayed at the bottom of the screen.
An interesting feature of starting the TUI from the interactive shell like this is that you can switch back and forth between them seamlessly.
Once you exit the TUI, you will be returned to the exosphere> prompt, allowing you to run more targeted or specialized commands.
Tip:
For more details on the TUI, continue on to the Text User Interface (TUI) <> page.
Return Codes¶
Exosphere uses specific return codes to indicate the outcome of commands. Key return codes are typically:
- 0: Success - The command completed successfully without any issues.
- 1: Input Error - The problem is in what you asked: invalid arguments or options, an unknown host name, or a declined confirmation prompt.
- 2: Application Error - We couldn't do what you asked: an operation failed while running, such as a host that could not be reached or refreshed.
- 3: Special - A condition was met, not necessarily an error.
The special return code (3) is used very deliberately and is intended to assist with scripting and automation, where you need to differentiate between errors and specific conditions.
For instance, exosphere version check will return 3 if updates are available, and the various --updates-only filters on inventory status will also return 3 if no hosts matched what you requested, and lastly, sudo generate will return it as well if no sudoers snippet needs to be generated for that host/provider.
Commands returning 3 will typically inform you of the meaning in their help text.
- Note
-
In versions of Exosphere prior to 3.0, the "input" and "application" return codes were the other way around, with input errors returning 2 and application errors returning 1. This was in fact the major breaking change that justified the version bump.
Beyond the Basics¶
Every command offers exhaustive built in documentation. Feel free to explore the available commands and options with the --help flag, or by running help in the interactive shell.
For advanced, file based reporting, see the Reporting and JSON Export <> page.
A complete CLI Command Reference <> is also available, which provides a comprehensive list of all the commands and their options.
TEXT USER INTERFACE (TUI)¶
The Text User Interface of Exosphere provides a visual, interactive way of accessing the information gathered by Exosphere across your hosts.
It is a modal interface comprised of several screens you can toggle between, and allows you to perform actions such as:
- Viewing the status of all hosts in a Dashboard
- Viewing the inventory status and drilling down into host details
- Performing actions such as refreshing updates, pinging hosts, etc.
- Viewing runtime logs in a nice colored panel.
While the TUI does not provide all the features of the CLI, it is often more convenient for overviews and at-a-glance status checks. It does provide most of the same host operation features through screen actions as well as the command palette, and it can also easily be used in conjunction with the Command Line Interface (CLI) <> for more advanced operations.
Launching the UI¶
You can launch the UI by running:
$ exosphere ui
Or, from interactive mode:
exosphere> ui
Tip:
Note:
Interface Navigation¶
The UI is divided into several screens, each accessible via a keybind. At the very top of the screen, you will see the title bar with the current screen name.
The UI is separated in three main screens:
- Dashboard: A grid view of all hosts, showing their online status.
- Inventory: A detailed view of all hosts and their updates.
- Logs: A real-time view of the logs generated by Exosphere.
The bottom of the screen contains a status bar with keybinds for navigation and actions. [image: Example of Exosphere TUI with commands] [image]
Some of the keys displayed there will show up globally, while others are specific to the current screen you are on.
For instance here, you can press i to go to the Inventory screen. Keys are shown as they should be typed, so shift+p will trigger Ping All, and ctrl+d will trigger Discover All.
Universally, in every screen, you can press ctrl+p to access the command palette, which you can use to get keybind help, change the color theme, or run operations against all or specific hosts.
On Any Screen, you can press ctrl+q to Quit the UI.
Executing Operations¶
Most if not all of the operations you can perform on hosts in the UI are going to be dispatched through the same parallelized Thread Pool as the CLI, with minor implementation differences.
The UI will present a modal progress bar whenever this is occurring: [image: Example of Exosphere TUI Progress Bar] [image]
- Note
-
While you can press ESC to cancel the operation, it will not abort already executing tasks in the Thread Pool, only prevent new tasks from being started past this point.
The Command Palette¶
Pressing ctrl+p from any screen will open the Command Palette, which allows you to select and fuzzy search through commands that can be invoked. This includes some built-in ones like Keys and Theme, but also Exosphere specific commands allowing you to perform operations on hosts in your inventory.
The palette can be invoked from any screen, and the available commands will be contextual to the screen you are on, if applicable. [image: Example of Exosphere TUI Command Palette] [image]
Host operations come in three flavors:
On All Hosts [image: Example of Exosphere TUI Command Palette with global host operations] [image]
These include operations like Ping all hosts, Discover all hosts, Refresh all hosts etc. Invoking these will perform the action immediately, displaying the progress screen, as described in the previous section. These can be invoked from any screen.
On Any Host
These commands allow you to select a specific host from your inventory and perform an operation on it, such as Ping..., Discover..., Refresh..., etc. [image: Example of Exosphere TUI Command Palette with host-specific operations] [image]
Invoking these will open a second prompt with a list of hosts available in your inventory, allowing you to either select one with the arrow keys and Enter, or to fuzzy search for it by typing its name, completely or partially. [image: Example of Exosphere TUI Command Palette with host selection] [image]
These commands can also be invoked from any screen.
On the currently selected host
When the palette is opened from the Inventory screen, each operation will also propose a variant that applies to the currently selected host in the inventory table. [image: Example of Exosphere TUI Command Palette with current host operations] [image]
Selecting it will let you run that operation immediately on whichever host is currently under the cursor in the inventory. These options will also sort above the global ones in the palette, making them quick to access.
These can only be invoked from the Inventory screen.
Tip:
The Dashboard¶
The default screen Exosphere launches into is the Dashboard. It presents a colored grid, each square representing a host in your inventory. [image: Example of Exosphere TUI Dashboard] [image]
Each square is color coded according to the status of the host. Green for Online, Red for Offline. Basic information about each host is also displayed.
This view is mostly useful as a poor man's monitoring dashboard, allowing you to quickly see which hosts are online or offline at a glance.
The following operations can be performed from the Dashboard:
- Ping All: Press shift+p to ping all hosts and update their status.
- Discover All: Press ctrl+d to discover all hosts and update their platform information.
Inventory Screen¶
[image: Example of Exosphere TUI Inventory] [image]
The Inventory screen provides a detailed view of all the hosts in your inventory.
The following operations can be performed from the Inventory screen:
- Refresh Updates: Press ctrl+r to refresh the updates for all hosts.
- Sync & Refresh: Press ctrl+x to sync the repositories and refresh updates for all hosts.
- Filter: Press ctrl+f to filter the hosts shown in the table.
- Sort: Press ctrl+s to sort the table by a chosen column.
- Note
-
Syncing repositories may take a long time depending on inventory size and host specifications.
It functions almost identically to the inventory status command in the CLI, but it allows you to navigate the rows with the Arrow Keys. The same status indicators apply, with * marking stale data and ! marking a pending reboot, as shown in the table legend.
You can select a host with Enter, which will open a panel with more details: [image: Example of Exosphere TUI Host Details] [image]
Any available updates will be displayed in a list. You can navigate this list with the arrow keys, much like the inventory itself, and select any of them with Enter. [image: Example of Exosphere TUI Update Details] [image]
Details about the currently selected update will be displayed in a new panel. This includes the package name, source, version change and whether or not it is a security update.
Filtering Hosts
It is also possible to filter hosts with ctrl+f, which will open a prompt with the available filters. [image: Example of Exosphere TUI Filter Prompt] [image]
Tip:
After selecting a filter, only hosts matching the criteria will be displayed. The active filter will be shown in the status bar at the bottom of the screen: [image: Exosphere TUI Inventory Status Bar with Security Updates filter active] [image]
You can clear the filter by pressing ctrl+f again and selecting the "Show All" option.
Sorting Hosts
You can sort the hosts with ctrl+s, which opens a prompt listing the sortable columns along with a Reverse order checkbox. Navigate the columns with the Arrow Keys, toggle reverse by pressing r (or focusing the checkbox with Tab and pressing Space), and press Enter to apply. [image: Example of Exosphere TUI Sort Prompt] [image]
Tip:
After applying a sort, the active sort field and direction are shown in the status bar alongside any active filter. You can restore the original configuration order by pressing ctrl+s again and selecting the "Default (config order)" option (or pressing D). [image: Exosphere TUI Inventory Status Bar with sorted status and direction] [image]
Sorting and filtering are independent and can be combined freely.
- Note
-
Sorting by Version groups hosts by flavor first, then orders versions within each flavor, since version numbers are not directly comparable across different flavors. Likewise, sorting by Flavor groups hosts by OS first, keeping OS families together.
Additionally, hosts with no meaningful data for the selected sort column always sort to the bottom of the list, regardless of the requested order. Within that bottom tier, Undiscovered hosts sort above Unsupported ones.
Logs Screen¶
[image: Example of Exosphere TUI Logs] [image]
The Logs screen provides a real-time view of the logs generated by Exosphere. You can access it by pressing l from the Dashboard or Inventory screen.
The window can be scrolled left and right, and will color certain elements.
Tip:
REPORTING AND JSON EXPORT¶
Exosphere includes a comprehensive reporting system that allows you to generate detailed reports of your inventory status and system updates in multiple formats.
This functionality does not require any connectivity or live access to hosts and operates entirely from the Cache, allowing reports or json to be exported on a schedule or from a different context where your SSH agent is not available.
The only requirement is read access to the Exosphere cache database. (See Managing Cache <> for more details.)
Available Formats¶
Below are examples of each output format to help you choose the right one for your needs. HTML Report Styled with a visually appealing design, entirely self-contained in a single file. Suitable for reading or printing. Offers an optional quick navigation box to jump between hosts.
Recommended for most uses.
📁 Sample Reports:
- Full Report - Complete inventory with all hosts
- No Navigation - Without quick navigation menu
- Filtered Report - Specific hosts selection
- Security Updates Only - Only security-related updates
- Updates Only - Only hosts with available updates
Plain Text Useful for quick overviews or for environments where rich text is not supported. If you want a cron job that sends an email, don't worry, we got you.
Plain Text Report Sample (partial)
===================== SYSTEM UPDATES REPORT ===================== Full Report, complete, generated: 2026-06-25 15:44:01 -0400 Summary:
Total hosts: 5
Hosts with updates: 4
Total updates: 11
Security updates: 4 web-prod-01 (10.0.1.10) ----------------------- Web Server
System: linux ubuntu 22.04
Package Manager: apt
Last Refresh: 2026-06-25 13:44:01 -0400
Updates (4):
Security Updates (2):
- apache2: 2.4.52-1ubuntu4.6 -> 2.4.52-1ubuntu4.7
Source: security
- php8.1: 8.1.2-1ubuntu2.13 -> 8.1.2-1ubuntu2.14
📁 Sample Reports:
- Full Report - Complete inventory, text format
- Filtered Report - Selected hosts only
- Updates Only - Hosts with updates available
- Security Updates Only - Security updates only
Markdown Made available mostly as a lightweight intermediate format, since they can be rendered to a variety of other formats while providing support for tables. They can also be fed directly into any other tool that supports markdown.
Markdown Report Sample (header and first host info)
# System Updates Report Full Report, complete, generated on 2026-06-25 15:44:01 -0400 - **Total hosts:** 5 - **Hosts with updates:** 4 - **Total updates:** 11 - **Security updates:** 4 ## web-prod-01 (10.0.1.10) **System Information:** - **Description**: Web Server - **OS**: linux ubuntu 22.04 - **Package Manager**: apt - **Last Refresh**: 2026-06-25 13:44:01 -0400 **Available Updates (4):** | Package | Current Version | New Version | Sec | Source | |---------|-----------------|-------------|-----|--------| | **apache2** | 2.4.52-1ubuntu4.6 | 2.4.52-1ubuntu4.7 | **Yes** | security | | **php8.1** | 8.1.2-1ubuntu2.13 | 8.1.2-1ubuntu2.14 | **Yes** | security |
📁 Sample Reports:
- Full Report - Complete inventory, markdown format
- Filtered Report - Selected hosts only
- Updates Only - Hosts with updates available
- Security Updates Only - Security updates only
JSON Export Available for integration with other tools, implementation of which is left as an exercise for the reader. It is also useful for displaying the raw internal state of the inventory and hosts.
The downloadable examples below should give you a good idea of the structure.
For more details on the JSON schema, see the JSON Schema Details section below.
📁 Sample Reports:
- Full Report - Complete JSON inventory
- Security Updates Only - Security updates in JSON
- Updates Only - Available updates only
- Filtered Report - Selected hosts as JSON
Basic Usage¶
The simplest way to generate a report is:
$ exosphere report generate
This will output a plain text report to your terminal showing all hosts and their update status.
The --format/-f option controls the output format, and accepts any of text, html, markdown, or json.
Save to File
You can save the report to a file with --output/-o:
$ exosphere report generate --format html --output systems-report.html
Displaying Specific Hosts
Which hosts are included in the report can be controlled by specifying them as arguments. For example, to generate a JSON report for just three hosts:
$ exosphere report generate --format json web1 web2 database
Updates Available Only
The report can be filtered to only show hosts with updates available using --updates-only:
$ exosphere report generate --updates-only --format html --output updates.html
Security Updates Only
To exclusively select security updates, use --security-updates-only:
$ exosphere report generate --security-updates-only
Advanced Options¶
File Output with Preview
$ exosphere report generate --format html --output report.html --tee
Quiet Mode
$ exosphere report generate --format json --quiet --output daily-report.json
HTML Navigation
$ exosphere report generate --format html --no-navigation -o report.html
Report Content¶
All reports include:
- Host Information: Name, IP address, operating system details
- Update Summary: Total updates available, security updates count
- Update Details: Package names, versions, and security status
- Metadata: Report generation time and scope information
The presentation and formatting varies by format, but the core information remains consistent across all output types.
Tip:
Status Summary¶
For a quick, at-a-glance overview rather than a full report, report status prints a condensed, plain-text summary of the entire inventory:
$ exosphere report status 15 of 25 hosts have pending updates, 10 with security updates 2 hosts have a pending reboot. 1 host has stale data, consider running a refresh.
The reboot and stale lines only appear when there is something to report, and when nothing is pending the summary simply reads All hosts are up to date.. Hosts that have not yet been discovered contribute nothing to the counts, as they have no known state.
Like the rest of the reporting commands, this operates entirely from the cache and requires no connectivity. Color is automatically dropped when the output is not a terminal, which makes it well suited to non-interactive uses, such as redirecting it into a MOTD or similar through a user cronjob, timer, or periodic task.
JSON Schema Details¶
The JSON output format provides a structured representation of the inventory and update information, making it suitable for programmatic consumption.
If you want to have a Discord bot that reports updates, or feed your event queue for your astoundingly complex MQTT Doorbell Over Zigbee that also brews coffee, this should enable you to do so.
JSON Schema¶
The JSON output follows a well-defined schema for consistency and integration purposes. The schema is available in the source tree as exosphere/schema/host-report.schema.json, but is also made available here, corresponding to the version this documentation is built for:
host-report.schema.json as of v3.0.0
You can also emit the schema for your installed version directly from the CLI with report schema (printed to stdout, or written to a file with --output), which is handy for validating or integrating with the JSON output offline.
$ exosphere report schema --output host-report.schema.json
Structure Overview¶
The report consists of an array of host objects. When generated via the CLI, the hosts will be pre-filtered to only include hosts that have been discovered, are supported, and have a valid package manager provider <> assigned to them.
Tip:
Host Object Properties
| Property | Type | Description |
| name | string | Host identifier/name |
| description | string | Optional user-provided description of the host. Omitted if not provided. |
| ip | string | IP address or FQDN of the host |
| port | integer | SSH port number (Min: 1, Max: 65535) |
| os | string or null | Operating system family. null if not yet discovered. |
| flavor | string or null | OS distribution/flavor. null if not yet discovered. |
| version | string or null | OS version. null if not yet discovered. |
| supported | boolean | Whether this host type is supported by Exosphere |
| stale | boolean | Whether the host data is stale and needs refreshed |
| online | boolean | Whether the host was last reachable |
| needs_reboot | boolean or null | Whether the host requires a system reboot. null if undetermined or not tracked. |
| package_manager | string or null | Package manager in use. null if not yet discovered or unsupported. |
| updates | array | List of available updates |
| last_refresh | string or null | ISO 8601 timestamp of last data refresh. null if never refreshed. (Format: date-time) |
- Note
-
The description field will be omitted entirely if no description was provided for the host in the configuration.
Each host's updates array contains update objects with the following structure. Update Object Properties
| Property | Type | Description |
| name | string | Package name |
| current_version | string or null | Currently installed version. null for NEW packages or dependencies |
| new_version | string | Available version |
| security | boolean | Whether this is a security update |
| source | string | Update source/repository |
- Note
-
The current_version field may be null whenever the package is a new dependency. Interfaces in the Exosphere API usually translate this to the string (NEW), but the raw JSON will have null in these cases.
Example JSON report structure
[
{
"name": "web-server-01",
"description": "Production web server",
"ip": "192.168.1.10",
"port": 22,
"os": "linux",
"flavor": "ubuntu",
"version": "22.04",
"supported": true,
"online": true,
"package_manager": "apt",
"updates": [
{
"name": "curl",
"current_version": "7.81.0-1ubuntu1.4",
"new_version": "7.81.0-1ubuntu1.6",
"security": true,
"source": "security"
},
{
"name": "new-dependency",
"current_version": null,
"new_version": "1.0.0",
"security": false,
"source": "main"
}
],
"last_refresh": "2024-03-15T14:30:00.000Z"
},
{
"name": "database-server",
"ip": "192.168.1.20",
"port": 22,
"os": "freebsd",
"flavor": "freebsd",
"version": "13.1-RELEASE",
"supported": true,
"online": true,
"package_manager": "pkg",
"updates": [],
"last_refresh": null
} ]
More examples are available in the Sample Reports section above.
Integration Examples¶
Here are some concrete but deeply uncreative examples of how the reporting feature can be used in practice.
If you make a cool thing, please let us know <https://github.com/mrdaemon/exosphere/issues/new/choose> via a GitHub issue! We'll happily showcase it here.
Email text report about security updates
#!/bin/bash exosphere report generate --updates-only --quiet \ | mail -s "System Updates Available" bigadmin@example.com
JSON Processing with jq
# Count hosts with security updates
exosphere report generate --format json --security-updates-only | jq 'length'
# Extract just host names and update counts
exosphere report generate --format json | jq '.[] | {name, updates: .updates | length}'
# The same but only hosts that have updates
exosphere report generate --format json \
| jq '.[] | select(.updates | length > 0) | {name, updates: .updates | length}'
CONNECTIONS AND AUTHENTICATION¶
This section of the documentation describes the authentication mechanisms (or lack thereof) provided by Exosphere, as well as how SSH connections are established and reused.
For how privileges and sudo are handled, see Sudo Policies and Privileges <>.
Connecting to systems¶
Exosphere uses SSH to connect to remote hosts, using the lovely Fabric <https://www.fabfile.org/> library. The intended authentication method is to use SSH keys, which should be loaded into your SSH agent.
Exosphere purposefully does not support password authentication in any of its subsystems, to avoid having to deal with the complexities of storing credentials, or prompting for them in a way that does not introduce a security risk.
The main configurable parameters of host connections (at least through Exosphere's interface) are as follows:
- The username <#default-username-option>, which is used to connect to the remote host.
- The port <#hosts-port-option>, which defaults to 22, but can be set to any port you like, per host.
- The IP or Hostname <#hosts-ip-option>, which is the address of the host to connect to.
- Note
-
Exosphere will (through Fabric) absolutely load and honor SSH client configurations from ~/.ssh/config or /etc/ssh/ssh_config if they exist.
This means you can set up advanced SSH options, such as host aliases, per-host SSH keys and even gateways, without relying on Exosphere to provide the functionality you need.
Using SSH Agents¶
An SSH agent is a program that loads your SSH keys into memory, usually with your login session on your workstation or laptop, allowing you to connect to remote hosts without having to enter your passphrase every time. This is instrumental to many SSH automation tools and workflows.
Exosphere relies on the SSH agent to provide the necessary keys for authentication.
The process for setting up an SSH agent and/or generating key pairs for your hosts is beyond the scope of this documentation, but plenty of guides are available online, including your distribution's documentation.
A reasonable place to start is the Arch Linux Wiki's Article on SSH keys <https://wiki.archlinux.org/title/SSH_keys>, which is generic enough to apply to most if not all distributions.
Tip:
Testing connectivity¶
You can test your SSH connectivity to a host using discover as it will display a nice table of errors for hosts where connectivity fails.
You can do this for the entire inventory with:
exosphere> inventory discover
Or for a specific host, such as a host named bigserver:
exosphere> host discover bigserver
Authentication failures will display clearly in the output. The exact cause, however, can vary, but you should check the following:
- Ensure your SSH agent is running and has the necessary keys loaded.
- Ensure the username and port are correct in The Configuration File <>
- Ensure the remote host is reachable over the network and that the SSH service is running.
- Ensure the remote host's SSH configuration allows Public Key Authentication
For debugging purposes, you can try connecting to the host yourself with verbose output:
$ ssh -vvv bigserver
This will provide detailed information about the SSH connection process, which can help pinpoint the exact issue with authentication or connectivity.
Tip:
SSH Pipelining¶
By default, Exosphere closes SSH connections to remote hosts after each operation (with some exceptions for batching purposes). This ensures no resources are left open on both the local and remote systems.
Exosphere makes a best-effort attempt to batch queries within an operation to minimize unnecessary connection churn and overhead, but this is scoped to individual operations (e.g., discover, refresh, sync, etc.).
If you have a reasonably sizeable inventory and/or find that the overhead of repeatedly opening and closing SSH connections reduces performance, you can enable SSH Pipelining via the ssh pipelining option <#ssh-pipelining-option>.
When this setting is enabled, Exosphere will not close connections after each operation, but will instead keep them open for reuse.
Connections will be allowed to idle for a configurable amount of time (default is 5 minutes) before being automatically closed in the background.
This can speed up operations significantly if your workflow involves multiple operations in sequence on the same set of hosts, at the cost of leaving connections to remote hosts open for a longer period of time.
- Note
-
Be aware that SSH pipelining is mostly useful if you use exosphere in interactive mode (the REPL) or with the Text User Interface (TUI), as connections are systematically closed on program exit. If you use the CLI for one-off commands, the connections will be closed at the end of the command execution anyway.
With pipelining enabled, you can view and manage the currently open connections via:
exosphere> connections show
as well as:
exosphere> connections close
See the connections command help for more details.
The configurable values for SSH Pipelining include the maximum lifetime of idle connections <#ssh-pipelining-lifetime-option>, as well as the interval at which they are reaped <#ssh-pipelining-reap-interval-option>.
THE CONFIGURATION FILE¶
Exosphere loads all of its settings and inventory from a configuration file. The configuration file can be provided in multiple formats, including yaml <https://yaml.org/>, toml <https://toml.io/en/>, and json <https://www.json.org/>.
Location¶
Where the configuration file lives will depend on your platform. For instance, for a YAML configuration file, the default locations are: Linux, Unix ~/.config/exosphere/config.yaml macOS ~/Library/Application Support/exosphere/config.yaml Windows %LOCALAPPDATA%\exosphere\config.yaml
You can of course substitute the file extension with .toml or .json if you wish to use those formats instead.
You can also ask Exosphere where it expects the configuration file to be on your platform:
exosphere config paths
Additionally, you can specify a custom configuration file location via the EXOSPHERE_CONFIG_FILE environment variable, with the full path to the file as the value.
Structure¶
Below is a full example of a configuration file, in all supported formats. Any option left out will use the default values, which are documented below. YAML
options:
log_level: DEBUG
max_threads: 5 # Limit parallel actions to 5 threads
default_username: alice # Default username across hosts (optional) hosts:
- name: host1
ip: host1.example.com
- name: host2
ip: host2.example.com
port: 2222
description: "Example Host"
- name: host3
ip: host3.example.com
description: "Another Example Host"
username: admin # Override username for this host
sudo_policy: nopasswd
TOML
[options] log_level = "DEBUG" max_threads = 5 # Limit parallel actions to 5 threads default_username = "alice" # Default username across hosts (optional) [[hosts]] name = "host1" ip = "host1.example.com" [[hosts]] name = "host2" ip = "host2.example.com" port = 2222 description = "Example Host" [[hosts]] name = "host3" ip = "host3.example.com" description = "Another Example Host" username = "admin" # Override username for this host sudo_policy = "nopasswd"
JSON
{
"options": {
"log_level": "DEBUG",
"max_threads": 5,
"default_username": "alice"
},
"hosts": [
{
"name": "host1",
"ip": "host1.example.com",
"description": "Example Host"
},
{
"name": "host2",
"ip": "host2.example.com",
"port": 2222,
"description": "Example Host"
},
{
"name": "host3",
"ip": "host3.example.com",
"description": "Another Example Host",
"username": "admin",
"sudo_policy": "nopasswd"
}
]
}
The configuration file is split into two main sections, Options and Hosts. The Options section contains general settings for Exosphere, while the Hosts section contains the Inventory of hosts that Exosphere will connect to.
Environment Variables¶
The location of the configuration file can be overridden by setting the EXOSPHERE_CONFIG_FILE environment variable to the full path of the file you wish to use. Unix/macOS
export EXOSPHERE_CONFIG_FILE="/path/to/my/config.yaml"
Windows/PowerShell
$env:EXOSPHERE_CONFIG_FILE = "c:\path\to\my\config.yaml"
Windows/cmd
set EXOSPHERE_CONFIG_FILE="c:\path\to\my\config.yaml"
Tip:
Exosphere also supports loading configuration options from environment variables. You can use this to override any specific Option from the configuration file. You cannot use environment variables to override the Hosts section.
The environment variable names are prefixed with EXOSPHERE_OPTIONS_ and the option name in uppercase.
For example, to override the log_level option, set the following environment variable: Unix/macOS
export EXOSPHERE_OPTIONS_LOG_LEVEL="DEBUG"
Windows/PowerShell
$env:EXOSPHERE_OPTIONS_LOG_LEVEL = "DEBUG"
Windows/cmd
set EXOSPHERE_OPTIONS_LOG_LEVEL=DEBUG
This pattern applies to all configuration options.
- Note
-
Option types are all strings in this context, but they will be parsed as json <https://www.json.org/> types when loaded. This means "true" and "false" will correctly be interpreted as booleans, and "null" will be interpreted as None. Essentially, you do not need to worry about it as type conversion is properly handled automatically.
Exosphere can display which environment variables are influencing the configuration (if any):
exosphere config source
Options¶
The options section contains general settings for Exosphere. These options are applied globally, and affect how Exosphere behaves at runtime.
- log_level
- default_sudo_policy
- debug
- log_file
- log_max_bytes
- log_backup_count
- history_file
- history_max_entries
- cache_autosave
- cache_autopurge
- cache_file
- stale_threshold
- default_timeout
- default_username
- default_ssh_locale
- max_threads
- ssh_pipelining
- ssh_pipelining_lifetime
- ssh_pipelining_reap_interval
- update_checks
- no_banner
- editor
Below is a detailed list of all available options, their defaults, and examples of how to set them in the configuration file.
- log_level
- The logging level for Exosphere. This can be set to one of the following values, as a string:
- DEBUG
- INFO
- WARNING
- ERROR
This controls the verbosity of the logs generated by Exosphere.
Default: INFO
Example: YAML
options:
log_level: DEBUG
TOML
[options] log_level = "DEBUG"
JSON
{
"options": {
"log_level": "DEBUG"
}
}
- default_sudo_policy
- The global sudo policy to use when running commands on hosts. This can be set to one of the following values:
- skip: Do not run commands that require sudo at all
- nopasswd: Assume sudoers configuration allows running the provider commands without a password
This controls how Exosphere will handle sudo permissions when running commands on hosts. The default is skip, which means Exosphere will not attempt to use sudo at all.
If you want Exosphere to run commands that require elevated privileges at all, you must configure your sudoers file to allow the user Exosphere connects as to run those commands with NOPASSWD: in the sudoers file.
More details on how to configure this can be found in the Sudo Policies and Privileges <> documentation.
- Note
-
Depending on the Providers you use, you may not need to configure this at all! See the Providers <> documentation for more details.
This is the global value that, by default, applies to all hosts. It can be overridden on a per-host basis in the inventory, inside the hosts section, via sudo_policy.
Default: skip
Example: YAML
options:
default_sudo_policy: nopasswd
TOML
[options] default_sudo_policy = "nopasswd"
JSON
{
"options": {
"default_sudo_policy": "nopasswd"
}
}
- debug
- Enable debug mode, which sets the root logger to DEBUG level. This is
useful for development and debugging purposes, if you also want to see
debug logs from libraries and other components.
Normally, there's very little reason to enable this unless you are actively developing Exosphere or troubleshooting a specific issue.
Caution:
You probably want to set log_level to DEBUG instead.
Default: false
Example: YAML
options:
debug: true
TOML
[options] debug = true
JSON
{
"options": {
"debug": true
}
}
- log_file
- A filesystem path to a file where Exosphere will write logs. If not set,
Exosphere will use the platform default location for application logs.
You can set this to any valid path on your filesystem where you have write permissions.
Default: (Platform Default)
Example: YAML
options:
log_file: /home/alice/tmp/exosphere.log
TOML
[options] log_file = "/home/alice/exosphere.log"
JSON
{
"options": {
"log_file": "/home/alice/exosphere.log"
}
}
- log_max_bytes
- The maximum size, in bytes, that the log_file may reach before it
is rotated. When the log file grows past this size, it is rolled over and
a fresh file is started.
This only applies when logging to a file; it has no effect on console logging. Set to 0 to disable rotation entirely and let the log grow without bound.
Default: 5242880 (5 MiB)
Example: YAML
options:
log_max_bytes: 10485760 # 10 MiB
TOML
[options] log_max_bytes = 10485760 # 10 MiB
JSON
{
"options": {
"log_max_bytes": 10485760
}
}
- log_backup_count
- The number of rotated log files to keep. When log_file is rotated,
older files are named with a numeric suffix (e.g. exosphere.log.1),
and any beyond this count are deleted.
With the defaults, the total disk used by logs is therefore essentially log_max_bytes * (log_backup_count + 1).
This must be a positive integer of 1 or more, any lower value is rejected as invalid.
To disable rotation entirely, set log_max_bytes to 0 instead.
Default: 3
Example: YAML
options:
log_backup_count: 5
TOML
[options] log_backup_count = 5
JSON
{
"options": {
"log_backup_count": 5
}
}
- history_file
- A filesystem path to a file where Exosphere will store the REPL history.
If not set, Exosphere will use the platform default and name the file
repl_history.
This file is used to persist the command history across executions of Exosphere, allowing you to navigate through or search for previously executed commands.
Default: (Platform Default)
Example: YAML
options:
history_file: /home/alice/.exosphere_history
TOML
[options] history_file = "/home/alice/.exosphere_history"
JSON
{
"options": {
"history_file": "/home/alice/.exosphere_history"
}
}
- history_max_entries
- The maximum number of entries to retain in the history_file. The
history file is trimmed to the most recent entries when the interactive
REPL starts, so it cannot grow without bound.
Set to 0 to disable trimming and keep unlimited history.
Default: 1000
Example: YAML
options:
history_max_entries: 5000
TOML
[options] history_max_entries = 5000
JSON
{
"options": {
"history_max_entries": 5000
}
}
- cache_autosave
- Automatically save the state to disk when changes are made. This is on by
default, and probably should not be turned off unless you have a very
specific reason to do so.
If this is disabled, you will need to manually save the state with inventory save from the interactive mode for changes to systems state to persist across executions.
See Managing Cache <> for more details on the cache file
Caution:
Default: true
Example: YAML
options:
cache_autosave: false
TOML
[options] cache_autosave = false
JSON
{
"options": {
"cache_autosave": false
}
}
- cache_autopurge
- Whether or not to automatically remove hosts from cache when they are
removed from the configuration file.
If cache_autosave is set to False, this option has no effect.
- Note
-
If all of the hosts are removed from the configuration file, Exosphere will err on the side of caution and leave the cache file alone, regardless of this setting.
This is to prevent accidental cache loss if the wrong configuration is loaded, or if the file is made temporarily inaccessible.
If you really want to remove all the contents of the cache file, use the exosphere inventory clear command.
Default: true
Example: YAML
options:
cache_autopurge: false
TOML
[options] cache_autopurge = false
JSON
{
"options": {
"cache_autopurge": false
}
}
- cache_file
- A filesystem path to a file where Exosphere will store the state of the
inventory. If not set, Exosphere will use the platform default location
for the cache file.
This file is used to persist the state of the inventory across executions, including the results of discovery, host updates, last check times, and more.
The file is lzma compressed to save space, and is not human readable.
It can be cleared with the exosphere inventory clear command, without having to delete the file manually.
See Managing Cache <> for more details on the cache file
Default: (Platform Default)
Example: YAML
options:
cache_file: /home/alice/tmp/exosphere.db
TOML
[options] cache_file = "/home/alice/tmp/exosphere.db"
JSON
{
"options": {
"cache_file": "/home/alice/tmp/exosphere.db"
}
}
- stale_threshold
- The number of seconds after which a host's data is considered stale.
If a host has not been refreshed in this many seconds, an asterisk or similar flag will be shown in the UIs to indicate that the update count may not be accurate, and that the host should be refreshed.
The default is 24 hours, which is reasonable, but you may want a shorter or longer span of time depending on your environment.
Default: 86400 (24 hours)
Example: YAML
options:
stale_threshold: 3600 # 1 hour
TOML
[options] stale_threshold = 3600 # 1 hour
JSON
{
"options": {
"stale_threshold": 3600
}
}
- default_timeout
- The number of seconds to wait for a response from a host over SSH.
This is the maximum time Exosphere will wait for a response from a host before timing out, flagging the host as offline, or raising an error condition.
This is useful for hosts that may be slow to respond, or if you have a large number of hosts and want to avoid long delays on That One Host.
- Note
-
This is the global value that, by default, applies to all hosts. It can be overridden on a per-host basis in the inventory, inside the hosts section, via connect_timeout.
Default: 10 (seconds)
Example: YAML
options:
default_timeout: 60 # 1 minute
TOML
[options] default_timeout = 60 # 1 minute
JSON
{
"options": {
"default_timeout": 60
}
}
- default_username
- The default SSH username to use when connecting to hosts. This is useful
if you have a common username across all hosts, and do not want to specify
it for each host in the inventory.
If not set, Exosphere will try to use the current user's username on the system where Exosphere is running.
- Note
-
This is the global value that, by default, applies to all hosts. It can be overridden on a per-host basis in the inventory, inside the hosts section, via username.
Default: None (Current user's username)
Example: YAML
options:
default_username: alice # Use 'alice' as the default SSH username
TOML
[options] default_username = "alice" # Use 'alice' as the default SSH username
JSON
{
"options": {
"default_username": "alice"
}
}
- default_ssh_locale
- The locale forced on every command Exosphere runs on a remote host.
Some exosphere providers have to rely on parsing the human-readable output of remote commands to determine the state of the host.
Since many of these commands are subject to gettext translation, which changes on the remote host depending on the locale, this can lead to non-deterministic results.
In order to prevent this scenario, Exosphere, by default, forces the locale on the remote host to C (POSIX locale), which is guaranteed to be available and will always produce canonical, untranslated output.
A reasonable alternative, if available, is C.UTF-8.
Attention:
Default: C
Example: YAML
options:
default_ssh_locale: C.UTF-8
TOML
[options] default_ssh_locale = "C.UTF-8"
JSON
{
"options": {
"default_ssh_locale": "C.UTF-8"
}
}
- max_threads
- The maximum number of threads to use for parallel operations.
This is the maximum number of threads Exosphere will use for parallel operations, such as discovery, ping, checking for updates or synchronizing repositories.
This can be useful to limit the number of concurrent operations, especially in environments with many hosts, to avoid overwhelming the network or the computer where you are running Exosphere.
The default is a generous 15 threads, which you may want to lower depending on your context.
Default: 15
Example: YAML
options:
max_threads: 5 # Limit parallel actions to 5 threads
TOML
[options] max_threads = 5 # Limit parallel actions to 5 threads
JSON
{
"options": {
"max_threads": 5
}
}
- ssh_pipelining
- Enable SSH connection pipelining to improve performance when connecting to
multiple hosts.
By default, Exosphere closes connections automatically after each Host operation (sync, discover, refresh, ping etc).
Enabling this option will leave connections open for reuse across multiple operations, significantly improving performance in workflows that involve multiple operations on the same hosts.
Idle connections will be closed automatically after a certain period of time, configurable via ssh_pipelining_lifetime, and reaped periodically via ssh_pipelining_reap_interval.
Default: false
Example: YAML
options:
ssh_pipelining: true
TOML
[options] ssh_pipelining = true
JSON
{
"options": {
"ssh_pipelining": true
}
}
- ssh_pipelining_lifetime
- The number of seconds an idle SSH connection will be kept open when SSH
pipelining is enabled.
This setting only applies if ssh_pipelining is set to true.
When a connection has been idle (unused) for longer than this duration, it will be closed by the connection reaper thread.
Attention:
You will get a warning in the logs to this effect if you configure this value to be less than 60 seconds. Consider setting this to at least the longest time an operation may take on your slowest host, as a baseline.
Otherwise, you can leave this at the default value.
Default: 300 (5 minutes)
Example: YAML
options:
ssh_pipelining_lifetime: 240 # 4 minutes
TOML
[options] ssh_pipelining_lifetime = 240 # 4 minutes
JSON
{
"options": {
"ssh_pipelining_lifetime": 240
}
}
- ssh_pipelining_reap_interval
- The interval (in seconds) at which the reaper thread wakes up to check for
and close idle SSH connections when SSH pipelining is enabled.
This setting only applies if ssh_pipelining is set to true.
Attention:
Conversely, having the reaper thread wake up frequently has negligible overhead since it will only perform work when there are actually idle connections to close.
You should consider that this value effectively adds up to this amount of time to the actual lifetime of idle connections. For example, with a lifetime of 300s and an interval of 30s, connections may remain open for up to 330s.
If in doubt, leave this at the default value.
Default: 30 (30 seconds)
Example: YAML
options:
ssh_pipelining_reap_interval: 60 # 1 minute
TOML
[options] ssh_pipelining_reap_interval = 60 # 1 minute
JSON
{
"options": {
"ssh_pipelining_reap_interval": 60
}
}
- update_checks
- Whether or not Exosphere is allowed to check for updates on PyPI.
Exosphere currently doesn't perform any automatic update checks, only when explicitly asked to via the version check command.
This option allows you to disable that functionality entirely.
This is intended for:
- Environments that have stringent policies about external connectivity
- Environments where Exosphere is installed by other means than PyPI
- Brave souls who would package Exosphere in the context of an OS distribution.
In all of these contexts, the version check command will be disabled and print a clear message instead.
If in doubt, leave this at the default value.
Default: true
Example: YAML
options:
update_checks: false
TOML
[options] update_checks = false
JSON
{
"options": {
"update_checks": false
}
}
- Do not show the ascii banner when starting Exosphere in interactive mode.
Setting this to true will suppress the banner entirely, showing
only the welcome text and the prompt.
Tip:
Default: false
Example: YAML
options:
no_banner: true
TOML
[options] no_banner = true
JSON
{
"options": {
"no_banner": true
}
}
- editor
- The editor command used by the config edit <#config-edit-cmd>
command to open the configuration file.
When unset, Exosphere falls back to the VISUAL environment variable, then EDITOR, and finally a platform default (notepad on Windows, vi everywhere else).
The value is a command that may include arguments.
Attention:
On Windows, a path that contains spaces must be quoted within the value, or it will be ambiguous and fail to resolve. See the examples below for the correct form in each format. A bare command found on PATH (like code --wait) needs no quoting.
Tip:
Default: (Unset) (use VISUAL / EDITOR / platform default)
Example: YAML Command on path
options:
editor: "code --wait"
Windows path with spaces and arguments
options:
editor: '"C:\Program Files\Editor\ed.exe" --wait'
TOML Command on path
[options] editor = "code --wait"
Windows path with spaces and arguments
[options] editor = '"C:\Program Files\Editor\ed.exe" --wait'
JSON Command on path
{
"options": {
"editor": "code --wait"
}
}
Windows path with spaces and arguments
{
"options": {
"editor": "\"C:\\Program Files\\Editor\\ed.exe\" --wait"
}
}
Inventory¶
The second section of the configuration file is the Hosts section, which is referred to throughout the documentation as The Inventory.
The Hosts section contains a list of hosts that Exosphere will connect to, as well as their connection parameters and any specific option for each host.
Host entries are structured as follows. This example describes two hosts, one of which has a custom connection timeout value set, overriding default_timeout. YAML
hosts:
- name: myhost
ip: myhost.example.com
- name: anotherhost
ip: 127.0.1.8
connect_timeout: 30
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com" [[hosts]] name = "anotherhost" ip = "127.0.1.8" connect_timeout = 30
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com"
},
{
"name": "anotherhost",
"ip": "127.0.1.8",
"connect_timeout": 30
}
]
}
Mandatory fields for each host entry are:
- name: The name of the host, which is used to identify it in the UI and logs.
- ip: The address of the host, which can be a hostname or an IP address.
Optional fields for each host entry include:
- port: The SSH port to connect to the host. Defaults to 22.
- username: An optional SSH username to use when connecting to the host
- description: A short string describing the host, to be displayed in UIs
- connect_timeout: The number of seconds to wait for a response from the host over SSH
- sudo_policy: The sudo policy to use when running commands on the host
- ssh_locale: The locale forced on remote commands run against the host
Below is the detailed list of all available host options and their defaults.
- name
- The name of the host, which uniquely identifies the host within the
inventory. It is recommended to keep this to a short string rather than a
fully qualified domain name, although it can be arbitrary.
Attention:
Mandatory: Yes
Example: YAML
hosts:
- name: myhost
TOML
[[hosts]] name = "myhost"
JSON
{
"hosts": [
{
"name": "myhost"
}
]
}
- ip
- The IP address or hostname of the host to connect to over SSH. This can be
a fully qualified domain name, an IP address, or a short hostname, so long
as it resolves. It is recommended to use a fully qualified domain name or
an IP address to avoid issues with DNS resolution.
Attention:
Mandatory: Yes
Example: YAML
hosts:
- name: myhost
ip: myhost.example.com
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com"
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com"
}
]
}
- port
- The SSH port to connect to the host. This is optional, and defaults to 22.
If your host uses a different port for SSH, you can specify it here.
Default: 22
Example: YAML
hosts:
- name: myhost
ip: myhost.example.com
port: 2222
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com" port = 2222
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com",
"port": 2222
}
]
}
- username
- An optional SSH username to use when connecting to the host.
- Note
-
This option has precedence over default_username
This is useful if you need to connect to a particular host with a different user than the one you are running Exosphere as, or the one configured globally in default_username.
Default: Current user's username
Example: YAML
hosts:
- name: myhost
ip: myhost.example.com
username: alice
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com" username = "alice"
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com",
"username": "alice"
}
]
}
- description
- A short string describing the host, to be displayed in UIs. This is
optional, but can be useful to provide additional context about the host,
such as its role or purpose.
Default: None
Example: YAML
hosts:
- name: myhost
ip: myhost.example.com
description: "Web Server"
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com" description = "Web Server"
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com",
"description": "Web Server"
}
]
}
- connect_timeout
- The number of seconds to wait for a response from the host over SSH. This
is optional, and defaults to the value set in default_timeout.
If you have hosts that are particularly slow to respond, you can increase this value on a per-host basis.
Default: Value of default_timeout
Example: YAML
hosts:
- name: myhost
ip: myhost.example.com
connect_timeout: 30 # 30 seconds
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com" connect_timeout = 30 # 30 seconds
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com",
"connect_timeout": 30
}
]
}
- sudo_policy
- The sudo policy to use when running commands on the host.
- Note
-
This option has precedence over the global option, see default_sudo_policy for documentation and usage details.
Default: Value of default_sudo_policy
Example: YAML
hosts:
- name: myhost
ip: myhost.example.com
sudo_policy: nopasswd
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com" sudo_policy = "nopasswd"
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com",
"sudo_policy": "nopasswd"
}
]
}
- ssh_locale
- The locale forced on remote commands run against this host.
- Note
-
This option has precedence over the global option, see default_ssh_locale for documentation and usage detail.
Attention:
Default: Value of default_ssh_locale
Example: YAML
hosts:
- name: myhost
ip: myhost.example.com
ssh_locale: C.UTF-8
TOML
[[hosts]] name = "myhost" ip = "myhost.example.com" ssh_locale = "C.UTF-8"
JSON
{
"hosts": [
{
"name": "myhost",
"ip": "myhost.example.com",
"ssh_locale": "C.UTF-8"
}
]
}
SUDO POLICIES AND PRIVILEGES¶
Exosphere and its provider modules try, as much as possible, to avoid requiring elevated privileges at all. Unfortunately, on some platforms, some operations that we rely on do require them.
This section describes how to configure the Sudo Policy for Exosphere as well as optionally grant the required privileges on the remote hosts.
- Note
-
These instructions below are entirely optional, and you can absolutely use Exosphere without ever setting up sudoers configuration or privileges. You will just be limited to the operations that do not require elevated privileges, which is the majority of them.
Enumerating Providers and their Privileges¶
The documentation for Providers <> includes details, but you can query this via the exosphere CLI and its sudo command. Here is an example below:
$ exosphere sudo providers
Providers Requirements ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ ┃ Provider ┃ Platform ┃ Sync Repositories ┃ Refresh Updates ┃ ┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ │ Apt │ Debian/Ubuntu Derivatives │ Requires Sudo │ No Privileges │ │ Pkg │ FreeBSD │ Requires Sudo │ No Privileges │ │ PkgAdd │ OpenBSD │ No Privileges │ No Privileges │ │ Dnf │ Fedora/RHEL/CentOS Derivatives │ No Privileges │ No Privileges │ │ Yum │ RHEL/CentOS 7 and earlier │ No Privileges │ No Privileges │ └──────────┴────────────────────────────────┴───────────────────┴─────────────────┘
For instance, we can see here that the Apt and Pkg providers require sudo privileges to sync repositories, but do not require any privileges to refresh updates.
Note:
- Sync Repositories: Updating package repository metadata (e.g., apt-get update)
- Refresh Updates: Checking for available package updates
Configuring Sudo Policies¶
There are currently two valid settings for the Sudo Policy options:
- skip: Do not use sudo at all, skip operations that require it and emit a warning in logs
- nopasswd: Assume sudoers configuration allows running the provider commands without a password
The default Sudo Policy for exosphere is skip, configured globally <#default-sudo-policy-option>. This means that Exosphere will not attempt to use sudo at all when running provider commands.
This can also be configured per system, by setting the sudo policy option <#hosts-sudo-policy-option> at the host level.
If you want to be able to use Exosphere to run operations that require sudo privileges, you will need to configure sudoers on the remote host(s) where this applies to allow them to be run without a password.
Attention:
Generating a Sudoers configuration¶
You can manually configure sudoers with NOPASSWD: as you wish, so long as it allows the commands specified in the Providers <> documentation to run.
However, since this can be a combination of tedious, risky and error-prone, Exosphere provides a helper command that will generate a sudoers snippet for you, for any host, or specific provider, while also allowing you to specify a username.
To generate a sudoers configuration snippet for the Apt provider, for instance, with the username bigadmin, you can run the following command:
$ exosphere sudo generate --provider apt --user bigadmin # Generated for Debian/Ubuntu Derivatives Cmnd_Alias EXOSPHERE_CMDS = /usr/bin/apt-get update bigadmin ALL=(root) NOPASSWD: EXOSPHERE_CMDS
You can then take this output and drop it in a file on the remote host, such as /etc/sudoers.d/zz-exosphere (or, if on a FreeBSD System, /usr/local/etc/sudoers.d/zz-exosphere) and then switch the Sudo Policy to nopasswd for that host.
- On usernames
-
The username parameter is optional. If you do not specify it, the command will try to use, in this order:
- 1.
- The username configured for the host, if any (when using --host)
- 2.
- The username configured in the global configuration, if any
- 3.
- The current local username running the exosphere command
You can also use the --host option to automatically detect the provider for a host and generate the appropriate sudoers snippet for it.
For more details, see exosphere sudo generate --help.
Security Considerations¶
The generated sudoers configuration is designed to be as secure as possible:
- Specific commands only: Only the exact commands needed by the provider are allowed
- Absolute paths: Commands use full absolute paths (e.g., /usr/bin/apt-get)
- Root user only: Commands are restricted to run as root (not ALL)
- No password required: Uses NOPASSWD: to avoid credential storage/prompting
- Command aliases: Uses Cmnd_Alias for better maintainability
This approach is significantly more secure than granting broad sudo access, as it:
- Limits the attack surface to specific commands that are known in advance
- Prevents privilege escalation beyond the intended operations
- Avoids the security risks of password-based authentication
Alternatives¶
If your relevant providers only require sudo privileges for repository synchronization, and you prefer not to use the sudoers configuration, you can still configure your remote systems to sync those repositories on a schedule. You will just not be able to use Exosphere to do it on-demand, but the repository contents should always be reasonably up to date.
On Debian/Ubuntu systems, consider these options:
- The unattended-upgrades <https://wiki.debian.org/UnattendedUpgrades> package, which can be configured to automatically run apt-get update and optionally apt-get upgrade on a schedule
- The apt-config-auto-update package for simpler automatic update configuration
- Custom cron jobs with apt-get update if you prefer manual control
On FreeBSD, you can set up a cron job or periodic task to run /usr/sbin/pkg update regularly.
For other distributions, similar automated package management tools are available.
How can I check what the effective Sudo Policy is for a given host?¶
You can use the sudo check helper command.
As an example, to check the effective Sudo Policy for a host named bigserver:
$ exosphere sudo check bigserver Sudo Policy for bigserver
Global Policy: skip
Host Policy: nopasswd (local)
Package Manager: apt
Can Sync Repositories: Yes
Can Refresh Updates: Yes
This will tell you what the effective Sudo Policy is for that host, as well as where that is configured. For instance, in the example above, you can see the global policy is skip, but the host policy has been set to nopasswd locally, in the inventory host options.
The global Sudo Policy can also be displayed via:
$ exosphere sudo policy Global SudoPolicy: skip
MANAGING CACHE¶
Exosphere saves the state of all hosts in a cache file, stored on disk. This allows the software to remember the state of hosts and updates between runs. It is lzma <https://docs.python.org/3/library/lzma.html> compressed and stored in a binary, pickle <https://docs.python.org/3/library/pickle.html> format.
The cache file location can be configured with the relevant option in the configuration <#cache-file-option>.
The default path for the cache file varies by platform and configuration, but can be displayed with the command:
exosphere> config paths
Changing options, either globally or per host in the configuration should not be negatively affected by the cache file, which will update itself accordingly. If it does not, this is a bug and should be reported.
Tip:
Clearing the Cache¶
If you encounter issues or inconsistencies with the cache, you can clear it. It can generally safely just be deleted on disk, and will be recreated on next run.
The cache file can also be manually cleared within Exosphere in the Command Line Interface (CLI) <>:
$ exosphere inventory clear
The confirmation prompt can be bypassed with the -f flag.
Upon clearing the cache, you will have to perform a full Discovery and subsequent Refresh of the entire inventory to repopulate it.
TROUBLESHOOTING GUIDE¶
When something is not working as expected, this guide walks through how to diagnose the problem, starting from the tools Exosphere gives you and working toward the most common causes.
For specific symptoms and their fixes, see the FAQ <#faq-troubleshooting>. If you work through both and are still stuck, Getting Help <> points you at the right place to ask, or submit a bug report.
Check the logs¶
Exosphere always writes a log file, regardless of how you run it, and it is the first place to look. To find it, run:
$ exosphere config paths
and look under the Log: entry for the path on your platform.
If you are in the TUI <>, you can also press l to open the Logs screen and watch events as they happen.
Turn up the verbosity¶
By default, Exosphere logs at INFO level. If the logs do not explain the problem, raise it to DEBUG via the log_level <#log-level-option> option: YAML
options:
log_level: DEBUG
TOML
[options] log_level = "DEBUG"
JSON
{
"options": {
"log_level": "DEBUG"
}
}
You can also raise it for a single run, without editing your config, via the EXOSPHERE_OPTIONS_LOG_LEVEL environment variable <#config-env-vars>. Unix/macOS
$ EXOSPHERE_OPTIONS_LOG_LEVEL=DEBUG exosphere
Windows/PowerShell
$env:EXOSPHERE_OPTIONS_LOG_LEVEL = "DEBUG" exosphere
Windows/cmd
set EXOSPHERE_OPTIONS_LOG_LEVEL=DEBUG exosphere
You can confirm this worked by checking the output of exosphere config source and exosphere config diff.
For library-level detail (the SSH internals from Fabric and paramiko, for instance), there is the debug <#debug-option> option, but be warned that it is extremely noisy and is rarely needed outside of development. We suggest not using this unless asked in a bug report.
Check the configuration Exosphere actually loaded¶
A surprising number of "it is not doing what I told it to" problems come down to Exosphere loading a different configuration file than you expect, or an environment variable quietly overriding a value.
Confirm what was loaded, and from where:
$ exosphere config source
This shows the active configuration file path and any environment variables influencing the configuration. To inspect the effective values, use config show, or config diff to see only what differs from the defaults.
Test connectivity¶
Most failures are connectivity or authentication problems. The quickest test is a discovery, which prints a clear table of any errors:
exosphere> inventory discover
or, for a single host:
exosphere> host discover bigserver
If a host fails, work through the checklist:
- Your SSH agent is running and has the right key loaded
- The username and port are correct (see The Configuration File <>)
- The host is reachable and its SSH service is running
- The host allows public key authentication
To reproduce the connection outside of Exosphere, with full detail:
$ ssh -vvv bigserver
Remember that Exosphere honors ~/.ssh/config and /etc/ssh/ssh_config, so double-check any host aliases or per-host settings there. The Connections and Authentication <> page covers all of this in depth.
Tip:
Common situations¶
A few recurring issues, with where to look:
- A host is flagged Offline but you can reach it --- usually slow DNS on the remote sshd; the FAQ <#faq-troubleshooting> covers the UseDNS no fix and the per-host connect_timeout <#connect-timeout-host-option> option.
- "Private key file is encrypted" --- an authentication failure in disguise; the FAQ <#faq-troubleshooting> explains the underlying cause.
- A dnf or yum host hangs or errors on refresh --- the FAQ <#faq-troubleshooting> has the manual makecache workaround and the read-only database fix.
- Frequent connections upset your SSH server --- enable SSH pipelining <#ssh-pipelining-docs> to cut down on connection churn.
- A generated sudoers snippet does not work --- the FAQ <#faq-troubleshooting> has the ownership, permissions, and rule-ordering checklist.
When to look at the providers¶
If a host connects fine but updates or repository sync misbehave, the cause is often specific to the package manager. The Providers <> page documents the exact commands each provider runs, along with platform quirks --- running the failing command by hand on the remote host is often the fastest way to see what is really going wrong.
Still stuck?¶
If you have worked through this guide and the FAQ <#faq-troubleshooting> without luck, head to Getting Help <> for where to ask and how to file a useful bug report.
FREQUENTLY ASKED QUESTIONS¶
And also troubleshooting tips, in general.
General Questions¶
Can Exosphere help me apply the updates and patches?¶
Unfortunately, no. Exosphere is not a configuration management or automation tool, simply a reporting and aggregation tool.
The gap it exists to fill is providing you with a unified, centralized view of the state of updates and patches across your systems, so you can make informed decisions about what needs patching, and when.
This functionality is not planned, and left to frankly better tooling that already exists, such as UnattendedUpgrades <https://wiki.debian.org/UnattendedUpgrades>, Ansible <https://www.ansible.com/>, RunDeck <https://www.rundeck.com/>, etc.
Didn't Exosphere used to have a Web UI? What happened to it?¶
It was removed in version 3.0. The Web UI started as a neat curiosity more than a feature, but never left the experimental stage.
It was always provided as a separate, opt-in, extra for the python packages, and installed and used by few, least of all the author.
As the project matured, and new features started clashing with the way it was implemented, it became clear it should be removed instead of being left to rot in its current, janky, underdeveloped state.
Why all the different config file formats?¶
The author is fond of yaml, but recognizes toml is gaining traction in the Python community. At this point also supporting json was so low effort that it was added in.
The overhead of supporting this is so negligible that we'd prefer to make everyone happy, if at all possible.
They all de-serialize to exactly the same data structure (and this is validated with unit tests), so you can use whichever of the formats you feel strongest about, or hate the least.
Why Python 3.13?¶
For completely selfish reasons such as:
- Wanting to use the latest and greatest Python features
- Not wanting to bother with multi version support
Exosphere was written mostly to scratch the author's own itch. While it is made public in the hopes that it will be useful to others, and great care and effort has been spent on documentation and ease of use, the focus at this time remains to keep the author happy.
Compatibility test matrices are unfortunately not a source of happiness.
Platform Support¶
I really like the dashboard. Can I still use it if my systems are unsupported?¶
Yes, as long as the remote system is a Unix-like operating system.
In this case, if your remote operating system is not supported, Exosphere will allow you to use the dashboard and online checks (ping command, etc) just fine.
You won't be able to perform refresh or sync operations on them, and the update counts will be disabled, but this part will remain functional.
If the system in question is not a Unix-like operating system, it will not be discoverable at all, and should not be added to the inventory.
When managing Ubuntu systems, will this handle snaps?¶
Exosphere does not currently support snaps or flatpaks. There are no immediate plans to add support for these, but it is certainly possible in the future, if this becomes a common facet of server management.
On BSD systems, will this handle system updates and source ports?¶
Exosphere does not currently support system updates or source ports. It only supports Binary Packages, for both FreeBSD and OpenBSD.
There are plans to add support for system updates in the future, presenting them as a synthetic package in the updates view, but this needs more work.
For the time being, cron reports and mailing lists for syspatch and freebsd-update are recommended to keep tabs on these.
Does FreeBSD support extend to things like OPNSense?¶
Since 1.3.4, the pkg provider performs repository synchronization in a manner that is compatible with OPNSense, and the platform is supported as FreeBSD.
As long as you configure sudo and sudoers correctly, and that the system uses pkg underneath, it should work just fine.
Is Windows support planned or even possible?¶
The application runs fine on Windows, and while managing Windows is something we would love to implement, the connection methods are not incredibly straightforward, and the APIs and interfaces for update and patch management are not great. Microsoft continues to hope you will buy into their management tools, so the core APIs are not very accessible as a result.
Windows support remains an eventual goal, but it is not currently planned.
Configuration and Customization¶
Can I specify a custom path for the configuration file?¶
Yes! You can specify a custom path for the configuration file by setting the EXOSPHERE_CONFIG_FILE environment variable to the full path of the file you wish to use.
See The Configuration File <> for more details on other environment variables you can define to influence or override the configuration.
I don't like the ascii art banner in interactive mode¶
You can disable it entirely with the no_banner config option <#no-banner-option>.
Is there any way to disable the update check?¶
Yes, you can disable the update check by setting the update_checks config option <#update-checks-option> to false in the configuration file.
This should be helpful in environments where you do not want to talk to PyPI at all.
If you are a prospective package maintainer wishing to package Exosphere for your favorite platform's repositories, it is recommended that you patch out the default value of this option to False in exosphere/config.py, or override via environment variables <#config-env-vars>, if feasible.
Troubleshooting¶
Why does ping report Offline when the system is reachable?¶
The ping checks in exosphere aren't ICMP ping, but SSH pings. They will only return an Online status if the remote system can be connected to successfully, over SSH, and a simple POSIX test command can be executed. (/bin/true or shell built-in equivalent)
As such, scenarios that can cause an Offline status include:
- SSH Authentication Failure (bad username, invalid credentials)
- Timeouts and Connectivity Errors
- Failure to execute the supremely basic test command
We consider "Online" to mean "the system is up and ready to process further queries", instead of just "the system is reachable over the network".
This is by design, and aims to avoid scenarios where the system is reachable, but is currently shutting down, or has not finished booting.
Generally, if the host shows up as Offline, you would not be able to perform any of the other operations on it anyways.
You can re-run the discovery command to find out what the issue is and correct it, if you are getting this during initial setup.
I get an error with "Private key file is encrypted", what does it mean?¶
The presence of this error in logs means that authentication failed in some way.
Verify that:
- The server has Public Key Authentication enabled
- Your SSH agent is running and has the correct key loaded
- The right user name is being used to connect
The unhelpful error message is unfortunately a Known Issue <https://github.com/paramiko/paramiko/issues/387> in the paramiko library, which is used internally to handle SSH connections. Whenever authentication fails when an SSH agent is used, this is the exception that will be raised, regardless of the actual issue.
Exosphere will generally catch this specific error and rewrite the error message to be more helpful, but there are a few edge cases where it may be displayed as-is.
My system using dnf or yum hangs when refreshing¶
The dnf and yum providers do a best effort to prevent interactive prompts when running the commands they need to synchronize repositories and cache, but sometimes, they will still prompt for user input, which Exosphere cannot handle.
To resolve this, you can simply connect to the remote system as the same user you use within Exosphere, and manually run the following commands: dnf
dnf makecache --refresh dnf check-update
yum
yum makecache --refresh yum check-update
And answer all the prompts that may appear. The provider should no longer hang past this point.
After an update, my system using dnf fails to refresh!¶
After certain types of updates, you may get the following error message when trying to refresh a dnf based system:
Failed to get current versions: Error: SQLite error on "/var/lib/dnf/history.sqlite": Executing an SQL statement failed: attempt to write a readonly database
This is a known issue where dnf apparently needs to perform some database updates before it can perform its queries. This requires root privileges, which Exosphere does not have access to during normal operations.
To resolve this, you can connect to the remote system and run a simple query with root privileges to fix the database:
$ sudo dnf --quiet -y list installed kernel.x86_64
This should resolve the issue, and you should be able to refresh the system without write access errors afterwards.
I've tuned the timeout but this one host keeps getting flagged offline¶
Exosphere does use a fairly aggressive timeout value for its SSH connections, but if you have a host that is consistently supremely slow to respond, yet you can connect to it reliably, it is likely you have DNS issues on that server.
Check your resolvers and/or add UseDNS no to your sshd configuration. FreeBSD notoriously ships with the option enabled by default, for instance.
If you can't or this has no effect, you can increase the timeout value for that host specifically by setting the connect_timeout host option <#connect-timeout-host-option> to a higher value, without having to change the global option.
The frequent SSH connections are causing issues on my SSH server¶
If you have systems that have connection rate limiting, or take a while to authenticate, you can enable SSH connection pipelining to reduce the amount of connection churn.
See the documentation on SSH Pipelining <#ssh-pipelining-docs> as well as the ssh_pipelining configuration option <#ssh-pipelining-option>.
Updates refresh fails on my OpenBSD system with an exotic architecture!¶
Exosphere relies on the availability of the syspatch command to determine if the system is tracking a stable release or -current.
If you're running a more exotic, non-x86 architecture, Exosphere may not be able to handle the failure mode gracefully, and we'd deeply appreciate it if you could file a bug report <https://github.com/mrdaemon/exosphere/issues> with the output of syspatch -l so we can improve this situation.
Help, the sudoers snippet I generated does not work!¶
The usual checklist for files in sudoers.d applies here:
- The file must be owned by root
- Must have permissions of 0440
- Must not contain syntax errors (check with visudo -c -f /etc/sudoers.d/yourfile)
If you are still having issues, a common problem is another rule matching last. Sudo reads rules in lexicographic order (i.e., not strictly alphabetical), but does not merge them, and the last matching rule wins.
You can verify ordering with visudo -c and find out which rule is matching last with:
sudo -l -U youruser /the/sudo/command --and --args
and compare with the output of sudo -ll to see which rule matched vs which was expected.
You can find which exact command exosphere is trying to run in the Providers <> documentation.
A quick workaround for ordering issues is to just name the generated snippet with a prefix that ensures it is loaded and matched last, for instance:
/etc/sudoers.d/zz-exosphere
After upgrading to 3.0, my old shell completion misbehaves¶
Exosphere can install tab-completion for zsh, bash and fish with:
exosphere --install-completion
Versions prior to 3.0 generated completion differently (via Typer) and wrote the scripts to different locations. Re-running --install-completion installs the new script alongside the old one rather than replacing it, so the stale files from the previous version are left behind.
For all cases except PowerShell, the new completion takes precedence and the leftovers are harmless, but it is cleanest to remove them. If a stale script ever did take precedence, it would try to run exosphere at completion time and drop into the interactive REPL, appearing to hang your shell.
To clean up the previous version's files:
- bash: delete ~/.bash_completions/exosphere.sh and remove its source line from ~/.bashrc.
- zsh: delete ~/.zfunc/_exosphere (the new script is installed under ~/.zsh/completions, or your oh-my-zsh completions directory).
- fish: nothing to do --- the new script overwrites the old one at the same path.
Attention:
Typer appended its completion directly into your PowerShell profile (rather than a separate file). To remove it, open the profile:
notepad $PROFILE
and delete the Exosphere completion block, which looks roughly like:
Import-Module PSReadLine
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
$scriptblock = {
param($wordToComplete, $commandAst, $cursorPosition)
$Env:_EXOSPHERE_COMPLETE = "complete_powershell"
# ... several lines referencing exosphere ...
}
Register-ArgumentCompleter -Native -CommandName exosphere -ScriptBlock $scriptblock
Remove the $scriptblock assignment and the matching Register-ArgumentCompleter ... -CommandName exosphere line. You can leave the generic Import-Module PSReadLine / Set-PSReadLineKeyHandler lines if other tools rely on them. Restart PowerShell afterwards.
GETTING HELP¶
While exosphere is provided as-is, with no expectation of warranty or support, there are a few resources available for help if you run into issues or have questions.
Before reaching out¶
Common issues are already covered in the following places:
- The Troubleshooting Guide <> walks through diagnosing the common failures.
- The FAQ <#faq-troubleshooting> collects specific symptoms and their fixes.
It is worth a quick pass through both --- the answer is often there, and if it is not, the steps you already tried are exactly what helps someone help you.
Asking a question¶
For usage questions, "how do I...", ideas, or just to share what you have built, use GitHub Discussions <https://github.com/mrdaemon/exosphere/discussions>. This is the best place for anything that is not clearly a bug.
Reporting a bug¶
If you have found a bug, please open an issue using the bug report form <https://github.com/mrdaemon/exosphere/issues/new/choose>.
To make it actionable, include as much of the following as you can:
- •
- The Exosphere version you are running:
$ exosphere version check
- Your platform: the operating system you run Exosphere on, and the remote platform(s) involved.
- Relevant log output: Reproduce the problem with log_level <#log-level-option> set to DEBUG, then attach the relevant portion of the log file (find it via exosphere config paths).
- A sanitized configuration snippet, or the output of exosphere config diff, so the relevant options are visible. Remove anything sensitive first.
- Steps to reproduce, along with what you expected versus what actually happened.
For problems with updates or repository sync on a specific platform, the Providers <> page lists the exact commands Exosphere runs --- running the failing one by hand on the remote host and including its output is incredibly helpful.
Feature requests and ideas¶
Suggestions are welcome. Open a discussion on GitHub Discussions <https://github.com/mrdaemon/exosphere/discussions>, or an issue via the bug report form <https://github.com/mrdaemon/exosphere/issues/new/choose> --- whichever feels more appropriate. If you have built something neat on top of Exosphere's Reporting and JSON Export <> (a dashboard, a bot, a coffee-brewing cron job), we would love to hear about it.
PROVIDERS¶
Exosphere implements platform support for Patch and Update management through an extensible Providers API <> that allows for new providers to be more or less transparently implemented.
Current implementation details and notes for the built-in providers are provided below.
Debian/Ubuntu (Apt)¶
The Debian/Ubuntu provider is implemented in the exosphere.providers.debian module.
Repo sync requires sudo privileges, as it needs to run apt-get update to update the package cache from repository.
By default, given the stock Sudo Policy <#default-sudo-policy-option>, in Exosphere, Repo sync will not run for Debian-like hosts, and you will need to configure sudoers appropriately before changing the Sudo Policy.
Updates retrieval is done using apt-get dist-upgrade in simulation mode, and does not require elevated privileges.
Pending reboot detection checks for the presence of /var/run/reboot-required, which the system creates after applying updates that need a reboot to take effect (such as kernel or libc upgrades). This does not require elevated privileges.
- Note
-
If you want repo sync without sudo privileges, you can also just install the apt-config-auto-update package, or configure Unattended Upgrades <https://wiki.debian.org/UnattendedUpgrades> to achieve this on a schedule.
Exact Commands run on remote hosts¶
- /usr/bin/apt-get update (requires sudo)
- apt-get dist-upgrade -s | grep -e '^Inst'
- test -f /var/run/reboot-required
Command dependencies¶
- apt-get
- grep
RedHat-Likes (Yum/DNF)¶
The RedHat provider is implemented in the exosphere.providers.redhat module.
It implements the functionality identically between Yum and DNF, as they share an interface for the relevant commands. The only distinction is the command name.
Internally, using Yum as a provider wraps Dnf, but with a different command name.
Repo sync does not require sudo privileges, as it runs yum/dnf makecache as the connection user to retrieve the information.
Updates retrieval is done using yum/dnf check-update, and does not require elevated privileges.
Pending reboot detection uses needs-restarting -r, which reports whether a reboot is recommended following kernel or core library updates, and does not require elevated privileges. The exact invocation depends on the backend:
- On dnf, the dnf needs-restarting subcommand is used. It is built in to dnf5 and provided by the python3-dnf-plugins-core plugin on dnf4 (installed by default on RHEL 8/9).
- On yum, the standalone needs-restarting command is used, shipped with the yum-utils package.
If the command or plugin is unavailable, the reboot status is reported as unknown rather than failing the refresh, making this feature entirely optional.
Exact Commands run on remote systems¶
Note:
- dnf --quiet -y makecache --refresh
- dnf --quiet -y check-update
- dnf --quiet -y check-update --security
- dnf --quiet -y list installed <package_name> [<package_name> ...]
- dnf needs-restarting -r or needs-restarting -r (dnf vs yum)
Command dependencies¶
- yum or dnf
- For updates (optional):
- python3-dnf-plugins-core on dnf4 (installed by default on RHEL 8/9)
- yum-utils on yum
Usage Notes and Issues¶
Some minor limitations:
- Current version detection is done on a best effort basis, installonly packages are clobbered down to the last installed version. This is generally accurate enough, but it is difficult to provide guarantees given the dnf/yum interfaces available.
- Some Vendor configurations may cause the provider to fail to detect kernel updates. This is generally a misconfiguration, and you should seek vendor support to resolve this. Google Compute Platform (GCP) is known to exhibit this issue with some legacy vendor kernels.
In some scenarios, the yum or dnf commands may hang when running due to unexpectedly prompting for user input interactively, which Exosphere cannot handle.
The provider is written to avoid this, but if you do encounter this, simply run dnf makecache --refresh or yum makecache --refresh manually on the remote system and answer any prompts that may appear.
Once that is done, you should be able to run Exosphere commands without issues.
Note that we consider having to do this a bug, and would appreciate if you could file a bug report <https://github.com/mrdaemon/exosphere/issues>.
FreeBSD (Pkg)¶
The FreeBSD provider is implemented in the exosphere.providers.freebsd module. It uses the pkg command to manage packages and updates.
Repo sync requires sudo privileges, as it needs to run /usr/sbin/pkg update to update the package cache from repository, as well as refresh vuln.xml for use by pkg audit.
This also means you will need to have the sudo package installed on the remote system if you want to use this functionality. Unfortunately, doas is not supported at this time.
By default, given the stock Sudo Policy <#default-sudo-policy-option>, in Exosphere, Repo sync will not run for FreeBSD hosts, and you will need to configure sudoers appropriately before changing the Sudo Policy.
Alternatively, you can run /usr/sbin/pkg update via a cronjob or similar mechanism to keep the repository information up to date without having to configure sudo privileges for Exosphere.
Updates retrieval is done using pkg upgrade in simulation mode, and does not require elevated privileges.
Pending reboot detection compares the installed kernel version (freebsd-version -k) with the running kernel (freebsd-version -r). A mismatch indicates a kernel update that has been installed but not yet booted. This is intentionally kernel-only, and does not require elevated privileges.
Exact Commands run on remote systems¶
- /usr/sbin/pkg update -q (requires sudo)
- /usr/sbin/pkg audit -qF (requires sudo)
- /usr/sbin/pkg audit -q for security updates
- /usr/sbin/pkg upgrade -qn | grep -e '^\\s'
- freebsd-version -k
- freebsd-version -r
Command dependencies¶
- pkg
- grep
- freebsd-version
OpenBSD (pkg_add)¶
The OpenBSD provider is implemented in the exosphere.providers.openbsd module. It uses the pkg_add command to manage packages and updates.
Repo sync is essentially a no-op, as OpenBSD does not have a command to synchronize package repositories. The command being run will directly query package mirrors on demand, and maintains no cache.
Updates retrieval is done using pkg_add -un, and does not require elevated privileges.
Branch detection is done using syspatch -l, which is in turn used to determine whether updates should be considered security updates or not. This does not require elevated privileges either.
Pending reboot detection is not implemented for OpenBSD, as it does not really provide any useful tooling around this.
Additionally, as the provider only handles binary packages and not syspatch or system updates, reboot status is always reported as unknown.
Limitations¶
- On stable/release, all package updates are assumed to be security updates, since OpenBSD only ever updates packages for security issues.
- If the system is tracking -current or -beta, security status will default to False, as there is no way to tell given the rolling release nature of these branches.
- On more exotic architectures, syspatch may not be available and the failure modes are untested. If you have such a system, and this breaks for you, please file a bug report <https://github.com/mrdaemon/exosphere/issues> and include the output of syspatch -l.
- Only handles binary packages, does not support ports or syspatch/system updates.
- Handles transitive dependencies without marking them as such, and may, in some edge cases, list more packages than strictly necessary for an update.
- Reboot status is always reported as unknown
Exact Commands run on remote systems¶
- /usr/sbin/syspatch -l
- /usr/sbin/pkg_add -u -v -x -n | grep -e '^Update candidate'
Command dependencies¶
- pkg_add
- grep
- syspatch
CLI COMMAND REFERENCE¶
Below is a complete reference of all the commands and subcommands available through the Exosphere CLI. This information is available at runtime via the --help option, but is also provided here for reference.
Each command includes detailed descriptions of its purpose, available options, and usage examples. Commands are organized by functional groups to help you find what you need quickly.
Tip:
inventory¶
Inventory and Bulk Operations Commands
Commands to bulk query, discover and refresh hosts in the inventory. Most commands accept an optional list of host names to operate on.
status is the primary command to display the current state of hosts in the inventory.
discover¶
Detect and gather platform information for hosts
inventory discover [ARGS...]
On a fresh inventory start, this needs to be done at least once before operations can be performed on the hosts. It can also be used to refresh this information if it has changed, or if a new provider has been added to Exosphere.
The discover operation will connect to the specified host(s) and gather their current state, including Operating System, flavor, version and pick a Package Manager implementation for further operations.
Arguments:
- NAMES
- Host(s) to discover, all if not specified
refresh¶
Refresh the state and update data for hosts
inventory refresh [OPTIONS] [ARGS...]
Connects to hosts in the inventory and retrieves pending package updates.
If --discover is specified, the platform information (Operating System flavor, version, package manager) will also be refreshed. Also refreshes the online status in the process.
If --sync is specified, the package repositories will also be synchronized remotely.
Synchronizing the package repositories involves invoking whatever mechanism the package manager uses to achieve this, and can be a very expensive operation, which may take a long time, especially on large inventories with a handful of slow hosts.
By default, only the progress bar is shown during the operation. If --verbose is specified, the name and completion status of each host will be shown in real time.
Arguments:
- NAMES
- Host(s) to refresh, all if not specified
Parameters:
- --discover, -d
- Also refresh platform information [Default: False]
- --sync, -s
- Sync the package repositories as well as updates [Default: False]
- --verbose, -v
- Show verbose output during operations [Default: False]
ping¶
Check connectivity and online status of hosts
inventory ping [ARGS...]
Attempts to connect to all hosts in the inventory. On failure, the affected host will be marked as offline.
You can use this command to quickly check whether or not hosts are reachable and online.
You can also invoke this command to explicitly refresh the Online status of hosts in the inventory.
The connectivity check is based on SSH reachability, and the criteria for a host being considered online is "ready to execute commands via SSH".
Arguments:
- NAMES
- Host(s) to ping, all if not specified
status¶
Show inventory hosts and their status
inventory status [OPTIONS] [ARGS...]
Display a nice table with the current state of all the hosts in the inventory, including their package update counts, their online status and whether or not the data is stale.
Output can be filtered to show only hosts with pending updates (--updates-only) or only those with pending security updates (--security-only). These two filters are mutually exclusive.
Output can also be sorted by any column with --sort, optionally reversed with --reverse. Sorting by 'version' groups hosts by flavor first, since versions are not comparable across flavors.
When sorting by any column other than name, hosts with unknown or unsupported values for that column will be grouped together at the end.
Use --full to include extra columns, such as the host description.
No matches when filtering will exit with code 3.
Arguments:
- NAMES
- Host(s) to show status for, all if not specified
Parameters:
- --full, -f
- Show additional columns, including host descriptions [Default: False]
Filtering Options:
- --updates-only, -u
- Show only hosts with pending updates [Default: False]
- --security-only, -s
- Show only hosts with pending security updates [Default: False]
Sorting Options:
- --sort, -o
- Sort the table by the given column [Choices: host, os, flavor, version, updates, security, status]
- --reverse, -r
- Reverse the sort order (requires --sort) [Default: False]
save¶
Save the current inventory state to disk
inventory save
Manually save the current state of the inventory to disk using the configured cache file.
The data is compressed using LZMA.
If options.cache_autosave is enabled, this will be automatically invoked after every discovery or refresh operation.
Since this is enabled by default, you will rarely need to invoke this manually.
This command is only available in interactive mode, as the inventory state is not persisted between separate CLI invocations when autosave is disabled.
clear¶
Clear the inventory state and cache file (reset state)
inventory clear [OPTIONS]
This will empty the inventory cache file and re-initialize all hosts from scratch.
This is useful if you want to reset the inventory state, or have difficulties with stale data that cannot be resolved.
Note that this will remove all cached host data, so you will need to re-discover the entire inventory after this operation.
Parameters:
- --force, -f
- Do not prompt for confirmation [Default: False]
host¶
Host Operations Commands
Commands to query, refresh and discover individual hosts.
show is the primary command to display the current state of a host in the inventory.
show¶
Show detailed state of a specific host
host show [OPTIONS] HOST
This command retrieves the host by name from the inventory and displays its details in a rich format on the terminal.
Arguments:
- HOST
- Host from inventory to show [Required]
Parameters:
- --updates, -u, --no-updates, -n
- Show update details for the host [Default: True]
- --security-only, -s
- Show only security updates for the host when displaying updates [Default: False]
discover¶
Detect and gather platform data for a host
host discover HOST
This command retrieves the host by name from the inventory and synchronizes its platform data, such as OS, version and package manager.
Arguments:
- HOST
- Host from inventory to discover [Required]
refresh¶
Refresh the state and update data for a specific host
host refresh [OPTIONS] HOST
This command retrieves the host by name from the inventory and refreshes its state and available updates.
If --sync is specified, the package repositories will also be synchronized remotely.
Arguments:
- HOST
- Host from inventory to refresh [Required]
Parameters:
- --sync, -s
- Also sync package repositories [Default: False]
- --discover, -d
- Also refresh platform information [Default: False]
ping¶
Ping a specific host to check connectivity and online status
host ping HOST
The ping status is based on ssh connectivity, and will update the host's online status in the inventory accordingly.
Arguments:
- HOST
- Host from inventory to ping [Required]
connections¶
Connection State Management Commands
Commands to inspect the state of SSH connections to inventory hosts. These commands are only useful when SSH Pipelining is enabled, otherwise no persistent connections to hosts are maintained.
Only useful from Interactive Mode, as connections are not maintained between separate CLI invocations.
show¶
Show SSH connection state for inventory hosts
connections show [OPTIONS] [ARGS...]
Display the current SSH connection state for specified hosts, or all hosts if none are specified.
Connections that have been idle for longer than the configured maximum age will be marked as "Expiring".
Only useful when SSH Pipelining is enabled, and exclusively from interactive mode, as connections are not maintained between individual CLI invocations.
Arguments:
- NAMES
- Hosts to show connection state for. If omitted, shows all hosts.
Parameters:
- --active, -a
- Show only hosts with active connections. [Default: False]
close¶
Close SSH connections explicitly
connections close [OPTIONS] [ARGS...]
Close SSH connections to specified hosts, or all hosts if none are specified.
Only useful when SSH Pipelining is enabled, and exclusively from interactive mode, as connections are not maintained between individual CLI invocations.
Arguments:
- NAMES
- Hosts to close connections for. If omitted, close all connections.
Parameters:
- --verbose, -v
- Show detailed output of closed connections. [Default: False]
ui¶
Start the Exosphere User Interface
Launches the Text-based User Interface (TUI). When started from interactive mode, quitting the UI returns you to the prompt.
Takes no arguments; the 'start' subcommand is an alias kept for backward compatibility with older versions of Exosphere.
start¶
Start the UI (compatibility alias)
ui start
This subcommand is kept for backwards compatibility with older versions of Exosphere, to preserve the muscle memory of users who have relied on it since 1.0.0. It simply launches the UI, exactly like invoking 'ui' with no arguments.
configuration¶
Configuration-related Commands
Commands to inspect or modify the currently loaded configuration.
show¶
Show the current configuration
config show [OPTIONS] [ARGS]
Displays the current configuration options, or the value of a specific option if specified.
If --full is specified, it will show the entire configuration structure, including the inventory, beyond just the "options" section.
Arguments:
- OPTION
- Name of the option to show. All if not specified.
Parameters:
- --full, -f
- Show full configuration structure, including inventory. [Default: False]
source¶
Show the configuration source, where it was loaded from
config source [OPTIONS]
Displays the path of the configuration file loaded, if any, and any environment variables that affect the configuration.
Parameters:
- --env, --no-env
- Show environment variables that affect the configuration. [Default: True]
paths¶
Show the paths of application directories
config paths
Will display the platform-specific filesystem paths that exosphere uses for configuration, state, logs, and cache.
diff¶
Show the differences between the current configuration and the defaults
config diff [OPTIONS]
Exosphere follows convention over configuration, so your configuration file can exclusively contain the options you want to change.
This command allows you to see exactly what has been changed, optionally in its context, using the --full option.
For a full config dump, use the show command instead.
Parameters:
- --full, -f
- Show full configuration diff, including unmodified options. [Default: False]
edit¶
Open the current configuration file in an editor
config edit [OPTIONS]
Launches your text editor against the currently loaded configuration file. If no configuration file is loaded, the default platform path is opened instead, letting you create one from scratch.
The editor to use is determined from the editor configuration option and then falls back to the VISUAL and EDITOR environment variables, then finally, a platform default.
Changes do not affect the running process; they take effect on next startup. After editing, the file is validated and, if invalid, you are offered the chance to re-open the editor and fix it.
Parameters:
- --validate, --no-validate
- Validate the file after editing (default: enabled). [Default: True]
report¶
Reporting Commands
Commands to generate reports about the current state of the inventory. Allows exporting the state of the inventory to various formats, including JSON for use in other tools or custom reporting.
generate¶
Generate a report of the current inventory state
report generate [OPTIONS] [ARGS...]
The report can be generated in various formats, including html for for a pretty self-contained document, json for easy integration with other tools, or plain text for human readability.
The report can also be filtered to include only specific hosts by providing their names as arguments. If no hosts are specified, the report will include all hosts in the inventory.
It can further be narrowed to hosts with pending updates (--updates-only) or pending security updates (--security-updates-only), which are mutually exclusive.
Note: Undiscovered or unsupported hosts are excluded from the report.
Arguments:
- HOSTS
- One or more hosts to include (all if not specified)
Filtering Options:
- --updates-only, -u
- Only include hosts with available updates [Default: False]
- --security-updates-only, -s
- Only report security updates [Default: False]
Output Options:
- --format, -f
- Output format for the report [Choices: text, html, markdown, json, Default: text]
- --output, -o
- Write report to file (defaults to stdout)
- --tee
- Also print report to stdout (requires --output) [Default: False]
- --quiet, -q
- Suppress informational messages [Default: False]
- Include navigation section (html only) [Default: True]
schema¶
Show or write the JSON Schema for the current version of Exosphere
report schema [ARGS]
Emits the JSON Schema (draft-07) describing the structure produced by report generate --format json, for the currently running version of Exosphere.
This allows anyone to easily get an overview of the structure, validate and integrate, offline, without a local source tree or access to the online documentation.
By default the schema is printed to stdout. Use --output to write it to a file instead.
Parameters:
- OUTPUT, --output, -o
- Write the schema to a file (defaults to stdout)
status¶
Show a brief, condensed status summary of the inventory.
report status
Prints a short, executive-summary overview of the whole inventory: how many hosts have pending updates (and how many of those include security updates), how many are awaiting a reboot, and whether any host data has gone stale.
The output is plain and compact, suitable as an at-a-glance overview or for inclusion in a system MOTD (e.g. by redirecting it to a file).
Color is automatically dropped when the output is not a terminal.
Hosts that have not yet been discovered contribute nothing to the update and reboot counts, as they have no known state.
sudo¶
Sudo Policy Management Commands
Exosphere providers may require sudo privileges to execute certain operations on remote systems. These commands allow you to inspect, validate and generate suitable sudoers configurations.
Exosphere has a global Sudo Policy that dictates how operations requiring those privileges are handled (the default is to skip them).
Individual hosts may override the global Sudo Policy with their own Sudo Policy in the inventory configuration.
For more details, see the Sudo Policies and Privileges section of the Exosphere documentation.
policy¶
Show the current global Sudo Policy
sudo policy
This command will display the current global Sudo Policy in effect. Individual hosts may override this with their own Sudo Policy.
check¶
Check the effective Sudo Policies for a given host
sudo check HOST
The command will take in consideration the current global Sudo Policy and the host-specific Sudo Policy (if defined) to determine if the host can execute all of its Package Manager provider operations.
Arguments:
- HOST
- Host to check security policies for [Required]
providers¶
Show Sudo Policy requirements for available providers
sudo providers [ARGS]
Some providers require sudo privileges to execute certain operations. You can use this command to enumerate these requirements, if applicable.
Arguments:
- NAME
- Provider to display. All if not specified.
generate¶
Generate a sudoers configuration for passwordless operations
sudo generate [OPTIONS]
Creates snippet suitable for /etc/sudoers.d/* on target systems.
Will use username from host configuration, global configuration, or current user if not specified.
Outputs to stdout, can be redirected to a file.
Parameters:
- --user, -u
- Override the username for the sudoers snippet
Target:
(Required, Mutually Exclusive)
- --host, -h
- Generate sudoers snippet based on host configuration
- --provider, -p
- Generate sudoers snippet for a specific provider
version¶
Version and Update Check Commands
Show current version, check for updates.
details¶
Show detailed version and environment information
version details
Displays the currently installed version along with Python version, virtual environment status, and operating system details.
check¶
Check for exosphere updates
version check [OPTIONS]
Compares the current installed version with the latest version available on PyPI and reports if an update is available.
Exits with code 3 if an update is available.
Parameters:
- --verbose, -v
- Show verbose output for check [Default: False]
GLOSSARY AND COMMON TERMS¶
This section defines common terms and concepts used within Exosphere.
- Host
- A host is a remote system that Exosphere connects to in order to gather the information it needs. It refers specifically to the remote system in the inventory.
- Inventory
- The inventory is the collection of Hosts that Exosphere knows about. It is defined through the configuration file, in the Hosts section. Commands and functions that operate on the inventory will generally target All Hosts.
- Provider
- A Provider is a platform-specific implementation of a package manager
interface that Exosphere uses to gather information. For instance, on
Debian and Ubuntu systems, the apt provider is used.
Providers are generally not exposed directly through configuration, just automatically detected based on the platform.
- Update
- An Update, within Exosphere, is an object representing a package that has a new version available for installation.
- Security
- Whenever the term "Security" is used, it refers to the security status of an Update. Security Updates are updates that address security vulnerabilities in the software installed on the Host. Exosphere will generally report these with some form of emphasis, as they are more urgent than regular updates.
- Discovery
- Discovery is the initial process through which Exosphere connects to a host and tries to determine platform details. This usually consists of:
- Operating System: The Operating System installed on the host (Linux, FreeBSD, etc)
- Version: The version of the operating system (20.04, 22.04, 8, etc)
- Flavor: The distribution or flavor (Debian, Ubuntu, RedHat, etc)
- Package Manager: The package manager in use (apt, dnf, yum, etc)
This usually only needs to be done once per host, but can be repeated if any details change, such as a new OS version or package manager change.
- Refresh
- A Refresh is the process of querying the host for its current available
updates and general state. This is generally done by querying the package
manager. The process is universally read-only, and does not perform any
system changes, aside from affecting some metadata timestamps and caches
on certain platforms and operating systems.
This is usually separate from a Repository Sync, but often can be combined into a single operation depending on context.
- Repositories
- Repositories is the generic term for the authoritative list of packages on the host platform. For instance, on Debian and Ubuntu systems, it refers to the remote systems configured in /etc/apt/sources.list and friends. On RedHat-likes, it refers to the repositories configured in /etc/yum.repos.d/, and so on.
- Repository Sync
- Synchronizing the repositories is the process of updating the local host
cache from these remote servers, so that the next update check will have
the latest information.
This is equivalent to running apt-get update on Debian-based systems, or dnf makecache on RedHat-based systems.
This process is generally safe and read-only, but on systems where sudo is required, it may update repository metadata system wide. This is generally not an issue, but if it is problematic, rest assured that the behavior is entirely opt-in, in these cases.
RELEASE NOTES¶
Historical release notes for Exosphere can be found here.
For the highlights of the current release, see the What's New <> page.
3.0.0 - Reboots, Palettes, Sorting and refreshed CLI¶
The first major version release actually backed by a major set of changes. This release lands several long overdue features, refactors a lot of internals, swaps out the entire CLI engine and provides a much more polished help and documentation experience.
It has been cooking for a while, and the release notes are correspondingly long. Most of these changes are transparent, but there are some unavoidable incompatibilities. Make sure to read User Actions Required and Incompatible Changes before upgrading.
Feature Highlights¶
Pending Reboot Detection¶
[image: image] [image]
Exosphere can now tell you when a host is waiting on a reboot to finish applying updates --- a running kernel that no longer matches the installed one, a distro's reboot-required flag, and so on.
This is another feature grown out of a question that comes up frequently when managing updates across a fleet of hosts: "Has everyone been rebooted?". It felt only natural for Exosphere to attempt to answer that question.
This is presented in several places across the application interfaces:
- The CLI and inventory TUI status tables, as a small ! marker in the Status column --- much like the existing * marker for stale data
- Detailed host views (host show, the TUI host details panel)
- Reports of every format (text, Markdown, HTML) and JSON output
The feature is implemented for all supported platforms where this information is available (Debian/Ubuntu, RHEL and derivatives, FreeBSD) and is entirely best-effort. None of the reboot checks require elevated privileges, so there is no sudoers change. If a provider cannot determine the status --- a missing tool, an unexpected error --- it is simply reported as unknown rather than failing the operation, so it will never block you from doing anything else.
TUI Command Palette Operations¶
For a long time the only way to perform targeted operations on a specific host was to use the CLI host commands, or specify hosts in bulk inventory operations.
The TUI was previously limited to bulk operations, and on specific screens.
To resolve this, the TUI now makes use of the command palette (Accessible via Ctrl+P) to allow you to run any of the host operations (sync, refresh, ping, etc) from any screen, and targeting any host.
[image: image] [image]
Selecting hosts also conveniently presents as a fuzzy search list, making the whole process light in keystrokes, and high in discoverability.
[image: image] [image]
The palette will also preselect the currently highlighted host in the Inventory screen, further lubricating the process.
[image: image] [image]
The palette and its operations can be invoked from any screen, and with this, there is finally functional parity between the CLI and TUI for host operations.
Inventory Sorting¶
[image: image] [image]
[image: image] [image]
Inventories can now be sorted, in both the CLI and the TUI.
- On the CLI, status and the inventory listing gained sort options, including a compound sort by flavor and a --full view that includes the description for hosts.
- In the TUI, a sort modal lets you pick a field with quick-select keys and reverse the order with r.
Undiscovered and unsupported hosts always sort last, so the interesting hosts stay at the top regardless of the chosen field.
Reworked Built-in Help and CLI Polish¶
Exosphere has swapped out its CLI framework internals, and with that came the perfect opportunity to give a polish pass to the built-in help system.
[image: image] [image]
Multiple help panels, especially for the most complex commands like sudo or report, have been rewritten to be more helpful, explain what they do, and most importantly, group their copious options and flags into logical, meaningful sections.
[image: image] [image]
Additionally, unknown commands or verbs will now display a helpful message, with fuzzy suggestions for what you might have meant, leading to a friendlier experience when exploring the CLI or REPL.
The CLI engine change also brings a lot of internal improvements and better behavior for both the CLI and REPL.
New Commands¶
A few small but helpful new commands have been added:
- config edit -- opens the current configuration file in your text editor, with proper validation and waits. The editor is determined by configuration, $EDITOR, or falls back to a platform default.
- report schema -- exports the current JSON schema for the reporting system, to use as a reference or for validation in external tools.
- report status -- a very short, two or three lines summary of the current state of the inventory. Suitable for inclusion in scripts or system MOTD.
All of these are documented more extensively in the Command Line Interface (CLI) <> docs as well as the Reporting and JSON Export <> docs.
The Web UI has been removed¶
It had always been more of an experimental curiosity than a real feature, and had not been actively developed since 1.0.0. Newer features (such as instance/cache locking) had begun to clash with it, and on balance it had become more of a maintenance burden than a useful capability.
As a result:
- The ui webstart command has been removed.
- The web optional dependency extra (textual-serve) is gone.
- A bare ui command now launches the TUI directly.
- ui start remains as a compatibility alias for launching the TUI, so existing muscle memory and scripts are not broken.
See the User Actions Required section for details.
Other Improvements¶
- Task Dispatch Logic Improvements -- the subsystem responsible for dispatching tasks to hosts has been refactored and unified across the CLI and TUI. This includes better handling of unsupported hosts, and preemptively skipping them in bulk operations where they would otherwise do nothing.
- Remote command robustness -- all remote commands now setup a POSIX-compliant, deterministic environment for execution. This includes running all provider commands under /bin/sh, and pinning the locale to a known value. This makes reliability across login shells and localized server environments much more predictable.
- Cache file locking -- Exosphere now takes a lock on the state cache to prevent two concurrent instances from writing to it at the same time.
- Stricter configuration validation -- malformed configuration files (non-mapping documents, and other structural problems) now produce clear, actionable errors instead of confusing downstream failures. Empty config files are handled gracefully.
- Logging polish -- Package Manager Providers now automatically prefix their log messages with the host that produced them, making the logs much more useful.
- Non-TTY Handling -- Exosphere now actively guards interactive-only features when running in a non-TTY environment, such as script, cronjob or similar. The primary side effect is that it prevents Exosphere from hanging while trying to read input it will never receive, and instead produces a clear error message.
Bugfixes¶
Exosphere¶
- CLI and TUI now use the same descriptors for undiscovered hosts, instead of "(unknown)".
- Fixed latent config load issue with paths, which could result in environment variables not being applied correctly or ignored, in rare cases.
- --version flag no longer goes through the entire initialization process, and now prints the version immediately.
- TUI Inventory Screen now correctly preserves the cursor position when refreshing
- Fixed issue where Dashboard host would fall back to "(unknown)" instead of "(unsupported)" when detected as Offline.
- Cancelling a TUI Sync operation now also correctly aborts the follow-up Refresh, instead of infuriatingly continuing to run the next step of the chain.
- Removed a spurious notification when a filter matched no hosts after an operation triggered a refresh in the TUI.
Providers¶
- OpenBSD -- Correctly handle flavors, quirks renames. All scenarios should now parse correctly.
- RHEL -- Fix issue parsing post-release snapshots, especially on Fedora and derivatives. Parsing has been lined up with upstream package name specs, and should be more robust from hereon.
User Actions Required¶
Shell completion must be reinstalled. The new CLI engine generates completion differently, so re-run exosphere --install-completion to install the updated scripts. On everything except PowerShell the new scripts take precedence and the old ones are harmless leftovers. If you do not use the shell completion feature at all, you have nothing to do. If you would like to remove the old scripts, see the FAQ <#faq-completion-upgrade> for the full details.
PowerShell completion is no longer supported and its leftovers must be cleaned up by hand, unfortunately, as there is no way around it. See the FAQ <#faq-completion-upgrade> for the full details and cleanup steps.
Web UI has been removed. The ui webstart command and the web install extra no longer exist. If you installed Exosphere as exosphere-cli[web], drop the [web] extra from your install. Existing installations will automatically resolve this on their own during upgrade, so there is no need to reinstall. Use the TUI instead, which is now the default ui command.
Incompatible Changes¶
- CLI Return Codes: The CLI now returns 1 for input errors, and 2 for runtime errors. This is a change from the previous behavior where this was reversed. Scripts that depended on the old behavior will need to be updated. The behavior of special status code 3 remains unchanged.
- Multiple instances of Exosphere are no longer supported. This was never a supported configuration, given the semantics of the cache file, but it also was never explicitly protected against. The cache file is now locked to prevent concurrent access and a second instance will fail to start with a clear error message.
Project and Documentation¶
- Licensing -- the repository's licensing was cleaned up into a REUSE-style layout, with a top-level COPYRIGHT, per-license files under LICENSES/, and an explicit LLM contribution policy added to the README.
- Changelog system -- release notes are now maintained in-repo as Markdown files under changelog/, rendered into the docs by a small Sphinx extension that manages the index and "What's New" page automatically. All 26 prior releases were backfilled.
- Docs refresh -- the table of contents was reorganized with a new Concepts section, the CLI reference was reformatted, screenshots were refreshed for the new features, and most importantly, a significant polish pass was made, making this version of the online documentation the best so far. Many dense sections were split and reorganized for better legibility, including the FAQ.
What's Changed¶
- Add ability to sort inventory (CLI and TUI)
- Unify undiscovered display, fix dashboard bug
- TUI: Add Command Palette entries for Host Operations
- Remove Typer, Replace with Cyclopts
- Improve UI logging, cleanup loglevels
- Improve CLI help formatting and validation logic
- CLI: Skip unsupported hosts during sync and refresh
- REPL: Fix help behavior for invalid subcommands
- CLI: Add --install-completion support
- UI: Add quick-select keys for sorting options
- Add log caps to Application logs, REPL History
- Main: Fix latent config load issue with paths
- UI: Select Sort Modal entries via quick key
- Add file locking to prevent concurrent cache use
- Add config edit command, refactor CLI internals
- Config: Add stricter schema validation
- Cleanup Project Licensing
- Add pending reboot detection feature
- Remove Exosphere Web UI feature
- redhat: Fix issue parsing post-release snapshots
- Core: Enforce locale and shell for remote commands
- TUI DataTable Improvements, preserve cursor position during refresh
- CLI: Cleanup and improve help text for commands
- docs: Reformat CLI reference docs
- OpenBSD: Correctly handle flavors, quirks renames
- Docs: Reorganize TOC, add Concepts, docs refresh
- Docs: Add Changelog and Changelog Accessories
- Reporting: Add schema export and status commands
- Core: Cleanup task dispatch for unsupported hosts
- Tests: Consolidate Host factory fixtures
2.4.3 - Hotfix Release¶
Released May 28, 2026
This optional hotfix release constraints a dependency (Typer) to a specific version to ensure compatibility and prevent runtime breakage, especially when exosphere is installed or updated via pipx. This is due to an upstream change in Typer <https://github.com/fastapi/typer/releases/tag/0.26.0>.
2.4.2 - Bugfix Release¶
Released April 14, 2026
An additional bugfix release containing some more pressing fixes before we embark on the 2.5 series where new features will land.
Bugfixes¶
- Resolved an issue where the discover process required lsb-release, which could be absent on some modern Debian installs (#244)
- Debian provider now logs APT warnings to help surface non-fatal errors leading to strange behaviors (#243)
- Redhat provider now correctly handles unknown or obsolete repo source metadata when querying the current version of a package. This resolves a bug where some packages would, in certain circumstances, incorrectly be displayed as NEW.
Minor Features¶
The Documentation <> is written with Sphinx, and used a visual theme that has been declared as unmaintained. It also has a history of friction with versions of sphinx >=9. It has been removed and replaced with sphinx-rtd, alongside a custom CSS override that has been written to replicate the original look and feel. Additional enhancement to code boxes, syntax highlighting and general layout were also added. This also allows us to further customize the look and feel in the future.
What's Changed¶
- setup: Do not rely on lsb-release for version
- Debian: Log APT warnings in provider operations
- Redhat: fix provider parsing of unknown sources
- Replace Renku Sphinx theme with rtd and CSS
- CI: Include docs in test-minimum action
2.4.1 - Red Hat Provider Bugfix Release¶
Released April 06, 2026
Minor point release including a refactor and streamlining of the Red Hat dnf/yum Provider, as well as correction of two bugs, while work is being done on the upcoming 2.5 release.
Red Hat provider Refactor¶
Handling of kernel packages no longer hinges on manual resolution to work around vendor-specific kernel repositories having odd configurations in some environments. This mostly affected certain cloud platform images with misconfigured repositories.
- The kernel update specific code paths were removed entirely, and the process has been streamlined back into relying exclusively on check-update internally.
- The dnf/yum tabular data parser has been refactored and hardened against unexpected annotation that some versions of the package manager sometimes insert in some edge cases.
- Parsing of columns has also been significantly hardened and brought in line with the rest of the providers.
This streamlining resolves a handful of bugs, and also massively improves performance on Red Hat-like systems by no longer having to do expensive rpm database queries, sometimes twice.
Bugfixes¶
- DNF Provider incorrectly parses Security annotations in check-updates #234
- DNF Provider may report a ghost kernel update when third party repositories are enabled #231
What's Changed¶
- Move sudo auth failure message to errors module
- Refactor and simplify Red Hat Provider
- Providers: compile regex patterns on first use
2.4.0 - Sudo, FreeBSD vuln.xml improvements¶
Released March 10, 2026
A minor update that resolves two annoyances:
- 1.
- The FreeBSD provider's reposync operation now fetches the latest vuln.xml as part of its run, preventing failures on fresh installs where the vulnerability database has not been downloaded yet, and ensuring it is up to date alongside the repositories.
- 2.
- Sudo authentication failures now surface a much clearer error message, instead of confusing, out of context Fabric/invoke messages. The error message will now point users towards the documentation chapter about configuring sudoers.
It gets a minor version bump due to user-facing configuration changes, detailed in the next section.
User Actions Required¶
The minor change to the FreeBSD provider implies a change to sudoers configuration. The reposync operation, which runs through sudo, now also runs /usr/sbin/pkg audit -qF as part of the process.
If you have FreeBSD hosts with a sudo policy of NOPASSWD within exosphere, you will need to update or regenerate your sudoers configuration.
This can be done very simply via exosphere sudo generate. Failure to do so will result in an error message that will point you to the documentation on how to configure this <#generating-a-sudoers-configuration>.
If you use SKIP (the default) as a sudo policy, or do not have FreeBSD hosts in your inventory, no action is required.
What's Changed¶
- FreeBSD Provider: Ensure sync refreshes vuln.xml
- Add sudo failure error handling to requires_sudo
2.3.0 - Maintenance Release¶
Released February 19, 2026
It is time for a periodic maintenance release, with mostly a fix to the json output, some internal library and dev tools upgrades, as well as a bunch of minor documentation improvements.
New "stale" field in json export¶
Previously, json format exports in reporting module did not include whether or not Exosphere considers the host stale according to its configuration.
A "stale" boolean field has been added to both the to_dict() method on Host objects as well as the expected json schema. The documentation now covers this as well.
This has been a long standing oversight, since every other reporting format actively includes this information, and consumers of the json data should not have to do date math to figure out that information.
Since it is an addition to the schema, the change is backwards compatible.
Documentation improvements¶
- Project README key features now cover parallelization and SSH pipelining
- Configuration docs now have better inter document links in regard to config file sections
- uv is now very clearly linked in Quickstart Guide, instead of being easily missed one word links
- Quickstart Guide now has better, more targeted links to specific documentation sections, as jump points
- Quickstart Guide now mentions the existence of the 'help' command (which felt like an oversight)
- The Next Steps section of the Quickstart Guide have been reorganized to better direct new users to features they might want
What's Changed¶
- Add stale field to json export
- Misc Docs Fixes
2.2.0 - SSH Pipelining and Spring Cleanup¶
Released January 12, 2026
A polish pass and a feature¶
This release contains a hot new feature and a polish pass on the entire codebase, refactoring a lot of internal code that was either sub-par, or naively designed for simpler times back in 1.0, and had not been revisited since.
It's not spring, but spring cleaning is a state of mind, unbound to such trivial things as calendars.
New Feature: SSH Pipelining¶
[image: image] [image]
A new opt-in configuration setting <#ssh-pipelining-docs> now allows you to leave SSH connections open between operations in Interactive (REPL) or TUI mode, which will allow Exosphere to reuse them, reducing connection open/close churn, and improving performance on larger inventories, or setups where the ssh negotiation part of the connection is particularly slow.
The connection will be closed after a configurable idle time <#ssh-pipelining-lifetime-option> that defaults to 300 seconds.
This comes with a new REPL command, connections which will display the current state of any connection currently held open by Exosphere, as well as let you manually close them if that is something you want to do.
By default, the pipelining feature is disabled and the previous Exosphere behavior of closing connections after each operation remains unchanged.
However, some minor batching and optimizations have been done in the dispatch and provider code to ensure there is significantly less connection churn, batching all queries related to a single operation (sync, refresh, ping etc) within the same connection. Performance should be improved in general, even with pipelining disabled.
The choice of which mechanism is preferable is left entirely to the user.
Internal refactoring and polish pass¶
A lot of the earlier code within Exosphere was designed around a much smaller, more naive ideal for how Exosphere should function. As the application grew and found its exact scope, a lot of these design decisions were mostly hacked around or left alone.
The primary one is the way the state cache (exosphere.db) is built and loaded. Several improvements have been done around the serialization machinery. The state of a Host object is now contained within a HostState dataclass that is easily serializable, with a proper version schema.
This allows us to ensure seamless migration of data between exosphere versions in a much cleaner way, replacing the series of horrifying serialization hacks we had previously to achieve this.
Migration to this new serialization format will be handled transparently by Exosphere, so there is no user action required. INFO level logs are produced on the initial conversion, but otherwise the cached state of your hosts should carry over.
Other than this, a lot of miscellaneous warts and unpleasant areas of the code that bothered the author for a while have been rewritten to be much, much nicer, with no user facing changes or differences. The UI code in particular had a lot of horrifying hacks removed, and duplicated code with subtle differences unified, resulting in a much cleaner code base.
Dependencies changes¶
Some runtime libraries had their version constraints changed, for compatibility or security reasons:
- Typer>=0.20.0
- Textual>=6.7.0 (for new autosize grid components)
- pyyaml>=6.0.3
- rich>=14.1.0
Bugfixes¶
- •
- cache_autopurge option now correctly respects cache_autosave being false in configuration. This has been clarified in the documentation.
What's Changed¶
- Docs: Add FAQ entry for dnf sqlite ro issues
- Feature: SSH Pipelining
- Refactor Host serialization and cache format
- REPL: Refactor host completion to be dynamic
- Misc internal fixes and cleanups
- Dashboard: Switch to ItemGrid container
- Internal UI refactors
- Minor Cleanups
2.1.2 - Optional hotfix¶
Released November 09, 2025
Optional Hotfix Release¶
Minor hotfix and minimum version bumps to accommodate Python 3.14 environments, specifically the optional web ui component of Exosphere.
Also contains internal changes to the CI jobs and test suite to prevent future regression and better test against minimum versions in pyproject to avoid the 2.1.1 issues.
No Exosphere code changes, purely metadata and dependencies, so this hotfix is entirely optional, but of interest if you:
- Use python 3.14 already
- Want the webui support
What's Changed¶
- Add Action to run test suite against minimum versions
- Add basic integration tests for TUI
- Cleanup CI jobs
- Update test suite badge in README
- Require pyyaml >= 6.0.3 for 3.14 support
- Explicitly add rich to dependencies
- Bump textual-serve to 1.1.3 for 3.14 support
- Expand UI Test Coverage
- Bump version to 2.1.2 for release
2.1.1 - Hotfix¶
Released November 01, 2025
Hotfix Release¶
Minimum version of Textual as a dependency was incorrectly set, in some installations this can result in the Inventory screen crashing on access with Footer.__init__() got an unexpected keyword argument 'compact'
Bumps Textual dependency minimum to v6.2.0 to resolve the issue.
I blame the spooky Halloween ghosts.
👻 sorry my release was haunted sorry
2.1.0 - The Big Quality Release¶
Released November 01, 2025
Big Quality of Life Update¶
🎃 A spooky Halloween Release 🎃
This update contains multiple long standing QoL changes that I have been wanting to put in for a while. It is my hope that this makes the experience of using Exosphere more pleasant.
Let's go over the major ones:
TUI Inventory Screen Features¶
[image: image] [image]
Sync Repos as an action has been reworked into Sync & Refresh. When hitting ctrl+x, Exosphere will now do a repository sync followed by a refresh, as there was essentially no scenario in which you would just want a sync alone. This saves you the need to hit ctrl+r immediately after, as it will do it for you.
Filtering functionality on TUI Inventory Screen¶
[image: image] [image]
You can now hit ctrl+f to filter the inventory view to only display hosts with updates, or hosts with Security Updates exclusively. The CLI inventory command had this functionality for a while, and I strongly felt like the TUI one needed feature parity.
[image: image] [image]
A status bar has been added at the bottom of the inventory screen which will inform you whenever the view is filtered in any way.
Themes Support¶
Most of the Textual CSS and Colors within the Exosphere TUI have been reworked to use generalized colors that honor the selected Color Theme. So you can now fully swap to your favorite using the appropriate Palette command, and Exosphere will absolutely respect it.
TUI navigation improvement¶
The bottom footer with navigation keybinds no longer shows the keybind for the screen you are currently on. This conserves screen real estate significantly, and prevents the menu from being overwhelming.
Additionally, the inventory screen now switches the layout of the footer to a more compact one to ensure it is legible on smaller terminal sizes.
Before: [image: image] [image]
After: [image: image] [image]
REPL Improvements¶
In addition to a new shiny logo banner on startup (which can now be disabled <#no-banner-option>, if you don't share my eclectic tastes in ascii art), the REPL has seen massive improvements to its tab completion features.
Host Completion¶
Exosphere in interactive mode can now tab complete inventory hosts, either as positional or option arguments.
[image: image] [image]
This includes the expected readline-like double tab to show all possible matches features.
Better readline/shell-like completion flow¶
The Completion code has been refactored significantly to allow closer behavior to that of unix shells and readline in general. More specifically, trailing spaces are appended after matches, and options that do not take arguments (i.e. --sync) will simply tab through, allowing you to tab complete lines at blazing speed, in a context sensitive way.
What's Changed¶
- TUI: Improve Sync behavior on inventory screen
- TUI: Add Filtering functionality to Inventory screen
- UI: Improve footer usability
- REPL: Massively improve tab completion
- REPL: Prevent double completion in help full match
- Update REPL banner, add option to disable it entirely
- Misc docs and comments cleanup
- Fix documentation for default_sudo_policy
- Support Textual theme colors where possible
- Dashboard: add ~3chars tolerance in sizing columns
- Refresh documentation screenshots, README
- Bump version, update lockfile
2.0.1 - Hotfix Release¶
Released October 12, 2025
Small bugfix release¶
Fixes the issue described in #111 where exosphere version check would exit with 0 status when options.update_checks is disabled. Now properly exits with nonzero.
What's Changed¶
- •
- Fix version check should return 1 when disabled
2.0.0 - CLI exit codes and Python 3.14 Support¶
Released October 11, 2025
Big number, small changes¶
Exosphere now uses consistent and documented exit codes across all of its CLI components. Since, strictly speaking, this is a backwards incompatible change (although it is unlikely to affect many people), the version has been incremented to 2.0.0 to communicate this, in accordance with the holy texts of Semantic Versioning.
Return Codes¶
Exosphere now consistently returns the following exit codes:
- 0 - Success
- 1 - Execution error (something went wrong during processing)
- 2 - Argument error (something wrong with an option or argument you provided)
- 3 - Special - Used sparingly to communicate specific scenarios
Using 2 for argument errors is a consistent behavior with the Typer library (which we use extensively for CLI commands) and multiple Unix utilities, such as grep.
Status 3 is used very sparingly, and so far only returned by exosphere version check to communicate that a new version is available, as well as by inventory status whenever any of its filtering options (--updates-only etc) do not match any hosts.
This is documented in our Lovely Documentation in its Appropriate Section <#return-codes>
Python 3.14 Compatibility¶
Python 3.14 is now officially supported with this release.
Internally, the test suite for Exosphere has been put in a Matrix that runs against both 3.13 and 3.14, to prevent regressions across supported versions. The uv lockfile has been updated with versions of main dependencies and dev tools that support both, but the minimum required versions have been left alone.
This should ensure compatibility between 3.13 and 3.14, and lays the groundwork to support upcoming versions without too much hassle.
New detailed version command¶
In order to make diagnostics and debugging easier, the version command now has a details subcommand that will return information about the current Python environment, venv, and host system.
What's Changed¶
- Github: Add test matrix for ci workflow
- Additional Python 3.14 Compatibility
- Uniformize return codes across application
- Bump version to 2.0.0 for release
v1.5.1 - Minor QoL Update¶
Released October 10, 2025
Minor point release introducing a small QoL improvement that is fully backwards compatible, as well as Python 3.14 uv housekeeping.
[image: image] [image]
Exosphere now has the ability to filter inventory status output with --updates-only and --security-only, and it feels weird that it didn't from day one.
Documented in the CLI section <#viewing-inventory-status>.
Additionally, the inventory being empty is now correctly considered an error case, and Exosphere commands will correctly return non zero exit when unable to perform their actions due to that scenario.
The lockfile for uv dependencies has been updated with a handful of dependencies that are either minor, or have explicit Python 3.14 support patches added in. We're preemptively adding them it for consistency and future compatibility tests.
1.5.0 - The Reporting Update¶
Released October 04, 2025
Exosphere can now generate reports¶
[image: image] [image]
If you ever felt it was weird that a patch reporting tool could not actually produce reports you can print, email or otherwise use outside of the application, this update will likely please you.
Exosphere now provides a report command which allows you produce document based reports in HTML, Plain Text and Markdown formats, which should hopefully cover most use cases.
The reports can be filtered to include only a selection of hosts, updates only, or security only, and have a wealth of useful options. Various in depth examples of the formats as well as copious details on usage can be found in our ever growing documentation <>.
Exosphere can now emit JSON with the current state¶
[image: image] [image]
As part of the same feature, we now have a nice JSON report format available for programmatic consumption of the data and inventory state. It is simply treated as an extra format the reporting module can handle.
This should be helpful if you ever wanted to integrate Exosphere into something else, or feed the data that it generates into something else, ranging from a Discord bot to your event system for your overly complex Doorbell over zigbee MQTT system.
It's also reasonably helpful for use with jq <https://jqlang.org/> to perform ad-hoc queries that Exosphere itself doesn't expose.
This feature is discussed in great detail, including a full definition of the JSON Schema, in our ever growing documentation <#json-schema>.
Version Check command¶
There is now a version command with a check subcommand that will query PyPI to tell you whether or not your version of exosphere is up to date, and provide you with links to release notes and upgrade documentation if relevant.
We do not have automatic checks on startup or anything of that nature, it is strictly on-demand. This feature can also be forcefully disabled via the relevant configuration option <#update-checks-option> if necessary for your environment.
Minor CLI improvements¶
[image: image] [image]
- inventory refresh now has a --verbose option that will give you a host by host view of tasks as they complete, much like how discover does by default.
- Built-in help for commands options has been reworked to offer a more consistent view across subcommands.
Changes in this Release¶
- Docs: Detail syspatch usage for OpenBSD provider
- Improve CLI help, add verbose switch to "inventory refresh"
- Use UTC timezone-aware datetime objects for host.last_refresh
- Add Reporting Feature
- Misc docs fixes
- Add sphinx-lint, poe task, linting pass
- Update FAQ Entry regarding OPNSense
- Add Version Check feature
- Library updates in uv lockfile, both for development and runtime
- Misc source tree cleanups
1.4.1 - Hotfix Release¶
Released September 14, 2025
This hotfix release corrects handling of the scenario where OpenBSD hosts can exclusively have packages installed that have never gotten any sort of update. This scenario is now checked early and handled gracefully instead of raising an exception in the provider.
What's Changed¶
- •
- OpenBSD: Fix handling of packages never having updates
1.4.0 - OpenBSD Support¶
Released September 13, 2025
Exosphere now fully supports OpenBSD as a remote platform¶
[image: image] [image]
The major feature in this release is the addition of a new PkgAdd provider, which targets OpenBSD remote systems. If you add OpenBSD systems to your inventory, discovery should enumerate them fully and you will be able to perform refresh actions on it, and obtain host details, just like any other supported remote Operating System.
Notes¶
If you already have OpenBSD hosts in your inventory , and they have been discovered as unsupported, that state will not automatically change. You must run exosphere inventory discover at least once after updating to 1.4.0 to have them fully setup and integrated into exosphere.
By default, on a release or stable install, all package updates are Security Updates, by definition, and will show up as such in Exosphere.
If you are running -current or -beta, the security status of package updates can't be ascertained and none of them will show up as security updates.
Special Thanks¶
Thanks to Solène (@solene@bsd.network) on the Fediverse for the helpful pointers regarding the specific semantics of package updates on OpenBSD
What's Changed¶
- •
- Add OpenBSD Support
1.3.5 - Optional Documentation Hotfix¶
Released September 12, 2025
This completely optional releases updates the lockfile dependencies, and corrects a handful of minor issues in the project documentation.
No code changes.
What's Changed¶
- Documentation and Dependencies update
- Docs: document sudo requirements for FreeBSD
- Docs: update FAQ for OPNSense, add sudoers help
1.3.4 - Provider reposync enhancements¶
Released September 08, 2025
This is a small release that changes a few behaviors for reposync in providers that require sudo privileges.
- 1.
- FreeBSD provider now has a reposync implementation that requires sudo, in order to enhance reliability and security
- 2.
- All providers that require sudo use absolute paths when calling their commands, in line with the generated sudo snippets.
The second change should have no impact on your systems, and the change is reflected in the documentation <>.
The first change however may need some configuration adjustments, if you want to opt into the new feature.
FreeBSD Provider Changes (potential actions required)¶
Previously, the FreeBSD provider's reposync method was basically a no-op, and did nothing. If your sudo policy <> (either globally or local to freebsd hosts) is skip (which is the default), nothing changes, and you can continue using the software as-is if you are happy with the behavior.
If you have a global policy set to nopasswd, ensure your FreeBSD systems have sudoers configured for Exosphere. You should configure this either way if you wish to be able to perform a repository sync (^x in the ui, or refresh --sync in the cli) on FreeBSD hosts.
This is not mandatory, and you could instead elect to run pkg update -q via a cron or periodic job on the systems to ensure repository freshness.
Documentation regarding this procedure is available <#generating-a-sudoers-configuration>.
Why the late change?¶
Previously, the FreeBSD provider worked on the assumption that the upgrade process synchronized repositories automatically during updates/upgrades -- which it does. However, this does not actually occur in the simulation mode we use to query available updates on the systems.
Given the presence of the sudoers policy system, and the fact that doing nothing maintains the existing behavior, I've elected to make an actual reposync available on FreeBSD hosts, as an incremental fix.
What's Changed¶
- Recommend uvx over uv tool in docs
- Require sudo privileges for FreeBSD reposync, use absolute paths for sudo
1.3.3 - FreeBSD Bugfix Release¶
Released September 04, 2025
This is a bugfix release containing fixes for the FreeBSD package manager provider in Exosphere.
Recent versions of pkg(7) on FreeBSD 14 now include the Repository tag in brackets in the output of packages, which broke parsing due to where it was inserted. This would cause no updates to ever be shown on affected systems.
This bugfix adds support for the output format of newer pkg versions, while still retaining compatibility with older versions. Parsing has been made slightly more defensive to minimize the chance of future issues.
Additionally, since we now have access to the repository name metadata, we now correctly report it in Exosphere. If the version of pkg on the target system does not report it, the previous "Packages Mirror" value will continue to be used.
Additional changes¶
Minor dependencies updates in lockfile
Dependencies:
- platformdirs (4.4.0)
- prompt-toolkit (3.0.52)
- textual (6.1.0)
- typer (0.17.3)
Transitive (deps of deps):
- cryptography (45.0.7)
- typing-extensions (4.15.0)
Internal/Dev:
- coverage (7.10.6)
- pyright (1.1.405)
- pytest (8.4.2)
- pytest-mock (3.15.0)
- ruff (0.12.12)
- sphinx-autobuild (2025.8.25)
1.3.2 - Bugfix Release¶
Released August 30, 2025
This release is a bugfix release correcting issues in the discovery process and redhat providers for Fedora systems and dnf5.
What's Changed¶
- •
- Fix Fedora and dnf5 support in discovery, redhat provider
1.3.1 - Optional Hotfix¶
Released August 24, 2025
Version 1.3.1 is comprised mostly of obvious documentation fixes (mostly spelling, typos and grammar). An editing pass has been done over comments and docstrings as well.
The uv lockfile has also been updated with a few dependencies updates.
This hotfix is entirely optional, and contains no actual code changes beyond updated dependencies if you install Exosphere via uv tool.
What's Changed¶
- Update dependencies (dev + runtime)
- Docs: fix typos, grammar and odd phrasing
- Hotfix/1.3.1
1.3.0 - Supporting the Unsupported Release¶
Released August 20, 2025
Exosphere now supports keeping unsupported hosts in the inventory¶
[image: image] [image]
The main major feature of this release is the ability to add unix-like systems that do not have a package manager Provider available to the inventory. This allows the connectivity checks to function, and the hosts to show up on the dashboard, but you will not be able to perform package refresh and repository syncs on them.
A recurring piece of user feedback has been the expectation that unsupported hosts in the inventory that pass the Online check should not suddenly turn Offline when the discovery process identifies them as unsupported. This feature update now resolves this, and we now officially support this scenario! The UI (cli commands and TUI both) will properly accommodate them as well, marking them explicitly as unsupported, and will not attempt to display Update counts or stale indicators for them.
Note that this is still limited to Unix-like, or at least Reasonably POSIX Compliant hosts. Other proprietary platforms where SSH is available (i.e. Network equipment, Windows hosts with sshd that does not lead to WSL, etc) will simply not be supported at all, and the discovery process will report them as such, encouraging you to remove them from the inventory.
Upgrade Notes¶
There are two important notes if you are upgrading from 1.2.0 or earlier:
- You should run exosphere inventory discover after upgrading to ensure unsupported hosts are correctly picked up, if you have any.
- We no longer support installation outside venvs via pip, as this is only a recipe for disaster, and unsupported in many distributions anyways. Consider installing via pipx or uv tool instead.
New Features¶
- Support for unsupported hosts in the inventory. Unsupported Unix-like hosts are now allowed in the inventory to still benefit from the dashboard and online checks (#36)
- Configuration file validation improvements: hosts missing critical fields will now be correctly reported on startup
- Discovery process has been overhauled further to now report useful errors to users and avoid confusion and further distinguish Authentication errors from other types of failure cases.
- Error messages have been improved as per user feedback.
- Documentation has been updated to reflect these changes, and improved in many parts.
Bugfixes¶
- Filter out @ from the ip field in the hosts section of the configuration, to avoid undefined connection behaviors with the underlying SSH libraries (#50)
- Redhat Provider: Prevent duplicate updates from being reported in some configurations
- Redhat Provider: Correctly report Kernel updates in spite of DNF not considering those updates in most configurations (#48). We now abstract this and present them as upgrades as that is more consistent with expectations from a UX standpoint.
Misc¶
- Internal command for SSH ping test has been changed to POSIX true instead of some flaky echo. This allows us to further distinguish specific failure cases in future iterations, while ensuring minimal POSIX compatibility for hosts.
- Removed old compat module, unnecessary since switch to our own REPL code.
- Dev dependencies updates
- Library updates in uv.lock (textual 5.3.0)
- Drop support for pip install --user as it only causes problems outside of venvs and is no longer possible on Debian out of the box.
1.2.0 - The Reactive UI release¶
Released August 04, 2025
The dashboard is now fully reactive¶
The grid of hosts will now adjust itself, dynamically changing its amount of columns to optimally present the contents in varying terminal sizes.
Additionally, much of the presentation code has been rewritten to use a nice hierarchy of labels, making maintaining the position of the online status line across tiles with different contents much easier. The result should be a much more consistent display, even when the terminal is resized.
UI Logs¶
The UI logs screen has also gotten a coat of fresh paint with a custom Formatter that now presents the information in a much more helpful way. Additionally, multiple modules repeated the same host exceptions at INFO level. Most of these have been moved to DEBUG, since they are not particularly helpful at runtime for users.
This should make for a much more pleasant experience when trying to figure out what the error was on any of the UI Screens.
What's changed¶
- Make path to repl history configurable (Options: history_file)
- Make Dashboard Responsive
- Rework empty inventory error messages, they now show up consistently in the middle
- Rework UI logging in general
- Bump textual from 5.0.1 to 5.2.0
1.1.0 - The Fancy CLI Release¶
Released August 01, 2025
[image: image] [image]
After spending the last weeks before 1.0 polishing up the TUI, the Interactive command line interface was in dire need of some love. At the center of this release is a brand new, improved interactive CLI component and improved error reporting.
Highlights¶
A brand new REPL Module¶
Previously, the interactive shell, or REPL for Exosphere was provided by a quick hack around click_shell, in order to get the hierarchy going quickly. The experience it provided wasn't up to scratch, and functionality depended on platform. Not to mention, a bunch of horrifying compatibility hacks were added to ensure basic feature parity on Windows.
All of this has been completely replaced with a brand new, purpose built REPL module! Some exciting features include:
- Readline-style Tab Completion down to individual options for each command and subcommand
- Persistent history and reverse search (ctrl+r)
- Completely multi-platform (linux, unix, mac, windows), pure Python, with no dependencies on readline
- Improved colors and general presentation
- Much improved subcommand error handling
- A few built-in commands, all documented
Much Improved error reporting¶
The discover command, both at inventory and host level, will now clearly report authentication issues, allowing for a much smoother first experience when adding hosts to the inventory. Apologies to people who had to look at the logs previously and furrow their brows at less than useful error messages written in SSH Library Speech.
The documentation has also been refreshed to cover this very topic, which hopefully should make onboarding much smoother.
Dependency Slimming¶
The Web UI component of Exosphere is mostly experimental, and more of a curiosity than Generally Helpful, and burdening every install with its large stack of dependencies felt rude, so it has been made completely opt-in.
By default, it will not be installed, but you can very easily add it back by installing exosphere-cli[web], as an extra.
Finally, on a personal note, seeing other people get use out of my silly little piece of software has brought immense joy to my cold, bitter, industry veteran heart. If you sent any sort of experience report, thank you. If you didn't, thank you all the same. <3
What's Changed¶
- Replaced click_shell with new, purpose built REPL module
- Make WebUI Dependencies Optional
- Massively improve error reporting for discovery
- Refresh documentation with new features
1.0.1 - Bugfix release¶
Released July 29, 2025
It's been very nice to see other people enjoy Exosphere, and so here is a bugfix release to celebrate!
What's Changed¶
- Refactored the way tables are indexed in the TUI
- Resolved issue where host 'name' fields containing punctuation or starting with a digit would crash the UI on startup
- Improved error handling in logging initialization
- Normalized string loglevels to UPPERCASE, so "debug" is now valid, instead of just "DEBUG"
- Misc minor documentation touch ups
1.0 - Initial Public Release¶
Released July 26, 2025
First Public Release¶
I've been working on this tool for quite a while now, and I am feeling comfortable enough with the state it is in to release it in the wild. Hopefully it is helpful to others, because I quite enjoyed writing it, and I'm enjoying using it even more.
Initial Pre-Release¶
Released July 05, 2025
This initial build was pushed to PyPI as a preview, and to validate documentation and processes.
It probably isn't suitable for human consumption, but can be installed.
EXOSPHERE API REFERENCE¶
This section of the documentation covers internal APIs useful if you wish to rely on Exosphere as a library, or if you wish to implement a new package manager provider.
Exosphere configuration¶
The configuration module in Exosphere is wildly flexible, allowing you to essentially provide your configuration structure in any format you'd like.
At runtime, the effective, current configuration structure is accessible through exosphere.app_config, which will always contain (at the very least) the default values defined in the Configuration.DEFAULTS dict.
- class exosphere.config.Configuration
- Bases: dict
Hold configuration values for the application. Extends a native dict to store the global options section of the inventory toml file.
Has the following peculiarities vs a native dict:
- Has many from_* methods to populate itself from various sources such as environment variables, files of various formats
- Enforces a set of default values for the nested options dict
- Enforces unicity for name keys in the hosts dict.
- Has a deep_update() method to recursively update nested dicts without replacing them entirely.
- Is entirely self-validating and normalizing, using a pydantic schema to ensure the configuration is always in a valid state
This configuration structure is strongly inspired by the one used by Flask, because good things are worth replicating.
- DEFAULTS = {...}
- Default configuration values This dict contains the default configuration and is always used as a base for what the configuration object contains. This can be accessed to get the default values for any config key. It is derived directly from the OptionsModel schema.
- deep_update(d: dict, u: dict) -> dict
- Recursively update a dictionary with another dictionary. Ensures nested dicts are updated rather than replaced.
- from_env(prefix: str = 'EXOSPHERE_OPTIONS', parser: ~collections.abc.Callable[[str], ~typing.Any] = <function loads>) -> bool
- Populate the configuration structure from environment variables.
Any environment variable that starts with the specified prefix (e.g., EXOSPHERE_OPTIONS_*) will be considered for updating the configuration.
Note that this is, currently, limited to the options section of the configuration. The inventory cannot be updated this way.
If there are any nested dictionaries in the configuration, you can specify them using a double underscore (__) to separate the keys.
The values for the keys are parsed as JSON types by default, but you can specify a custom loader function to parse the values, as long as it operates on strings.
Invalid keys or values will be be ignored and logged as warnings, and nested dictionary keys will have their entire subtree dropped if any of the leaves are invalid.
- prefix -- The prefix to look for in environment variables
- parser -- A callable that takes a string and returns a parsed value
- Returns
- True if the configuration was successfully updated
- from_file(filepath: str, loader: Callable[[BinaryIO], dict], silent: bool = False) -> bool
- Populate the configuration structure from a file, with a specified loader
function callable.
The loader must be a reference to a callable that takes a file handle and returns a mapping of the data contained within.
For instance, tomllib.load() is a valid loader for toml files
This allows for the format of the configuration file to be essentially decoupled from the validation and internal representation of the data.
- filepath -- Path to the file to load
- loader -- A callable that takes a file handle and returns a dict
- silent -- If True, suppress IOError exceptions for missing files
- Returns
- True if the configuration was successfully updated
- from_json(filepath: str, silent: bool = False) -> bool
- Populate the configuration structure from a json file
This method is a convenience wrapper used for shorthand for the from_file method, with json.load() as the loader.
see from_file() for details.
- filepath -- Path to the json file to load
- silent -- If True, suppress IOError exceptions for missing files
- Returns
- True if the configuration was successfully updated, False if the file was not found
- from_toml(filepath: str, silent: bool = False) -> bool
- Populate the configuration structure from a toml file
This method is a convenience wrapper used for shorthand for the from_file method, with tomllib.load() as the loader.
see from_file() for details.
- filepath -- Path to the toml file to load
- silent -- If True, suppress IOError exceptions for missing files
- Returns
- True if the configuration was successfully updated, False if the file was not found
- from_yaml(filepath: str, silent: bool = False) -> bool
- Populate the configuration structure from a yaml file
This method is a convenience wrapper used for shorthand for the from_file method, with yaml.safe_load() as the loader.
see from_file() for details.
- filepath -- Path to the yaml file to load
- silent -- If True, suppress IOError exceptions for missing files
- Returns
- True if the configuration was successfully updated, False if the file was not found
- update_from_mapping(*mapping: dict, **kwargs: dict) -> bool
- Populate values like the native dict.update() method, but only if
the key is a valid root configuration key.
This will also deep merge the values from the mapping if they are also dicts.
This method is transactional: validation errors within the mapping will roll back any partial changes, guaranteeing that the configuration is always in a valid state.
- mapping -- A single mapping to update the configuration with
- kwargs -- Additional keyword arguments to update the configuration with
- Returns
- True if the configuration was successfully updated
Package Manager Provider API¶
This document provides an overview of the API used internally by Exosphere to implement package manager providers.
A package manager provider is a Python class that implements the low level API for a specific package manager. It is generally responsible for connecting to the host, querying available package updates, parsing that list and returning Update objects that can be used to populate state.
Implementing a new provider requires creating a new class under exosphere.providers that inherits from the base provider class exosphere.providers.api.PkgManager.
This class should implement the methods and members below.
Providers API
This module defines the abstract base class for package managers as well as helper functions and decorators to be used by package manager provider implementations.
- class exosphere.providers.api.PkgManager
- Bases: ABC
Abstract Base Class for Package Manager
Defines the interface for Package Manager implementations.
When implementing a Package Manager Provider, you should inherit from this class and implement the reposync and get_updates methods.
- Note
-
If either of the methods require elevated privileges, (i.e., they use cx.sudo() instead of cx.run()), you should decorate them with the @requires_sudo decorator.
- SUDOERS_COMMANDS: list[str] | None = None
- List of commands that require sudo privileges. This will be used by the CLI helper commands to generate the appropriate sudoers file entries.
SUDOERS_COMMANDS = [
"/usr/bin/apt-get update",
"/usr/bin/something-else --with-args -o option=value", ]
If you do not require elevated privileges at all, omit it entirely from your implementation or set it to None.
- bind_host(host_name: str) -> None
- Attach host context to this provider's logger.
- Parameters
- host_name -- Name of the host this provider instance serves.
- abstractmethod get_reboot_status(cx: Connection) -> bool | None
- Determine whether the host requires a reboot.
This method should be implemented by subclasses to detect a pending system reboot (for example following a kernel or libc update). It must be read-only and, like the other query methods, avoid elevated privileges wherever possible.
It should return a boolean corresponding the "has pending reboot" status of the host, or None if the status cannot be determined, or if the platform does not have a sensible signal for this information.
Implementations should avoid raising exceptions in failure cases, and prefer returning None instead. Exceptions should be reserved for genuine connection-level failures.
- Parameters
- cx -- Fabric Connection object
- Returns
- True if a reboot is required, False if not, None if unknown.
- abstractmethod get_updates(cx: Connection) -> list[Update <#exosphere.data.Update>]
- Get a list of available updates.
This method should be implemented by subclasses to provide the specific logic for retrieving updates for different package managers.
It is preferable if this can be done without the need for elevated privileges and remains read-only, as much as possible.
- Parameters
- cx -- Fabric Connection object
- Returns
- List of available updates as Update objects.
- abstractmethod reposync(cx: Connection) -> bool
- Synchronize the package repository.
This method should be implemented by subclasses to provide the specific synchronization logic for different package managers.
Some package managers may not require explicit synchronization, in which case this method can be a no-op that returns True.
If it is possible to perform the synchronization without elevated privileges, it is vastly preferable to do so.
- Parameters
- cx -- Fabric Connection object
- Returns
- True if synchronization is successful, False otherwise.
- exosphere.providers.api.requires_sudo(func: Callable) -> Callable
- Decorator to mark a function as requiring sudo privileges.
This decorator sets an attribute on the function to indicate that it requires sudo privileges to execute. You should add it to any method that requires elevated privileges, i.e. whenever you are using 'cx.sudo()' instead of 'cx.run()'.
Additionally, the decorator provides enhanced error handling for sudo related failures, presenting a clear message about sudo policies and sudoers configuration when an AuthFailure or related exception occurs.
Data Classes¶
The core objects used by Exosphere are mostly Host and Update objects.
Host is the high level object, providing functionality to interact with the host and perform operations on it, such as discovery or refreshing package updates.
The only mandatory fields for a Host are defined by the HostInfo dataclass, listed below.
- class exosphere.data.HostInfo(os: str, version: str | None, flavor: str | None, package_manager: str | None, is_supported: bool)
- Bases: object
Data class to hold platform information about a host. This includes the operating system, version, and package manager. Used for discovery and setup module results.
- class exosphere.data.Update(name: str, current_version: str | None, new_version: str, security: bool = False, source: str | None = None)
- Bases: object
Data class to hold information about a software update. Includes the name of the software, the current version, new version, and optionally a source.
- class exosphere.data.HostState(os: str | None, version: str | None, flavor: str | None, package_manager: str | None, supported: bool, online: bool, updates: tuple[Update <#exosphere.data.Update>, ...], last_refresh: datetime | None, needs_reboot: bool | None, schema_version: int = 2)
- Bases: object
Data class to hold the state of a host. Used mainly for serialization to disk.
Contains a schema_version field to help with compatibility checks when loading cache from an earlier version of exosphere.
It is not intended for this field to be specified directly, but instead to be incremented via its default value whenever the structure changes, to allow for easy migrations in load_or_create.
Updates list is stored as a tuple to ensure container immutability.
Exosphere objects¶
The primary low level objects used by Exosphere are Host and Inventory objects.
They provide the main functionality to interact with the hosts and perform operations on them.
- class exosphere.objects.Host(name: str, ip: str, port: int = 22, username: str | None = None, description: str | None = None, connect_timeout: int | None = None, sudo_policy: str | None = None, ssh_locale: str | None = None)
- Bases: object
Host object representing a remote system.
This object can be used to query the host for information, perform operations on it as well as manage its state.
The host will be marked as offline until the first discovery operation is performed. Errors in processing will update this status automatically.
- __init__(name: str, ip: str, port: int = 22, username: str | None = None, description: str | None = None, connect_timeout: int | None = None, sudo_policy: str | None = None, ssh_locale: str | None = None) -> None
- Create a new Host Object
Note: The parameters of the Host object can and will be affected by the process of reloading them from cache! See: exosphere.inventory.Inventory.load_or_create_host
Keep in mind the need to verify this process if you make changes to the constructor signature or default values.
- name -- Name of the host
- ip -- IP address or FQDN of the host
- port -- Port number for SSH connection (default is 22)
- username -- SSH username (optional, will use current if not provided)
- description -- Optional description for the host
- connect_timeout -- Connection timeout in seconds (optional)
- sudo_policy -- Sudo policy for package manager operations (skip, nopasswd)
- ssh_locale -- Locale forced on remote commands (optional, default is C)
- close(clear: bool = False) -> None
- Close the SSH connection if one exists.
Explicitly close the Connection object. Subsequent calls to connection property will recreate it if necessary.
This should be called when done with batch operations on the host or when cleaning up on exit.
You can use the clear parameter to also clear the internal connection object after closing it, if you want to ensure it is not reused.
- Parameters
- clear -- If True, sets the internal connection object to None after closing.
- property connection: Connection
- Establish a connection to the host using Fabric. This method sets up the
connection object for further operations.
Connection objects are recycled if already created.
The connection is setup with an environment override that forces two things on all commands run through it:
- 1.
- The locale is set to the configured value (default is C)
- 2.
- The command is explicitly ran under /bin/sh (POSIX)
This allows consistent, deterministic output and behavior, regardless of the user's login shell or locale.
If you work with Host objects directly, make sure to call host.close() when done with operations (such as discover, refresh_updates, etc) to avoid leaving ssh connections open.
If you don't, all connections will be closed automatically on program exit.
- Returns
- Fabric Connection object
- property connection_last_used: float | None
- Get the timestamp of the last use of the connection.
"last used" here is defined as the last time anything requested the Connection object through the property for this host.
Property access is thread-safe, and will reset the timestamp to None if the connection is no longer active.
- Returns
- Timestamp of last use in seconds since epoch, or None if connection has never been used.
- discover() -> None
- Synchronize host information with remote system. Attempts to detect the
platform details, such as operating system, version, flavor, and package
manager.
Online status is also updated in the process.
- from_state(state: HostState <#exosphere.data.HostState>) -> None
- Update the Host object from a HostState dataclass instance. Useful for loading state from disk or cache.
- Parameters
- state -- HostState instance to load state from
- property is_connected: bool
- Check if the host has an active SSH connection.
- Returns
- True if connection exists and is connected, False otherwise
- property is_stale: bool
- Check if the host is staled based on refresh timestamp
A host is considered stale if it has not been refreshed within the "stale_threshold" value in seconds set in the configuration. Default is 86400 seconds (24 hours).
- Returns
- True if the host is stale, False otherwise
- ping(raise_on_error: bool = False, close_connection: bool = True) -> bool
- Check if the host is reachable by executing a simple command.
Can optionally raise an exception, which will contain much deeper details about the connection failure.
As such, with raise_on_error set to True, ping() can be used to verify authentication and connectivity in general.
- raise_on_error -- Whether to raise an exception on failure
- close_connection -- Whether to close the connection after pinging. This has no effect if SSH pipelining is enabled, as the connection will be managed by the Reaper Thread.
- Returns
- True if the host is reachable, False otherwise
- refresh_updates() -> None
- Refresh the state of updates for the host. This method retrieves the list
of available updates and populates the updates attribute.
It also handles updating various host state attributes, such as the last refresh timestamp and pending reboot status.
- property security_updates: list[Update <#exosphere.data.Update>]
- Get a list of security updates available on the host.
- Returns
- List of security updates
- sync_repos() -> None
- Sync the package repositories on the host.
Will invoke the concrete package manager provider implementation associated during initial host sync.
This is the equivalent of your 'apt-get update' or similar
- to_dict() -> dict
- Convert the Host object to a dictionary representation. Useful for
serialization or reporting
Note: Only includes informational fields, does not include configuration or connection details.
Any datetime fields are represented as ISO 8601 strings in UTC. They explicitly follow what JavaScript's Date.toJSON() produces for maximum compatibility.
- Returns
- Dictionary representation of the Host object
- to_state() -> HostState <#exosphere.data.HostState>
- Convert the Host object to a HostState dataclass instance. Useful for serialization to disk or caching.
- Returns
- HostState instance representing the current state of the Host
- class exosphere.objects.HostOperation(*values)
- Bases: Enum
Operations that can be dispatched against a Host.
Each member's value is the name of a Host method, and doubles as the stable task identifier.
The label value is a human-readable name for the operation, suitable for display.
The modifies_state boolean indicates whether or not the operation modifies the local Host object state (e.g. anything that round trips through HostData from and to the cache). If the operation does not (for instance, syncing repositories), this should be set to False, which allows operations to skip the cache writeout steps after completion.
The requires_supported boolean indicates whether the operation can only run against a host on a supported platform. Host object level implementations check this and return before dispatching, but also documenting this here allows callers to pre-filter based on the operation type, instead of just going for it, which saves threads and potential false success/failure reports.
- class exosphere.inventory.Inventory(config: Configuration <#exosphere.config.Configuration>)
- Bases: object
Inventory and state management
Handles reading the inventory from file and creating the Host objects.
Also handles dispatching tasks to the Host objects, via a parallelized ThreadPoolExecutor.
Convenience methods for discovery, repo sync, updates refresh and ping are provided, and are all parallelized using Threads.
Runtime errors are generally non-fatal, but will be logged. The Host objects themselves usually handle their own failure cases and will log errors as appropriate, on top of flagging themselves as offline if they are unable to perform their tasks.
- clear_state() -> None
- Clear the current state of the inventory This will remove the cache file and re-init the inventory.
- close_all(clear: bool = False) -> None
- Close all SSH connections for all hosts in the inventory.
Invokes the close method on each Host object, closing the ssh connection if one exists.
It will be re-established on next request.
- Parameters
- clear -- If True, clears the connection object on each host after closing it by setting it to None.
- discover_all() -> None
- Discover all hosts in the inventory.
- filter_hosts(mode: FilterMode, hosts: list[Host <#exosphere.objects.Host>] | None = None) -> list[Host <#exosphere.objects.Host>]
- Filter hosts by the given FilterMode.
Operates on the provided list of hosts, or the entire inventory if none is given.
Returns a new list of hosts matching the filter.
- mode -- The FilterMode to apply
- hosts -- Optional list of hosts to filter, defaults to entire inventory
- Returns
- List of hosts matching the filter
- get_host(name: str) -> Host <#exosphere.objects.Host> | None
- Get a Host object by name from the inventory
If the host is not found, it returns None and logs an error message. If the inventory was properly loaded, there a unicity constraint on host names, so you can reasonably expect to not have to deal with duplicates.
- Parameters
- name -- The name of the host to retrieve, e.g. "webserver1"
- Returns
- The Host object if found, None otherwise
- init_all() -> None
- Setup the inventory by creating Host objects from the configuration.
Existing state will be cleared in the process.
- load_or_create_host(name: str, host_cfg: dict[str, Any], cache: DiskCache) -> Host <#exosphere.objects.Host>
- Attempt to load a host from the cache, or create a new one if that fails
in any meaningful way.
It will bind the host configuration parameters to the Host objects, which will already have been validated before they reach this point.
The new host's other configuration properties will be updated if they have changed from config since (i.e. ip address, port etc)
- name -- The name of the host to load or create
- host_cfg -- The configuration dictionary for the host
- cache -- The DiskCache instance to use for loading the host
- Returns
- An instance of Host
- ping_all() -> None
- Ping all hosts in the inventory.
This method will call the ping method on each Host object in the inventory and log whether each host is online or offline.
- refresh_updates_all() -> None
- Refresh the list of available updates on all hosts in the inventory.
This method will call the refresh_updates method on each Host object in the inventory.
- run_task(operation: HostOperation <#exosphere.objects.HostOperation>, hosts: list[Host <#exosphere.objects.Host>] | None = None) -> Generator[tuple[Host <#exosphere.objects.Host>, Any, Exception | None], None, None]
- Run an operation on specified hosts in the inventory. If none are
specified, run on all hosts.
Uses a ThreadPoolExecutor to run the operation's Host method concurrently, and returns a generator that can be safely iterated over to process the results as the tasks complete.
- operation -- The HostOperation to run on each host
- hosts -- Optional list of Host objects to run the operation on. If unspecified, runs on all hosts in the inventory.
- Returns
- A generator yielding tuples of (host, result, exception)
- save_state() -> None
- Save the current state of inventory hosts to the cache file.
- sort_hosts(by: SortField, hosts: list[Host <#exosphere.objects.Host>] | None = None, reverse: bool = False) -> list[Host <#exosphere.objects.Host>]
- Sort hosts by the given SortField.
Operates on the provided list of hosts, or the entire inventory if none is given.
The sort is stable, so hosts comparing equal retain their existing relative order (e.g. their order in the configuration file).
Sorting by SortField.VERSION is compound: hosts are grouped by flavor first, then ordered by a natural-sort of their version within each flavor, since version strings are not meaningfully comparable across different flavors.
Handling of hosts with placeholder/no data values is as follows
- All hosts can always be sorted by name and online status, since those are always known
- Undiscovered hosts have no platform data at all, so they sort last on every other data column
- Unsupported hosts report an OS but nothing else, so they sort normally by OS but last on every other data column
- Hosts with no data for a column are pinned to the bottom of the sort, regardless of desired order
- Unsupported hosts sort after Undiscovered, since the latter are considered actionable.
Returns a new list of hosts sorted by the given field.
- by -- The SortField to sort by
- hosts -- Optional list of hosts to sort; defaults to all hosts in the inventory
- reverse -- Whether to reverse the sort order
- Returns
- New list of hosts sorted by the given field
- sync_repos_all() -> None
- Sync the package repositories on all hosts in the inventory.
This method will call the sync_repos method on each Host object in the inventory.
Reporting Interfaces¶
The exosphere.reporting module provides interfaces for generating reports in various formats, including HTML, Markdown, and plain text. It leverages the Jinja2 templating engine.
It is also responsible for returning the JSON representation of Host objects.
Reporting module
This module provides functionality to render reports in various formats using Jinja2 templates.
- class exosphere.reporting.OutputFormat(*values)
- Bases: str, Enum
Available output formats for reports
- class exosphere.reporting.ReportRenderer
- Bases: object
Renders reports in various formats using Jinja2 templates.
The core of the reporting system, handles setup of the Jinja2 environment, loading templates, and rendering them with provided data.
- render_html(hosts: list[Host <#exosphere.objects.Host>], hosts_count: int, report_type: ReportType <#exosphere.reporting.ReportType>, report_scope: ReportScope <#exosphere.reporting.ReportScope>, navigation: bool = True, **kwargs: Any) -> str
- Render hosts data report as HTML.
- hosts -- List of Host objects to include in the report
- hosts_count -- Total number of hosts selected for the report
- navigation -- Whether to include the quick navigation section
- report_type -- Type of report (full, updates only, security only)
- report_scope -- Scope of the report (complete or filtered)
- kwargs -- Additional context variables for the template
- Returns
- Rendered HTML template string
- render_json(hosts: list[Host <#exosphere.objects.Host>], report_type: ReportType <#exosphere.reporting.ReportType>, **kwargs: Any) -> str
- Render hosts data report as JSON.
Does not involve any template, simply uses json.dumps on Host.to_dict() under the hood for the informational properties
Elides optional fields (like description) when empty/None for cleaner JSON. Discovery fields (os, flavor, etc.) are always present, null if undiscovered.
kwargs are accepted for interface consistency but ignored.
- hosts -- List of Host objects to include in the report
- report_type -- Type of report (full, updates only, security only)
- kwargs -- Additional context variables (not used in JSON rendering)
- Returns
- JSON string representation of the hosts data
- render_markdown(hosts: list[Host <#exosphere.objects.Host>], hosts_count: int, report_type: ReportType <#exosphere.reporting.ReportType>, report_scope: ReportScope <#exosphere.reporting.ReportScope>, **kwargs: Any) -> str
- Render hosts data report as Markdown.
- hosts -- List of Host objects to include in the report
- hosts_count -- Total number of hosts selected for the report
- report_scope -- Scope of the report (complete or filtered)
- report_type -- Type of report (full, updates only, security only)
- kwargs -- Additional context variables for the template
- Returns
- Rendered Markdown template string
- render_text(hosts: list[Host <#exosphere.objects.Host>], hosts_count: int, report_type: ReportType <#exosphere.reporting.ReportType>, report_scope: ReportScope <#exosphere.reporting.ReportScope>, **kwargs: Any) -> str
- Render hosts data report as plain text.
- hosts -- List of Host objects to include in the report
- hosts_count -- Total number of hosts selected for the report
- report_scope -- Scope of the report (complete or filtered)
- report_type -- Type of report (full, updates only, security only)
- kwargs -- Additional context variables for the template
- Returns
- Rendered plain text template string
- setup_jinja_environment(text: bool) -> Environment
- Setup Jinja2 environment with templates from the package.
Configures autoescaping, global functions, and custom filters.
- Parameters
- text -- Turns on trim_blocks and lstrip_blocks for text templates
- Returns
- Configured Jinja2 Environment
Author¶
Alexandre Gauthier
Copyright¶
2025, Alexandre Gauthier
| April 7, 2026 |