microinit exposes a Unix domain stream socket for control and logs. The CLI (microinit start, list, logs, …) uses this protocol; you can also implement a client in any language.
Default path: $DATA_DIR/run/microinit.sock (hub default /data/run/microinit.sock; overridable with --socket on both the daemon and clients, or via the socket field in JSON config). The daemon creates the socket's parent directory if it does not exist.
Each message is one length-prefixed JSON frame:
| Bytes | Content |
|---|---|
| 4 | Payload length as little-endian u32 |
| N | UTF-8 JSON object |
- Maximum payload size: 16 MiB (
16777216bytes). - One request per connection is the usual pattern for short commands;
logswithfollow: truekeeps the connection open and streams manylogresponses. - Concurrent client handlers are capped (32). Excess clients receive an error response.
Requests and responses are tagged with a string field type (snake_case).
Unknown fields should be ignored by clients where possible; the server may add fields later.
{ "type": "list" }Response: list with all services.
Daemon build/runtime snapshot: version (ELF release section or dev), build commit/time, hostname, uptime, service counts, effective OpenTelemetry settings.
{ "type": "info" }Response: info with a DaemonInfo object:
| Field | Description |
|---|---|
version |
Release tag from ELF .microinit.version, or dev |
tag_commit |
Commit of the release tag (ELF) |
build_commit |
CI / build-time git SHA |
build_time |
UTC build timestamp (ISO-8601) |
pid |
microinit process ID |
hostname |
Host name |
uptime_secs |
Seconds since supervisor start |
socket |
IPC socket path |
mode |
init (machine reboot/poweroff) or supervise (process exit only) |
services_total |
Registered services |
services_running |
Services in running state |
otel_enabled |
Effective telemetry on/off |
otel_endpoint |
OTLP HTTP URL used by microinit |
otel_protocol |
Exporter protocol (http, etc.) |
otel_service_name |
OTEL_SERVICE_NAME |
otel_export_interval_secs |
Metric export interval (seconds) |
These otel_* fields mirror the effective openTelemetry block in
microinit.json after overlaying process environment and
$DATA_DIR/etc/otel.env (same precedence as runtime export). JSON config keys:
openTelemetry (JSON) |
Env / IPC |
|---|---|
enable |
ENABLE_TELEMETRY, OTEL_SDK_DISABLED (disable only) → otel_enabled |
endpoint |
OTEL_EXPORTER_OTLP_ENDPOINT → otel_endpoint |
protocol |
OTEL_EXPORTER_OTLP_PROTOCOL → otel_protocol |
serviceName |
OTEL_SERVICE_NAME → otel_service_name |
exportIntervalSecs |
OTEL_METRIC_EXPORT_INTERVAL (ms) → otel_export_interval_secs |
headers |
OTEL_EXPORTER_OTLP_HEADERS (not shown in info) |
CLI microinit info --json uses the same snake_case field names as IPC.
{ "type": "status", "name": "redis" }Response: status or error if unknown.
Rich status for one service: counters, uptime, direct deps, reverse deps, transitive dependency subgraph, and the last 16 lifecycle events.
{ "type": "describe", "name": "nginx" }Response: describe or error if unknown.
{ "type": "start", "name": "redis", "force": false }| Field | Default | Meaning |
|---|---|---|
name |
required | Service name |
force |
false |
If true, start even when dependsOn are not satisfied |
Response: ok with an optional human-readable message, for example:
"redis: starting""redis: waiting for dependencies (network)""redis: starting with --force (unmet dependencies: network)"
{ "type": "stop", "name": "redis" }Response: ok or error.
{ "type": "restart", "name": "redis" }Response: ok or error.
Enable or disable a service and persist the override file.
{ "type": "enable", "name": "dropbear", "enabled": true }{ "type": "enable", "name": "dropbear", "enabled": false }Response: ok or error.
Disabling stops the service; enabling requests a start (subject to dependencies).
{
"type": "logs",
"name": "redis",
"follow": false,
"lines": 100
}| Field | Default | Meaning |
|---|---|---|
name |
omit / null |
One service; omit for mixed stream |
follow |
required in practice | true = stream until the client disconnects |
lines |
config logs.lines |
How many historical lines to send first |
Response stream:
- Zero or more
{ "type": "log", "line": { … } } - If
followisfalse, a final{ "type": "ok" } - If
followistrue, furtherlogframes until disconnect (no trailingok)
{ "type": "shutdown", "mode": "reboot" }mode is one of: reboot, poweroff, halt.
Response: ok, then the daemon begins ordered shutdown:
initmode: stop all services, run late-unmount script, then reboot/poweroff/halt.supervisemode: stop all services, sync, and exit the process (no unmount script, noreboot(2)). Themodefield is accepted but ignored for machine power state.
Operators normally use the companion shutdown binary (shutdown -r now, …) which sends this request and falls back to BusyBox /sbin/{poweroff,reboot,halt} if the socket is missing.
{ "type": "ok" }{ "type": "ok", "message": "redis: starting" }message is optional (omitted or null when unused).
{ "type": "error", "message": "…" }{
"type": "list",
"services": [
{
"name": "redis",
"state": "running",
"pid": 1234,
"restarts": 0,
"liveness_failures": 0,
"enabled": true,
"labels": { "created-by": "bigfred" }
}
]
}pid may be null when not tracked. liveness_failures counts how many times livenessProbe failed since boot (or since the service was added on reload). labels is omitted when empty; keys come from the service config / drop-in.
{
"type": "status",
"status": {
"name": "redis",
"state": "running",
"pid": 1234,
"restarts": 0,
"liveness_failures": 0,
"enabled": true,
"labels": { "created-by": "bigfred" }
}
}{
"type": "describe",
"describe": {
"status": {
"name": "nginx",
"state": "running",
"pid": 1240,
"restarts": 2,
"liveness_failures": 1,
"enabled": true
},
"uptime_secs": 4320,
"depends_on": [
{ "name": "php-fpm", "state": "running" }
],
"dependents": [
{ "name": "cache", "state": "stopped" }
],
"dep_nodes": [
{ "name": "cache", "state": "stopped" },
{ "name": "nginx", "state": "running" },
{ "name": "php-fpm", "state": "running" }
],
"dep_edges": [
["php-fpm", "nginx"],
["nginx", "cache"]
],
"events": [
{
"ts": "2026-08-04T18:40:01.123Z",
"kind": "state_change",
"from": "pending",
"to": "starting"
},
{
"ts": "2026-08-04T18:51:10.001Z",
"kind": "liveness_failed",
"detail": "HTTP 503"
},
{
"ts": "2026-08-04T18:51:10.002Z",
"kind": "restart"
}
]
}
}| Field | Meaning |
|---|---|
depends_on |
Direct dependsOn (who this service needs); sorted by name |
dependents |
Who lists this service in their dependsOn; sorted by name |
dep_nodes / dep_edges |
Transitive subgraph (includes direct neighbours); edge [A, B] means B depends on A |
events |
Oldest → newest; kinds: state_change, restart, liveness_failed (ring = last 16) |
uptime_secs is omitted (or null) when the service is not currently running.
Event field presence by kind:
kind |
Set fields |
|---|---|
state_change |
from, to |
restart |
(none beyond ts / kind) |
liveness_failed |
optional detail (probe failure reason) |
{
"type": "log",
"line": {
"ts": "2026-08-03T18:00:00.000000000Z",
"service": "redis",
"level": "stdout",
"msg": "Ready to accept connections"
}
}level is one of: stdout, stderr, info, warn, error.
| Value | Typical meaning |
|---|---|
pending |
Not started yet |
starting |
Start in progress |
running |
Daemon up |
succeeded |
Job finished OK |
failed |
Failed start or bad exit |
stopping |
Stop in progress |
stopped |
Stopped |
restarting |
Waiting to restart after crash |
disabled |
Enabled flag false |
waiting_for_dependency |
Blocked on dependsOn |
import json, socket, struct
def call(path, obj):
payload = json.dumps(obj).encode()
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.connect(path)
s.sendall(struct.pack("<I", len(payload)) + payload)
hdr = s.recv(4)
(n,) = struct.unpack("<I", hdr)
data = b""
while len(data) < n:
data += s.recv(n - len(data))
return json.loads(data)
print(call("/data/run/microinit.sock", {"type": "list"}))
print(call("/data/run/microinit.sock", {"type": "start", "name": "redis", "force": False}))For logs with follow: true, keep reading frames in a loop (each frame has its own 4-byte length prefix).
- Operator guide — day-to-day CLI
- Configuration — JSON files and hot reload
- Architecture — internals
- Documentation index