Query-daemon local IPC protocol¶
Slice 4 exposes the completed warm query runtime through a repository-local, authenticated transport. It is a transport boundary only: foreground process lifecycle, durable status/activity records, service-manager integration, and MCP discovery. CLI routing is documented separately.
Boundary and topology¶
One server is fixed to one resolved repository root and one effective output directory at startup. Its request format has no repository, output-directory, or generic filesystem-path field. The server never indexes files or mutates the SQLite or DuckDB index; it dispatches only explicitly registered read operations through the existing warm runtime.
On Linux and macOS, frames use a Unix-domain stream socket. On Windows, the
adapter uses multiprocessing.connection named pipes only through
send_bytes() and recv_bytes(); it never uses pickle-backed send() or
recv().
Protocol¶
The current protocol version is 1. Unix frames are a four-byte big-endian
length followed by one UTF-8 JSON object. Named-pipe messages contain that raw
UTF-8 JSON object directly. A client must first send:
{
"type": "handshake",
"protocol_version": 1,
"identity": "opaque repository/output digest",
"secret": "hex capability secret"
}
The successful response proves the same protocol version and identity and
reports the warm generation plus the approved operation names. Requests then
carry an opaque request_id, an approved operation name, and JSON arguments.
Responses repeat the request identifier and generation. Credentials are never
included in responses, endpoint descriptors, logs, or errors.
Before every handshake and request, the server reads the durable generation
record. It refuses service while the record is absent or updating, and it
requires the warm runtime to match the current ready generation. This makes
an incomplete index handoff transiently unavailable rather than presenting a
stale cached connection as current.
Local credentials and endpoints¶
Files reside below the effective output directory:
.codira/query-daemon-endpoint.jsonis public local discovery metadata: protocol version, transport, address, and opaque identity..codira/query-daemon.keyis a separate 32-byte capability secret, created owner-readable only on Unix-like platforms..codira/query-daemon.sockis the preferred Unix socket address; if a deep repository path exceeds portable Unix-socket limits, the descriptor names a short identity-derived socket below/tmp. Windows uses a stable named pipe derived from the opaque identity instead.
The descriptor is validated against the client’s own resolved identity and expected transport/address. A descriptor copied from another repository or output directory is rejected before a connection is attempted.
Foreground status and recovery¶
codira query-daemon run writes separate lifecycle records below the effective
output directory: query-daemon-status.json, query-daemon-activity.jsonl,
and query-daemon-owner.json. They are distinct from the indexing daemon's
daemon-status.json and activity log. The status reports process identity and
PID, backend names, current and observed generations, connection/model warmth,
request counters, last refresh, fallback availability, and the last error.
Activity records contain lifecycle and generation transitions only: they never
record query text or source paths. A stale owner PID causes the matching public
endpoint and socket to be cleaned before a new foreground process claims the
identity. Missing, corrupt, or updating generation records leave the daemon
degraded; the IPC endpoint remains local but refuses warm reads until a
later ready generation is warmed. SIGINT and SIGTERM request graceful closure
of the server, runtime, and ownership record.
Platform services¶
install, uninstall, start, and stop manage only the service whose
identity matches the current repository and effective output directory. The
systemd user unit, launchd LaunchAgent, and Windows SCM registration all invoke
the same foreground codira query-daemon --path … --output-dir … run command.
They are separate from the indexing daemon's service identities. User-session
services require a logged-in user session; systemd lingering or Windows SCM
startup policy remains an operator choice.
Limits and threat model¶
The service is local-only, but local endpoints are still untrusted boundaries. It applies bounded UTF-8 JSON request and response sizes, socket timeouts, and a bounded accepted-client queue. Oversized, malformed, truncated, incompatible, or unauthenticated frames are rejected. A client disconnect cannot poison a later connection. The server removes only its own socket path during shutdown; it refuses to replace a non-socket filesystem entry.
The capability secret protects against unrelated local processes that can reach the endpoint. It is not a multi-user authorization system: directory ownership and host access controls remain the operating-system boundary. Query text and source paths are not persisted by this transport.
MCP proxy and fallback¶
The MCP stdio server is a fixed-root proxy client. The query daemon registers the contract's approved MCP operations only, executes their existing adapter logic against its warm connection, and returns the normal MCP envelope. The stdio process validates the endpoint identity, protocol, transport, and capability secret through the IPC handshake on each request.
If there is no matching endpoint, or a warm request fails, the MCP process
executes the same request directly once. It does not auto-start the daemon.
Response provenance records warm, direct, or fallback execution plus the
served generation without exposing the endpoint or secret. This permits many
MCP clients to share one repository daemon while preventing cross-repository
or arbitrary-path access.
CLI proxy and fallback¶
When [query_daemon].enabled is true, the CLI opportunistically sends only
eligible, path-free reads to the same identity-bound endpoint: ctx, embedding
search, plugins, and caps. The daemon captures the existing command
renderer so warm output and exit codes match direct execution. Prefix-filtered
queries and every write-oriented command remain direct. A missing, stale,
incompatible, or failed endpoint performs one direct retry; the optional
--execution-mode diagnostic exposes warm, direct, or fallback without
changing standard output or revealing credentials.
Troubleshooting¶
If a client reports an unavailable endpoint, first confirm that the endpoint
descriptor and key exist under the intended effective output directory. Follow
the socket address recorded in the descriptor (it can be a short /tmp path
for a deeply nested repository). Remove only a stale socket after confirming
no query-daemon process owns it; never delete the key merely to diagnose
connectivity. A protocol or
identity mismatch normally means the client was started for a different
repository/output pair. An updating generation is expected during indexing;
callers should use their direct-core fallback until a later ready generation
is published.