Repository navigation
v7.86.0
Pairs with engine-service-v0.1.164 (REQUIRED_ENGINE_VERSION unchanged from 7.85.0), already deployed to the managed service; no engine changesets. On Windows, PDF support needs Microsoft's Visual C++ redistributable on this engine: 0.1.164 does not carry msvcp140_atomic_wait.dll, so a machine without it installs without PDF support and says so (see Fixed, nexus-vyy65).
Added
-
The Claude Desktop extension can carry PDF support, opt-in (nexus-dzc61). Its new "Include PDF support" setting (off by default) makes the launcher install
conexus[pdf]at the next start, about 0.25 GB more to download and 0.85 GB more on disk on macOS; turning it off removes the PDF packages again. With it off, a start resolves exactly what it did before, and a sync that fails with it on falls back to bare so the extension still starts. Indexing a PDF in the extension with the setting off names the setting.scripts/check_mcpb_resolve.pyresolves both variants (live, 2026-10-24: bare 139 packages, PDF 219, 0 pins moved), and a real sync on macOS installed, imported and removed the PDF stack. -
A weekly vulnerability audit of the shipped install lock (nexus-2k66t.4.5).
.github/workflows/dependency-drift-watch.ymlgains alock-auditjob:pip-auditoversrc/nexus/_install/constraints.txt(every install is pinned to it since nexus-2k66t.4.1, so a transitive security fix reaches users only through a release), summarised byscripts/audit_install_lock.py, one line per vulnerable package with its advisories and the highest fixed version. The run is red only for an advisory that has a fix and is not acknowledged (with a reason) in the script'sACKNOWLEDGED; an advisory with no fix is shown and never fails; an audit that examined fewer than 50 packages fails. Its first run (2026-10-24) found 258 advisories across 34 of 208 pinned packages, which the lock refresh nexus-13z79 clears. -
A PR-time resolve check for the
.mcpbbundle's dependency lock (nexus-zzkko).scripts/check_mcpb_resolve.pyran only in the release workflow, after the tag was pushed, so a lock that stopped resolving cost aworkflow_dispatchretry or a moved tag.ci.ymlnow has anmcpb-resolve-gatejob on pull requests todevelopandmainand ondeveloppushes. It always reports, and runs the resolve (against the checkout, nothing installed) only whensrc/nexus/_install/constraints.txt,uv.lock,pyproject.toml,mcpb/pyproject.toml,mcpb/src/bootstrap.pyor one of the two scripts changed; an unusable filter output fails the job instead of skipping the resolve. -
Release-battery leg
resolve: the shipped dependency lock must resolve on every supported target (nexus-2k66t.4.4).tests/test_install_constraints_pin.pyprovesconstraints.txtequalsuv.lockbut not that the lock installs anywhere (the onnxruntime wheel set starts at macOS 14).tests/e2e/constraints-resolve-gate.shrunsuv pip compilewith the shippedoverrides.txtandconstraints.txt, installing nothing: 22 compiles, 8 for the default install (Linux x86_64 and aarch64 and Windows x64 and macOS 14 arm64 on Python 3.12 and 3.13, torch backendcpuon Linux) and 14 for thepdfextra (the same, plus thecu130backend on Linux 3.12 and 3.13 andcu126on Linux 3.12), any unresolvable target named and the leg red. macOS 14 is expressed throughMACOSX_DEPLOYMENT_TARGET. The requirements come frompyproject.tomlas plain dependencies, because uv would otherwise apply[tool.uv.sources]and resolve CPU torch for every GPU target. Non-vacuity: the expected count is a literal, so deleting a cell fails the leg; a compile must reach a pin count near the real lock's (110 default, 180pdf); everypdfcompile must pindocling-slimandmineru; each Linuxpdfcell must resolve torch to its backend's local version; a probe fails closed with "uv too old for " before any compile; and a macOS 13 negative control must stay unresolvable with uv's onnxruntime platform-tag error (if it resolves, the verdict says the macOS floor moved and namesdocs/getting-started.mdandplatform_failure_hint). Wired intorelease-battery.sh(group, network; release battery and by hand, never the default suite);tests/e2e/constraints_resolve_gate_test.shis the offline self-test (stub uv, 82 checks). -
LLM steps can run on a direct Anthropic API key or an OpenAI-compatible server, not only the
claudeCLI (nexus-2k66t.3, phases 1 and 2). Every LLM step (thenx_answeroperators, aspect extraction, topic labels, memory roll-up) goes through one dispatch with three backends:cli(unchanged),anthropic(the Messages API onhttpx, no new dependency) andopenai_compat(Chat Completions for Ollama, vLLM, OpenRouter).llm.backend/NX_LLM_BACKENDisautoby default: the CLI whenclaudeis on PATH (today's behaviour and billing), else the API when ananthropic_api_keyresolves (nx config set anthropic_api_key --stdin, orANTHROPIC_API_KEY), else no backend, with an error naming both remedies.nx_plan_auditandnx_enrich_beadsuse tools and always run on the CLI. The setting, theopenai_compatendpoint (llm.openai_compat.base_url/.model) and the keys are read from the environment and the globalconfig.ymlonly, never a repository's.nexus.yml. The direct path forces aStructuredOutputtool with the operator's JSON schema where the model allows it (Claude Opus 5.5, Sonnet 5.5 and Fable 5.1 reject a forced tool choice, so they gettool_choice: autoplus an instruction), validates the answer locally withjsonschemaand sends one repair turn on a failure; it keeps the CLI's two-phase timeouts with partial output in the timeout log, retries 429/529/5xx/connection failures twice honouringretry-after, caps in-flight requests atNX_LLM_MAX_CONCURRENCY(default 4) and the output atNX_LLM_MAX_TOKENS(default 16000), enforcesmax_budget_usdas a pre-flight ceiling, and prices calls from a table (an unknown model reportscost_usd: Noneand a warning, never0.0). A key kept inconfig.ymlnever reachesos.environ, a log line, an exception message or aclaudechild; anANTHROPIC_API_KEYexported in the shell is still inherited by theclaude -pchildren nexus starts, as before this change, and a malformedconfig.ymlis reported by line number only.NX_LLM_OPENAI_API_KEYis removed from everyclaudechild's environment. Anopenai_compatcall under amax_budget_usd/NX_DISPATCH_MAX_BUDGET_USDceiling is refused unlessllm.openai_compat.price_in_per_mtok/price_out_per_mtokare set (then it is enforced and priced) orllm.openai_compat.unpriced_ok: trueaccepts it unenforced. Whenautofinds no backend the caller receivesNoBackendAvailableError, at the spawn path too. Aspect rows written through an API backend carry the model that produced them inmodel_version.nx doctorgains an "LLM backend" row (which backend and why; not applicable on a box with neither) and an "LLM key persistence (GUI spawn)" row. The README's no-API-key claim is narrowed to search and storage.llm_backend_available,backend_statusand selection flip together, and the aspect extractor routes through the selected API backend with its own 3-attempt retry kept (a 429 costs 3 requests, not 9). Prerequisites from the phase 1 reviews landed with it: the operator exceptions andDispatchUsagemoved below both modules intooperators/llm_types.py(still re-exported fromdispatch), and one usage-recording helper serves every backend. Before this release the four model aliases were checked live throughclaude -p(each resolved to the model ID the direct backend maps it to); theanthropicandopenai_compatbackends themselves were tested only against a local fake server, with no live API call.
Changed
-
The Claude Desktop
.mcpbbundle installs under the release's dependency lock (nexus-2k66t.4.6). The bundle'suv syncresolved every dependency fresh, so a bad transitive release reached Desktop users, who are the least able to recover (the nexus-l2ku5 shape). The release workflow now stagessrc/nexus/_install/constraints.txt(the file the wheel and every installer ship, pinned equal touv.lock) into the bundle withscripts/stage_mcpb_constraints.pybeforemcpb pack, appendsconexus==<release>so the bundle installs the release it was built from, and fails the release if the packed zip lacks the file. The stager reads the source with the launcher's own reader (any line the launcher would reject refuses the stage; floor 200 pins, the lock has 219).mcpb/src/bootstrap.pywrites it into the bundle'spyproject.tomlas[tool.uv] constraint-dependenciesbefore the sync (a projectuv synchas no constraints flag and ignoresUV_CONSTRAINT), and says so on stderr. The edited file is parsed withtomllibbefore it is written and is never written if it would not parse (an existingconstraint-dependencies, a begin marker with no end): it stays as it was, the line says "not pinned" and, when an earlier constraint is still in force, that. An end marker at the end of the file with no newline is now replaced cleanly. The scratch file ispyproject.toml.nx-tmp.<pid>and is removed on every path. If the sync fails with the pin in force for any reason except the release-propagation window (or the pin names no conexus to wait for), the launcher removes the pins, says so, and syncs once unpinned instead of failing the start. The opt-out:NX_INSTALL_UNPINNED=1(the CLI installers' variable;launchctl setenvon macOS, a user environment variable on Windows), the extension's owninstall_unpinnedsetting in Claude Desktop (manifestuser_config, which reaches the launcher asNX_MCPB_INSTALL_UNPINNED=true;1andtrueboth count), or deletingconstraints.txtfrom the extension directory. A bundle withoutconstraints.txt(a hand-packed one), or with one that is not a list of pins, installs unpinned as before and states that on stderr; it never fails the start. A pre-publish gate,scripts/check_mcpb_resolve.py, runs in the release workflow's pack step after the wheel is built: it stages and pins a scratch copy of the bundle exactly as the launcher does, points conexus at the fresh wheel (the release is not on PyPI yet), runsuv lock, and fails the release if the lock does not resolve, conexus is not locked at the release version, or a pin moved. Measured against a scratch copy of the real bundle: the pinned resolve holdsmcpat 1.27.1 as locked, the opted-out resolve takes 1.30.0 and moves 127 of the 213 pinned packages. Bareconexusstays the bundle's dependency; the[pdf]extra question is nexus-dzc61. -
The install sizes are measured, not derived (nexus-2k66t.4.10). Measured on 7.85.0 on macOS (hellmini) and Linux (chas, qwent WSL) on 2026-10-24; Windows was not measured. Local about 0.8 GB down (0.9 GB on Linux), 2.5 to 2.9 GB on disk; Cloud and CLI only about 0.45 GB down (0.6 GB on Linux), 1.8 to 2.2 GB on disk. Slim saves about 0.25 GB of download on macOS and 0.37 GB on Linux, and 0.85 GB on disk on macOS and 1.3 GB on Linux (the page said 0.8 GB for both). The uv cache is about 2.1 GB on Linux and 1.8 GB on macOS (the page said 2.4 and 3.6), and on Linux it shares files with the install, so the two together are about 2.2 GB. Corrected in the README, the install guides, the setup command, the stand-in and the
setuptool description. -
PDF support is the
pdfextra; a bare install leaves it out, the first PDF index installs it, and the installers and the plugin's setup add it up front (nexus-2k66t.4.2, nexus-2k66t.4.9, Sam 2026-10-23). docling, MinerU, torch, torchvision and pdftext were 57 to 65% of the download and 49% of the installed size (T2nexus/install-weight-measurement-2026-10-23: macOS 428 to 186 MB, Linux 567 to 197 MB, 792 of 1605 MB installed), and search and store never import them. They moved from[project].dependenciesto[project.optional-dependencies] pdf; the dev group includesconexus[pdf], souv sync, CI and the suite keep the stack;uv.lockandsrc/nexus/_install/constraints.txtare regenerated (219 pins, unchanged, since the file already covers every extra).nx index pdf,nx index pdf --dir,nx dt indexof a PDF record,nx dt captureof a PDF (before DEVONthink is touched, so the re-run cannot capture twice),nx collection reindexof a docs or knowledge collection with a PDF source (before the purge),nx index repowhen its walk finds a PDF, andnx mineru startcallpdf_stack.ensureBEFORE any catalog or T3 write;doc_indexer.index_pdfitself callspdf_stack.requirebefore it registers anything, and a census test fails on any ungated caller. The default policy installs, on a terminal and off one (the commonest caller is an agent's Bash tool): one stderr line names the size and uv's progress streams, then a new generation is built with thepdfextra at the RUNNING version through the generation builder's own arguments (perform_self_install(add_extras=("pdf",), version=<running>): CPU torch on Linux, the packaged overrides, the constraints the new package ships; a bareuv pip install conexus[pdf]would resolve CUDA torch on Linux, and without the version pin the fetch would be an upgrade), and the command re-runs as a child of<tools>/current/bin/nx(NX_PDF_STACK_REEXEC=1stops a loop;nx index repounwinds first so its index lock is free). A file lock serializes concurrent fetches. It is never silent: exit 69 when the install is refused (NX_PDF_STACK=refuseorpdf_stack.auto_install: false; a checkout, a directory-source generation or a legacy uv tree, which get their own command; Windows without the VC++ runtime), 75 on a network or TLS failure, 70 when the installer fails or the stack is still absent afterwards, each before anything is written, each naming the command.PDFExtractor.extractrefuses by name when the stack is absent in every extractor mode, and its two ImportError messages say "PDF support is not installed" with the command when that is the cause; nothing falls back topymupdf_normalized. The post-commit hook stanza exportsNX_PDF_STACK=refuse: a backgroundnx index repoindexes code and prose, does not register or index the PDFs (they still count as present for the catalog's orphan sweep, and a--since-headbase does not advance past them), logs an ERROR line naming each, exits 69, andnx doctorcounts them.nx doctorhas a "PDF support" row: a pass with the pin check when present, informational (never red) when absent, red with the repair command when broken; the MinerU server row and--check-minerureport not applicable without the stack. -
Every ordinary install path installs PDF support by default;
--slimopts out (nexus-2k66t.4.9, Sam 2026-10-23: install everything by default).nx self install --bootstrapnow accepts--extras(it still refuses--version): the throwawayuvenvironment that runs it stays slim and the generation gets the extras, and an interrupted slim build is rebuilt, not finished, when--extras pdfis asked.web/install.shandweb/install.ps1run... nx self install --bootstrap --extras pdfand take--slimto leave it out; the plugin's setup (nx_setup.py,start --slim) does the same, and thesetuptool, on the stand-in and the real server, has a booleanslimargument (default false, recorded in the setup status so a resume passes it on). The REPAIR command the stand-in prints carries--extras pdf. A bareuv tool install conexus, the Claude Desktop.mcpbbundle and--slimstill arrive slim and fetch the stack on the first PDF index (nexus-2k66t.4.2);nx self installon a legacy uv tree already carried it. The size rows everywhere a user chooses an install (the stand-in and the setup tool,/conexus:setup, README, getting-started, windows-install, desktop-deployment, RDR-228, both installers) show the default: Local about 0.8 GB down (0.9 GB on Linux), 2.4 to 3.1 GB on disk; Cloud and CLI only about 0.45 GB down (0.6 GB on Linux), 2.1 to 2.3 GB on disk, with a slim line (0.25 GB less down on macOS, 0.37 GB on Linux, 0.8 GB less on disk). The download figures are derived from the 2026-10-23 measurement of 7.85.0 (T2nexus/install-weight-measurement-2026-10-23), the disk figures from the 7.81.0 measurement;tests/test_install_size_rows.pypins every place. The release gate follows the default:tests/e2e/fresh-install-mvv.shbuilds its generation with--extras pdf(the probe's pdf branches and the receipt's extras now run) and adds leg 9b, a slim generation in its own virgin home (NX_MVV_SKIP_SLIM_LEG=1skips it and the final line says so);rehearse_package_upgrade.shstage 6 builds with the extra too (NX_REHEARSE_SLIM=1for the bare build).nx doctor's "PDF support" row is a warning, not a plain pass, when an upgrade owes an install the stack (it names the pending carry-forward, or when the last one failed and the retry command); the legacy-uv-tree remedy is one command,nx self install(it moved the tree and carried PDF support already), not two. ORDER: the installer pages call--bootstrap --extras, whichconexus@latestaccepts only from this release on, soweb/install.shandweb/install.ps1publish after the client release is on PyPI. -
An existing install ALWAYS carries the PDF stack forward; only a fresh install goes without it (nexus-2k66t.4.2). The receipt's
installer_schemais now 2 ("pdfis an extra"); a receipt below 2, or without the field, was written by an installer that built the stack into every generation, soperform_self_install, the uv-takeover repair,scripts/reinstall-tool.sh(which also reads list-valued extras now, and takesNX_REINSTALL_EXTRAS),migrate_legacy.shand the Windowsgeneration_core.migrate_legacyaddpdfto the extras they build. The oldernx self installthat moves a box INTO this release cannot know the rule and builds a slim generation of the new package, sonx upgrade(the SessionStart lockstep runs it) builds the generation that addspdfwhen it sees a pre-split receipt; a failure leaves the install working, is retried by the nextnx upgrade, and the automatic run waits six hours between attempts. -
nx self installbuilds the new generation with the installer of the release it installs, not the running release's (nexus-2k66t.4.3). The lock pin (nexus-2k66t.4.1) lives in the installer a release ships, so an upgrade built by the old installer resolved the new release fresh and only the upgrade after it was pinned. COVERAGE: upgrades FROM a release that carries this code. The hop out of 7.85.0, which does not, is still built by 7.85.0's installer; that generation is re-pinned only by the PDF carry-forward (nexus-2k66t.4.2), which rebuilds at the running version on the firstnx upgradeafter it. Every route that builds a generation uses one selection rule: the upgrade, the uv-takeover repair (the uv tree's ownnexus/_install/, already on disk, no fetch) and the legacy uv-tool convergence (the newest release, or--version, fetched; on POSIXmigrate_legacy.shis handed the target'sinstall_generation.shthroughNX_MIGRATE_BUILD_SCRIPTand keeps its own flip and shim steps; on Windows the target'sgeneration_core.migrate_legacyruns whole, flip and PATH entry included). A registry target is fetched alone withuv pip install --no-deps --targetat the version asked for, with the Python the build uses (3.12); a checkout is used where it stands; a wheel file is unpacked. Elsewhere only the build changes hands: flip, shims and reap stay with the running code. A target that predates this (no installer in the package, a support file missing, or an installer with no arm for a flag the running code passes) builds with the running installer; one stderr line says why and the same note is logged at warning level. A failed fetch exits before anything is built, leavingcurrentas it was, with the package-index diagnosis when the network is the cause; an unreadable local wheel says so rather than "could not fetch". A build the target's installer fails namesNX_INSTALL_RUNNING_INSTALLER=1(build with the running release's installer) andNX_INSTALL_UNPINNED=1(resolve fresh). No fetch happens when the pinned version is the running one. After the build, a warning names both versions when the generation holds a different conexus version than the installer was read at (the index moved in between); no--versionpin is added, which would change the receipt's spec.nx self install --dry-runprints the running installer's argv: the target's is read only when the build runs, since reading it is a fetch. -
nx upgraderebuilds a generation that was built without the release's dependency lock (nexus-au0s3). The receipt now recordsconstraints:applied(the release'sconstraints.txt, or an explicit--constraintsfile, was used),unpinned(NX_INSTALL_UNPINNED=1skipped it on purpose) ornone(the package shipped none); a receipt that predates the field reads as unknown. Both builders write it (install_generation.sh,generation_core.py);installer_schemastays 2 andRECEIPT_SCHEMAstays 1, so an older nx reads the new receipts and drops the key. Whencurrentis a registry build of the running version whose receipt saysnoneor nothing, and this package ships a lock,nx upgrade(and its--autorun) builds one generation at the same version with EXACTLYcurrent's extras (not the running generation's) and the running installer, flips, and reaps by the keep-3 rule. It is checked afterwards: ifcurrentdoes not recordapplied, the attempt counts as failed and backs off six hours under--autoon its own marker (installer-rebuild-failed), so a build that succeeds without the lock cannot repeat every session start. A deliberateunpinnedinstall is never re-pinned silently; the next plainnx self installpins it again. COVERAGE: the hop out of 7.85.0 is NOT this rung's. Its receipts predate the PDF split, so the PDF carry-forward (nexus-2k66t.4.2) builds the one generation that re-pins it, and this rung stands aside while that is owed. The rung covers later generations built at the running version without the lock, which in practice means an installer fallback (NX_INSTALL_RUNNING_INSTALLER=1, or a target that ships no usable installer); it is a safety net with a small population, since it requires the running package to ship the lock.--skip-t3defers it.nx doctorshows a "Dependency lock" warning when the rebuild is owed or its last attempt failed, withnx upgradeas the retry; a box that owes nothing shows no row. The install-lock waiter now names the build that holds it ("rebuilding the current generation", not always "installing PDF support"). -
A receipt written by a newer installer is read, not refused (nexus-lvvhm, nexus-ff366). An upgrade is built by the TARGET release's installer, which writes the receipt, while the running release flips, shims, reaps and reads it back;
RECEIPT_SCHEMAwas compared for equality, so a target that bumped it would have broken the running code mid-upgrade. The reader now compares a separateMIN_READABLE_RECEIPT_SCHEMA(1), so the writer's stamp can move without making any receipt already on disk unreadable. It accepts a schema at or above the minimum, takes the fields it needs and drops the rest, and refuses, always as the layout error, a schema below the minimum or not an integer, aninstaller_schemathat is not an integer, and a required field that is missing or not a string (a dict or nullversionis no longer turned into a string). The compatibility rule is written onRECEIPT_SCHEMA, onReceiptand inlayout.sh, where the shell writer's author works: an additive field needs NO bump (released clients, 7.85.0 and earlier, compare the number strictly, so any bump locks them out of every receipt written after it); a change in what an existing field means needs a new field name; wideningsource_kindbreaks older readers; an unknownconstraintsword reads asunknown, which the installer-rebuild rung treats as owed.nx self installreads the built generation's receipt before it movescurrent: a receipt this nx cannot read stops the install withcurrent,previousand the shims untouched, namingNX_INSTALL_RUNNING_INSTALLER=1. The same read-back now sits between the build and the flip in the legacy uv-tool convergence on both platforms:migrate_legacy.shchecks throughlayout.sh'snx_check_receipt, and on Windows the check is theverifyargument ofgeneration_core.migrate_legacy(the flip is inside that call, so a check around it could only run after it); a target release's core that predates the argument is replaced by the running release's core for that convergence, with one stderr line. On the upgrade path (the--autorun included) an unreadable receipt no longer repeats at every session start: the unreadable generation is removed and the generation is built once more with the running release's installer, saying so on stderr;NX_INSTALL_RUNNING_INSTALLER=1and a second refusal still end the install.scripts/reinstall-tool.shreads the receipt through the same reader instead of two inline copies, and stops withREFUSINGon a receipt it cannot read rather than dropping the box's extras. -
The shipped dependency lock is refreshed: the install audit goes from 34 vulnerable packages and 258 advisories to 2 packages and 46 (nexus-13z79).
pip-auditoversrc/nexus/_install/constraints.txt(208 pins examined before, 215 after; the audit counts every platform's pin) now flags only pillow 12.3.0 (37 advisories, all fixed solely in pillow 13.0.0, which fastembed through 0.9.0 and docling-slim cap below, and which was released 2026-10-16) and transformers 4.57.6 (9, three with no fix; the rest need transformers 5, whichmineru[pipeline]forbids).uv lock --upgrademoved 147 packages and added 10 and dropped 3;uv.lockandconstraints.txtagree. Bounds changed, each with its reason inpyproject.toml:torchandtorchvisionfrom the minors the lock already ran (2.8 on Linux, 2.10 on macOS py3.13) to 2.13 and 0.28 on every platform (2.8.0 carried eight advisories, one fixed only in 2.13.0; torch 2.13 has no cu128 build: see the next entry);fastembed<0.8to>=0.8.1,<0.9(0.7.x capped pillow below 12; bge-base-en-v1.5 vectors from fastembed 0.7.4 and 0.8.1 differ by at most 1.3e-4 per component, minimum cosine 0.9999996, measured with onnxruntime also moving from 1.24.2 to 1.31.0; stored vectors come from the engine's own ONNX runtime, which this does not touch, so nothing re-embeds);docling-slimfrom the exact patch 2.125.0 to the exact patch 2.132.0 (seven advisories in backends nexus never calls). Major moves in the lock: pillow 11 to 12, starlette 0.52 to 1.9, cryptography 48 to 50, protobuf 6 to 7, opencv 4 to 5, rich 14 to 15, filelock 3 to 4, attrs 25 to 26, multidict 6 to 7, reportlab 4 to 5, deprecated 1 to 3, more-itertools 10 to 11, xxhash 3 to 4, aiofiles 24 to 25, av 18 to 19, soupsieve 2 to 3, twine 6 to 7, syrupy 5 to 6, readme-renderer 44 to 46, and the 0.x minors torch 2.13, torchvision 0.28, mcp 1.30, fastapi 0.162, uvicorn 0.54, llama-index-core 0.14.25, onnxruntime 1.31, numpy 2.5.llama-index-coreandtree-sitter-language-packstay inside their caps (0.14.x, 0.13.x). Checked on chas: the full unit suite and the lint bucket, the docling extraction tests with none skipped,ci_warm_docling.py, both-m slowMinerU fixtures with their exact locked values. The MVV and the release shakedown are still the final gate for the docling and torch moves. -
NX_TORCH_BACKEND=cu128no longer resolves (nexus-13z79). The torch the lock now carries (2.13) has no cu128 build. The default is stillcpu.autopicks a build from the NVIDIA driver, so on a driver that supports only CUDA 12.8 it can pick cu128 and fail to resolve: namecu126there (it covers CUDA 12.6 to 12.8 drivers). Newer drivers can usecu129orcu130;cu132also resolves. All of these resolve on x86_64 and aarch64, which closes the earlier aarch64 cu128 gap. Seedocs/getting-started.mdanddocs/cli-reference.md.
Fixed
-
Doctor rows and error messages name commands that exist (nexus-t99tw). Fix suggestions say
nx initinstead of the deprecatednx init --service(plainnx initruns the same local provisioning); on a managed or cloud box the footer saysNX_LOCAL=1 nx init. The vector-write retry summary says "vector store" andnx doctor --check-quotassaysvector:instead ofchroma;nx collection audit --livehelp names the T3 service store;nx doctor --fixon the service store says HNSW tuning is server-side instead of "Updated HNSW search_ef on 0 collection(s)". -
On Windows, PDF support needs
msvcp140_atomic_wait.dll; a machine without it gets nexus without PDF support and is told (nexus-vyy65). torch 2.13 imports that DLL andimport torchfails with WinError 126 without it. The gate checked onlymsvcp140.dllandmsvcp140_1.dll, so the stack installed and then could not load. The gate now needs all three DLLs in System32 (Microsoft's Visual C++ redistributable) or together in one app-local directory (the engine directory, the PG bundlebin,<config>/vcrt). On a machine with neither, every build path leaves PDF support out and prints one line that says so and how to get the runtime:nx self installand its--bootstrapform, the Windows legacy convergence, the uv-takeover repair, the PDF carry-forward and the installer rebuildnx upgraderuns. The line is worded as what will happen, so it is true on--dry-runtoo. Where it reaches the user: interactive commands print it; the plugin setup (conexus/launch/nx_setup.py, which with the stand-in's repair command is the only caller that passes--bootstrap --extras pdf;web/install.ps1andweb/install.shpass no extras and so build slim already) copies it into its done message;nx upgrade --autowrites it to the log only (upgrade_pdf_stack,upgrade_installer_rebuild), and the SessionStart lockstep action writes it tolockstep.logaslockstep_pdf_slim. The new receipt does not listpdf, so no later upgrade is held back by it. A typednx self install --extras pdfbuilds the same way and says PDF support will not be installed and why. The first PDF index refuses with the download link and installs the stack on first use once the runtime is in place;PDFExtractor.extractrefuses an installed stack that cannot load instead of failing with a raw WinError 126;nx doctorshows "PDF support" red, with the redistributable as the fix, on an install that has the stack but not the DLL, and amber (not installed, and why) on one that lacks both. The Desktop extension's opt-in PDF setting still applies, and its launcher adds a stderr warning when this machine lacks the runtime. The runtime needs no redistributable once an engine release carries the DLL, on every mode: the Windows PG bundle and the engine archive built from this source shipmsvcp140_atomic_wait.dll(engine 0.1.164, which this release pins, does not carry it, so on 7.86.0 a Windows machine without the DLL installs the redistributable for PDF support) beside the other runtime DLLs (copied from the same redist folder, with the same Microsoft signature check); a local install places it beside the engine from an engine archive that has it, andnx upgrade(andnx initon a cloud or managed install) top it up into<config>/vcrtfrom the pinned PG bundle on a machine that has the base pair (in System32 or an earlier<config>/vcrt) or nothing, at most once per pinned engine tag (the tag checked is recorded in the vcrt provenance, so an older bundle is not fetched again until the pin moves). An older pinned archive or bundle without the DLL still installs. The DLL search path takes an app-local directory that has all three even when System32 has an old redistributable with only the base pair. A machine that bootstraps beforenx initor the engine install has placed anything builds without PDF support, and PDF support installs on first use once they have. Until an engine release carries the DLL, PDF support on Windows needs the redistributable. -
NX_MCPB_SKIP_RESOLVE_RETRY=1no longer applies the.mcpbdependency pin (nexus-puzdu). The pin was still written into the bundle'spyproject.toml, but its unpinned fallback lives in the sync step the variable skips, and the launchuv runis an exec with no process left to retry, so a lock that cannot resolve on a machine would end the start where the unpinned install would have survived. With the variable set the launcher now applies no pin, removes a pin block left by an earlier launch, and says so on stderr. -
A failed installer rebuild puts
currentandpreviousback (nexus-ff366).nx upgradeflipped to the rebuilt generation before checking that its receipt records the dependency lock as applied, so a build that did not take leftcurrenton a generation no better than the one it replaced, and each six-hourly retry built another. The check now runs after the flip and BEFORE the keep-3 reap (perform_self_install(after_flip=...); the reap still runs afterwards, also when the check fails), and a failure re-pointscurrentat the generation it replaced andpreviousat what it named before, through the same flip helpers (junctions and the logon task on Windows), keeps the backoff marker, and says so in the line. The line is worded from a re-read of both pointers: apreviousthat could not be restored, or was removed since the flip, is named as such, and a rollback that could not movecurrentsays it stays on the rebuilt generation. -
On Windows the on-demand PDF install shows progress, and the upgrade's carry-forward checks the VC++ runtime (nexus-2k66t.4.7). The Windows generation build captured uv's output until uv exited, so the PDF-stack install (a download of several hundred MB) sat silent for minutes after its notice line while the POSIX path streamed. With
progressset,generation_core.build_generationnow copies uv's stderr through as it arrives and prints aninstall_generation: ... still running (Ns elapsed)heartbeat every 20 s of silence (uv writes no progress bar when its output is a pipe); both go to stderr, so callers that capture stdout are unaffected. The heartbeat waits for what is left of the silence window, so output landing just after a check no longer stretches the gap to twice 20 s. A dead stderr (closed pipe, none under pythonw) is ignored, so uv's pipe stays drained and the build's own error is reported; uv is killed and its pipes closed on Ctrl-C. The request now reaches every Windows build a person waits on:nx self install(soinstall.ps1's--bootstrapand the setup tool's build) and the legacy-tree convergence (migrate_legacy). On POSIXnx self installnow also copies the builder's stderr through.pdf_stack.carry_forwardskipped the Visual C++ runtime checkensure()runs, so a Windows box without it installed the stack and then showed PDF support as broken innx doctor; both paths now run one check and refuse with the same words before building (the carry returns the refusal as its line, as it never raises, and leaves the auto-run backoff clear).nx upgradeprovisions the runtime (_converge_vc_runtime) before the carry-forward, so the first upgrade on a cloud-mode box is not refused for want of the DLLs it is about to place. -
PDF-stack and setup follow-ups (nexus-2k66t.4.8, nexus-5kvjb, nexus-w8ug5). A process waiting on the PDF-stack install lock prints one line saying so instead of blocking silently.
nx index repono longer installs the PDF stack when every PDF in its walk is already indexed: a catalog-only check clears a PDF only when its document is complete at the file's current sha256, and the indexer's own staleness check then runs on the cleared ones before any file is dispatched (one shared helper decides both); PDFs held early and late are recorded together fornx doctor, and the refusal prints once.nx self install --bootstrapremoves the generation it superseded when that was a leftover (nocurrent, the same version, or an interpreter that is gone); a working older generation, and apreviousrollback target, are left to the normal keep-3 prune, and the bootstrap never removes uv's launchers. The setup tool'sslimis now omitted, true or false: omitted resumes an unfinished slim run as slim,slimfalse switches it to the full install, and a slim run's resume and failure text say so. -
Every install path installs the versions the release's
uv.lockresolved, not a fresh package-index resolution (nexus-2k66t.4.1).install_generation.shconstrained an install only when handed a constraints file, and nothing insrc/orscripts/ever handed it one, so a registry install resolved afresh: the 7.85.0 generation on the measuring box ran onnxruntime 1.31.0, opencv-python-headless 5.0 and pymupdf 1.28.2 against locked 1.24.2, 4.13 and 1.27.1 (nexus-l2ku5 was this class: mcp 2.0.0 resolved off PyPI and killed both MCP servers for four days). The wheel now shipsnexus/_install/constraints.txt, generated fromuv.lockbyscripts/regen-install-constraints.sh(runtime set plus every extra, platform markers kept, no+cpulocal label in the shipped file, soNX_TORCH_BACKEND=autostill resolves from it;scripts/reinstall-tool.sh's checkout flow exports the raw lock with its+cpulabels and does not, nexus-jd8fi). With no--constraintsgiven, the POSIX builder and the Windowsgeneration_core.build_generationfetch the package alone (uv pip install --no-deps), read the constraints it shipped out of the new venv, and install again with the dependencies under them; the file comes from the package being installed, never from thenxrunning the build, so an upgrade is held to the new release's lock. The installer that runs is still the runningnx's own, so the pin starts once the runningnxcarries this change: an install of this release and every later upgrade are pinned, but the upgrade INTO this release from an oldernxis built by the older, unpinned installer and is not. That coversnx self install,--bootstrap(the plugin's setup), the legacy-tree convergence and the session hook'snx self installon a generation box, which all go through the builder.scripts/reinstall-tool.shfrom a checkout still exports the checkout's own lock; with a registry source (--allow-registry-over-dev) it takes the shipped file. A package that predates the file (a--versionrollback) installs as before and the build prints a warning that noconstraints.txtwas found in it and its dependencies were resolved unconstrained.NX_INSTALL_UNPINNED=1skips the pin on purpose (one unconstrained install and a warning that the install is not pinned to the release's lock), the way to take a transitive security fix ahead of a release; an explicit--constraintsfile still wins. macOS 14 or later on Apple Silicon is now the declared floor: the pinned onnxruntime 1.24.2 ships only macOS 14 wheels, so a macOS 13 Mac fails the resolve, and the failure message now says so. Not covered: a bareuv tool install conexus/pip install conexus(and the hook'suv tool upgradeon an unmigrated legacy tree), the throwaway environmentuv tool runmakes to run the bootstrap (it is discarded; the generation it builds is pinned), and the.mcpbbundle'suv sync, none of which can read a lock before the package is fetched.tests/test_install_constraints_pin.pyfails the default suite while the shipped file anduv.lockdisagree (regenerate after any lock change; the release skill's Step 5 does it), and the fresh-install MVV (leg 9) and the package-upgrade MVV (Stage 6) now assert that an installed generation equals the lock for onnxruntime, opencv-python-headless, pymupdf and mcp.