syntax = "proto3"; package cloud; option go_package = "github.com/amir20/dozzle/proto/cloud"; service CloudToolService { // Dozzle sends ToolResponse, cloud sends ToolRequest rpc ToolStream(stream ToolResponse) returns (stream ToolRequest); // Dozzle-initiated unary call: search log lines this instance has streamed // to Cloud (gated by streamLogs opt-in). Cloud scopes the query server-side // to the (user_id, api_key_id) derived from the authenticated connection; // Dozzle does NOT pass any identity fields in the request. rpc SearchLogs(SearchLogsRequest) returns (SearchLogsResponse); } message ToolRequest { string request_id = 1; oneof type { ListToolsRequest list_tools = 2; CallToolRequest call_tool = 3; CancelStreamRequest cancel_stream = 4; } } message ToolResponse { string request_id = 1; oneof type { ListToolsResponse list_tools = 2; CallToolResponse call_tool = 3; // Unsolicited server-push: batched container log lines streamed from // Dozzle to Cloud for ingestion into VictoriaLogs. request_id is empty // for log batches — they are not replies to a ToolRequest. LogBatch log_batch = 4; } } // Batch of log lines from one or more containers. Dozzle pushes these // continuously while connected. Cloud routes them to VictoriaLogs scoped // to the owning user (derived from the connection's auth). message LogBatch { repeated LogBatchEntry entries = 1; } message LogBatchEntry { string host_id = 1; string container_id = 2; string container_name = 3; int64 timestamp_ns = 4; // unix nanoseconds string message = 5; string stream = 6; // "stdout" or "stderr" string level = 7; // "info", "warn", "error", etc. (best-effort) // Deterministic FNV-32a hash of the raw log line, the same id Dozzle // stamps on LogEvent.Id. Cloud indexes this as a non-stream field so // search results can produce a stable permanent link // (/container/:id/time/:datetime?logId=...) that lands the user on // exactly the matching line in the local log viewer. uint32 log_id = 8; } message ListToolsRequest {} message ListToolsResponse { repeated ToolDefinition tools = 1; string version = 2; } message ToolDefinition { string name = 1; string description = 2; string parameters_json = 3; // scope tells the cloud router how to multiplex calls to this tool. Dozzle // itself has no notion of "multiple instances"; this field lets the router // decide whether to fan out (default), target a specific container/host // inferred from the existing host_id/container_id params, or target the // whole Dozzle instance (in which case the router injects an instance_id // argument into the LLM-facing schema and strips it before forwarding). ToolScope scope = 4; // read_only = true means the tool has no side effects and is safe to fan // out across every connected Dozzle instance when the scope's routing // argument is missing (e.g. list_notifications without instance_id queries // all instances and merges results). Mutating tools (create/delete/deploy/ // restart/etc.) must leave this false — the router will require the scope // argument and error if it's missing, so a write never fans out by mistake. bool read_only = 5; } enum ToolScope { // Default — treated as INSTANCE. Exists so forward-compat clients without // a scope field don't misroute. TOOL_SCOPE_UNSPECIFIED = 0; // Applies to the whole Dozzle instance (list_hosts, notifications, etc.). // Requires instance_id in the args. TOOL_SCOPE_INSTANCE = 1; // Targets a specific Docker host (deploy_compose, list_deploy_versions). // Requires host_id in the args. TOOL_SCOPE_HOST = 2; // Targets a specific container (logs, actions, inspect). Requires // container_id in the args (host_id is typically also present for the // Docker API call inside Dozzle but isn't used for routing). TOOL_SCOPE_CONTAINER = 3; } message CallToolRequest { string name = 1; string arguments_json = 2; } message CallToolResponse { bool success = 1; string error = 2; bool stream = 9; bool end_stream = 10; oneof result { ListHostsResult list_hosts = 3; ListContainersResult list_containers = 4; ContainerStatsResult container_stats = 5; ActionResult action = 6; FetchLogsResult fetch_logs = 7; InspectContainerResult inspect_container = 8; DeployResult deploy = 11; NotificationResult notification = 12; } } message CancelStreamRequest { string stream_request_id = 1; } // Host information message HostInfo { string id = 1; string name = 2; int32 n_cpu = 3; int64 mem_total = 4; string docker_version = 5; string agent_version = 6; string type = 7; bool available = 8; } message ListHostsResult { repeated HostInfo hosts = 1; } // Container information message ContainerInfo { string id = 1; string name = 2; string image = 3; string command = 4; string created = 5; string started_at = 6; string finished_at = 7; string state = 8; string health = 9; string host_name = 10; string host_id = 12; string group = 11; } message ListContainersResult { repeated ContainerInfo containers = 1; } // Container stats message ContainerStatEntry { string id = 1; string name = 2; string host = 3; double cpu_percent = 4; double memory_percent = 5; double memory_usage = 6; double max_cpu_5min = 7; double max_memory_5min = 8; string host_id = 9; uint64 network_rx_total = 10; uint64 network_tx_total = 11; uint64 network_rx_5min = 12; uint64 network_tx_5min = 13; } message ContainerStatsResult { repeated ContainerStatEntry stats = 1; } // Container logs message LogEntry { int64 timestamp = 1; string message = 2; string stream = 3; // "stdout" or "stderr" string level = 4; // "info", "warn", "error", etc. } message FetchLogsResult { string container_name = 1; repeated LogEntry entries = 2; } // Container inspect result message InspectContainerResult { string id = 1; string name = 2; string image = 3; string command = 4; string created = 5; string started_at = 6; string finished_at = 7; string state = 8; string health = 9; string host_name = 10; string host_id = 19; map labels = 11; uint64 memory_limit = 12; double cpu_limit = 13; reserved 14; reserved "env"; repeated string ports = 15; repeated string mounts = 16; string restart_policy = 17; string network_mode = 18; } // Container action result message ActionResult { bool success = 1; string container_id = 2; string action = 3; string message = 4; } // Deploy compose result message DeployResult { bool success = 1; string project = 2; string message = 3; } // Notification/alert tool result (list, create). message NotificationResult { bool success = 1; string message = 2; } // Cloud log search. message SearchLogsRequest { // Substring/word-filter query. Empty -> empty result. Whitespace-only // is rejected client-side; server treats as empty. string query = 1; // Result cap. Default 20, server-capped at 50. int32 limit = 2; // Pagination cursor: return only hits with timestamp_ns < this value. // 0 = newest. Reserved for future use. int64 before_ts_ns = 3; // Optional filter — narrow to a specific Docker host inside the instance. // Empty = all hosts under this instance. string host_id = 4; // Optional filter — narrow to a specific container. string container_id = 5; } message SearchLogsResponse { repeated SearchLogHit hits = 1; bool has_more = 2; // For pagination: pass back as before_ts_ns to fetch the next page. int64 next_before_ts_ns = 3; } message SearchLogHit { int64 timestamp_ns = 1; string host_id = 2; string container_id = 3; string container_name = 4; // Full log line as indexed. string message = 5; string stream = 6; string level = 7; // FNV-32a hash of the raw log line — same id Dozzle assigns LogEvent.Id // and exposes via "Copy permalink". Lets the search-result row deep-link // straight to the matching line. uint32 log_id = 8; }