Skip to main content

CLI Reference

Complete reference for the membrowse command-line tool. For the GitHub Actions integration, see the membrowse-action repository.

Installation​

pip install membrowse

To update to the latest version:

pip install --upgrade membrowse

Requirements: Python 3.8+

Quick Start​

# Generate a local report
membrowse report build/firmware.elf "linker.ld"

# Output as JSON (for troubleshooting)
membrowse report build/firmware.elf "linker.ld" --json

# Analyze and upload to MemBrowse
membrowse report build/firmware.elf "linker.ld" \
--upload \
--target-name my-target \
--api-key YOUR_API_KEY

Commands​

membrowse report​

Generate and optionally upload a memory report.

membrowse report <elf_path> [ld_scripts] [options]

Arguments​

ArgumentRequiredDescription
elf_pathYes*Path to the ELF file (*not required with --identical)
ld_scriptsNoSpace-separated linker script paths in quotes — supports GNU LD (.ld) and IAR ICF (.icf) formats (if omitted, uses default Code/Data regions based on ELF section flags)

Mode Options​

OptionDescription
--uploadUpload report to MemBrowse platform
--no-gitDisable auto-detection of Git metadata when uploading
--githubUse GitHub Actions environment for Git metadata detection (use with --upload)

Upload Options​

Required when using --upload:

OptionDescription
--api-key KEYMemBrowse API key
--target-name NAMEBuild configuration/target (e.g., esp32, stm32, x86)
--api-url URLMemBrowse API base URL (default: https://api.membrowse.com)
--identicalMark commit as having identical memory footprint to previous (metadata-only upload, no ELF analysis required)

Git Metadata Options​

These are auto-detected by default. Use --no-git to disable auto-detection, or specify manually to override:

OptionDescription
--commit-shaGit commit SHA
--parent-shaGit parent commit SHA. Use append to set the parent to the head of the default branch, or none for no parent.
--base-shaAlias for --parent-sha
--branch-nameGit branch name
--repo-nameRepository name
--commit-messageCommit message
--commit-timestampCommit timestamp (ISO format)
--author-nameCommit author name
--author-emailCommit author email
--pr-numberPull request number
--pr-namePull request name/title
--pr-author-namePull request author name
--pr-author-emailPull request author email

Performance Options​

OptionDescription
--skip-line-programSkip DWARF line program processing for faster analysis
--def VAR=VALUEDefine linker script variable (can be specified multiple times)

Alert Options​

OptionDescription
--dont-fail-on-alertsExit 0 even if budget alerts triggered

Output Options​

OptionDescription
--jsonOutput report as JSON (default is human-readable format)
--all-symbolsDisplay all symbols instead of just top 20 (human-readable mode only)
--output-raw-responseOutput raw API response as JSON to stdout

Upload Response​

When uploading with --upload, the API returns a JSON response containing:

  • success: Whether the upload succeeded
  • report_id: The ID of the uploaded report
  • alerts: Any budget alerts triggered
  • diffs: Memory differences compared to the previous commit, broken down by region and section

Use --output-raw-response to output this JSON to stdout for further processing:

RESULT=$(membrowse report \
build/firmware.elf \
"linker.ld" \
--upload \
--target-name my-target \
--api-key YOUR_API_KEY \
--output-raw-response)

echo "$RESULT" | jq '.diffs'

Examples​

# Local analysis - human-readable output (default)
membrowse report build/firmware.elf "linker.ld"

# Local analysis without linker scripts (uses default Code/Data regions)
membrowse report build/firmware.elf

# Show all symbols locally
membrowse report build/firmware.elf "linker.ld" --all-symbols

# Output as JSON
membrowse report build/firmware.elf "linker.ld" --json

# Upload to MemBrowse (Git metadata auto-detected)
membrowse report build/firmware.elf "linker.ld" \
--upload \
--target-name my-target \
--api-key YOUR_API_KEY

# Upload without Git metadata
membrowse report build/firmware.elf "linker.ld" \
--upload --no-git \
--target-name my-target \
--api-key YOUR_API_KEY

# GitHub Actions mode (auto-detects Git metadata from GitHub environment)
membrowse report build/firmware.elf "linker.ld" \
--upload --github \
--target-name stm32f4 \
--api-key YOUR_API_KEY

# Multiple linker scripts
membrowse report build/firmware.elf "memory.ld sections.ld" \
--upload \
--target-name my-target \
--api-key YOUR_API_KEY

# Define linker script variables
membrowse report build/firmware.elf "linker.ld" \
--def __flash_size__=4096K \
--def __ram_size__=256K

membrowse summary​

Retrieve memory footprint summaries for a commit from the MemBrowse API. Returns data for all targets associated with the commit — each target's region changes, section changes, and layout are included in the response under a targets list.

membrowse summary <commit_sha> --api-key KEY [options]

Arguments​

ArgumentRequiredDescription
commit_shaYesGit commit SHA to retrieve summary for

Options​

OptionDescription
--api-key KEYMemBrowse API key (required)
--api-url URLMemBrowse API base URL (default: https://api.membrowse.com)
--jsonOutput raw JSON response from API (includes targets array with per-target summaries)
--template PATHPath to custom Jinja2 template file (default: built-in template). The template receives the full response including the targets list.

--json and --template are mutually exclusive.

Examples​

# Human-readable summary (all targets)
membrowse summary abc123def --api-key YOUR_API_KEY

# Raw JSON output (for scripting)
membrowse summary abc123def --api-key YOUR_API_KEY --json

# Custom template
membrowse summary abc123def --api-key YOUR_API_KEY --template my_template.j2

membrowse onboard​

Analyze historical commits to build baseline data. Supports two modes: processing the last N commits, or processing a specific list of commits/tags.

# Mode 1: Last N commits
membrowse onboard <num_commits> <build_script> <elf_path> <target_name> <api_key> [api_url] [options]

# Mode 2: Specific commits
membrowse onboard <build_script> <elf_path> <target_name> <api_key> --commits "REF1 REF2 ..." [options]

Arguments​

ArgumentRequiredDescription
num_commitsNoNumber of commits to process (required unless --commits is used)
build_scriptYesShell command to build the firmware (quoted)
elf_pathYesPath to ELF file after build
target_nameYesTarget name in MemBrowse
api_keyYesMemBrowse API key
api_urlNoMemBrowse API base URL (default: https://api.membrowse.com)

Options​

OptionDescription
--ld-scripts SCRIPTSSpace-separated linker script paths — supports GNU LD (.ld) and IAR ICF (.icf) formats (if omitted, uses default Code/Data regions)
--def VAR=VALUEDefine linker script variable (can be specified multiple times)
--build-dirs DIR [DIR ...]Directories that trigger rebuilds. Commits with no changes in these directories upload metadata-only reports with identical=True. Mutually exclusive with --binary-search.
--initial-commit HASHStart processing from this commit hash (must be on the main branch). Only valid with num_commits.
--commits REFSSpace-separated list of commit hashes and/or tags to process. Mutually exclusive with num_commits and --initial-commit.
--initial-parent REFSet the parent of the first commit when using --commits. Used to chain multiple onboard runs together. Only valid with --commits.
--binary-searchMinimize builds using binary search — builds endpoints first, compares memory fingerprints, and only builds midpoints where changes are detected. Mutually exclusive with --build-dirs.
--dry-runRun the full workflow but skip uploading reports (logs what would be uploaded)

Examples​

# Basic onboarding with linker scripts
membrowse onboard \
50 \
"make clean && make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY \
--ld-scripts "linker.ld"

# Without linker scripts (uses default Code/Data regions)
membrowse onboard \
50 \
"make clean && make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY

# With custom API URL
membrowse onboard \
25 \
"idf.py build" \
build/firmware.elf \
esp32 \
YOUR_API_KEY \
https://custom-api.example.com \
--ld-scripts "build/esp-idf/esp32/esp32.project.ld"

# Skip commits without changes in build directories
membrowse onboard \
100 \
"make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY \
--ld-scripts "linker.ld" \
--build-dirs src/ lib/ include/

# Start from a specific commit
membrowse onboard \
50 \
"make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY \
--ld-scripts "linker.ld" \
--initial-commit abc123def

# Onboard specific version tags
membrowse onboard \
"make clean && make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY \
--commits "v1.0 v1.1 v2.0 v2.1" \
--ld-scripts "linker.ld"

# Chain multiple onboard runs across version boundaries
membrowse onboard \
"make clean && make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY \
--commits "v2.0 v2.1 v2.2" \
--initial-parent v1.9 \
--ld-scripts "linker.ld"

# Minimize builds with binary search
membrowse onboard \
100 \
"make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY \
--ld-scripts "linker.ld" \
--binary-search

# Dry run to verify setup without uploading
membrowse onboard \
10 \
"make all" \
build/firmware.elf \
my-target \
YOUR_API_KEY \
--ld-scripts "linker.ld" \
--dry-run

Behavior​

  1. Fetches git history (requires full clone)
  2. Uses --first-parent to follow only main branch (not feature branch commits)
  3. Iterates from oldest to newest commit
  4. For each commit:
    • Checks out the commit
    • Runs the build script
    • Analyzes the ELF file
    • Uploads the report
  5. Skips building commits with no changes in --build-dirs (uploads metadata-only)
  6. With --binary-search, builds only endpoints first, then bisects where memory fingerprints differ
  7. Uploads empty reports for failed builds
  8. Restores original HEAD when complete

Global Options​

These options apply to all commands:

OptionDescription
-v, --verbose LEVELSet logging verbosity: WARNING (default), DEBUG, INFO
--versionShow installed version
--helpShow help message
# Info output
membrowse -v INFO report build/firmware.elf "linker.ld"

# Debug output
membrowse -v DEBUG report build/firmware.elf "linker.ld"

Exit Codes​

CodeMeaning
0Success
1Error (budget alert, invalid input, API error, etc.)

Use --dont-fail-on-alerts to prevent budget alerts from causing exit code 1.


Output Formats​

Human-Readable (default)​

Memory Report for build/firmware.elf
=====================================

FLASH: 45,234 / 262,144 bytes (17.3%)
.text: 32,456 bytes
.rodata: 12,778 bytes

RAM: 12,834 / 65,536 bytes (19.6%)
.data: 1,234 bytes
.bss: 11,600 bytes

Top Symbols by Size:
1. main 2,456 bytes (.text)
2. usb_buffer 4,096 bytes (.bss)
3. string_table 1,892 bytes (.rodata)
...

JSON (with --json)​

When using --json, the report is output as JSON to stdout. When uploading with --upload, a JSON report is generated containing:

  • Memory regions with usage
  • All sections with sizes
  • Complete symbol table
  • Git metadata (commit, branch, etc.)