@ondeinference / cli / commits / c5d3fe7

Add distribution skill doc and update README title

keypair34 committed May 3, 2026 at 11:18 UTC c5d3fe726056e1bd73b9898ea2baadc03a137262
2 files changed +219 -1
.agents/skills/distribution/SKILL.md
+218
@@ -0,0 +1,218 @@
1 +---
2 +name: distribution
3 +description: Use when adding, fixing, or documenting package distribution for Onde CLI. Covers wrapper-package design across npm, PyPI, NuGet, pub.dev, GitHub Releases, and Homebrew, plus version alignment, artifact staging, README surfaces, and smoke-test strategy.
4 +---
5 +
6 +# Onde CLI distribution
7 +
8 +This skill captures how `onde-cli` is distributed today and what to watch when adding new channels.
9 +
10 +## Distribution model
11 +
12 +`onde-cli` is a native Rust CLI first.
13 +
14 +Everything else is packaging.
15 +
16 +That means:
17 +
18 +- build the Rust binary once per target
19 +- publish thin wrappers that install or launch that binary
20 +- keep channel-specific logic small and predictable
21 +
22 +This design keeps behavior consistent across ecosystems and avoids re-implementing CLI logic in each language.
23 +
24 +## Channel map
25 +
26 +### Native source of truth
27 +
28 +- Rust crate: `onde-cli`
29 +- binary name: `onde`
30 +- root manifest: `Cargo.toml`
31 +
32 +### Wrapper channels
33 +
34 +- npm: JavaScript launcher + optional platform packages
35 +- PyPI: `maturin` binary wheels
36 +- NuGet: .NET global tool launcher
37 +- pub.dev: Dart launcher package
38 +
39 +### Native artifact channels
40 +
41 +- crates.io
42 +- GitHub Releases
43 +- Homebrew
44 +
45 +## Wrapper design patterns
46 +
47 +### npm
48 +
49 +Use a very small Node launcher that:
50 +
51 +- detects OS and architecture
52 +- resolves the installed platform package
53 +- spawns the binary with inherited stdio
54 +
55 +Good fit for users who already live in npm tooling.
56 +
57 +### PyPI
58 +
59 +Use `maturin` with `bindings = "bin"` so the native executable is what gets installed.
60 +
61 +Good fit for Python users who want the CLI but not a Python reimplementation.
62 +
63 +### NuGet
64 +
65 +Use a `.NET global tool` wrapper.
66 +
67 +Important details:
68 +
69 +- keep the package as a launcher, not a managed rewrite
70 +- place native binaries under the tool payload
71 +- resolve the runtime identifier at startup
72 +- set Unix execute bits before launch
73 +
74 +Good fit for .NET developers and CI environments that already use `dotnet tool install`.
75 +
76 +### pub.dev
77 +
78 +Use a Dart package with a command entrypoint and a library that launches the bundled native binary.
79 +
80 +Important details:
81 +
82 +- executable command should stay `onde`
83 +- use `Isolate.resolvePackageUri` to find the installed package path
84 +- keep the runtime-id mapping explicit
85 +- do not overcomplicate the wrapper with platform-specific Dart APIs unless necessary
86 +
87 +Good fit for Dart and Flutter developers who want the same CLI through familiar tooling.
88 +
89 +## Runtime identifier mapping
90 +
91 +Keep these names aligned anywhere wrappers or workflows refer to native assets:
92 +
93 +- `darwin-x64`
94 +- `darwin-arm64`
95 +- `linux-x64`
96 +- `linux-arm64`
97 +- `windows-x64`
98 +- `windows-arm64`
99 +
100 +If a wrapper uses one naming scheme and a workflow uploads another, the installed package will pass packaging but fail at runtime.
101 +
102 +## Release workflow principles
103 +
104 +### Build first, package second
105 +
106 +Always build native binaries in a target matrix first.
107 +
108 +Then let the wrapper channel jobs package those artifacts.
109 +
110 +This avoids rebuilding the product multiple times and makes failures easier to reason about.
111 +
112 +### Idempotency
113 +
114 +Every publish workflow should check whether the target version already exists before publishing.
115 +
116 +Examples:
117 +
118 +- npm: `npm view`
119 +- PyPI: package JSON endpoint
120 +- NuGet: flat container index
121 +- pub.dev: package API endpoint
122 +
123 +### Smoke tests should match the product shape
124 +
125 +Because `onde` is TUI-first, avoid smoke tests that assume a traditional CLI help flow unless you know that code path is stable and non-interactive.
126 +
127 +Safer checks:
128 +
129 +- install succeeds
130 +- bundled native binary exists where expected
131 +- package manager validation passes
132 +
133 +## pub.dev-specific notes
134 +
135 +pub.dev behaves differently from npm and NuGet in one important way:
136 +
137 +- files ignored by git are generally excluded from publish input
138 +
139 +That means staged native binaries for `pub/onde_cli/native/` must be available to the package at publish time.
140 +
141 +Two practical consequences:
142 +
143 +- do not ignore `pub/onde_cli/native/` in the root `.gitignore` if CI stages binaries there
144 +- a `.pubignore` can hide local tool noise, but do not hide the native payload you intend to publish
145 +
146 +Run these during verification:
147 +
148 +- `dart pub get --directory pub/onde_cli`
149 +- `dart analyze pub/onde_cli`
150 +- `dart pub publish --dry-run --directory pub/onde_cli`
151 +
152 +## NuGet-specific notes
153 +
154 +NuGet packaging is sensitive to path layout.
155 +
156 +The safest pattern is:
157 +
158 +- copy native files into the publish output
159 +- let the .NET tool pack process carry them into the final package
160 +
161 +Avoid custom `PackagePath` patterns that can duplicate path segments or create nested native folders by accident.
162 +
163 +If the tool installs but cannot find the native binary, inspect the `.nupkg` contents before debugging the launcher.
164 +
165 +## README surfaces
166 +
167 +Every user-facing channel should document the same product with channel-specific installation instructions.
168 +
169 +Main files:
170 +
171 +- `README.md`
172 +- `npm/onde-cli/README.md`
173 +- `pypi/README.md`
174 +- `nuget/onde-cli/README.md`
175 +- `pub/onde_cli/README.md`
176 +
177 +Keep these aligned on:
178 +
179 +- product description
180 +- supported platforms
181 +- install method
182 +- license and copyright
183 +- relevant supporting links like the forward-pass explainer
184 +
185 +Do not let one channel sound like a different product.
186 +
187 +## Version alignment
188 +
189 +When cutting a release, update every user-facing distribution version that should move with the CLI.
190 +
191 +At minimum, check:
192 +
193 +- Rust crate version
194 +- npm package version
195 +- npm lockfile version if committed
196 +- PyPI release version source
197 +- NuGet package version at pack time
198 +- pub.dev package version in `pubspec.yaml`
199 +- workflow example tags and docs that mention concrete versions
200 +
201 +## Common failure modes
202 +
203 +- wrapper version does not match the Rust release version
204 +- staged native binaries land in the wrong directory before packaging
205 +- package builds successfully but installs without the native binary
206 +- pub.dev package omits staged assets because gitignore excludes them
207 +- smoke test invokes a TUI-first binary in a way that does not make sense for CI
208 +- README badges and install commands drift out of sync with real package names
209 +
210 +## Rule of thumb
211 +
212 +If the native binary works and the wrappers are boring, distribution stays manageable.
213 +
214 +If a wrapper starts acting like its own product, complexity grows fast.
215 +
216 +Keep it thin.
217 +Keep it aligned.
218 +Keep the Rust binary as the source of truth.
README.md
+1 -1
@@ -2,7 +2,7 @@
2 <img src="https://raw.githubusercontent.com/ondeinference/onde/main/assets/onde-inference-logo.svg" alt="Onde Inference" width="96">
3 </p>
4
5 -<h1 align="center">onde</h1>
5 +<h1 align="center">Onde Inference CLI</h1>
6
7 <p align="center">
8 Command-line interface for <a href="https://ondeinference.com">Onde Inference</a>.