{"id":50137018,"url":"https://github.com/sadjow/aith","last_synced_at":"2026-05-23T22:31:23.891Z","repository":{"id":358101810,"uuid":"1238027467","full_name":"sadjow/aith","owner":"sadjow","description":"Native CLI for profile-scoped AI coding tool auth across Codex CLI, Claude Code, and Cursor Agent.","archived":false,"fork":false,"pushed_at":"2026-05-16T15:30:51.000Z","size":159,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T22:06:13.896Z","etag":null,"topics":["account-switcher","ai","authentication","claude-code","cli","codex","cursor","developer-tools","profiles","rust"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sadjow.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-13T18:37:13.000Z","updated_at":"2026-05-16T15:30:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sadjow/aith","commit_stats":null,"previous_names":["sadjow/aith"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/sadjow/aith","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadjow%2Faith","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadjow%2Faith/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadjow%2Faith/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadjow%2Faith/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sadjow","download_url":"https://codeload.github.com/sadjow/aith/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadjow%2Faith/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33415020,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"ssl_error","status_checked_at":"2026-05-23T22:14:43.778Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["account-switcher","ai","authentication","claude-code","cli","codex","cursor","developer-tools","profiles","rust"],"created_at":"2026-05-23T22:31:21.309Z","updated_at":"2026-05-23T22:31:23.885Z","avatar_url":"https://github.com/sadjow.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# aith\n\n`aith` is a native CLI for managing account profiles for AI coding tools.\n\nThe goal is to make work, personal, and client identities explicit across tools\nlike Codex CLI, Codex Desktop, Claude Code, Claude Desktop, Cursor Agent, and\nCursor Desktop without repeated logout/login flows.\n\n## Supported Surfaces\n\n`aith` treats each auth surface separately. A terminal tool and a desktop app can\nbe logged into different accounts, so they should not share one profile target.\n\nCurrent command keys:\n\n- `codex-cli`: Codex CLI. Legacy alias: `codex`.\n- `codex-desktop`: Codex desktop app.\n- `claude-code`: Claude Code. Legacy alias: `claude`.\n- `claude-desktop`: Claude desktop app.\n- `cursor-agent`: Cursor Agent or terminal Cursor auth through `CURSOR_API_KEY`.\n  Legacy alias: `cursor`.\n- `cursor-desktop`: Cursor desktop app.\n\nDesktop app targets are read-only today. They support `status` and `doctor`\ndiscovery, but profile switching is intentionally not implemented until their\nauth stores are understood well enough to mutate safely.\n\n## Status\n\n`aith` is early. Codex CLI profile management is implemented first because\nCodex CLI stores its active auth state in a local `auth.json` file.\n\nImplemented:\n\n- Tool status checks for Codex CLI, Claude Code, and Cursor Agent.\n- Read-only desktop app status checks for Codex Desktop, Claude Desktop, and\n  Cursor Desktop.\n- Read-only doctor diagnostics for auth/profile readiness.\n- Claude Code auth/config discovery.\n- Claude Code env-profile save/list/remove.\n- Claude Code one-command and shell-scoped env-profile sessions.\n- Cursor Agent env-profile save/list/remove.\n- Cursor Agent one-command and shell-scoped env-profile sessions.\n- Codex CLI profile save/list/current/use/remove.\n- Codex CLI backup list/restore.\n- Codex CLI one-command temporary profile execution.\n- Codex CLI shell-scoped temporary profile sessions.\n- Automatic backup before replacing active Codex CLI auth.\n- Private Unix permissions for stored profile directories, auth files, and env\n  profile files.\n\nNot implemented yet:\n\n- Claude Code global login switching, including subscription/Keychain account\n  switching.\n- Cursor Agent global login switching beyond terminal API-key sessions.\n- Desktop app profile switching for Codex, Claude, or Cursor.\n\n## Quick Start\n\nUse `devenv` to enter the pinned Rust development environment:\n\n```sh\ndevenv shell\ncargo run -- status\ncargo run -- status codex-desktop\n```\n\n## Installation\n\nWhile the repository is private, install from GitHub with SSH access:\n\n```sh\ncargo install --git git@github.com:sadjow/aith.git --locked\n```\n\nAfter public releases are available:\n\n```sh\ncurl --proto '=https' --tlsv1.2 -LsSf https://github.com/sadjow/aith/releases/download/v0.1.0/aith-installer.sh | sh\nbrew install sadjow/tap/aith\nnpm install @sadjow/aith@0.1.0\ncargo install aith --locked\nnix run github:sadjow/aith\n```\n\nRelease process details live in [docs/releasing.md](docs/releasing.md).\n\nSave the current Codex CLI login as a profile:\n\n```sh\ncargo run -- save codex-cli personal\n```\n\nInspect and switch Codex CLI profiles:\n\n```sh\ncargo run -- list codex-cli\ncargo run -- current codex-cli\ncargo run -- doctor codex-cli\ncargo run -- use codex-cli personal\n```\n\nInspect backups created by profile switches:\n\n```sh\ncargo run -- backups codex-cli\ncargo run -- restore codex-cli auth-1778702155-74626.json\n```\n\nRun one command with a saved Codex CLI profile without switching your active\nlogin:\n\n```sh\ncargo run -- exec codex-cli personal -- codex\n```\n\nStart a shell with a saved Codex CLI profile without switching your active login:\n\n```sh\ncargo run -- shell codex-cli personal\n```\n\nSave a Claude Code env profile without storing the secret value:\n\n```sh\nexport ANTHROPIC_API_KEY_WORK=sk-ant-...\ncargo run -- save claude-code work --from-env ANTHROPIC_API_KEY=ANTHROPIC_API_KEY_WORK\ncargo run -- exec claude-code work -- claude\n```\n\nSave a Cursor Agent env profile without storing the secret value:\n\n```sh\nexport CURSOR_API_KEY_WORK=...\ncargo run -- save cursor-agent work --from-env CURSOR_API_KEY=CURSOR_API_KEY_WORK\ncargo run -- exec cursor-agent work -- cursor-agent\n```\n\nRemove a saved Codex CLI profile:\n\n```sh\ncargo run -- remove codex-cli old-client\n```\n\n## Commands\n\n### Tools\n\nList supported tools:\n\n```sh\naith tools\n```\n\n### Status\n\nShow safe auth/config status. This checks whether expected files and\nenvironment variables exist, but does not print credential values.\n\n```sh\naith status\naith status codex-cli\naith status codex-desktop\naith status claude-code\naith status claude-desktop\naith status cursor-agent\naith status cursor-desktop\n```\n\n### Doctor\n\nShow a read-only diagnostic report for tool auth paths, relevant environment\nvariables, saved profile counts, backup counts, and current profile detection.\nCredential file contents are never printed.\n\n```sh\naith doctor\naith doctor codex-cli\naith doctor codex-desktop\naith doctor claude-code\naith doctor claude-desktop\naith doctor cursor-agent\naith doctor cursor-desktop\n```\n\nFor Claude Code and Cursor Agent, `doctor` reports both safe path/env status and\nsaved env profiles. It still warns that global login switching is not\nimplemented for those tools.\n\nFor desktop app targets, `doctor` reports known app/data paths as read-only and\nmarks profiles, backups, and current profile detection as unsupported.\n\n### Save\n\nSave the current auth state as a named profile.\n\n```sh\naith save codex-cli personal\n```\n\n`add` is an alias for `save`:\n\n```sh\naith add codex-cli work\n```\n\nProfiles can be overwritten explicitly:\n\n```sh\naith save codex-cli personal --force\n```\n\nClaude Code and Cursor Agent profiles are env-based. `aith` stores references to\nsource environment variables, not their values:\n\n```sh\nexport ANTHROPIC_API_KEY_WORK=sk-ant-...\naith save claude-code work --from-env ANTHROPIC_API_KEY=ANTHROPIC_API_KEY_WORK\naith save cursor-agent work --from-env CURSOR_API_KEY=CURSOR_API_KEY_WORK\n```\n\nNon-secret settings can be stored as literals:\n\n```sh\naith save claude-code work \\\n  --from-env ANTHROPIC_API_KEY=ANTHROPIC_API_KEY_WORK \\\n  --set-env ANTHROPIC_BASE_URL=https://api.anthropic.com \\\n  --force\n```\n\n`aith` refuses literal values for sensitive names such as `ANTHROPIC_API_KEY`;\nuse `--from-env` for secrets.\n\n### List\n\nList saved profiles for a tool:\n\n```sh\naith list codex-cli\naith list claude-code\naith list cursor-agent\n```\n\nDesktop app targets do not support saved profiles yet.\n\n### Current\n\nDetect which saved profile matches the active auth state:\n\n```sh\naith current codex-cli\naith current claude-code\naith current cursor-agent\n```\n\nPossible outputs:\n\n```text\ncodex-cli: personal\ncodex-cli: unknown\ncodex-cli: ambiguous\n  matches personal, duplicate\n```\n\n`ambiguous` means more than one saved profile has the same auth snapshot. Env\nprofiles are session-scoped, so `aith current claude-code` and\n`aith current cursor-agent` report `unknown` instead of trying to infer a global\nactive account.\n\nDesktop app targets do not support current profile detection yet.\n\n### Use\n\nSwitch a tool to a saved profile:\n\n```sh\naith use codex-cli personal\n```\n\nFor Codex CLI, this replaces the active `auth.json` with the saved profile\nsnapshot. The previous active `auth.json` is backed up first. If the previous\nactive profile was last activated by `aith` and Codex has since rotated its\nOAuth tokens, `aith` syncs the refreshed active `auth.json` back to that saved\nprofile before switching away.\n\nCodex app/plugin connector OAuth state, such as `codex_apps` MCP connector\ntokens, is separate from the Codex CLI account `auth.json`. If a connector\nreports `token_revoked` after an account switch, re-authenticate that connector\nfor the currently active Codex account.\n\n### Remove\n\nRemove a saved profile:\n\n```sh\naith remove codex-cli old-client\naith remove claude-code old-client\naith remove cursor-agent old-client\n```\n\nBy default, `remove` refuses to delete a profile that matches the active auth\nstate:\n\n```text\nError: profile 'personal' is currently active for codex-cli; pass --force to remove it\n```\n\nForce removal when you intentionally want to delete the saved profile:\n\n```sh\naith remove codex-cli personal --force\n```\n\nThis removes only the saved profile directory. It does not touch active Codex\nCLI auth and does not delete backups.\n\n### Backups\n\nList backups created before profile switches or restores:\n\n```sh\naith backups codex-cli\naith backups claude-code\naith backups cursor-agent\n```\n\nEnv profiles do not replace active auth files, so there are no Claude Code or Cursor Agent\nbackups to list.\n\nExample output:\n\n```text\nauth-1778702155-74626.json      /Users/sadjow/Library/Application Support/aith/backups/codex/auth-1778702155-74626.json\n```\n\nBackup IDs use this generated form:\n\n```text\nauth-\u003ctimestamp\u003e-\u003cpid\u003e.json\n```\n\n### Restore\n\nRestore a backup into the active auth location:\n\n```sh\naith restore codex-cli auth-1778702155-74626.json\n```\n\nFor Codex CLI, this copies the selected backup to the active `auth.json`. The\ncurrent active `auth.json` is backed up first, so restore is reversible.\n\n### Exec\n\nRun a command with a temporary profile-scoped auth environment:\n\n```sh\naith exec codex-cli personal -- codex\naith exec codex-cli work -- codex exec \"review this repo\"\naith exec claude-code work -- claude\naith exec cursor-agent work -- cursor-agent\n```\n\nFor Codex CLI, `exec` creates a temporary `CODEX_HOME`, copies the selected\nprofile's `auth.json` into it, copies the current Codex CLI `config.toml` when\none exists, and runs the command with that temporary `CODEX_HOME`.\n\nThe active Codex CLI auth file is not modified, and the temporary directory is\nremoved after the command exits. If Codex refreshes OAuth tokens inside the\ntemporary `CODEX_HOME`, the refreshed `auth.json` is synced back to the saved\nprofile so the profile does not keep a stale refresh token. `aith exec` exits\nwith the same status code as the child command.\n\nFor Claude Code and Cursor Agent, `exec` resolves saved env references at runtime and\nstarts the child command with those target variables set. Config files, login\nstate, and Keychain entries are not modified.\n\n### Shell\n\nStart a shell with a temporary profile-scoped auth environment:\n\n```sh\naith shell codex-cli personal\naith shell claude-code work\naith shell cursor-agent work\n```\n\nFor Codex CLI, `shell` stages the selected profile exactly like `exec`, then\nstarts your configured shell with `CODEX_HOME` pointing at the temporary profile\nhome. This lets separate terminal tabs use different Codex CLI profiles at the\nsame time.\n\nThe active Codex CLI auth file is not modified, and the temporary directory is\nremoved when the shell exits. If Codex refreshes OAuth tokens inside the\ntemporary `CODEX_HOME`, the refreshed `auth.json` is synced back to the saved\nprofile so the profile does not keep a stale refresh token. `aith shell` exits\nwith the same status code as the shell.\n\nFor Claude Code and Cursor Agent, `shell` resolves saved env references and starts your\nconfigured shell with those variables set. This lets separate terminal tabs use\ndifferent API-key profiles at the same time when the upstream command honors\nterminal auth env vars.\n\n## Storage\n\nProfiles are stored under `AITH_HOME` when it is set. Otherwise, `aith` uses the\nplatform data directory:\n\n- macOS: `~/Library/Application Support/aith`\n- Linux: `${XDG_DATA_HOME:-~/.local/share}/aith`\n- Windows: `%LOCALAPPDATA%\\aith`\n\nCodex CLI profiles are stored as:\n\n```text\nprofiles/codex/\u003cprofile\u003e/auth.json\n```\n\nCodex CLI backups are stored as:\n\n```text\nbackups/codex/auth-\u003ctimestamp\u003e-\u003cpid\u003e.json\n```\n\nEnv profiles for Claude Code and Cursor Agent are stored as:\n\n```text\nprofiles/\u003cstorage-key\u003e/\u003cprofile\u003e/profile.toml\n```\n\nStorage keys remain the short legacy names for compatibility with existing\nprofiles: `codex`, `claude`, and `cursor`.\n\nThe last Codex CLI profile activated or saved by `aith` is tracked as:\n\n```text\nstate/codex/active-profile\n```\n\nThis marker lets `aith use codex-cli ...` sync refreshed OAuth tokens back to\nthe previous saved profile before switching to another profile. The sync only\noccurs when the active auth and saved profile share the same Codex\n`tokens.account_id`.\n\nExample Claude Code profile:\n\n```toml\n[env]\nANTHROPIC_API_KEY = { from_env = \"ANTHROPIC_API_KEY_WORK\" }\nANTHROPIC_BASE_URL = \"https://api.anthropic.com\"\n```\n\nExample Cursor Agent profile:\n\n```toml\n[env]\nCURSOR_API_KEY = { from_env = \"CURSOR_API_KEY_WORK\" }\n```\n\nOn Unix, profile directories are created with `0700` permissions and auth files\nor profile files are written with `0600` permissions.\n\n## Claude Code Discovery and Env Profiles\n\n`aith status claude-code` and `aith doctor claude-code` check known Claude Code\nsettings and auth surfaces without reading credential contents.\n\nClaude Code discovery checks:\n\n- User config directory: `CLAUDE_CONFIG_DIR` or `~/.claude`\n- User settings: `settings.json`\n- User state: `~/.claude.json`\n- Project settings: `.claude/settings.json` and local `.claude/settings.local.json`\n- Managed settings path for the current platform\n- Terminal auth environment variables such as `ANTHROPIC_API_KEY`,\n  `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, and cloud-provider mode\n  variables\n\nCredential storage differs by platform. On macOS, Claude Code subscription\ncredentials are stored in Keychain and `aith` does not inspect Keychain. On\nLinux and Windows, Claude Code uses `.credentials.json` under the Claude config\ndirectory, including `CLAUDE_CONFIG_DIR` when set.\n\nClaude Code env profiles are intentionally narrower than Codex CLI file-backed\nprofiles. They do not switch the logged-in Claude Code subscription account.\nThey only set terminal auth environment variables for\n`aith exec claude-code ...` and `aith shell claude-code ...` sessions.\n\nReferences:\n\n- [Claude Code settings](https://code.claude.com/docs/en/settings)\n- [Claude Code authentication](https://code.claude.com/docs/en/team)\n- [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference)\n\n## Cursor Agent Env Profiles\n\n`aith status cursor-agent` and `aith doctor cursor-agent` check the Cursor user\ndata path and terminal auth environment without printing credential values.\n\nCursor Agent env profiles set terminal auth environment variables for\n`aith exec cursor-agent ...` and `aith shell cursor-agent ...` sessions. They do\nnot modify Cursor user data or any global login state.\n\n## Desktop App Discovery\n\n`aith` tracks desktop apps separately from CLI and terminal agent targets:\n\n- `codex-desktop`\n- `claude-desktop`\n- `cursor-desktop`\n\nDesktop targets are read-only today. `aith status \u003cdesktop-target\u003e` and\n`aith doctor \u003cdesktop-target\u003e` check known app bundle, app support, settings,\nbrowser storage, and user-data paths without opening credential-bearing files or\nprinting credential values.\n\nDesktop discovery intentionally does not inspect macOS Keychain, cookies,\nLevelDB, IndexedDB, SQLite databases, or app-managed session stores. Those\nstores may contain sensitive or app-version-specific auth state, so switching is\nblocked until each desktop auth model has a dedicated, reversible implementation.\n\n## Safety Model\n\n- Credential file contents are never printed by status/doctor/current/list\n  commands.\n- Profile names are limited to ASCII letters, numbers, `-`, and `_`.\n- `use` and `restore` create a backup before replacing active Codex CLI auth.\n- `use` syncs the previously activated Codex CLI profile before switching away\n  when the active auth still belongs to the same Codex account id.\n- `exec` runs with a temporary `CODEX_HOME` and does not modify active Codex CLI\n  auth. Refreshed Codex CLI tokens are synced back to the selected saved\n  profile.\n- `shell` starts a temporary `CODEX_HOME` session and does not modify active\n  Codex CLI auth. Refreshed Codex CLI tokens are synced back to the selected\n  saved profile.\n- Env profiles store source env variable names for secrets, not secret values.\n  Secret values are resolved only when `exec` or `shell` starts.\n- Claude Code and Cursor Agent env sessions do not modify config files,\n  credential files, user data, or macOS Keychain entries.\n- Desktop app auth stores are read-only in current profile operations.\n- `remove` refuses to delete the active matching profile unless `--force` is\n  passed.\n- `restore` only accepts generated backup IDs in the form\n  `auth-\u003ctimestamp\u003e-\u003cpid\u003e.json`.\n- Claude Code, Cursor Agent, and desktop global login switching intentionally\n  return “not implemented yet” until their auth models are handled explicitly.\n- Codex CLI OAuth refresh tokens can rotate. Avoid running multiple concurrent\n  sessions for the same Codex profile unless you are ready to re-save the\n  profile from a fresh login.\n- Codex app/plugin connector OAuth tokens are not part of Codex CLI profile\n  snapshots and may need to be re-authenticated after switching accounts.\n\n## Development\n\nThis project uses [devenv](https://devenv.sh/) to provide a pinned Rust\ntoolchain matching `rust-version` in `Cargo.toml`.\n\n```sh\ndevenv shell\ncargo check\ncargo test\ncargo run -- status\n```\n\nCommon one-off checks can run without entering an interactive shell:\n\n```sh\ndevenv shell cargo check\ndevenv shell cargo fmt -- --check\ndevenv shell cargo clippy --all-targets -- -D warnings\ndevenv shell cargo test\ndevenv shell ci\n```\n\nIntegration tests run the real `aith` binary against temporary fake `AITH_HOME`,\n`CODEX_HOME`, `CLAUDE_CONFIG_DIR`, and `HOME` directories. They do not read or\nmodify real tool credentials.\n\n## Continuous Integration\n\nGitHub Actions runs the same checks as the local CI script on pushes to `main`\nand pull requests:\n\n```sh\ndevenv shell ci\n```\n\nThe workflow installs Nix and `devenv`, then runs the pinned Rust toolchain from\n`devenv.nix`.\n\nRelease automation uses `cargo-dist` through [dist-workspace.toml](dist-workspace.toml).\n\n## Project Structure\n\n- `src/cli.rs`: command parsing and user-facing output.\n- `src/doctor.rs`: read-only diagnostic report generation.\n- `src/profiles/`: shared profile storage, result types, validation, backups,\n  and filesystem safety helpers.\n- `src/tools/`: tool metadata and tool-specific adapters.\n- `src/tools/claude.rs`: Claude Code auth/config discovery and env-profile\n  sessions.\n- `src/tools/codex.rs`: Codex CLI auth/profile behavior.\n- `src/tools/cursor.rs`: Cursor Agent auth discovery and env-profile sessions.\n- `src/tools/desktop.rs`: read-only desktop app discovery.\n- `src/tools/env_session.rs`: shared env-profile session behavior.\n\n## Design Direction\n\n- Local-first: credentials never leave the machine.\n- Tool-native: use each upstream tool's supported auth and config mechanisms.\n- Explicit: profile switches should be visible and reversible.\n- Session-friendly: support one-command and shell-scoped temporary identities.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsadjow%2Faith","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsadjow%2Faith","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsadjow%2Faith/lists"}