UI Auto-Tidy
Auto-Tidy uses Omniscio's local signal for which controls you have not used recently to quietly declutter the interface over time. After 30 or more days without touching a sidebar integration or a toolbar icon, it moves the item somewhere quieter. Tidying is a reversible demotion, never a deletion, it is opt-in and off by default, and all of it is restorable.
Library page — describes what users see and how to use it, then how it works under the hood. Self-contained so an outside AI (with no repo access) can read this and answer "what is Auto-Tidy and how does it work?"
What it is
Auto-Tidy uses Omniscio's local "which controls you haven't used recently" signal (see UI Usage tracking) to quietly declutter the interface over time. When you've gone 30+ days without touching a particular sidebar integration or toolbar icon — even one you used before — Omniscio moves it somewhere quieter so the screen stays calm:
- a sidebar integration collapses into a low-key "Unused" group at the bottom of the projects sidebar, and
- a toolbar icon drops into the toolbar's "…" overflow menu.
Crucially, tidying is a gentle, reversible demotion — never a deletion. Nothing is removed, disabled, or uninstalled; the thing still works exactly as before, it's just tucked out of the way. When Omniscio tidies something, it drops one consolidated inbox notice telling you what moved, and everything stays restorable in Settings → Diagnostics → Hidden items with a single click.
The feature is opt-in and off by default — auto-rearranging someone's UI without asking would be surprising, so Omniscio never tidies anything until you turn it on.
This is 100% local, like the usage tracking it builds on. Auto-Tidy reads only this device's own click history; nothing about it is uploaded or shared. (It is unrelated to the separate, unbuilt "cross-user rollup" idea mentioned on the UI Usage page.)
Where to find it
- Open Omniscio.
- Open Settings (gear icon in the toolbar, or the Settings entry in the Omniscio sidebar group).
- Go to the Diagnostics section. Two things live there for this feature:
- A toggle, "Automatically tidy away controls you never use" (off by default). Turning it on is what enables the whole loop.
- A "Hidden items" card that lists everything Auto-Tidy currently has tucked away, each with a one-click Restore. When nothing is hidden it shows a short empty state.
How it behaves
How the tidying works
Once you've turned it on, Omniscio runs a quick check when it launches and then at most once a day — the check is remembered across restarts, so quitting and reopening Omniscio several times in a day never re-runs it. For something to be tidied away, all of these must be true:
- Auto-Tidy is turned on.
- There's been at least 30 days of usage history — so a brand-new install never tidies anything (on day one everything looks unused, which is why there's a floor).
- You haven't used the item in the last 30 days — a rolling window. Something you used months ago but have since stopped using is fair game; something you clicked last week is not.
- The item is established, not brand-new. A feature added in a recent update gets its own 30-day grace period — it's never tidied the day it appears (zero recent clicks then means new, not ignored). Omniscio proves "established" from your real history: it was used more than 30 days ago, or it's been on-screen 30+ days.
- The item is currently relevant — an enabled, visible integration, or a toolbar icon you actually have pinned. A feature you've already turned off isn't "tidied" (off is not the same as unused).
- You haven't already restored it (see below).
To keep the first tidy gentle, Omniscio moves at most a handful of items per run (a soft cap of 8); anything left over moves on later days rather than all at once. Each run that moves something posts one inbox notice — "Omniscio tidied up N unused items". The notice is a little switchboard: every tidied item gets its own row with its icon, a one-line summary of what it is, a link to open it (for sidebar features), and a switch to bring it back — flip it on to restore, off to tuck it away again — plus a Bring all back shortcut and a compact footer with a one-line explanation and a Turn off link. Everything it lists is also in Settings → Diagnostics → Hidden items.
Nothing is deleted, and everything comes back
Tidying only changes where something lives, never whether it exists:
- A demoted integration is still fully enabled and works the same — it just renders inside the collapsed "Unused" group instead of the main list. Expand the group to see it.
- A demoted toolbar icon still works — it's just in the "…" overflow instead of pinned.
The simplest way to bring something back is to just use it — open the tucked-away integration from the "Unused" group (or reach it any other way), or click the toolbar icon in the "…" overflow, and Omniscio restores it to its normal spot on the spot. You can also flip its switch on in the inbox notice, or open Settings → Diagnostics → Hidden items and click Restore. Any of these returns the item immediately, and Omniscio won't auto-tidy it again — even if you then go another 30 days without using it. (You can still deliberately tuck it away yourself by flipping the notice switch back off.) The one exception to "using it brings it back" is the inbox notice's own open link — that's a look-only peek so you can check what a tidied item is without committing; use the notice's switch there. The Settings panel is the always-available record, so you can find and undo a tidy there even after the notice is gone.
For agents
How it works (for agents with repo access)
The design mirrors the usage tracking it depends on: all the intelligence lives in the renderer, and the main process does nothing new beyond raising one inbox alert. There is no new database table, no new background service, and no new data leaving the device.
State. A handful of local AppSettings fields hold everything, persisted in config.json:
autoTidyEnabled(defaultfalse) — the opt-in master switch.autoTidyDemoted: string[]— surface-prefixed keys currently demoted (integration:<id>ortoolbar:<id>). This is the single source of truth every rendering surface reads to decide where to place an item.autoTidyKept: string[]— keys you've restored; permanently excluded from future auto-demotion.autoTidyUnusedCollapsed(defaulttrue) — whether the sidebar "Unused" group is collapsed.autoTidyFirstSeen: Record<string, string>(default{}) — demotedKey → ISO of when Auto-Tidy first observed each candidate. This is the per-item 30-day clock that keeps a freshly-added control from being tidied on day one.autoTidyLastSweep: string | null(defaultnull) — ISO of the last sweep that actually ran; the once-per-24h-across-launches throttle keys off it.autoTidyFirstSeenRepaired: boolean(defaultfalse) — a one-time guard: true once the damage from a retired 2026-07-25 "reconcile" has been repaired. That reconcile clamped re-stamped first-seens back to the tracking start and couldn't tell an established control from a brand-new one, so it wrongly aged new controls; the repair resets any clamped first-seen forward to "now". Auto-Tidy never moves a first-seen backward.
The allow-list. A curated static registry is the only set Auto-Tidy may touch.
Toolbar items are an explicit list (TOOLBAR_HIDEABLE), each paired with the
data-ui-anchor the usage tracker records its clicks under so the "never used" check
works; integrations are any currently-visible built-in except an exclude set (the Alerts
integration is excluded — the tidy notice lives there). Essential controls (Send, Stop, the
composer input, Settings, Notifications, Focus Mode, the CPU-Burst button) are simply
absent from the allow-list, so they can never be tidied.
The evaluator. A pure function takes the all-time AND last-30-day usage counts + "tracking
since" date (two ui-usage:summary reads), the per-item autoTidyFirstSeen map, the
currently-relevant candidate list, and the current demoted/kept sets, and returns the
newly-eligible items — rolling and per-feature: past the global 30-day history floor, NOT
used in the last 30 days, and established (used more than 30 days ago, OR first-seen ≥30 days
old), and not already demoted or kept — capped per run. A thin driver hook runs it on launch and
on a 24h interval, persists autoTidyLastSweep to skip a sweep under 24h old, and stamps a "seen
now" time into autoTidyFirstSeen for any new candidate. One-time repair: on its first run it
resets any first-seen at/before the tracking start — the fingerprint of a retired "reconcile" that
clamped clocks backward and wrongly aged brand-new controls — FORWARD to "now" (guarded by
autoTidyFirstSeenRepaired), so a new control regains its full 30-day cold-start clock; Auto-Tidy
never moves a first-seen backward. The hook waits for the full settings load before it runs (it
gates on settingsFullyHydrated) — at first mount the settings are still loading, so running early
would read the default "off" and then never retry, which on a machine that restarts often meant the
sweep silently never ran; gating on the load makes it run the moment real settings arrive. On a
non-empty result it writes the new keys into autoTidyDemoted and fires the consolidated notice; a
failure logs and never blocks launch.
The levers. Each surface reads autoTidyDemoted independently: the toolbar render forces
a demoted id into the "…" overflow (separate from your manual pin config), and the projects
sidebar reroutes a demoted integration's row into a collapsible "Unused (N)" group (mirroring
the existing "Archived" pattern). Neither lever touches the integration's enabled flag.
The notice. One consolidated inbox alert per run, raised through the existing
inbox-alert primitive via a thin auto-tidy:notify IPC that calls the same main-side
createAlert everything else uses. It carries an order-independent dedup key (prefixed
AUTO_TIDY_DEDUP_PREFIX) so two runs before you act don't double-post — and that key also
packs this run's tidied item keys, so the renderer needs no extra data to draw the notice.
The renderer's AlertInboxViewer recognises the key and renders the Switchboard
(AutoTidyNoticeBody) instead of the plain text viewer: one row per tidied item with its
icon, an open link (integrations → activateVirtualProject), a Hidden/Back status, a
bring-back toggle, and the "why" explanation. The plain-text body is the fallback for
list/notification previews (one item per line + a omniscio://setting/auto-tidy-hidden-items
link).
Restore / re-hide. restoreKey (drop from autoTidyDemoted, add to autoTidyKept) and
its exact inverse reHideKey are pure transitions; the Settings card, the notice's switch, and
auto-restore-on-use all call restoreKey (reading fresh store state) and persist both arrays.
The kept set is what keeps the evaluator from re-tidying a restored item; a deliberate
switch-off re-hides it.
Auto-restore-on-use. Using a demoted item auto-restores it. The renderer's
restoreDemotedKeyOnUse rides the two ui-usage "use" chokepoints — an integration open at
trackProjectActivation (the universal setActiveProject funnel, so sidebar / search / keyboard /
deep-link opens all count) and a hideable toolbar-control click at bufferControlClick. It maps the
event back to its demoted key (demotedKeyForUsage) and, if that key is currently demoted, calls
restoreKey. The tidy-notice's own open link is exempt (AUTO_TIDY_NOTICE_ACTIVATION_SOURCE — a
look-only peek), and restore-on-use is gated with local usage tracking exactly like the events it
rides. No new state, no new egress — it reuses the same sanctioned transition as manual Restore.
Files (for agents with repo access)
- Settings type + defaults — src/shared/types.ts
(
autoTidyEnabled/autoTidyDemoted/autoTidyKept/autoTidyUnusedCollapsed); Zod — src/shared/ipc-schemas/update-settings.ts. - Hideable registry + key helpers — src/shared/auto-tidy-registry.ts.
- Eligibility evaluator (pure) — src/renderer/src/lib/auto-tidy-evaluator.ts.
- Demoted/kept state transitions (pure) — src/renderer/src/lib/auto-tidy-state.ts.
- Auto-restore-on-use (reuses
restoreKey; triggered from the usage tracker) — src/renderer/src/lib/auto-tidy-restore-on-use.ts + src/renderer/src/lib/ui-usage-tracker.ts. - Candidate builder (pure) — src/renderer/src/hooks/auto-tidy-candidates.ts.
- Driver hook (launch + daily) — src/renderer/src/hooks/useAutoTidy.ts.
- Consolidated inbox notice IPC (
auto-tidy:notify→createAlert) — src/main/ipc/handlers-auto-tidy.ts. - Switchboard notice card (per-item icon / open / bring-back toggle / why) — src/renderer/src/features/alerts/AutoTidyNoticeBody.tsx, wired in AlertInboxViewer.tsx.
- Toolbar overflow lever — src/renderer/src/features/toolbar/toolbar-items.ts.
- Sidebar "Unused" group — src/renderer/src/features/dashboard/auto-tidy-unused-group.ts + ProjectsSidebar.tsx.
- Settings opt-in toggle + Hidden-items card — src/renderer/src/features/settings/sections/diagnostics/HiddenItemsCard.tsx.
- Full invariants + the tests that lock them — .claude/memory/contracts/auto-tidy-contract.md.
Related
- UI Usage tracking — the local "used vs. never used" signal Auto-Tidy acts on. UI Usage just reports what you use; Auto-Tidy acts on the never-used part by gently demoting it.
- Coaching Tips — the neighboring "teach you about unused features" nudges; Auto-Tidy instead removes visual noise from features you've proven you don't use.
Last verified 2026-09-23