Files
Veskslop-t/remchild/plan.md
T

4.7 KiB

remchild — remote child plan

remchild is a separate module that runs on a remote machine. Veskslop feeds it work and it feeds results back. Planned uses: STT (local SAM/VOX stack or an AI model), TTS, later video (a window or an MPV file), and finally the full desktop control app.

Status: PoC on branch remchild (client + server + naming). No Web UI yet.

What the PoC does

Piece Path Notes
Client client/main.c C11, libc only, no runtime dependencies. Linux.
Word lists words.json, client/words.h Two lists of 128 words. The header is generated for the client.
Server server/server.mjs Node, no dependencies. Proves the listener, allowlist, heartbeat, ping test, and history.
Test client/remchild --once One hello, one ping, one pong, exit.

Build and run:

cc -O2 -o remchild/client/remchild remchild/client/main.c
node remchild/server/server.mjs --port 8799 --ips 192.168.1.5
./remchild/client/remchild --server 192.168.1.5:8799

The client prints its assigned name, connects, and shows p (ping test) and q (quit). The server prints each connect, state change, and disconnect, and appends to server/clients.jsonl.

Naming

Each client gets two words. The pair comes from the first non-loopback MAC address (fallback /etc/machine-id):

  1. Hash the identity bytes with FNV-1a 64.
  2. first = hash % 128, second = (hash / 128) % 128.
  3. If both indexes are equal, second = (second + 1) % 128, so Queer Queer becomes Queer Groin.

The lists share words on purpose, so Funky Monkey, Funky Queer, and Queer Monkey are all possible. A random MAC changes the name; a stable machine-id does not.

Heartbeats and states

The client sends heartbeat on this schedule after boot:

Time since start Interval
0 to 60 s 10 s
60 s to 6 min 30 s
after 6 min 5 min

The server keeps three states from lastSeen:

State Age Effect
active under 12 min Jobs and commands may be sent
stale 12 to 30 min No jobs or commands
gone over 30 min Considered offline; a late heartbeat revives it

First and last seen are kept in memory and written to clients.jsonl. SIGINT prints the table.

Transport

Newline-delimited JSON over TCP on a dedicated port (PoC: 8799). No Discord connection, no HTTP framework.

Direction Message Meaning
client → server hello id, name, platform, version
server → client welcome Assigned name, heartbeat interval, server name
client → server heartbeat ts
both ping / pong seq echo, for the test button and latency
server → client job Later: a unit of work with an ID and a payload
client → server job-result Later: id, ok, data or error

Binary payloads (PCM, video frames) get their own framing later: a length-prefixed binary frame on the same socket, or a second UDP channel for audio where loss is cheap.

Server side in Veskslop

The PoC server moves into the daemon as poc/src/remchild-server.ts:

  • Separate listener, default port 8799 (VESKSLOP_REMCHILD_PORT).
  • Settings: preferences.remchild.allow (IP list) and preferences.remchild.allowNonLan.
  • The launch argument --allow-non-lan (or VESKSLOP_REMCHILD_ALLOW_NON_LAN=1) is required before a non-LAN address in the list is accepted. Without the list, only LAN and Tailscale ranges pass.
  • The daemon never scans for clients. It listens, records, and dispatches.
  • The client registry feeds a Status section later; no Web UI work is needed now.

Phases

Phase Work
M1 (done) PoC: naming, listen, allowlist, heartbeat, ping test, history
M2 Move the server into the daemon, add settings, the launch-arg unlock, and tests. Add job dispatch and job-result with retry and dedupe.
M3 Audio: the daemon sends call audio to the client, the client runs VAD and STT (SAM/VOX or an AI model), and returns annotated text and voice commands. The same path carries TTS back.
M4 Video: stream a window or play a file with MPV, and return frames or a stream URL.
M5 Desktop: an ImGui control app. Wayland first: pick a Wayland-capable backend (SDL3, or SDL2/GLFW built with Wayland and libwayland-dev, wayland-protocols, xkbcommon) or a native wlroots/EGL backend. X11 is a fallback only. The terminal UI in the PoC is a placeholder because the current host has no GUI dev libraries.

Open questions

  • Track-to-user audio mapping for remote STT (see ../docs/voice-audio-split.md).
  • Job retry policy and idempotency keys.
  • Whether audio uses the same socket or a second channel.
  • Wake-on-LAN or reconnect backoff for a client that drops.