Quicx
§ 02.03Core Concepts

Binary Protocol

Every frame on the wire is a 6-byte header followed by a variable-length payload. No framing ambiguity, no partial reads, no text encoding — parsing is a couple of pointer reads.

Frame header

total header = 6 bytes fixedtotal message = 6 + length bytes
version
Protocol revision. Currently 0x01. The daemon rejects any other version with MSG_ERROR 0x02 so protocol evolution is additive and opt-in.
type
Message opcode — one of the 11 types below. The daemon routes on type alone; producers and workers speak the same header shape.
length
32-bit big-endian unsigned integer: the payload size in bytes. Zero is legal for MSG_READY, MSG_WAIT, MSG_HEARTBEAT, MSG_PONG and MSG_STATS.
payload
Exactly length bytes. The per-type layouts below are the full contract — there is no escaping, no delimiters and no padding.

Message types

TypeNameDirection
0x01MSG_SUBMITproducer → daemon
0x02MSG_OKdaemon → producer
0x03MSG_ERRORdaemon → producer
0x04MSG_READYworker → daemon
0x05MSG_TASKdaemon → worker
0x06MSG_DONEworker → daemon
0x07MSG_FAILEDworker → daemon
0x08MSG_WAITdaemon → worker
0x09MSG_HEARTBEATeither direction
0x0AMSG_PONGeither direction
0x0BMSG_STATSmonitor → daemon
0x0CMSG_STATS_RESPONSEdaemon → monitor

Payload formats

0x01MSG_SUBMITproducer → daemon
[type_len : 1 byte][type : type_len bytes][payload : rest of bytes]
type = "send_email"
payload = {"to":"user@gmail.com"}
bytes   = [10][send_email][{"to":"user@gmail.com"}]
0x02MSG_OKdaemon → producer
[task_id : 4 bytes]
task_id = 0x00000A42  →  accepted task id = 2626
0x03MSG_ERRORdaemon → producer
[error_code : 1 byte][message : rest of bytes]
CodeMeaning
0x01queue full — PMAD pool exhausted
0x02invalid message (bad version / length / type)
0x03payload too large for the largest size class
0x04unknown task type
0x04MSG_READYworker → daemon
(no payload — length = 0)
Sent once per connection, immediately after connect, to register
the socket as an idle worker. The daemon replies with MSG_TASK or
MSG_WAIT.
0x05MSG_TASKdaemon → worker
[task_id : 4 bytes][type_len : 1 byte][type : type_len bytes][payload : rest]
Mirror of MSG_SUBMIT with the task id prepended. The worker dispatches
by type and replies with MSG_DONE or MSG_FAILED carrying the same id.
0x06MSG_DONEworker → daemon
[task_id : 4 bytes]
Confirms successful completion. The daemon frees the task slot back
to PMAD before responding to any producer waiting on this id.
0x07MSG_FAILEDworker → daemon
[task_id : 4 bytes][reason : rest of bytes]
reason is a UTF-8 string propagated verbatim to producers that
observe the task, and logged by the daemon.
0x08MSG_WAITdaemon → worker
(no payload — length = 0)
Sent in place of MSG_TASK when the queue is empty. The worker keeps
the socket open and issues another MSG_READY after a short backoff.
0x09MSG_HEARTBEATboth directions
(no payload — length = 0)
Liveness probe. Either side may send it; the receiver replies with
MSG_PONG. Intended for long-idle worker sockets behind stateful
load balancers.
0x0AMSG_PONGboth directions
(no payload — length = 0)
The only valid reply to MSG_HEARTBEAT. Shape-symmetric with
MSG_HEARTBEAT for trivial framing.
0x0BMSG_STATSmonitor → daemon
(no payload — length = 0)
Requests a one-shot metrics snapshot. The daemon responds with
MSG_STATS_RESPONSE.
0x0CMSG_STATS_RESPONSEdaemon → monitor
[queue_depth : 4 bytes][workers_total : 4 bytes][workers_idle : 4 bytes][pmad_bytes_used : 8 bytes][pmad_bytes_total : 8 bytes]
All integers are big-endian. The 28-byte body is a fixed shape so
dashboards can parse it without a schema.