Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e1eed9b
pkg: add zig packages for nix formats
Uzaaft Sep 28, 2026
96f72b8
core: add libhelios c abi and rust bindings
Uzaaft Sep 28, 2026
6a1317a
server: add helios-server
Uzaaft Sep 28, 2026
4fb8dd9
cli: add helios cli and end-to-end test
Uzaaft Sep 28, 2026
81aecb5
bench: compare pkg against reference libraries and nix
Uzaaft Sep 28, 2026
8fed9f9
build: replace the worker and pnpm workspace with cargo
Uzaaft Sep 28, 2026
439069e
docs: describe the self-hosted deployment
Uzaaft Sep 28, 2026
3861854
core: export sha256, hmac and randomness
Uzaaft Sep 28, 2026
1a72024
build: add sqlite to the dev shell and package
Uzaaft Sep 28, 2026
210aa56
server: cut the dependency tree from 116 to 64 crates
Uzaaft Sep 28, 2026
3b905f0
cli: replace reqwest with a small hyper client
Uzaaft Sep 28, 2026
3cab8b1
docs: document logging and the dependency policy
Uzaaft Sep 28, 2026
3bc251e
nix: add a nixos module for the server
Uzaaft Sep 28, 2026
a5a0984
docs: document the nixos module
Uzaaft Sep 28, 2026
5ea7885
server: add a maintenance api on a unix socket
Uzaaft Sep 28, 2026
a4a89b7
server: report nar bytes awaiting gc in stats
Uzaaft Sep 28, 2026
b2152ed
daemon: add helios-daemon for cache maintenance
Uzaaft Sep 28, 2026
0b0a7de
cli: add watch-store to push paths as they are built
Uzaaft Sep 28, 2026
8e8f99e
nix: run the maintenance daemon and watch-store from the module
Uzaaft Sep 28, 2026
cd9981c
docs: document the daemon and watch-store
Uzaaft Sep 28, 2026
c0d9800
core: generate nix signing keys
Uzaaft Sep 28, 2026
b79bf7c
server: add generate-secrets for first-run setup
Uzaaft Sep 28, 2026
d027fc0
nix: add an oci image with the server and daemon
Uzaaft Sep 28, 2026
a758933
docs: document the docker image
Uzaaft Sep 28, 2026
f116901
build: format rust with a checked-in rustfmt config
Uzaaft Sep 28, 2026
c167522
nix: wait for the new admin socket on container restart
Uzaaft Sep 28, 2026
ba5199f
ci: test with nix and publish the image to ghcr
Uzaaft Sep 28, 2026
82bb81f
server: say why a token is refused
Uzaaft Sep 28, 2026
587ad0a
cli: create read-only tokens by default
Uzaaft Sep 28, 2026
a9de8fd
log: move the binaries to tracing
Uzaaft Sep 28, 2026
eeb8b26
push: upload large NARs in resumable chunks
Uzaaft Sep 28, 2026
1f3859f
cli: add helios use to configure nix for a cache
Uzaaft Sep 28, 2026
493ef6f
nix: declare caches in the module
Uzaaft Sep 28, 2026
cc8a952
gc: let pins keep paths and their closures
Uzaaft Sep 28, 2026
6ca2690
core: export detached signing
Uzaaft Sep 28, 2026
367fa1e
push: publish build traces for content-addressed derivations
Uzaaft Sep 28, 2026
4b953ff
bench: name reference implementations by their packages
Uzaaft Sep 28, 2026
e0da841
pkg: reject mismatched signing keys and duplicate references
Uzaaft Sep 28, 2026
463b298
core: compress with a long window and the exact NAR size
Uzaaft Sep 28, 2026
c2c6f80
server: stop leaking private NARs and fix review findings
Uzaaft Sep 28, 2026
4a347da
cli: compress with the server defaults and harden push and use
Uzaaft Sep 28, 2026
d72f7e3
daemon: resume scrubs and keep auto-gc to what helios holds
Uzaaft Sep 28, 2026
70e5346
nix: harden the module, image and CI
Uzaaft Sep 28, 2026
bdbe87b
docs: document compression and the codec benchmark
Uzaaft Sep 28, 2026
400c4cb
nix: update nixpkgs
Uzaaft Oct 3, 2026
fbdb6dc
build: update rust dependencies
Uzaaft Oct 3, 2026
80b5261
bench: fix the fixture lookup and the push token
Uzaaft Oct 4, 2026
a414405
build: move to zig 0.17
Uzaaft Oct 4, 2026
cafe1d9
bench: escape benchmark outputs through one barrier
Uzaaft Oct 4, 2026
a2a0d64
pkg: recover zig 0.17 regressions in nix32 and flake.lock
Uzaaft Oct 4, 2026
ad9bfa4
pkg: replace api zig 0.17 deprecates
Uzaaft Oct 4, 2026
90d9cdf
bench: compare whole processes with poop
Uzaaft Oct 4, 2026
0e3180d
nix-archive: map large files a window at a time
Uzaaft Oct 4, 2026
6e72d1d
push: let the server's verification stand for the client's hashes
Uzaaft Oct 4, 2026
f2296fd
cli: give nix subprocesses no stdin
Uzaaft Oct 4, 2026
e8d1436
tests: drop redundant tests and merge the fragmented ones
Uzaaft Oct 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Tests on x86_64 and aarch64, then publishes the OCI image to
# ghcr.io/<owner>/helios on pushes to master and on v* tags.
name: ci

on:
push:
branches: [master]
tags: ["v*"]
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
test:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
system: x86_64-linux
arch: amd64
- runner: ubuntu-24.04-arm
system: aarch64-linux
arch: arm64
runs-on: ${{ matrix.runner }}
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: DeterminateSystems/nix-installer-action@3138316df39ed29be04236d7ffc686fa525866aa # v23
with:
# Upstream Nix, as users of the module and image run.
determinate: false
extra-conf: |
system-features = nixos-test benchmark big-parallel kvm

- name: Format
run: nix develop -c cargo fmt --check
- name: Clippy
run: nix develop -c cargo clippy --release --all-targets -- -D warnings
- name: Rust tests
run: nix develop -c cargo test --release
- name: Zig tests
run: nix develop -c ./scripts/test-zig.sh
- name: End to end
run: nix develop -c sh -c 'cargo build --release && ./scripts/e2e.sh'

# The NixOS and Docker VM tests need KVM, which only the x86_64
# runners have.
- name: Enable KVM
if: matrix.system == 'x86_64-linux'
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Nix checks
if: matrix.system == 'x86_64-linux'
run: nix flake check -L
- name: Nix build
if: matrix.system != 'x86_64-linux'
run: nix build -L .#checks.${{ matrix.system }}.package .#docker

# Builds and pushes each architecture's image. Kept apart from the tests,
# which run pull request code, so only pushes ever hold a write token.
push:
if: github.event_name == 'push'
needs: test
strategy:
matrix:
include:
- runner: ubuntu-24.04
arch: amd64
- runner: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: DeterminateSystems/nix-installer-action@3138316df39ed29be04236d7ffc686fa525866aa # v23
with:
determinate: false

- name: Push image
env:
ARCH: ${{ matrix.arch }}
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
version=$(nix eval --raw .#helios.version)
if [[ "$GITHUB_REF_TYPE" == tag && "$GITHUB_REF_NAME" != "v$version" ]]; then
echo "tag $GITHUB_REF_NAME does not match package version $version" >&2
exit 1
fi
image="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/helios"
nix run --inputs-from . nixpkgs#skopeo -- copy \
--dest-creds "$GITHUB_ACTOR:$TOKEN" \
"docker-archive:$(nix build --print-out-paths .#docker)" \
"docker://$image:sha-${GITHUB_SHA::12}-$ARCH"

# Joins the per-architecture images into one multi-arch tag.
image:
if: github.event_name == 'push'
needs: push
runs-on: ubuntu-24.04
permissions:
packages: write
steps:
- name: Publish manifest
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "$TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin
image="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/helios"
sha="sha-${GITHUB_SHA::12}"
tags=(-t "$image:$sha")
if [[ "$GITHUB_REF_TYPE" == tag ]]; then
tags+=(-t "$image:${GITHUB_REF_NAME#v}" -t "$image:latest")
else
tags+=(-t "$image:$GITHUB_REF_NAME")
fi
docker buildx imagetools create "${tags[@]}" "$image:$sha-amd64" "$image:$sha-arm64"
21 changes: 15 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
node_modules/
.pnpm-store/
.wrangler/
coverage/
dist/
*.log
.DS_Store
*.log
result
result-*

# Rust
/target
/bench/flake-lock-rs/target

# Zig
.zig-cache/
zig-out/

# Benchmark output (bench/*.sh, perf, poop): keep results out of the tree
/bench/**/*.txt
*.tsv
perf.data*
75 changes: 58 additions & 17 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,72 @@
# Helios

This repository is a `pnpm` workspace for Cloudflare-native services.
A self-hosted Nix binary cache: Rust server and CLI over a Zig core.

## Workspace Layout

- `workers/*`: deployable Cloudflare Workers
- `apps/*`: operator or end-user applications that sit beside Workers
- `packages/*`: shared code used by workers or apps
- `pkg/*`: Zig packages for Nix formats and the NAR pipeline, one concern
each. Each builds and tests on its own (`zig build test`).
- `core/`: libhelios, the C ABI over `pkg/*`, compiled to a static library
by `crates/helios-core/build.rs`. `core/include/helios.h` is the contract.
- `crates/helios-core`: safe Rust bindings to libhelios.
- `crates/helios-server`, `crates/helios-cli`, `crates/helios-daemon`: the
binaries. `crates/helios-log` sets up their logging. The daemon drives
the server over its maintenance socket and never writes the database
itself.
- `nix/`: the NixOS module (`services.helios`), the OCI image, and their VM
tests.
- `bench/`: comparisons against the Haskell Nix libraries, the Rust
nix-flake-lock crate and Nix C++. Not part of the Cargo workspace.

Keep deployable runtime code inside `workers/`. Move shared protocol, parsing, and storage helpers into `packages/` only after they are reused.
Put Nix format logic in a `pkg/*` package and expose it through
`core/src/root.zig` only when Rust needs it. Keep calls across the C ABI
coarse, such as a whole NAR or narinfo per call.

## Tooling

- Use `pnpm`, not `npm`, for dependency management and scripts.
- Do not commit `package-lock.json` files.
- If `pnpm` or `wrangler` are missing locally, use `nix shell nixpkgs#nodejs nixpkgs#pnpm nixpkgs#wrangler`.
- Run workspace commands from the repository root unless a package-specific command is clearer.
- Use `nix develop` for zig 0.17, cargo, zstd and pkg-config.
- Zig 0.17 APIs changed a lot; check `zig env` for the std source rather
than relying on older examples.
- System libraries: zstd and sqlite (pkg-config).
- `HELIOS_ZIG_CPU` sets libhelios's `-Dcpu` (default `native`; the Nix
package uses `baseline`).

## Cloudflare Rules
## Dependencies

- Before changing Workers, R2, D1, Durable Objects, Queues, or platform limits, fetch current Cloudflare docs.
- Prefer platform-native APIs such as `fetch`, Web Streams, and Web Crypto.
- Do not enable `nodejs_compat` unless a concrete dependency requires it.
- After changing a worker's bindings in `wrangler.jsonc`, run that package's `cf-typegen` script.
Keep the dependency tree small; every crate is build time, audit surface and
supply-chain risk. Before adding one, check whether libhelios, std or a few
dozen lines cover it, and disable default features. Deliberately absent:
reqwest (and `url`/`idna`), aws-lc-rs, parking_lot, uuid,
hmac/sha2 (libhelios provides SHA-256, HMAC and randomness) and mimalloc
(measured: no gain here).

Logging is `tracing` with `tracing-subscriber` (fmt, ansi and json only; no
`env-filter`, whose regex engine `Targets` makes unnecessary) and
`tracing-journald`, set up once in `crates/helios-log`.

## Performance Rules

- Measure before and after; `bench/run.sh` and `bench/flake-lock.sh`
compare against the reference implementations on the same corpus.
`bench/poop.sh` compares whole processes with poop (wall time, peak RSS,
cycles, cache and branch misses), including `helios push` against
`nix copy`. Benchmark output stays out of the tree.
- Keep the narinfo read path free of SQLite on misses and of per-request
signing.
- Keep a scalar reference for every SIMD routine, with a test asserting the
two agree.

## Verification

- Install dependencies with `pnpm install` from the repo root.
- Run `pnpm check` before finishing substantial changes.
- For worker-only iteration, use `pnpm --filter <package> dev`.
CI (`.github/workflows/ci.yml`) runs all of this on x86_64 and aarch64
(the VM tests on x86_64 only) and publishes the image on pushes.

- `cargo fmt --check` and `cargo clippy --release --all-targets -- -D warnings`
- `cargo test --release`
- `./scripts/test-zig.sh`
- `nix build .#checks.x86_64-linux.nixos` after changing `nix/`: a VM test of
the NixOS module. `.#checks.x86_64-linux.docker` likewise for the OCI
image.
- `./scripts/e2e.sh` before finishing changes to the server, the CLI or wire
formats; it substitutes a real closure through Nix with signatures
required.
Loading