Skip to content

A GUI App's CLI May Not Share Its Name

Looking for a Mac app's command-line tool, the obvious check is to peek inside the bundle:

ls "/Applications/Spark Desktop.app/Contents/MacOS"
# Spark Desktop
# SparklyRemote

Two executables, neither named spark. Easy conclusion: no CLI here. Wrong. SparklyRemote is the Spark CLI:

"/Applications/Spark Desktop.app/Contents/MacOS/SparklyRemote" --version
# 1.3.0

A 2026-07-31 audit made exactly this call — listed both filenames, saw no spark, and recorded "no CLI binary… confirmed dead end." The tool had been installed and working the whole time. The resulting task sat blocked in a backlog for eight days, waiting on a decision nobody needed to make.

The Short Answer

Never conclude "not installed" from filenames. Ask the binaries what they are:

APP="/Applications/Some App.app"
for b in "$APP/Contents/MacOS/"*; do
  echo "--- $b"
  "$b" --help 2>&1 | head -5
done

And check /usr/local/bin for a symlink pointing back into the bundle, which is how most Mac apps install their CLI:

ls -l /usr/local/bin | grep -i "app-name\|Applications"

Why the Obvious Checks Miss It

The CLI is often a differently-named helper inside the bundle. Vendors name the GUI binary after the product and the CLI after an internal component. SparklyRemote reads like a background sync helper; nothing suggests a user-facing CLI.

The PATH check can mislead too. That same audit reported "no spark-named binary on PATH" — but /usr/local/bin/spark existed, symlinked into the bundle, and /usr/local/bin is on the default PATH. Two independent checks agreed, and both were wrong, which is exactly what makes this kind of conclusion stick.

Package managers won't show it. The Homebrew cask (readdle-spark) installs the .app only. brew list reveals nothing about a CLI the app installs into /usr/local/bin itself, usually via an in-app "install command-line tool" action — which leaves no record in any package database.

Dating the Install

A symlink's timestamp tells you when the CLI appeared, which is often more reliable than anyone's memory:

ls -l /usr/local/bin/spark
# lrwxr-xr-x  1 root  wheel  60 Jul 31 10:58 /usr/local/bin/spark -> /Applications/Spark Desktop.app/Contents/MacOS/SparklyRemote

Useful when reconstructing whether a tool predates a documented "it's missing" claim — here it did.

Check Capability, Not Just Presence

Once found, confirm what it can actually do. Spark's CLI reports its access level per account:

spark accounts
# Email Account: you@gmail.com "Gmail" (Access: read-only)

read-only matters: reads, search, and threads work, but anything that composes or sends needs a different tool. A tool being present says nothing about the operations it will permit — the same trap as an MCP server reporting "Connected".

Rule of Thumb

Presence on disk, absence from PATH, and absence from a package manager are all weak evidence. Running the thing is strong evidence. When a check concludes "the tool isn't here," spend the extra ten seconds running --help on every unfamiliar executable nearby before writing it down as a dead end — a wrong "not installed" gets trusted and re-read for as long as it stays on file.