# 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`](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
0. 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.** `checkPolicy` runs 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 `mountNetworkTools` beside `/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` · `ok` are 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.** `classifyDevice` scores 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.


---
Source: .claude/skills/leumas-network/SKILL.md
Canonical: https://docs.leumas.tech/p/skills/leumas-network
