License & Third-Party Notices

VERSION a9b38ce
License & Third-Party Notices

meshfox itself is MIT-licensed (see LICENSE, also inlined below). This document tracks every third-party dependency pulled into the published binary/bundle — backend (Rust crates, Cargo.toml) and UI (npm packages, web/package.json) — and records the license-compatibility check against MIT.

Only direct dependencies are listed by name below; the full transitive tree actually reachable from a shipped binary (628 Rust crates on macOS — normal-dependency edges only, dev/build-only trees excluded, since those never compile into what's published; 187 npm production packages) was checked programmatically and is summarized in "License compatibility" — nothing in it requires anything beyond attribution, with weak-copyleft exceptions noted below (option-ext; cssparser/selectors, both via scraper). The Rust-side count jumped from 321 once meshfox tui (see "Usage") landed — syntax highlighting (syntect) and terminal image rendering (ratatui-image, image) both pull real transitive weight; image's own default codec set was trimmed to just png/jpeg/gif/webp/bmp to keep that from growing further than it has to. It grew by another 27 once meshfox check-updates (see "Usage") landed — self_update's GitHub-release polling, tarball extraction, and TLS (rustls, built with the ureq HTTP backend rather than reqwest, to keep that addition as small as it can be) each pull their own small tree. It grew by another 62 once meshfox pdf (see "Usage") landed — headless_chrome (drives a real Chrome/Chromium to print the HTML static export to PDF, downloading a pinned Chromium build via its own fetch feature when no system browser is found) and lopdf (merges the diagram-overview and document-flow pages into one PDF) each pull their own tree. One of headless_chrome's transitive deps, option-ext (via directories/dirs-sys, used to locate the Chromium download cache), is MPL-2.0 rather than MIT — weak, file-level copyleft that only obligates keeping that crate's own source available/modifiable if redistributed in modified form; it doesn't extend to the rest of this binary (same as cssparser/selectors below, once scraper reached it for real). meshfox pdf also gave both its own printed pages and meshfox static's own site-template the same font the web UI already uses (crates/cli/src/pdf/templates/'s CSS, site-template/style.css). pdf's own copy isn't a second embedded copy at all: web/dist (Vite's build output) is already embedded into this same binary via rust-embed for the web UI's own sake (crates/server's WebAssets), so meshfox_server::find_web_asset just pulls the same @fontsource/fira-code bytes back out of that already-embedded bundle at PDF-generation time (weights 400/700, latin+cyrillic subsets — pdf runs against arbitrary canvases, so it keeps both this project's own content actually mixes) rather than shipping a redundant include_bytes!-embedded copy of its own; if web/ hasn't been built into this particular binary, the lookup just comes back empty and that @font-face silently falls through to the page's own CSS fallback stack instead of failing the export. site-template/fonts/ is a separate, genuine copy (loose files, latin only, weights 400/500/600/700 — that template is this repo's own working example, used to publish README.md itself, all-English) since a static-site export has no already-compiled binary to borrow bytes from — copied straight from the same npm package's own build, own fonts/LICENSE alongside it, same OFL-1.1 font-file-level attribution requirement as the npm entry below. A template built for other content can add back whatever subsets it needs (latin-ext/cyrillic-ext — Central/Eastern-European accented Latin, historic/extended Cyrillic — neither this repo's own template nor pdf needs). It grew by another 4 once constraint fences gained read access to a file-type node's own already-declared target (.content()/.json()/.yaml()/.toml()/.csv() — see "Constraint fences") — JSON and TOML parsing already leaned on serde_json/toml (both already direct deps for other reasons), so only .yaml()/.csv() needed new ones: csv (plus its own small csv-core) and serde_norway (plus its own unsafe-libyaml-norway) — the latter a maintained fork of serde_yaml, which upstream itself now points people away from. It grew by another 19 (on macOS — this pulls a different, platform-specific clipboard backend on Linux/Windows) once meshfox tui gained its own fullscreen source editor (e, see "Usage") — edtui (the editor widget itself: buffer, cursor, vim-style input, and — via its own syntax-highlighting feature — a second, independent syntect instance from the one markdown.rs's read-only code-fence highlighting already uses) pulls in arboard for system-clipboard copy/paste (objc2/objc2-app-kit/objc2-core-foundation/objc2-core-graphics/objc2-encode/objc2-foundation on macOS), plus onig/onig_sys — an alternate regex engine syntect's own default features pull in alongside the regex-fancy one this binary already asks for elsewhere, since Cargo unifies a shared dependency's features across the whole build rather than keeping two differently-configured copies. onig_sys vendors the Oniguruma C library itself, BSD-2-Clause; everything else in this batch (edtui, edtui-jagged, arboard, the objc2* family, plist, quick-xml, tiff) is MIT or a permissive MIT/Apache-2.0/Zlib choice. crossterm itself was bumped 0.28 → 0.29 in the same change, purely to match the version edtui (and ratatui 0.30's own ratatui-crossterm backend) already depends on — Cargo can't unify two different 0.x majors of the same crate the way it does minor/feature differences within one, so without this bump the binary would've ended up with two distinct, mutually-incompatible crossterm::event::KeyEvent types instead of one. meshfox_server gained two more direct deps once link nodes' preview="true" (see SPEC.md's "Node types") landed — reqwest (default-features = false, just the rustls feature, matching this binary's existing TLS-backend preference over native-tls/OpenSSL) for the SSRF-hardened OpenGraph fetch itself, and scraper (Selector::parse/.select() against the fetched HTML, crates/server/src/link_preview.rs) for parsing its <meta property="og:..."> tags — this is also where scraper's own transitive cssparser/selectors (both MPL-2.0, weak/file-level copyleft, same terms as option-ext above) first actually reached the published binary, despite crates/cli's own separate dev-only copy of scraper (used by its own tests) predating it. Both reqwest/scraper were already reachable elsewhere in the workspace's own dependency graph before this — reqwest as a transitive dep of self_update (see the check-updates entry above), scraper as that crates/cli-dev-only copy — so promoting them to real, direct meshfox_server deps added meaningfully less new transitive weight than a from-scratch addition of either would have. It grew by one more once runnable fences gained their own interpreter="..." attribute (generalized from the file-node attribute of the same name, see SPEC.md's "Runnable code fences") — shlex splits that shebang-style command+flags string into a program name and argument list; it's a tiny, dependency-free crate (no transitive tree of its own). node find (see "Usage") promoted crates/cli's own scraper copy from dev-only to a second real, direct use — CSS-selector matching against a synthetic HTML skeleton of the canvas tree (crates/cli/src/main.rs's find_node_ids), the same engine link_preview.rs already uses — adding no new transitive weight at all, cssparser/selectors having already reached the binary via meshfox_server as described just above. meshfox mcp (see "Usage") added rmcp — the official Rust SDK for the Model Context Protocol, server+transport-io features only (a stdio tool server, nothing else) — plus its own schemars (JSON Schema generation for each tool's parameters). Both, and everything either pulls in transitively (rmcp-macros, pastey, dyn-clone, schemars_derive, serde_derive_internals, tracing/tracing-attributes, the futures/futures-channel/futures-executor family), are MIT/Apache-2.0/dual — no new copyleft exceptions beyond the ones already noted above. uuid/libc/serde_json were already documented above (via meshfox_server); this just promotes each to also be a direct dependency of crates/cli (session ids, process-group kill signals, and structured tool results), adding no new rows. It grew by 3 more (on macOS) once meshfox mcp gained multi-canvas support (canvas_open/canvas_close/canvas_list, see "Usage") — rmcp picked up its own client+transport-child-process features so the same binary can also act as an MCP client, spawning meshfox mcp <file> as an isolated child process per opened canvas and talking to it over its own stdio (the same mechanism an MCP host uses to launch us in the first place, just one level up). transport-child-process pulls in process-wrap for reliable process-tree spawning/killing, which in turn pulls in nix (Unix syscalls) and tokio-stream; a fourth transitive, windows (plus its own small windows-collections/-future/-numerics/-threading family), is cfg(windows)-only and never reaches this macOS binary at all. All of it is MIT or MIT/Apache-2.0 dual — no new copyleft exceptions. It grew by exactly 1 more once the TUI's read-only preview and its fullscreen editor (e) were unified onto one shared grammar set (see "Usage") — syntect-tmlanguage (loads real TextMate .tmLanguage.json grammars into syntect's own SyntaxDefinition, MIT OR Apache-2.0) was the only new Cargo.lock entry the change added (checked via git diff Cargo.lock): its own syntect/serde/serde_json/thiserror/yaml-rust dependencies were all already satisfied by this binary's existing tree. Neither this binary nor web/dist gained a new package dependency for meshfox's own bundled grammar pool (grammars/README.md — Starlark, for ```starlark constraint fences, and Elixir, the original motivating case for the whole "Единая база языков подсветки" effort) — it's vendored source (.tmLanguage.json files, include_str!ed into the CLI binary and, for Starlark only, imported into the web bundle directly — Elixir is syntect-only, since Shiki already bundles it natively), same category as @fontsource/fira-code's own font files below rather than a Cargo.lock/package.json entry. grammars/starlark.tmLanguage.json is vendored from bazelbuild/vscode-bazel (Apache-2.0); grammars/elixir.tmLanguage.json from elixir-lsp/vscode-elixir-ls (MIT) — both retain their own attribution in grammars/README.md. That pool grew by 16 more files, all wired into syntax_registry.rs's BUNDLED_POOL_ADDITIONS, once that same audit was run against all 346 of Shiki's own bundled languages to see which load into syntect for free; same non-Cargo.lock/package.json vendored-source category as Starlark/Elixir. Each one's upstream source/license was checked against the real GitHub repo it comes from (via sources-grammars.ts in shikijs/textmate-grammars-themes, not assumed from Shiki's own blanket MIT repackaging license) — all 16 are MIT or Apache-2.0 (full per-file list in grammars/README.md). That check caught two real exclusions, deliberately not vendored: the nginx grammar (hangxingliu/vscode-nginx-conf-hint) turned out to be genuinely GPL-3.0 upstream despite Shiki's own package-level MIT license, a copyleft conflict with this project's MIT licensing; Swift (jtbandes/swift-tmlanguage, itself MIT) uses \G 65 times woven through core declaration/generics parsing rather than one peripheral rule, so unlike the 16 that made it in, it isn't a safe mechanical patch — not worth vendoring a file that can't actually be wired in. It grew by one more once meshfox-core gained node-level createdAt/updatedAt timestamps (see SPEC.md's "Timestamps") — time (crates/core/src/timestamp.rs) does the actual RFC3339 parsing/formatting/validation rather than a hand-rolled calendar implementation; it was already reachable transitively before this (via headless_chrome's own dependency tree, see the pdf entry above), so promoting it to a real, direct meshfox-core dependency added no new transitive weight. It grew by another 25 once the TUI learned to draw SVG images (meshfox tui, see "Usage") — resvg (rasterizes an SVG to pixels, since a terminal can only show a raster image and the image crate has no SVG decoder), built with only its text/system-fonts features (no embedded-raster <image> decoders, no memory-mapped fonts), pulls usvg, tiny-skia (BSD-3-Clause), fontdb, rustybuzz, svgtypes and a few small helpers — all MIT/Apache-2.0/BSD-3-Clause, no new copyleft exception. It grew by 2 more once meshfox lsp (see "Usage") landed — lsp-server (rust-analyzer's synchronous stdio transport and JSON-RPC framing for the Language Server Protocol, MIT OR Apache-2.0) and its one new dependency crossbeam-channel (MIT OR Apache-2.0); lsp-types (the protocol's data types, MIT) was already reachable through starlark's syntax crate and is now also a direct dependency of crates/cli, adding no package. No new copyleft exception.

It grew by one more once crates/cli's main gained an explicit rustls::crypto::ring::default_provider().install_default() call — rustls (already reachable transitively via headless_chrome/self_update's own ureq backend, and via meshfox_server's reqwest feature flags) was promoted to a real, direct crates/cli dependency so that call has something to name; picking the ring backend there (rather than the default aws-lc-rs) keeps only one crypto backend compiled into the binary, matching reqwest's own rustls-no-provider feature choice in meshfox_server. Apache-2.0 OR ISC OR MIT — permissive, no new copyleft exception. crates/server now names the same rustls/ring dependency directly as well: Source-mode saves of a canvas-valued include can make a loopback reqwest request when the server is embedded as a library, without the CLI's main having installed a provider. This adds no package to the existing transitive tree.

On Linux only, crates/core has one more direct dependency, secret-service (cfg(target_os = "linux"), the freedesktop Secret Service client behind secret_store = "keychain" there; default-features = false with the rt-async-io-crypto-rust feature, so pure-Rust crypto and the async-io zbus runtime — no libdbus/OpenSSL to link and no tokio runtime for its blocking API to collide with). It pulls 39 crates that do not reach the macOS binary at all (zbus and its zvariant/zbus_names/endi family, async-io/async-lock/async-process/blocking/polling and friends, enumflags2, hkdf, num*, winnow/toml_edit) — 16 MIT OR Apache-2.0, 14 Apache-2.0 OR MIT, 9 MIT; no copyleft, so no new exception. The 627 figure above stays the macOS count.

It grew by one more once service blocks (see SPEC.md's "Service blocks (experimental)") gained per-process CPU/memory/uptime sampling for the webui's service panel and the TUI's own service view — sysinfo (MIT), used from crates/server's new services module (shared by both, since the TUI links this crate as a library rather than talking to it over HTTP).

It grew by 5 more once undo/redo gained its own per-canvas history log (crates/server/src/undo_log.rs, .meshfox/<canvas>.session.sqlite3) — rusqlite, bundled feature so this doesn't depend on a system SQLite install, plus its own small fallible-iterator/fallible-streaming-iterator/hashlink/libsqlite3-sys tree (checked via git diff Cargo.lock, same as the syntect-tmlanguage entry above). libsqlite3-sys's own vcpkg build-dependency (a Windows-only system-library lookup) also landed in Cargo.lock but is excluded from the 639 count above, same "dev/build-only trees excluded" rule the rest of this count already follows. All five are MIT or MIT/Apache-2.0 dual — no new copyleft exception.

File input/output tracking adds direct uses of blake3 (CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception) and globset (Unlicense OR MIT). Both were already in Cargo.lock. The macOS normal-edge count was refreshed from cargo metadata --filter-platform aarch64-apple-darwin; the license scan found no additional mandatory copyleft requirement beyond the existing MPL exceptions. Alternative-license crates retain a permissive option.

Slug generation for meshfox serve --http (crates/core/src/slug.rs) adds a direct use of unicode-normalization (MIT OR Apache-2.0) to put paths in NFC before hashing. It was already in Cargo.lock (transitively), so the shipped tree and the license scan do not change.

The .meshfoxignore files of meshfox serve --http (crates/core/src/canvas_index.rs) add a direct use of ignore (Unlicense OR MIT, the .gitignore matcher from ripgrep). It was already in Cargo.lock (transitively) at the same version, so the shipped tree and the license scan do not change.

meshfox serve --http (crates/cli/src/gateway.rs) also makes axum, blake3 and serde_urlencoded direct dependencies of crates/cli. All three were already direct or transitive dependencies of the shipped binary at the same versions (meshfox-server uses axum with the ws feature; reqwest pulls serde_urlencoded), so the compiled tree and the license scan do not change.

It grew by exactly 1 more once meshfox-core gained a line-based three-way merge (crates/core/src/merge.rs, used to combine two concurrent edits of one node body or file instead of rejecting the later one) — similar (Apache-2.0, default-features untouched, so only its text line-diff module) computes the base→mine and base→theirs line diffs; the diff3 grouping on top of them is this repo's own code. similar has no dependencies of its own — it was the only new Cargo.lock package the change added (checked via git diff Cargo.lock), permissive, no new copyleft exception.

The TUI Unicode palette adds unicode_names2 3.1.0 ((MIT OR Apache-2.0) AND Unicode-DFS-2016), with unicode_names2_generator (MIT OR Apache-2.0) used at build time. Unicode data attribution is covered by the crate's bundled Unicode license. The macOS normal-edge shipped dependency count was refreshed to 627 using Cargo metadata; no new copyleft obligations were found.

Computed Starlark views add a direct use of allocative (Apache-2.0) in meshfox-core for heap accounting of the native MarkdownFragment value. It was already a normal dependency of starlark, so this adds no packages to the shipped dependency graph. Refreshed with cargo metadata --filter-platform aarch64-apple-darwin: 629 normal-edge third-party crates, with no additional copyleft requirement beyond the exceptions above.

Inline color spans unify meshfox-core and the CLI on pulldown-cmark 0.13.4 (MIT, already used by the CLI). This removes the separate 0.12.2 package. Refreshed via cargo metadata --filter-platform aarch64-apple-darwin: 628 normal-edge third-party crates, 790 total non-workspace packages across all targets and dependency kinds. The only package removed is MIT-licensed; no new licenses or copyleft obligations are introduced.

Packed canvases (.canvas.tar.xz, SPEC.md's "Packed canvases") add two direct dependencies of crates/model, which also builds for the browser: lzma-rust2 (Apache-2.0, pure Rust) reads and writes the xz stream — it compiles to WebAssembly, so the command line and the browser editor use the same code to read and to write a pack — and tar (MIT OR Apache-2.0). tar was already in Cargo.lock (through self_update); lzma-rust2 is new, with sha2 for xz's SHA-256 check, which was already in the tree. liblzma (MIT OR Apache-2.0, bindings to the C library) is a dev-dependency of crates/model only, used by its tests to check the reader and the writer against the reference implementation, and never ships, so it is omitted from the table. No copyleft is added.

MIT License
MIT License

Copyright (c) 2026 Maksim Dementev

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Backend dependencies (Rust / crates.io)

Direct dependencies across crates/core, crates/server, crates/cli (cargo metadata, deduplicated; dev-only deps omitted since they never ship; futures-util and tokio-tungstenite also occur as shipped CLI dependencies; crates/cli's own scraper (ISC) copy is a real, shipped dependency too as of node find, not just a dev one — see the narrative above for its own transitive cssparser/selectors, both MPL-2.0). All are permissive and MIT-compatible, aside from the weak-copyleft exceptions already called out above.

CrateLicense
allocativeApache-2.0
anyhowMIT OR Apache-2.0
async-streamMIT
axumMIT
base64MIT OR Apache-2.0
blake3CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception
clapMIT OR Apache-2.0
clap_completeMIT OR Apache-2.0
crosstermMIT
csvUnlicense OR MIT
edtuiMIT
futures-utilMIT OR Apache-2.0
globsetUnlicense OR MIT
ignoreUnlicense OR MIT
headless_chromeMIT
imageMIT OR Apache-2.0
libcMIT OR Apache-2.0
lopdfMIT
lzma-rust2Apache-2.0
lsp-serverMIT OR Apache-2.0
lsp-typesMIT
mime_guessMIT
openMIT
portable-ptyMIT
pulldown-cmarkMIT
ratatuiMIT
ratatui-imageMIT
reqwestMIT OR Apache-2.0
resvgApache-2.0 OR MIT
rmcpApache-2.0
rpasswordApache-2.0
rusqliteMIT
rust-embedMIT
rustlsApache-2.0 OR ISC OR MIT
schemarsMIT
scraperISC
secret-serviceMIT OR Apache-2.0
self_updateMIT
serdeMIT OR Apache-2.0
serde_jsonMIT OR Apache-2.0
serde_norwayMIT OR Apache-2.0
serde_urlencodedMIT OR Apache-2.0
shlexMIT OR Apache-2.0
similarApache-2.0
starlarkApache-2.0
syntectMIT
syntect-tmlanguageMIT OR Apache-2.0
sysinfoMIT
tarMIT OR Apache-2.0
teraMIT
thiserrorMIT OR Apache-2.0
timeMIT OR Apache-2.0
tokioMIT
tokio-tungsteniteMIT
tomlMIT OR Apache-2.0
tower-httpMIT
unicode-normalizationMIT OR Apache-2.0
unicode_names2(MIT OR Apache-2.0) AND Unicode-DFS-2016
uuidApache-2.0 OR MIT

Cross-checked against the three manifests below (core/server/cli Cargo.toml, read via .toml() — see examples/constraints.canvas.md): every crate in each one's own [dependencies] (skipping workspace-internal path deps like meshfox-core) must have a row in the table above.

def _table_names(text):
    names = []
    for raw_line in text.split("\n"):
        line = raw_line.strip()
        if not line.startswith("|"):
            continue
        cells = line.split("|")
        if len(cells) < 3:
            continue
        name = cells[1].strip()
        if name == "" or name == "Crate" or name.startswith("-"):
            continue
        names.append(name)
    return names

def _real_deps(dep_table):
    names = []
    for name in dep_table:
        v = dep_table[name]
        if type(v) == "dict" and "path" in v:
            continue  # workspace-internal crate, not third-party
        names.append(name)
    return names

manifests = [c for c in self.children() if c.type == "file"]
documented = _table_names(self.text)
actual = {}
for m in manifests:
    data = m.toml()
    if data == None or "dependencies" not in data:
        fail(m.id + ": could not read/parse Cargo.toml")
    else:
        for name in _real_deps(data["dependencies"]):
            actual[name] = True

for name in actual:
    if name not in documented:
        fail(name + " is a direct dependency (cargo) but has no entry in the table above")
core/Cargo.toml
server/Cargo.toml
cli/Cargo.toml
UI dependencies (npm)

Direct dependencies from web/package.json — these ship inside the built browser bundle. All are permissive and MIT-compatible; @fontsource/fira-code (the self-hosted Fira Code font files) is SIL OFL-1.1 rather than MIT, which only requires the font itself keep its license/copyright notice — it doesn't reach the rest of the bundle:

PackageLicense
@fontsource/fira-codeOFL-1.1
@monaco-editor/reactMIT
@shikijs/monacoMIT
@xterm/addon-fitMIT
@xterm/addon-imageMIT
@xterm/xtermMIT
@xyflow/reactMIT
anserMIT
monaco-editorMIT
reactMIT
react-domMIT
react-markdownMIT
remark-gfmMIT
shikiMIT

Direct devDependencies — build/test tooling only, never shipped:

PackageLicense
@playwright/testApache-2.0
@types/nodeMIT
@types/reactMIT
@types/react-domMIT
@vitejs/plugin-reactMIT
typescriptApache-2.0
viteMIT

Cross-checked against package.json below (web/package.json, read via .json()): every key under both dependencies and devDependencies must have a row in one of the two tables above.

def _table_names(text):
    names = []
    for raw_line in text.split("\n"):
        line = raw_line.strip()
        if not line.startswith("|"):
            continue
        cells = line.split("|")
        if len(cells) < 3:
            continue
        name = cells[1].strip()
        if name == "" or name == "Package" or name.startswith("-"):
            continue
        names.append(name)
    return names

pkg_nodes = [c for c in self.children() if c.type == "file"]
pkg = pkg_nodes[0].json() if len(pkg_nodes) == 1 else None
if pkg == None:
    fail("package.json: could not find/read/parse web/package.json")
else:
    documented = _table_names(self.text)
    actual = list(pkg.get("dependencies", {}).keys()) + list(pkg.get("devDependencies", {}).keys())
    for name in actual:
        if name not in documented:
            fail(name + " is a direct dependency (npm) but has no entry in either table above")
package.json