Turn it on
The API is off by default. Enable it in Sigil ▸ Settings… ▸ Advanced ▸ Local automation API. The app then listens on a Unix domain socket at:
~/Library/Application Support/Sigil/sigil.sock
The socket is owned by your user with permissions no one else can read (mode 0600), and nothing is exposed to the network. To drive Sigil from another machine, forward the socket over SSH:
ssh -L /tmp/sigil.sock:"$HOME/Library/Application Support/Sigil/sigil.sock" mac.local
The protocol
One JSON object per line, UTF-8, in both directions. On connect the server sends a hello: the versioned handshake, which also carries the full command catalog. The schema grows additively within v1.
{"hello":{"api":"sigil-api:v1","app":"Sigil","version":"0.1.13","build":"…",
"commands":[{"name":"open","primaryArg":"path","usage":"open <path> — …"}, …]}}
Requests carry a verb name and an args object. An id is optional and echoed back in the reply:
{"id":1,"command":"open","args":{"path":"/captures/pager1.sigmf"}}
{"id":1,"ok":true,"failures":[]}
Success is an empty failure list. A command succeeds only if its postcondition held (the decode finished, the window appeared, the layout took); otherwise the reply lists what failed. Commands execute strictly in order, one at a time across all connections, and each runs to completion before its reply arrives, so issue them sequentially and trust the answer. v1 is request and response only; there is no event push.
Argument values use the same mini-grammars as the app and the CLI: transform names like whiten:PN9, framing specs like sync or 128:32, layout operations like split:bits:trailing:decoder. Arguments that take a list accept a JSON array or one comma-separated string.
The sigil app client
The bundled CLI is the ready-made client. A bare value goes to the verb's primary argument; everything else is key=value:
sigil app list # every verb, from the hello sigil app open ~/captures/pager1.sigmf sigil app select low=929.6e6 high=929.65e6 sigil app run-decoder flex sigil app select-tab bits sigil app bits-export /tmp/bits.json sigil app render-window /tmp/window.png sigil app workspace "Blind RE" --json # raw JSON reply
sigil app steps runs a quoted sequence of verbs over one connection and stops at the first failure — the scriptable form of a driven session.
Any other language
The core of a Python client is a dozen lines:
import json, os, socket
path = "/captures/recording.sigmf" # replace with your recording
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(os.path.expanduser("~/Library/Application Support/Sigil/sigil.sock"))
reader = sock.makefile("rb")
hello = json.loads(reader.readline())
sock.sendall(json.dumps({"command": "open", "args": {"path": path}}).encode() + b"\n")
reply = json.loads(reader.readline())
For exploration, nc works straight from the shell:
echo '{"command":"render-window","args":{"path":"/tmp/w.png"}}' | \
nc -U ~/Library/Application\ Support/Sigil/sigil.sock
Verbs
sigil app list (or the hello's commands array) is the authoritative, always-current catalog for your installed version. The families: session setup (open, select, save-capture, set-audio-mode, demod-analysis); the display viewport (zoom-selection, box-zoom); audio (play-audio, record-audio); bookmarks; devices (scan-devices reports what was found and which driver libraries loaded); decoders (run-decoder, select-tab, last-result for the machine-readable results); the transport-stream player; the Symbols, Demod, and Bits workbenches (demod-family, demod-burst, the bits-* family through bits-export); walkthroughs; panes, dock tabs, workspaces, and window layout; issue reporting; window renders; and the app lifecycle (close-capture, quit). render-window captures the laid-out window with the Metal-drawn plots rendered in. Only video playback surfaces are not captured.
Getting help
The docs page covers the app and the rest of the CLI, and support has contact details if the API does something these pages don't explain.