Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b0929e9
SECURITY.md: describe what is signed and how the updater trusts it
fstubner Oct 7, 2026
79ea2fa
packaging docs: fix the npm example and four stale passages
fstubner Oct 7, 2026
f19206d
crate READMEs: make the core example compile and list what shipped
fstubner Oct 7, 2026
2bc4b12
CONTRIBUTING and ARCHITECTURE: fix Node, Linux packages, PR checklist…
fstubner Oct 7, 2026
bf6c1b0
Remove the 2026-08-29 acceptance run log from docs/
fstubner Oct 7, 2026
75326e0
PRODUCT.md: tell the origin the way the README does
fstubner Oct 7, 2026
26244ed
AGENTS.md: five small drifts
fstubner Oct 7, 2026
7006174
README: current desktop screenshot, and four small accuracy fixes
fstubner Oct 7, 2026
4508e8c
Remove two docs images nothing links to
fstubner Oct 7, 2026
e9b856e
Remove three docs screenshots that duplicate the site's own copies
fstubner Oct 7, 2026
41d5c92
.gitignore: ignore keys, env files and crash dumps
fstubner Oct 7, 2026
aa0d7e1
Give the three published crates keywords and categories
fstubner Oct 7, 2026
3551a77
CHANGELOG: add 0.3.5's Security entry, and fix one colon in 0.3.4
fstubner Oct 7, 2026
fd3325a
ux-walkthrough: bring the website half and one desktop gap up to date
fstubner Oct 7, 2026
08a79bf
netscli-mcp README: take the em dashes and semicolons out
fstubner Oct 7, 2026
dd591a7
PRODUCT.md: no em dash in the Rust constraint I re-wrapped
fstubner Oct 7, 2026
fc004cb
MICROSOFT-STORE.md: say how the README screenshot was taken
fstubner Oct 7, 2026
0bdf5e2
CONTRIBUTING: say 'You need Rust', not a bare fragment
fstubner Oct 7, 2026
62968e5
Give the published crates netscli.com as their homepage
fstubner Oct 7, 2026
2c2ac7b
Merge remote-tracking branch 'origin/main' into docs/repo-docs
fstubner Oct 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ bun-debug.log*

# Test outputs
#
# Scoped to the repo root rather than repo-wide (C-28): a bare `*.csv` also
# Scoped to the repo root rather than repo-wide: a bare `*.csv` also
# swallowed any legitimate CSV fixture a test might want to commit, and the
# only CSVs we actually want ignored are ad-hoc exports dropped at the top
# level while poking at the CLI.
Expand Down Expand Up @@ -62,6 +62,16 @@ nul
.netscli/
*.db

# Keys, environment files and crash dumps. Nothing tracked matches these, so
# they only catch a stray `git add .`. A key or certificate that really is a
# test fixture needs `git add -f`. Git Bash writes `*.stackdump` when a
# command crashes.
*.key
*.pem
.env*
*.stackdump
*.dmp

# Claude Code
.claude/

Expand All @@ -82,7 +92,7 @@ skills-lock.json

# Built by scripts/dev-gui-pcap.ps1, which sets a separate target dir so a
# pcap build does not clobber the normal one. Multiple GB, and it appeared as
# untracked noise throughout the documented Windows workflow (C-27).
# untracked noise throughout the documented Windows workflow.
/target-pcap/

# Written by scripts/check-linux.sh, from inside the container. Separate from
Expand All @@ -94,7 +104,8 @@ skills-lock.json
.superpowers/

# Local-only docs:
# - DEVLOG: rolling personal devlog, kept on disk but not part of public history
# - DEVLOG: rolling personal devlog, kept on disk and out of the tree (it was
# committed once and removed on 2026-05-03, so the early history has it)
# - release-drafts: raw blog / announcement notes before they are polished
# - docs/superpowers/{specs,plans}: brainstorm/plan artifacts that shouldn't
# leak into the repo's docs/ tree (the rendered design lives in CHANGELOG +
Expand Down
16 changes: 9 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ netscli/
netscli-gui/ # Desktop GUI (Tauri 2 + React 19 + TypeScript)
src/ # React frontend
src-tauri/ # Tauri Rust backend
scripts/ # OUI generator, install scripts (excluded from workspace)
scripts/ # OUI generator, install scripts, release/ helpers, check-*.mjs guards (excluded from workspace)
site/ # Astro/Starlight landing page + docs (netscli.com)
docs/ # Repo-internal docs (ARCHITECTURE, PUBLISHING, RELEASE) + assets
docs/ # Repo-internal docs (ARCHITECTURE, PUBLISHING, RELEASE, MICROSOFT-STORE) + assets
packaging/ # Distribution manifests and installer templates
```

Expand Down Expand Up @@ -52,7 +52,7 @@ cargo test -p netscli-core # targeted test run
./scripts/test-pcap.ps1 # Windows PCAP tests with Npcap SDK env
cd apps/netscli-gui && npm run test:unit # GUI helper tests
cd apps/netscli-gui && npm run build # GUI typecheck + Vite build
cd apps/netscli-gui && npm run test:tauri-render # Tauri render automation
cd apps/netscli-gui && npm run test:tauri-render # Tauri render automation, local only (not a PR check)

# Linting & formatting
cargo fmt # apply rustfmt
Expand Down Expand Up @@ -95,10 +95,10 @@ binary directly.

## Toolchain

- Rust **1.96.0** pinned in `rust-toolchain.toml` (includes rustfmt + clippy)
- MSRV: 1.96
- Rust at the version pinned in `rust-toolchain.toml` (includes rustfmt + clippy)
- MSRV: the same version (`rust-version` in `Cargo.toml`)
- Cargo resolver: v2
- GUI frontend: Node.js with npm, Vite, TypeScript
- GUI frontend: Node.js (the version in `.nvmrc`) with npm, Vite, TypeScript

## Key Dependencies

Expand All @@ -116,7 +116,7 @@ binary directly.
| `clap` 4.6 (derive) | CLI argument parsing |
| `ratatui` 0.30 + `crossterm` 0.29 | Terminal UI |
| `ratatui-textarea` 0.9 | TUI input editing (replaced `tui-textarea`) |
| `tauri` 2.0 | Desktop GUI framework |
| `tauri` 2 | Desktop GUI framework |
| React 19 + Vite + TypeScript | GUI frontend |

## Architecture Rules
Expand Down Expand Up @@ -166,6 +166,7 @@ All network operations are async (tokio). Long-running operations accept progres
| `oui.rs` | MAC vendor database (compressed gzip JSON) |
| `dns.rs` | DNS lookup (A, AAAA, CNAME, MX, NS, TXT, SRV, PTR, SOA, CAA) |
| `inspect.rs` | Combined host analysis (ping + scan + resolve) |
| `os_hint.rs` + `os_hint/` | A best guess at a host's OS from clues a scan already has, each with its source |
| `sweep.rs` | Full network sweep (discover + scan all hosts) |
| `trace.rs` | Traceroute; shells out to the platform tool |
| `mdns.rs` | mDNS/DNS-SD device discovery (behind `mdns` feature flag) |
Expand Down Expand Up @@ -251,3 +252,4 @@ Enforced in `ops/validation.rs` (subnet size) and `common/ports/` (port count),

- Use clear, imperative commit subjects (e.g., "Add scan timeout flag")
- PRs should describe user-facing impact, mention affected commands/modules, and note any required setup
- Branch protection on `main` requires the `CI Gate` and `Site Gate` checks, which are the summary jobs of `ci.yml` and `site.yml`. A PR needs both green.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,14 @@ its heading and collects entries. The date and the link go on with the tag.

### Security

- **Four open advisories cleared, all in build tooling.** `source-map-js`
1.2.1 → 1.2.2 (GHSA-68fv-2mgg-jv7q, high) is in the build dependencies of
both the desktop app and the website. The other three are the website's
alone, `http-cache-semantics` 4.2.0 → 4.3.0 (GHSA-ch52-4w7c-c8xp, high),
`sharp` 0.35.4 → 0.35.5 (GHSA-wq5f-xc86-pv6w, high) and `smol-toml` 1.8.0
→ 1.9.0 (GHSA-r4xh-jqrq-34v2, moderate). None of the four is in anything a
release ships.

- **MCP packet captures never overwrite a file or follow a symlink.**
`capture_pcap` wrote `capture.pcap` in the server's working directory,
often your project, and replaced any file of that name. On Linux and
Expand Down Expand Up @@ -444,7 +452,7 @@ its heading and collects entries. The date and the link go on with the tag.
Memcached say nothing until asked, so each gets the one read-only question
that returns its version. Scans report this as `product` and `version` in
the JSON, and in a Version column in the CLI, the terminal UI and the
desktop app. It's far narrower than nmap's `-sV`: a service that doesn't
desktop app. It's far narrower than nmap's `-sV`. A service that doesn't
announce itself, and isn't one of those three, gets no version.

- **UDP scanning.** `netscli scan <host> --udp` checks the UDP services most
Expand Down
73 changes: 67 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,23 @@ Issues and pull requests are welcome.

## Prerequisites

Rust 1.96.0, pinned in `rust-toolchain.toml`. The desktop app also needs
Node.js 18+.
You need Rust at the version pinned in `rust-toolchain.toml`. The desktop app
also needs Node.js 22 or newer. `.nvmrc` pins 22, which is what CI runs.

On Linux, `cargo test --all` and `cargo clippy --all-targets` compile the
desktop app's Tauri crate as well, and it will not link without the GTK and
WebKit development packages. On Debian or Ubuntu, CI installs these:

```bash
sudo apt-get install -y \
libpcap-dev pkg-config \
libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev \
librsvg2-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
```

`libpcap-dev` is only for packet capture builds. Other distributions have
equivalents, listed in
[Tauri's prerequisites](https://v2.tauri.app/start/prerequisites/).

## Building

Expand All @@ -32,9 +47,12 @@ window without it. To produce installers instead, use `npm run tauri build`.
Packet capture is feature-gated so the default binary has no non-Rust runtime
dependencies. Build it with `--features pcap`.

On Windows that also needs the Npcap SDK. `scripts/test-pcap.ps1` sets `LIB`,
`INCLUDE` and the runtime `PATH` for you, and `scripts/dev-gui-pcap.ps1` does
the same for the desktop app. Requirements are covered in the
On Windows that also needs the Npcap SDK and the Npcap runtime.
`scripts/test-pcap.ps1` sets `LIB`, `INCLUDE` and the runtime `PATH` for you,
and `scripts/dev-gui-pcap.ps1` does the same for the desktop app. Both look
for the extracted SDK in `NPCAP_SDK`, or in `%LOCALAPPDATA%\netscli\npcap-sdk`
when that is not set, and stop with an error if `Lib\x64\wpcap.lib` is not
there. Requirements are covered in the
[packet capture docs](https://netscli.com/docs/packet-capture/).

### Cross-compiling
Expand All @@ -44,16 +62,59 @@ rustup target add x86_64-unknown-linux-musl
cargo build -p netscli --target x86_64-unknown-linux-musl --release
```

### Checking the Linux code from Windows

`netscli-core` has Linux-only code, such as the ARP table and raw ICMP, that
a Windows build never compiles. `./scripts/check-linux.sh` runs clippy and
the tests for the three Rust crates in Docker, with every feature on. It
skips the desktop app and is not the macOS path, so CI is still the check
that counts.

## Before opening a PR

CI runs these checks, so run them before you push. If this list and
`.github/workflows/ci.yml` ever disagree, the workflow is right.

```bash
cargo fmt
cargo clippy --all-targets -- -D warnings
cargo clippy --all-targets --features pcap -- -D warnings
cargo test --all
```

If you changed the desktop app, also run these in `apps/netscli-gui`:

```bash
npm run lint
npm run test:unit
npm run build
```

And these from the repository root. They hold source files to about 300 lines,
check the design tokens, and check that the app's links into the docs site
still resolve:

```bash
node scripts/check-file-size.mjs
node scripts/design-tokens.mjs
node scripts/check-app-doc-links.mjs
```

Two more things are easy to miss. CI checks that the TypeScript types in
`apps/netscli-gui/src/types/generated` match the Rust structs they come from,
so after changing a struct the desktop app mirrors, regenerate them with the
command in the `TypeScript bindings match the Rust types` step of `ci.yml`.
And CI only compiles the Windows packet capture tests, so if you changed
packet capture code, run `./scripts/test-pcap.ps1` on a Windows machine with
Npcap installed.

Changes under `site/` run their own checks, listed in
`.github/workflows/site.yml`, starting with `npm run build` and `npm run check`
in `site/`.

Add tests for new behaviour, and update the docs under `site/src/content/docs/`
when you change something a user would notice.
when you change something a user would notice. The narrower per-crate commands
are under Contribution Gates in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).

## Repository layout

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ resolver = "2"
authors = ["Felix Stubner"]
license = "MIT"
repository = "https://github.com/fstubner/netscli"
homepage = "https://github.com/fstubner/netscli"
homepage = "https://netscli.com"
documentation = "https://docs.rs/netscli"
keywords = ["networking", "scanner", "tui", "cli", "mcp"]
categories = ["command-line-utilities", "network-programming"]
Expand Down
26 changes: 13 additions & 13 deletions PRODUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ Answer questions about a local network — what is on it, what is reachable,
what is listening — and return the answer as structured data rather than
text a human has to read and re-type.

The origin, from the README, was narrower: driving those questions from an
AI agent, which existing tools make awkward ("half a dozen CLI invocations,
brittle output parsing, no shared context"). The MCP server was built
first, then the TUI, CLI, and desktop app, all over one Rust core
The origin, from the README, was the terminal UI. It was built first, to
learn how the newer TUIs work, with a network scanner to give it something
to do. The MCP server came next, so an agent could ask about a network
instead of parsing output written for a person. The CLI followed, for
scripts and cron jobs, and the desktop app came last, all over one Rust core
(`netscli-core`).

**A tension worth recording.** The README and the website both lead with
the agent/MCP story, but the maintainer ranks agent-driven users *last* of
four (see Users). The code's history explains the emphasis; the priorities
below are what the product is actually for now. Where the two disagree,
this document is the current intent and the README is the origin story.
The README tells that history. The priorities below are what the product is
for now, and the maintainer ranks agent-driven users *last* of four (see
Users). Where the two disagree, this document is the current intent and the
README is the origin story.

## Users

Expand Down Expand Up @@ -83,10 +83,10 @@ a moment in time.

## Constraints

- **Rust 1.96**, one workspace, crates versioned together but not
inheriting a workspace version — each manifest carries its own, and a
release has to touch all of them plus `package.json` and
`tauri.conf.json`. See `docs/PUBLISHING.md`.
- **Rust**, at the version in `rust-toolchain.toml`, one workspace, crates
versioned together but not inheriting a workspace version. Each manifest
carries its own, and a release has to touch all of them plus
`package.json` and `tauri.conf.json`. See `docs/PUBLISHING.md`.
- **Privilege boundaries are real and platform-specific.** Raw ICMP needs
administrator rights on Windows; clearing the ARP table needs them
everywhere. Where a capability is unavailable the product must say so and
Expand Down
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ netscli arp # ARP table with vendor lookup
netscli interfaces
```

Every non-interactive command takes `--json` or `--yaml`, so results pipe
straight into `jq`, and the ones that return a list also take `--csv` and
Every command that returns a result takes `--json` or `--yaml`, so results
pipe straight into `jq`, and the ones that return a list also take `--csv` and
`--md`.

Run `netscli` with no arguments for the terminal UI: slash commands with
Expand All @@ -103,6 +103,12 @@ Full command reference: **[CLI](https://netscli.com/docs/cli/)** ·
}
```

That form needs netscli installed. To skip the install, use `npx` as the
command (`"command": "npx", "args": ["-y", "netscli", "serve"]`), or open an
`.mcpb` bundle from the
[latest release](https://github.com/fstubner/netscli/releases/latest) in a
client that supports them.

Nine tools by default: discover, scan, ping, DNS, ARP, inspect, sweep,
interfaces and mDNS. Packet-capture builds add four more. Details and the
full schemas are in the **[MCP guide](https://netscli.com/docs/mcp/)**.
Expand All @@ -117,6 +123,7 @@ full schemas are in the **[MCP guide](https://netscli.com/docs/mcp/)**.
| [Terminal UI](https://netscli.com/docs/tui/) | Slash commands and session behaviour |
| [Desktop app](https://netscli.com/docs/desktop/) | Tabs, filters, exports |
| [MCP server](https://netscli.com/docs/mcp/) | Tools, schemas, agent setup |
| [Interface coverage](https://netscli.com/docs/interface-coverage/) | Which capabilities each interface exposes |
| [Operations](https://netscli.com/docs/operations/) | What each scan actually does |
| [Result model](https://netscli.com/docs/result-model/) | Shape of the JSON and YAML output |
| [Packet capture](https://netscli.com/docs/packet-capture/) | Requirements and the pcap builds |
Expand All @@ -130,4 +137,4 @@ dev loop, packet-capture builds and the repository layout are all in

## License

MIT
MIT. See [LICENSE](LICENSE).
Loading
Loading