Leumas Network
Scan a network or capture packets from Leumas — nmap, wireshark, tshark, pcap, device discovery, capture filters, Information → Nmap and Information → Wireshark.
Looking at the network Leumas is running on
Two Information tabs over the operator's own installed binaries — nothing is bundled, nothing is installed on anyone's behalf. One SDK underneath, so the Studio surface, an MCP client, an AI function-call and a workflow node all call the same functions.
Information UI · MCP tool · AI functioncall · workflow node
↓ (all four, same functions)
shared/engines/adapters/domain/network/ ← HTTP + MCP + functioncall, no router written
↓
@leumas/network-sdk shared/engines/network/
↓ ↓
NmapProvider TSharkProvider
↓ ↓
runBounded(bin, args, { shell: false }) ← @leumas/runcode
Inventory of every verb, route and limit: reference/capabilities.md.
Reach for it when
| You want | Call |
|---|---|
| What is on this network | discover({ target }) — or the Nmap tab, which does it on arrival |
| What is this one device | inspect({ target }) · services({ target }) |
| Which adapters can capture | interfaces() |
| Watch traffic for a bounded period | capture({ interfaceIndex }) · observe({ address }) |
| Read a saved capture | analyze({ file }) |
| What changed since last time | snapshot(scan) then diff(before, after) |
| Does this machine even have the tools | health() |
Headless, the same thing: node ops/tools/run-tool/run-tool.mjs network discover '{"target":"127.0.0.1"}'.
The traps, each of which has already cost a pass
Detection cannot use PATH alone. Measured: tshark working from D:\Wireshark with where tshark finding nothing, and nmap under Program Files (x86) rather than Program Files. A PATH-only probe tells somebody running Wireshark that Wireshark is missing — the worst failure this feature can have, because it is indistinguishable from the truth. detect.js probes an env override, then PATH, then a per-tool table of real install locations. pnpm check:toolchains is PATH-only and will disagree; that is expected, not a bug.
-e ip.src is empty on IPv6. Those frames have no ip. field at all and -T ek omits absent fields rather than emitting a blank. On a dual-stack home network that is most* traffic, so the packet list renders with blank source and destination columns while every IPv4 fixture passes. Use _ws.col.def_src / _ws.col.def_dst.
-w plus -P -T ek ignores -e. Writing a pcap and printing summaries at once makes tshark emit its column set instead. Reading a file back has no -w, so it is not in that mode and needs the fields named explicitly — miss this and analysis returns the right number of packets with every field empty, while the live path looks perfect.
dumpcap -d exits 0 on an invalid filter when its output is piped. Read the Invalid capture filter text, never the exit code.
nmap's progress restarts per task. The ARP sweep reaches 100% and DNS resolution begins again at
- One unlabelled bar appears to run backwards; render the task name, or use
ProgressBar's
stages/stage.
routeInfo() in @leumas/devices/host is not usable here. Measured at over eight seconds for an empty answer. defaultGateway() in this SDK reads the routing table directly in about a fifth of a second. Do not "fix" one by calling the other.
**Studio CSS tokens are --color-, not --text-1/--surface-2/--accent.* An unknown custom property is invalid-at-computed-value-time: no warning anywhere, the page just renders flat and grey. This surface shipped that way once. shared/engines/network/test/theme-tokens.test.js now fails on an unresolvable var().
The rules that are not negotiable
- No shell string, ever. Every argument is a constant or a validated value in an array, spawned
shell: false. There is no free-text nmap/tshark argument box — the command that ran is shown instead, which is what an expert actually wanted from one.
- The policy lives in the SDK, not the caller.
checkPolicyruns inside every scan verb, so an
MCP client is bound exactly as the UI is. Private ranges and this machine's own subnets by default; anything wider needs an explicit allowPublic, and an oversize range is refused before a spawn.
- Machine-local planes only. Mounted in
mountNetworkToolsbeside/api/device-hub. On a hosted
plane the network being scanned would be the server's, so the routes must be absent, not gated.
- A refusal is data.
unavailable·refused·cancelled·okare fields on a resolved
object. Nothing throws for an expected outcome, and a cancel is never drawn as an error.
- Never state a guess as a fact.
classifyDevicescores evidence and the UI renders its hedged
label — "Possible router", never "Router" — unless several signals agree. Exactly two titles are allowed to be flat: "This computer" and "Your router", both from facts. Cleaning up a name in present.js must never strengthen a claim; that is why the two files are separate.
- Nothing captured is kept. A capture writes a bounded pcapng to a temp directory that is removed
unless the operator explicitly saves it. Payload bytes are never the default view.
Changing it
Guards: pnpm check:adapters check:mcp check:toolchains, pnpm smoke:network, and the package's own node --test test/*.test.js. Touching the surface adds check:ui-kit check:theme check:nav.
The fixtures under shared/engines/network/test/fixtures/ came off the real binaries — sanitised, but real shapes. Prefer adding one to inventing a shape by hand; every trap above was found by a fixture disagreeing with an assumption.
Related
leumas-guards for what to run · leumas-capabilities for how an adapter pack becomes three surfaces · leumas-domains for the Information tab strip itself.