A portable, modular shell environment and developer-tooling framework for local-first development.
Mantle gives you a user-owned shell runtime, an extensible mantle CLI, and reusable installer primitives that keep workstation setup deterministic, portable, and explicit across local development, containers, and CI.
Overview Β· Project status Β· Features Β· Supported environments Β· Quick start Β· Release lifecycle Β· CLI usage Β· Configuration Β· Architecture Β· Testing Β· Contributing
Mantle is a shell-first environment framework for people who want their development environment to be portable, inspectable, and owned by the user instead of hidden behind machine-specific bootstrap scripts.
Today, Mantle is composed of five main surfaces:
- A public
.shellrcentrypoint for Bash and Zsh. - A native Fish runtime entrypoint at
runtime/shells/fish/runtime.fish. - Shared libraries and modules that establish XDG, privacy, PATH, history, and platform behavior.
- A public
mantleCLI inbin/mantle. - Private command and installer implementations under
libexec/mantle/.
That separation matters: runtime initialization configures the current shell session, reusable libraries provide the foundations, the mantle CLI is the supported command-line interface, and libexec/ remains an internal implementation detail.
Mantle is local-first and repository-owned. Startup is designed to stay deterministic, quiet, and free from implicit network access, privileged operations, or unverified remote-script execution.
Mantle is an actively developed project with a real CLI, runtime modules, platform adapters, and a multi-layer test suite. It is not yet presented here as a general-purpose production-ready shell distribution.
- Bash and Zsh initialization through the repository-level
.shellrc. - Native Fish runtime loading through
runtime/shells/fish/runtime.fish. - Portable shared/runtime bootstrapping, XDG directory management, privacy defaults, PATH construction, and interactive history policy.
- Public
mantle help,mantle version, andmantle installcommand surfaces. - Read-only
mantle storageinspection for disk capacity, directory sizes, large files, and local repository/object/LFS storage, with human and JSON output. - Filtered
mantle archiveproject snapshots with dry-run manifests, explicit file exceptions, reproducible output, and no-overwrite publication. - Explicit runtime profiles and a validated command capability catalog, with
minimal
core,container, andcistartup options. - Literal typed configuration with value provenance, allowlisted environment inspection, installation/PATH inspection, and generated shell completions.
- Resilient
mantle hls-downloadmedia downloads with redacted signed-CDN diagnostics, explicit request compatibility controls, and validated output. - Dynamic installer discovery and tested dry-run/help flows for representative installers such as
eza,shfmt,shdoc,pyenv,linuxbrew, andtalisman. - CI-backed validation on Linux and macOS, plus static validation for shell syntax, ShellCheck, and formatting when local tools are available.
- A governed Identity v1 Brand Kit with reproducible tokens, guidance, metadata, social preview, and accessible repository-banner variants.
- Windows support is currently limited to Unix-compatible environments such as MSYS2 and Git Bash through
platforms/windows/runtime.sh; native PowerShell is out of scope. - Fish support has a native runtime, but its entrypoint differs from the Bash/Zsh
.shellrcflow and requires explicitMANTLE_ROOTconfiguration. - Some optional policies, such as automatic update-check suppression and project-local PATH injection, are opt-in by environment variable.
- Broader platform validation coverage, especially around Windows environments.
- A first tagged release has not yet been published. The signed-release workflow,
deterministic source package, and verification guide are ready for the first
v*tag. - Additional documentation depth.
- Public
.shellrcentrypoint that must be sourced, not executed. - Idempotent initialization with explicit
initialized,initializing, andfailedstates. - Separate loading phases for shared runtime, POSIX baseline, active-shell runtime, modules, and platform adapters.
- Interactive-only loading for aliases and history behavior.
- Native Fish runtime with its own functions, completions, and
conf.dfragments. - Shared profile definitions for
core,interactive,workstation,container,ci, andfull;workstationpreserves the default behavior.
- XDG-compliant config, cache, data, state, and runtime directory defaults.
- Deterministic PATH construction that prefers user-owned tool directories and Mantle's own
bin/. - Optional project-local PATH support gated behind
MANTLE_ENABLE_PROJECT_PATH=1. - Privacy-conscious defaults that disable telemetry for many supported tools by default.
- Separately configurable automatic update-check suppression.
Existing application state is preserved rather than silently moved into XDG
directories. config/xdg-exceptions.tsv records
compatibility exceptions and explicit migration limits.
Profiles with the tooling capability (workstation and full) configure
RubyGems through one explicit Mantle contract:
GEM_HOMEdefaults to"$XDG_DATA_HOME/gem"when you have not already set it.GEM_SPEC_CACHEdefaults to"$XDG_CACHE_HOME/gem/specs".- If
GEM_PATHis unset and an activegemcommand is available, Mantle asks that RubyGems installation forgem env pathafter applyingGEM_HOME, then exports the resulting value asGEM_PATH. This keeps the active Ruby's default and system gem locations visible instead of replacing them withGEM_HOMEalone. "$GEM_HOME/bin"is added once to Mantle's deterministicPATHconstruction even before that directory exists, so a gem executable installed later in the same shell becomes discoverable without manualPATHrepair.- If you already set
GEM_HOME,GEM_PATH, orGEM_SPEC_CACHE, Mantle preserves those values rather than guessing a safer override. The exception is safety validation around path projection: a relativeGEM_HOMEis preserved but not copied into derivedGEM_PATHorPATH; Mantle warns instead of inventing precedence for a non-absolute gem home. - Mantle does not choose or initialize a Ruby version manager for you. System Ruby, Homebrew Ruby,
asdf,rbenv, andmiseremain responsible for selecting the activeruby/gem; Mantle only derivesGEM_PATHfrom whichevergemis already active. If no activegemcommand is available, Mantle leavesGEM_PATHunset and warns when Ruby-manager hints are present. - Bundler remains project-specific. Mantle only sets user-scoped defaults such as
BUNDLE_USER_CONFIG,BUNDLE_USER_PLUGIN, andBUNDLE_USER_CACHE; it does not rewrite a repositoryGemfile,bundle execworkflow, or local binstubs.
- Public
mantledispatcher with validated command-name routing. - Dynamic help output from executable command implementations.
- Installer discovery from
libexec/mantle/installers/without maintaining a duplicate hard-coded list. - Locked installer resolution and
mantle install --assurancediagnostics, with native package-manager limits recorded explicitly. - Dry-run support for installers that surfaces the planned download, version, asset, and destination.
- Reusable install primitives under
lib/install/for archive, checksum, GitHub release, filesystem, and platform tasks.
- Transactional module loader with cycle detection and retryable failed loads.
- Opt-in extension loader for optional libraries in
lib/extensions/. - Current shipped extensions for fonts, GitHub helpers, and Wget workflows.
| Environment | Status | Runtime | Notes |
|---|---|---|---|
| Bash | Supported | .shellrc |
Public entrypoint; tested locally and in CI. |
| Zsh | Supported | .shellrc |
Public entrypoint; tested locally and in CI when Zsh is available. |
| Fish | Supported with separate entrypoint | runtime/shells/fish/runtime.fish |
Requires explicit MANTLE_ROOT; does not use .shellrc. |
| POSIX shell | Baseline/shared support | runtime/shells/posix/runtime.sh |
Shared layer loaded before shell-specific runtime; not a standalone public entrypoint here. |
| Linux | Supported | platforms/linux/runtime.sh |
Covered by CI and used for Linux/WSL detection. |
| macOS | Supported | platforms/darwin/runtime.sh |
Covered by CI; intended for Apple Silicon and Intel. |
| Windows / MSYS2 / Git Bash | Experimental | platforms/windows/runtime.sh |
Minimal Unix-compatible adapter only; native PowerShell is out of scope. |
| WSL | Supported through Linux adapter | platforms/linux/runtime.sh |
Runtime environment can classify WSL; platform adapter normalizes to Linux. |
- Git
- Bash, Zsh, or Fish
- Python 3.9+ for storage inspection, project archives, profile/catalog inspection and validation, HLS downloads, and building release archives (not needed to install Mantle or initialize the shell)
- FFmpeg/ffprobe with HLS segment retry support (FFmpeg 6.1+) for HLS downloads
- Optional: Bats, ShellCheck, and shfmt for local validation
The repository-root installer keeps Mantle in a user-owned prefix and can manage
Bash, Zsh, and Fish activation for you. It targets Bash 3.2+ so it can run with
the stock /bin/bash on macOS.
./install.sh
./install.sh --dry-run
./install.sh --status
./install.sh --doctor
./install.sh --disable --shell bash
./install.sh --uninstallUseful installer options:
--method copyis the safe default;--method symlinkis the explicit development mode.--prefix "/custom/path"installs into a custom user-owned location.--shell bash|zsh|fish|allchooses which startup files are managed.--no-shell-hookis the non-mutating activation opt-out for CI and containers.--environment-diffprints the environment delta without mutating the parent shell.--pin VERSIONverifies that a downloaded release archive is exactly the expected version.--update --pin VERSIONatomically replaces an existing installer-owned prefix while leaving its activation hooks unchanged.
git clone "https://github.com/egohygiene/mantle.git"
cd "mantle"
source "./.shellrc"That flow is non-destructive: it initializes Mantle for the current shell session without overwriting your existing shell configuration.
mantle help
mantle version
mantle install --listFor Fish, set MANTLE_ROOT to the absolute path of your clone and source the native runtime:
set -gx MANTLE_ROOT (pwd)
source "./runtime/shells/fish/runtime.fish"- For the current shell: start a new shell session without sourcing Mantle.
- For persistent dotfiles: remove or comment out the line that sources Mantle from your personal shell configuration.
Mantle does not require replacing your existing shell startup files, and this README does not recommend editing them until you decide how you want to integrate it locally.
For production or Realm consumption, install an exact signed release archive rather than a mutable Git branch. The release guide covers checksum, Sigstore, and provenance verification plus pinned install, update, doctor, disable, enable, uninstall, rollback, and devcontainer paths.
See the release and recovery guide.
The supported public interface is bin/mantle, usually invoked as mantle after initialization or by running ./bin/mantle from the repository.
mantleresolves its own executable path.- It derives
MANTLE_ROOTfrom that path. - If
MANTLE_ROOTis already set, it must match the resolved installation root or the command exits with an error. - An installer-managed symlink prefix is also valid when its dispatcher resolves to the exact same executable; another checkout remains rejected.
- It dispatches only validated public commands from
libexec/mantle/commands/. - Internal scripts under
libexec/are implementation details, not the normal user interface.
mantle help
mantle help install
mantle version
mantle version --short
mantle doctor
mantle storage directory
mantle storage large-files . --limit 10
mantle storage repo . --json
mantle archive . --dry-run
mantle archive . --output "../project.tar.gz" --reproducible
mantle profiles list
mantle profiles show ci --json
mantle catalog validate
mantle config show
mantle config explain history
mantle env
mantle path --entries
mantle completion bash
mantle hls-download "$HLS_URL" --output "episode.mkv"
mantle hls-download "$HLS_URL" --diagnose
mantle install --help
mantle install --list
mantle install eza --help
mantle install talisman --dry-runmantle helplists executable public commands dynamically.mantle help <command>delegates to the command's own--helpoutput.mantle versionprintsmantle <version>.mantle version --shortprints only the resolved version identifier.- Version resolution prefers
MANTLE_VERSION, thenVERSION, then Git metadata, thendevelopment. mantle doctorvalidates the installed payload and runs the isolated shell diagnostics without editing a startup file.
mantle install --listprints one discovered installer name per line fromlibexec/mantle/installers/.mantle install --assurance [TOOL]reports the checked-in resolution and integrity boundary. See installer assurance.mantle install TOOL [INSTALLER_OPTIONS]forwards installer-specific options unchanged.- Dry-run support is installer-specific; for
talisman,--dry-runprints the planned version, asset, URL, archive format, and destination instead of performing an install. - Invalid command names and unknown global options exit with status
64, and non-executable internal command implementations exit with status70.
Installer destinations are configurable per installer where supported. For example, installers may expose flags such as --install-dir, --destination, --target, --ref, or tool-specific home-directory options.
mantle env prints only named public Mantle/XDG state inherited by the command;
it never dumps the complete process environment. --shell emits safely quoted
Bash-compatible exports. Shell-local functions and unexported initialization
state are not reconstructed by an external command.
mantle path --root, --bin, and --entries inspect installation paths and the
current executable search path without modifying them. mantle completion bash|zsh|fish generates native completion definitions from the installed
command/installer inventory. Regenerate definitions after that inventory changes.
git-delete-gone-branches previews local branches whose configured upstream is
gone. Its explicit --apply deletes only eligible merged branches and protects
checked-out worktrees. --fetch is a separate opt-in that updates remote refs
even during a deletion dry run; nothing fetches automatically.
mantle storage disk|directory|repo|objects|large-files [PATH] provides local,
read-only measurements with a shared --json output contract. It distinguishes
apparent file sizes from allocated storage, skips links and scan boundaries, and
reports partial results explicitly. Python 3.9+ is required only when inspecting
storage. Repository commands inspect the local Git layout without running Git
or Git LFS. See the
storage command and output contract for accounting rules,
boundaries, and examples.
mantle archive [PATH] --dry-run previews a filtered source snapshot. Use an
explicit --output destination without --dry-run to create an archive; existing files
are never overwritten. Git state and common credential/dependency/cache/build
filters govern selection, and exact-file --include exceptions remain subject
to path and filesystem boundaries. --json exposes the manifest and
--reproducible normalizes archive metadata. See the
archive command contract for defaults, exceptions, and examples.
mantle hls-download URL (also hls-download URL) defaults to an MKV
stream-copy download. MP4/TS, H.264/AAC transcoding, live capture, request-header
files, opt-in query inheritance, and Range compatibility are explicit options.
The command keeps signed request data out of its logs and FFmpeg arguments,
detects failed required resources, and publishes only after ffprobe validation.
See the HLS download contract for diagnostics, retries,
credential handling, interruption, and the ordinary AES-128/DRM boundary.
Set a profile before activation to choose the shell capabilities you need:
export MANTLE_PROFILE="ci"
source "/path/to/mantle/.shellrc"workstation is the compatibility default. core, container, and ci load
the portable foundation without workstation tooling or interactive setup.
interactive adds shell ergonomics, and full combines all shipped profile
capabilities. Start a new shell to change an initialized profile.
See runtime profiles and the command catalog for the profile
matrix, canonical lifecycle, Fish examples, extension rules, shell/platform
support, and Realm/CI ownership boundaries. Profile metadata does not hide or
rename commands in the existing flat bin/ namespace.
An optional "$XDG_CONFIG_HOME/mantle/config.conf" (defaulting to
"$HOME/.config/mantle/config.conf") selects typed policy without executing
shell code. Set MANTLE_CONFIG_FILE to an explicit absolute path when needed.
The file is not created automatically. Start from
config/example.conf:
schema_version=1
profile=workstation
history=true
presentation=share-safe
Precedence is profile defaults, then the literal file, then explicit environment
overrides. The six existing profiles and their capability graph remain intact;
settings cannot add workstation capabilities to core or ci. Unknown or
duplicate keys, invalid values, unsupported schemas, and malformed files fail
validation rather than being sourced as a script. An explicitly selected
missing file also fails; an absent default file preserves existing behavior.
mantle config list-profiles
mantle config path
mantle config validate "./config/example.conf"
mantle config show
mantle config explain historyconfig/settings.tsv defines supported policy keys,
environment overrides, and applicability. Setting groups cover aliases,
history, explicit update-check suppression, and presentation. Experimental
behavior is reserved and enabling it is rejected before initialization.
config list-profiles reports the original graph without Python;
the separate profiles/catalog JSON inspection commands retain their existing
Python dependency. Change a selected runtime profile in a new shell.
Interactive profiles preserve the historical alias corpus by default. Focused
alias-group flags select additional helpers; setting one to false does not
remove helpers supplied by that corpus. To use only selected groups, set
aliases.legacy=false before enabling the desired aliases.safe,
aliases.network, aliases.system, or aliases.safety groups. Existing
user-defined aliases are outside this configuration's scope.
Mantle stays quiet by default. To enable its bundled, offline Fastfetch dashboard, set these variables before the existing Mantle activation line in your Bash/Zsh startup file:
export MANTLE_STARTUP_DISPLAY="1"
export MANTLE_STARTUP_BANNER="0"For Fish, put the equivalent settings before sourcing Mantle's native runtime:
set -gx MANTLE_STARTUP_DISPLAY 1
set -gx MANTLE_STARTUP_BANNER 0The existing activation hook handles presentation; no display logic needs to be
copied into a dotfile. Bash/Zsh invoke the shared mantle startup command after
successful initialization. Fish invokes it through the native fish_greeting.
The inherited session guard prevents repeated sourcing and nested shells from
printing the dashboard again. CI, redirected input/output, noninteractive shells,
and TERM=dumb remain silent and do not consume that guard.
The bundled profile uses the original Incompris wordmark on recognized iTerm and Kitty image terminals, with a plain-text Incompris fallback elsewhere. Optional presentation settings are:
| Variable | Default | Purpose |
|---|---|---|
MANTLE_STARTUP_DISPLAY |
0 |
Global opt-in; 0 disables all automatic presentation. |
MANTLE_STARTUP_BANNER |
1 |
Include the short text banner; set 0 for just Fastfetch. |
MANTLE_STARTUP_FASTFETCH |
1 |
Include Fastfetch when installed. |
MANTLE_STARTUP_TIMEOUT_SECONDS |
3 |
Total display deadline, an integer from 1 to 30 seconds. |
MANTLE_STARTUP_DIAGNOSTICS |
0 |
Report component statuses and elapsed seconds, without raw tool errors. |
MANTLE_BANNER_FILE |
Bundled text fallback | Select a trusted text/ANSI banner. |
MANTLE_FASTFETCH_CONFIG |
Existing XDG config, then bundled profile | Select a readable Fastfetch configuration. |
MANTLE_FASTFETCH_LOGO |
Profile/terminal-dependent | Select a readable logo file without changing its bytes. |
MANTLE_FASTFETCH_LOGO_TYPE |
auto |
Explicit image protocol such as iterm, kitty-direct, or chafa, or text file. |
Fastfetch is optional and is never installed during startup. Existing
$XDG_CONFIG_HOME/fastfetch/config.jsonc (then config.json) is respected, and
its logo is preserved unless explicitly overridden. Custom profiles are trusted
user configuration: their command/network modules are outside the bundled
profile's offline guarantee. Mantle never evaluates a configuration as shell
code, and logo paths are passed through quoted environment expansion to avoid
interpreting filename metacharacters in Fastfetch's path expansion.
Use mantle startup --diagnostics to inspect an enabled display from a terminal.
To redisplay after automatic startup, run unset MANTLE_STARTUP_SHOWN first
(set --erase MANTLE_STARTUP_SHOWN in Fish). This does not reinitialize Mantle.
Missing tools, failed optional components, and timeouts never fail shell
initialization. The deadline cleans up renderer descendants and restores cursor,
color, and line wrapping when a renderer is interrupted.
Presentation policy adds private, share-safe, ci, and off modes while
retaining the explicit display opt-in. share-safe limits automatic output to
the bundled static text and does not run Fastfetch or custom display inputs;
ci and off suppress it. See the presentation contract.
The bundled Fastfetch configuration targets 2.67.0 and groups session,
system, hardware, local network, development, and media information. It uses
short fixed keys and 12-column progress bars. Its four /bin/sh command modules
call mantle fastfetch runtime, workspace, toolchains, and contexts.
These collectors query local state only; tool probes are time-bounded and context
hints do not contact Docker, Kubernetes, or cloud services.
For narrow terminals, reduce the logo width or optional modules in your own
profile. Nerd Font icons, terminal image support, and color are enhancements;
text keys and the text logo remain usable without them. For a plain font, set
display.key.type to string and use a plain separator in a custom profile.
Workspace, local network, and media rows can expose personal context: disable
those modules in a shareable profile before recording your terminal.
Environment variables remain explicit overrides for the literal configuration contract. The table below focuses on public or user-relevant runtime controls.
| Variable | Default | Purpose | Example |
|---|---|---|---|
MANTLE_ROOT |
Resolved from the entrypoint or CLI | Absolute path to the Mantle installation root | export MANTLE_ROOT="$HOME/src/mantle" |
MANTLE_PROFILE |
workstation |
Selects runtime capabilities before initialization | export MANTLE_PROFILE="ci" |
MANTLE_CONFIG_FILE |
XDG Mantle config path | Selects an existing absolute literal configuration path | export MANTLE_CONFIG_FILE="$HOME/.config/mantle/config.conf" |
MANTLE_EXTENSIONS |
Empty | Explicit colon-separated optional extension selection for Bash/Zsh | export MANTLE_EXTENSIONS="github:wget" |
MANTLE_SHELL_NAME |
Detected (bash, zsh, fish) |
Active shell runtime identifier | export MANTLE_SHELL_NAME="bash" |
MANTLE_INTERACTIVE |
Detected from the current shell | Distinguishes interactive and noninteractive initialization | export MANTLE_INTERACTIVE="1" |
MANTLE_DISABLE_TELEMETRY |
1 |
Enables Mantle's telemetry opt-out defaults when set to 1 |
export MANTLE_DISABLE_TELEMETRY="1" |
MANTLE_DISABLE_AUTOMATIC_UPDATE_CHECKS |
0 |
Opts into the update-check suppression module | export MANTLE_DISABLE_AUTOMATIC_UPDATE_CHECKS="1" |
MANTLE_ENABLE_PROJECT_PATH |
0 |
Prepends "$PWD/bin" and "$PWD/node_modules/.bin" when enabled |
export MANTLE_ENABLE_PROJECT_PATH="1" |
MANTLE_CREATE_XDG_DIRECTORIES |
1 |
Creates missing XDG directories and XDG_BIN_HOME |
export MANTLE_CREATE_XDG_DIRECTORIES="0" |
MANTLE_HISTORY_SIZE |
50000 |
Controls interactive shell and REPL history sizing | export MANTLE_HISTORY_SIZE="100000" |
MANTLE_DEBUG |
0 |
Enables additional debug logging and loader diagnostics | export MANTLE_DEBUG="1" |
XDG_CONFIG_HOME |
"$HOME/.config" |
XDG config root | export XDG_CONFIG_HOME="$HOME/.config" |
XDG_CACHE_HOME |
"$HOME/.cache" |
XDG cache root | export XDG_CACHE_HOME="$HOME/.cache" |
XDG_DATA_HOME |
"$HOME/.local/share" |
XDG data root and default base for many managed tool directories | export XDG_DATA_HOME="$HOME/.local/share" |
XDG_STATE_HOME |
"$HOME/.local/state" |
XDG state root, including history storage | export XDG_STATE_HOME="$HOME/.local/state" |
XDG_RUNTIME_DIR |
Platform-specific secure fallback | Private runtime directory for transient state | export XDG_RUNTIME_DIR="/run/user/1000" |
XDG_BIN_HOME |
"$HOME/.local/bin" |
User-owned executable destination added to PATH | export XDG_BIN_HOME="$HOME/.local/bin" |
TALISMAN_HOME |
"$XDG_DATA_HOME/talisman" |
Example installer destination override for talisman |
export TALISMAN_HOME="$HOME/.local/share/talisman" |
MANTLE_GITHUB_CONNECT_TIMEOUT |
10 |
Optional GitHub extension request connect timeout | export MANTLE_GITHUB_CONNECT_TIMEOUT="5" |
MANTLE_GITHUB_REQUEST_TIMEOUT |
30 |
Optional GitHub extension request total timeout | export MANTLE_GITHUB_REQUEST_TIMEOUT="15" |
Notes:
- Many other exported variables in
modules/tooling.sh,modules/privacy.sh, andmodules/history.share downstream tool settings rather than Mantle-specific controls. - Variables such as
MANTLE_INITIALIZATION_STATE,MANTLE_LAST_ERROR_STATUS,MANTLE_LOADED_MODULES, and loader sentinels are internal runtime state and should not be treated as stable configuration APIs.
Read ARCHITECTURE.md for component ownership, source-time dependency direction, native shell entrypoints, and command/publication boundaries. PROVENANCE.md records the immutable Empathy source lineage and retained license, artwork, and generated-material notices.
.
βββ .shellrc
βββ bin/
β βββ mantle
βββ init/
β βββ bootstrap.sh
β βββ init.sh
β βββ load-core.sh
β βββ load-extensions.sh
β βββ load-platform-runtime.sh
βββ lib/
β βββ core/
β βββ extensions/
βββ libexec/
β βββ mantle/
β βββ commands/
β βββ installers/
βββ modules/
βββ platforms/
β βββ darwin/
β βββ linux/
β βββ windows/
βββ runtime/
β βββ shared/
β βββ shells/
βββ tests/
/.shellrcβ public Bash/Zsh entrypoint./bin/mantleβ public CLI dispatcher./init/β initialization orchestration and loader boundaries./lib/core/β reusable shell libraries for detection, guards, logging, time, colors, and Bash helpers./lib/config/β literal typed settings, profile defaults, precedence, and value provenance./lib/extensions/β optional libraries loaded explicitly throughmantle_load_extension./modules/β runtime policies for XDG, privacy, tooling, PATH, cache, aliases, history, and update checks./platforms/β OS-specific adapters loaded after portable modules./runtime/shared/and/runtime/shells/β shared and shell-specific runtime behavior./libexec/mantle/commands/β supported public command implementations./libexec/mantle/installers/β private installer entrypoints discovered bymantle install./tests/β unit, integration, contract, and static validation harnesses.
mantle install talisman
β
βΌ
bin/mantle
β
βΌ
libexec/mantle/commands/install.sh
β
βΌ
libexec/mantle/installers/talisman.sh
β
βΌ
lib/install/
At a high level, Mantle initialization follows this sequence:
- The public
.shellrcentrypoint is sourced. - Mantle resolves
MANTLE_ROOTfrom the source path and classifies the current shell as interactive or noninteractive. init/init.shresolves the selected runtime profile, then loads core libraries and runtimes throughinit/load-core.sh.init/load-extensions.shdefines the opt-in extension loader.lib/modules.shdefines the transactional module loader.init/bootstrap.shselects noninteractive modules from the canonical orderxdg,privacy,cache,tooling,environment;cacheandtoolingrequire thetoolingcapability.- The platform adapter is loaded through
init/load-platform-runtime.sh. - Explicitly selected optional extensions load, followed by
aliasesandhistorywhen the profile permits interactive behavior and the shell is interactive. - If everything succeeds,
.shellrcrecordsMANTLE_INITIALIZATION_STATE=initialized.
Operational guarantees from the current implementation:
- Initialization is idempotent for the selected profile; a different profile requires a new shell.
- Recursive initialization is rejected with an error.
- Failed loads remain retryable; Mantle records a failed state instead of pretending initialization succeeded.
- Extensions are opt-in and are sourced at most once after a successful load.
- Startup does not install software, prompt for privilege escalation, or perform network access by default.
Use the public mantle install interface rather than invoking scripts in libexec/mantle/installers/ directly.
mantle install --list
mantle install eza --help
mantle install shfmt --helpmantle install talisman --dry-runFor validated installers such as talisman, dry-run reports the planned tool name, version, download URL, archive format, and install destination without mutating the system.
- Installer-specific help is implemented by each installer script.
- Some installers support version or ref selection with flags such as
--versionor--ref. - Destination control is installer-specific and may use flags such as
--install-dir,--destination,--target, or dedicated tool-home variables. - Installers are tested to avoid silent
sudousage. - Mantle ships reusable install libraries under
lib/install/for archive extraction, GitHub release metadata, checksums, and filesystem operations.
Because the installer set is discovered dynamically from libexec/mantle/installers/, the canonical way to see the current catalog is:
mantle install --listMantle's extension model is explicit and opt-in. The default selection is empty.
Set MANTLE_EXTENSIONS="github:wget" before Bash/Zsh activation to load selected
libraries after the platform runtime, or call the existing loader directly.
Fish reports requested Bash extensions as unsupported. See the
extension selection contract.
Current extensions in the repository:
fontsgithubwget
Typical loading pattern:
source "./.shellrc"
mantle_load_extension "wget"
mantle_wget_helpRepresentative extension capabilities:
fontsexposes font inventory helpers for Linux, macOS, and Windows-compatible environments.githubprovides release and tag-query helpers for GitHub repositories.wgetprovides a large set of reusable download/mirroring helpers and its ownmantle_wget_helpreference.
Treat these functions as optional libraries loaded into the current shell, not as always-on runtime behavior.
Mantle's current implementation makes several concrete promises that are worth calling out:
- Mantle itself does not perform startup-time network requests during normal shell initialization.
- Telemetry opt-out defaults are enabled by
modules/privacy.shunlessMANTLE_DISABLE_TELEMETRYis changed. - Automatic update-check suppression is separate and opt-in through
MANTLE_DISABLE_AUTOMATIC_UPDATE_CHECKS=1. - Platform runtimes must remain quiet, idempotent, and free from install, prompt, privilege, and preference-mutation side effects.
- Installers are contract-tested to avoid
sudousage. - XDG runtime directories are created with private permissions when Mantle needs a fallback.
- Public command, module, and extension names are validated before dispatch/loading.
- User-owned XDG locations are the default destination model for runtime state and many tool directories.
These are implementation-backed boundaries, not absolute security guarantees. Review individual installer help and source before using them in sensitive environments.
Mantle ships a canonical test runner at ./tests/run.sh.
./tests/run.sh
./tests/run.sh unit
./tests/run.sh integration
./tests/run.sh contract
./tests/run.sh static
./tests/run.sh formatThe optional Task interface adds task validate, task test, task doctor,
task profiles:list, task profiles:validate, and task catalog:validate.
task validate checks profile/catalog metadata and then the existing static
suite. The underlying CLI and test runner remain available without Task.
task check adds the isolated installation smoke test to local validation.
task ci runs the strict tool-complete suite and the same smoke test; local
skips do not establish CI readiness.
What the current test harness provides:
- Bats-based unit, integration, and contract tests.
- Static validation for Bash syntax, optional Zsh/Fish syntax, optional ShellCheck, optional shdoc parsing, and optional shfmt checks.
- Canonical shell formatting through the root
.editorconfig. - Hermetic temporary-home isolation for tests that interact with shell state.
- Root-installer integration coverage for copy installs, symlink installs, shell activation, dry-run, pinned update, status, doctor, disable, uninstall, and rollback.
- Deterministic source-distribution packaging and isolated release-lifecycle verification.
- CI coverage for:
staticon Ubuntutest-linuxon Ubuntu with Bash, Zsh, Fish, and the completebin/catalogtest-macoson macOS with Bash and Zsh for the portable runtime, installer, release lifecycle, and contracts
For local setup details, fixture guidance, command stubs, and debugging failed tests, see tests/README.md.
Tests are intended to avoid real installations and should stub external tools or network interactions when exercising installer flows.
A focused development workflow for this repository looks like this:
- Clone the repository.
- Create a branch for one focused change.
- Update the smallest relevant runtime, CLI, installer, or documentation surface.
- Add or update tests when behavior changes.
- Run the canonical validation commands from
./tests/run.sh. - Use a Conventional Commit for your commit message.
- Open a pull request with a concise summary of user-visible behavior and validation.
Current development tooling mentioned in the repository includes Bats, ShellCheck, shfmt, and shdoc-oriented help annotations in shell scripts.
If you want to contribute:
- Report bugs and request features through GitHub issues.
- Propose new installers by following the existing
libexec/mantle/installers/patterns and validating them with./tests/run.sh integration. - Add runtime capabilities through focused modules, shared libraries, or platform adapters instead of broad startup scripts.
- Add or update tests alongside behavior changes, especially for public entrypoints and installer contracts.
- Avoid committing machine-specific state, credentials, local config files, or generated artifacts.
See CONTRIBUTING.md for source roles, portability, shdoc and formatting conventions, metadata registration, provenance, and validation.
Near-term work that can be inferred from the current repository and issue context includes:
- Broader Windows and cross-platform validation coverage.
- More complete contributor and architecture documentation.
- Publish the first signed release from a
v*tag. - Expanded command surfaces and shell ergonomics where they fit the current modular architecture.
These are directional items, not dated promises.
Mantle is available under the MIT License.
Mantle builds on established shell and Unix conventions, including the XDG Base Directory specification, Bats for behavioral testing, and ShellCheck for static shell validation.