Install Ghidra 11+ separately through your package manager or extract an
official release,
then follow the CLI install steps.
A full JDK is required (javac and
jdk.compiler, not a JRE); Ghidra 12.x requires JDK 21 (older releases accept
JDK 17). The CLI selects a suitable JDK automatically; --java-home overrides it.
On macOS, build Ghidra's native components after extracting a release; the
archive does not include the macOS decompiler. Follow Ghidra's
native build instructions
(./gradlew buildNatives in the installation's support/gradle directory).
CI builds these tools before caching its macOS installation.
find bytes --regex requires Ghidra's native memsearch API, introduced in
Ghidra 11.2. Installations without it report an error for that command; other
commands remain available.
ghidra-cli doctor checks the installation, compiles the embedded Java bundle,
probes storage with temporary create/write/rename/delete operations, and tests
loopback TCP bind/connect. It reports resolved paths and their configuration
sources. These checks do not establish that the JVM can start; the runtime check
is explicitly not_checked unless --runtime is supplied.
ghidra-cli doctor --runtime also creates a disposable project in the configured
project directory, starts and pings the real bridge, then stops it and removes
the project. It uses the actual environment and settings/cache locations; it may
populate Ghidra's normal caches. If shutdown fails, it retains the diagnostic
project and reports its location. Prerequisite failures prevent the runtime probe.
Preserve file modification times when extracting a release: Ghidra compares
compiled .sla language definitions with their sources, and incorrect times can
trigger unnecessary recompilation on import. To repair an affected installation,
stop its bridges, extract a fresh copy into a new directory, and select that path
with GHIDRA_INSTALL_DIR or config set ghidra_install_dir PATH.
The CLI also supports the default output of Ghidra's official
support/buildGhidraJar (buildGhidraJar.bat on Windows). Build it from a complete
distribution; the generated ghidra.jar appears in the current directory:
/path/to/ghidra/support/buildGhidraJar
ghidra-cli config set ghidra_jar "$PWD/ghidra.jar"
ghidra-cli doctor --runtimeAlternatively, set GHIDRA_JAR to the JAR's path. The JAR can be moved away from
the distribution used to build it. Place it in a path without +, including any
resolved symlink target: Ghidra 12.1.4's JAR loader interprets + as a space. If the CLI
rejects such a path, move the JAR and update the selection.
Keep a compatible full JDK installed: the bridge and user Java scripts still
need the Java compiler. Custom module
selections made through BuildGhidraJarScript are outside the supported default
configuration. Non-Java script runtimes are not included in the standalone format.
Native components must be present when building the JAR. On macOS, complete the
native build described above first. Ghidra extracts bundled native resources at
runtime, so its settings/cache locations must be writable even when the JAR is
read-only. Use doctor --runtime to check the selected JAR in its actual runtime
environment.
The CLI launches the JAR directly with the selected JDK. Its heap limit uses
GHIDRA_HEADLESS_MAXMEM, then GHIDRA_MAXMEM, then 2 GiB. Standard JVM
JAVA_TOOL_OPTIONS can supply additional JVM settings.
Project directory precedence is --projects-dir DIR, GHIDRA_PROJECT_DIR, config
ghidra_project_dir, then the default, for project management, doctor, and bridge
commands. The flag does not change the environment or saved configuration.
Ghidra selection uses environment overrides (GHIDRA_INSTALL_DIR or
GHIDRA_JAR), then saved configuration (ghidra_install_dir or ghidra_jar),
then automatic directory detection. Specifying both forms in the effective
layer is an error; an environment override takes precedence over saved settings.
config set ghidra_jar PATH clears saved ghidra_install_dir, and setting
ghidra_install_dir clears saved ghidra_jar. Explicit paths are validated; an
empty or invalid override fails instead of selecting another installation.
Doctor reports the effective format, path, source, and version.
config get/list shows saved settings only. A running bridge keeps its selected
Ghidra runtime until stopped; use bridge restart --project P after changing the
selection to apply it to that project.
Detection checks absolute PATH entries in order, resolving Ghidra launcher
symlinks and Homebrew's package layout without executing wrappers. If PATH does
not identify an installation, it checks the known Arch, Kali/Pentoo, Void,
Homebrew, and MacPorts layouts, or the existing Windows search locations.
Homebrew's HOMEBREW_PREFIX is also recognized. Nix installations are found
through their PATH symlinks. Multiple distinct installations at the same priority
are an error: select one with config set ghidra_install_dir PATH (or fix an
existing environment override). Detection does not choose the newest version or
save its result. Arbitrary ZIP extraction locations require PATH or an explicit
setting; arbitrary filesystem locations are not searched. Standalone JARs require
an explicit setting and do not affect directory detection.
See the installation implementation and layout sources.
Set a persistent JDK with ghidra-cli config set java_home /opt/jdk-21.
JDK selection precedence is --java-home, GHIDRA_CLI_JAVA_HOME, config
java_home, then automatic detection. Flag and environment overrides do not
change the saved value.
Project listing and existence checks recognize .gpr/.rep artifacts.
Deletion removes those artifacts and leaves same-named bare directories intact.
Deletion first stops the CLI bridge and obtains Ghidra's project lock; another
Ghidra process using the project prevents deletion. Deleting .gpr/.rep
requires a working Ghidra/JDK installation; if it is unavailable, the project
files are retained.
Ghidra 12.1+ rejects project paths containing dot-prefixed components; on Linux
the default falls back from the cache directory to ~/ghidra-cli-projects.
Configuration updates lock the resolved config target and atomically replace its contents. Existing config symlinks remain links; a dangling link fails rather than being replaced. Concurrent updates preserve unrelated settings.
Output precedence is explicit format, --pretty, --json, configured
default_output_format, then TTY detection (human-readable on TTY, compact JSON
otherwise). For newline-delimited JSON, use --format ndjson or
config set default_output_format ndjson.
default_limit also applies after client filtering, sorting, and
offset when no explicit limit is given; --count and --limit 0 bypass that cap.
Set defaults with ghidra-cli config set default_project target and
ghidra-cli config set default_program target.bin. Project selection uses
--project, then default_project. Explicit
--program selects a program; a running bridge otherwise keeps its current
selection. When starting a bridge, config default_program supplies the default
program if no explicit program was given.
| Variable | Purpose |
|---|---|
GHIDRA_INSTALL_DIR |
Ghidra installation; also config set ghidra_install_dir PATH |
GHIDRA_JAR |
Official standalone Ghidra JAR; also config set ghidra_jar PATH |
GHIDRA_PROJECT_DIR |
Base project directory |
GHIDRA_CLI_JAVA_HOME |
Full JDK override; also --java-home or config set java_home PATH |
GHIDRA_CLI_CONFIG |
Config file path override |
On Linux, XDG_CONFIG_HOME controls the CLI configuration and Java source bundle,
and XDG_DATA_HOME controls bridge discovery/lock files and CLI logs.
GHIDRA_CLI_CONFIG changes only the YAML file, not these other locations.
Ghidra also uses settings and caches; its version-specific paths are reported by
doctor --runtime. Set XDG_CONFIG_HOME and XDG_CACHE_HOME before launching it
when the default locations are inaccessible. Other platforms use their native
directory conventions; inspect the paths in the doctor report.
For a restricted Linux workspace, choose absolute writable paths, for example:
export XDG_CONFIG_HOME="$PWD/tmp/analysis/config"
export XDG_CACHE_HOME="$PWD/tmp/analysis/cache"
export XDG_DATA_HOME="$PWD/tmp/analysis/data"
export GHIDRA_PROJECT_DIR="$PWD/tmp/analysis/projects"
export GHIDRA_INSTALL_DIR=/opt/ghidra
ghidra-cli doctor --runtimeUse the same environment for subsequent commands so they find the same bridge.
Directory overrides do not grant loopback networking permission. If a sandbox
denies 127.0.0.1 bind/connect, obtain permission for the affected command from
the environment running the CLI. The CLI does not change sandbox policy.
Timeout values are seconds.
| Variable | Budget and default |
|---|---|
GHIDRA_CLI_LAUNCH_TIMEOUT |
Bridge readiness, 180; also config launch_timeout_secs |
GHIDRA_CLI_OP_TIMEOUT |
Long analyze/import/decompile, high p-code, semantic type/field searches, variable-edit and return-type-edit socket waits, unset or 0 = unbounded |
GHIDRA_CLI_DECOMPILE_TIMEOUT |
Per-function native limit for decompile, pcode function --high, function var list/get/set, function set-return-type, type uses --kind variable, type field uses and find virtual-callers; unset or 0 = unbounded, maximum 2,147,483 seconds |
GHIDRA_CLI_READ_TIMEOUT |
Other request reads, 300; 0 = indefinite; includes queue wait |
GHIDRA_CLI_CONNECT_DEADLINE |
Connection retries, 60; minimum 1 |
GHIDRA_CLI_SHUTDOWN_TIMEOUT |
Total shutdown budget (lock, connection, reply, exit), 300; 0 = indefinite |
Invalid native decompiler budgets are errors. The maximum prevents overflow in Ghidra's conversion from seconds to milliseconds; use 0 for an unlimited budget.
ghidra-cli bridge start --project P --program bin
ghidra-cli bridge status --project P
ghidra-cli bridge ping --project P
ghidra-cli job list --project P
ghidra-cli job get 2c7a3b91-f960-4b85-87d7-e90cf7bf0625 --project P
ghidra-cli job cancel 2c7a3b91-f960-4b85-87d7-e90cf7bf0625 --project P
ghidra-cli bridge restart --project P --program otherbin
ghidra-cli bridge stop --project PCommands needing the bridge start a per-project JVM on demand. Program jobs use
a FIFO of 256, with 1,000 completed job records retained. job cancel defaults to the active
job; queued cancellation is immediate, active cancellation cooperative. Socket
read timeouts return Timeout: with exit 75 while work stays running or queued;
use the reported recovery command before retrying a mutation. Shutdown rejects new work and
drains accepted jobs, including a full queue.
The shutdown timeout reports an error (exit 75) and preserves discovery files and
the live process; it does not force termination. Inspect the process and retry
stop after accepted work finishes. Cancellation state is isolated per job.
If the final save fails, stop/restart/project deletion return an error and keep
the same JVM and program open. Resolve the cause, retry program save, then stop.
The CLI generates a UUID for each bridge program operation before sending it.
Successful output and confirmed errors keep their usual shape. A timeout or
lost/malformed response adds the job ID, actual operation name, resolved project,
and recovery.argv to diagnostics; human output shows the same retrieval command:
ghidra-cli job result 2c7a3b91-f960-4b85-87d7-e90cf7bf0625 --project Pjob result reads a saved response without rerunning the operation. Exit 0 means
retrieval succeeded, including when the original job failed or was cancelled;
inspect state and response.status, then response.detail for rollback,
partial-save, and save-failure information. Pending jobs report exit 75 and may
be queried again; unavailable results report exit 1. job get shows availability.
The response is the bridge envelope before CLI filtering/formatting; generated
files and the enclosing CLI/batch workflow are not snapshots of that envelope.
A preparatory open_program job completing does not mean the later edit ran.
Bodies are retained in memory for at most 30 minutes, with a 64 MiB combined
limit and 16 MiB per result. Capacity removes oldest bodies early; oversized
responses are delivered normally but not retained. expired, evicted, and
too_large distinguish unavailable bodies while their job metadata remains.
The 1,000-record history limit removes the whole record. Retrieval does not
extend retention. A bridge stop/restart loses the history; job commands never
auto-start a bridge. Missing results do not prove an operation was not executed.
CLI termination before it can report the generated ID has no guaranteed recovery
lookup; job list still provides the bridge's recent metadata.
Program commands, including analysis, scripts, and each batch operation, save before reporting success. Switching/closing also saves first; failure keeps the program open. For a bridge from another build, follow upgrading.
program delete NAME deletes the project file without selecting it.
Deleting the current program saves and closes it first; deleting another file
preserves the current selection. Other consumers and checkouts can prevent
deletion.
Save errors carry detail.save_failed: true; program commands also retain the
editing response in detail.command_response. A save failure is returned without
an implicit retry in that request. Changes may remain in memory: keep the bridge running,
resolve the reported cause, and retry program save for the same project/program
without restarting or repeating the edit.
Saving a stopped bridge is a no-op. Auto-save covers the bridge's current program;
scripts that open other programs own their saving and release. Scripts must close
transactions they start.
Ordinary program requests are atomic: failure or cancellation rolls back every
change in that request, including clearing before redisassembly and multi-symbol
deletion. Errors report detail.rolled_back: true, plus detail.cancelled: true
when cancelled. Earlier completed requests remain intact. Batch commands run
sequentially with these individual boundaries; a batch is not one transaction.
A rolled-back request does not save pending edits from an earlier save failure.
Transaction-boundary failures, save failures, and timeouts always stop a batch,
including nested batches; completed rollbacks follow its --on-error policy.
Analysis, scripts, imports, exports, and program open/close/save/delete are explicit
exceptions. They can retain partial changes and external file/project effects;
saved partial changes report detail.partial_changes_saved: true. Cancellation
cannot interrupt saving after commit, so completion may follow it.
detail.transaction_failed: true means the bridge could not establish or finish
transaction ownership; it does not confirm rollback. An ordinary request is
rejected before execution if another script left a transaction active, preserving
that owner's transaction and edits. If native code instead leaves a child
transaction open during an atomic request, the bridge marks its own root aborted;
rollback remains pending until the child's owner closes it. Those request edits
cannot be committed or saved. Keep the bridge running and resolve the outstanding
transaction through its owner before retrying; recovery scripts remain available.
The bridge never ends an unknown transaction to force recovery.
Before replacing the CLI, run ghidra-cli bridge stop --project P for each running
project. Stop waits for accepted jobs to finish and pending changes to save; resolve
any save failure before updating. Start bridges again after updating so the CLI
and running Java bridge use the same build. Do not run different CLI versions
concurrently for the same project.
Program dispatch requires bridge_info.explicit_addresses: true,
auto_save: true, and atomic_edits: true. The CLI rejects a bridge missing a
required capability before sending program commands. It does not restart or
replay a failed command automatically. Explicit program save bypasses this
gate so pending edits can be saved in place before an explicit bridge restart.
Use -v/-vv/-vvv for warn/info/debug logs; --quiet suppresses
non-essential output.
Start with ghidra-cli doctor; use doctor --runtime for OSGi compatibility and
Ghidra's startup writes (see installation for probe side effects).
Startup errors identify the operation and path where available. Import failures
also carry detail.workflow_stage, project, import_status, analysis_status,
and the saved program when known. A saved import is retained if later bridge
startup fails. Fix the reported cause and follow detail.recovery (an argument
array); do not re-import. unknown means completion was not confirmed. A timeout
can leave a job running: inspect job list before retrying. Settings failures before
the Java script runs retain the launcher output instead of inventing a path.
Rust filesystem diagnostics include detail.io_kind, a stable snake_case
classification such as read_only_filesystem, permission_denied, or
not_found (other for unclassified kinds). detail.os_error is the native
numeric code when the I/O error exposes one, otherwise null. Use io_kind for
automation instead of parsing messages; wrappers can hide the numeric code while
retaining the classification.
Linux/WSL may need X11 libraries even headless because initialization loads AWT.
For libXtst.so.6 errors, install libxtst (Arch), libxtst6 (Debian/Ubuntu), or
libXtst (Fedora/RHEL). On Arch/Debian, JDK 21 packages are jdk21-openjdk and
openjdk-21-jdk, respectively. WSL2 is preferable for compatibility.
On Linux, discovery files are ~/.local/share/ghidra-cli/bridge-{md5}.port and
.pid, keyed by the canonical .rep directory. Liveness requires a valid port,
live PID, and TCP connectivity; bridge status also pings the protocol.
Startup and shutdown clean stale discovery under an OS-backed lifecycle lock;
bridge status only observes. The .starting lock file persists after release and must
not be deleted. Ghidra project lock files are never removed by CLI recovery;
do not manually delete them to bypass an owner. A live PID with missing or
unreachable discovery prevents cleanup/startup, and discovery PIDs are never
used for force termination. A busy program lane does not prove the bridge is
dead; inspect job list before restarting.