One Ghidra,
many heads.
Hydra Engine is a headless reverse-engineering engine for AI agents. One long-lived daemon holds Ghidra, its projects, its analysed programs and its warm decompilers, and serves every agent harness, MCP server and script on the machine at once.
Derived from NSA's Ghidra (Apache-2.0). Not affiliated with or endorsed by the NSA or the Ghidra project, and not affiliated with Marvel.
From the engine's README
measured- launch until the daemon is ready
- 348 ms
- open a 243,855-function program
- 847 ms
- launch until the first decompile
- 1.52 s
- a warm decompile
- 6.7–7.1 ms
Medians of 9 rounds on Ghidra master (12.3 DEV) with the session module, Windows 11, JDK 25.0.4, 24 threads; a 66.7 MB x64 executable with 243,855 functions, opened read-only, AOT and class search caches on. README, Performance
An agent session
What an agent session looks like
The first client starts the daemon; every later one joins it through a per-user endpoint file and finds the project, the program and the decompilers already warm. Name yourself with client and harness, and every status and busy answer says who is doing what.
- Read-only by default. A project opens without a lock file, so a Ghidra window can read it too.
- Imports once. The same file is refused by SHA-256.
- Any language. JSON lines over an authenticated loopback socket; Python ships a stdlib-only client.
>>> import ghidra_session as gs, 2.2 ms
>>> s = gs.connect(client='demo', harness='readme'), 643.3 ms
>>> s.call('open_project', path='demo.gpr', writable=True)['id'], 145.3 ms. Output: 'p1'
>>> s.call('import', file='hydra_demo.exe', analyze=True)['imported'], 15.52 s. Output: True
>>> s.call('import', file='hydra_demo.exe')['imported'] # same SHA-256: never twice, 4.2 ms. Output: False
>>> {k: s.call('info')[k] for k in ('format', 'language', 'functions')}, 2 ms. Output: {'format': 'Portable Executable (PE)', 'language': 'x86:LE:64:default', 'functions': 574}
>>> print(s.call('decompile', name='grow_heads')['c']), 248.2 ms. Output: int __cdecl grow_heads(int param_1,int param_2) { int iVar1; iVar1 = 0; if (0 < param_2) { do { if (param_1 == 0) { return 0; } param_1 = param_1 + 1; iVar1 = iVar1 + 1; } while (iVar1 < param_2); } return param_1; }
>>> s.call('decompile', name='grow_heads')['signature'], 3 ms. Output: 'int __cdecl grow_heads(int param_1,int param_2);'
Each tab is labelled with its source. Times are measured; nothing on this terminal is simulated.
One body, many heads
The heads come and go. The body stays.
In the myth the Hydra has one body and many heads. Here the body is one long-lived JVM holding Ghidra, its open projects, its analysed programs and its warm decompilers. The heads are the clients: agent harnesses, MCP servers, scripts. When one is cut off, its locks are freed and its unsaved edits dropped, and the others never notice.
What it does
Built for many agents on one machine
Inside, it is Ghidra: the same packages, modules and paths, so Ghidra scripts and extensions work unchanged. What Hydra Engine adds is one module, a shared session daemon, and a headless-only build. Features marked on main are in the repository but not yet in a release.
In the 12.3-hydra.1 release
- in 12.3-hydra.1
One shared daemon, fair lanes
One JVM per user holds Ghidra, its projects, programs and warm decompilers. Quick requests and long ones (analyze, import, script, save) run in separate lanes, admitted round-robin by client, so one agent's whole-program analysis never stalls another's 10 ms query.
Read more about One shared daemon, fair lanes - in 12.3-hydra.1
Read-only views without a lock
A project opens the way File > View Project does: no lock file, nothing written. Any number of clients, and a Ghidra window, can read it at the same time, without copying it first.
Read more about Read-only views without a lock - in 12.3-hydra.1
Upgrade cache: answers first
A program saved by an older Ghidra opens at once, upgraded in memory, while an upgraded copy is built in the background, in the long lane and only when no client waits. Later opens read the copy; the project is never touched.
Read more about Upgrade cache: answers first - in 12.3-hydra.1
Imports once
Any format a Ghidra loader accepts. A file whose SHA-256 is already in the project is never imported twice: the second import answers in milliseconds with the existing program.
Read more about Imports once - in 12.3-hydra.1
Scripts, contained
Any GhidraScript, Java or Python, with arguments. On a program you do not own it runs inside a transaction that is always rolled back, so it cannot change what others see.
Read more about Scripts, contained - in 12.3-hydra.1
A dead client costs nobody else
When a client disconnects or its process dies, its requests are cancelled, its unsaved changes discarded and logged, and its programs go back to read-only for the others.
Read more about A dead client costs nobody else - in 12.3-hydra.1
A headless build
gradle buildHeadless leaves out the window-only modules, help, javadoc and Python stubs: a 639 MB install against 862 MB for the full build with the GUI, with byte-identical decompiled C on the binaries tested.
Read more about A headless build - in 12.3-hydra.1
Release assets with checksums
Each release publishes the Windows x64 headless install as a zip, with a SHA256SUMS file built and tested by the release workflow on the unzipped install.
Read more about Release assets with checksums
On main, for the next release
- on main · next release
Forks: copy-on-write working copies
fork_project copies a project into a working copy while its source and read-only views stay open and in use: a block clone on ReFS (measured 204-225 ms for a 1.49 GB project), a full copy elsewhere.
Read more about Forks: copy-on-write working copies - on main · next release
Overlays: private hypotheses
A client's own annotation view of a shared program: renames, labels, comments, signatures and types that nobody else sees and nothing saves, until promote_overlay replays them into a fork.
Read more about Overlays: private hypotheses - on main · next release
Shared writing
Several clients write one program at once: each change its own transaction, journalled with its author; expect turns a lost update into a conflict that names the last editor.
Read more about Shared writing - on main · next release
Revision tokens and refresh
Every project and program carries a revision. Answers flag a read-only view whose project another process saved (stale), and refresh reopens it for all its clients at once, under the same keys.
Read more about Revision tokens and refresh - on main · next release
A versioned client and the hello check
hello and status report protocol, minClient, hydraVersion, ghidraVersion and installId; the client refuses an engine it does not fit, and releases ship it as hydra-client-<version>.zip.
Read more about A versioned client and the hello check - on main · next release
Per-request client and harness labels
One MCP server serving several agents labels each request; busy and conflict answers, status and cancel then name the agent, not just the connection.
Read more about Per-request client and harness labels - on main · next release
Parallel imports, a visible queue
Up to maxImports imports (default one per four CPUs, 1 to 4) load at once, into one project or several; the rest queue first-come, first-served, say who they wait behind with an estimate, and cancel cleanly.
Read more about Parallel imports, a visible queue
How it works
Watch the daemon share itself out
Three views, each drawn from a data file the site renders: who runs when, who holds which program, and where an agent's question spends its time.
- sample traceMany agents, one daemonSeven agents on six programs: two lanes, round-robin admission, a cancel, a client that dies.
- sample traceWho holds whatReaders, owners, shared writers, forks and overlays, step by step through the protocol.
- sample traceA question's lifeDecompile, xrefs, strings, rename, import, analyze: where the wall time goes, cold and warm.
Quick start
Running in a minute
You need a JDK 25 and Python 3.10 or later. Releases ship the headless install for Windows x64; on Linux and macOS, build it from source for now.
1. Download, check the SHA-256, unzip, start the daemon
PowerShellGet-FileHash hydra-engine-12.3-hydra.1-win_x86_64.zip # compare with SHA256SUMS Expand-Archive hydra-engine-12.3-hydra.1-win_x86_64.zip C:\tools $GS = "C:\tools\ghidra_12.3_DEV\Ghidra\Features\HeadlessSession\support\ghidra_session.py" python $GS ensure # starts the daemon if it is not running2. Ask it something
PowerShellpython $GS call open_project path=/re/MyProject # read-only view, no lock python $GS call open_program path=target.exe python $GS call decompile address=rva:0x1000 python $GS status # projects, programs, clients, lanes, memory3. Or connect from your harness
Pythonimport ghidra_session as gs with gs.connect(client="my-tool", harness="my-harness") as s: # joins the daemon, or starts it s.call("open_project", path="/re/MyProject") # read-only, no lock s.call("open_program", path="target.exe") print(s.call("decompile", name="main")["c"])