1 ---
2 name: forked-dependencies
3 description: The complete inventory of forked crates and [patch.crates-io] overrides that the onde stack depends on — mistral.rs, candle, sysctl, mio, tqdm, core2 — including the retired ones. Explains what each fork is for, where it is consumed, how the git-vs-published two-tier model works, and how to update or add one. Apply whenever a build fails on a missing/incompatible crate for an Apple or Android target, when bumping the mistral.rs or candle fork, or when adding a new patched dependency.
4 allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5 user-invocable: true
6 ---
7
8 # Skill: Forked Dependencies
9
10 The onde stack pulls several crates from forks instead of crates.io. They exist
11 for three reasons: **platform support** the upstream crate lacks (watchOS,
12 visionOS), **unreleased APIs** a dependency needs before upstream cuts a release
13 (candle), and **registry constraints** (`cargo publish` rejects git deps, so the
14 mistral.rs fork is republished under `onde-*` names).
15
16 This skill is the single source of truth for every fork and patch. When a build
17 breaks on a missing symbol or unsupported target, or you are bumping a fork,
18 start here.
19
20 ---
21
22 ## The two-tier consumption model (read this first)
23
24 There are two distinct ways the same dependency tree gets built, and they
25 resolve forks differently. Almost every confusing bug in this area comes from
26 mixing them up.
27
28 1. **Building the mistral.rs fork from source** (its own CI, or `onde` local dev
29 with the git override uncommented). Here the fork's `Cargo.toml` git deps and
30 `[patch.crates-io]` entries apply directly.
31
32 2. **Publishing to crates.io** (`cargo publish` of the `onde-mistralrs-*`
33 crates). **`cargo publish` strips every `git =` field and the entire
34 `[patch.crates-io]` table.** Published crates fall back to the `version = "..."`
35 registry requirement on each dep. So a git-only dep is invisible to anyone
36 installing from crates.io.
37
38 3. **onde consuming the published crates.** onde depends on the registry
39 `onde-mistralrs-*` crates, so it gets the *registry-resolved* tree — the
40 stripped-down one from step 2, not the fork's git tree. onde then re-applies
41 whatever patches it still needs in **its own** `[patch.crates-io]`. Those
42 apply to onde's from-source CI builds (Swift XCFramework, Android/Kotlin,
43 the `cargo check` matrix) but are themselves stripped when onde publishes to
44 crates.io.
45
46 **Consequence that used to bite (now fixed — kept as the canonical example):**
47 originally the `tqdm` fork bumped crossterm to 0.29 (which pulls mio 1.x, which
48 supports visionOS) but was a *git* dep of mistral.rs, so it was stripped on
49 publish. onde therefore resolved crates.io `tqdm 0.8.0` → `crossterm 0.25` →
50 `mio 0.8.11`, which does *not* support visionOS — so onde needed its own `mio`
51 visionOS patch even though the tqdm fork "already fixed" crossterm upstream of
52 it.
53
54 The fix that removed the whole problem was to make the crossterm-0.29 tqdm a
55 **registry** dep of the mistral.rs fork rather than a git one, since a registry
56 dep survives publish: onde's resolved tree then gets `crossterm 0.29` → `mio
57 1.x` and the `mio 0.8.11` line disappears entirely. That shipped first as the
58 stopgap fork crate `onde-tqdm` (in `onde-mistralrs-*` 0.9.3), which let onde
59 delete its `[patch.crates-io] mio` entry and retire the `mio` fork.
60
61 Upstream has since merged the crossterm bump (mrlazy1708/tqdm#28) and released
62 it as **`tqdm 0.8.1`**, so the fork crate is no longer needed: the mistral.rs
63 fork depends on plain `tqdm = "0.8.1"` and **`onde-tqdm` is retired**. See the
64 tqdm and mio entries.
65
66 ---
67
68 ## Inventory
69
70 | Crate | Fork / source | Ref | Purpose | Consumed where |
71 |-------|---------------|-----|---------|----------------|
72 | mistral.rs (12 crates) | `setoelkahfi/mistral.rs` | branch `fix/all-platform-fixes` | All-platform fixes; **published** as `onde-mistralrs-*` | onde deps (registry) |
73 | candle-core, candle-nn | `setoelkahfi/candle` | branch `onde/candle-0.11.0-27f20fea` (rev `27f20fea`) | Post-0.11.0 candle APIs; **published** as `onde-candle-{core,nn}` | mistral.rs fork deps (registry) |
74 | tqdm | *none — upstream* | crates.io `tqdm 0.8.1` | Crossterm 0.29 (→ mio 1.x) is upstream as of 0.8.1 | mistral.rs fork dep (registry) |
75 | sysctl | `setoelkahfi/sysctl-rs` | branch `feature/watchos` | watchOS (`target_os = "watchos"`) support | `[patch.crates-io]` in onde **and** mistral.rs fork |
76 | mio | `setoelkahfi/mio` | branch `feature/visionos` | visionOS support for the `mio 0.8.11` line | **RETIRED** — patch removed from onde once it consumed onde-mistralrs 0.9.3 (crossterm 0.29 → mio 1.x). Fork kept for history/upstream PR. |
77
78 > **Retired:** `onde-tqdm` (`setoelkahfi/tqdm`, branch `release/onde-tqdm`,
79 > published 0.8.1/0.8.2) — the stopgap republish of the crossterm-0.29 tqdm
80 > fork. Upstream merged the bump and released `tqdm 0.8.1`, so the mistral.rs
81 > fork now depends on upstream directly. See the tqdm entry.
82
83 > **Retired:** `core2` (`bbqsrc/core2` rev `545e84bc`) — was a `[patch.crates-io]`
84 > workaround for the yanked `core2 0.4.0`; removed from the mistral.rs fork after
85 > `bitstream-io` 4.x dropped `core2`. No longer present.
86
87 ---
88
89 ## Per-fork detail
90
91 ### mistral.rs → `onde-mistralrs-*`
92
93 - **Fork:** `setoelkahfi/mistral.rs`, branch `fix/all-platform-fixes`.
94 - **Why:** carries fixes upstream hasn't merged (iOS 32-bit memory limits,
95 watchOS/visionOS Metal compile, Android 32-bit const overflows, HF cache
96 seeding, metallib link flags, and more).
97 - **Published as:** `onde-mistralrs`, `-core`, `-quant`, `-paged-attn`,
98 `-flash-attn`, `-metal-compile`, `-code-exec`, `-sandbox`, `-macros`,
99 `-vision`, `-audio`, `-mcp`. The rename is a `package = "onde-..."` override on
100 each workspace dep entry, so Rust source still `use`s `mistralrs_*` unchanged.
101 - **Publishing + bump flow:** see [[sdk-regressions]] (the 12-crate publish
102 order, the candle Step 0, and the tqdm/core2 publish-verification snags).
103
104 ### candle → `onde-candle-{core,nn}`
105
106 - **Fork:** `setoelkahfi/candle`, branch `onde/candle-<ver>-<rev>` (currently
107 `onde/candle-0.11.0-27f20fea`).
108 - **Why:** mistral.rs pins a candle git rev past the latest release for APIs no
109 published candle has (`QTensor::indexed_gemv`, `gemv_fused_shared_lhs`,
110 `BarrierPool::execute_chunked`). Publishing the `onde-mistralrs-*` crates
111 fails verification (E0080/E0599) if their candle dep resolves to the released
112 crate, so the pinned rev is republished under `onde-candle-*`.
113 - **Only the diverged crates are renamed.** At the 0.11.0 rev only `candle-core`
114 and `candle-nn` differ from the release; `candle-metal-kernels` and
115 `candle-flash-attn-v3` are byte-identical, so the mistral.rs fork points those
116 at the official `0.11.0` crates. `candle-nn` must be republished whenever
117 `candle-core` is (even if unchanged) or the official `candle-nn` drags the
118 official `candle-core` back into the graph → two `candle-core` crates → type
119 mismatch.
120
121 ### sysctl → watchOS
122
123 - **Fork:** `setoelkahfi/sysctl-rs`, branch `feature/watchos`. Upstream PR:
124 johalun/sysctl-rs#74.
125 - **Why:** upstream sysctl has no `target_os = "watchos"` support.
126 - **Applied in:** `[patch.crates-io]` in **both** onde and the mistral.rs fork
127 (each workspace root that builds for watchOS needs its own patch entry).
128
129 ### mio → visionOS (RETIRED)
130
131 - **Status:** the onde `[patch.crates-io] mio` entry has been **removed**. onde
132 now consumes `onde-mistralrs 0.9.3`, whose `onde-tqdm` dep pulls `crossterm
133 0.29 → mio 1.x`, so `mio 0.8.11` is gone from onde's tree. The fork below is
134 kept only for history and a possible upstream PR; it is no longer wired into
135 any build.
136 - **Fork:** `setoelkahfi/mio`, branch `feature/visionos` (commit `683fca8`).
137 Based on `mio 0.8.11`. This is the **official GitHub fork** of tokio-rs/mio
138 (in tokio's fork network, so it can open upstream PRs). An earlier standalone
139 clone that carried this branch was renamed to `setoelkahfi/mio-patch` and
140 deleted; the branch now lives on the real fork.
141 - **Why:** `mio 0.8.11` hits `compile_error!("unsupported target for
142 mio::unix::pipe")` on visionOS, and its Apple cfg gates (kqueue `Filter`/
143 `Flags` type aliases, `net.rs` `sin_len`/`sin6_len`, `tcp.rs` accept path,
144 `uds/listener.rs` `accept4`/`SOCK_NONBLOCK`) omit visionos, breaking the Swift
145 XCFramework build and the visionOS CI checks. The fork adds
146 `target_os = "visionos"` to every cfg gate that already lists `tvos`/`watchos`.
147 tokio's `mio 1.x` already supports visionOS, so **only the 0.8.x line** needs it.
148 - **Where 0.8.11 came from:** `tqdm → crossterm 0.25 → mio 0.8.11`, and
149 `signal-hook-mio → crossterm`. Not from tokio (that uses `mio 1.2.2`).
150 - **Applied in:** *(historical)* was `[patch.crates-io]` in onde. The fork's
151 version (`0.8.11`) stayed semver-compatible with the `^0.8` requirement it
152 replaced; it did not touch tokio's `^1`.
153 - **How it was retired (the real fix):** the `onde-tqdm` publish (below) removed
154 the `mio 0.8.11` line from onde's registry-resolved tree entirely. Verified:
155 with onde consuming the onde-tqdm-carrying `onde-mistralrs 0.9.3` crates, onde's
156 lockfile resolves `mio 1.2.2` only — no 0.8.11 — and both visionOS targets
157 (`aarch64-apple-visionos{,-sim}`) `cargo +nightly check -Z build-std` pass with
158 the `mio` patch deleted.
159
160 ### tqdm → upstream (`onde-tqdm` RETIRED)
161
162 - **Status:** no fork. `setoelkahfi/tqdm` branch `deps/bump-crossterm` was
163 merged upstream as mrlazy1708/tqdm#28 and released as **`tqdm 0.8.1`**, which
164 carries the crossterm 0.29 bump (→ mio 1.x) that the whole `mio 0.8.11`
165 visionOS problem hinged on.
166 - **Consumed in:** the mistral.rs fork's `[workspace.dependencies]` as plain
167 `tqdm = "0.8.1"`. It must stay a **registry** dep — `cargo publish` strips git
168 deps, so a git tqdm would never reach onde.
169 - **The `onde-tqdm` stopgap (retired):** branch `release/onde-tqdm` set
170 `package = "onde-tqdm"` (lib name stayed `tqdm`, so `use tqdm::…` and doctests
171 were unchanged) and was published as `onde-tqdm` 0.8.1/0.8.2 — the same rename
172 trick as `onde-mistralrs-*` and `onde-candle-*`, needed only because upstream
173 hadn't released the bump yet. Its source was byte-identical to upstream
174 `tqdm 0.8.1` apart from the package metadata, so the swap back is a drop-in.
175 - **Which release drops it:** `onde-mistralrs-core` 0.9.2 used plain
176 `tqdm ^0.8.0` (crossterm 0.25), 0.9.3 used `onde-tqdm 0.8.2`, and the next
177 publish (0.9.4) goes back to upstream `tqdm 0.8.1`. The published `onde-tqdm`
178 versions stay up so 0.9.3 keeps resolving; don't yank them.
179
180 ### core2 → removed
181
182 - **Was:** `bbqsrc/core2` rev `545e84bc`, a `[patch.crates-io]` workaround for
183 the yanked `core2 0.4.0` (pulled via `bitstream-io → rav1e → ravif → image`).
184 - **Status:** **deleted** from the mistral.rs fork. `bitstream-io` 4.x moved off
185 `core2` (to `no_std_io2`), so nothing pulls it. Removed in the same commit that
186 wired `onde-tqdm` and bumped to 0.9.3.
187
188 ---
189
190 ## Operational gotchas (hit these during the 1.2.1 release)
191
192 - **A patched fork must be pushed to GitHub before the patch works in CI.** The
193 `mio` fork existed only locally; the patch URL 404'd until it was pushed to
194 `setoelkahfi/mio`. Verify with `git ls-remote <url> <branch>` before relying
195 on a patch.
196 - **Shallow clones cannot be pushed** (`remote unpack failed: index-pack
197 failed`). If a fork was cloned shallow, `git fetch --unshallow <upstream>`
198 first, then push.
199 - **Local fork fetches need `CARGO_NET_GIT_FETCH_WITH_CLI=true`.** This machine
200 rewrites GitHub URLs to SSH aliases; cargo's built-in fetcher can't auth, so
201 export that var (or run the `cargo update` that pulls the fork with it). CI
202 fetches public https forks fine without it — same as the long-standing sysctl
203 patch.
204 - **`[patch.crates-io]` version must be semver-compatible** with the requirement
205 it replaces. A `0.8.11` fork replaces `^0.8`, not a `^1` requirement of the
206 same crate — which is how the `mio` patch touches only the crossterm line and
207 leaves tokio's `mio 1.x` alone.
208 - **Forks are public** (mio, sysctl-rs, tqdm are MIT/Apache): keep the upstream
209 `LICENSE` intact. See [[legal-and-trademarks]] for attribution obligations
210 (candle and mistral.rs especially).
211
212 ---
213
214 ## Adding a new patch
215
216 1. Fork upstream, add the fix on a descriptive branch, **push it public** to
217 `setoelkahfi/<crate>`, keep the `LICENSE`.
218 2. Add to `[patch.crates-io]` in every workspace root that builds the affected
219 target (onde, and the mistral.rs fork if it builds there too). Match the
220 fork's crate version to the requirement being replaced.
221 3. `CARGO_NET_GIT_FETCH_WITH_CLI=true cargo update -p <crate>@<ver>` to move the
222 lockfile onto the git source; verify `source = "git+..."` in `Cargo.lock`.
223 4. If it fixes a mistral.rs-fork build (not just onde), remember it is stripped
224 on publish — onde will still need its own copy of the patch unless the fix
225 also lands in a published `onde-*` crate.
226 5. `cargo check` on host, then let CI validate the target that was failing.
227
228 ---
229
230 *Update this skill whenever a fork's branch/rev changes, a patch is added or
231 removed, or a fork gets published under an `onde-*` name.*