Docs
/
what you can do

Devices

<!-- GENERATED by ops/tools/skill-sync — do not edit by hand. Run pnpm skills:sync. -->

<!-- GENERATED by ops/tools/skill-sync — do not edit by hand. Run pnpm skills:sync. -->

Devices — what you can do

/admin/d/devices · pillar devices

Every device you can reach - this browser, this machine, paired computers, and hardware that moves.

Fetch this, never remember it

These change per install and per release. Call for them - a list written here would be a future lie.

WhatCallWhy
every device this Studio can currently reachlist_devicesdevices arrive from several fleets and a fleet can be unreachable on this deployment; the answer is different on every install and on every day
which paired machines are online and what each will runlist_fabric_capabilitiesGET /api/fabric/capabilitiesA CAPABILITY IS OFFERED BY A MACHINE, NOT BY THE FABRIC - the index is derived from what nodes advertise right now, so it changes as machines come and go
whether the fabric is even present on this installfabric_statusGET /api/fabric/statuson a hosted install the fabric routes are absent rather than empty, and absent is a different answer from "no machines"
the protocols this build can speak to a devicelist_device_driversthe driver catalogue is what Leumas has code for, and can is DERIVED from what each driver actually implements - a verb missing from it is a real limitation, not an oversight
the machines physically attached to this computerGET /api/machinesthis lane exists ONLY on an install with the hardware attached, so its absence is the normal state on a hosted Studio. route-ok: mounted by mountLocalHardware in products/leumas-api/src/planes/appliance.js and therefore absent from the recorded route table, which is captured without local hardware

How to actually do things here

Written by hand, because the order and the traps are the part no file can derive.

Answer "what hardware do I have, and can I talk to it?"

  1. list_devices FIRST — every other tool takes an id from it.
  2. Read unreachableFleets on the result BEFORE saying a device does not exist. A hosted Studio has no machine to inspect, and that is not the same as an empty estate.
  3. get_device for one, device_summary for the shape of the whole estate.
  4. select_device and open_device_tab move the operator’s view, so they can see what you mean.

Trap: The page tools are READ-ONLY. They will not stop a process, delete a device or move a machine — the HTTP lane does that, on an install that has the hardware.

Send a print or a cut to a machine

  1. This is the machines lane, and it only exists where the hardware is attached. GET /api/machines lists them; GET /api/machines/printers is the printer-shaped view.
  2. Get a PROGRAM in — there are three doors and they all end in the same place. Already-sliced G-code: POST /api/machines/programs with the text. A 3D model: POST /api/machines/:id/slice (bytes go base64, not multipart; GET /api/machines/slice/status says whether a slicer is even installed). A board you designed: POST /api/machines/cam/pcb, with GET /api/machines/cam/profiles for the profiles.
  3. The create call returns the PREFLIGHT SCAN — time, peak temperature, bounding box. That scan is the product of the call, so read it rather than discarding it.
  4. Take the machine: POST /api/machines/:id/claim, then POST /api/machines/:id/connect. Only one session may hold a machine at a time.
  5. POST /api/machines/:id/preflight before anything moves. Then POST /api/machines/:id/jobs with the program id.
  6. Watch GET /api/machines/:id/stream. Control it with POST /api/machines/:id/jobs/pause, /resume or /cancel. Release it when done: POST /api/machines/:id/release.

Trap: [critical] THIS WORKS FOR A MACHINE ATTACHED TO THIS COMPUTER. A machine reached through a PAIRED NODE cannot be started from here: the node side is complete, but the control plane never calls its start verb, so a remote machine answers "connect the machine first" forever no matter how many times it is retried. Say that plainly rather than looping. CONFIRM WITH THE OPERATOR BEFORE ANYTHING MOVES — a machine cuts, heats and moves next to a person, and a job has no undo. A claim is a 15-minute lease renewed by each command, and it is exclusive: a refusal means somebody else holds it, which is a conversation rather than a retry. POST /api/machines/:id/estop is the stop of last resort and deliberately does NOT require the claim — a safety stop that needs a lock first is not a safety stop. route-ok: this whole lane is mounted by mountLocalHardware in planes/appliance.js, so it exists only on an appliance or dev install and is absent from the recorded route table, which was captured before it landed.

Run work on another computer the operator owns

  1. fabric_status first — the fabric may not be present at all on this install.
  2. list_fabric_capabilities for what the paired machines actually offer. Ask for a capability, never for a named computer: choosing the machine is the scheduler’s job.
  3. POST /api/fabric/run places the job.
  4. Follow it with list_fabric_jobs and fabric_job_events.

Trap: [critical] A FRESHLY PAIRED MACHINE RUNS NOTHING. The allowlist ships empty, so the first answer is usually a refusal — and the two refusals mean different things: "no node offers this" and "nodes offer it but all are offline" send an operator to two completely different places. fabric_node says what one machine will and will not accept, and why. Placing work is ADMIN-ONLY, and the reply is a job id with status 202 — never a result, because a capability may run for an hour and an HTTP request held open that long dies to a proxy timeout with the work still running and nobody able to find it. An unsatisfiable job fails immediately and names the requirement it could not meet.

Move a file or an asset between machines

  1. fabric_storage_summary for what the fabric is holding and where.
  2. list_fabric_objects for the objects themselves. An object is content-addressed and replicated, so it outlives the machine it was born on.
  3. Pin it where it is needed: POST /api/fabric/objects/:objectId/pin, and DELETE the pin to let it drift again.
  4. GET /api/fabric/storage is the per-node view of what is stored.

Trap: [critical] NO BYTE OF AN OBJECT PASSES THROUGH THE API. There is no upload route and no download route, by design — an object is content-addressed and enters the index only when a node ANNOUNCES that it holds it, and it is read by talking to a machine that has it. Studio holds the index, not the data, so its disk is never the ceiling on the fabric. Pinning keeps a copy on a node; an unpinned one may move. POST /api/fabric/media/stage is a DIFFERENT job — it writes an installer kit onto a removable drive so a new machine can join, and it is the only route here that writes the filesystem of the computer Studio runs on.

Work out why something will not connect

  1. Serial: list_serial_ports, then serial_port_holder — a port already held by another session is the usual answer.
  2. Network: list_network_adapters, list_connections, and adapter_throughput for live rates.
  3. Ports: list_listening_ports, then port_owner names the process sitting on it.
  4. IoT: list_device_drivers is the protocol CATALOGUE — what Leumas has code for, not what the operator owns.

Trap: unavailableHere is about THIS BROWSER, not the driver. Web Bluetooth and Web Serial do not exist in Firefox or on iOS and need a secure context. Never report that as broken hardware. Pairing is a browser permission gesture that only a real click can start.

Tabs

Every one is a real URL. A tab with its own section below carries a real job.

TabPathGroupWhat it is for
all-EverythingEvery reachable device across every fleet. The entry point — ids come from here.
audio-This browserEvery speaker in this home, ticked and played: outputs on this computer, on paired machines, on Chromecasts, on UPnP televisions and on Rokus. The front page finds them, groups them and proves one works.
audio/share-This browserSend what one machine is playing to Studio windows on the others, and choose which output each of them uses.
audio/speakers-This browserWhere every speaker came from — which protocol answered, what identifies it, and which addresses it has been seen at.
audio/sync-This browserMeasure the real latency — the socket round trip, the output path of this machine, and what a microphone actually hears.
audio/browser-This browserSpeakers and outputs THIS BROWSER can play through, and the test tone that proves one works.
cameras-This browserCameras this browser can open — and only after the person grants it.
mics-This browserMicrophones this browser can open, under the same permission gesture.
bluetooth-This browserBluetooth devices already paired with this machine.
wifi-This machineWhere this machine sits on the network, and which adapters it has.
ports-This machineWhat is listening on this machine, and which process owns it.
traffic-This machineLive connections and throughput per adapter.
fabric-The fabricMachines paired into the fabric: presence, capabilities, and what each one refuses.
compute-The fabricMachines offering compute, and what each is willing to run.
compute/jobs-The fabricWork handed to a compute node, and how each run ended.
capabilities-The fabricThe whole capability index — every verb the paired machines currently offer.
jobs-The fabricEvery fabric job, its events and how it finished.
storage-The fabricWhat the fabric is holding, where the copies are, and which are pinned.
installer-The fabricMake the media a new machine joins from — an installer kit written to a removable drive.
iot-MachinesThe driver catalogue — the protocols Leumas can speak, not the devices the operator owns.
printers-MachinesThe 3D printers this machine can reach, their state, and the jobs running on them.
cnc-MachinesCNC mills, routers and PCB machines — state, claim and the running job.
engraving-MachinesLaser engravers and markers — the fleet, the machine console, and the artwork lane that turns a photo, an SVG, a line of text or a raw program into something the beam can run.
serial-MachinesSerial ports on this machine, and which session is holding each one.
base8-MachinesThe ten-key macro pad: bind any key to anything this Studio can do.
sensors-MachinesSensor channels and their live readings.
sensors/layout-MachinesWhere each sensor physically sits, so a reading has a place attached to it.
sensors/recordings-MachinesCaptured sensor history, for what already happened rather than what is happening.
remotes-MachinesRemote controls and input devices bound to this Studio.
tv-MachinesEvery smart television and streaming player on this network — find them, keep them indexed, and drive each one with a remote. Roku, Vizio SmartCast and Google Cast, behind one vocabulary.
remote/admin/tv-The TV remote on its own page, at /admin/tv — the fleet picker, the remote, quick actions and a "play <title>" box, plus the television tools the Leviathan assistant uses.

Tabs in focus

all - All devices

Every reachable device across every fleet. The entry point — ids come from here.

Read with: list_devices | device_summary | get_device | fabric_status | list_fabric_capabilities

Write with: select_device | open_device_tab | refresh_devices

  1. list_devices, then check unreachableFleets before drawing any conclusion about what is missing.
  2. get_device for detail; select_device and open_device_tab to show the operator.

Trap: The only writes here move the operator’s VIEW. Nothing on this tab commands hardware.

audio - Audio

Every speaker in this home, ticked and played: outputs on this computer, on paired machines, on Chromecasts, on UPnP televisions and on Rokus. The front page finds them, groups them and proves one works.

Trap: TWO CONTROLS THAT SOUND ALIKE ARE NOT THE SAME THING. "Play a test sound" makes a short tone come out of everything ticked and works on every kind of speaker listed. "Share this computer's sound" sends a live stream to other Studio WINDOWS only — a Chromecast or a television fetches audio from an address and cannot receive it, and no lane exists that would let it. Never describe one as the other. A group is also as tight as its LOOSEST member, never an average.

audio/share - Audio → Share sound

Send what one machine is playing to Studio windows on the others, and choose which output each of them uses.

Trap: A SPEAKER THAT IS PLAYING IS NOT A SPEAKER THAT IS IN SYNC. Latency on this path is a few hundred milliseconds, because it is the browser one — getDisplayMedia in, MediaSource out. Quote the number the Sync Lab measured, never a target. The capturing machine is refused as a speaker of its own session, structurally, because loopback capture would feed its own output straight back in.

audio/speakers - Audio → How they were found

Where every speaker came from — which protocol answered, what identifies it, and which addresses it has been seen at.

Trap: An address that answered no discovery protocol is a CANDIDATE, never a speaker: it looks selectable and would never play. A speaker identified by its NAME is re-identified if somebody renames the device, which loses its saved delay. Multicast DNS finds Chromecasts and AirPlay; UPnP finds televisions and Rokus — a network that blocks either simply has fewer speakers on it, which looks identical to a home that has fewer.

audio/sync - Audio → Line them up

Measure the real latency — the socket round trip, the output path of this machine, and what a microphone actually hears.

Trap: Every number here was measured on THIS rig. Skew between two speakers is self-calibrating and worth acting on; a single-speaker reading includes the microphone path and is not the latency of that speaker alone. A median without its spread is not a measurement.

bluetooth - Bluetooth

Bluetooth devices already paired with this machine.

Read with: list_paired_bluetooth

Write with: refresh_paired_bluetooth

Trap: Pairing a NEW device is a browser permission gesture only a real click can start, and Web Bluetooth does not exist in every browser. An absent device may be an absent API.

wifi - WiFi

Where this machine sits on the network, and which adapters it has.

Read with: network_position | list_network_adapters

Write with: refresh_network

ports - Ports

What is listening on this machine, and which process owns it.

Read with: list_listening_ports | port_owner

Write with: refresh_ports

Trap: Freeing a port kills somebody’s process. That is an operator decision, and it is not a page tool.

traffic - Traffic

Live connections and throughput per adapter.

Read with: list_connections | adapter_throughput

fabric - Fabric

Machines paired into the fabric: presence, capabilities, and what each one refuses.

Read with: list_fabric_nodes | fabric_node

Write with: fabric_update_status | refresh_fabric

  1. list_fabric_nodes for who is paired and who is online.
  2. fabric_node for one machine — what it advertises, and what its policy will not allow.

Trap: Pairing, approving and revoking a node are operator decisions taken on this tab, not tool calls. A node that is paired but offline is a different problem from one that refuses the work.

compute - Compute

Machines offering compute, and what each is willing to run.

Read with: list_fabric_capabilities

Trap: A capability is offered by a MACHINE. If nothing advertises it, the honest answer is that this fabric cannot do it — not that the job is queued.

compute/jobs - Compute → Jobs

Work handed to a compute node, and how each run ended.

Read with: list_fabric_jobs | fabric_job_events

capabilities - Capabilities

The whole capability index — every verb the paired machines currently offer.

Read with: list_fabric_capabilities

Trap: Derived, never stored: it changes the moment a machine goes offline.

jobs - Jobs

Every fabric job, its events and how it finished.

Read with: list_fabric_jobs | fabric_job_events

Write with: refresh_jobs

storage - Storage

What the fabric is holding, where the copies are, and which are pinned.

Read with: fabric_storage_summary | list_fabric_objects

Write with: refresh_storage

  1. fabric_storage_summary for the shape.
  2. list_fabric_objects for the objects, then pin one where it is needed.

Trap: An object is content-addressed and replicated — it outlives the machine it was born on. An unpinned copy may move.

installer - Installer

Make the media a new machine joins from — an installer kit written to a removable drive.

Trap: This is a FILESYSTEM WRITE to a real drive, not a transfer to a device. It is how a machine is enrolled, not how work reaches one.

iot - IoT

The driver catalogue — the protocols Leumas can speak, not the devices the operator owns.

Read with: list_device_drivers | device_driver

Trap: can is DERIVED from what each driver implements, so a missing verb is a real limitation. unavailableHere is about this browser, not the driver.

printers - 3D printers

The 3D printers this machine can reach, their state, and the jobs running on them.

  1. The page tools here are named at RUNTIME (one hook serves printers and CNC), so call listTools on the live page rather than assuming a name.
  2. To actually print: add a program, slice it for the machine, claim it, preflight, then start the job — the "Send a print or a cut" recipe above is the whole sequence.

Trap: Two firmware FAMILIES are supported — GRBL and Marlin — with a variant of each. Klipper, OctoPrint, Moonraker, Repetier and Smoothie are NOT, and a Klipper port does not even speak G-code. What a machine can do is DERIVED from its dialect: a verb the firmware lacks is refused as "cannot", not as an error. A motion verb is accepted only while the machine is idle or paused, and a temperature above the machine ceiling is refused with the ceiling. Serial needs an optional native module; without it every serial call refuses honestly rather than throwing.

cnc - CNC / PCB

CNC mills, routers and PCB machines — state, claim and the running job.

Trap: Same lane and same rules as printers, with less margin for error: these cut. The CAM door takes a designed board and its drill file, nothing else. Engravers are NOT here any more — they have their own tab, which is also where the image lane lives. Preflight before anything moves.

engraving - Engraving

Laser engravers and markers — the fleet, the machine console, and the artwork lane that turns a photo, an SVG, a line of text or a raw program into something the beam can run.

  1. Page tools here are READ-ONLY. Nothing on this page fires a beam, jogs a head or starts a job from a tool call, and that is deliberate: the line here is not irreversible, it is PHYSICAL, and the operator may have their hands in the machine.
  2. To engrave headlessly: POST /api/machines/:id/art to make the program, POST /api/machines/:id/art/frame to trace where it will land, then POST /api/machines/:id/jobs to run it. Full paths, because an abbreviated one is a 404 an agent cannot explain.

Trap: THE BEAM WILL NOT FIRE AT ALL unless the machine row records an interlock (flags.laserInterlockFitted) — that is a refusal, not a fault, and it now applies to a running JOB and not only to the manual beam control. FRAME BEFORE YOU RUN: the frame traces the artwork outline at about 1% so the operator can see where it lands, and it is the cheapest thing on this page. Peak power in the program is checked against ceilings.laserPercent, and an S word above the controller's $30 is refused because GRBL CLIPS rather than scaling. Progress is ACKNOWLEDGED lines, which can be half a minute behind the head.

serial - Serial

Serial ports on this machine, and which session is holding each one.

Read with: list_serial_ports | serial_port_holder

Write with: rescan_serial_ports

Trap: A port already held is the usual reason a machine will not connect — check the holder before blaming the hardware.

sensors - Sensors

Sensor channels and their live readings.

Read with: list_sensor_channels | read_sensor_channel

Write with: refresh_sensors

tv - TVs

Every smart television and streaming player on this network — find them, keep them indexed, and drive each one with a remote. Roku, Vizio SmartCast and Google Cast, behind one vocabulary.

  1. Ask what this build can talk to FIRST: GET /api/tv/drivers. Each vendor carries can flags derived from what it implements and a notes object stating its limits in words. route-ok: mounted by mountTv inside caps.localHardware.
  2. Find what is there: POST /api/tv/discover (admin). Every driver is asked at once; byDriver says how many each found. route-ok: same mount.
  3. List what is known: GET /api/tv/devices. Offline devices are INCLUDED with a lastSeenAt, and each row carries driverLabel and needsPairing. route-ok: same mount.
  4. Read one, live: GET /api/tv/devices/:id — gives actions (the buttons THAT device really has), what is playing, the current input, and can. route-ok: same mount.
  5. Press a button: POST /api/tv/devices/:id/command with { action } — an action NAME (home, select, volumeUp), never a vendor protocol key. route-ok: same mount.
  6. Pair a Vizio before using it: POST /api/tv/devices/:id/pair with {step:"start"} puts a PIN on the screen, then {step:"finish", pin, token, challenge}. Admin-gated, because it mints a credential. route-ok: same mount.
  7. Apps, text and inputs: GET /api/tv/devices/:id/apps then POST .../apps/:appId/launch; POST .../text; GET .../inputs then POST .../input. route-ok: same mount.
  8. The same verbs are on the adapter surface as tv.* (POST /api/adapters/tv/<verb>), which is what an MCP client, a chatbot and a workflow node reach. Identical behaviour, but METERED — use /api/tv for anything interactive.

Trap: ASK THE DEVICE WHAT IT CAN DO, AND ASK THE VENDOR FIRST. The three drivers are not equivalent and the differences are not cosmetic. [critical] A GOOGLE CAST DEVICE HAS NO REMOTE AT ALL — the buttons live behind the binary CASTV2 protocol on port 8009, which Leumas does not speak, so can.command is false and there is nothing to press. [critical] A VIZIO CANNOT BE TYPED INTO and has no play/pause: SmartCast has no text endpoint, and no publicly confirmed transport key codes, so those are absent rather than guessed. [critical] A VIZIO MUST BE PAIRED before anything but its power state can be read, and pairing needs a human to read a PIN off the screen — an agent cannot complete it alone. A ROKU PLAYER has no volume and cannot be turned on over the network once fully off; a Roku TV has both. apps reports inventory: "device" when the list was read off the television and "catalog" when it is what that model usually carries — only Roku can be asked, so a Vizio or Cast entry may simply not be installed and launching it will quietly do nothing. wake reports that an ATTEMPT was made, never that the screen came on. Discovery is per-vendor and mostly SSDP, which does not cross subnets; a device on another network is added by address instead.

remote - TV remote

The TV remote on its own page, at /admin/tv — the fleet picker, the remote, quick actions and a "play <title>" box, plus the television tools the Leviathan assistant uses.

Address: /admin/tv

  1. This page registers LIVE TOOLS while it is open: list_tvs, describe_tv, select_tv, press_button, open_app, play_title, type_text, set_power. They are what let somebody say "put Netflix on the living room TV" rather than clicking.
  2. ALWAYS call describe_tv before pressing anything. It returns the buttons THIS device actually has, whether it can search, what is playing, and what that brand cannot do, in words.
  3. To play a specific film or show, prefer play_title — it asks the television to search every service it has. Use open_app only when somebody names an app rather than a title.

Trap: THE PAGE AND THE TVs TAB ARE THE SAME COMPONENTS IN DIFFERENT FRAMES, not two implementations — the tab is for managing televisions (find, pair, rename), this page is for using one. [critical] NEVER SAY SOMETHING IS PLAYING. No television here reports that: play_title returns "asked the TV to find and open X", and a model that upgrades that to "it is on now" is telling somebody a fact while they look at a search screen. play_title only exists on Roku — check canSearch before offering it, or a Vizio owner is promised something that cannot happen. A device that needs pairing cannot be driven at all, and pairing needs a person to read a code off the screen, so an agent must stop and say so rather than retrying.

Ways in

Declared cross-links. Every address is matched against the real route table by check:huds.

FromDoesGo to
devices/hub:fabricMake a stick/admin/d/devices/installer
devices/hub:computeWhat it will run/admin/d/devices/capabilities

Tools an agent can call here

These are live page capabilities: they exist only while that surface is open, and they call the page's own mutators, so a change made through one is a change the operator can see. A tool missing from this list is not callable — reach for the API or an adapter instead.

devices:fabric — Devices → Fabric

Source: devices/capabilities/useFabricTabCapabilities.js

What the page tells an agent about itself:

This tab lists the OTHER machines this operator owns, paired into this Studio. It is not the browser devices and not the compute targets. Presence: online and idle both mean reachable — idle means recently seen, not gone. pending is a machine waiting to be approved, orphaned has lost its way back, revoked has been cut off deliberately.
ToolArgsDoes
list_fabric_nodespresenceEvery machine joined to this Studio — its name, presence, platform, version and whether it is behind on updates. Call this first; the other fabric tools take a nodeId from it.
fabric_nodenodeIdOne machine in detail — what it offers the fleet and why it might not be usable right now.
fabric_update_statusWhich release channel this Studio follows, whether the hourly sweep is on, and which machines are behind.
refresh_fabricRe-read the fleet.

devices:storage — Devices → Storage

Source: devices/capabilities/useFabricTabCapabilities.js

What the page tells an agent about itself:

This tab is the object store spread across the machines in the fabric. An object at risk has fewer copies than it was asked to keep, which means one machine going offline can lose it. The table is currently filtered to AT-RISK objects only. The table currently shows all objects. Lead with what is at risk rather than with the total size — a summary that says "4.2 TB across 6 machines" looks healthy while a single-copy object is one failure from gone.
ToolArgsDoes
fabric_storage_summaryHow much the fabric is holding, across how many machines, and how much of it is under-replicated.
list_fabric_objectsatRiskOnlyThe objects in the store — their size, how many copies exist and which machines hold them. Lead with the at-risk ones.
refresh_storageRe-read the object store.

devices:jobs — Devices → Jobs

Source: devices/capabilities/useFabricTabCapabilities.js

What the page tells an agent about itself:

This tab is work placed on the fabric — what ran, where, and what it produced. The live feed is attached, so the newest events are current. The live feed is NOT attached right now, so the durable list may be ahead of the events. You cannot cancel or retry a job. Both reach a running process on a machine somebody else is using.
ToolArgsDoes
list_fabric_jobsstatusRecent work placed on the fleet — its status, which machine took it and how long it ran.
fabric_job_eventsThe live event tail — what the fleet is doing right now. Use it when a job is still running and the durable row has not settled.
refresh_jobsRe-read the job list.

devices:iot — Devices → IoT

Source: devices/capabilities/useIotCapabilities.js

What the page tells an agent about itself:

This tab is the DRIVER CATALOG — the protocols Leumas has code for. It is not a list of devices the operator owns. can is derived from what each driver actually implements, so a verb missing from it is a real limitation, not an oversight. unavailableHere is about THIS BROWSER, not the driver: Web Bluetooth and Web Serial do not exist in Firefox or on iOS, and neither works outside a secure context. Never report that as broken hardware. You cannot connect a device. Pairing is a browser permission gesture that only a real click can start.
ToolArgsDoes
list_device_driversEvery protocol Leumas can speak in this browser — the transport, what each driver can do, and whether this browser can use it at all.
device_driveridOne driver in detail, including the fields its connect form asks for. Use it to answer "what do I need to connect an X".

devices:… — Devices → …

Source: devices/capabilities/useMachinesCapabilities.js

What the page tells an agent about itself:

This tab lists the ${noun}s this Studio can reach — either plugged into this computer or attached to a machine in the fabric. State: idle means connected, homed and ready — NOT that something is wrong. running is a job in progress, alarm and error need attention, disconnected means no session is open. A machine must be CLAIMED before it accepts anything, and only one session may hold it at a time. heldBy on the Serial tab is the usual reason a connection fails. You cannot jog, home, heat, run, e-stop or send a console line. These machines move, cut and get hot next to a person, and a jog has no undo — read the state, explain it, and let the operator press the control.

6 more tool(s) on this scope are named at runtime (a computed key, or built by a helper), so they cannot be listed here. Call listTools on the live page to see them.

devices:wifi — Devices → WiFi

Source: devices/capabilities/useNetworkCapabilities.js

What the page tells an agent about itself:

This tab describes the network position of the machine running this Studio: its adapters, the address other machines reach it on, its gateway and DNS, and its wireless link if it has one. Loopback adapters are filtered out of the table on screen. reachableAt is the address to give somebody who needs to connect to this Studio. You cannot start a LAN scan or adopt a discovered host. A scan sweeps a subnet, is audited, and on a corporate network looks like reconnaissance — the operator presses it.
ToolArgsDoes
network_positionWhere this machine sits on the network — the address others reach it on, its gateway, its DNS servers and its wireless link quality. Use it for "what is my IP" and "why can nothing reach this Studio".
list_network_adaptersEvery network adapter on this machine and the addresses bound to each. Loopback is excluded.
refresh_networkRe-read this machine’s network configuration.

devices:traffic — Devices → Traffic

Source: devices/capabilities/useNetworkCapabilities.js

What the page tells an agent about itself:

This tab shows the established connections of the machine running this Studio, and per-adapter throughput. Sampling is running, so the rates are current. Sampling is PAUSED. Byte totals are still accurate, but a rate needs two samples and there are none — do not report a rate of zero as an idle network. You cannot stop a connection or a process from here.
ToolArgsDoes
list_connectionsThe established connections on this machine, with the process behind each one. Use it for "what is this machine talking to".
adapter_throughputHow much each adapter is moving right now, and how much it has moved since the machine came up.

devices:bluetooth — Devices → Bluetooth

Source: devices/capabilities/useNetworkCapabilities.js

What the page tells an agent about itself:

This tab has two halves. The one you can read is the OPERATING SYSTEM’s paired list on the machine running this Studio. The other half is Web Bluetooth inside this browser, and it is deliberately not exposed: pairing there is a permission gesture that only a real click can open, and the chooser cannot be driven by a tool. A device being paired with the machine does NOT mean this browser can talk to it, and vice versa. Do not merge the two.
ToolArgsDoes
list_paired_bluetoothBluetooth devices already paired with the machine running this Studio, and the radios it has.
refresh_paired_bluetoothRe-read the machine’s paired list.

devices:ports — Devices → Ports

Source: devices/capabilities/usePortsCapabilities.js

What the page tells an agent about itself:

This tab lists the listening sockets on the machine running this Studio, joined to the process that owns each one. Call list_listening_ports first — port_owner takes a port number and is only useful once you know which ports exist. The table currently includes ESTABLISHED connections as well as listeners. The table currently shows LISTENING sockets only, so an outbound connection will not appear. You cannot stop a process. That needs a human, because it is irreversible — say which port and which process instead, and let the operator press it.
ToolArgsDoes
list_listening_portsEvery socket in the Ports table right now — the port, the process holding it, its pid and the address it is bound to. Call this before port_owner.
port_ownerportWhich process is holding one specific port. Use it to answer "why can I not bind to 3000".
refresh_portsRe-read the socket table. Use it after the operator has started or stopped something.

devices:sensors — Devices → Sensors

Source: devices/capabilities/useSensorsCapabilities.js

What the page tells an agent about itself:

This tab shows live channels on sensor boards plugged into the machine running this Studio over USB. ALWAYS report lastAt alongside a value. A board that stopped reporting still has a last value, and quoting it as the current reading is the main way a monitoring surface misleads. state: "live" means it is genuinely streaming. You cannot connect a board or start a recording — connecting takes a serial port away from whatever holds it, and a recording writes to disk.
ToolArgsDoes
list_sensor_channelsEvery channel the connected boards offer — what it measures, its unit, its latest value and when that value arrived. Call this first.
read_sensor_channelid limitThe recent history of one channel — the values this tab has seen streaming, oldest first. Use it for "is it rising" rather than for one number.
refresh_sensorsRe-read the channel list from the boards.

devices:serial — Devices → Serial

Source: devices/capabilities/useSerialCapabilities.js

What the page tells an agent about itself:

This tab lists every USB serial port on the machine running this Studio. heldBy is the important field: it names the machine session inside this Studio that has already claimed the port. A port that is held cannot be opened again, and that is the usual reason a connection fails. The host cannot enumerate ports right now: ${unavailable} You cannot open a port, write to one, or disconnect a session. Say what is holding it and let the operator act.
ToolArgsDoes
list_serial_portsEvery USB serial port on this machine — its path, what the device says it is, and which machine session is holding it.
serial_port_holderpathWhether one specific serial port is free, and which machine is holding it if not. Use it for "why can I not open COM7".
rescan_serial_portsRe-enumerate the serial ports. Use it after the operator has plugged something in.

devices:hub — Devices

Source: devices/model/useDeviceCapabilities.js

What the page tells an agent about itself:

This is the Devices console. Call list_devices FIRST — every other tool takes an id from it. Devices come from several fleets and a fleet can be unreachable on this deployment (a hosted Studio has no machine to inspect), so check unreachableFleets before telling the operator a device does not exist. You can highlight a device and change tabs, but you cannot stop a process or delete a device — those need a human.
ToolArgsDoes
list_devicesstate sourceEvery device this Studio can reach, from every fleet — the registry, paired phones, compute workers, Cast machines and signed-in browsers. Call this first: every other tool takes an id from it.
device_summaryHow many devices there are and how many are reachable right now.
list_fabric_capabilitiesWhat the machines joined to this Studio can actually do — each capability, which machines offer it, and how many could take work right now. Read-only: running one is a decision a person makes on the Capabilities tab.
fabric_statusThe pooled capacity of every machine joined to this Studio: how many are reachable, and the threads, memory and GPUs they add up to right now.
get_deviceidEverything known about one device, by the id from list_devices.
select_deviceidHighlight a device on the map and in the table, so the operator can see which one is being discussed.
open_device_tabtabMove the console to one of its tabs: overview, ${DEVICE_TAB_IDS.join(', ')}.
refresh_devicesRe-read every fleet. Use it after somebody has plugged something in.

1 more tool(s) on this scope are named at runtime (a computed key, or built by a helper), so they cannot be listed here. Call listTools on the live page to see them.

devices:tv

Source: devices/tv/useTvCapabilities.js

What the page tells an agent about itself:

You can drive the televisions on this network. ALWAYS call describe_tv before pressing a button or opening an app — the brands differ enormously and it tells you exactly what THIS device can do. To play a specific film or show, prefer play_title: it searches every service the television has. Use open_app only when somebody names an app rather than a title. Never tell somebody something is playing. The televisions do not report that. Say what you asked the TV to do. If a device needs pairing, say so and stop — pairing needs a person to read a code off the screen.
ToolArgsDoes
list_tvsEvery television and streaming device Leumas knows about, with whether each is reachable and which brand it is. Call this FIRST — the brands differ enormously in what they can do.
describe_tvWhat the SELECTED television can actually do right now — which buttons it has, what is playing, whether it can search for a title, and anything its brand cannot do. Call this before pressing anything.
select_tvdeviceIdChoose which television the remote controls. Takes the id from list_tvs.
press_buttonactionPress one button on the selected television. Use ONLY a name from describe_tv's buttons list — the brands differ and an unsupported name is refused.
open_appappOpen an app on the selected television by name — Netflix, YouTube, Hulu, Disney+, Prime Video. Opens the app at its home screen; use play_title to open a specific film or show.
play_titletitle type providerAsk the television to FIND a film, show or channel and open it, across every service it has. This is the right tool for "play Blade Runner" — it does not need to know which app has it. Only some brands can do this; check describe_tv's canSearch first.
type_texttext submitType text into whatever field the television has focused — a search box, a login. Only some brands can receive text; check describe_tv.
set_poweronTurn the selected television on or off. Turning ON only works on some devices — it reports that an attempt was made, never that the screen came on.

Traps

READ THE REACH BEFORE THE TAB. A browser device needs a permission gesture; a machine-local one needs an install with the hardware; a fabric one needs a node that is online. The same question has three different answers depending on which. The 36 page tools are READ-ONLY, and so is every MCP tool here — /mcp is unauthenticated, so a write tool would be a stranger with a kill switch. The fabric deliberately publishes four read-only tools and refuses to expose a run verb, because that would be a remote shell for every machine the customer owns. Driving hardware happens on the authenticated HTTP lane and nowhere else. The control-device action is NOT the machines lane: it reaches sensor boards only, with four typed verbs, and there is deliberately no free-text command path. It also cannot reach a browser-side device — only the page holding that driver can. The raw machine console is refused unless it was switched on for that machine or the caller is an admin, because a single console line can wipe stored firmware configuration. /api/device-hub, /api/fabric and /api/machines exist only where the hardware does. On a hosted Studio they are ABSENT rather than forbidden, and the panels read that 404 as "this deployment does not carry them" — a different answer from a refusal. The browser tabs — audio, cameras, mics — work EVERYWHERE, including hosted, because they are pure browser APIs and need only a permission gesture. The printer and CNC tabs are deliberately NOT hidden on a hosted install, because a machine can be reached two ways: plugged into this computer, or attached to a paired node. Hiding them on one axis would hide the product on the other. The panel explains its own reach instead — so a visible tab is not a promise that a machine is reachable. When the estate looks empty, read unreachableFleets before concluding anything: the All tab joins seven separate sources and any of them can be down or absent independently. A machine is claimed exclusively. A refusal usually means somebody else is holding it, not that the call was wrong. Devices is structurally ungateable: a pillar a tenant could remove would leave a dead header link.

Source .claude/skills/leumas-studio/reference/domains/devices.md (no-git)markdownjson
Generated from the Leumas repository. Every page cites the file it came from.leumas.techllms.txt