{"id":15171741,"url":"https://github.com/determinatesystems/riff","last_synced_at":"2025-10-01T06:32:04.386Z","repository":{"id":58750053,"uuid":"522585092","full_name":"DeterminateSystems/riff","owner":"DeterminateSystems","description":"Riff automatically provides external dependencies for Rust projects, with support for other languages coming soon.","archived":true,"fork":false,"pushed_at":"2023-10-10T20:12:35.000Z","size":2216,"stargazers_count":486,"open_issues_count":21,"forks_count":13,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-11-19T11:52:54.168Z","etag":null,"topics":["nix","rust"],"latest_commit_sha":null,"homepage":"https://riff.sh","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DeterminateSystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-08T14:34:53.000Z","updated_at":"2024-11-09T13:34:04.000Z","dependencies_parsed_at":"2024-01-18T02:37:13.447Z","dependency_job_id":"6ca6192b-e96c-48b4-8c7f-fbddcd9dbb6c","html_url":"https://github.com/DeterminateSystems/riff","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeterminateSystems%2Friff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeterminateSystems%2Friff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeterminateSystems%2Friff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeterminateSystems%2Friff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DeterminateSystems","download_url":"https://codeload.github.com/DeterminateSystems/riff/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234837098,"owners_count":18894537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nix","rust"],"created_at":"2024-09-27T09:03:05.302Z","updated_at":"2025-10-01T06:32:04.007Z","avatar_url":"https://github.com/DeterminateSystems.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Riff\n\n![logo-light](img/logo/riff-white.svg#gh-dark-mode-only)\n![logo-dark](img/logo/riff-black.svg#gh-light-mode-only)\n\n**Riff** is a tool that automatically provides external dependencies[^1] for\nsoftware projects. To enter a shell environment with all your project's external\ndependencies installed, run this at the project root:\n\n```shell\nriff shell\n```\n\nYou can also directly run commands with the shell environment applied but\nwithout entering the shell:\n\n```shell\nriff run cargo build\n```\n\nRiff currently supports [Rust] with support for other languages coming soon.\nIt uses the [Nix] package manager to handle dependencies but doesn't require\nyou to know or use Nix.\n\n\u003e For a video demo of Riff in action, see [below](#video-demo).\n\n## Requirements\n\nTo use Riff, you need to install these binaries on your system:\n\n- [`nix`][nix-install]\n- [`cargo`][rust-install]\n\n## Installation\n\n### Using Nix\n\nTo install Riff using Nix (make sure to have [flakes] enabled):\n\n```shell\nnix profile install github:DeterminateSystems/riff\n```\n\n### Using Homebrew\n\nTo install Riff on macOS using [Homebrew]:\n\n```shell\nbrew install DeterminateSystems/riff/riff\n```\n\n\u003e **Note**: The `riff` Homebrew formula does _not_ install [Nix] or [Cargo].\n\n### Using cURL\n\nYou can find instructions for installing Riff using cURL on the\n[releases page][releases].\n\n### GitHub Actions\n\nYou can install Riff in your [GitHub Actions][actions] pipelines using\n[`install-riff-action`][install-riff-action]. Here's an example configuration:\n\n```yaml\nsteps:\n  - uses: actions/checkout@v3\n  - name: Install Nix\n    uses: DeterminateSystems/nix-installer-action@main\n  - name: Install Rust\n    uses: actions-rs/toolchain@v1\n    with:\n      toolchain: stable\n  - name: Install Riff\n    uses: DeterminateSystems/install-riff-action@v1\n  - name: Build Rust app\n    run: riff run cargo build -- --release\n```\n\n### Prompt Customization\n\nYou can customize your shell's prompt to display when you're in a Riff shell\nenvironment by relying on the `$IN_NIX_SHELL` environment variable.\n\nIf you use [Starship], you get this information for free because the [Nix shell\nmodule] is enabled by default. However, if you want to add this to your shell\nprompt yourself, you can do that by adding `$name` to your prompt when\n`$IN_NIX_SHELL` is set.\n\nIn Bash, this might look something like:\n\n```bash\nexport PS1=\"$PWD \\${IN_NIX_SHELL:+\\$name }\\$ \"\n```\n\n\u003e Note the escaping of `\\${IN_NIX_SHELL}` and `\\$name`. This prevents Bash from\n\u003e taking the current values of those environment variables and using them even\n\u003e after one of them has changed.\n\nIn Zsh, it might look similar to:\n\n```zsh\nexport PROMPT=\"$PWD \\${IN_NIX_SHELL:+\\$name }\\$ \"\n```\n\nAnd in Fish, you might use something like:\n\n```fish\nfunction fish_prompt\n    echo -n \"$PWD \"\n    if set -q IN_NIX_SHELL\n        echo -n \"$name \"\n    end\n    echo -n \"\\$ \"\nend\n```\n\n\u003e Escaping `$name` is unnecessary here because Fish doesn't capture the value of\n\u003e `$name` until the function is run when your prompt is displayed.\n\nThe idea extends to any shell: if you can change the prompt and prevent it from\nevaluating the values of `$IN_NIX_SHELL` and `$name` until the prompt is\ndisplayed, you can add this information to your prompt.\n\n## What Riff provides\n\nMost programming languages use language-specific package managers to handle\ndependencies, such as [Cargo] for the [Rust] language. But these\nlanguage-specific tools typically don't handle dependencies written in other\nlanguages very well. They expect you to install those dependencies using some\nother tool and fail in mysterious ways when they're missing. Here's an\nexample error from trying to build the [`octocrab`][octocrab] crate without\n[OpenSSL] installed:\n\n```shell\n--- stderr\nthread 'main' panicked at '\n\nCould not find directory of OpenSSL installation, and this `-sys` crate cannot\nproceed without this knowledge. If OpenSSL is installed and this crate had\ntrouble finding it,  you can set the `OPENSSL_DIR` environment variable for the\ncompilation process.\n\nMake sure you also have the development packages of openssl installed.\nFor example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.\n```\n\nIn cases like this, it's up to you to install missing external dependencies,\nwhich can be laborious, error prone, and hard to reproduce.\n\nRiff enables you to bypass this problem entirely. It uses your your project's\nlanguage-specific configuration to infer which external dependencies are\nrequired and creates a shell environment with those dependencies both installed\nand properly linked. In cases where those dependencies can't be inferred, for\nexample in your [`build.rs`][build.rs] script, you can [explicitly declare\nthem](#how-to-declare-package-inputs) in your `Cargo.toml`.\n\nThese environments are _transient_ in the sense that they don't affect\nanything outside the shell; they install dependencies neither globally nor in\nyour current project, so you don't have to worry about Riff breaking anything\non your system. When you exit the Riff shell, the dependencies are gone.\n\n### Offline mode\n\nIn cases where you want to limit Riff's access to the Internet, you can run it\nin offline mode, which disables all network usage _except_ what's required by\nthe `nix develop` command (which Riff runs in the background). You can enable\noffline mode using either the `--offline` flag or the `RIFF_OFFLINE` environment\nvariable. Here are some examples:\n\n```shell\n# Via flag\nriff run --offline\n\n# Via environment variable\nRIFF_OFFLINE=true riff shell\n```\n\n## Example usage\n\nIn this example, we'll build the [Prost] project from source. Prost has an\nexternal dependency on [OpenSSL], without which commands like `cargo build`\nand `cargo run` are doomed to fail. Riff provides those dependencies\nautomatically, without you needing to install them in your regular\nenvironment. Follow these steps to see dependency inference in action:\n\n```shell\ngit clone https://github.com/tokio-rs/prost.git\ncd prost\n\n# Enter the Riff shell environment\nriff shell\n# ✓ 🦀 rust: cargo, cmake, curl, openssl, pkg-config, rustc, rustfmt, zlib\n\n# Check for the presence of openssl\nwhich openssl\n# The path should look like this:\n# /nix/store/f3xbf94zykbh6drw6wfg9hdrfgwrkck7-openssl-1.1.1q-bin/bin/openssl\n# This means that Riff is using the Nix-provided openssl\n\n# Build the project\ncargo build\n\n# Leave the shell environment\nexit\n\n# Check for openssl again\nwhich openssl\n# This should either point to an openssl executable on your PATH or fail\n```\n\n## How to declare package inputs\n\nWhile Riff does its best to infer external dependencies from your project's\ncrate dependencies, you can explicitly declare external dependencies if\nnecessary by adding a `riff` block to the `package.metadata` block in your\n`Cargo.toml`. Riff currently supports three types of inputs:\n\n- `build-inputs` are external dependencies that some crates may need to link\n  against.\n- `environment-variables` are environment variables you want to set in your dev\n  shell.\n- `runtime-inputs` are libraries you want to add to your `LD_LIBRARY_PATH` to\n  ensure that your dev shell works as expected.\n\nBoth `build-inputs` and `runtime-inputs` can be any packages available in\n[Nixpkgs]. You may find this particularly useful for [`build.rs`\nscripts][build.rs].\n\nHere's an example `Cargo.toml` with an explicitly supplied Riff configuration:\n\n```toml\n[package]\nname = \"riff-example\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[package.metadata.riff]\nbuild-inputs = [ \"openssl\" ]\nruntime-inputs = [ \"libGL\" ]\n\n[package.metadata.riff.environment-variables]\nHI = \"BYE\"\n\n# Other configuration\n```\n\nWhen you run `riff shell` in this project, Riff\n\n- adds [OpenSSL] to your build environment\n- sets the `LD_LIBRARY_PATH` environment variable to include [libGL]'s library\n  path\n- sets the `HI` environment variable to have a value of `BYE`\n\n### Target-specific dependencies\n\nIf a project has OS-, architecture-, or vendor-specific dependencies, you can\ndefine them in a `targets` block under `package.metadata.riff`. Here's an\nexample for Apple M1 (`aarch64-apple-darwin`) systems:\n\n```toml\n[package.metadata.riff.targets.aarch64-apple-darwin]\nbuild-inputs = [\n  \"darwin.apple_sdk.frameworks.CoreServices\",\n  \"darwin.apple_sdk.frameworks.Security\"\n]\n```\n\nThe Rust project maintains [a list of well-known targets][targets]\nthat you can view by running `nix run nixpkgs#rustup target list`. This\nfield can also contain custom targets, such as `riscv32imac-unknown-xous-elf`,\nalthough `riff` makes no effort to support cross compiling at this time.\n\nWhen target-specific dependencies are present, the `build-inputs` and\n`runtime-inputs` sections are _unioned_ (joined), while the target-specific\nenvironment variables _override_ default environment variables.\n\n#### macOS framework dependencies\n\nmacOS users may encounter issues with so-called \"framework\" dependencies, such\nas [`Foundation`][foundation], [`CoreServices`][coreservices], and\n[`Security`][security]. When these dependencies are missing, you may see error\nmessages like this:\n\n```\n= note: ld: framework not found CoreFoundation\n```\n\nYou can solve this by adding framework dependencies to your `build-inputs` as\n`darwin.apple_sdk.frameworks.\u003cframework\u003e`, for example\n`darwin.apple_sdk.frameworks.Security`. Here's an example `Cargo.toml`\nconfiguration that adds multiple framework dependencies:\n\n```toml\n[package.metadata.riff.targets.x86_64-apple-darwin]\nbuild-inputs = [\n  \"darwin.apple_sdk.frameworks.CoreServices\",\n  \"darwin.apple_sdk.frameworks.Security\"\n]\n\n[package.metadata.riff.targets.aarch64-apple-darwin]\nbuild-inputs = [\n  \"darwin.apple_sdk.frameworks.CoreServices\",\n  \"darwin.apple_sdk.frameworks.Security\"\n]\n```\n\n#### Riff understands dependencies transitively\n\nIf you add [Riff metadata](#how-to-declare-package-inputs) to `Cargo.toml`, this\ndoesn't just make it easier to build and run your project: it actually benefits\nconsumers of your crate as well. That's because Riff can use this metadata\ntransitively to infer which external dependencies are necessary _across the\nentire crate dependency graph_. Let's say that you release a crate called\n`make-it-pretty` that has an external dependency on [libGL] and you add that\nto your `Cargo.toml`:\n\n```toml\n[package.metadata.riff]\nruntime-inputs = [ \"libGL\" ]\n```\n\nNow let's say that another Rust dev releases a crate called `artify` that\ndepends on your `make-it-pretty` crate. If someone tries to build `artify` using\nCargo, they may receive an error if they don't have libGL installed. _But_ if\nthey use Riff to build `artify`, Riff knows to install libGL without any user\ninput.\n\nThe implication is that adding Riff metadata to your crates\u0026mdash;if they have\nexternal dependencies\u0026mdash;can benefit the Rust ecosystem more broadly.\n\n## How it works\n\nWhen you run `riff shell` in a Rust project, Riff\n\n- **reads** your [`Cargo.toml`][cargo-toml] configuration manifest to determine\n  which external dependencies your project requires and then\n- **uses** the [Nix] package manager\u0026mdash;in the background and without\n  requiring any intervention on your part\u0026mdash;to install any external\n  dependencies, such as [OpenSSL] or [Protobuf], and also sets any environment\n  variables necessary to discover those tools. Once it knows which external\n  tools are required, it\n- **builds** a custom shell environment that enables you to use commands like\n  `cargo build` and `cargo run` without encountering the missing dependency\n  errors that so often dog Rust development.\n\nThis diagram provides a basic visual description of that process:\n\n\u003c!-- Image editable at: https://miro.com/app/board/uXjVPdUOswQ=/ --\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg\n    src=\"img/riff.jpg\"\n    alt=\"Riff reads your Cargo.toml to infer external dependencies and then\n      uses Nix to build a shell environment that provides those dependencies\"\n    style=\"width:70%;\" /\u003e\n\u003c/p\u003e\n\nBecause Riff uses Nix, all of the dependencies that it installs are stored in\nyour local [Nix store], by default under `/nix/store`. For a more thorough\nbreakdown of how Riff works, see the [architecture docs][architecture].\n\n## Video demo\n\nYou can see a video demo of Riff in action here (click on the image for a\nlarger version):\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/riff-demo.gif\"\n      alt=\"Asciicast video demo of Riff with preview image\"\n      style=\"width:80%;\" /\u003e\n\u003c/p\u003e\n\nIn the video, running `cargo build` in the [Prost] project fails due to missing\nexternal dependencies. But running `riff run cargo build` succeeds because Riff\nis able to infer which external dependencies are missing and provide them in the\nbackground using Nix.\n\n## Garbage Collection\n\nOne of the disadvantages of Riff using [Nix] is that [Nix] can end up using\nsubstantial disk space. After using Riff on a few projects, you may notice the\n`/nix/store` directory grow in size. Luckily, it is relatively easy to reclaim\nthis space by running `nix-collect-garbage`. Note that garbage collection may\nclean up any Riff shells you have used, which in turn may cause your next riff\ninvocation to take slightly longer because Riff\u0026mdash;using Nix\u0026mdash;needs to\nfetch the dependencies that were cleaned up.\n\n## Direnv Integration\n\nYou can add Riff support to Direnv on a project-specific or global basis. To\nenable Riff in a project, create a `.envrc` file that contains this:\n\n```bash\n# reload when these files change\nwatch_file Cargo.toml Cargo.lock\n# add any other files you might want to trigger a riff reload\n# load the riff dev env\neval \"$(riff print-dev-env)\"\n```\n\nYou can enable Riff support globally by either adding a `use_riff` function\neither to your `~/.config/direnv/direnvrc` file or a new\n`~/.config/direnv/lib/riff.sh` file. The `use_riff` function should look\nsomething like this:\n\n```bash\nuse_riff() {\n  watch_file Cargo.toml watch_file Cargo.lock\n  eval \"$(riff print-dev-env)\"\n}\n```\n\nWith Direnv now aware of this function, you can enable Riff in any directory\nwith:\n\n```bash\necho \"use riff\" \u003e .envrc\n```\n\nWhen you run `direnv allow` you will automatically enter the Riff shell every\ntime you navigate to the project directory.\n\n## Privacy policy\n\nFor the sake of improving user experience, Riff does collect some [telemetry].\nYou can read the full privacy policy for [Determinate Systems], the\ncreators of Riff, [here][privacy].\n\nTo disable telemetry on any Riff command invocation, you can either\n\n- Use the `--disable-telemetry` flag or\n- Set the `RIFF_DISABLE_TELEMETRY` environment variable to any value except\n  `false`,`0`, or an empty string (`\"\"`).\n\nHere are some examples:\n\n```shell\n# Via flag\nriff shell --disable-telemetry\n\n# Via environment variable\nRIFF_DISABLE_TELEMETRY=true riff run cargo build\n```\n\n### Telemetry\n\nWhen you use Riff, Riff generates a random version 4 UUID for you. It\ncontains no personally identifiable information about you and is used\nto know how many people use the tool and to focus our limited research\nand development. You can delete this file at any time to create a new\nID.\n\nTo see exactly what data we send, you may run Riff as follows:\n\n```shell\n$ RUST_LOG=riff::telemetry=debug riff run echo 'Hello, Riff!'\n✓ 🦀 rust: cargo, openssl, pkg-config, rustc, rustfmt\n  2022-09-29T21:29:01.476342Z DEBUG riff::telemetry: Sent telemetry data to https://registry.riff.determinate.systems/telemetry, telemetry: Telemetry { distinct_id: Some(Secret([REDACTED riff::telemetry::DistinctId])), system_os: \"linux\", system_arch: \"x86_64\", os_release_name: Some(\"NixOS\"), os_release_version_id: Some(\"22.11\"), riff_version: \"1.0.1\", nix_version: Some(\"nix (Nix) 2.12.0pre20220928_c3c0682\"), is_tty: true, subcommand: Some(\"run\"), detected_languages: {Rust}, in_ci: false }\n    at src/telemetry.rs:129\n    in riff::telemetry::send\n    in riff::flake_generator::generate_flake_from_project_dir with project_dir: None, offline: false\n```\n\n\u003e This will also appear when running with `--debug`, accompanied by other debug logging.\n\nThe table below shows the data Riff collects in a more readable format:\n\n| Field                   | Use                                                                                                                                                                                                                                                          |\n| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `distinct_id`           | The ID of the Riff installation. More specifically, we at Determinate Systems care about our weekly active users count and this field helps us measure that.                                                                                                 |\n| `system_os`             | The operating system Riff is running on.                                                                                                                                                                                                                     |\n| `system_arch`           | The architecture Riff is running on.                                                                                                                                                                                                                         |\n| `os_release_name`       | The distribution Riff is running on. This uses the `NAME` field of `/etc/os-release` if it exists.                                                                                                                                                           |\n| `os_release_version_id` | The version of the distribution Riff is running on. This uses the `VERSION_ID` field of `/etc/os-release` if it exists.                                                                                                                                      |\n| `riff_version`          | The version of Riff being used.                                                                                                                                                                                                                              |\n| `nix_version`           | The version of Nix being used by Riff.                                                                                                                                                                                                                       |\n| `is_tty`                | Whether Riff is being run interactively.                                                                                                                                                                                                                     |\n| `subcommand`            | The subcommand Riff is executing. This only contains information about the Riff subcommand, and not any commands being run by Riff (i.e. `riff run echo 'Hello, Riff!'` will not send any telemetry including the fact that Riff ran `echo 'Hello, Riff!'`). |\n| `detected_languages`    | Which languages Riff detected in the project.                                                                                                                                                                                                                |\n| `in_ci`                 | Whether Riff is being used in CI (e.g. GitHub Actions).                                                                                                                                                                                                      |\n\n## Community\n\nIf you'd like to discuss Riff with other users, join our [Discord] (also bridged\nto a [Matrix room][matrix]).\n\n[actions]: https://github.com/features/actions\n[architecture]: ./ARCHITECTURE.md\n[build.rs]: https://doc.rust-lang.org/cargo/reference/build-scripts.html\n[cargo]: https://doc.rust-lang.org/cargo\n[cargo-toml]: https://doc.rust-lang.org/cargo/reference/manifest.html\n[coreservices]: https://developer.apple.com/documentation/coreservices\n[determinate systems]: https://determinate.systems\n[discord]: https://discord.gg/urAzkgf7YM\n[flakes]: https://nixos.wiki/wiki/Flakes\n[foundation]: https://developer.apple.com/documentation/foundation\n[homebrew]: https://brew.sh\n[install-riff-action]: https://github.com/marketplace/actions/install-riff\n[libgl]: https://dri.freedesktop.org/wiki/libGL\n[matrix]: https://matrix.to/#/#riff:matrix.org\n[nix]: https://nixos.org/nix\n[nix-install]: https://nixos.org/download.html\n[nixpkgs]: https://search.nixos.org/packages\n[nix shell module]: https://starship.rs/config/#nix-shell\n[nix store]: https://nixos.wiki/wiki/Nix_package_manager\n[octocrab]: https://github.com/XAMPPRocky/octocrab\n[openssl]: https://openssl.org\n[privacy]: https://determinate.systems/privacy\n[prost]: https://github.com/tokio-rs/prost\n[protobuf]: https://developers.google.com/protocol-buffers\n[releases]: https://github.com/DeterminateSystems/riff/releases\n[rust]: https://rust-lang.org\n[rust-install]: https://www.rust-lang.org/tools/install\n[security]: https://developer.apple.com/documentation/security\n[starship]: https://starship.rs/\n[targets]: https://doc.rust-lang.org/nightly/rustc/platform-support.html\n[telemetry]: ./src/telemetry.rs\n\n[^1]:\n    We define **external** dependencies as those that are written in another\n    language and thus can't be installed using the same language-specific package\n    manager that you use to build your code.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeterminatesystems%2Friff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeterminatesystems%2Friff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeterminatesystems%2Friff/lists"}