Development Documentation (main branch) - For stable release docs, see docs.rs/eidetica
Skip to main content

Module service

Module service 

Source
Expand description

Local service (daemon) mode for Eidetica.

This module enables running Eidetica as a local daemon that serves an Instance to multiple client processes over a Unix domain socket. The primary motivation is shared storage: multiple CLI tools and applications can operate on the same Eidetica data without each process opening its own backend.

§Architecture

The RPC boundary sits at the storage operation level. A RemoteConnection forwards all operations over a Unix socket to the daemon, backing the RemoteBackend seam impl. Instance::connect(path) loads InstanceMetadata from the remote backend, then constructs an Instance with no local secrets.

§Security Model

Client-side signing. The daemon stores and serves encrypted key material and signed entries but never holds plaintext user signing keys or passwords.

  • User keys stay client-side: clients fetch encrypted UserCredentials from the daemon, derive the key-encryption-key locally (Argon2id), decrypt the user’s signing key in-process, and sign entries before sending them to the daemon for storage. The signing key never crosses the socket.
  • Authentication via challenge-response: when the daemon needs to prove a connecting client controls a user account, the daemon issues a fresh random challenge per session and the client signs it with the user’s root key. The daemon verifies against the user’s public key from its auth tables. No password is sent over the wire; successful decryption of the user’s signing key on the client is password verification.
  • Encrypted stores remain opaque to the daemon: per-database encrypted CRDTs (e.g. PasswordStore) merge as Vec<EncryptedBlob> — the daemon participates in storage and sync without ever holding a content encryption key. Clients decrypt and merge in-process and may write the result back as an encrypted cache entry.
  • Filesystem permissions: the socket directory is owner-only (mode 0700) and the socket itself is mode 0600 as an additional access-control layer.

See the brain note “Service Architecture” § Security Model for the design rationale, including why daemon-side signing (the earlier draft) was rejected and the deferred work that grew out of that decision (hardware-backed PrivateKey::Remote, async sign(), OS-keyring caching of derived encryption keys).

§Write Coordination

Client writes travel as DatabaseOp::SubmitSignedEntry — the daemon stores the entry Unverified, then runs its own verification pass before the entry is exposed on any default read.

§V1 Limitations

  • No server-push notifications: Clients see latest state on each request but are not notified when the daemon receives entries from sync peers, or when another client writes through the same daemon. As a consequence, Database::on_write on a connected Instance observes only writes this client’s own commit path produced — see that method’s doc for the full caveat list. Future: bidirectional framing with a Notification variant alongside Response, plus a client-side reader task that routes notifications to the local callback registry.

  • enable_sync() on remote Instance: A silent no-op (returns Ok(())) rather than building a client-side sync module that would race the daemon’s own sync. The daemon either already runs sync or it does not, and the client cannot change that over the current wire surface. Future: add an admin-gated EnableSync RPC that delegates to the server’s Instance, and similarly for sync(), flush_sync(), etc.

Re-exports§

pub use client::RemoteConnection;
pub use server::ServiceServer;

Modules§

client
Remote connection client for the Eidetica service.
error
Wire-format error type for the service protocol.
protocol
Wire protocol types for the Eidetica service.
server
Service server: accepts Unix socket connections and dispatches BackendImpl operations.

Functions§

default_socket_path
Default socket path for the Eidetica service.
default_socket_url
Default unix:// URL for Instance::connect, derived from default_socket_path.