TacidOS
DevelopersGitHub

Decision 0005

JSON-RPC 2.0 over Unix sockets everywhere; no polkit on the Tacid path

Architecture decision record 0005: JSON-RPC 2.0 over Unix sockets everywhere; no polkit on the Tacid path

Status
Accepted
Date
2026-09-03

Context

Clients, tools, helpers and remote bodies need one wire dialect. The TUI and the shell must have feature parity without duplicated logic.

The three plans

  • Grok: local IPC, “JSON-lines or capnp; keep it boring”.
  • Fable: Unix socket, JSON-RPC; MCP for tools.
  • Codex: D-Bus or a tightly defined local IPC; polkit where appropriate.

Decision

JSON-RPC 2.0, newline-delimited, over Unix domain sockets, with file descriptors passed by SCM_RIGHTS for audio, pseudo-terminals and large blobs. One tacid-protocol crate with generated JSON Schema; a separate minimal crate for the stem. Authentication by SO_PEERCRED and a per-boot token. MCP is JSON-RPC 2.0 as well, so one codec serves clients, tools and helpers. The protocol is transport-agnostic so the same messages travel over SSH or WireGuard to a remote body (ADR-0030).

The protocol carries UI state (plans, live tool state, diffs, pending approvals, badges); clients are pure renderers; parity follows.

polkit is not used between Tacid processes: it requires a session agent that is absent on a tty, a serial console and a headless node, adds a second policy language, and has its own history. It remains available for udisks-class peers. D-Bus via zbus only for desktop interop.

Consequences

  • One codec, one schema, one place to version.
  • Streams are notifications; binary never travels base64.
  • Remote transport is a wrapper, not a redesign.

Alternatives rejected

  • D-Bus for the core: a bus daemon dependency on the boot-critical path and a second type system.
  • Varlink: elegant and systemd-native, but a weak Rust story and a second codec.
  • gRPC/Cap’n Proto: heavier tooling for no gain on a local socket.