Part I — User manual

How to use MAMA

Available pages

Homepage (click the logo, top left)

An overview of current projects and a computer resource overview, plus other quality-of-life widgets as needed.

Setup menu

Run the setup wizard again. It auto-scans your system to determine prerequisites.

Settings

Change several settings about the app. It can also be edited directly in the app files at user/settings.json — it was intentionally designed to be flexible, portable, and easy to access.

Several settings are optional and not needed for core functions, but they are used in several of the app's tests. For example, several installers require the OS field to be filled out, as they determine the system OS via the settings JSON file, and not through other means.

Multimodel design

An easy GUI for designing multi-model systems.

Database explorer

A quality-of-life feature that lets you browse a web database (such as Hugging Face) to easily transfer information from outside sources.

Export model

A page that walks you through exporting a model for any use case. Future aspirations include instant app/website generation (from template, not LLM), Ollama (or other client) exports, and more.

Baby's first project

  1. Make a directory
  2. Open the directory with MAMA
  3. Design a multimodel interface, and save it to the directory
  4. Click begin training
  5. Export the model

Themes

The app uses a file-based theme system. Themes are JSON files placed in user/themes/. Each file adds an option to the appearance dropdown in settings.

Built-in themes

The app ships with no built-in theme visible in the dropdown. The only hardcoded palette is a dark fallback that activates automatically when user/themes/ is empty. If the folder has any valid JSON themes, the fallback is replaced.

Adding a theme

Create a new .json file in user/themes/ with this structure:

{
  "name": "my-theme",
  "title": "My Theme",
  "variables": {
    "--page-bg": "#ffffff",
    "--page-text": "#000000"
  }
}
  • name — a short identifier (no spaces recommended). Used internally and stored in settings.
  • title — what appears in the dropdown menu.
  • variables — CSS custom properties that change the app colours.

Once saved, open Settings → Appearance and your theme will appear in the dropdown. No restart needed — just navigate to settings or reload the page.

Example themes

The repo includes three example themes in user/themes/:

  • light.json — light mode
  • dark.json — dark mode
  • dark-green.json — dark mode with green accents

You can enable or disable any theme by adding or removing its .json file.

Fallback

If you remove all .json files from user/themes/, the dropdown will show only System and Fallback. The fallback is a default dark palette built into the app.

Part II — Power user guide

The power user's manual

A supplement to the regular user manual, aimed at those past the beginner stage. For in-depth explanations of each component, refer to the developer's guide.

The user folder

The user folder, located at mama/user, holds most of everything the user will need. Most files live here, including those for custom editing.

Framework installation & verification

Installation (install_fw.py)

Handles the installation of PyTorch and TensorFlow via pip.

  • Variants: Supports cuda (NVIDIA), rocm (AMD), and cpu (standard).
  • Logic: Dynamically builds the installation command based on the requested framework and hardware variant.
  • Execution: Uses subprocess.run to execute the installation, streaming output for real-time monitoring.

Verification (import_test.py)

Verifies the installation and hardware acceleration.

  • PyTorch: Checks for CUDA/ROCm availability and prints GPU details (model, VRAM, version).
  • TensorFlow: Checks for available physical GPU devices.
  • Error handling: Returns exit code 0 on success or 1 on ImportError, allowing the pipeline to detect installation failures.
FeaturePyTorchTensorFlow
Installpip install torchpip install tensorflow
Verificationimport torchimport tensorflow
Hardware checkCUDA / ROCm / CPUPhysical GPU devices
DiagnosticsGPU model & VRAMDevice list

Setup wizard — modular architecture

The setup wizard (components/setup/setup.js) has been refactored from a single monolithic script into a modular system. Each step of the wizard lives in its own file under components/setup/modules/, and the order is controlled by components/setup/setup.json.

How it works

  1. setup.json defines two things: steps — an array of step definitions, each with an id, title, and script path; and setup_order — an ordered array of step IDs that determines the wizard's navigation sequence.
  2. setup.js (the parent loader) fetches setup.json, loads _shared.js, then loads each step module. After all modules are loaded, it reorders window.__setupSteps to match setup_order.
  3. modules/_shared.js provides shared state (window.__setupState), utilities (window.__setupUtils), settings management (window.__setupSettings), and rendering/navigation (window.__setupRender).
  4. Each step module (e.g., step-welcome.js, step-framework.js) is an IIFE that pushes a step object with { id, title, render, afterRender?, collect? } to window.__setupSteps.

Reordering steps

To change the wizard's step order, edit the setup_order array in setup.json. No JavaScript changes are needed. For example, to move "Language" after "Appearance":

"setup_order": [
  "welcome",
  "appearance",
  "language",
  ...
]

Adding a new step

  1. Create a new file in components/setup/modules/step-your-step.js.
  2. Add its definition to the steps array in setup.json.
  3. Add its ID to setup_order at the desired position.

Custom theming

Themes are set as CSS variables. Each theme is represented as a .json file in user/themes. Each JSON should automatically be added as an entry; duplicates will be ignored.

The values of said themes can be any CSS-accepted color value, in quotations.

Part III — Developer's guide

The developer's guide

The complete guide on every working part of this application, including intended usage.

Framework installation & verification — deep dive

Overview

This module provides the logic for automatically installing deep learning frameworks (PyTorch and TensorFlow) and verifying their installation and hardware acceleration. It is designed to be called by a parent process and provides streamed output for real-time monitoring.

1. Installation phase (install_fw.py)

The installation script handles the mapping between user requirements and the specific pip commands needed.

  1. Input parsing: Accepts framework (torch/tf), gpu_variant (cuda/rocm/cpu), and an optional accel_version.
  2. Command construction: The build_command() function determines the correct installation string:
    • PyTorch: Maps requirements to torch installation strings, including specific wheels for CUDA or ROCm.
    • TensorFlow: Maps requirements to tensorflow or tensorflow-gpu packages.
    • CPU fallback: Installs the CPU-only versions of the frameworks.
  3. Execution: Executes the command using subprocess.run(). stdout and stderr are inherited, allowing the calling process to capture installation progress in real-time.

2. Verification phase (import_test.py)

After installation, this script ensures the framework is functional and the system hardware is correctly recognized.

  • PyTorch verification: Attempts import torch; NVIDIA path checks torch.cuda.is_available() and prints CUDA version, GPU count, and per-GPU properties (model name, VRAM); AMD path checks torch.version.hip and prints ROCm version; CPU path falls back to "CPU only" status.
  • TensorFlow verification: Attempts import tensorflow as tf; GPU detection uses tf.config.list_physical_devices("GPU") to list all available hardware.
  • Exit status: 0 success · 1 ImportError or critical failure · 2 invalid arguments.
FeaturePyTorch pathTensorFlow path
Install commandpip install torch (+ variant)pip install tensorflow (+ variant)
Verificationimport torchimport tensorflow as tf
Hardware checktorch.cuda / torch.version.hiptf.config.list_physical_devices
DiagnosticsGPU model, VRAM, CUDA/HIP versionList of physical GPU devices

Theme system

Architecture

Themes are stored as JSON files in user/themes/. Each file represents one theme and must contain three fields:

{
  "name": "theme-id",
  "title": "Display Name",
  "variables": {
    "--highlight-color": "#00d4ff",
    "--main-color": "#1a1a2e"
  }
}
  • name — unique identifier used as the internal key and stored in settings.
  • title — human-readable label shown in the appearance dropdown.
  • variables — a flat map of CSS custom properties to values. Each key must start with --.

Theme loading flow

  1. Startupcomponents/styling/theme.js calls window.electron.themesRead() (IPC) on initialization.
  2. Backendcomponents/styling/theme-loader.js reads all .json files from user/themes/, validates structure (name, title, variables), and returns the array.
  3. Renderertheme.js merges each theme's variables into a palettes lookup by name.
  4. Settings — both the settings page (components/setup/settings.js) and setup wizard (components/setup/setup.js) call themesRead() to populate the appearance dropdown.

Fallback behaviour

When user/themes/ is empty or contains no valid .json files, the app falls back to a hidden built-in dark palette. This fallback is never listed in the dropdown — instead a single "Fallback" option appears. The fallback is hardcoded in theme.js as fallbackPalette.

File locations

FilePurpose
user/themes/*.jsonUser-provided theme files
components/styling/theme-loader.jsBackend module that reads themes from disk
components/styling/theme.jsFrontend theme manager — applies CSS variables, manages state
components/backend/ipc/ipc-handlers.jsRegisters themes-read IPC handler
preload.jsExposes themesRead() to renderer via contextBridge

Variables reference

The complete set of CSS custom properties a theme can define — all optional; missing ones simply won't override the previous value:

--highlight-color --main-color --shadow-color --heading-color --body-color --page-bg --page-text --page-muted --panel-bg --panel-border --widget-bg --widget-border --topbar-bg --topbar-border --topbar-text --topbar-muted --topbar-active --input-bg --input-text --input-border --button-secondary-bg --button-secondary-text

Theme manager API

The window.ThemeManager object exposed by theme.js provides:

MethodPurpose
applyTheme(themeName, broadcast?)Apply a theme by name
getCustomThemeList()Returns [{name, title}] of loaded themes
isUsingFallback()Returns true if no user themes exist
getActiveTheme()Returns the currently active theme name
initializeTheme()Re-initialize (loads themes from IPC, applies stored preference)
getResolvedTheme(themeName)Returns the resolved palette key

Setup wizard — deep dive

File layout

components/setup/
├── setup.js              # Parent loader — fetches setup.json, loads modules, bootstraps
├── setup.json            # Step definitions + setup_order array
└── modules/
    ├── _shared.js        # Shared state, utilities, settings, rendering
    ├── step-welcome.js
    ├── step-language.js
    ├── step-appearance.js
    ├── step-os-detect.js
    ├── step-python-detect.js
    ├── step-python-dependency.js
    ├── step-gpu-detect.js
    ├── step-compat-check.js
    ├── step-framework.js
    ├── step-fw-install.js
    ├── step-fw-verify.js
    ├── step-resources.js
    ├── step-project-folder.js
    ├── step-qol.js
    ├── step-security.js
    └── step-finish.js

Bootstrap flow

  1. setup.js listens for DOMContentLoaded, then:
    • Fetches setup.json to get steps (definitions) and setup_order (ordering).
    • Loads _shared.js via dynamic <script> injection.
    • Loads each step module in the order listed in steps.
    • Reorders window.__setupSteps to match setup_order.
    • Builds the wizard DOM (#setup-wizard with header, content, progress dots, and action buttons).
    • Calls window.__setupSettings.loadSettings() to hydrate the settings cache.
    • Wires up navigation event listeners (next, back, skip, finish).
    • Renders the first step.

Shared module (_shared.js)

Exposes four global namespaces:

NamespacePurpose
window.__setupStateAll mutable state — selectedFramework, selectedMode, installSucceeded, detected (OS, Python, GPU, compat), pythonDetectCache, selectedProjectFolder, currentStep, settingsCache
window.__setupUtilsPure utility functions — escapeHtml, parseKV, boolVal, okIcon, warnIcon, gpuVariant, torchIndexURL, gpuVariantLabel, buildInstallCommand, getPythonDetectResult
window.__setupSettingsSettings persistence — loadSettings, defaultSettings, applyStepData, collectAndSave
window.__setupRenderRendering and navigation — renderStep, nextStep, prevStep

Step module contract

Each step module is an IIFE that pushes an object to window.__setupSteps:

{
  id: 'unique-step-id',           // matches the id in setup.json
  title: 'Display Title',         // shown in progress dots
  render(settingsCache) { ... },  // returns HTML string (synchronous)
  afterRender() { ... },          // async — runs after DOM is injected
  collect() { ... }               // returns data to persist into settings
}
  • render() — must be synchronous. Returns the HTML for the step. Receives the current settingsCache as argument.
  • afterRender() — optional async hook. Runs after the HTML is in the DOM. Used for event binding, async detection, and dynamic UI updates.
  • collect() — optional. Called when the user navigates away from the step. Returns data that applyStepData() maps into the settings cache.

Step ordering

The setup_order array in setup.json is the single source of truth for navigation order. After all modules load, setup.js builds a lookup map by step ID and reassembles window.__setupSteps to follow setup_order. Steps not listed in setup_order are dropped. Steps listed but not found are silently skipped.

Adding / removing / skipping a step

  • Add: create components/setup/modules/step-your-step.js following the contract above, add an entry to steps in setup.json, then insert the step ID into setup_order at the desired position.
  • Remove: delete its entry from steps and remove its ID from setup_order.
  • Skip without deleting: just remove its ID from setup_order — the module still loads but won't appear in the wizard.

Documentation system

The documentation system is quite simple. Add the relative path of any MD file to docs/register.json (it assumes the file is in the docs folder, but you can change the path).

{
  "display name" : "filename.md",
  "file outside of docs folder" : "../path/to/file.md"
}

Auto-updater

MAMA can update itself from GitHub releases. The whole system lives in updater.py; the UI is components/elements/updater.js (banner on every page) plus an "Updates" panel on the settings page.

How it works

  1. Checkupdater.check_for_update() lists api.github.com/repos/CrankyTitanO7/mama/releases and picks the release with the highest version tag (stable over prerelease — /releases/latest can't be used because it returns the most recently published release, so a later-published lower tag would hide a higher one). It compares the tag against the bundled components/version.json and matches an asset: macOS → mama-macos.dmg (or mama-macos-<arch>.dmg/.zip), Windows → mama-windows.zip, Linux → mama-linux.AppImage. One plain archive not targeting another platform is used as a fallback.
  2. Downloadupdater.download_update() streams the asset into ~/Library/Application Support/mama/updates (per-OS equivalent elsewhere) and verifies its sha256 against the GitHub-provided asset digest.
  3. Stageupdater.stage_update() unpacks the artifact (dmg → hdiutil attach + ditto out the .app; zip → extract + locate the app folder, handling the Windows mama/ wrapper; AppImage → used as-is, made executable) into updates/mama-<tag>/ and writes an apply.json marker. Staging is refused when running from source (unpackaged).
  4. Apply — on quit, bridge.py's on_quit spawns a detached mama --apply-update <marker> process. It waits for the old process to exit, swaps the old install for the staged one (whole bundle/folder, or single-file replacement for AppImages), copies user data (user/, components/recents.json) from the old install — locating the data dir in the new build even if the PyInstaller layout changed (Contents/Resources vs _internal) — deletes the backup, and relaunches the new build (open on macOS, direct exec elsewhere). An applying.lock prevents two processes swapping at once, and a marker left by a crashed session is applied on the next startup (updater.recover_pending() in main.py).

Frontend API (via the shim)

MethodPurpose
electron.updateCheck()Returns {available, current_version, latest_version, notes, asset, error}
electron.updateDownload()Starts a background download; progress via _updateProgressCallback
electron.updateInstall()Stages the download; emits ready
electron.appQuit()Closes the window (triggers the quit hand-off)

Releasing a new version

The GitHub workflow .github/workflows/build.yml handles the whole release: push a tag and it builds on all three platforms, writes the version into components/version.json from the tag name, packages the artifacts (mama-macos.dmg, mama-windows.zip, mama-linux.AppImage) and uploads them to a GitHub release:

git tag v0.2.0 && git push origin v0.2.0

The build environment MUST have certifi installed (the workflow installs it, and build_release.py warns if it is missing): without it the packaged app contains no CA certificates and every HTTPS request fails from inside the app — the updater can't reach GitHub and reports a TLS error.

The workflow uses the same artifact names the updater expects — a release created any other way must use those names, or the updater won't offer it. To build locally instead, python build_release.py --version 0.2.0 bumps components/version.json, runs PyInstaller, zips the build into dist/mama-<os>-<arch>.zip and prints the sha256; then create a GitHub release and attach the zip.