Skip to content

Commit 4a92e04

Browse files
Add AGENTS.md agent guidance and fix documentation drift (#287)
Co-authored-by: UltralyticsAssistant <web@ultralytics.com>
1 parent da55f64 commit 4a92e04

7 files changed

Lines changed: 123 additions & 34 deletions

File tree

AGENTS.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# AGENTS.md
2+
3+
This file provides guidance to AI coding agents (Claude Code, etc.) when working with code in this repository. CLAUDE.md is a symlink to this file.
4+
5+
## Core Principles (CRITICAL)
6+
7+
Respecting these principles is critical for every PR.
8+
9+
**Less is more. The simplest solution is the best solution.**
10+
11+
The action hierarchy for every change: **Delete > Replace > Add**. The best code change is a deletion. The second best is modifying what exists. Adding new code is the last resort.
12+
13+
1. **Minimal**: The simplest solution that works. Do not over-engineer, over-abstract, or add code just in case. Three similar lines beat a premature abstraction. Avoid error handling for impossible states, feature flags, compatibility shims, or policy scaffolding unless they are truly required.
14+
2. **Solve at the source**: Do not hack fixes. Solve problems at their root. If something is broken, fix or remove the broken thing. Never patch over a broken abstraction, add workarounds, or add synchronization code for state that should not be duplicated.
15+
3. **Delete ruthlessly**: When replacing code, delete what it replaced. Remove unused imports, functions, types, files, and commented-out code. Git preserves history. Run the repo's relevant dead-code or cleanup check when available.
16+
4. **Replace > Add**: Modify existing code over adding new code. Edit existing files, extend existing components or functions with minimal parameters, and reuse existing utilities. If creating a new file, first prove it cannot fit cleanly in an existing file.
17+
5. **Check existing**: Search the entire repo before creating anything new. If a feature, component, helper, responder, workflow, or utility already solves a similar problem, reuse or adapt it and delete the duplicate path.
18+
6. **Deduplicate**: Do not duplicate existing code when updating the repo. Consolidate or refactor duplicates you find when it is in scope and low risk.
19+
7. **Zero Regression**: Do not break existing features or workflows unless the PR intentionally removes them with evidence.
20+
8. **Production ready**: All changes must be thoroughly debugged, validated, and production ready.
21+
22+
**When fixing bugs, ask: "What can I delete?" before "What can I replace?" before "What should I add?"**
23+
24+
## PR Workflow
25+
26+
After opening a PR:
27+
28+
1. Wait for the automated PR review and auto-format commit from Ultralytics Actions (`format.yml`), then pull and address every finding.
29+
2. Launch an independent adversarial review agent with cold context (just the PR diff and this file) to hunt for bugs, regressions, and Core Principles violations — use the Codex CLI, one fresh `codex exec` run per round. Fix, push, and repeat until a fresh run reports LGTM.
30+
3. Never fight other commits: Ultralytics Actions pushes auto-format and header commits, and multiple users may work on the same PR. `git pull --rebase` before pushing; never force-push, reset, or revert commits you did not author.
31+
4. After the PR merges, clean up: remove local worktrees and branches for it, then `git checkout main && git pull`.
32+
33+
## Commands
34+
35+
```bash
36+
# Build (native; default features = annotate + visualize)
37+
cargo build
38+
39+
# Run all tests as CI does on Linux/Windows (macOS CI uses "coreml,annotate")
40+
cargo test --no-default-features --features annotate
41+
42+
# Run one test by name filter (add -- --ignored --exact for the network e2e tests)
43+
cargo test --no-default-features --features annotate test_boxes_creation
44+
45+
# Lint exactly as CI (ci.yml `test` job; macOS swaps in "coreml,annotate")
46+
cargo clippy --all-targets --no-default-features --features annotate -- -D warnings
47+
48+
# Format (checked with --check in ci.yml and format.yml)
49+
cargo fmt --all
50+
51+
# Coverage exactly as CI (ci.yml `coverage` job: nightly toolchain, cargo-llvm-cov, FFmpeg dev libs)
52+
cargo llvm-cov --features annotate,video,visualize --workspace --lcov --output-path lcov.info --ignore-filename-regex '(src/cuda_inference\.rs|src/visualizer/viewer\.rs|src/main\.rs|crates/web/)'
53+
54+
# Wasm checks (ci.yml `wasm` job)
55+
cargo build -p ultralytics-inference --lib --no-default-features --target wasm32-unknown-unknown
56+
cargo clippy -p ultralytics-inference-web --target wasm32-unknown-unknown -- -D warnings
57+
58+
# npm package build (wasm-pack + tsc)
59+
cd web && npm ci && npm run build
60+
61+
# Python tooling (only used in CI, e.g. ultralytics-actions): always uv, never bare pip
62+
uv pip install --system ultralytics-actions
63+
```
64+
65+
- CI matrix (`ci.yml`): `test` on ubuntu/macos/windows; `test-video` in FFmpeg 7.1/8.0 Linux containers (`--features annotate,video`); video builds on macOS/Windows; `wasm`; `coverage` (nightly) uploads to Codecov.
66+
- MSRV is Rust 1.89 (`rust-version` in Cargo.toml), edition 2024.
67+
- First native build downloads ONNX Runtime binaries (ort `download-binaries` feature), so builds need network once.
68+
69+
## Architecture
70+
71+
Rust workspace with two crates plus an npm wrapper, all versioned together from the root `Cargo.toml`:
72+
73+
- Root crate `ultralytics-inference`: YOLO inference library (`src/lib.rs`) and CLI binary (`src/main.rs`, thin wrapper over `src/cli/`). Pipeline: `source.rs` (images/dirs/globs/video/webcam) → `preprocessing.rs` (SIMD letterbox) → `model.rs` (`YOLOModel`, the ONNX Runtime session via `ort`, configured by `inference.rs`'s `InferenceConfig`) → `postprocessing.rs``results.rs` (`Results`/`Boxes`/`Masks`/`Keypoints`/`Probs`/`SemanticMask`, mirroring the Ultralytics Python API). `model.rs` reads embedded ONNX metadata (`metadata.rs`) and auto-downloads known YOLOv8/YOLO11/YOLO26 models and sample images (`download.rs`).
74+
- `crates/web` (`ultralytics-inference-web`, `publish = false`): wasm32-only WebGPU bindings via `ort-web`. Excluded from `default-members`, so plain `cargo build`/`cargo test` from the root skip it; it only builds for `--target wasm32-unknown-unknown`.
75+
- `web/`: npm package `@ultralytics/yolo` — TypeScript wrapper (`web/src/index.ts`) over the wasm-pack output of `crates/web`, with an optional LiteRT.js backend for `.tflite` models.
76+
- GPU/accelerator features (`cuda`, `tensorrt`, `coreml`, …) gate no public API; docs.rs builds with `annotate,visualize,video` only (see `[package.metadata.docs.rs]`).
77+
- Release gating: on every push to main, `publish.yml` reads the version from `Cargo.toml` — if tag `v{version}` does not exist it tags, creates a GitHub release, and publishes to crates.io; `npm-publish.yml` likewise publishes `@ultralytics/yolo` if that version is missing from npm. So merging a version bump to main releases both packages.
78+
79+
## Conventions
80+
81+
- Every source file starts with the `Ultralytics 🚀 AGPL-3.0 License` header — Ultralytics Actions adds them automatically; don't add or revert manually.
82+
- Ultralytics Actions (`format.yml`) also runs Prettier (YAML/JSON/Markdown), codespell, and a nightly `cargo fmt` check on PRs; expect it to push an auto-format commit to your PR branch.
83+
- Lints are strict: clippy `all`/`pedantic`/`nursery`/`cargo` plus `missing_docs` and `unsafe_code` warn at the workspace level (CI promotes to errors with `-D warnings`), and `src/lib.rs` denies `dead_code` — document all public items and delete unused code.
84+
- Unit tests live inline in `src/` modules; integration tests in `tests/integration_test.rs`. The e2e tests that download models/images (e.g. `test_run_prediction_e2e`) are `#[ignore]`d — run them explicitly with `-- --ignored`; macOS CI runs `test_coreml_model_loads_and_warms_up` this way. Note the non-ignored `src/batch.rs` tests also auto-download `yolo26n.onnx` on first run, so the plain test suite needs network until that file is cached.
85+
- Version bumps update root `Cargo.toml`, `crates/web/Cargo.toml`, and `web/package.json` together; merging the bump to main auto-tags and publishes (see Architecture).

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AGENTS.md

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ inference/
398398
│ ├── inference.rs # InferenceConfig
399399
│ ├── batch.rs # Batch processing pipeline
400400
│ ├── device.rs # Device enum (CPU, CUDA, CoreML, etc.)
401+
│ ├── cuda_inference.rs # Fused CUDA preprocess kernel (cuda-preprocess feature)
402+
│ ├── parallel.rs # Rayon parallelism shims (sequential on wasm)
401403
│ ├── download.rs # Model and asset downloading
402404
│ ├── annotate.rs # Image annotation (bounding boxes, instance masks, keypoints, semantic overlay)
403405
│ ├── io.rs # Result saving (images, videos)

README.zh-CN.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -223,25 +223,25 @@ ultralytics-inference predict --model <model.onnx> --source <source>
223223

224224
**CLI 选项:**
225225

226-
| 选项 | 简写 | 说明 | 默认值 |
227-
| --------------- | ---- | ------------------------------------------------------------------------------------------------------------------------ | --------------------------------- |
228-
| `--model` | `-m` | ONNX 模型文件路径;若为已知 YOLOv8/YOLO11/YOLO26 名称则自动下载 | `yolo26n.onnx` |
229-
| `--task` | | 任务类型(`detect``segment``pose``obb``classify``semantic`\*);省略 `--model` 时选择 nano 模型 | `detect` |
230-
| `--source` | `-s` | 输入源(图片、目录、glob、视频、摄像头索引或 URL) | 与任务相关的 Ultralytics URL 资源 |
231-
| `--conf` | | 置信度阈值 | `0.25` |
232-
| `--iou` | | NMS IoU 阈值 | `0.7` |
233-
| `--max-det` | | 最大检测数量 | `300` |
234-
| `--imgsz` | | 推理图片尺寸 | 模型元数据 |
235-
| `--rect` | | 启用矩形推理(最小填充) | `true` |
236-
| `--batch` | | 推理 batch size | `1` |
237-
| `--half` | | 使用 FP16 半精度推理 | `false` |
238-
| `--save` | | 将标注结果保存到 runs/\<task\>/predict | `true` |
239-
| `--save-frames` | | 为视频输入保存单帧(而不是视频文件) | `false` |
240-
| `--save-json` | | 保存语义分割类别图 PNG,便于外部评估 | `false` |
241-
| `--show` | | 在窗口中显示结果 | `false` |
242-
| `--device` | | 设备字符串,例如 cpu、cuda:0、coreml、directml:0、openvino、tensorrt:0、rocm:0、xnnpack;启用 feature 后可选择更多提供方 | `cpu` |
243-
| `--verbose` | | 显示详细输出 | `true` |
244-
| `--classes` | | 按类别 ID 过滤,例如 `0``"0,1,2"``"[0, 1, 2]"` | 所有类别 |
226+
| 选项 | 简写 | 说明 | 默认值 |
227+
| --------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------- |
228+
| `--model` | `-m` | ONNX 模型文件路径;若为已知 YOLOv8/YOLO11/YOLO26 名称则自动下载 | `yolo26n.onnx` |
229+
| `--task` | | 任务类型(`detect``segment``pose``obb``classify``semantic`\*);省略 `--model` 时选择 nano 模型 | `detect` |
230+
| `--source` | `-s` | 输入源(图片、目录、glob、视频、摄像头索引或 URL) | 与任务相关的 Ultralytics URL 资源 |
231+
| `--conf` | | 置信度阈值 | `0.25` |
232+
| `--iou` | | NMS IoU 阈值 | `0.7` |
233+
| `--max-det` | | 最大检测数量 | `300` |
234+
| `--imgsz` | | 推理图片尺寸 | 模型元数据 |
235+
| `--rect` | | 启用矩形推理(最小填充) | `true` |
236+
| `--batch` | | 推理 batch size | `1` |
237+
| `--half` | | 使用 FP16 半精度推理 | `false` |
238+
| `--save` | | 将标注结果保存到 runs/\<task\>/predict | `true` |
239+
| `--save-frames` | | 为视频输入保存单帧(而不是视频文件) | `false` |
240+
| `--save-json` | | 保存语义分割类别图 PNG,便于外部评估 | `false` |
241+
| `--show` | | 在窗口中显示结果 | `false` |
242+
| `--device` | | 设备字符串,例如 cpu、cuda:0、coreml、directml:0、openvino、tensorrt:0、rocm:0、xnnpack;启用 feature 后可选择更多提供方(见 Features 表) | `cpu` |
243+
| `--verbose` | | 显示详细输出 | `true` |
244+
| `--classes` | | 按类别 ID 过滤,例如 `0``"0,1,2"``"[0, 1, 2]"` | 所有类别 |
245245

246246
**任务和模型解析:**
247247

@@ -397,6 +397,8 @@ inference/
397397
│ ├── inference.rs # InferenceConfig
398398
│ ├── batch.rs # Batch 处理流程
399399
│ ├── device.rs # Device 枚举(CPU, CUDA, CoreML 等)
400+
│ ├── cuda_inference.rs # 融合 CUDA 预处理 kernel(cuda-preprocess feature)
401+
│ ├── parallel.rs # Rayon 并行抽象(wasm 上为顺序执行)
400402
│ ├── download.rs # 模型和资源下载
401403
│ ├── annotate.rs # 图片标注(边界框、实例 mask、关键点、语义叠加)
402404
│ ├── io.rs # 结果保存(图片、视频)

docs/CUDA.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,7 @@ the CPU path runs and the flag is silently ignored:
166166
- `cuda_preprocess` is `true` (the default),
167167
- the device is `Cuda(_)`, `TensorRt(_)`, or unset (auto-detect),
168168
- the task is not `Classify` (which uses center-crop, not letterbox),
169-
- the model takes an FP32 input tensor (FP16-input models keep the CPU path),
170-
- the model input is square (H == W).
169+
- the model takes an FP32 input tensor (FP16-input models keep the CPU path).
171170

172171
It is wired into `predict_image` specifically (single-frame). `predict_batch`
173172
and the multi-image batch path always use CPU preprocess.

src/cli/args.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use clap::{Args, Parser, Subcommand};
2424
--save-frames Save individual frames for video input (instead of video file)
2525
--save-json Save semantic segmentation class-map PNGs for external evaluation
2626
--show Display results in a window [default: false]
27-
--device <DEVICE> Device (cpu, cuda:0, coreml, directml:0, openvino, tensorrt:0, xnnpack)
27+
--device <DEVICE> Device (cpu, cuda:0, coreml, directml:0, openvino, tensorrt:0, rocm:0, xnnpack)
2828
--verbose Show verbose output [default: true]
2929
--classes <CLASSES> Filter by class IDs (e.g., "0", "0,1,2", "[0, 1]")
3030
@@ -118,7 +118,7 @@ pub struct PredictArgs {
118118
#[arg(long, default_value_t = false)]
119119
pub show: bool,
120120

121-
/// Device to use (cpu, cuda:0, mps, coreml, directml:0, openvino, tensorrt:0, etc.)
121+
/// Device to use (cpu, cuda:0, coreml, directml:0, openvino, tensorrt:0, rocm:0, xnnpack)
122122
#[arg(long)]
123123
pub device: Option<String>,
124124

0 commit comments

Comments
 (0)