Skip to content

feat(nix): add Nix flake support for acryl-tui and acryl-desktop - #1

Closed
levonk wants to merge 16 commits into
mainfrom
feature/nix-flake-support
Closed

levonk wants to merge 16 commits into
mainfrom
feature/nix-flake-support

Conversation

@levonk

@levonk levonk commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add Nix flake support with two package outputs:
    • packages.${system}.acryl (default) — the terminal client (TUI + web server)
    • packages.${system}.acryl-desktop — the Electron desktop app
  • Add devbox.json for reproducible development environment
  • Add .github/workflows/nix.yml for CI across all 4 supported systems
  • Add /result and /result-* to .gitignore
  • Update docs/DEVELOPMENT-LOG.md with implementation details

Usage

nix run .#acryl -- --help
nix run .#acryl-desktop -- --help
nix profile install github:levonk/acryl#acryl

Test plan

  • nix flake check --no-build passes
  • nix build .#acryl succeeds
  • nix run .#acryl -- --help prints help
  • nix build .#acryl-desktop succeeds
  • nix run .#acryl-desktop -- --help prints help
  • CI passes on all 4 supported systems

@levonk
levonk force-pushed the feature/nix-flake-support branch 2 times, most recently from aa04fae to cfa8b92 Compare September 2, 2026 20:30
musichen added a commit that referenced this pull request Sep 8, 2026
…ayfinder ticket

New milestone: the agent engine (agent loop / durable sessions / tools /
approvals owner) becomes a replaceable provider behind acryl-harness-runtime.
DSH-in-CLI-mode is engine #1, pi (pi.dev / prime-agent) is engine acryldev#2, a
DSH+pi combo is a later candidate. Depends on M2. Grilling ticket 04 must
resolve before specs/028 is specified.
Add Nix flake support targeting the acryl-tui terminal client. The
flake uses nixpkgs' modern PNPM hooks (fetchPnpmDeps, pnpmConfigHook)
with pnpm_11 and fetcherVersion 4.

Key design decisions:
- Targets acryl-tui (not the Electron desktop app) as the default
  package, exposing the `acryl` binary via `nix run .#acryl`
- Uses nixpkgs-26.05-darwin legacy pin for x86_64-darwin (Intel
  macOS), since nixpkgs-unstable dropped support after 26.05
- Forces nodeLinker: hoisted in pnpm-workspace.yaml during the build
  to flatten node_modules (pnpm 11 moved this setting from .npmrc)
- Builds only the TUI dependency chain (acryl-control ->
  acryl-harness-runtime -> acryl-tui) instead of the full workspace
- Sets dontStrip and dontFixup to avoid slow strip/fixup phases on
  thousands of JS files in node_modules
- ESBUILD_BINARY_PATH points to nixpkgs esbuild to avoid the
  postinstall binary download (skipped by --ignore-scripts)

Also adds:
- devbox.json for reproducible development environment
- .github/workflows/nix.yml for CI across all 4 supported systems
- /result and /result-* to .gitignore
Document the implementation commit d6d2e46
which added Nix flake support for building acryl-tui.
Add `packages.${system}.acryl-desktop` to the flake, building the
Electron desktop app alongside the existing TUI output.

Key decisions:
- Uses nixpkgs electron (43.1.0) as the runtime instead of the npm
  electron package (which downloads a platform binary via postinstall,
  blocked by --ignore-scripts in the Nix sandbox)
- Creates a CJS shim at node_modules/electron/index.js that exports
  the nixpkgs electron path, replacing the real npm package
- Skips the generate-* build scripts (they use sharp for image
  processing) since build/ assets are already tracked in git
- Builds the full dependency chain: acryl-control ->
  acryl-harness-runtime -> dsh-community-market ->
  acryl-development-canvas -> acryl-desktop
- Refactors shared derivation attrs (pnpmDeps, preConfigure, etc.)
  into commonDerivationAttrs to avoid duplication between TUI and
  desktop derivations

Both outputs verified:
  nix run .#acryl -- --help
  nix run .#acryl-desktop -- --help
Document implementation commit 397f91034cb6a6444c6dccf6f33d06e8b10bf43b
which added the Electron desktop app as a separate Nix package output.
- SHA-pin all GitHub Actions to 40-char commit SHAs (checkout@v5,
  nix-installer-action@v22, magic-nix-cache-action@v14) instead of
  mutable @v4/@main refs — prevents supply-chain attacks
- Add if: github.event_name != 'pull_request' guard on nix run steps
  to prevent PR-controlled code from reaching GITHUB_TOKEN/OIDC
- Add path filtering to nix.yml (flake.nix, flake.lock, **/*.nix,
  pnpm-lock.yaml, etc.) so CI only fires when Nix files change
- Add nix run .#default -- --help test to CI
- Add act to devbox.json packages (required for local CI validation)
- Remove invalid nixpkgs.commit field from devbox.json (devbox 0.18
  ignores it; was set to channel name not 40-char hash)
- Add .devbox/ to .gitignore (devbox generated artifacts)
- Add Nix (Flake) and Devbox install sections to README.md,
  README.en.md, and README.zh.md
- Update bilingual-docs hash record in README.i18n.yaml

devbox.lock cannot be generated on x86_64-darwin due to devbox 0.18
hardcoding a nixpkgs commit that dropped x86_64-darwin support;
generate on aarch64-darwin or Linux.
devbox 0.18 ignores the nixpkgs.commit field for regular package-name
resolution and hardcodes nixpkgs 26.11, which dropped x86_64-darwin.
Work around this by referencing every package as a flake URL pointing
at the nixpkgs-26.05-darwin commit (f6107e5) — flake-based references
bypass devbox's package index, and nixpkgs.commit controls the shell
infrastructure (mkShell). This works on all platforms: x86_64-darwin,
aarch64-darwin, and Linux.

Generate and commit devbox.lock for reproducible environments.
Use per-package platform scoping: clean package names (nodejs_22,
pnpm_11, esbuild, act) for normal platforms (Linux, aarch64-darwin),
and flake URL references to nixpkgs-26.05-darwin only for x86_64-darwin.
The nixpkgs.commit field is set to the 26.05-darwin pin for the shell
infrastructure (mkShell), which devbox 0.18 honors when all active
packages on a platform are flake-based.

On normal platforms, packages resolve from nixpkgs-unstable via
devbox's index — the same behavior as before. On x86_64-darwin, the
flake URL references bypass devbox's hardcoded nixpkgs 26.11 (which
dropped x86_64-darwin) and pull from 26.05-darwin instead.

The lock file records both resolution paths. Linux/aarch64-darwin
entries will be populated when a user on that platform runs
devbox install.
Replace all github:levonk/acryl references with github:acryldev/acryl
in flake.nix (homepage meta), README.md, README.en.md, README.zh.md,
and DEVELOPMENT-LOG.md commit links. Update bilingual-docs hash record.
Add packages.<system>.prebuilt — fetches the prebuilt CLI tarball from
GitHub releases (v0.1.19). Each tarball bundles its own Node runtime
and native addons (node-pty, koffi, sharp), so no from-source build is
needed for the prebuilt path. Uses autoPatchelfHook on Linux for glibc
linking.

The default output remains #acryl (from-source build), following Nix
convention. #prebuilt is an optional fast path for users who want the
exact release binary.

Add CI steps to build and test #prebuilt on all 4 platforms.
Update READMEs to document the #prebuilt output.
…D hash

Four fixes for the CI failures on PR acryldev#5:

1. Rebase onto upstream/main (was 11 commits behind — caused the
   "Typecheck, test, and build" failure on a test already fixed on main)

2. Add use-flakehub: false to magic-nix-cache-action (the action defaults
   to use-flakehub: true, which attempts FlakeHub OIDC auth and breaks CI
   for orgs without a FlakeHub account — root cause of the "Unable to
   authenticate to FlakeHub" error)

3. Add timeout-minutes: 20 to the build job (was missing — GitHub's
   default max is 6h, caused the aarch64-darwin job to hang)

4. Update fetchPnpmDeps hash (stale after rebase picked up new upstream
   pnpm-lock.yaml changes)
The preConfigure hook checked `if ! grep -q "nodeLinker"` and only
inserted `nodeLinker: hoisted` when the key was absent. But
pnpm-workspace.yaml already had `nodeLinker: isolated`, so the sed
never ran. The isolated linker creates a .pnpm/ virtual store with
symlinks that break when copied to the Nix store, leaving
node_modules/ with only 3 entries (the workspace packages) and no
registry dependencies like @deepseek-ai/dsh-llm.

Replace the value when the key exists, instead of only inserting when
missing. After this fix, node_modules/ has 648 packages and all four
outputs (default, acryl, prebuilt, acryl-desktop) pass smoke tests.
The prebuilt release tarball bundles both glibc-linked and musl-linked
native koffi addons (musl_x64/koffi.node alongside linux_x64/koffi.node).
autoPatchelfHook was only finding glibc (stdenv.cc.cc.lib), so it failed
with "could not satisfy dependency libc.musl-x86_64.so.1" on Linux.

Add pkgs.musl to buildInputs so autoPatchelf can patch both variants.
The magic-nix-cache v14 static binary for arm64-darwin fails on the
macos-14 runner with:
  dyld: Symbol not found: __ZNSt13exception_ptr31__from_native_exception_pointerEPv
  Expected in: /usr/lib/libc++.1.dylib

This is a DeterminateSystems binary incompatibility — the binary was
built against a newer libc++ than the runner ships. The build itself
never starts; the job hangs for 20 minutes then gets cancelled.

Make the cache action Linux-only. Darwin builds work without it, just
slower (no cache acceleration). The flake and builds are unaffected.
@levonk
levonk force-pushed the feature/nix-flake-support branch from 19fa777 to b3309f3 Compare September 9, 2026 23:31
@levonk

levonk commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

Closing as duplicate — this branch is already submitted upstream as PR acryldev#5 in acryldev/acryl, which tracks the same feature/nix-flake-support branch from this fork.

@levonk levonk closed this Sep 9, 2026
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.

1 participant