Dulus
An AI agent for your desktop and terminal, on any model you choose. Hosted models run on Fuel, paid in $DULUS.
翻訳待ち
リポジトリ情報はまだ収集していません。
No updates detected yet. GitHub releases will appear here.
A desktop app that keeps several Claude Code accounts saved on Linux and macOS and switches the active one from its window or from the system tray.
翻訳待ち
Loading the full README.
Read the full README ↗Fair warning: this thing is entirely vibe coded.
Not one line of it was typed by hand. It was prompted into existence with Claude Code, and reviewed mostly by using it. It works, though — so, honestly: who cares.
A desktop app (Tauri 2 + React + React Aria Components) that keeps several Claude Code accounts saved on Linux and macOS and switches the active one from its window or from the system tray.
The interface speaks English and Italian: it follows the system language, with an override in settings.
Claude Code keeps its login in two pieces:
~/.claude/.credentials.json, on macOS in
the login keychain, under the service Claude Code-credentials~/.claude.json — configuration, of which only a few keys (oauthAccount,
userID, …) identify the accountThe app copies both into ~/.config/claude-switch/profiles/<id>/ (on macOS
~/Library/Application Support/claude-switch/) and restores them when you
switch. The rest of ~/.claude.json — projects, history, preferences — is left
alone: writes are atomic, and every switch leaves a snapshot in backups/.
On macOS the app writes wherever it finds the login: if the keychain already holds an entry it uses that, otherwise it falls back to the file. Either way the CLI reads the right account, whichever of the two routes your installed version takes.
Before every switch the live credentials are copied back into the active profile, because Claude Code rotates the tokens as it runs.
Every account shows two meters: 5-hour session and week. The numbers
come from GET https://api.anthropic.com/api/oauth/usage, the same endpoint
Claude Code queries for its own /usage, called with that account's OAuth
token. This is not a public API: its shape may change without notice, so
every field is treated as optional — when one is missing the meter shows — and
the auto-switch does not fire.
Each meter carries a draggable marker: the threshold past which the account counts as spent (100% by default, so only at a full limit). With auto-switch on, the app checks the active account every minute and, as soon as either counter reaches its own threshold, moves to the next account in list order — which you rearrange by dragging rows from the handle on the left.
A candidate already past its own thresholds is skipped; if none is available the app says so and stays put. An account whose usage cannot be read (typically an expired token) is treated as usable instead: better to attempt the switch than to stall on a network error.
Usage for accounts that are not active is read with the stored token — and
the app keeps that token alive itself, so the meters no longer go blank on an
account nobody has run claude under lately. See below.
Settings → Start on the freest account (off by default) puts the app on the account with the most week left, once, at launch. "Most" is a ratio, not a percentage: what the weekly window has left, over the days it still has to cover.
room per day = (100 - week used) / days until the week resets
So 20 points to make six days last (3.3 a day) is a tighter week than 70 points for one day (70), and the second account wins. Below a day the divisor stops falling — a window resetting in ten minutes is not a reason to start on an account with nothing left in it right now.
A window with no reset date is read by what is in it. At nothing, the week has not started: its seven days begin when you pick the account up rather than now, so there is nothing yet to spread and the account ranks ahead of every week already running. With something spent in it, the date is one the endpoint did not send, and the whole seven is the cautious reading of that.
It runs once per launch, before the window is up, and it is deliberately quiet about the cases it declines: an account whose usage cannot be read is not a candidate (a comparison against a blank is not one, and that holds for the account already in place), a login the app has never saved is left alone until you save it, and being on the freest account already means nothing happens. When it does move, the window says which account it landed on and why.
The window spends its life in the tray, so a strip inside it is the wrong place for something that happens at three in the afternoon and gets read at six. The app decides per message, and never sends the same one twice:
A message that is really a state is said once and then left alone. "Nothing left to switch to" is the same answer every minute for as long as it holds, so it is announced when the standstill starts and not again until something moves it: a window resetting, an account added or freed, or you switching yourself. Being stuck on a different account, or on the other window, is a different situation and does get said. In between, the telling is the window — meters sitting full, and the warning on the tray icon. A token that will not renew works the same way, with the mark on its card doing the telling.
A launch landing on the freest account is the exception, and stays inside the window: a notification at every login would be something to dismiss rather than something to read. So is anything answering a button you just pressed — Refresh, or an update install — which belongs where your finger is.
This is the beginning of the README. Read the rest at the original. Read the full README ↗