CLI
One Python file: launcher, daemon manager and client.
ghidra_session.py replaces Ghidra's .bat and .sh launchers for the daemon. It finds the JDK, builds the classpath, starts the JVM detached, and talks to it. It needs Python 3.10 and nothing outside the standard library.
Commands
| Command | Does |
|---|---|
ensure | Starts the daemon unless it's running; prints its endpoint, without the token. |
status | Projects, programs and who uses them, clients, lanes, memory. |
call CMD key=value... | Sends one request as a new client that disconnects afterwards. |
stop [--force] | Shuts the daemon down; refused while other clients are connected, unless --force. |
kill | Kills the daemon's JVM outright, for a wedged daemon. |
version | Client version, protocol and release. Needs no daemon. |
config | The effective configuration, JDK and install. |
serve | Runs the daemon in the foreground, for a service manager. |
stdio | A private session on this process's stdin and stdout: no daemon, no socket. |
aot | Builds the AOT class cache (JDK 25+). |
command | Prints the Java command line it would run. |
One-off requests
call turns key=value pairs into a request. Values that parse as JSON are sent as JSON, so writable=true is a boolean and limit=20 a number.
1python $GS call ping2python $GS call projectsEach call is its own client, and a client's open projects and programs close when it leaves. For anything that takes more than one request, keep one connection: from Python, gs.connect(); from a shell, stdio below.
A private session over stdio
stdio runs a session inside this process and reads requests from stdin, one JSON object per line. The first line out is the ready event. Nothing is shared and the JVM starts cold, so it suits scripts and CI more than agents.
1python $GS stdio <<'EOF'2{"id": 1, "cmd": "open_project", "path": "/re/MyProject"}3{"id": 2, "cmd": "open_program", "path": "target.exe"}4{"id": 3, "cmd": "decompile", "name": "main"}5EOFGlobal options
| Option | Sets |
|---|---|
--ghidra | The install, when the script isn't inside one. |
--state | The state directory (endpoint, locks, logs, caches). |
--instance | The daemon's name; run several side by side with different names. |
--java | The JDK home. |
--max-heap | The JVM's -Xmx. |
--gc | g1, zgc, parallel or default. |
--mode | fast (default classpath and AOT cache) or standard (Ghidra's own class loader). |
--tmpdir | Where Ghidra keeps unsaved database buffers. |
Each option also has a config.json key and most have an environment variable; see Configuration.
Lifecycle
A daemon stays up until stop, kill, or idleTimeout seconds without clients (0, the default, means stay up). It starts detached from the client that launched it, so it outlives the harness that happened to start it.
Exit codes worth knowing: 3 when a second daemon of the same instance starts (it exits at once), 4 when the client refuses an engine it can't drive.