+ );
+}
diff --git a/apps/web/src/components/usage/UsageLimits.tsx b/apps/web/src/components/usage/UsageLimits.tsx
index b1a57582bc9f..e2910d005c31 100644
--- a/apps/web/src/components/usage/UsageLimits.tsx
+++ b/apps/web/src/components/usage/UsageLimits.tsx
@@ -24,7 +24,11 @@ import {
import { GaugeIcon, TrendingDownIcon, TrendingUpIcon } from "lucide-react";
import { Fragment, useState } from "react";
-import { usePrimarySettings } from "../../hooks/useSettings";
+import {
+ useClientSettings,
+ usePrimarySettings,
+ useUpdateClientSettings,
+} from "../../hooks/useSettings";
import { environmentPresentations } from "../../state/presentation";
import { serverEnvironment } from "../../state/server";
import { useAtomCommand } from "../../state/use-atom-command";
@@ -42,6 +46,7 @@ import {
AlertDialogTitle,
} from "../ui/alert-dialog";
import { Button } from "../ui/button";
+import { Switch } from "../ui/switch";
import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
import { PROVIDER_PRESENTATION } from "./usageProviders";
@@ -397,6 +402,22 @@ const SOURCE_KIND_LABEL: Record = {
cliproxy: "CLI Proxy",
};
+function SidebarLimitsToggle() {
+ const checked = useClientSettings((settings) => settings.sidebarUsageLimitsEnabled);
+ const updateSettings = useUpdateClientSettings();
+ return (
+
+ );
+}
+
type LimitsSource = ReturnType[number];
/** Read-only accounts pooled by a configured usage source. */
@@ -435,6 +456,9 @@ export function UsageLimitsSection() {
return (
+
+
+
{groups.length === 0 && sources.length === 0 ? (
No provider on a connected environment reports subscription limits.
diff --git a/docs/user/usage.md b/docs/user/usage.md
index fceedc3c2560..b12990f9c964 100644
--- a/docs/user/usage.md
+++ b/docs/user/usage.md
@@ -18,6 +18,12 @@ provider health-check interval and update live while a turn runs. API-key accoun
subscription windows and say so; that includes a Claude Code that reaches Anthropic through a proxy
via `ANTHROPIC_AUTH_TOKEN`, since the CLI then treats itself as an API-key client.
+When an open chat's provider reports subscription limits, the bottom of the sidebar shows the
+remaining quota for its shortest window, such as the five-hour session. Hover or focus the indicator
+to see every window for that provider without leaving the chat. The indicator is hidden by default;
+turn **Show in sidebar** on at the top of the Limits view to display it. The Usage button remains in
+the sidebar.
+
If you pool accounts behind a CLIProxyAPI hub, open **Settings → Providers → Usage providers**
and choose **Add hub**. Select the device that should connect to the hub; its accounts appear on
the Limits view. Remove hubs from the same settings section. Each limits row shows its provider
diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts
index fef3b2992f07..651113fe13ba 100644
--- a/packages/contracts/src/settings.ts
+++ b/packages/contracts/src/settings.ts
@@ -331,6 +331,7 @@ export const ClientSettingsSchema = Schema.Struct({
// old keys, so everyone, including prior beta opt-outs, resets to the new
// default sidebar.
legacySidebarEnabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
+ sidebarUsageLimitsEnabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
sidebarProjectGroupingMode: SidebarProjectGroupingMode.pipe(
Schema.withDecodingDefault(Effect.succeed(DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE)),
),
@@ -1201,6 +1202,7 @@ export const ClientSettingsPatch = Schema.Struct({
proactivePanelsEnabled: Schema.optionalKey(Schema.Boolean),
showSkillsInSlashMenu: Schema.optionalKey(Schema.Boolean),
legacySidebarEnabled: Schema.optionalKey(Schema.Boolean),
+ sidebarUsageLimitsEnabled: Schema.optionalKey(Schema.Boolean),
sidebarProjectGroupingMode: Schema.optionalKey(SidebarProjectGroupingMode),
sidebarProjectGroupingOverrides: Schema.optionalKey(
Schema.Record(TrimmedNonEmptyString, SidebarProjectGroupingMode),