EIPC Developer Documentation v0.1.0

Inter-process communication protocol for EmbeddedOS components. Length-prefixed binary framing with JSON payloads, HMAC-SHA256 authentication, and transport over TCP or Unix sockets. C SDK header: <eipc.h>. Go server in eipc/server/.

📦 Wire Format

EIPC Frame Layout

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Frame Length (4 bytes)                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Version    |     Type      |          Flags (2 bytes)      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                   Sequence Number (4 bytes)                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               Header Length (2 bytes)                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    JSON Header (variable)                      |
|                          ...                                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 Payload Length (4 bytes)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    JSON Payload (variable)                     |
|                          ...                                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 HMAC-SHA256 (32 bytes, optional)               |
|                          ...                                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
FieldSizeDescription
Frame Length4 bytesTotal frame size (big-endian, excludes this field).
Version1 byteProtocol version (currently 1).
Type1 byte0=Intent, 1=Ack, 2=ToolRequest, 3=ToolResult, 4=Heartbeat, 5=Error.
Flags2 bytesBit 0: HMAC present, Bit 1: compressed, Bit 2: encrypted.
Sequence4 bytesMonotonic sequence number for ordering.
Header JSONvariableJSON object: service_id, request_id, timestamp, source.
Payload JSONvariableMessage-type-specific JSON payload.
HMAC32 bytesHMAC-SHA256 over version+type+flags+seq+header+payload (if flag set).

📦 Frame Codec API

Encode/decode EIPC frames. Header: <eipc.h>

eipc_status_t eipc_frame_encode(const eipc_frame_t *frame, uint8_t *buf, size_t buf_size, size_t *out_len)

Encode an EIPC frame into a byte buffer for transmission. Serializes header JSON, payload JSON, and optionally appends HMAC.

Parameters
frameconst eipc_frame_t *Frame to encode.
bufuint8_t *Output buffer.
buf_sizesize_tBuffer capacity.
out_lensize_t *Actual encoded length written.
Returns

EIPC_OK on success. EIPC_ERR_BUFFER if buffer too small. EIPC_ERR_INVALID on bad frame data.

eipc_status_t eipc_frame_decode(const uint8_t *buf, size_t buf_len, eipc_frame_t *frame)

Decode a byte buffer into an EIPC frame. Parses header JSON, payload JSON, and validates HMAC if present.

Parameters
bufconst uint8_t *Input buffer.
buf_lensize_tBuffer length.
frameeipc_frame_t *Output frame.
Returns

EIPC_OK on success. EIPC_ERR_PARSE on malformed data. EIPC_ERR_HMAC if HMAC verification fails.

🔒 HMAC Security

HMAC-SHA256 message authentication for frame integrity and authenticity.

void eipc_hmac_sign(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t mac[32])

Compute HMAC-SHA256 over the signable portion of a frame. The signable bytes include version, type, flags, sequence, header JSON, and payload JSON (excludes frame length and the MAC field itself).

Parameters
keyconst uint8_t *HMAC key (recommended: 32+ bytes).
key_lensize_tKey length in bytes.
dataconst uint8_t *Data to sign (from eipc_frame_signable_bytes).
data_lensize_tData length.
macuint8_t[32]Output: 32-byte HMAC.
Example
const uint8_t key[] = "my-secret-hmac-key-at-least-32-bytes!!";
uint8_t signable[4096];
size_t sig_len = eipc_frame_signable_bytes(&frame, signable, sizeof(signable));
uint8_t mac[32];
eipc_hmac_sign(key, strlen((char*)key), signable, sig_len, mac);
memcpy(frame.hmac, mac, 32);
frame.flags |= EIPC_FLAG_HMAC;
bool eipc_hmac_verify(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, const uint8_t mac[32])

Verify HMAC-SHA256. Returns true if the computed MAC matches the provided MAC (constant-time comparison).

Parameters
key/key_lenuint8_t*/size_tHMAC key.
data/data_lenuint8_t*/size_tSigned data.
macuint8_t[32]MAC to verify against.
Returns

true if valid. false if mismatch.

🔌 Transport API

TCP and Unix socket transport with length-prefixed framing.

eipc_status_t eipc_transport_connect(eipc_socket_t *sock, const char *address)

Connect to an EIPC server. Address format: "tcp://host:port" or "unix:///path/to/socket".

Parameters
sockeipc_socket_t *Output socket handle.
addressconst char *Server address.
Returns

EIPC_OK on success. EIPC_ERR_CONNECT on failure. EIPC_ERR_RESOLVE if hostname unresolvable.

eipc_status_t eipc_transport_listen(eipc_socket_t *sock, const char *address)

Bind and listen on an address for incoming EIPC connections.

Parameters
sockeipc_socket_t *Output listening socket.
addressconst char *Bind address (e.g., "tcp://0.0.0.0:8421").
Returns

EIPC_OK on success.

eipc_status_t eipc_transport_accept(eipc_socket_t listen_sock, eipc_socket_t *client_sock, char *remote_addr, size_t remote_addr_size)

Accept a new client connection. Blocking call that returns when a client connects.

Parameters
listen_sockeipc_socket_tListening socket from eipc_transport_listen.
client_sockeipc_socket_t *Output client socket.
remote_addrchar *Output remote address string (can be NULL).
remote_addr_sizesize_tBuffer size for remote_addr.
Returns

EIPC_OK on success.

eipc_status_t eipc_transport_send_frame(eipc_socket_t sock, const eipc_frame_t *frame) / eipc_transport_recv_frame(eipc_socket_t sock, eipc_frame_t *frame)

Send or receive a complete EIPC frame over a socket. Handles length-prefix framing automatically. recv_frame blocks until a complete frame is received.

Parameters
sockeipc_socket_tConnected socket.
frameeipc_frame_t *Frame to send or output frame buffer.
Returns

EIPC_OK on success. EIPC_ERR_IO on network error. EIPC_ERR_CLOSED if peer disconnected.

void eipc_transport_close(eipc_socket_t sock)

Close a socket and free associated resources.

💻 Client API

High-level client for sending intents, tool requests, and heartbeats.

eipc_status_t eipc_client_init(eipc_client_t *c, const char *service_id)

Initialize a client with a service identifier. The service_id is included in all message headers for routing.

Parameters
ceipc_client_t *Client to initialize.
service_idconst char *Service identifier (e.g., "eni-provider-1", "eai-agent").
Returns

EIPC_OK on success.

eipc_status_t eipc_client_connect(eipc_client_t *c, const char *address, const char *hmac_key)

Connect to an EIPC server with optional HMAC authentication. If hmac_key is non-NULL, all subsequent messages are HMAC-signed.

Parameters
ceipc_client_t *Initialized client.
addressconst char *Server address (e.g., "tcp://192.168.1.100:8421").
hmac_keyconst char *HMAC key (NULL to disable signing).
Returns

EIPC_OK on success. EIPC_ERR_CONNECT on failure.

eipc_status_t eipc_client_send_intent(eipc_client_t *c, const char *intent, float confidence)

Send a decoded intent event to the server. Used by ENI providers to forward neural intents.

Parameters
ceipc_client_t *Connected client.
intentconst char *Intent name.
confidencefloatConfidence score 0.0-1.0.
Returns

EIPC_OK on success.

eipc_status_t eipc_client_send_tool_request(eipc_client_t *c, const char *tool, const eipc_kv_t *args, int arg_count)

Send a tool execution request to the server. The server routes to the appropriate tool handler.

Parameters
ceipc_client_t *Connected client.
toolconst char *Tool name.
argsconst eipc_kv_t *Key-value argument pairs.
arg_countintNumber of arguments.
Returns

EIPC_OK on success.

eipc_status_t eipc_client_send_heartbeat(eipc_client_t *c) / eipc_client_receive(eipc_client_t *c, eipc_message_t *msg) / eipc_client_close(eipc_client_t *c)

send_heartbeat: Send keepalive. receive: Blocking receive of next message. close: Disconnect and free resources.

🌐 Server API

eipc_status_t eipc_server_init(eipc_server_t *s) / eipc_server_listen(eipc_server_t *s, const char *address, const char *hmac_key)

Initialize and start listening for connections. HMAC key enables mandatory authentication for all clients.

eipc_status_t eipc_server_accept(eipc_server_t *s, eipc_conn_t *conn)

Accept a client connection. Blocking call.

Parameters
seipc_server_t *Listening server.
conneipc_conn_t *Output connection handle.
Returns

EIPC_OK on success.

eipc_status_t eipc_server_receive(eipc_conn_t *conn, eipc_message_t *msg) / eipc_server_send_ack(eipc_conn_t *conn, const char *request_id, const char *status) / eipc_server_send_message(eipc_conn_t *conn, const eipc_message_t *msg)

receive: Read next message from client. send_ack: Send acknowledgment with request_id and status. send_message: Send arbitrary message to client.

📄 JSON Helpers

eipc_status_t eipc_header_to_json/eipc_header_from_json / eipc_intent_to_json/eipc_intent_from_json / eipc_ack_to_json/eipc_ack_from_json / eipc_tool_request_to_json / eipc_heartbeat_to_json

Serialize/deserialize EIPC header, intent, ack, tool request, and heartbeat structures to/from JSON strings. Minimal JSON implementation with no external dependencies.

Intent JSON Format
// eipc_intent_to_json output:
{
  "intent": "move_cursor_left",
  "confidence": 0.92,
  "source": "neuralink_n1",
  "timestamp": "2026-03-31T01:30:00Z"
}

// eipc_ack_to_json output:
{
  "request_id": "req-abc123",
  "status": "ok",
  "timestamp": "2026-03-31T01:30:00Z"
}

// eipc_tool_request_to_json output:
{
  "tool": "gpio_write",
  "args": {"pin": "12", "value": "true"},
  "request_id": "req-def456"
}

💻 Go Server/Client Examples

Go Server

package main

import (
    "fmt"
    "github.com/embeddedos-org/eipc/server"
)

func main() {
    srv := server.New(server.Config{
        Address:  "tcp://0.0.0.0:8421",
        HMACKey:  "my-secret-key-32-bytes-minimum!!",
    })

    srv.OnIntent(func(conn *server.Conn, intent string, confidence float64) {
        fmt.Printf("[%s] Intent: %s (%.0f%%)\n", conn.ServiceID, intent, confidence*100)
        conn.SendAck(conn.LastRequestID(), "ok")
    })

    srv.OnToolRequest(func(conn *server.Conn, tool string, args map[string]string) {
        fmt.Printf("[%s] Tool: %s args=%v\n", conn.ServiceID, tool, args)
        result := executeLocalTool(tool, args)
        conn.SendMessage(server.ToolResult{
            RequestID: conn.LastRequestID(),
            Result:    result,
        })
    })

    fmt.Println("EIPC server listening on :8421")
    srv.ListenAndServe()
}

Go Client

package main

import (
    "fmt"
    "github.com/embeddedos-org/eipc/client"
)

func main() {
    c := client.New("eni-neuralink-1")
    err := c.Connect("tcp://192.168.1.100:8421", "my-secret-key-32-bytes-minimum!!")
    if err != nil {
        panic(err)
    }
    defer c.Close()

    // Send decoded neural intent
    c.SendIntent("move_cursor_left", 0.92)

    // Send tool request and wait for result
    result, err := c.SendToolRequest("gpio_write", map[string]string{
        "pin":   "12",
        "value": "true",
    })
    fmt.Printf("Tool result: %s\n", result)

    // Heartbeat loop
    go func() {
        for {
            c.SendHeartbeat()
            time.Sleep(5 * time.Second)
        }
    }()
}

🔧 C SDK Example

// C SDK client - connects to EIPC server and sends intents
#include <eipc.h>

int main(void) {
    eipc_client_t client;
    eipc_client_init(&client, "eni-sensor-1");

    eipc_status_t rc = eipc_client_connect(&client,
        "tcp://192.168.1.100:8421",
        "my-secret-key-32-bytes-minimum!!");
    if (rc != EIPC_OK) {
        fprintf(stderr, "Connect failed: %d\n", rc);
        return 1;
    }

    // Send intent
    eipc_client_send_intent(&client, "move_cursor_left", 0.92f);

    // Send tool request
    eipc_kv_t args[] = {
        {"pin", "12"}, {"value", "true"}
    };
    eipc_client_send_tool_request(&client, "gpio_write", args, 2);

    // Receive response
    eipc_message_t msg;
    if (eipc_client_receive(&client, &msg) == EIPC_OK) {
        printf("Response type=%d\n", msg.type);
    }

    eipc_client_close(&client);
    return 0;
}

Thread Safety: Transport layer is NOT thread-safe per socket. Use one socket per thread. HMAC functions are stateless and thread-safe. Client/Server APIs are NOT thread-safe per instance.