IPC
The wire format: framing, handshake, and the serialized value encoding
Required One chapter of the Open Q Language specification. README.txt states what must be implemented, how conformance is defined, and how rule IDs work.
This chapter specifies the bytes on the wire. It is the interoperability contract: two implementations conform when either can read what the other writes. The same encoding is what -8! produces and -9! consumes, so an implementation can be checked against it without a network.
Every byte sequence below was observed from the reference implementation.
IPC-00011. Framing
Every message is an 8-byte header followed by one serialized value.
offset size meaning
0 1 endianness of this message: 1 little, 0 big
1 1 message type: 0 async, 1 sync, 2 response
2 1 compressed flag: 0 uncompressed, 1 compressed
3 1 unused (0)
4 4 TOTAL message length, header included, in the
endianness given by byte 0
The length counts the header, so a boolean atom message is 10 bytes, not 2.
-8!0b -> 01 00 00 00 0a 00 00 00 ff 00
| | | | \--------/ \---/
| | | unused len=10 payload
| | not compressed
| async (what -8! stamps)
little-endian
IPC-00021.1 Endianness
A reader MUST honour byte 0 rather than assume its own order: the length field and every multi-byte value in the payload are in the sender's order. JVM clients send big-endian. A reply need not match the request's order; the peer adapts from byte 0.
IPC-00031.2 Message type
0 async fire and forget. The receiver MUST NOT reply. 1 sync the receiver MUST reply with exactly one type-2 message. 2 response the reply to a sync request, or an error (section 5).
-8! stamps type 0. The transport sets the real type; the body encoding is identical in all three cases.
Verified against the reference over a socket: a type-1 "2+3" is answered with 01 02 00 00 11 00 00 00 f9 05 00 00 00 00 00 00 00 — a type-2 frame carrying the long atom 5. The same body sent as type 0 draws no reply.
IPC-00042. Handshake
Before any framed message, the client sends a raw, UNFRAMED byte string:
"user:password" , capability_byte , 0x00
The capability byte is the highest protocol version the client supports. The server replies with ONE raw byte: the version it agrees to use, which is at most what the client asked for. No header is involved in either direction.
client -> 03 00 (empty credentials, capability 3)
server -> 03 (agreed)
Credentials may be empty, as above. A server that rejects the connection closes it instead of replying. After the single reply byte, both directions speak framed messages only.
IPC-00053. Value encoding
A payload is one value. Every value begins with a one-byte TYPE CODE, which is the language's type code (core.txt 4) taken as a SIGNED byte: atoms are negative and appear as 0xff..0xee, vectors are positive.
IPC-00063.1 Atoms: type byte, then the value
No count, no attribute byte.
code hex type payload
-1 ff boolean 1 byte
-2 fe guid 16 bytes, big-endian as displayed
-4 fc byte 1 byte
-5 fb short 2 bytes
-6 fa int 4 bytes
-7 f9 long 8 bytes
-8 f8 real 4 bytes (IEEE)
-9 f7 float 8 bytes (IEEE)
-10 f6 char 1 byte
-11 f5 symbol NUL-TERMINATED bytes, variable length
-12 f4 timestamp 8 bytes ns since 2000.01.01
-13 f3 month 4 bytes months since 2000.01
-14 f2 date 4 bytes days since 2000.01.01
-15 f1 datetime 8 bytes IEEE days since 2000.01.01
-16 f0 timespan 8 bytes ns duration
-17 ef minute 4 bytes
-18 ee second 4 bytes
-19 ed time 4 bytes ms
Symbols are the only variable-length atom: `abc is f5 61 62 63 00, and the empty symbol ` is f5 00.
Null and infinity are the ordinary sentinels, not a special encoding: 0N is f9 followed by i64 MIN, 0Ng is fe followed by 16 zero bytes.
IPC-00073.2 Simple vectors: type, attribute, count, elements
A positive type code, then ONE attribute byte, then a 4-byte element COUNT, then the elements back to back with no per-element type byte.
1 2 3 -> 07 00 03000000 0100.. 0200.. 0300..
| | \------/
| | count = 3
| attribute (section 3.6)
type 7 = long vector
Char vectors carry no terminator: "abc" is 0a 00 03000000 61 62 63. Symbol vectors carry one NUL per element: `a`b is 0b 00 02000000 61 00 62 00.
IPC-00083.3 General list
Type 0, attribute byte, count, then each element as a COMPLETE value with its own type byte.
() -> 00 00 00000000
(1;`a) -> 00 00 02000000 f9 0100000000000000 f5 6100
IPC-00093.4 Dictionary, table, keyed table
dict 99 (0x63) then TWO values: keys, then values. No attribute byte,
no count — the two values carry their own.
`a`b!1 2 -> 63 0b 00 02000000 610062 00 07 00 02000000 ...
table 98 (0x62) then ONE attribute byte, then a DICTIONARY of column
name vector -> column list.
([]a:1 2) -> 62 00 63 0b 00 01000000 6100 00 00 01000000 ...
keyed table
a DICTIONARY (99) whose key value and value value are both TABLES.
It is not a distinct wire type.
([k:1 2]v:3 4) -> 63 62 00 63 ... 62 00 63 ...
IPC-00103.5 Functions and singletons
100 (0x64) lambda: a NUL-terminated context/namespace string, then the
source text as a char vector. {x+y} is
64 00 0a 05000000 7b782b797d — the lambda travels as SOURCE,
not as compiled form, which is why any runtime can read it.
101 (0x65) unit / generic null (::) : one following byte, 0. 102 (0x66) a primitive verb, as a one-byte index into the primitive
table. (+) is 66 01. The index table is shared by convention
between implementations and is the least portable part of this
chapter.
IPC-00113.6 The attribute byte
Simple vectors and tables carry their attribute on the wire; it is not lost in transit and not re-derived by the receiver.
0 none 1 `s (sorted) 2 `u (unique)
3 `p (parted) 4 `g (grouped)
`s#1 2 3 -> 07 01 03000000 ...
`u#`a`b -> 0b 02 02000000 ...
`p#`a`a -> 0b 03 02000000 ...
`g#`a`b -> 0b 04 02000000 ...
IPC-00123.7 What does not survive
ENUMERATIONS ARE RESOLVED TO SYMBOLS. A value of type 20h is sent as a plain symbol vector (type 11); the domain does not travel and the receiver gets no enumeration back.
s:`a`b; -8!`s$`a`b -> 0b 00 02000000 610062 00
This is the one place where a round-trip is not identity, and any runtime that keeps enumerations must accept that IPC flattens them. Handles are process-local integers and are never serialized at all.
IPC-00134. Compression
Header byte 2 flags a compressed payload. The reference implementation does NOT compress same-host connections: over loopback it left byte 2 at 0 for an 80,014-byte message of a single repeated long, which is as compressible as a message gets. -8! never compresses either — count -8!10000#1 is 80014.
OPEN: the compressed payload encoding is not pinned by this chapter. It
could not be observed without a non-loopback peer, and this specification
does not state bytes it has not seen. A conformant runtime must therefore
be prepared to RECEIVE a compressed frame from kdb+ over a real network,
and is free never to SEND one. This is a gap to close, not a claim that
compression is absent.
IPC-00145. Errors and the reserved codes
An error in reply to a sync request is a type-2 frame whose payload is type 128 (0x80) followed by the NUL-terminated error text.
The ! verb's reserved negative left arguments (core.txt 5) expose this codec to the language:
-8!x serialize x to a byte vector (async header, type 0)
-9!b deserialize a byte vector back to a value
-18!x compress a byte vector
-19!x ... and the file variants
-9!-8!x is identity for every value except enumerations (section 3.7):
(-9!-8!([]a:1 2))~([]a:1 2) is 1b.Source: spec/ipc.txt