Skip to content

Enable static builds - #323

Merged
edolstra merged 16 commits into
mainfrom
tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix
Feb 6, 2026
Merged

edolstra merged 16 commits into
mainfrom
tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix

Conversation

@RossComputerGuy

@RossComputerGuy RossComputerGuy commented Jan 22, 2026 •

Copy link
Copy Markdown
Member

Motivation

Enables static builds so static binaries can be made.

Context

Summary by CodeRabbit

  • New Features

    • Optional WASM support for expression evaluation and derivation building.
    • Per-package and per-stdenv static package variants exposed publicly.
    • Static dev-shells added for native static builds.
  • Improvements

    • Unity-build defaults enabled; prelink behavior is now configurable by compiler/build.
    • CI now builds static package variants.
    • Better arm64 detection and improved startup ordering for the signal handler.
  • Bug Fixes

    • Safer HTTP/curl defaults and avoid creating interrupt callbacks in static builds.
    • Header protection added and packaging fixes to handle Clang/static/libunwind scenarios.

@coderabbitai

coderabbitai Bot commented Jan 22, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds centralized, compiler-aware Meson prelink logic; makes Wasmtime/WASM optional with Meson options and package flags and gates WASI code/linking behind that flag; adds static-build guards and compiler-rt/libunwind handling for Clang+static+libcxx; starts a Unix signal handler on non‑Windows; adds a header guard; updates CPU doc; and adds CI static build step.

Changes

Cohort / File(s) Summary
Central prelink config
nix-meson-build-support/common/meson.build
Probe C++ compiler and set local prelink (false for clang+static, true otherwise).
Prelink adoption (many targets)
src/libutil/meson.build, src/libutil-c/meson.build, src/libexpr-c/meson.build, src/libfetchers-c/meson.build, src/libflake-c/meson.build, src/libflake/meson.build, src/libstore-c/meson.build, src/libcmd/meson.build, src/libexpr-test-support/meson.build, src/libmain-c/meson.build, src/libmain/meson.build, src/libstore-test-support/meson.build, src/libutil-test-support/meson.build, src/libfetchers/meson.build, src/libexpr-test-support/meson.build
Replace hard-coded prelink: true with prelink: prelink so targets follow centralized setting.
Perl library prelink
src/perl/lib/Nix/meson.build
Define local prelink (Darwin+static → false) and apply it to Store library.
Wasmtime/WASM options & gating
src/libexpr/meson.options, src/libstore/meson.options, src/libexpr/package.nix, src/libstore/package.nix
Add wasm Meson options and enableWasm package flags; make Wasmtime optional and propagate mesonFlags.
Libexpr: unity, linking, sources
src/libexpr/meson.build, src/libexpr/primops/meson.build
Enable unity defaults, compute link_args and wasmtime_required, conditionally include wasm.cc, move/add parser sources, and replace fixed -lwasmtime with computed link_args.
Libstore: wasm gating & runtime flag
src/libstore/meson.build, src/libstore/unix/build/derivation-builder.cc, src/libstore/package.nix, src/libstore/meson.options
Expose IS_STATIC, compute/export NIX_USE_WASMTIME, gate WasiDerivationBuilder behind it, and use conditional linking for wasmtime.
Signal handler init
src/libutil-c/nix_api_util.cc
Call nix::unix::startSignalHandlerThread() on non‑Windows during libutil init.
File transfer static guard
src/libstore/filetransfer.cc
Guard curl interrupt-callback creation with !defined(IS_STATIC) to avoid static-build segfaults.
Header guard & fetchers
src/libfetchers/include/nix/fetchers/input-cache.hh, src/libfetchers/meson.build
Add #pragma once and adopt prelink variable in Meson for fetchers.
Packaging overrides & flags
packaging/dependencies.nix, src/nix/package.nix
Add libblake3 and curl overrides; conditionally include llvmPackages.libunwind and append NIX_CFLAGS_COMPILE flags and libunwind buildInputs for Clang+static+libcxx scenarios.
Flake: static variants exposure
flake.nix
Expose per-package -static and per-stdenv -${stdenv}-static attributes and add native static devShells entries.
CPU detection & docs
nix-meson-build-support/default-system-cpu/meson.build, doc/manual/source/development/building.md
Treat arm64 like arm for CPU detection and update docs table.
CI static build artifact
.github/workflows/build.yml
Add nix build .#packages.${{ inputs.system }}.nix-cli-static --no-link -L step to build static artifact(s).

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant Meson as Meson (configure)
  participant Build as Compiler/Linker
  participant Wasmtime as Wasmtime lib
  participant Runtime as Nix runtime

  Dev->>Meson: set option `wasm` / package `enableWasm`
  Meson->>Meson: compute `prelink`, `wasmtime_required`, `link_args`, set NIX_USE_WASMTIME
  Meson->>Build: emit compile defs and `link_args` (may include -lwasmtime)
  Build->>Wasmtime: link if `link_args` contains wasmtime
  Runtime->>Runtime: instantiate WasiDerivationBuilder if NIX_USE_WASMTIME
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Wasm support #309 — Overlapping Wasmtime/WASM integration, Meson options, and conditional linking.

Suggested reviewers

  • cole-h

Poem

🐇 I nudged prelink to heed the compiler's tune,
let Wasm be optional, or absent by noon,
unity stitched files, links chosen with care,
signals wake on unix air, static guards everywhere,
the rabbit hops — the build sings in tune.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Enable static builds' directly and accurately describes the main objective of this PR, which is to enable static build support throughout the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jan 22, 2026 •

Copy link
Copy Markdown

@github-actions
github-actions Bot temporarily deployed to pull request January 22, 2026 18:20 Inactive
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 529dd02 to dcb75d7 Compare January 22, 2026 18:35
@github-actions
github-actions Bot temporarily deployed to pull request January 22, 2026 18:36 Inactive
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 7053c04 to 769f599 Compare January 23, 2026 18:16
@github-actions
github-actions Bot temporarily deployed to pull request January 23, 2026 18:21 Inactive
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch 3 times, most recently from 878d282 to 37b33a6 Compare January 23, 2026 18:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/build.yml:
- Line 55: The step running "nix build .#packages.${{ inputs.system
}}.nix-cli-static --no-link -L" must be gated to Linux because nix-cli-static
relies on pkgsStatic which only works on Linux; add an if condition to the step
such as if: contains(inputs.system, 'linux') (or if: runner.os == 'Linux') so
the nix-cli-static build is only executed for Linux systems and skipped on macOS
(e.g., aarch64-darwin).

Comment thread .github/workflows/build.yml
@github-actions
github-actions Bot temporarily deployed to pull request January 23, 2026 23:58 Inactive
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 255efce to 1fee9a2 Compare January 24, 2026 00:11
@github-actions
github-actions Bot temporarily deployed to pull request January 24, 2026 00:18 Inactive
@github-actions
github-actions Bot temporarily deployed to pull request January 24, 2026 00:44 Inactive
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch 2 times, most recently from f8bfb37 to 512bac7 Compare January 24, 2026 01:01
@github-actions
github-actions Bot temporarily deployed to pull request January 24, 2026 01:06 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packaging/dependencies.nix`:
- Around line 86-90: The curl override uses pkgs.stdenv to detect static builds
which can differ from the scoped stdenv in this file; change the checks in the
override to use the scoped stdenv available in the current scope (replace
pkgs.stdenv.hostPlatform.isStatic with stdenv.hostPlatform.isStatic) so
pslSupport and idnSupport are computed correctly for static/cross builds (update
references in the curl override block for pslSupport and idnSupport).

Comment thread packaging/dependencies.nix
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 678239b to a75a0c5 Compare January 24, 2026 02:02
@github-actions
github-actions Bot temporarily deployed to pull request January 24, 2026 02:04 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In `@src/libfetchers-c/nix_api_fetchers.h`:
- Around line 24-35: Fix the doc comment for nix_libfetchers_init: correct the
grammar "it idempotent" to "it is idempotent" and change the `@ingroup` tag from
libfetcher_init to the existing group name libfetchers (or alternatively define
a libfetcher_init subgroup if that was intended) so the group reference matches
the file's `@defgroup`; update only the comment block above the
nix_libfetchers_init declaration.

In `@src/libfetchers/fetchers.cc`:
- Around line 546-557: initFetchers() currently registers every input scheme by
calling registerTarballInputScheme(), registerGitHubInputScheme(),
registerPathInputScheme(), etc., but each of those is also registered via
OnStartup wrappers in their individual modules (e.g., tarball.cc, github.cc,
path.cc), causing duplicate-registration errors from registerInputScheme() when
initFetchers() runs later; remove the OnStartup registration wrappers from the
individual source files (e.g., the OnStartup calls in tarball.cc, github.cc,
path.cc and any other register*InputScheme() OnStartup usages) so that
initFetchers() is the single place that calls all register*InputScheme()
functions and no duplicate registerInputScheme() calls occur.

In `@src/libfetchers/git.cc`:
- Around line 1238-1243: The duplicate registration happens because
rGitInputScheme (the OnStartup lambda) calls registerGitInputScheme() and
initFetchers() also calls the same function, causing registerInputScheme() to
throw on second registration; fix by making the registration idempotent or
removing the automatic startup registration: either delete the rGitInputScheme
OnStartup declaration so registerGitInputScheme() is only invoked from
initFetchers(), or change registerGitInputScheme() to guard against double
registration (for example with a static bool/atomic "registered" flag or by
checking if the scheme is already registered before calling
registerInputScheme()) so repeated calls are safe; update references to
rGitInputScheme, registerGitInputScheme, and registerInputScheme accordingly.

In `@src/libfetchers/github.cc`:
- Around line 662-664: These static variables use OnStartup wrappers which cause
duplicate registration when initFetchers() also registers schemes; remove the
OnStartup(...) wrapper and initialize the variables by directly calling the
registration functions instead (replace the lines for rGitHubInputScheme,
rGitLabInputScheme, and rSourceHutInputScheme so they call
registerGitHubInputScheme(), registerGitLabInputScheme(), and
registerSourceHutInputScheme() directly or remove the variables entirely and
rely on initFetchers() to perform registration).

In `@src/libfetchers/include/nix/fetchers/fetchers.hh`:
- Around line 281-282: The header declares nix::fetchers::initFetchers() but the
only implementation is nix::initFetchers() — causing a linker mismatch; either
remove the nix::fetchers::initFetchers() declaration from the header or add a
delegating implementation (nix::fetchers::initFetchers() { return
::nix::initFetchers(); }) so both symbols exist and link correctly; locate the
declaration in the nix::fetchers namespace and either delete it or implement the
wrapper to call the existing nix::initFetchers().

In `@src/libfetchers/indirect.cc`:
- Around line 142-147: The OnStartup static rIndirectInputScheme currently calls
registerIndirectInputScheme() but initFetchers() also calls
registerIndirectInputScheme(), causing double registration and a thrown error
from registerInputScheme(); fix by making registration idempotent: modify
registerIndirectInputScheme() to check for prior registration (e.g., a static
bool/guard or query existing schemes) and return early if already registered, or
alternatively remove the OnStartup rIndirectInputScheme registration so
initFetchers() is the sole initializer; update references to
rIndirectInputScheme, OnStartup, registerIndirectInputScheme(),
registerInputScheme(), and initFetchers() accordingly.

In `@src/libfetchers/mercurial.cc`:
- Around line 378-383: The Mercurial fetcher is being registered twice due to
the OnStartup static rMercurialInputScheme plus the initFetchers() path; remove
the duplicate registration by deleting the OnStartup usage and relying on
initFetchers() (or vice versa) so only one registration occurs. Specifically,
eliminate the rMercurialInputScheme = OnStartup(...) static or stop calling
registerMercurialInputScheme() from initFetchers(), ensuring only one of the
symbols (rMercurialInputScheme, registerMercurialInputScheme, or the
initFetchers registration entry) performs the
registerInputScheme(std::make_unique<MercurialInputScheme()) call.

In `@src/libfetchers/path.cc`:
- Around line 174-179: Static initialization via rPathInputScheme (OnStartup)
plus the explicit call to registerPathInputScheme() from initFetchers() causes
double registration and a thrown error from registerInputScheme; fix by making
registration idempotent or removing the automatic startup. Either remove
rPathInputScheme/OnStartup so registerPathInputScheme() is only invoked from
initFetchers(), or guard registerPathInputScheme() with a static bool (or check
registerInputScheme for existence) so repeated calls to
registerPathInputScheme() simply return without re-registering; reference
registerPathInputScheme, rPathInputScheme, OnStartup, registerInputScheme, and
initFetchers when applying the change.

In `@src/libfetchers/tarball.cc`:
- Around line 521-522: Remove the OnStartup wrappers to prevent duplicate
registration: replace the static initializers using OnStartup
(rTarballInputScheme and rFileInputScheme) with direct calls to
registerTarballInputScheme() and registerFileInputScheme() so the schemes are
registered exactly once (matching how initFetchers() performs registration);
update the lines referencing OnStartup to static auto rTarballInputScheme =
registerTarballInputScheme(); and static auto rFileInputScheme =
registerFileInputScheme().

Comment thread src/libfetchers-c/nix_api_fetchers.h Outdated
Comment on lines +24 to +35
/**
* @brief Initialize the Nix fetchers.
* @ingroup libfetcher_init
*
* This function must be called at least once,
* at some point before using a fetcher for the first time.
* This function can be called multiple times, and it idempotent.
*
* @param[out] context Optional, stores error information
* @return NIX_OK if the initialization was successful, an error code otherwise.
*/
nix_err nix_libfetchers_init(nix_c_context * context);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor documentation issues.

  1. Line 30: Grammar issue - "it idempotent" should be "it is idempotent"
  2. Line 26: The @ingroup libfetcher_init references a group that doesn't appear to be defined. The file's @defgroup on line 3 uses libfetchers. Consider using @ingroup libfetchers for consistency, or define a libfetcher_init subgroup.
Suggested fix
 /**
  * `@brief` Initialize the Nix fetchers.
- * `@ingroup` libfetcher_init
+ * `@ingroup` libfetchers
  *
  * This function must be called at least once,
  * at some point before using a fetcher for the first time.
- * This function can be called multiple times, and it idempotent.
+ * This function can be called multiple times, and it is idempotent.
  *
  * `@param`[out] context Optional, stores error information
  * `@return` NIX_OK if the initialization was successful, an error code otherwise.
  */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @brief Initialize the Nix fetchers.
* @ingroup libfetcher_init
*
* This function must be called at least once,
* at some point before using a fetcher for the first time.
* This function can be called multiple times, and it idempotent.
*
* @param[out] context Optional, stores error information
* @return NIX_OK if the initialization was successful, an error code otherwise.
*/
nix_err nix_libfetchers_init(nix_c_context * context);
/**
* `@brief` Initialize the Nix fetchers.
* `@ingroup` libfetchers
*
* This function must be called at least once,
* at some point before using a fetcher for the first time.
* This function can be called multiple times, and it is idempotent.
*
* `@param`[out] context Optional, stores error information
* `@return` NIX_OK if the initialization was successful, an error code otherwise.
*/
nix_err nix_libfetchers_init(nix_c_context * context);
🤖 Prompt for AI Agents
In `@src/libfetchers-c/nix_api_fetchers.h` around lines 24 - 35, Fix the doc
comment for nix_libfetchers_init: correct the grammar "it idempotent" to "it is
idempotent" and change the `@ingroup` tag from libfetcher_init to the existing
group name libfetchers (or alternatively define a libfetcher_init subgroup if
that was intended) so the group reference matches the file's `@defgroup`; update
only the comment block above the nix_libfetchers_init declaration.

Comment thread src/libfetchers/fetchers.cc Outdated
Comment on lines +546 to +557
void initFetchers()
{
registerTarballInputScheme();
registerFileInputScheme();
registerGitInputScheme();
registerGitHubInputScheme();
registerGitLabInputScheme();
registerSourceHutInputScheme();
registerPathInputScheme();
registerIndirectInputScheme();
registerMercurialInputScheme();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Double registration issue affects all input schemes.

This initFetchers() function calls all register*InputScheme() functions. However, each of those functions is also called via OnStartup in their respective source files (e.g., tarball.cc lines 521-522, github.cc lines 662-664, path.cc line 174).

Since registerInputScheme() throws on duplicate registration (line 29-30), calling initFetchers() after the OnStartup callbacks have already run will crash.

The OnStartup wrappers in all the individual files should be removed to let initFetchers() be the sole registration mechanism.

🤖 Prompt for AI Agents
In `@src/libfetchers/fetchers.cc` around lines 546 - 557, initFetchers() currently
registers every input scheme by calling registerTarballInputScheme(),
registerGitHubInputScheme(), registerPathInputScheme(), etc., but each of those
is also registered via OnStartup wrappers in their individual modules (e.g.,
tarball.cc, github.cc, path.cc), causing duplicate-registration errors from
registerInputScheme() when initFetchers() runs later; remove the OnStartup
registration wrappers from the individual source files (e.g., the OnStartup
calls in tarball.cc, github.cc, path.cc and any other register*InputScheme()
OnStartup usages) so that initFetchers() is the single place that calls all
register*InputScheme() functions and no duplicate registerInputScheme() calls
occur.

Comment thread src/libfetchers/git.cc Outdated
Comment thread src/libfetchers/github.cc Outdated
Comment on lines +662 to +664
static auto rGitHubInputScheme = OnStartup([] { registerGitHubInputScheme(); });
static auto rGitLabInputScheme = OnStartup([] { registerGitLabInputScheme(); });
static auto rSourceHutInputScheme = OnStartup([] { registerSourceHutInputScheme(); });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove OnStartup wrappers to avoid double registration.

Same issue as in other fetcher files - these OnStartup wrappers will conflict with initFetchers() calls.

Proposed fix
-static auto rGitHubInputScheme = OnStartup([] { registerGitHubInputScheme(); });
-static auto rGitLabInputScheme = OnStartup([] { registerGitLabInputScheme(); });
-static auto rSourceHutInputScheme = OnStartup([] { registerSourceHutInputScheme(); });
-
 void registerGitHubInputScheme()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static auto rGitHubInputScheme = OnStartup([] { registerGitHubInputScheme(); });
static auto rGitLabInputScheme = OnStartup([] { registerGitLabInputScheme(); });
static auto rSourceHutInputScheme = OnStartup([] { registerSourceHutInputScheme(); });
void registerGitHubInputScheme()
🤖 Prompt for AI Agents
In `@src/libfetchers/github.cc` around lines 662 - 664, These static variables use
OnStartup wrappers which cause duplicate registration when initFetchers() also
registers schemes; remove the OnStartup(...) wrapper and initialize the
variables by directly calling the registration functions instead (replace the
lines for rGitHubInputScheme, rGitLabInputScheme, and rSourceHutInputScheme so
they call registerGitHubInputScheme(), registerGitLabInputScheme(), and
registerSourceHutInputScheme() directly or remove the variables entirely and
rely on initFetchers() to perform registration).

Comment on lines +281 to +282
void initFetchers();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all occurrences of initFetchers in the header file
echo "=== Declarations in fetchers.hh ===" 
rg -n "void initFetchers" src/libfetchers/include/nix/fetchers/fetchers.hh -B 2 -A 2

echo -e "\n=== Implementations in fetchers.cc ===" 
rg -n "void initFetchers\|void.*fetchers.*initFetchers" src/libfetchers/fetchers.cc -B 2 -A 10

Repository: DeterminateSystems/nix-src

Length of output: 341


🏁 Script executed:

#!/bin/bash
# Check namespace context for declarations
echo "=== Namespace context around line 281-282 in fetchers.hh ===" 
sed -n '270,290p' src/libfetchers/include/nix/fetchers/fetchers.hh

echo -e "\n=== Namespace context around line 20-22 in fetchers.hh ===" 
sed -n '15,30p' src/libfetchers/include/nix/fetchers/fetchers.hh

echo -e "\n=== Namespace context around implementations in fetchers.cc ===" 
sed -n '540,560p' src/libfetchers/fetchers.cc

Repository: DeterminateSystems/nix-src

Length of output: 1367


🏁 Script executed:

#!/bin/bash
# Search the entire codebase for all initFetchers implementations
echo "=== All initFetchers function definitions in the codebase ===" 
rg -n "^\s*(void\s+)?initFetchers\s*\(" src/libfetchers/ --type cpp --type h -A 3

Repository: DeterminateSystems/nix-src

Length of output: 904


Remove or implement the duplicate nix::fetchers::initFetchers() declaration.

The declaration at line 281 in the nix::fetchers namespace lacks a corresponding implementation. The only implementation (in fetchers.cc:546) is in the nix namespace. This will cause linker errors if the nix::fetchers::initFetchers() function is called. Either remove this declaration or provide an implementation. If both namespace versions are needed, have one delegate to the other.

🤖 Prompt for AI Agents
In `@src/libfetchers/include/nix/fetchers/fetchers.hh` around lines 281 - 282, The
header declares nix::fetchers::initFetchers() but the only implementation is
nix::initFetchers() — causing a linker mismatch; either remove the
nix::fetchers::initFetchers() declaration from the header or add a delegating
implementation (nix::fetchers::initFetchers() { return ::nix::initFetchers(); })
so both symbols exist and link correctly; locate the declaration in the
nix::fetchers namespace and either delete it or implement the wrapper to call
the existing nix::initFetchers().

Comment thread src/libfetchers/indirect.cc Outdated
Comment thread src/libfetchers/mercurial.cc Outdated
Comment thread src/libfetchers/path.cc Outdated
Comment thread src/libfetchers/tarball.cc Outdated
Comment on lines +521 to +522
static auto rTarballInputScheme = OnStartup([] { registerTarballInputScheme(); });
static auto rFileInputScheme = OnStartup([] { registerFileInputScheme(); });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove OnStartup wrappers to avoid double registration.

Same issue as flagged in path.cc and fetchers.cc - these OnStartup wrappers will cause double registration when initFetchers() is called.

Proposed fix
-static auto rTarballInputScheme = OnStartup([] { registerTarballInputScheme(); });
-static auto rFileInputScheme = OnStartup([] { registerFileInputScheme(); });
-
 void registerTarballInputScheme()
🤖 Prompt for AI Agents
In `@src/libfetchers/tarball.cc` around lines 521 - 522, Remove the OnStartup
wrappers to prevent duplicate registration: replace the static initializers
using OnStartup (rTarballInputScheme and rFileInputScheme) with direct calls to
registerTarballInputScheme() and registerFileInputScheme() so the schemes are
registered exactly once (matching how initFetchers() performs registration);
update the lines referencing OnStartup to static auto rTarballInputScheme =
registerTarballInputScheme(); and static auto rFileInputScheme =
registerFileInputScheme().

@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch 2 times, most recently from a661669 to b7fef3b Compare January 24, 2026 04:16
@github-actions
github-actions Bot temporarily deployed to pull request January 24, 2026 04:21 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/libfetchers/fetchers.cc`:
- Around line 546-567: The current initFetchers() uses a non-atomic static bool
guard which can race; replace that pattern with a thread-safe one-time
initialization using a static std::once_flag and std::call_once. Inside
initFetchers(), remove the static bool init and its check/assignment, declare a
static std::once_flag (e.g. fetchers_init_flag) and wrap the registration calls
(registerTarballInputScheme, registerFileInputScheme, registerGitInputScheme,
registerGitHubInputScheme, registerGitLabInputScheme,
registerSourceHutInputScheme, registerPathInputScheme,
registerIndirectInputScheme, registerMercurialInputScheme) in a
std::call_once(fetchers_init_flag, [] { ... }); to ensure registrations run
exactly once across threads.
♻️ Duplicate comments (1)
src/libfetchers-c/nix_api_fetchers.h (1)

24-35: Documentation issues persist from previous review.

The past review flagged two issues that remain unaddressed:

  1. Line 26: @ingroup libfetcher_init should be @ingroup libfetchers to match the @defgroup on line 3
  2. Line 30: Grammar error - "and it idempotent" should be "and it is idempotent"
Suggested fix
 /**
  * `@brief` Initialize the Nix fetchers.
- * `@ingroup` libfetcher_init
+ * `@ingroup` libfetchers
  *
  * This function must be called at least once,
  * at some point before using a fetcher for the first time.
- * This function can be called multiple times, and it idempotent.
+ * This function can be called multiple times, and it is idempotent.
  *
  * `@param`[out] context Optional, stores error information
  * `@return` NIX_OK if the initialization was successful, an error code otherwise.
  */

Comment thread src/libfetchers/fetchers.cc Outdated
Comment on lines +546 to +567
namespace nix {

using namespace nix::fetchers;

void initFetchers()
{
static bool init;
if (init)
return;

init = true;

registerTarballInputScheme();
registerFileInputScheme();
registerGitInputScheme();
registerGitHubInputScheme();
registerGitLabInputScheme();
registerSourceHutInputScheme();
registerPathInputScheme();
registerIndirectInputScheme();
registerMercurialInputScheme();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make initFetchers() thread-safe (static bool causes a data race).

Line 552 uses a non-atomic static bool guard. If initFetchers() is reached concurrently (now possible via Input::fromURL / fromAttrs), two threads can pass the guard, causing double-registration or UB. Prefer std::once_flag + std::call_once.

🔧 Suggested fix (thread-safe one-time init)
+#include <mutex>
 ...
 void initFetchers()
 {
-    static bool init;
-    if (init)
-        return;
-
-    init = true;
-
-    registerTarballInputScheme();
-    registerFileInputScheme();
-    registerGitInputScheme();
-    registerGitHubInputScheme();
-    registerGitLabInputScheme();
-    registerSourceHutInputScheme();
-    registerPathInputScheme();
-    registerIndirectInputScheme();
-    registerMercurialInputScheme();
+    static std::once_flag once;
+    std::call_once(once, [] {
+        registerTarballInputScheme();
+        registerFileInputScheme();
+        registerGitInputScheme();
+        registerGitHubInputScheme();
+        registerGitLabInputScheme();
+        registerSourceHutInputScheme();
+        registerPathInputScheme();
+        registerIndirectInputScheme();
+        registerMercurialInputScheme();
+    });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
namespace nix {
using namespace nix::fetchers;
void initFetchers()
{
static bool init;
if (init)
return;
init = true;
registerTarballInputScheme();
registerFileInputScheme();
registerGitInputScheme();
registerGitHubInputScheme();
registerGitLabInputScheme();
registerSourceHutInputScheme();
registerPathInputScheme();
registerIndirectInputScheme();
registerMercurialInputScheme();
}
namespace nix {
using namespace nix::fetchers;
void initFetchers()
{
static std::once_flag once;
std::call_once(once, [] {
registerTarballInputScheme();
registerFileInputScheme();
registerGitInputScheme();
registerGitHubInputScheme();
registerGitLabInputScheme();
registerSourceHutInputScheme();
registerPathInputScheme();
registerIndirectInputScheme();
registerMercurialInputScheme();
});
}
🤖 Prompt for AI Agents
In `@src/libfetchers/fetchers.cc` around lines 546 - 567, The current
initFetchers() uses a non-atomic static bool guard which can race; replace that
pattern with a thread-safe one-time initialization using a static std::once_flag
and std::call_once. Inside initFetchers(), remove the static bool init and its
check/assignment, declare a static std::once_flag (e.g. fetchers_init_flag) and
wrap the registration calls (registerTarballInputScheme,
registerFileInputScheme, registerGitInputScheme, registerGitHubInputScheme,
registerGitLabInputScheme, registerSourceHutInputScheme,
registerPathInputScheme, registerIndirectInputScheme,
registerMercurialInputScheme) in a std::call_once(fetchers_init_flag, [] { ...
}); to ensure registrations run exactly once across threads.

@github-actions
github-actions Bot temporarily deployed to pull request January 24, 2026 05:27 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/libexpr/include/nix/expr/primops.hh`:
- Around line 24-27: The member primOp is currently declared as an rvalue
reference (PrimOp && primOp) which can dangle; change the member to store PrimOp
by value (PrimOp primOp) and update the constructor initializer to move the
parameter into the member (primOp(std::move(primOp))) so that ensure() and
primOps().push_back(primOp) own a valid object; keep the existing registered
bool and ensure() usage unchanged.

In `@src/libexpr/primops.cc`:
- Around line 5205-5219: The ensure() method in RegisterPrimOp mutates
registered and primOps() without synchronization; wrap the body of
RegisterPrimOp::ensure() with a mutex to make the check-then-act atomic: add a
(likely static) std::mutex (or std::recursive_mutex if needed) used by
RegisterPrimOp::ensure(), acquire a std::lock_guard<std::mutex> at the start of
ensure(), then re-check registered and, if false, push primOp into primOps() and
set registered = true; include <mutex> and keep the lock scope minimal to cover
the check and mutation only.

Comment thread src/libexpr/include/nix/expr/primops.hh Outdated
Comment on lines +24 to +27
void ensure();
private:
bool registered;
PrimOp && primOp;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find RegisterPrimOp class definition and constructor
rg -n "class RegisterPrimOp|struct RegisterPrimOp" -A 20 --type cpp --type h

Repository: DeterminateSystems/nix-src

Length of output: 1537


🏁 Script executed:

#!/bin/bash
# Find RegisterPrimOp::ensure() implementation
rg -n "RegisterPrimOp::ensure|void ensure" -B 2 -A 10 --type cpp --type h

Repository: DeterminateSystems/nix-src

Length of output: 6538


🏁 Script executed:

#!/bin/bash
# Search for RegisterPrimOp instantiation patterns to see if temporaries are used
rg -n "RegisterPrimOp\s*[({]|new RegisterPrimOp" -B 2 -A 2 --type cpp

Repository: DeterminateSystems/nix-src

Length of output: 1103


🏁 Script executed:

#!/bin/bash
# Check if registered member is initialized anywhere
rg -n "registered\s*=" -C 2 --type cpp --type h | head -30

Repository: DeterminateSystems/nix-src

Length of output: 269


🌐 Web query:

C++ rvalue reference data members lifetime semantics constructor temporary binding

💡 Result:

In C++, binding a temporary to a reference data member (including an T&& rvalue-reference member) generally does not extend the temporary’s lifetime to the lifetime of the containing object. The temporary typically dies at the end of the full-expression that performed the construction, leaving the member dangling. [1]

The rule (what does and doesn’t get lifetime extension)

A temporary’s lifetime is extended when it is directly bound to a reference in certain contexts (e.g., a local const T& r = T{...}; or T&& r = T{...};). But there are important exceptions, including:

  • A temporary bound to a reference in a member initializer (mem-initializer) (e.g. S(T&& x) : r(std::move(x)) {} or : r(T{}) {}) lives only until the end of the full-expression containing the construction (i.e., through the ; of S s(...);), not as long as s lives. [1]

Consequence for rvalue-reference data members

struct S {
  std::string&& r;
  S(std::string&& x) : r(std::move(x)) {}
};

S make() { return S(std::string("hi")); } // r will dangle after the full-expression

std::string("hi") is a temporary; S::r ends up referring to it, but that temporary is destroyed at the end of the statement that creates the S. [1]

A subtle special case: aggregate initialization in C++20

For aggregates, C++20 introduced a distinction:

struct A { int&& r; };

A a1{7}; // lifetime *is* extended (braces) [1]
A a2(7); // well-formed, but r dangles (parens) [1]

So brace-init aggregate can extend the lifetime in this specific scenario, but constructor-style init does not. [1]

Why expression-template code can “work”

Expression-template libraries avoid dangling by ensuring that:

  • they only store references to operands that outlive the expression object, and/or
  • they capture rvalues by value (owning storage) while referencing lvalues, often via perfect-forwarding wrappers.

If you store an rvalue-reference member to a temporary operand, you’ll reproduce the dangling behavior discussed in practice. [2]

Practical guidance

  • Don’t use T&& (or const T&) data members to “hold” temporaries unless you prove the referred object outlives the containing object.
  • Prefer storing by value (possibly with move) for ownership:
    struct S { std::string v; S(std::string x) : v(std::move(x)) {} };

Sources: cppreference on temporary lifetime extension and the “reference member in new-expression / construction” exception (and aggregate brace/parens difference) [1], plus a representative discussion showing the dangling behavior with rvalue-reference members in practice [2].

[1] Reference initialization & temporary lifetime notes (cppreference)
[2] “Data member and rvalue life-time” discussion (Stack Overflow)


Store PrimOp by value to prevent dangling references.

The member PrimOp && primOp binds to an rvalue reference parameter that may itself be bound to a temporary. Per C++ semantics, temporaries bound to reference data members in the initializer list do not have their lifetime extended—they are destroyed at the end of the constructor's full-expression. This leaves the member reference dangling when ensure() later accesses it via primOps().push_back(primOp).

The constructor correctly initializes registered to false, but storing primOp by value is necessary to own the object safely.

Suggested fix
-    bool registered;
-    PrimOp && primOp;
+    bool registered = false;
+    PrimOp primOp;

Update the constructor initializer to primOp(std::move(primOp)), which will move-assign the parameter into the by-value member.

🤖 Prompt for AI Agents
In `@src/libexpr/include/nix/expr/primops.hh` around lines 24 - 27, The member
primOp is currently declared as an rvalue reference (PrimOp && primOp) which can
dangle; change the member to store PrimOp by value (PrimOp primOp) and update
the constructor initializer to move the parameter into the member
(primOp(std::move(primOp))) so that ensure() and primOps().push_back(primOp) own
a valid object; keep the existing registered bool and ensure() usage unchanged.

Comment thread src/libexpr/primops.cc
Comment on lines 5205 to 5219
RegisterPrimOp::RegisterPrimOp(PrimOp && primOp)
: registered(false)
, primOp(std::move(primOp))
{
primOps().push_back(std::move(primOp));
ensure();
}

void RegisterPrimOp::ensure()
{
if (registered)
return;

primOps().push_back(primOp);
registered = true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate the file and check the RegisterPrimOp class definition
find . -name "primops.cc" -o -name "primops.h" | head -20

Repository: DeterminateSystems/nix-src

Length of output: 125


🏁 Script executed:

# Search for RegisterPrimOp class definition
rg "class RegisterPrimOp" -A 10 -B 2

Repository: DeterminateSystems/nix-src

Length of output: 52


🏁 Script executed:

# Search for where initPrimOps is called
rg "initPrimOps\(" -n

Repository: DeterminateSystems/nix-src

Length of output: 221


🏁 Script executed:

# Search for primOps function definition
rg "primOps\(\)" -B 3 -A 5 --max-count=10

Repository: DeterminateSystems/nix-src

Length of output: 1983


🏁 Script executed:

# Check the context where initPrimOps() is called
sed -n '335,350p' src/libexpr/eval.cc

Repository: DeterminateSystems/nix-src

Length of output: 595


🏁 Script executed:

# Find RegisterPrimOp class definition
rg "struct RegisterPrimOp|class RegisterPrimOp" -A 15

Repository: DeterminateSystems/nix-src

Length of output: 1110


🏁 Script executed:

# Search for where RegisterPrimOp objects are instantiated
rg "RegisterPrimOp\{" -B 3 -A 3

Repository: DeterminateSystems/nix-src

Length of output: 52


🏁 Script executed:

# Check the EvalState constructor to see if it's called from multiple threads
rg "EvalState::" src/libexpr/eval.cc | head -20

Repository: DeterminateSystems/nix-src

Length of output: 1220


🏁 Script executed:

# Find initPrimOps() implementation
sed -n '5535,5600p' src/libexpr/primops.cc

Repository: DeterminateSystems/nix-src

Length of output: 2001


🏁 Script executed:

# Search for RegisterPrimOp constructor calls more thoroughly
rg "RegisterPrimOp" src/libexpr/primops.cc | head -30

Repository: DeterminateSystems/nix-src

Length of output: 1262


🏁 Script executed:

# Look for global RegisterPrimOp instances
rg "^.*RegisterPrimOp" src/libexpr/primops.cc | grep -v "//" | head -20

Repository: DeterminateSystems/nix-src

Length of output: 866


🏁 Script executed:

# Check for any threading/concurrency related comments or patterns in eval.hh
rg "thread|concurrent|lock|mutex|atomic" src/libexpr/include/nix/expr/eval.hh

Repository: DeterminateSystems/nix-src

Length of output: 592


🏁 Script executed:

# Look for any synchronization in the codebase for primop initialization
rg "primOps\|RegisterPrimOp" src/libexpr/primops.cc | grep -i "lock\|mutex\|atomic"

Repository: DeterminateSystems/nix-src

Length of output: 52


Add synchronization to RegisterPrimOp::ensure() for thread-safe concurrent initialization.

The registered field and primOps() vector are mutated without synchronization. Since initPrimOps() is called in the EvalState constructor and EvalState can be constructed concurrently from multiple threads (as evidenced by concurrent data structures elsewhere in the codebase), this creates a data race. The check-then-act pattern (if (registered) return; ... registered = true;) without locking is unsafe under concurrent access.

🔒 Suggested fix (mutex-guarded registration)
+#include <mutex>
...
 void RegisterPrimOp::ensure()
 {
+    static std::mutex primOpsMutex;
+    std::lock_guard<std::mutex> lock(primOpsMutex);
     if (registered)
         return;

     primOps().push_back(primOp);
     registered = true;
 }
🤖 Prompt for AI Agents
In `@src/libexpr/primops.cc` around lines 5205 - 5219, The ensure() method in
RegisterPrimOp mutates registered and primOps() without synchronization; wrap
the body of RegisterPrimOp::ensure() with a mutex to make the check-then-act
atomic: add a (likely static) std::mutex (or std::recursive_mutex if needed)
used by RegisterPrimOp::ensure(), acquire a std::lock_guard<std::mutex> at the
start of ensure(), then re-check registered and, if false, push primOp into
primOps() and set registered = true; include <mutex> and keep the lock scope
minimal to cover the check and mutation only.

@cole-h
cole-h force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 7c6e6ba to 5600f5f Compare January 28, 2026 19:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
nix-meson-build-support/default-system-cpu/meson.build (1)

13-18: Change 'arm64' to 'aarch64' in the cpu_family condition.

Meson's canonical cpu_family value for Apple Silicon (and 64-bit ARM generally) is 'aarch64', not 'arm64'. The current condition checks for 'arm64' which will never match, causing Apple Silicon machines to fall through to other branches and produce incorrect system strings. Update the condition to host_machine.cpu_family() in [ 'arm', 'aarch64' ].

🤖 Fix all issues with AI agents
In `@src/nix/main.cc`:
- Around line 44-53: The current preprocessor blocks using __arm__ and __arm64__
unconditionally invoke `#error` (with macros STRINGIFY/TOSTRING) which breaks all
ARM/aarch64 builds; modify the blocks around the symbols __arm__ and __arm64__
to be conditional on an explicit opt-in debug macro (e.g., NIX_ARM_DIAGNOSTIC or
ENABLE_DEBUG_DIAGNOSTICS) or remove the `#error` entirely, and replace the
informal error text with a professional diagnostic via `#pragma` message (or log)
if the debug macro is set; ensure STRINGIFY and TOSTRING are still used for
printing NIX_LOCAL_SYSTEM, and keep the diagnostic gated so normal builds on ARM
succeed.

Comment thread src/nix/main.cc Outdated
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 77850bc to 83c2e4f Compare February 5, 2026 15:50
@github-actions
github-actions Bot temporarily deployed to pull request February 5, 2026 15:57 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/libexpr/meson.build`:
- Around line 82-91: The problem is that link_args is a list but the += is
adding a string when wasmtime is enabled; modify the wasmtime_required.enabled()
branch to add the flag as a one-element list or use the list append method
instead of concatenating a raw string — update the block that references
link_args and wasmtime_required (the link_args variable and
wasmtime_required.enabled() conditional) to use either link_args +=
['-lwasmtime'] or link_args.append('-lwasmtime') so Meson receives a list.

Comment thread src/libexpr/meson.build
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 39f7fd3 to a7f926c Compare February 5, 2026 19:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@nix-meson-build-support/common/meson.build`:
- Around line 68-75: The variable cxx (set via meson.get_compiler('cpp')) is
declared too late; move the statement cxx = meson.get_compiler('cpp') to the top
of the meson.build file before any use (before the first occurrence where cxx is
referenced) so all subsequent checks (the clang/static-library prelink logic
using cxx.get_id(), and other uses currently at the earlier occurrences) see a
defined compiler instance; remove or avoid the later duplicate assignment at its
current location and ensure all references use that single top-level cxx
binding.

Comment thread nix-meson-build-support/common/meson.build
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from a7f926c to 7f7fef6 Compare February 5, 2026 19:37
@github-actions
github-actions Bot temporarily deployed to pull request February 5, 2026 19:40 Inactive
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch 3 times, most recently from 6f015ee to 65030cd Compare February 5, 2026 20:22
@github-actions
github-actions Bot temporarily deployed to pull request February 5, 2026 20:30 Inactive
Comment thread packaging/dependencies.nix
@RossComputerGuy
RossComputerGuy force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from 65030cd to 1f2a242 Compare February 5, 2026 20:48
@github-actions
github-actions Bot temporarily deployed to pull request February 5, 2026 20:50 Inactive
@cole-h
cole-h requested a review from edolstra February 5, 2026 21:10
@cole-h

cole-h commented Feb 5, 2026

Copy link
Copy Markdown
Member

This all looks roughly fine to me. But I'll leave it to Eelco (as the more knowledgeable about this codebase ;p) for final approval.

@github-actions
github-actions Bot temporarily deployed to pull request February 6, 2026 11:33 Inactive
@edolstra
edolstra force-pushed the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch from a06c8c2 to afca2cf Compare February 6, 2026 11:58
@edolstra
edolstra enabled auto-merge February 6, 2026 11:59
@github-actions
github-actions Bot temporarily deployed to pull request February 6, 2026 12:00 Inactive
@edolstra
edolstra added this pull request to the merge queue Feb 6, 2026
Merged via the queue into main with commit 0e0935f Feb 6, 2026
28 checks passed
@edolstra
edolstra deleted the tristanross/dsp-62-collab-figure-out-static-building-of-determinate-nix branch February 6, 2026 12:37

This branch was previously deployed

1 inactive deployment
pull request — afca2cff Deployed Feb 6, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants