Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,8 @@ jobs:
- name: Select pinned Rust
shell: pwsh
run: |
$pins = @(Get-ChildItem bin/.rust-*.pkg)
if ($pins.Count -ne 1) { throw "Expected exactly one repository Rust pin" }
$version = $pins[0].Name -replace '^\.rust-(.*)\.pkg$', '$1'
$version = (Select-String -Path rust-toolchain.toml -Pattern '^channel = "(.+)"$').Matches.Groups[1].Value
if (!$version) { throw "Expected a rust-toolchain.toml channel" }
rustup toolchain install $version --profile minimal --component clippy
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
"RUSTUP_TOOLCHAIN=$version" >> $env:GITHUB_ENV
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,15 @@ jobs:
id: pins
shell: pwsh
run: |
foreach ($tool in @('rust', 'node', 'pnpm')) {
foreach ($tool in @('node', 'pnpm')) {
$pins = @(Get-ChildItem "bin/.$tool-*.pkg")
if ($pins.Count -ne 1) { throw "Expected one $tool pin" }
$version = $pins[0].Name -replace "^\.$tool-(.*)\.pkg$", '$1'
"$tool=$version" >> $env:GITHUB_OUTPUT
}
$rust = (Select-String -Path rust-toolchain.toml -Pattern '^channel = "(.+)"$').Matches.Groups[1].Value
if (!$rust) { throw "Expected a rust-toolchain.toml channel" }
"rust=$rust" >> $env:GITHUB_OUTPUT
- name: Select pinned Rust
shell: pwsh
env:
Expand Down
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ scripts/bootstrap-worktree.sh /absolute/path/to/source/checkout

Do not start development before bootstrap completes. The script copies the
git-ignored `.env.local` without overwriting an existing target, then uses that
worktree's Hermit proxy to run `bin/pnpm install --frozen-lockfile`. Do not copy
worktree's Hermit proxies to run `bin/rustup toolchain install` and
`bin/pnpm install --frozen-lockfile`. Do not copy
other ignored paths: Keychain credentials and pnpm's package cache are
machine-shared, while dependencies and build output are regenerated. Git hooks
need no per-worktree setup; see [Git hooks](docs/contributing.md#git-hooks).
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion bin/cargo
2 changes: 1 addition & 1 deletion bin/cargo-clippy
2 changes: 1 addition & 1 deletion bin/cargo-fmt
1 change: 1 addition & 0 deletions bin/cargo-miri
2 changes: 1 addition & 1 deletion bin/clippy-driver
1 change: 1 addition & 0 deletions bin/rls
2 changes: 1 addition & 1 deletion bin/rust-analyzer
2 changes: 1 addition & 1 deletion bin/rust-gdb
2 changes: 1 addition & 1 deletion bin/rust-gdbgui
2 changes: 1 addition & 1 deletion bin/rust-lldb
2 changes: 1 addition & 1 deletion bin/rustc
2 changes: 1 addition & 1 deletion bin/rustdoc
2 changes: 1 addition & 1 deletion bin/rustfmt
1 change: 1 addition & 0 deletions bin/rustup
21 changes: 16 additions & 5 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Contribution workflow

The repository pins just 1.58.0, Node.js 24.18.0, pnpm 11.8.0, Lefthook 2.2.2,
and Rust 1.98.1
(including Cargo, rustfmt, and Clippy) with [Hermit](https://cashapp.github.io/hermit/).
and rustup with [Hermit](https://cashapp.github.io/hermit/). `rust-toolchain.toml`
pins Rust 1.98.1 (including Cargo, rustfmt, and Clippy), which rustup installs
under the machine-shared `~/.rustup`.
No global tool installation is required: `bin/hermit` bootstraps Hermit and tools
are downloaded on first use. Desktop development still requires the
[Tauri platform prerequisites](https://v2.tauri.app/start/prerequisites/).
Expand All @@ -11,9 +12,18 @@ From the repository root:

```sh
source bin/activate-hermit # bash/zsh; fish: source bin/activate-hermit.fish
rustup toolchain install
just --list
```

Run `rustup toolchain install` after cloning and after `rust-toolchain.toml`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Optional: the bootstrap install only covers new worktrees. Existing checkouts that pull this get an implicit install on the first proxy call, so an editor plus a terminal can still hit the concurrent-install failure described here. Reproduced: bin/rustup --version silently added rust-analyzer to an existing 1.98.1. An "after pulling this, run bin/rustup toolchain install once" note at merge is probably enough. A hook would be overkill.

changes, before an editor or parallel commands start the Rust proxies. rustup
does not serialize installs, so concurrent first use can leave the toolchain
missing a component's binaries while rustup reports it installed (for example,
`cargo clippy` fails although `rustup component add clippy` says it is up to
date). To repair it, reinstall the toolchain:
`rustup toolchain uninstall 1.98.1 && rustup toolchain install`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: the hardcoded 1.98.1 goes stale on the next bump. rustup toolchain uninstall "$(rustup show active-toolchain | cut -d' ' -f1)" or a "the pinned version" phrasing would avoid that.


Without activation, use `bin/just`, `bin/pnpm`, or `bin/cargo` from the root;
these proxies supply the pinned environment to child commands too. For example,
`bin/just web` needs no shell setup. With activation, commands also work from
Expand Down Expand Up @@ -171,8 +181,9 @@ scripts/bootstrap-worktree.sh /absolute/path/to/source/checkout
```

The idempotent script copies the source checkout's git-ignored `.env.local`
without overwriting an existing target, then uses the new worktree's Hermit proxy
to run `bin/pnpm install --frozen-lockfile`. It rejects checkouts from another
without overwriting an existing target, then uses the new worktree's Hermit
proxies to run `bin/rustup toolchain install` and
`bin/pnpm install --frozen-lockfile`. It rejects checkouts from another
repository. Keychain credentials and pnpm's package cache remain machine-shared;
do not copy private keys, `node_modules`, build output, `.npmrc`, or other ignored
files. Git hooks need no per-worktree step; see [Git hooks](#git-hooks).
Expand Down Expand Up @@ -240,7 +251,7 @@ Buzz library are described in [Agents](agents.md#community-inventory).

## Running the app

Hermit pins just, Node.js 24, pnpm 11.8.0, and Rust in `bin/`; no global tool
Hermit pins just, Node.js 24, pnpm 11.8.0, and rustup in `bin/`; no global tool
installation is needed. From the repository root, activate the pinned environment:

```sh
Expand Down
4 changes: 4 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "1.98.1"
profile = "minimal"
components = ["clippy", "rustfmt", "rust-analyzer"]
Comment thread
matt2e marked this conversation as resolved.
4 changes: 4 additions & 0 deletions scripts/bootstrap-worktree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ else
echo "No .env.local to copy from $source"
fi

# Install the pinned toolchain before editors or parallel commands use the Rust
# proxies: concurrent first-use installs into the shared ~/.rustup can corrupt it.
(cd "$target" && bin/rustup toolchain install)

"$target/bin/pnpm" install --dir "$target" --frozen-lockfile
2 changes: 2 additions & 0 deletions tests/integration/hooks.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ function fixture(t, { install = true } = {}) {
"package.json",
"lefthook.yml",
"justfile",
// rustup selects the pinned toolchain from the working directory.
"rust-toolchain.toml",
"scripts",
...biomePlugins.map((plugin) => path.normalize(plugin)),
];
Expand Down
Loading