{
  "schema": "leumas.docs.page/1",
  "id": "skill:leumas-network#capabilities",
  "slug": "skills/leumas-network/capabilities",
  "kind": "tools",
  "bucket": "skill",
  "title": "The network capability, in full",
  "name": "The network capability, in full",
  "eyebrow": null,
  "chip": null,
  "summary": "Hand-written, not generated. Everything here is a decision or a shape that changes rarely; the live inventory of adapter packs is in leumas-capabilities/reference/adapters.md.",
  "keywords": [
    "leumas-network",
    "rarely",
    "leumas-capabilities",
    "inventory",
    "hand-written",
    "capture analysis arguments",
    "scan profiles",
    "filter languages"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# The network capability, in full\n\nHand-written, not generated. Everything here is a decision or a shape that changes rarely; the live\ninventory of adapter packs is in `leumas-capabilities/reference/adapters.md`.\n\n## Where the code is\n\n| Piece | Path |\n|---|---|\n| The SDK | `shared/engines/network/` — `@leumas/network-sdk` |\n| Browser-safe half | `shared/engines/network/src/client.js` — pure modules only, no node builtins |\n| Detection | `shared/engines/network/src/detect.js` |\n| Scan policy | `shared/engines/network/src/targets.js` |\n| Nmap provider | `shared/engines/network/src/providers/nmap/` — `args.js` · `parse.js` · `index.js` |\n| TShark provider | `shared/engines/network/src/providers/tshark/` — `args.js` · `parse.js` · `filters.js` · `index.js` |\n| What a device *is* | `shared/engines/network/src/normalize/devices.js` |\n| What a device is *called* | `shared/engines/network/src/normalize/present.js` |\n| Traffic rollup | `shared/engines/network/src/normalize/rollup.js` |\n| Snapshot comparison | `shared/engines/network/src/normalize/diff.js` |\n| Default route | `shared/engines/network/src/gateway.js` |\n| Running work | `shared/engines/network/src/jobs.js` |\n| Streaming routes | `shared/engines/network/src/router.js` |\n| Adapter pack | `shared/engines/adapters/domain/network/` |\n| API mount | `products/leumas-api/src/planes/appliance.js` → `mountNetworkTools` |\n| Studio surface | `products/leumas-studio/src/admin/information/network/` |\n| Tab registration | `products/leumas-studio/src/admin/information/model/tabs.js` |\n| Smoke test | `ops/infra/scripts/smoke-network.mjs` |\n\n## Verbs\n\nEvery one resolves; none throws for an expected outcome.\n\n| Verb | Does |\n|---|---|\n| `health({ refresh })` | which binaries exist, their versions, paths, and an install guide for the running platform |\n| `localNetworks({ listAdapters })` | the subnets this machine is on; `primary` is what \"my network\" means |\n| `defaultGateway()` | the address traffic leaves through — the one device nameable as a fact |\n| `discover({ target })` | what is on a network. No port is touched |\n| `inspect({ target })` | one device's common ports |\n| `services({ target })` | what software answers on those ports |\n| `inventory({ target, hostLimit })` | discover, then inspect everything found, in one nmap run |\n| `interfaces({ listAdapters })` | capture adapters, enriched with friendly names and addresses |\n| `capture({ interfaceIndex, … })` | a bounded live capture, streaming summaries |\n| `observe({ address })` | a capture filtered to one device |\n| `analyze({ file })` | a saved pcap, through the same normalizer as a live capture |\n| `validateFilter({ interfaceIndex, filter })` | check a BPF filter without capturing |\n| `snapshot(scan)` / `diff(before, after)` | the small history record, and what changed |\n\nThe adapter pack exposes the same set at `/api/adapters/network/<verb>`, as MCP tools, and as AI\nfunction-calls — one file on disk, three surfaces, no router written.\n\n## Routes\n\n`/api/network`, machine-local planes only, `requireAuth` + `toolLimit`.\n\n`GET /health` · `GET /networks` · `GET /interfaces` · `POST /filter/validate` · `POST /diff` ·\n`POST /scan` · `POST /capture` · `POST /analyze` · `GET /stream?job=` (SSE) · `GET /jobs` ·\n`GET /jobs/:id` · `POST /jobs/:id/cancel` · `DELETE /jobs/:id` · `GET /jobs/:id/file`\n\nLong work returns `202 { jobId }` and reports over SSE. Every job is scoped to its owner; somebody\nelse's job is reported **absent**, not forbidden, so the endpoint cannot be used to learn it exists.\n\n## Limits\n\nAll of them in `shared/engines/network/src/limits.js` — never a number typed into a component.\n\nCapture defaults 30s · 50,000 packets · 100 MB, whichever comes first. Ceilings 300s · 500,000 · 512 MB.\nScans default to a 120s budget and a 256-host limit, ceiling 1024. A pcap over 512 MB is refused by\nsize before tshark is spawned.\n\nThe Nmap tab sweeps automatically on arrival only when the detected network is at or under\n`AUTO_MAX_HOSTS` (1024 addresses) — anything larger renders the same page with a button and the count\nnamed. Results are cached for five minutes across mounts, because the tab remounts on every tab\nswitch and StrictMode mounts it twice.\n\n## Scan profiles\n\n| Profile | Arguments |\n|---|---|\n| `discover` | `-sn -T4 --stats-every 1s -oX -` |\n| `inspect` | `-sT -F -T4 --host-timeout 60s --stats-every 1s -oX -` |\n| `services` | `-sT -sV --version-intensity 2 -F -T4 -oX -` |\n| `inventory` | `discover`, then one `inspect` over every address found |\n\n`-sT` (connect) rather than `-sS` (SYN) throughout, because connect needs no privileges and an\noperator who is not an administrator is the common case. `-O` and `-sS` are offered only when\n`health().nmap.privileged` is true, and are dropped rather than failing when it is not.\n\n## Capture and analysis arguments\n\nLive: `-i N [-f BPF] -a duration:S -a filesize:KB -c N -w FILE -P -T ek -q -l`. All three bounds are\nalways set — any one alone is a capture that ends when something else runs out. `-w` plus `-P`\nwrites the pcap *and* prints summaries, which is what makes \"save this capture\" possible at all.\n\nFile: `-r FILE [-Y display-filter] -c N -T ek -e …` with the fields named explicitly, because\nwithout `-w` tshark is not in write-and-print mode.\n\nFilter validation: `dumpcap -i N -d -f FILTER` compiles and exits. Read the message, not the code.\n\n## The two filter languages\n\nThey look alike and are not the same, which is the most common thing to get wrong:\n\n- **Capture filter** (BPF, `-f`) decides what is **recorded**: `tcp port 443`. What it drops is gone.\n- **Display filter** (`-Y`) decides what is **shown** from what was already recorded: `tcp.port == 443`.\n\n`quickCheckFilter(text, kind)` catches the mix-up instantly and by name, which is far more use than\nhanding either one to a parser that will answer \"syntax error\".\n\n## Device identity\n\n`classifyDevice` scores vendor OUI, open ports and OS-detection evidence into\n`confident` (≥4) / `likely` (≥2) / `unknown`, and renders a matching label. A randomised MAC\nshort-circuits vendor matching entirely — phones rotate their hardware address per network, so\nreading a vendor off one produces confident nonsense.\n\n`presentDevice` then turns that into words: ISP suffixes stripped, UUID and MAC-shaped hostnames\ndiscarded, a consumer noun from the vendor when there is no usable name. It may not change a\nconfidence. `groupDevices` sorts into fixed sections — the router, this computer, what we recognised,\nwhat we could not — because the order *is* the sort for somebody who cannot sort a table.\n\n## Where results come from\n\nnmap ships the full IEEE OUI database and names most consumer hardware. `oui.js` in\n`@leumas/devices` knows a short hand-seeded list and is not a substitute. `arpNeighbours()` is fully\npassive but reads a sparse OS cache — measured at a fraction of what a sweep finds. If you want\nidentity, run the sweep.\n",
  "source": {
    "path": ".claude/skills/leumas-network/reference/capabilities.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 6986,
    "hash": "1da45a612f487a78c3d0dafc759bbc809df268c6"
  },
  "urls": {
    "html": "/p/skills/leumas-network/capabilities",
    "json": "/docs/skills/leumas-network/capabilities.json",
    "md": "/docs/skills/leumas-network/capabilities.md"
  },
  "links": {
    "composes": [],
    "usedBy": [],
    "product": [],
    "howTo": [],
    "skills": []
  }
}
