textaccounts
Manage multiple Claude Code accounts with full directory isolation. Each profile is a complete ~/.claude/ config directory — sessions, memory, settings, and auth stay separate.
Why?
Claude Code stores everything in a single directory tree (~/.claude/). If you use multiple accounts (work + personal), you need separate directories. textaccounts registers and switches between them by setting CLAUDE_CONFIG_DIR.
Install
pip install textaccounts
Then install shell integration:
textaccounts install
This writes a fish function and completions to ~/.config/fish/. Open a new shell to activate.
Quick start
# Register existing directories — nothing is moved or copied
textaccounts adopt work ~/.claude-work
textaccounts adopt personal ~/.claude-personal
# Switch profile (sets CLAUDE_CONFIG_DIR in your shell)
textaccounts switch work
# Check status
textaccounts status
# Interactive view
textaccounts view
Commands
textaccounts list # show all profiles
textaccounts status # active profile + sync state
textaccounts adopt <name> <path> # register an existing dir
textaccounts create <name> # snapshot current config dir
textaccounts create <name> --shallow \
--from <parent> # shallow clone — copy only .claude.json + settings.json
textaccounts create <name> \
--clone-from <src> # deep clone — auth + settings + agents/hooks/plugins,
# strip state (sessions/projects/history/caches)
textaccounts create <name> --shallow \
--from <parent> --ephemeral \
[--owner <run-id>] # mark for sweep by `gc` / `destroy`
textaccounts gc [--max-age 7d] \
[--owner <run-id>] [--dry-run] # sweep ephemeral profiles older than max-age
textaccounts destroy <name> # remove a single ephemeral profile
textaccounts adopt-token <name> \
[--path <dir>] # register a token-auth profile (CLAUDE_CODE_OAUTH_TOKEN)
textaccounts switch <name> # switch profile (sets CLAUDE_CONFIG_DIR)
textaccounts show <name> # print shell command without executing
textaccounts rename <old> <new> # rename a profile
textaccounts alias <profile> <alias> # add a shorthand alias
textaccounts describe <name> [text] # set/clear a per-profile description (omit text to clear)
textaccounts desc # print current profile's description (for statuslines)
textaccounts view # interactive profile view
textaccounts doctor # check stale paths + Claude Code version
textaccounts install [--shell fish] # install shell integration
textaccounts export [output.zip] # export registry + settings to encrypted zip
textaccounts import <backup.zip> # import profiles from an export zip
Export and import
textaccounts export creates a password-protected AES-256 zip containing your
profiles.yaml registry and each profile's .claude.json and settings.json.
A .sha256 hash file is written alongside for integrity verification.
Auth tokens are not included — they live exclusively in the macOS Keychain
and are never written to disk by textaccounts.
# Export (password prompted)
textaccounts export
# → textaccounts-20260514.zip
# → textaccounts-20260514.zip.sha256
# Export to a specific path
textaccounts export ~/backups/ta-backup.zip
# Import on another machine (password prompted, skips existing profiles)
textaccounts import ta-backup.zip
# Import and overwrite any conflicting profiles
textaccounts import ta-backup.zip --overwrite
After importing, run textaccounts switch <name> for each profile and
re-authenticate via /login — Keychain tokens are machine-local.
Shallow clones and ephemeral lifecycle
--shallow --from <parent> creates a minimal copy: just .claude.json and
settings.json, no agents/, hooks/, plugins/, sessions/, etc. Useful
when an orchestrator (e.g. a parallel-agents batch leader) needs many isolated
worker profiles cheaply. --clone-from <src> is the deeper variant that also
copies agents/, hooks/, plugins/, and symlinks.
Disposable runs. Add --ephemeral (or --owner <run-id>, which implies
ephemeral) to flag the profile for cleanup:
# Orchestrator: spawn a worker for a specific run-id
textaccounts create bot-1 --shallow --from work --owner run-42
# When the run is done, sweep everything it created
textaccounts gc --owner run-42
# Or destroy a single one immediately
textaccounts destroy bot-1
gc defaults to --max-age 7d and ignores anything not flagged
ephemeral: true — so it can't accidentally remove your real profiles. Every
removal is appended to ~/.local/state/textaccounts/gc.log for auditing.
Token-auth profiles
Some Claude accounts use a long-lived CLAUDE_CODE_OAUTH_TOKEN (service-account style) instead of the interactive OAuth flow. textaccounts supports these as first-class profiles — the token is stored in the macOS Keychain and injected automatically at switch time.
# Register a token-auth profile (you will be prompted for the token, no shell history)
textaccounts adopt-token my-service-account
# Optionally specify a config dir (created if absent)
textaccounts adopt-token my-service-account --path ~/.claude-svc
# Switch — injects both CLAUDE_CONFIG_DIR and CLAUDE_CODE_OAUTH_TOKEN into your shell
textaccounts switch my-service-account
# The profile shows [token-auth] in the list
textaccounts list
The config dir (~/.claude-<name> by default) still holds settings, sessions, and MCP config — only the auth part changes. Tooling that calls env_for_profile("my-service-account") gets both CLAUDE_CONFIG_DIR and CLAUDE_CODE_OAUTH_TOKEN automatically.
To rotate the token, run adopt-token again with a new value (coming in a future release; for now, delete and re-adopt the profile).
Per-profile descriptions
Each profile can carry a free-text description (a one-liner like "day job" or
"hobby + paperworlds"). It shows up:
- In the interactive view bottom bar when a profile is highlighted (
nto edit) - In your Claude Code statusline via
textaccounts desc, which resolves the description for the currentCLAUDE_CONFIG_DIR— so subprocesses launched by tools liketextsessionsshow the right description automatically
Wire it into your statusline script:
ta_desc=$(textaccounts desc 2>/dev/null)
[ -n "$ta_desc" ] && parts+=("$ta_desc")
Interactive view
textaccounts view provides a Textual TUI for managing profiles:
| Key | Action |
|---|---|
s |
Switch to selected profile |
a |
Adopt a new directory |
r |
Rename selected profile |
l |
Edit aliases |
n |
Edit description (shown in bottom bar) |
q |
Quit |
Auto-discovers unregistered ~/.claude*/ directories and shows them as adoption suggestions.
Config
Profiles are stored in ~/.textaccounts/profiles.yaml:
version: '1.0'
active: work
profiles:
work:
path: /Users/you/.claude-work
email: yo***@company.com
adopted: 2026-04-12T10:00:00Z
worker: false
description: day job
personal:
path: /Users/you/.claude-personal
email: y***@gmail.com
adopted: 2026-04-12T10:00:00Z
worker: false
description: hobby projects
aliases:
- p
defaults:
profiles_dir: ~/.textaccounts/profiles
New profiles created with textaccounts create go into ~/.textaccounts/profiles/.
How it works
textaccounts switch sets CLAUDE_CONFIG_DIR in your shell via a fish function that evals the output of textaccounts show. A Python subprocess can't modify the parent shell's environment directly — the fish function bridges that gap.
Claude Code reads CLAUDE_CONFIG_DIR natively. No patches, no wrappers around claude itself.
Public API
textaccounts.api is the stable import surface for tools that integrate with
textaccounts (see textsessions for an example consumer). Functions:
available, list_profiles, active_profile, profile_dir, env_for_profile,
profile_description. Full contract: docs/specs/textaccounts-api.md.
Roadmap
- Publish to PyPI (under Paperworlds org — account TBD)
- Upgrade to Python 3.13
-
dkey in view to remove/unregister a profile - Bash/zsh shell integration (currently fish only)
License
MIT
Metadata
Release files for textaccounts 0.5.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| textaccounts-0.5.3.tar.gz | 61.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| textaccounts-0.5.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 88.9 kB
Release files / textaccounts-0.5.3.tar.gz
| Download URL | textaccounts-0.5.3.tar.gz |
|---|---|
| Size | 61.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b90e083b6015f3415f0930764cc3ac745ab92ef146e75826882d9e00f6d9dd73
|
|
BLAKE2b-256 checksum How to use checksums |
3209356d398a1954959b73dd5b65065fa152aeaa34014d88aebaf0baf0afb449
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / textaccounts-0.5.3-py3-none-any.whl
| Download URL | textaccounts-0.5.3-py3-none-any.whl |
|---|---|
| Size | 27.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a87e0372f3039aa106f851df9f9a1c559ea8834532497df9036cecc52a74eb98
|
|
BLAKE2b-256 checksum How to use checksums |
b356bb504178e83ceb7c2a87adf93e1da4e818c5c7e3cec63721d31d6514c1ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for textaccounts 0.5.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.