kittycad.rs user-facing docs (sample)
File: 00-ABOUT-THIS-SAMPLE.md (raw markdown)
About this sample
This is an unsolicited redocumentation demo produced by Arrowmere (EXP-003 productized documentation service) as a portfolio piece.
- Target project:
KittyCAD/kittycad.rs— the official Rust client for the Zoo (KittyCAD) API. MIT-licensed. - Snapshot used: crate
kittycadv0.5.7, repo cloned 2026-10-10. - Why this project: the repository README is maintainer-facing (code generation, release process, CI smoke tests). A developer evaluating the crate gets no install → authenticate → first-call path. The crate-level docs on docs.rs are auto-generated from the OpenAPI spec and read like a reference, not an onboarding guide.
- What this sample shows: a user-facing README rewrite, a quickstart, and a worked-examples page. Every type, method and signature shown was verified against the crate source at the snapshot above — nothing is invented.
Honesty notes (shown to prospects): - This documentation is AI-produced, then verified against the project source. - It was NOT commissioned by Zoo. It is a demonstration of service quality. - A paid engagement would also include: full module-by-module API guide, error-handling guide, CI-checked doc examples, and unlimited revisions within scope.
Files:
- README-proposed.md — drop-in replacement for the crate's user-facing README
- QUICKSTART.md — zero to first API call
- EXAMPLES.md — worked examples (file conversion, units, account, pagination)
File: README-proposed.md (raw markdown)
kittycad
The official Rust client for the Zoo API — CAD file conversion and analysis, text-to-CAD, the Zoo modeling engine, and account management, from Rust.
The client is generated from Zoo's OpenAPI spec, so it tracks the live API surface. It is async (Tokio), returns strongly-typed results, and retries transient failures automatically.
Installation
[dependencies]
kittycad = "0.5.7"
tokio = { version = "1", features = ["rt", "macros"] }
Authentication
Generate an API token in your Zoo account settings, then either export it:
export ZOO_API_TOKEN="your-token" # KITTYCAD_API_TOKEN also works
let client = kittycad::Client::new_from_env();
or pass it explicitly:
let client = kittycad::Client::new("your-token");
First call
Convert a CAD file from one format to another:
use kittycad::types::{FileExportFormat, FileImportFormat};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = kittycad::Client::new_from_env();
let input = std::fs::read("part.step")?;
let conversion = client
.file()
.create_conversion(
FileExportFormat::Stl,
FileImportFormat::Step,
&bytes::Bytes::from(input),
)
.await?;
println!("status: {:?}", conversion.status);
Ok(())
}
See QUICKSTART.md for a full walkthrough and EXAMPLES.md for more worked examples.
What's in the box
Each area of the API is reached through a method on Client:
| Accessor | What it does |
|---|---|
client.file() |
CAD file conversion, volume, mass, density, surface area, center of mass |
client.ml() |
Text-to-CAD, KCL code completions, proprietary-format-to-KCL conversion |
client.modeling() |
WebSocket connection to the Zoo modeling engine |
client.executor() |
Remote code execution environments |
client.unit() |
Unit conversions (length, mass, pressure, torque, …) |
client.users() / client.orgs() |
Account, org and member management |
client.api_tokens() / client.service_accounts() |
Credential management |
client.api_calls() |
Query your API usage (debugging, billing) |
client.payments() |
Billing and payment information |
client.oauth2() |
OAuth 2.0 grant flows |
Full per-method reference: docs.rs/kittycad.
Errors, retries, pagination
- Every method returns
Result<T, kittycad::types::error::Error>; server failures carry the HTTP status and response body. - Transient failures are retried with backoff via
reqwest-retry. - List endpoints have a
*_streamvariant that paginates for you as afutures::Stream.
Contributing
The code in this repository is generated from
spec.json —
please don't edit it by hand (a bot closes such PRs). To regenerate locally,
run make generate. Maintainer docs (releasing, CI smoke tests) live in
MAINTAINERS.md (moved out of this README; see note in sample).
Support
- API questions: zoo.dev/docs or api@zoo.dev
- Bugs in this client: open an issue
License
MIT
File: QUICKSTART.md (raw markdown)
Quickstart: your first Zoo API call from Rust
This guide takes you from an empty directory to a successful API call in about five minutes.
1. Get an API token
- Sign in at zoo.dev.
- Open Account → API tokens and create a token.
- Export it (the client checks
ZOO_API_TOKEN, thenKITTYCAD_API_TOKEN):
export ZOO_API_TOKEN="your-token"
2. Create a project
cargo new zoo-hello && cd zoo-hello
cargo add kittycad anyhow
cargo add tokio --features rt,macros
cargo add bytes
3. Verify authentication
Replace src/main.rs with:
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = kittycad::Client::new_from_env();
let me = client.users().get_self().await?;
println!("authenticated as: {:?}", me);
Ok(())
}
cargo run
If you see your account details, the token works. A
401-carrying Error::Server here means the token is missing or wrong.
4. Do something real: convert a CAD file
The file API converts between CAD formats server-side — no local CAD kernel needed. This converts a STEP file to STL:
use kittycad::types::{FileExportFormat, FileImportFormat};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = kittycad::Client::new_from_env();
let input = std::fs::read("part.step")?;
let conversion = client
.file()
.create_conversion(
FileExportFormat::Stl, // what you want
FileImportFormat::Step, // what you have
&bytes::Bytes::from(input), // raw file bytes
)
.await?;
println!("conversion status: {:?}", conversion.status);
Ok(())
}
Small conversions usually complete synchronously; the returned
FileConversion carries the status, and completed output is returned
base64-encoded in the response's outputs map.
5. Where to go next
- Worked examples (units, account, pagination): EXAMPLES.md
- Every endpoint: docs.rs/kittycad
- The underlying HTTP API: zoo.dev/docs/api
Troubleshooting
| Symptom | Likely cause |
|---|---|
Error::Server { status: 401, .. } |
Token missing/expired — re-check step 1 |
new_from_env() panics |
Neither ZOO_API_TOKEN nor KITTYCAD_API_TOKEN is set |
| Conversion returns an error status | Source format doesn't match the bytes you sent |
File: EXAMPLES.md (raw markdown)
Worked examples
All examples assume ZOO_API_TOKEN is exported and these dependencies:
[dependencies]
kittycad = "0.5.7"
tokio = { version = "1", features = ["rt", "macros"] }
anyhow = "1"
bytes = "1"
futures-util = "0.3"
1. Convert a CAD file (STEP → STL)
use kittycad::types::{FileExportFormat, FileImportFormat};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = kittycad::Client::new_from_env();
let input = std::fs::read("part.step")?;
let result = client
.file()
.create_conversion(
FileExportFormat::Stl,
FileImportFormat::Step,
&bytes::Bytes::from(input),
)
.await?;
println!("{:?}", result.status);
Ok(())
}
The same module also computes geometry properties of an uploaded file:
create_volume, create_mass, create_density, create_surface_area,
create_center_of_mass, create_bounding_box.
2. Convert units
Server-side unit conversion across length, mass, force, pressure, torque, temperature, and more:
use kittycad::types::UnitLength;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = kittycad::Client::new_from_env();
let conv = client
.unit()
.get_length_conversion(UnitLength::In, UnitLength::Mm, 2.5)
.await?;
println!("2.5 in = {:?} mm", conv.output);
Ok(())
}
3. Inspect your account and API usage
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = kittycad::Client::new_from_env();
let me = client.users().get_self().await?;
println!("me: {:?}", me);
Ok(())
}
client.api_calls() exposes your recent API calls — useful for debugging
and for understanding billing.
4. Paginate with streams
Every list endpoint has a *_stream twin that handles page tokens for you
and yields items as a futures::Stream. For example, listing your
text-to-CAD generations:
use futures_util::TryStreamExt;
use kittycad::ml::ListTextToCadPartsForUserParams;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = kittycad::Client::new_from_env();
let mut ml = client.ml();
let mut stream = ml.list_text_to_cad_parts_for_user_stream(
ListTextToCadPartsForUserParams {
conversation_id: None,
limit: None,
no_models: None,
no_parts: Some(true), // metadata only
page_token: None,
sort_by: None,
},
);
while let Some(part) = stream.try_next().await? {
println!("{:?}", part);
}
Ok(())
}
5. Handling errors
Every call returns Result<T, kittycad::types::error::Error>. Server-side
failures carry the status and raw body:
use kittycad::types::error::Error;
#[tokio::main]
async fn main() {
let client = kittycad::Client::new_from_env();
match client.users().get_self().await {
Ok(me) => println!("ok: {:?}", me),
Err(Error::Server { status, body }) => {
eprintln!("API error {}: {}", status, body);
}
Err(other) => eprintln!("client-side error: {}", other),
}
}
Transient network failures are retried automatically with backoff
(reqwest-retry under the hood), so you generally only see errors that are
worth surfacing.