PACKAGING.md 8.7 KB

Packaging and install layout

moos runs from two layouts: a source checkout (what ./moos and ./moos-tui build and exec) and a packaged install (the relocatable tree tools/pack/pack.sh produces). One crate answers every path question for both, so a packaged run never guesses at a checkout and a source run never writes outside the repository.

What the packaged tree looks like

Linux tarball (moos-<version>-linux-<arch>/):

Path Contents
bin/moos desktop shell (GUI)
bin/moos-tui terminal UI
bin/moos-maker the daemon both UIs spawn
libexec/tor bundled Tor Expert Bundle binary
libexec/*.so* only the shared objects tor links — the expert bundle's pluggable_transports/ are left out (torrc policy is NoExec 1)
libexec/monero-wallet-rpc Monero wallet RPC sidecar
share/moos/webview.py WebKit2GTK window helper for the GUI
share/doc/moos/ README.md, AGENTS.md, docs/ (CONTRACT.md, METRICS.md, OPERATIONS.md, this file), LICENSE*

macOS ships the same pieces inside moos.app: binaries in Contents/MacOS/, everything else in Contents/Resources/ (libexec, moos/webview.py, doc/moos/).

Installing means unpacking that tree anywhere and running bin/moos-tui / bin/moos. A packaged install is mainnet-only, and there is no system-wide state: the identity, the swap wallet, the tor DataDirectory and per-run logs live under the user's data dir.

The desktop shell (bin/moos) additionally needs the GUI runtime on the host: python3 with PyGObject and the GTK 3 + WebKit2GTK 4.1 typelibs (Debian: python3-gi gir1.2-gtk-3.0 gir1.2-webkit2-4.1). The artifact ships only the webview.py helper. packaging/verify.sh prints a warning when they are missing; bin/moos then serves the UI headless instead of opening a window.

Where runtime state goes

What Packaged Source checkout
state root $MOOS_STATE_DIR, else $XDG_DATA_HOME/moos, else $HOME/.local/share/moos (macOS: ~/Library/Application Support/moos) same, with in-place reuse of an existing checkout dir (below)
identity (ETH key + swap wallet) <state>/identity/ <repo>/rundir-mainnet/identity/ if it exists, else <state>/identity/
tor root (DataDirectory, cookie, logs) <state>/tor/ <repo>/rundir-mainnet/tor/ if it exists, else <state>/tor/
per-run logs <state>/run/<network>/moos-<secs>-<pid>/ same

Funds safety: an existing source identity is reused in place, never copied or split. A packaged install never reads a checkout; if it has to mint a fresh identity it says so once, and the old one is not imported silently — move it yourself:

# The state root: $MOOS_STATE_DIR when set, else $XDG_DATA_HOME/moos, else
# $HOME/.local/share/moos. macOS: "$HOME/Library/Application Support/moos".
state="${MOOS_STATE_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/moos}"
mv <old>/rundir-mainnet/identity "$state/identity"   # same files, same keys

MOOS_MAINNET_IDENTITY_DIR relocates the identity for any layout (and is what lets two instances on one box run side by side).

Overrides

Every resolved path has an explicit override, checked before the bundled or checkout location:

Variable Chooses
MOOS_INSTALL_ROOT <root>/bin + <root>/libexec (tarball-style tree)
MOOS_SOURCE_ROOT the checkout to fall back to (debug binaries first)
MOOS_DAEMON_BIN moos-maker
MOOS_TOR_BIN tor
MOOS_MONERO_BIN monero-wallet-rpc
MOOS_TOR_DIR the tor root (a DataDirectory is single-writer)
MOOS_STATE_DIR the state root (must be absolute)

Diagnostics

bin/moos-tui --check-runtime

prints the resolved state root and each binary with its --version, and exits non-zero when anything is missing or cannot answer. Use it on a packaged install before trying to swap.

Assembling an install tree

The pipeline lives in packaging/; tools/pack/pack.sh only assembles. No artifact is published: this repository has no download path, so the tree below is for local use only. The mainnet SwapCreator address is baked (moos_core::contract::MAINNET_SWAPCREATOR) and the launch gate refuses it unless the code there matches the pinned runtime.

packaging/fetch.sh                 # download + verify sidecars (assets.lock)
packaging/build.sh                 # offline build, assemble, smoke-test
packaging/verify.sh dist/moos-*.tar.gz
Script Does
fetch.sh downloads the Tor Expert Bundle and Monero CLI listed in assets.lock, rejects any sha256 mismatch, extracts into packaging/assets/<platform>/ (host-runnable tor is executed once)
build.sh resolves packaging/assets/<platform>, then runs tools/pack/pack.sh
docker.sh the same build inside the pinned rust image (MOOS_DOCKER_IMAGE, default rust:1.85-bookworm); the tag is pinned but mutable, and the distro packages it apt-installs float with Debian. git gets a safe.directory entry for the root-owned bind mount
macos.sh fetches the macOS assets, builds moos.app, signs it when MOOS_CODESIGN_ID is set
appimage.sh wraps an assembled Linux stage into an AppImage (appimagetool required)
verify.sh runs an artifact's sidecars, --check-runtime, the packaged default (mainnet), and its README's relative links; requires all three shipped binaries to carry one clean rev; warns when the host lacks the GUI runtime (python3, GTK 3, WebKit2 4.1)

assets.lock is the only pinned-input list: platform, component, HTTPS URL, sha256. A version bump edits that file and re-runs verify.sh; nothing downloads implicitly during a build.

tools/pack/pack.sh --tor-bundle <dir> expects the extracted Expert Bundle root (the directory holding tor/tor plus its sibling libraries) and --monero-dir a directory holding monero-wallet-rpc; both are produced by fetch.sh. Binaries are built offline from engine/vendor with cargo build --offline --release -p moos -p moos-gui -p moos-daemon --bins (--no-build reuses them).

Before assembling, the script runs the bundled tor --version with only its sibling libraries on the loader path (the exact configuration the runtime creates with LD_LIBRARY_PATH / DYLD_LIBRARY_PATH), and after assembling it runs --check-runtime from the staged tree. Both must pass or nothing is written to dist/.

Before building, pack.sh re-verifies its sidecar inputs against assets.lock: the fetch cache archive is re-hashed against the lock, and every file the pack consumes (tor, the libraries beside it, monero-wallet-rpc, the license texts) must be byte-identical to the member of the same name inside that pinned archive. A mutated input tree or a missing cache refuses the pack loudly; pack.sh never downloads. Tarball modes are normalized — dirs 0755, files 0644, executables 0755 (the libexec objects ship executable: tor loads them as code) — so the bundle's upstream 0700 modes never leak into an artifact, and every tar entry is rooted (--owner=0 --group=0 --numeric-owner; bsdtar's --uid 0 --gid 0 on macOS), so the packager's identity never appears in the headers. Upstream license texts (LICENSE in the Monero tarball, the bundle's when present) are copied into share/doc/moos/; see packaging/licenses/README.md.

engine/vendor/ is build input only: a package never contains crate sources.

Differences between the two layouts

  • tor is bundled on Linux/macOS. A packaged install does not need a system tor; a source run uses the system tor if one is usable, and otherwise starts its own private user tor (no group/usermod setup).
  • No checkout writes. The package never writes under its own directory; logs, keys, wallets and chain data all live in the state root.

Pre-release gate

No download is produced: the escrow address is the missing input, and until a v3 deployment is published there is nothing to stage. The gate below is what a source release must pass; the tree it can assemble stays local.

git status --porcelain                                    # 1. clean tree
cd engine
cargo build --offline --bins                              # 2. build gate
cargo test --offline -p moos-core -p moos-daemon -p moos  # 2. test gate
# 3. soak per docs/OPERATIONS.md §5 (--direction=eth-to-xmr)
cd ..
git tag v0.1.1                                            # 4. tag
packaging/fetch.sh                                        # 5. sidecars
packaging/build.sh                                        # 5. build + pack
packaging/verify.sh dist/moos-*.tar.gz                    # 6. revs, links, sidecars
tar --numeric-owner -tvzf dist/moos-*.tar.gz | head       # 6. owners all 0/0
packaging/contract-verify.sh                              # 7. bytecode pins