@ondeinference / onde / commits / 22961ee

docs(skills): add forked-dependencies inventory

Document every fork and [patch.crates-io] override in the stack (mistral.rs, candle, sysctl, mio, tqdm, core2): what each is for, where it is consumed, the git-vs-published two-tier resolution model, and how to add or update one. Cross-link from sdk-regressions.

keypair34 committed Jul 20, 2026 at 22:31 UTC 22961eec02675d05ef82413fba23e7b70f0e2892
2 files changed +191
.agents/skills/forked-dependencies/SKILL.md new
+186
@@ -0,0 +1,186 @@
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. 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 bites:** the `tqdm` fork bumps crossterm to 0.29 (which pulls
47 +mio 1.x, which supports visionOS). But that fork is a *git* dep of mistral.rs,
48 +so it is stripped on publish. onde therefore resolves crates.io `tqdm 0.8.0` →
49 +`crossterm 0.25` → `mio 0.8.11`, which does *not* support visionOS. That is why
50 +onde needs its own `mio` patch even though the tqdm fork "already fixed"
51 +crossterm upstream of it. See the mio and tqdm entries below.
52 +
53 +---
54 +
55 +## Inventory
56 +
57 +| Crate | Fork / source | Ref | Purpose | Consumed where |
58 +|-------|---------------|-----|---------|----------------|
59 +| mistral.rs (12 crates) | `setoelkahfi/mistral.rs` | branch `fix/all-platform-fixes` | All-platform fixes; **published** as `onde-mistralrs-*` | onde deps (registry) |
60 +| 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) |
61 +| sysctl | `setoelkahfi/sysctl-rs` | branch `feature/watchos` | watchOS (`target_os = "watchos"`) support | `[patch.crates-io]` in onde **and** mistral.rs fork |
62 +| mio | `setoelkahfi/mio` | branch `feature/visionos` | visionOS support for the `mio 0.8.11` line | `[patch.crates-io]` in onde |
63 +| tqdm | `setoelkahfi/tqdm` | branch `deps/bump-crossterm` (version `0.8.0`) | Bumps crossterm to 0.29 | git dep in mistral.rs fork |
64 +| core2 | `bbqsrc/core2` (not ours) | rev `545e84bc` | Yanked-`core2 0.4.0` workaround | `[patch.crates-io]` in mistral.rs fork — **now unused, removable** |
65 +
66 +---
67 +
68 +## Per-fork detail
69 +
70 +### mistral.rs → `onde-mistralrs-*`
71 +
72 +- **Fork:** `setoelkahfi/mistral.rs`, branch `fix/all-platform-fixes`.
73 +- **Why:** carries fixes upstream hasn't merged (iOS 32-bit memory limits,
74 + watchOS/visionOS Metal compile, Android 32-bit const overflows, HF cache
75 + seeding, metallib link flags, and more).
76 +- **Published as:** `onde-mistralrs`, `-core`, `-quant`, `-paged-attn`,
77 + `-flash-attn`, `-metal-compile`, `-code-exec`, `-sandbox`, `-macros`,
78 + `-vision`, `-audio`, `-mcp`. The rename is a `package = "onde-..."` override on
79 + each workspace dep entry, so Rust source still `use`s `mistralrs_*` unchanged.
80 +- **Publishing + bump flow:** see [[sdk-regressions]] (the 12-crate publish
81 + order, the candle Step 0, and the tqdm/core2 publish-verification snags).
82 +
83 +### candle → `onde-candle-{core,nn}`
84 +
85 +- **Fork:** `setoelkahfi/candle`, branch `onde/candle-<ver>-<rev>` (currently
86 + `onde/candle-0.11.0-27f20fea`).
87 +- **Why:** mistral.rs pins a candle git rev past the latest release for APIs no
88 + published candle has (`QTensor::indexed_gemv`, `gemv_fused_shared_lhs`,
89 + `BarrierPool::execute_chunked`). Publishing the `onde-mistralrs-*` crates
90 + fails verification (E0080/E0599) if their candle dep resolves to the released
91 + crate, so the pinned rev is republished under `onde-candle-*`.
92 +- **Only the diverged crates are renamed.** At the 0.11.0 rev only `candle-core`
93 + and `candle-nn` differ from the release; `candle-metal-kernels` and
94 + `candle-flash-attn-v3` are byte-identical, so the mistral.rs fork points those
95 + at the official `0.11.0` crates. `candle-nn` must be republished whenever
96 + `candle-core` is (even if unchanged) or the official `candle-nn` drags the
97 + official `candle-core` back into the graph → two `candle-core` crates → type
98 + mismatch.
99 +
100 +### sysctl → watchOS
101 +
102 +- **Fork:** `setoelkahfi/sysctl-rs`, branch `feature/watchos`. Upstream PR:
103 + johalun/sysctl-rs#74.
104 +- **Why:** upstream sysctl has no `target_os = "watchos"` support.
105 +- **Applied in:** `[patch.crates-io]` in **both** onde and the mistral.rs fork
106 + (each workspace root that builds for watchOS needs its own patch entry).
107 +
108 +### mio → visionOS
109 +
110 +- **Fork:** `setoelkahfi/mio`, branch `feature/visionos`. Based on `mio 0.8.11`.
111 +- **Why:** `mio 0.8.11` hits `compile_error!("unsupported target for
112 + mio::unix::pipe")` on visionOS, breaking the Swift XCFramework build and the
113 + visionOS CI checks. The fork adds `target_os = "visionos"` to the cfg gates
114 + that already list `tvos`/`watchos` (kqueue/pipe/waker/uds). tokio's `mio 1.x`
115 + already supports visionOS, so **only the 0.8.x line** needs the patch.
116 +- **Where 0.8.11 comes from:** `tqdm → crossterm 0.25 → mio 0.8.11`, and
117 + `signal-hook-mio → crossterm`. Not from tokio (that uses `mio 1.2.2`).
118 +- **Applied in:** `[patch.crates-io]` in onde. The fork's version (`0.8.11`)
119 + must stay semver-compatible with the `^0.8` requirement it replaces; it does
120 + not touch tokio's `^1`.
121 +- **Alternative fix (not used):** patching `tqdm`/`crossterm` up to crossterm
122 + 0.29 in onde would drop `mio 0.8.11` entirely. The `mio` patch is the smaller,
123 + targeted change.
124 +
125 +### tqdm → crossterm 0.29
126 +
127 +- **Fork:** `setoelkahfi/tqdm`, branch `deps/bump-crossterm`, pinned `version = "0.8.0"`.
128 +- **Why:** bumps crossterm to 0.29.
129 +- **Applied in:** git dep in the **mistral.rs fork** only. **Stripped on
130 + publish**, so it does not reach onde — onde gets crates.io `tqdm 0.8.0`
131 + (crossterm 0.25 → mio 0.8.11). This is exactly why the onde `mio` patch is
132 + required; do not assume the tqdm fork covers onde.
133 +
134 +### core2 → (dead)
135 +
136 +- **Source:** `bbqsrc/core2` rev `545e84bc`, patched in the mistral.rs fork.
137 +- **Status:** **unused.** It was a workaround for the yanked `core2 0.4.0`
138 + (pulled via `bitstream-io → rav1e → ravif → image`). Bumping `bitstream-io` to
139 + `4.10.0` dropped `core2` (it moved to `no_std_io2`), so the patch is now
140 + `[patch.unused]` in the fork lockfile. Safe to delete from the fork's
141 + `[patch.crates-io]` on the next fork touch.
142 +
143 +---
144 +
145 +## Operational gotchas (hit these during the 1.2.1 release)
146 +
147 +- **A patched fork must be pushed to GitHub before the patch works in CI.** The
148 + `mio` fork existed only locally; the patch URL 404'd until it was pushed to
149 + `setoelkahfi/mio`. Verify with `git ls-remote <url> <branch>` before relying
150 + on a patch.
151 +- **Shallow clones cannot be pushed** (`remote unpack failed: index-pack
152 + failed`). If a fork was cloned shallow, `git fetch --unshallow <upstream>`
153 + first, then push.
154 +- **Local fork fetches need `CARGO_NET_GIT_FETCH_WITH_CLI=true`.** This machine
155 + rewrites GitHub URLs to SSH aliases; cargo's built-in fetcher can't auth, so
156 + export that var (or run the `cargo update` that pulls the fork with it). CI
157 + fetches public https forks fine without it — same as the long-standing sysctl
158 + patch.
159 +- **`[patch.crates-io]` version must be semver-compatible** with the requirement
160 + it replaces. A `0.8.11` fork replaces `^0.8`, not a `^1` requirement of the
161 + same crate — which is how the `mio` patch touches only the crossterm line and
162 + leaves tokio's `mio 1.x` alone.
163 +- **Forks are public** (mio, sysctl-rs, tqdm are MIT/Apache): keep the upstream
164 + `LICENSE` intact. See [[legal-and-trademarks]] for attribution obligations
165 + (candle and mistral.rs especially).
166 +
167 +---
168 +
169 +## Adding a new patch
170 +
171 +1. Fork upstream, add the fix on a descriptive branch, **push it public** to
172 + `setoelkahfi/<crate>`, keep the `LICENSE`.
173 +2. Add to `[patch.crates-io]` in every workspace root that builds the affected
174 + target (onde, and the mistral.rs fork if it builds there too). Match the
175 + fork's crate version to the requirement being replaced.
176 +3. `CARGO_NET_GIT_FETCH_WITH_CLI=true cargo update -p <crate>@<ver>` to move the
177 + lockfile onto the git source; verify `source = "git+..."` in `Cargo.lock`.
178 +4. If it fixes a mistral.rs-fork build (not just onde), remember it is stripped
179 + on publish — onde will still need its own copy of the patch unless the fix
180 + also lands in a published `onde-*` crate.
181 +5. `cargo check` on host, then let CI validate the target that was failing.
182 +
183 +---
184 +
185 +*Update this skill whenever a fork's branch/rev changes, a patch is added or
186 +removed, or a fork gets published under an `onde-*` name.*
.agents/skills/sdk-regressions/SKILL.md
+5
@@ -393,6 +393,11 @@ attribution obligations.
393
394 ### The `onde-mistralrs` workaround
395
396 +> For the full inventory of every fork and `[patch.crates-io]` override in the
397 +> stack (mistral.rs, candle, sysctl, mio, tqdm, core2) and how the
398 +> git-vs-published tiers resolve differently, see the **forked-dependencies**
399 +> skill. This section covers only the mistral.rs publish mechanics.
400 +
401 `cargo publish` strips every `git =` field before uploading to crates.io.
402 That means a git-only dep is useless to anyone who installs `onde` from the
403 registry — they can't resolve it.