Clients
Every head names itself, and leaves cleanly.
A client is any process holding a connection to the daemon: an agent harness, an MCP server, a script, a test. The daemon doesn't care which. It cares about names, because names are how everyone else learns who holds what.
Name yourself
hello carries client (your tool) and harness (the agent running it). status lists both, and a busy or conflict answer names whoever is in the way:
{"id": 9, "ok": false, "error": {"code": "busy", "message": "...", "details": {"holder": "client 3 (agent-b, claude-code) script Export.java", "holderInfo": {"client": 3, "name": "agent-b", "harness": "claude-code", "command": "script Export.java", "heldMs": 41200}, "suggest": "retry"}}}Names are free-form. Use the harness's usual name, such as claude-code, codex, opencode or qoder, so people reading status know what they're looking at.
One connection, several agents
An MCP server serves several agents over one connection. Any request may carry its own client and harness, which replace the connection's names for that request in holders, status, the import queue and cancel.
1agent_a = s.labelled(client="agent-a", harness="claude-code")2agent_a.call("decompile", address="0x1000")3agent_a.cancel_all() # cancels agent-a's requests onlyLabels tell callers apart and scope cancellation. They aren't access control: anyone with the token can send any label, and ownership stays with the connection.
Ordering
Without parallel, one client's requests run in the order it sent them; different clients always run in parallel. Send parallel: true when a connection carries independent callers, or when you want to cancel or ask for status while a long request runs.
Other languages
The Python client is a convenience, not a requirement. Any language that can open a TCP socket can be a head:
- Run
python ghidra_session.py ensureonce, so a daemon is up. - Read
default.jsonin the state directory:%LOCALAPPDATA%\GhidraSessionon Windows,~/Library/Application Support/GhidraSessionon macOS,~/.local/state/ghidra-sessionon Linux. - Connect to its loopback
portand send JSON lines. The first must behellowith the file'stoken. - Refuse to continue if the answer's
protocolisn't2, or if your client version is older than itsminClient.
{"id": 1, "cmd": "hello", "client": "my-tool", "harness": "codex", "clientVersion": "1.0.0", "token": "<from default.json>"}{"id": 1, "ok": true, "ms": 1, "result": {"protocol": 2, "minClient": "1.0.0", "hydraVersion": "12.3-hydra.2", "ghidraVersion": "12.3", "installId": "...", ...}}Leaving
Closing the connection is the whole goodbye. Your requests are cancelled, uncommitted changes rolled back, unsaved changes to programs you owned discarded (and logged), and those programs return to read-only for everyone else. A crash is handled the same way, because the OS resets the socket.
Read-only projects you opened stay warm for the next client. A writable project closes, releasing its lock, when its last user leaves.