diff --git a/CHANGELOG.md b/CHANGELOG.md
index ff29e363..0450a1a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,66 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## 3.0.0 (2026-11-02)
+
+### Documentation (BREAKING)
+
+ - declare the Rust library API experimental
+ Mark the crate root so all Rust library exports participate in experimental
+ compatibility checks. Future API breaks require minor releases while patch
+ compatibility remains checked. Document tilde requirements for library
+ consumers and retain the stable CLI and dua-core compatibility policies.
+
+ The transition removes the previous stable Rust library API promise and
+ requires dua-cli 3.0.0. Let smart-release apply versions during release.
+
+### Bug Fixes (BREAKING)
+
+ - retain filesystem paths in traversal errors
+ Just looked at the production code and rubber-stamped the tests.
+ All that really happens is a new error type that retains more information
+
+
+ RootEvent and Walk previously yielded plain I/O errors, leaving consumers
+ unable to identify a failing descendant. Return a typed dua_core::Error
+ with the entry path, or the directory path when enumeration cannot identify
+ an entry, and retain the original I/O error for kind and OS-code inspection.
+
+ Keep sibling failures as separate iterator items. Update native and ordinary
+ reads, streamed roots, prepared roots, cancellation, and CLI forwarding.
+ Metadata errors remain attached to their Entry. Document the breaking API
+ change and conversion back to io::Error.
+
+ Regression coverage removes two sibling directories before descent in both
+ orders and metadata modes; it also checks missing and streamed roots,
+ original OS errors, source access, and conversion without losing context.
+ The regression initially failed because io::Error has no path accessor.
+
+### Commit Statistics
+
+
+
+ - 6 commits contributed to the release.
+ - 18 days passed between releases.
+ - 2 commits were understood as [conventional](https://www.conventionalcommits.org).
+ - 1 unique issue was worked on: [#421](https://github.com/Byron/dua-cli/issues/421)
+
+### Commit Details
+
+
+
+view details
+
+ * **[#421](https://github.com/Byron/dua-cli/issues/421)**
+ - Retain filesystem paths in traversal errors ([`d5114df`](https://github.com/Byron/dua-cli/commit/d5114df1baad7f63c008fe725a6f4d4d0c4ce0e4))
+ * **Uncategorized**
+ - Declare the Rust library API experimental ([`c45461d`](https://github.com/Byron/dua-cli/commit/c45461d32daf5ac7ffd0db682726d112be6c9870))
+ - Merge pull request #424 from Byron/better-error-handling ([`c392945`](https://github.com/Byron/dua-cli/commit/c392945c36444122f34fc5636985a4de1e0b300e))
+ - Merge pull request #415 from Rajvira10/fix/marked-path-display-width ([`9ccf20f`](https://github.com/Byron/dua-cli/commit/9ccf20fa900710ded07e502f31a7deb8d9d52dc5))
+ - Review ([`3ab91b4`](https://github.com/Byron/dua-cli/commit/3ab91b4cdd791c76c2d85e7956ab9eabe968a241))
+ - Fix marked-pane alignment for wide Unicode paths ([`d8a9376`](https://github.com/Byron/dua-cli/commit/d8a9376a98e2f5510a8eca7df0c8ea3310978595))
+
+
## 2.46.0 (2026-10-15)
A bugfix release, and one that should also restore cargo installations, making them function.
diff --git a/Cargo.lock b/Cargo.lock
index c7ad9f30..4687aead 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -687,7 +687,7 @@ dependencies = [
[[package]]
name = "dua-cli"
-version = "2.46.0"
+version = "3.0.0"
dependencies = [
"anyhow",
"bstr",
@@ -727,7 +727,7 @@ dependencies = [
[[package]]
name = "dua-core"
-version = "5.0.2"
+version = "6.0.0"
dependencies = [
"crossbeam",
"libc",
diff --git a/Cargo.toml b/Cargo.toml
index 5be6d395..3133963a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,7 @@ fn_params_excessive_bools = "allow"
[package]
name = "dua-cli"
-version = "2.46.0"
+version = "3.0.0"
authors.workspace = true
edition.workspace = true
repository.workspace = true
@@ -45,6 +45,18 @@ include = [
"!**/tests/*",
]
+[package.metadata.smart-release]
+api-check = ["cargo", "api-check", "release"]
+
+[package.metadata.api-check]
+profiles = [
+ { default-features = false, features = [] },
+ { default-features = false, features = ["tui-crossplatform"] },
+ { default-features = false, features = ["trash-move"] },
+ { default-features = true, features = [] },
+]
+recursive = true
+
[features]
default = ["tui-crossplatform", "trash-move"]
tui-crossplatform = [
@@ -57,7 +69,7 @@ tui-crossplatform = [
trash-move = ["trash"]
[dependencies]
-dua-core = { path = "crates/dua-lib", version = "^5.0.0" }
+dua-core = { path = "crates/dua-lib", version = "^6.0.0" }
clap = { version = "4.0.29", features = ["derive", "env"] }
clap_complete = "4.5.54"
byte-unit = { version = "5.2.5", features = ["u128"] }
diff --git a/README.md b/README.md
index a1672ba2..96ec5a86 100644
--- a/README.md
+++ b/README.md
@@ -339,6 +339,30 @@ Please note that all the following assumes a unix system. On Windows, the linux
make tests
```
+#### Check release compatibility
+
+Starting with `dua-cli` 3.0.0, the `dua` Rust library is experimental and its API
+may change in minor releases. Library consumers should use a tilde requirement,
+such as `~3.0.0`, to receive compatible patch updates. The `dua` command-line
+interface follows semantic versioning, and `dua-core` retains its stable Rust API.
+
+Both workspace crates configure Rust API checks in their `Cargo.toml` metadata.
+Use a `cargo-smart-release` build that includes `cargo api-check`, Rust 1.99
+(rustdoc JSON format 61), and `cargo-semver-checks` 0.51.0 or newer.
+
+Preview the release, including stable workspace dependencies, with [just](https://just.systems):
+
+```bash
+just smart-release
+```
+
+Run `just` without arguments to list available recipes. Additional arguments to
+`just smart-release` are forwarded to `cargo smart-release`.
+
+This is a dry run. The recipe's rustdoc allowance is needed for public links to private
+items in older release tags; it does not disable API checks. It can be removed
+once both release baselines contain the corrected documentation.
+
#### Learn about other targets
```
diff --git a/crates/dua-lib/CHANGELOG.md b/crates/dua-lib/CHANGELOG.md
index 46da8263..9b094731 100644
--- a/crates/dua-lib/CHANGELOG.md
+++ b/crates/dua-lib/CHANGELOG.md
@@ -5,6 +5,79 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## 6.0.0 (2026-11-02)
+
+### Chore
+
+ - check Rust APIs during release planning
+ Enable cargo api-check for both workspace packages. Cover all four CLI
+ feature combinations and recursively inspect exposed dua-core APIs.
+
+ Document the tool requirements and dry-run command, including the targeted
+ rustdoc allowance needed when building historical release baselines.
+
+### Documentation
+
+ - fix links in public traversal documentation
+ Replace links to the private Event type with prose so public rustdoc builds
+ pass with warnings denied, as required by the API checker.
+
+### Bug Fixes
+
+ - provide standard FileType traits on native platforms
+
+ Consumers could format std::fs::FileType on Linux but the same code failed
+ to compile for macOS and Windows. Derive Debug, PartialEq, Eq, and Hash on
+ both native FileType types, retaining their existing Copy and Clone traits.
+ No wrapper or platform API change is needed.
+
+### Bug Fixes (BREAKING)
+
+ - retain filesystem paths in traversal errors
+ Just looked at the production code and rubber-stamped the tests.
+ All that really happens is a new error type that retains more information
+
+
+ RootEvent and Walk previously yielded plain I/O errors, leaving consumers
+ unable to identify a failing descendant. Return a typed dua_core::Error
+ with the entry path, or the directory path when enumeration cannot identify
+ an entry, and retain the original I/O error for kind and OS-code inspection.
+
+ Keep sibling failures as separate iterator items. Update native and ordinary
+ reads, streamed roots, prepared roots, cancellation, and CLI forwarding.
+ Metadata errors remain attached to their Entry. Document the breaking API
+ change and conversion back to io::Error.
+
+ Regression coverage removes two sibling directories before descent in both
+ orders and metadata modes; it also checks missing and streamed roots,
+ original OS errors, source access, and conversion without losing context.
+ The regression initially failed because io::Error has no path accessor.
+
+### Commit Statistics
+
+
+
+ - 5 commits contributed to the release.
+ - 2 days passed between releases.
+ - 4 commits were understood as [conventional](https://www.conventionalcommits.org).
+ - 2 unique issues were worked on: [#421](https://github.com/Byron/dua-cli/issues/421), [#422](https://github.com/Byron/dua-cli/issues/422)
+
+### Commit Details
+
+
+
+view details
+
+ * **[#421](https://github.com/Byron/dua-cli/issues/421)**
+ - Retain filesystem paths in traversal errors ([`d5114df`](https://github.com/Byron/dua-cli/commit/d5114df1baad7f63c008fe725a6f4d4d0c4ce0e4))
+ * **[#422](https://github.com/Byron/dua-cli/issues/422)**
+ - Provide standard FileType traits on native platforms ([`904203f`](https://github.com/Byron/dua-cli/commit/904203f8fcae7d5dd2b4b2983db2224f9526011c))
+ * **Uncategorized**
+ - Check Rust APIs during release planning ([`5eb55e7`](https://github.com/Byron/dua-cli/commit/5eb55e711beec3874546af527334cbc6adb63834))
+ - Fix links in public traversal documentation ([`e6ab2a9`](https://github.com/Byron/dua-cli/commit/e6ab2a927c2933ea38f32793f2b01f8cc1ee1731))
+ - Merge pull request #424 from Byron/better-error-handling ([`c392945`](https://github.com/Byron/dua-cli/commit/c392945c36444122f34fc5636985a4de1e0b300e))
+
+
## 5.0.2 (2026-10-31)
Add license files to the release package.
@@ -17,7 +90,7 @@ Add license files to the release package.
- - 4 commits contributed to the release.
+ - 5 commits contributed to the release.
- 6 days passed between releases.
- 1 commit was understood as [conventional](https://www.conventionalcommits.org).
- 0 issues like '(#ID)' were seen in commit messages
@@ -35,6 +108,7 @@ Add license files to the release package.
view details
* **Uncategorized**
+ - Release dua-core v5.0.2 ([`bc03fed`](https://github.com/Byron/dua-cli/commit/bc03feddbdd946c16dd234a28b377d43c0688597))
- Prepare changelog prior to dua-core release ([`3f954df`](https://github.com/Byron/dua-cli/commit/3f954dfd86f240dc079ab51eac73b6ef1d29ab4a))
- Merge pull request #420 from blinxen/main ([`cca6d29`](https://github.com/Byron/dua-cli/commit/cca6d29f7ecfcf4181e296ddd384ec5f428299bf))
- Thanks clippy ([`996041e`](https://github.com/Byron/dua-cli/commit/996041e739ed8d8e8f84da30efd49438ea4b4aad))
diff --git a/crates/dua-lib/Cargo.toml b/crates/dua-lib/Cargo.toml
index 201e9c0f..82781946 100644
--- a/crates/dua-lib/Cargo.toml
+++ b/crates/dua-lib/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "dua-core"
-version = "5.0.2"
+version = "6.0.0"
authors.workspace = true
edition.workspace = true
repository.workspace = true
@@ -8,6 +8,12 @@ description = "Fast parallel filesystem traversal iterators"
license.workspace = true
rust-version = "1.88"
+[package.metadata.smart-release]
+api-check = ["cargo", "api-check", "release"]
+
+[package.metadata.api-check]
+profiles = [{ default-features = true, features = [] }]
+
[dependencies]
crossbeam.workspace = true
diff --git a/crates/dua-lib/src/lib.rs b/crates/dua-lib/src/lib.rs
index 5fce1be5..5534164e 100644
--- a/crates/dua-lib/src/lib.rs
+++ b/crates/dua-lib/src/lib.rs
@@ -312,9 +312,9 @@ enum Event {
}
/// Per-root events exposed by [`RootWalk`].
-/// Unlike [`Event`], batches are flattened into entries and pool-wide completion ends the iterator
+/// Unlike internal events, batches are flattened into entries and pool-wide completion ends the iterator
/// instead of being yielded; `Finished` therefore means only that the associated root completed.
-/// [`RootWalk`] yields `(root_idx, event)`, separating root routing from event meaning. [`Event`]
+/// [`RootWalk`] yields `(root_idx, event)`, separating root routing from event meaning. The internal event type
/// cannot do this uniformly because its `Finished` variant is pool-wide and has no root index.
pub enum RootEvent {
/// An entry or filesystem error produced while walking the root.
diff --git a/justfile b/justfile
new file mode 100644
index 00000000..d7533c50
--- /dev/null
+++ b/justfile
@@ -0,0 +1,8 @@
+[private]
+default:
+ @just --list
+
+# Preview a release; pass --execute to publish.
+[positional-arguments]
+smart-release *args:
+ RUSTDOCFLAGS="-A rustdoc::private_intra_doc_links" cargo smart-release --auto-publish-of-stable-crates "$@"
diff --git a/src/lib.rs b/src/lib.rs
index 529188e9..7446979c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,9 @@
-//! Public library API for `dua` core traversal and aggregation functionality.
+//! Core traversal and aggregation functionality used by the `dua` binary.
//!
-//! This crate powers the `dua` binary and can also be used as a library.
+//! **Unstable:** The entire Rust library API may change in minor releases.
+//!
+//! Library consumers should use a tilde requirement, such as `~3.0.0`, to receive
+//! compatible patch updates. The `dua` command-line interface follows semantic versioning.
#![deny(unsafe_code)]
#![deny(missing_docs)]