Teleport, tunnels and the volume
cua.env.v1 TeleportService, TunnelService and VolumeService: receiving teleported sessions and files, port forwards, hotspots and the guest mount of Cua Volume.
cua.env.v1 TeleportService, TunnelService and VolumeService: receiving teleported sessions and files, port forwards, hotspots and the guest mount of Cua Volume.
The receiving side of teleport (sending lives in the cua SDK), TCP port forwards, the reverse-SOCKS hotspot, and the guest mount of Cua Volume served by the client.
Source: libs/cua/proto/cua/env/v1/teleport.proto, libs/cua/proto/cua/env/v1/tunnel.proto, libs/cua/proto/cua/env/v1/volume.proto.
cua.env.v1.TeleportService
Receiving side of "teleport": moving an app session (browser profile cookies and storage, editor state) or a set of files from a user's machine into the guest.
The approval gate (biometric or explicit user consent for sensitive items) lives on the sending side, in the SDK; the guest never pulls. All uploads are unary chunks so browsers on gRPC-Web can send them.
/cua.env.v1.TeleportService/GetManifest, unary: GetManifestRequest to GetManifestResponse.
Describes what the guest can accept for an app: whether the provider exists, whether the app is installed or running, and which bundle format version to send.
/cua.env.v1.TeleportService/ImportSession, unary: ImportSessionRequest to ImportSessionResponse.
Uploads an rcdp-app-session bundle in offset-addressed chunks and, on
the final chunk, verifies and imports it. Resumable: resend from the
returned received_bytes.
/cua.env.v1.TeleportService/BeginReceiveFiles, unary: BeginReceiveFilesRequest to BeginReceiveFilesResponse.
Starts a file transfer into the guest's Downloads folder by declaring its manifest. Entries matching ignore rules are dropped here.
/cua.env.v1.TeleportService/ReceiveFilesChunk, unary: ReceiveFilesChunkRequest to ReceiveFilesChunkResponse.
Uploads one chunk of one declared file.
/cua.env.v1.TeleportService/CommitReceiveFiles, unary: CommitReceiveFilesRequest to CommitReceiveFilesResponse.
Verifies every file's SHA-256 and publishes the transfer atomically.
/cua.env.v1.TeleportService/AbortReceiveFiles, unary: AbortReceiveFilesRequest to AbortReceiveFilesResponse.
Discards a transfer.
/cua.env.v1.TeleportService/WipeImport, unary: WipeImportRequest to WipeImportResponse.
Removes what a committed import left in the guest: every file and
directory it created and every Keychain item it installed, as recorded
in the import's ledger. Guests that support it advertise the feature
"teleport.wipe". An unknown import_id is NOT_FOUND.
cua.env.v1.TunnelService
Network tunnels between a client and the guest, carried over WebSocket upgrades on the spacesd port so they work through the Fleet gateway, the relay and gRPC-Web-only networks.
Forward: client-to-guest TCP. Each WebSocket connection to
ws_path becomes one TCP connection to the guest port; binary frames
carry the byte stream in both directions./cua.env.v1.TunnelService/Forward, unary: ForwardRequest to ForwardResponse.
Authorizes TCP forwarding to a guest port and returns the WebSocket to connect to.
/cua.env.v1.TunnelService/ListForwards, unary: ListForwardsRequest to ListForwardsResponse.
Lists active forwards.
/cua.env.v1.TunnelService/CloseForward, unary: CloseForwardRequest to CloseForwardResponse.
Revokes a forward and closes its connections.
/cua.env.v1.TunnelService/StartHotspot, unary: StartHotspotRequest to StartHotspotResponse.
Starts the reverse-SOCKS hotspot for the calling client.
/cua.env.v1.TunnelService/StopHotspot, unary: StopHotspotRequest to StopHotspotResponse.
Stops the hotspot.
/cua.env.v1.TunnelService/GetHotspotStatus, unary: GetHotspotStatusRequest to GetHotspotStatusResponse.
Reports hotspot state and counters.
cua.env.v1.VolumeService
Cua Volume in the guest: the Space's view of the user's volume, mounted at a fixed path and served by the client (the host that runs the volume).
The client calls AttachVolume and opens the returned WebSocket
(/volume, ticket-authenticated), which it keeps open. Once it is
attached, cua-spacesd mounts the volume in the guest; the mount's traffic
travels as tunnel streams over that socket (the frame format of the
hotspot, OPEN carrying the target nfs or fs), and the client
answers them from its own copy of the volume, scoped to this Space. The
guest never holds storage keys and never has a network path to the
client. The mount goes away when the socket closes or on
DetachVolume.
| Guest | Backend | Mount path |
|---|---|---|
| macOS | nfs: the system NFS client | ~/Cua Volume |
| Linux | fs: FUSE (the file operations protocol) | /volume, else ~/Cua Volume |
| Windows | not yet: a preview (nfs, Client for NFS, on V:\) is off unless the guest sets CUA_VOLUME_WINDOWS_PREVIEW=1 |
On Windows a mount_path that is not a drive (for example
C:\Users\<user>\Cua Volume) becomes a directory symbolic link to the
drive the volume mounts on.
| RPC | Request | Response | Kind |
|---|---|---|---|
AttachVolume | AttachVolumeRequest | AttachVolumeResponse | unary |
DetachVolume | DetachVolumeRequest | DetachVolumeResponse | unary |
GetVolumeStatus | GetVolumeStatusRequest | GetVolumeStatusResponse | unary |
/cua.env.v1.VolumeService/AttachVolume, unary: AttachVolumeRequest to AttachVolumeResponse.
Prepares a mount and returns the WebSocket the client attaches.
/cua.env.v1.VolumeService/DetachVolume, unary: DetachVolumeRequest to DetachVolumeResponse.
Unmounts and closes the socket.
/cua.env.v1.VolumeService/GetVolumeStatus, unary: GetVolumeStatusRequest to GetVolumeStatusResponse.
Reports the mount.
cua/env/v1/teleport.proto#Request for TeleportService.GetManifest.
| Field | # | Type | Description |
|---|---|---|---|
app | 1 | string | Provider / app id, for example "firefox", "chromium", "chrome", "vscode". Advertised as capability "teleport.<app>". |
scope | 2 | TeleportScope | Requested scope. |
Response for TeleportService.GetManifest.
| Field | # | Type | Description |
|---|---|---|---|
supported | 1 | bool | True if the guest has a provider for this app. |
limitation | 2 | string | Why not, when unsupported. |
app_installed | 3 | bool | True if the app is installed in the guest. |
app_running | 4 | bool | True if the app is running. Importing may require closing it. |
bundle_version | 5 | uint32 | Bundle format version the sender must produce. |
scopes | 6 | repeated TeleportScope | Scopes this provider can import. |
supported_apps | 7 | repeated string | Every app id the guest can import, for discovery. |
Options applied when an imported session is committed.
| Field | # | Type | Description |
|---|---|---|---|
replace_existing | 1 | bool | Replace existing state instead of merging. |
close_running_app | 2 | bool | Close the app (gracefully, then forcefully after 5 seconds) if it is running. |
launch_after | 3 | bool | Launch the app after importing. |
expires_at_ms | 4 | uint64 | Unix time in milliseconds at which the guest wipes the import on its own, as WipeImport would. 0 means no expiry. Checked every 60 seconds and when the guest daemon starts, so an expiry survives restarts. |
broker_grant | 5 | string | Set by the Cua Keyvault broker when it delivers a session it authorized (a consent grant, an unattended rule or a first-party approval), to keyvault; empty for a direct SDK send. Not a secret and not verified by the guest. cua-spacesd counts deliveries with and without it (present or absent) in its opt-in aggregate telemetry; nothing else reads it. |
Request for TeleportService.ImportSession.
| Field | # | Type | Description |
|---|---|---|---|
import_id | 1 | string | Client-chosen import id, stable across retries. The first chunk (offset 0) creates the import. |
app | 2 | string | App id as in GetManifestRequest.app. |
scope | 3 | TeleportScope | Scope of the bundle. |
offset | 4 | uint64 | Offset of data[0] in the bundle. Must equal received_bytes; a chunk wholly below it is acknowledged as a duplicate. |
data | 5 | bytes | Bundle bytes. At most Limits.max_chunk_bytes. |
commit | 6 | bool | True on the last chunk: verify and import. May carry data. |
sha256 | 7 | string | Lowercase hex SHA-256 of the whole bundle. Required when commit. |
options | 8 | ImportOptions | Import options, read when commit. |
Outcome of an import, returned on the final chunk.
| Field | # | Type | Description |
|---|---|---|---|
imported | 1 | repeated string | Items imported (for example "cookies", "localStorage"). |
skipped | 2 | repeated string | Items skipped, with reasons, as "item: reason". |
launched | 3 | bool | True if the app was launched. |
Response for TeleportService.ImportSession.
| Field | # | Type | Description |
|---|---|---|---|
received_bytes | 1 | uint64 | Bundle bytes received so far. |
duplicate | 2 | bool | True if the chunk was a retry and was not written again. |
result | 3 | ImportResult | Set on the final chunk once the import completed. |
One entry of a file transfer manifest.
| Field | # | Type | Description |
|---|---|---|---|
relative_path | 1 | string | Path relative to the transfer root, "/"-separated. No "..", no absolute paths. |
directory | 2 | bool | True for a directory (no content). |
size | 3 | uint64 | File size in bytes. |
sha256 | 4 | string | Lowercase hex SHA-256 of the file content. |
mode | 5 | uint32 | Unix permission bits. 0 means 0o644 (files) or 0o755 (directories). |
modified_at | 6 | google.protobuf.Timestamp | Modification time to preserve. |
Request for TeleportService.BeginReceiveFiles.
| Field | # | Type | Description |
|---|---|---|---|
transfer_id | 1 | string | Client-chosen transfer id, stable across retries. Repeating the call with the same id returns the current progress. |
destination_subdir | 2 | string | Subdirectory of the guest user's Downloads folder to place the transfer in. Empty places entries directly in Downloads. |
entries | 3 | repeated TransferEntry | All entries. Directories may be listed explicitly or implied by file paths. |
ignore_patterns | 4 | repeated string | gitignore-syntax patterns applied relative to the transfer root. |
honor_gitignore | 5 | bool | Also honor .gitignore files that are part of the transfer (their content must be uploaded first; the server evaluates them at commit). |
conflict_policy | 6 | ConflictPolicy | What to do with existing files. |
ttl | 7 | google.protobuf.Duration | How long partial data is kept without progress. Unset means 1 hour. |
Progress of one file in a transfer.
| Field | # | Type | Description |
|---|---|---|---|
index | 1 | uint32 | Index into the accepted entries. |
received_bytes | 2 | uint64 | Bytes received. |
Response for TeleportService.BeginReceiveFiles.
| Field | # | Type | Description |
|---|---|---|---|
transfer_id | 1 | string | The transfer id. |
accepted | 2 | repeated TransferEntry | Entries that will be received, in the order indices refer to. |
ignored | 3 | repeated string | Relative paths dropped by ignore patterns. |
progress | 4 | repeated TransferFileProgress | Progress per accepted file, for resuming. |
max_chunk_bytes | 5 | uint32 | Largest chunk accepted. |
Request for TeleportService.ReceiveFilesChunk.
| Field | # | Type | Description |
|---|---|---|---|
transfer_id | 1 | string | Which transfer. |
index | 2 | uint32 | Index into BeginReceiveFilesResponse.accepted. |
offset | 3 | uint64 | Offset of data[0] in that file. Must equal its received bytes; a chunk wholly below is a duplicate. |
data | 4 | bytes | File bytes. At most max_chunk_bytes. |
Response for TeleportService.ReceiveFilesChunk.
| Field | # | Type | Description |
|---|---|---|---|
received_bytes | 1 | uint64 | Bytes received for that file. |
duplicate | 2 | bool | True if the chunk was a retry. |
Request for TeleportService.CommitReceiveFiles.
| Field | # | Type | Description |
|---|---|---|---|
transfer_id | 1 | string | Which transfer. |
A file placed by a committed transfer.
| Field | # | Type | Description |
|---|---|---|---|
path | 1 | string | Final absolute guest path (after conflict renaming). |
size | 2 | uint64 | Size in bytes. |
sha256 | 3 | string | Verified lowercase hex SHA-256. |
Response for TeleportService.CommitReceiveFiles.
| Field | # | Type | Description |
|---|---|---|---|
destination | 1 | string | Absolute guest path of the transfer root. |
files | 2 | repeated ReceivedFile | Files placed. |
skipped | 3 | repeated string | Relative paths skipped by CONFLICT_POLICY_SKIP or by .gitignore rules evaluated at commit. |
Request for TeleportService.AbortReceiveFiles.
| Field | # | Type | Description |
|---|---|---|---|
transfer_id | 1 | string | Which transfer. |
Response for TeleportService.AbortReceiveFiles.
No fields.
Request for TeleportService.WipeImport.
| Field | # | Type | Description |
|---|---|---|---|
import_id | 1 | string | Import to wipe, as sent in ImportSessionRequest.import_id. Ignored when all is set. |
all | 2 | bool | Wipe every ledgered import in the guest. |
Response for TeleportService.WipeImport.
| Field | # | Type | Description |
|---|---|---|---|
wiped_import_ids | 1 | repeated string | Import ids whose ledgers were wiped and removed. |
removed_paths | 2 | repeated string | Absolute guest paths removed (files, and directories the import created). |
keychain_items_removed | 3 | uint32 | Keychain items removed (macOS guests; 0 elsewhere). |
cookie_rows_removed | 4 | uint32 | Cookie rows deleted out of an existing Cookies database the import merged into (not itself in removed_paths: it was not the import's file to remove). |
Which part of an app's state to teleport.
| Value | # | Description |
|---|---|---|
TELEPORT_SCOPE_UNSPECIFIED | 0 | Not set. Treated as TELEPORT_SCOPE_SESSION. |
TELEPORT_SCOPE_SESSION | 1 | Sign-in state only: cookies, local storage, session storage. |
TELEPORT_SCOPE_PROFILE | 2 | The whole profile: session plus history, bookmarks, extensions, settings. |
What to do when a received file already exists.
| Value | # | Description |
|---|---|---|
CONFLICT_POLICY_UNSPECIFIED | 0 | Not set. Treated as CONFLICT_POLICY_RENAME. |
CONFLICT_POLICY_RENAME | 1 | Keep both: the new file becomes "name (1).ext". |
CONFLICT_POLICY_OVERWRITE | 2 | Replace the existing file. |
CONFLICT_POLICY_SKIP | 3 | Keep the existing file and drop the new one. |
cua/env/v1/tunnel.proto#Request for TunnelService.Forward.
| Field | # | Type | Description |
|---|---|---|---|
port | 1 | uint32 | Guest TCP port to reach. |
host | 2 | string | Guest host to connect to. Empty means "127.0.0.1". Only loopback and the guest's own addresses are allowed. |
ttl | 3 | google.protobuf.Duration | How long the ticket accepts new connections. Unset means 10 minutes; at most 24 hours. Open connections survive expiry. |
Response for TunnelService.Forward.
| Field | # | Type | Description |
|---|---|---|---|
forward_id | 1 | string | Forward id. |
ticket | 2 | string | Ticket accepted by the tunnel WebSocket. Reusable for many connections until expiry. |
ws_path | 3 | string | WebSocket path relative to the spacesd base URL, including the ticket, for example "/tunnel?ticket=…". |
expires_at | 4 | google.protobuf.Timestamp | When the ticket expires. |
An active forward.
| Field | # | Type | Description |
|---|---|---|---|
forward_id | 1 | string | Forward id. |
host | 2 | string | Guest host. |
port | 3 | uint32 | Guest port. |
active_connections | 4 | uint32 | Open connections. |
bytes_in | 5 | uint64 | Bytes sent to the guest port. |
bytes_out | 6 | uint64 | Bytes received from the guest port. |
expires_at | 7 | google.protobuf.Timestamp | Ticket expiry. |
Request for TunnelService.ListForwards.
No fields.
Response for TunnelService.ListForwards.
| Field | # | Type | Description |
|---|---|---|---|
forwards | 1 | repeated ForwardInfo | Active forwards. |
Request for TunnelService.CloseForward.
| Field | # | Type | Description |
|---|---|---|---|
forward_id | 1 | string | Which forward. |
Response for TunnelService.CloseForward.
No fields.
Request for TunnelService.StartHotspot.
| Field | # | Type | Description |
|---|---|---|---|
socks_port | 1 | uint32 | Guest loopback port for the SOCKS5 listener. 0 means 1080. |
set_system_proxy | 2 | bool | Point the guest's system proxy settings (and HTTP(S)_PROXY for new processes) at the hotspot. |
bypass | 3 | repeated string | Destinations (CIDRs or host suffixes) that bypass the hotspot and use the guest's own network. |
ticket_ttl | 4 | google.protobuf.Duration | How long the ticket accepts the client's WebSocket. Unset means 60 seconds. |
Response for TunnelService.StartHotspot.
| Field | # | Type | Description |
|---|---|---|---|
hotspot_id | 1 | string | Hotspot id. |
ticket | 2 | string | Ticket for the hotspot WebSocket. |
ws_path | 3 | string | WebSocket path relative to the spacesd base URL, including the ticket, for example "/hotspot?ticket=…". The client keeps this socket open; the hotspot stops when it closes. |
socks_address | 4 | string | Guest-side SOCKS5 address, for example "127.0.0.1:1080". |
Request for TunnelService.StopHotspot.
| Field | # | Type | Description |
|---|---|---|---|
hotspot_id | 1 | string | Which hotspot. |
Response for TunnelService.StopHotspot.
No fields.
Request for TunnelService.GetHotspotStatus.
No fields.
Response for TunnelService.GetHotspotStatus.
| Field | # | Type | Description |
|---|---|---|---|
state | 1 | HotspotState | State. |
hotspot_id | 2 | string | Hotspot id, when not stopped. |
peer_principal_id | 3 | string | Id of the principal whose client provides egress. |
socks_address | 4 | string | Guest-side SOCKS5 address. |
active_connections | 5 | uint32 | Open relayed connections. |
bytes_out | 6 | uint64 | Bytes sent from the guest through the hotspot. |
bytes_in | 7 | uint64 | Bytes received into the guest through the hotspot. |
Hotspot state.
| Value | # | Description |
|---|---|---|
HOTSPOT_STATE_UNSPECIFIED | 0 | Not reported. |
HOTSPOT_STATE_STOPPED | 1 | No hotspot. |
HOTSPOT_STATE_WAITING_FOR_PEER | 2 | Started, waiting for the client WebSocket. |
HOTSPOT_STATE_ACTIVE | 3 | Relaying. |
cua/env/v1/volume.proto#Request for VolumeService.AttachVolume.
| Field | # | Type | Description |
|---|---|---|---|
mount_path | 1 | string | Where to mount. Empty means the guest's default (see the table above). |
ticket_ttl | 2 | google.protobuf.Duration | How long the ticket accepts the client's WebSocket. Unset means 60 seconds. |
Response for VolumeService.AttachVolume.
| Field | # | Type | Description |
|---|---|---|---|
volume_id | 1 | string | Volume session id. |
ticket | 2 | string | Ticket for the volume WebSocket. |
ws_path | 3 | string | WebSocket path relative to the spacesd base URL, including the ticket, for example "/volume?ticket=…". |
mount_path | 4 | string | Where the volume will be mounted. |
backend | 5 | string | nfs or fs: the target name the guest's streams carry, which the client answers. |
Request for VolumeService.DetachVolume.
| Field | # | Type | Description |
|---|---|---|---|
volume_id | 1 | string | Which session. Empty means the current one. |
Response for VolumeService.DetachVolume.
No fields.
Request for VolumeService.GetVolumeStatus.
No fields.
Response for VolumeService.GetVolumeStatus.
| Field | # | Type | Description |
|---|---|---|---|
state | 1 | VolumeState | State. |
volume_id | 2 | string | Volume session id (empty when detached). |
mount_path | 3 | string | Mount path. |
backend | 4 | string | nfs or fs. |
detail | 5 | string | Why, when state is VOLUME_STATE_ERROR. |
active_streams | 6 | uint32 | Open streams to the client. |
bytes_out | 7 | uint64 | Bytes sent from the guest to the client. |
bytes_in | 8 | uint64 | Bytes received from the client. |
State of the guest mount.
| Value | # | Description |
|---|---|---|
VOLUME_STATE_UNSPECIFIED | 0 | Not reported. |
VOLUME_STATE_DETACHED | 1 | No volume. |
VOLUME_STATE_WAITING_FOR_CLIENT | 2 | Attached by RPC, waiting for the client WebSocket. |
VOLUME_STATE_MOUNTING | 3 | Mounting. |
VOLUME_STATE_MOUNTED | 4 | Mounted and served. |
VOLUME_STATE_ERROR | 5 | The mount failed; see detail. |