A single cross-platform Rust application that installs and manages a complete
OpenC3 COSMOS environment. It launches a graphical control panel by default and
exposes the full openc3.sh command set on the command line for headless use.
The app provides these functions (see requirements.md):
- Install Docker — installs a working Docker / docker compose engine for the native platform if one is not already available.
- Install Python — installs an isolated Python runtime under the
python/subfolder (viauv). - Install COSMOS — downloads the OpenC3 COSMOS environment into the
cosmos/subfolder. - Launch & monitor — brings the COSMOS containers up with docker compose and continuously monitors their health.
- GUI — an Iced-based control panel, on by default, with a fully headless mode.
- CLI — command-line functionality equivalent to
openc3.sh. - Host interfaces (the "bridge") — supervises host-side Python
microservices that drive interfaces which must run on the host (serial, USB
HID, local-only TCP), tunneling raw device bytes to COSMOS over
Iroh. See
docs/bridge-architecture.md. - Self-update — checks GitHub for a newer app release and the COSMOS project for a newer COSMOS version, and can install either from the GUI.
Everything an install needs lives in subfolders of a single application root
(overridable with --root or OPENC3_COSMOS_APP_HOME):
<root>/
bin/ downloaded helper tools (uv, ...)
python/ isolated Python runtime + venv
cosmos/ COSMOS environment (compose.yaml, .env, support dirs)
bridge/ control-plane identity (identity.key, current.json)
host_files/ synced plugin code for host interfaces
microservices/ per-host-interface working dirs + venvs
openc3-cosmos-app-settings.json persisted GUI settings
openc3-cosmos-app.lock single-instance guard
The default root depends on how the app is run:
- Portable binary (a writable folder, e.g. unzipped next to the executable): the directory containing the executable — components sit beside the binary.
- Installed app (inside a macOS
.appbundle, or any read-only/system location like/Applications,Program Files,/usr): a per-user data directory, so installs never write into a code-signed/read-only bundle:- macOS:
~/Library/Application Support/OpenC3 - Windows:
%APPDATA%\OpenC3 - Linux:
$XDG_DATA_HOME/openc3(or~/.local/share/openc3)
- macOS:
cargo run(dev): the current working directory.
# First-time setup: install Docker, Python, and COSMOS
openc3 install all
# Or individually
openc3 install docker
openc3 install python
openc3 install cosmos --tag latest
# Lifecycle (equivalent to openc3.sh)
openc3 start # build (dev) + run
openc3 run # start containers (http://localhost:2900)
openc3 stop # graceful stop + down
openc3 restart
openc3 status # container health summary
openc3 logs -f
openc3 monitor # continuous headless health monitor
openc3 cleanup --force
# COSMOS CLI inside a container
openc3 cli generate plugin MyPlugin
openc3 cliroot validate myplugin.gem
# Utilities (encode, hash, save, load, tag, push, pull, clean)
openc3 util hash "my password"
openc3 util pull 7.0.0
# Host interfaces (the bridge)
openc3 microservices # run the host-interface supervisor (headless)
openc3 bridge-enroll <token> # pair with a remote COSMOS bridge
# Graphical control panel (also the default with no subcommand)
openc3 guiRun any command with --headless to suppress the GUI, or --enterprise to
treat the install as COSMOS Enterprise.
Launched by default (or with openc3 gui), the Iced control panel provides:
- Start / open / shutdown COSMOS with a live readiness state, plus a Container Status table (health, uptime, CPU/memory) read from the Docker socket.
- Bridge status — whether the host-interface bridge is paired and connected, with per-interface connection state and rx/tx byte counts.
- Settings — COSMOS URL, Core vs Enterprise edition (+ enterprise token),
run-locally and bridge toggles, and Development Mode (drive COSMOS from a
local source checkout at
latest). The bridge defaults off before COSMOS 7.4.0 and on for COSMOS 7.4.0 or newer. - Self-update — background checks (startup + every 8h) for a newer app release and a newer COSMOS version, each surfaced as an install prompt; a Check for updates now button covers both.
- System tray / menu-bar integration (Windows/macOS) — closing the window hides to the tray; the app runs as a single instance. On Linux (no tray) closing prompts to confirm.
All building happens inside Docker, so the only host requirement is Docker.
# Build release executables for every supported platform into ./dist/
./build.sh
# Build specific targets
./build.sh x86_64-unknown-linux-gnu aarch64-apple-darwinSupported targets:
| Platform | Targets | Toolchain |
|---|---|---|
| Linux | x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu |
cargo-zigbuild |
| Windows | x86_64-pc-windows-gnu |
cargo-zigbuild |
| macOS | aarch64-apple-darwin |
cargo-zigbuild + macOS SDK |
(Windows uses the GNU ABI so cargo-zigbuild can compile the C/assembly in
transitive dependencies such as ring, which the Iroh bridge pulls in.)
macOS targets require a macOS SDK (which cannot be redistributed in the image).
Provide one with MACOS_SDK:
MACOS_SDK=/path/to/MacOSX.sdk ./build.sh aarch64-apple-darwinNative installers are built for the host OS and architecture (a .dmg needs
macOS, an .msi/.exe needs Windows, .deb/AppImage need Linux), using
cargo-packager. Output
lands in dist/installers/.
# macOS / Linux
./package.sh# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -File .\package.ps1| Host | Produces |
|---|---|
| macOS | OpenC3 COSMOS.app + OpenC3 COSMOS_<ver>_<arch>.dmg |
| Linux | .deb, .AppImage |
| Windows | .msi (WiX) and/or .exe (NSIS) |
The architecture matches the build host (e.g. aarch64 on Apple Silicon). To
produce Linux installers from a non-Linux host, run ./package.sh inside a
Linux container. Installer metadata (product name, identifier, etc.) lives under
[package.metadata.packager] in Cargo.toml.
The GUI (winit) loads libxkbcommon at runtime via dlopen for keyboard
handling on X11/Wayland. The .deb declares it as a dependency and the AppImage
bundles it, so installed packages work out of the box. The raw ./dist
binary, however, has no packaging layer — on a minimal image that doesn't
already ship libxkbcommon (e.g. some cloud GUI AMIs) the GUI won't start until
you install it:
sudo apt install libxkbcommon0 libxkbcommon-x11-0This only affects the GUI; CLI/headless use (--headless, openc3 run, etc.)
never needs it.
For quick iteration on the host (requires a Rust toolchain):
cargo run # launch the GUI
cargo run -- status # run a CLI command
cargo build --no-default-features # smaller headless-only binaryNative installers are built by the .github/workflows/openc3-cosmos-app-release.yml
workflow. Running it via workflow_dispatch produces installers as artifacts;
pushing a v<semver> tag (matching version in Cargo.toml) additionally
attaches them to a GitHub Release. The app's self-update compares that tag
against its compiled-in CARGO_PKG_VERSION.
See LICENSE.md — the OpenC3 Builder's License, or a commercial
license if purchased from OpenC3, Inc.