Releul de host-uri
Rulează o comandă shell sau citește un fișier pe desktopul tău de pe telefon, dintr-un browser sau dintr-un script — fără SSH, fără port de intrare, doar în același cont.
Releul de host-uri permite oricărui client al tău să execute un vocabular mic și fix de operații pe unul dintre desktopurile tale care are aplicația codai desktop deschisă. Desktopul ține o conexiune SSE de ieșire către gateway și se anunță ca host; un solicitant face POST cu un exec și gateway-ul îl retransmite, apoi retransmite răspunsul înapoi. Nimic nu este persistat, nimic nu ascultă pe desktop și în v1 host-ul și solicitantul trebuie să aparțină aceluiași utilizator.
telefon / browser / script gateway desktop (host)
────────────────────────── ───────── ───────────────
POST /v1/hosts/:dev/exec ───────▶ rendezvous după device id ─────▶ event: exec (pe SSE-ul lui)
{ op, args } rulează op-ul local
200 { ok, result } ◀─────── rendezvous după req_id ◀───── POST /v1/hosts/exec/:reqId/resultAceastă suprafață este servită de https://ai.codai.ro și nu face parte din specificația publicată Shared Sessions v1; tratează-o ca remote sessions v1.
Ce desktopuri sunt online
curl https://ai.codai.ro/v1/hosts -H "Authorization: Bearer $CODAI_API_KEY"{
"hosts": [
{
"device_id": "1c2f…-uuid",
"name": "Work laptop",
"platform": "desktop",
"os": "windows",
"hostname": "DRAGOS-PC",
"roots": ["E:\\gh\\codai", "C:\\Users\\dragos\\Documents"],
"since": 1790160000000,
"last_seen": 1790160045000
}
]
}Apar doar dispozitivele tale, cele văzute cel mai recent întâi. since și last_seen sunt milisecunde epoch; un host dispare din listă 45 de secunde după ultimul heartbeat. roots sunt directoarele pe care desktopul le va lăsa operațiile pe fișiere să le atingă.
Rulează ceva pe un host
POST /v1/hosts/:deviceId/exec — necesită cheia ta și un header x-codai-device care identifică solicitantul.
Proprietate
Tip
curl https://ai.codai.ro/v1/hosts/1c2f…/exec \
-H "Authorization: Bearer $CODAI_API_KEY" \
-H "x-codai-device: $(uuidgen)" -H "x-codai-device-platform: cli" \
-H "Content-Type: application/json" \
-d '{ "op": "shell", "args": { "cmd": "git status --short", "cwd": "E:\\gh\\codai" }, "timeout_ms": 30000, "label": "docs check" }'Răspunsul — răspunsul host-ului, exact așa cum a venit:
{
"req_id": "c0de…-uuid",
"ok": true,
"result": { "code": 0, "stdout": " M apps/docs/content/docs/en/sessions/hosts.mdx\n", "stderr": "", "truncated": false, "timed_out": false, "duration_ms": 412 },
"error": null
}Un eșec pe partea host-ului — o cale în afara roots, un argument greșit, o comandă care nu a putut porni — este tot HTTP 200 cu ok: false și error setat. Doar problemele releului sunt erori HTTP:
| Status | code | Când |
|---|---|---|
400 | bad_request | x-codai-device lipsă, op necunoscut, timeout_ms în afara intervalului. |
404 | not_found | deviceId nu este unul dintre dispozitivele tale (gateway-ul nu dezvăluie niciodată id-urile de dispozitiv ale altor utilizatori). |
409 | host_offline | Este dispozitivul tău, dar nu este conectat ca host acum — open codai desktop. |
504 | host_timeout | Host-ul nu a răspuns în timeout_ms — host did not answer within 30000 ms. |
Operații
Desktopul implementează fiecare op cu propriile comenzi verificate de permisiuni; căile de fișiere trebuie să fie sub roots-urile host-ului.
op | args | result |
|---|---|---|
shell | { cmd: string, cwd?: string, timeout_ms?: number } — PowerShell pe Windows, shell-ul de login în rest; timeout_ms este limitat la cel al request-ului. | { code, stdout, stderr, truncated, timed_out, duration_ms } |
fs_read | { path: string, max_bytes?: integer } — implicit 64 KB, max 512 KB. | { path, content, size, truncated } |
fs_write | { path: string, content: string } | { path, bytes, created } |
fs_list | { path: string } | { path, entries: [{ name, kind, size }], truncated } |
fs_roots | {} | { roots: string[] } |
info | {} | { os: 'windows' | 'linux' | 'macos', hostname, roots, platform: 'desktop' } |
shell rulează cu privilegiile utilizatorului de pe desktop. Releul nu adaugă niciun sandbox propriu — setarea de autonomie și regulile aplicației desktop decid ce va executa, și fiecare request apare în UI-ul ei cu label-ul tău. Ține cheile API care pot ajunge la /v1/hosts la fel de strict delimitate ca orice cheie SSH.
Construiește un host
Ai nevoie de această secțiune doar dacă îți scrii propriul host (aplicația codai desktop este deja unul).
Anunță-te
Deschide GET /v1/hosts/stream cu cheia ta și cu x-codai-device-ul propriu al host-ului. Descrie mașina în query string (un GET nu are body): ?os=windows&hostname=DRAGOS-PC&roots=E:\gh\codai,C:\Users\dragos\Documents — os ≤ 40 caractere, hostname ≤ 120, până la 32 de roots.
Primul frame este hello, apoi un ping la fiecare 15 s; fiecare ping îți reîmprospătează prezența (TTL 45 s). Serverul închide stream-ul după 6 ore — reconectează-te cu backoff (desktopul folosește 1 s → 30 s).
event: hello
data: {"device_id":"1c2f…","heartbeat_ms":15000}
event: ping
data: {"t":1790160045000}
event: exec
data: {"req_id":"c0de…","op":"shell","args":{"cmd":"git status --short","cwd":"E:\\gh\\codai"},"timeout_ms":30000,"label":"docs check","from_device_id":"9a0b…","ts":1790160050000}Execută și răspunde
Pentru fiecare frame exec, rulează op-ul și fă POST /v1/hosts/exec/:reqId/result cu { "ok": boolean, "result"?: any, "error"?: string ≤ 4000 }. Body-ul trebuie să rămână sub 2 MB, iar reqId trebuie să fie UUID-ul de 36 de caractere pe care l-ai primit. Un răspuns lipsă sau întârziat lasă pur și simplu timeout_ms-ul solicitantului să expire.
curl -X POST https://ai.codai.ro/v1/hosts/exec/c0de…/result \
-H "Authorization: Bearer $CODAI_API_KEY" -H "x-codai-device: 1c2f…" \
-H "Content-Type: application/json" \
-d '{ "ok": true, "result": { "code": 0, "stdout": "…", "stderr": "", "truncated": false, "timed_out": false, "duration_ms": 412 } }'req_id este o capability imposibil de ghicit, dată doar ție; gateway-ul potrivește după ea răspunsul cu solicitantul care așteaptă și răspunde { "ok": true }.
Impune-ți propriile roots
Gateway-ul retransmite; tu decizi ce rulează. Refuză căile din afara roots-urilor anunțate, limitează timeout-urile shell la timeout_ms-ul request-ului, plafonează dimensiunile output-ului (setează truncated: true) și afișează fiecare request în UI-ul tău cu label-ul și from_device_id-ul lui.
Partajare și organizații
Acordă un rol pe o sesiune unei persoane, unei organizații sau unui link; listează ce este partajat cu tine; gestionează apartenența la organizații.
Proiecte și medii
Dă-i agentului o mașină reală — un VM administrat sau propriul tău server — și conectează-te la ea din desktop, din CLI sau din hub.