Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

gRPC Node Protocol

The ennio-node daemon runs on remote machines and communicates with the orchestrator via gRPC over an SSH tunnel.

Running the Daemon

ennio-node [OPTIONS]
OptionDefaultEnv VarDescription
--port9100gRPC listen port
--idle-timeout3600Seconds before auto-shutdown
--workspace-rootRoot directory for workspaces
--auth-tokenENNIO_NODE_AUTH_TOKENBearer token for authentication

Authentication

When --auth-token is set, all gRPC calls must include a authorization metadata key with value Bearer <token>. The token is compared using constant-time SHA-256 hashing.

If no token is set, the daemon relies on SSH tunnel isolation for security (only reachable via the tunnel).

Connection Flow

Orchestrator                     Remote Host
    │                                │
    ├── SSH connect ────────────────►│
    ├── Port forward (tunnel) ──────►│ :9100
    ├── gRPC Heartbeat ────────────►│
    │◄──────────── healthy=true ────┤
    ├── gRPC CreateWorkspace ──────►│
    │◄──────────── workspace_path ──┤
    ├── gRPC CreateRuntime ────────►│
    │◄──────────── runtime handle ──┤
    │         ...polling...          │
    ├── gRPC Shutdown ─────────────►│
    │◄──────────── accepted=true ───┤
    │                                │

Idle Timeout

The daemon automatically shuts down after --idle-timeout seconds of no gRPC activity. This prevents orphaned daemons from consuming resources on remote machines. The orchestrator re-deploys the daemon on next connection.

Service Definition

service EnnioNode {
  rpc CreateWorkspace(CreateWorkspaceRequest) returns (CreateWorkspaceResponse);
  rpc DestroyWorkspace(DestroyWorkspaceRequest) returns (DestroyWorkspaceResponse);
  rpc CreateRuntime(CreateRuntimeRequest) returns (CreateRuntimeResponse);
  rpc DestroyRuntime(DestroyRuntimeRequest) returns (DestroyRuntimeResponse);
  rpc SendMessage(SendMessageRequest) returns (SendMessageResponse);
  rpc GetOutput(GetOutputRequest) returns (GetOutputResponse);
  rpc IsAlive(IsAliveRequest) returns (IsAliveResponse);
  rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
  rpc Shutdown(ShutdownRequest) returns (ShutdownResponse);
}

Message Types

Workspace Management

message CreateWorkspaceRequest {
  string project_id = 1;
  string repo_url = 2;
  string path = 3;
  string session_id = 4;
  string default_branch = 5;
  optional string branch = 6;
  string workspace_type = 7;    // "worktree" or "clone"
}

message CreateWorkspaceResponse {
  string workspace_path = 1;
}

message DestroyWorkspaceRequest {
  string workspace_path = 1;
}

message DestroyWorkspaceResponse {}

Runtime Management

message CreateRuntimeRequest {
  string session_id = 1;
  string launch_command = 2;
  map<string, string> env = 3;
  string cwd = 4;
  string session_name = 5;
}

message CreateRuntimeResponse {
  ProtoRuntimeHandle handle = 1;
}

message DestroyRuntimeRequest {
  ProtoRuntimeHandle handle = 1;
}

message DestroyRuntimeResponse {}

message ProtoRuntimeHandle {
  string id = 1;
  string runtime_name = 2;
  map<string, string> data = 3;
}

Session Communication

message SendMessageRequest {
  ProtoRuntimeHandle handle = 1;
  string message = 2;
}

message SendMessageResponse {}

message GetOutputRequest {
  ProtoRuntimeHandle handle = 1;
  uint32 lines = 2;
}

message GetOutputResponse {
  string output = 1;
}

message IsAliveRequest {
  ProtoRuntimeHandle handle = 1;
}

message IsAliveResponse {
  bool alive = 1;
}

Health and Lifecycle

message HeartbeatRequest {}

message HeartbeatResponse {
  bool healthy = 1;
  uint64 uptime_secs = 2;
}

message ShutdownRequest {
  bool graceful = 1;
}

message ShutdownResponse {
  bool accepted = 1;
}

RPC Reference

RPCPurposeRequestResponse
CreateWorkspaceCreate a git worktree or clone on the remote hostproject, repo, branch, typeworkspace path
DestroyWorkspaceRemove a workspace directoryworkspace path
CreateRuntimeLaunch an agent in a tmux sessioncommand, env, cwd, nameruntime handle
DestroyRuntimeKill a running agent sessionruntime handle
SendMessageSend text to a running agenthandle, message
GetOutputRead recent terminal outputhandle, line countoutput text
IsAliveCheck if agent process is runningruntime handlealive boolean
HeartbeatHealth checkhealthy, uptime
ShutdownRequest daemon shutdowngraceful flagaccepted boolean

Client Implementation

The orchestrator’s RemoteNode client in ennio-ssh handles:

  • SSH tunnel establishment to the gRPC port
  • Connection management and reconnection
  • All RPC calls with proper error mapping to EnnioError
  • Health checking before operations