GitTop just moved off the old keyring dependency path and onto keyring-core plus explicit platform stores.

The change is mostly dependency plumbing, but it fits the way GitTop is already structured: shared application logic in the middle, platform-specific behavior at the edges, and no pretending that Windows, Linux, and macOS expose the same desktop environment with different logos.

What Changed

The last point is the kind of bug that looks tiny in a diff and very stupid in a crash report. Rust strings are UTF-8. Byte indexes are not character indexes. If a pull request title contains a multi-byte character and the UI truncation code slices at the wrong byte, the app can panic. The fix is not clever; check the boundary before slicing.

Why Move

The keyring crate itself now tells application developers not to depend on it. The current direction is keyring-core for the API and separate crates for the actual credential stores.

That is more explicit and slightly more annoying. It also matches GitTop better.

GitTop already has a src/platform split because the OS-specific behavior is not a detail:

Windows/macOS: iced::application
Linux:         iced::daemon

On Linux, especially Wayland, tray-only behavior is not the same as hiding a normal desktop window. GitTop closes the window when minimizing to tray and opens a fresh one from the tray. On Windows and macOS, the normal desktop app flow works better.

The same logic applies to secrets. There is no single native keyring. There are platform stores with different behavior, setup requirements, failure modes, and user expectations. Hiding all of that behind one dependency was convenient, but GitTop is already past the point where “convenient” is the most important property.

The Part I Am Not Fully Comfortable With

This is also a bet.

keyring-core is the documented forward path. The maintainers are pretty clear about that. But the modular store crates and the new abstraction layer feel slower in practice: commits, PRs, and issues do not move especially fast there, while keyring-rs itself still sees more frequent maintainer activity.

That makes the situation a little awkward. The project says “do not depend on this crate”, but the crate you are told not to depend on still looks more alive from the outside than some of the pieces you are supposed to build on instead.

That does not mean the guidance is wrong. It does mean GitTop is taking on some ecosystem risk by following it early.

The old crate was convenient because it bundled more of the decision. The new shape makes the decision explicit:

set_default_store(...)
// use Entry::new(...)
unset_default_store()

That is cleaner architecturally, but it also means the app owns more lifecycle responsibility. Startup has to initialize the store. Shutdown should release it. Availability checks need to understand the selected backend. The backend name shown in diagnostics should be real, not whatever the old wrapper happened to imply.

I think this is the right direction. I am less sure it will stay painless.

Why This Fits GitTop

GitTop tries to feel native without lying about the platform.

The tray icon goes through different machinery on each OS. Notifications do too: WinRT toasts on Windows, DBus notifications on Linux, Notification Center on macOS. Memory trimming is platform-specific as well: EmptyWorkingSet() on Windows, malloc_trim() on glibc Linux. Dark mode even has Windows-specific behavior because matching the frame means calling into APIs that are not part of the neat cross-platform story.

So the keyring migration is not a weird exception. It is the same design rule applied to secrets:

shared API where useful, native store where it matters.

That is usually the shape that survives.