Help us shape the future of Go! Take the 2026 Go Developer Survey

aiacc

command module
v0.22.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 3 Imported by: 0

README ΒΆ

aiacc

One command per AI-CLI account.

Keep your personal, work, and client accounts for Claude Code, Codex, and any other AI CLI side by side β€” each in its own isolated config β€” and launch any of them by name.

Live page: carlosdanieldev.github.io/aiacc

Release CI Go Platforms

$ claude-work        # opens Claude Code signed in as your work account
$ claude-personal    # …a different account entirely β€” no re-login, no juggling

Bare aiacc opens an interactive launcher:

┏━ AIACC ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                              ┃
┃   β–„β–€β–ˆ β–ˆ β–„β–€β–ˆ β–ˆβ–€β–€ β–ˆβ–€β–€                          ┃
┃   β–ˆβ–€β–ˆ β–ˆ β–ˆβ–€β–ˆ β–ˆβ–„β–„ β–ˆβ–„β–„                          ┃
┃   // launch a profile                        ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃  β–Έ claude-work          carlos@work.io       ┃
┃    claude-personal      not logged in        ┃
┃    ⚠ old                dir missing          ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃  β—† 3 profiles   βœ“ ready              v0.21.0 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  ↑↓ move  ⏎ launch  a add  r rename  e edit  h hand off  d remove  q quit

Hacker / matrix-terminal skin β€” phosphor green on black, a > prompt with a blinking cursor and cyan hotkeys, a Β» N profiles :: βœ“ READY status readout with the build version dim at its right edge, and a live AIACC logo (dark-green β†’ bright-green β†’ cyan sweep) that glitches in short data-tear bursts, plus a reverse-video glow on the selected row. Add / rename / edit / remove / hand off / setup all happen in-screen. Honors NO_COLOR.

Responsive β€” the frame follows the terminal: it grows and narrows with the width, re-measures live on resize, and a profile list taller than the window scrolls inside the box (β–² n above Β· β–Ό n below) instead of spilling out of it.


✨ Why aiacc

  • πŸ”€ One command per account β€” claude-work opens Claude Code signed into that account. No env juggling, no re-login.
  • ⚑ One-step setup β€” aiacc setup installs the commands onto your PATH; they work immediately, in the shell you're already in. No sourcing, no reload.
  • 🧭 Interactive picker β€” a bare aiacc gives you an arrow-key list to launch, add, rename, or remove accounts.
  • 🧩 Same skills everywhere β€” every profile shares your skills, sub-agents, slash commands and hooks, so claude-work is the same tool as claude, not an empty one.
  • πŸ”’ Never touches your credentials β€” aiacc only points an environment variable at a config directory; each account's login stays in its own dir.
  • πŸͺΆ Nothing to install at runtime β€” a single static Go binary, with no runtime or helper to set up alongside it.
  • πŸ›Ÿ Hard to misuse β€” junk names can't be entered, broken profiles can't be launched, and destructive actions ask first.
How it works (one generic mechanism)

Each account is an isolated config directory, selected by an environment variable. Claude Code reads CLAUDE_CONFIG_DIR; point it at ~/.claude-work and Claude runs as your work account, at ~/.claude-personal and it's the personal one. aiacc registers those directories and installs a launcher command per account that runs CLAUDE_CONFIG_DIR=<dir> claude for you β€” scoped to that one launch, with no global state to get out of sync.

πŸ“¦ Install

# Go toolchain
go install github.com/CarlosDanielDev/aiacc@latest

# Install script (latest release binary β†’ /usr/local/bin or ~/.local/bin)
curl -fsSL https://raw.githubusercontent.com/CarlosDanielDev/aiacc/main/install.sh | sh

πŸš€ Quick start

# 1 Β· Add a couple of accounts (run `aiacc` and press `a`, or use flags):
aiacc add claude claude-work     --dir ~/.claude-work
aiacc add claude claude-personal --dir ~/.claude-personal

# 2 Β· Install the launcher commands β€” one step, works right away:
aiacc setup

# 3 Β· Launch by name:
claude-work

The name you give an account is its launcher command β€” so name it how you want to type it (claude-work, claude-client-x, …). Names are limited to letters, digits, - and _, since they must be valid shell command names.

The first time you launch a fresh account, Claude Code opens signed out β€” run /login inside it once, and that account's directory remembers it from then on.

⚑ Setup, in one step

aiacc setup

That's the whole thing. aiacc setup installs a small executable per account (claude-work, …) into a directory on your PATH, so the commands work immediately, in the shell you're already in β€” no sourcing, no reload, no new terminal. It's idempotent (safe to re-run), and aiacc add / aiacc remove / aiacc rename keep the commands in sync automatically.

In the rare case that no writable directory is already on your PATH, aiacc installs into ~/.local/bin and adds it to your PATH β€” the one situation where you'll open a new terminal to finish.

Migrating from aiacc shell-init?

shell-init is retired and prints only a comment. If your startup file still has an eval "$(aiacc shell-init …)" line, replace it with aiacc setup and delete the line. Open a new terminal to pick it up.

🧩 Same skills in every profile

A profile is an isolated config directory β€” and everything the CLI discovers lives in that directory. Point CLAUDE_CONFIG_DIR somewhere new and Claude Code starts with no skills, no sub-agents, no slash commands and no CLAUDE.md: the same binary, a much emptier tool.

aiacc setup fixes that in the same step, and aiacc link does it on demand:

aiacc link                    # share with every profile
aiacc link claude work        # …or just one
aiacc link --replace          # take over entries a profile already has

It symlinks your authored assets out of the CLI's own config dir, so they stay in one place β€” edit a skill once and every profile has it:

Provider Shared
claude (~/.claude) skills/ Β· agents/ Β· commands/ Β· hooks/ Β· output-styles/ Β· plugins/ Β· CLAUDE.md Β· settings.json
codex (~/.codex) prompts/ Β· AGENTS.md

What is never shared: credentials, projects/ transcripts, history.jsonl, usage counters β€” isolating those is the whole point of a profile.

Nothing is overwritten. An entry a profile already has of its own is left exactly as it is and reported instead. --replace opts into taking it over, and even then the original is renamed to <name>.aiacc-bak first (.aiacc-bak2, .aiacc-bak3, … when one is already there β€” the report names the path chosen), never deleted. Custom (non-preset) providers are skipped β€” aiacc doesn't guess at a CLI's asset layout.

πŸ”‘ A profile with its own endpoint

Some profiles differ in what they talk to, not who is logged in: Claude Code pointed at GLM, a proxy, or a gateway through an env block in a settings file. That block can't go in the shared settings.json, because every profile would pick it up β€” the profile needs a settings file of its own.

The easy way is to let aiacc write it. Run aiacc, press a, name the profile, and put glm in its settings field. aiacc generates ~/.claude-glm/glm.json with the GLM endpoint already filled in and a placeholder where your key goes, created chmod 600:

{
  "env": {
    "ANTHROPIC_AUTH_TOKEN": "PASTE-YOUR-KEY-HERE",
    "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
    "ANTHROPIC_CUSTOM_MODEL_OPTION": "glm-5.3-flash[1m]",
    "ANTHROPIC_CUSTOM_MODEL_OPTION_NAME": "GLM 5.3 Flash 1M (z.ai)",
    "ANTHROPIC_MODEL": "glm-5.3-flash[1m]"
  }
}

Open the file it names, paste your API key over the placeholder, and launch β€” claude-glm now talks to GLM from any directory. custom is the other preset: the same step, with the base URL left blank for you to fill in (add any model fields yourself). A settings file that is already there aborts the create β€” nothing is overwritten, ever.

Anything the presets don't cover, write the file yourself and hand aiacc the path. glm works on the command line too β€” --settings glm generates the same skeleton non-interactively (an existing file aborts, nothing is overwritten), while custom stays picker-only, since its blank base URL is yours to type in:

aiacc add claude claude-glm --dir ~/.claude-glm --settings glm                     # generate it
aiacc add claude claude-glm --dir ~/.claude-glm --settings ~/.claude-glm/glm.json # or hand-write it
{ "env": { "ANTHROPIC_BASE_URL": "…", "ANTHROPIC_AUTH_TOKEN": "…", "ANTHROPIC_MODEL": "…" } }

Either way, the launcher runs claude --settings ~/.claude-glm/glm.json, which layers that file over the shared settings, so claude-glm keeps your skills, hooks and statusline and talks to its own endpoint from any directory.

aiacc stores only the path and never reads the file on add, launch or doctor β€” your key never passes through aiacc unless you ask. e in the picker (edit) reads the file and rewrites only ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL and ANTHROPIC_MODEL, keeping every other key. The token is never shown: an empty token field keeps the key already there, and a file that isn't valid JSON is refused with nothing written. The file stays 0600 (never wider). Keep it private (chmod 600); aiacc doctor warns when it isn't and fails when it's missing.

πŸŽ›οΈ Commands

Command What it does
aiacc The interactive picker (front door). Piped/redirected, it prints help instead.
<account> Β e.g. claude-work Launch Claude Code in that account (installed by aiacc setup).
aiacc setup One-step install of the launcher commands onto your PATH β€” they work immediately.
aiacc add [provider] [account] --dir <path> Register an account (framed screen with no args in a terminal). Creates the dir if missing. --quota N sets an optional manual plan size. For a non-preset provider, add --env <ENV_VAR> --command <cli>. --settings <file> gives the profile its own settings file β€” or --settings glm generates a skeleton for you; an existing file is never overwritten (claude).
aiacc rename <provider> <old> <new> Rename an account and its launcher command, keeping its directory. (picker: r)
aiacc remove <provider> <account> Unregister an account; leaves the directory in place. (picker: d)
aiacc handoff [provider] [from] [to] Copy a session between accounts to resume it there β€” Claude profiles only for now, the transcript format is Claude's. No args β†’ interactive picker; --session <id>, --launch. (picker: h)
aiacc ai-memory <account> [args...] Run a claude or codex account under ai-memory, with its launcher and config dir set. Arguments after the account go to ai-memory, which passes them to the CLI except its own wrapper flags (--yolo, --fresh, …). See below.
aiacc link [provider] [account] Share your skills, sub-agents, commands and hooks with a profile (all of them by default). --replace takes over entries a profile owns; --prune removes dead links (asks first).
aiacc list Table of providers and their accounts. --status adds the active config dir and last-used time; --usage adds token totals and USED/QUOTA (- until the account has a --quota) from local session logs, so it is opt-in.
aiacc doctor Check that your launchers still work: duplicate installs, alias-only installs, stale launchers, dead shared links. Read-only; exits non-zero when something is broken.

βš™οΈ Configuration

State lives in a single TOML file at ~/.config/aiacc/config.toml ($XDG_CONFIG_HOME is honored). add / remove / rename write it for you, but it's plain text you can edit by hand:

[providers.claude]
env_var = "CLAUDE_CONFIG_DIR"

[providers.claude.accounts.claude-personal]
dir = "~/.claude-personal"

[providers.claude.accounts.claude-work]
dir = "~/.claude-work"

A leading ~ in a dir or settings path expands to your home directory. A missing config file is treated as empty, so read-only commands work before you register anything.

Writes are serialized through a config.toml.lock sibling that appears next to the file during mutations and is left in place (empty and harmless) afterwards. A config holding keys this version of aiacc doesn't know β€” say, written by a newer release or by hand β€” refuses to be overwritten by add / remove / rename, with the keys named, so nothing is silently dropped.

🎬 Tutorials

1 Β· Two accounts in a minute
# Register work + personal (each gets its own isolated config dir):
aiacc add claude claude-work     --dir ~/.claude-work
aiacc add claude claude-personal --dir ~/.claude-personal

# Install the launcher commands (one step, works immediately):
aiacc setup

# Launch β€” the first run opens Claude signed out; do /login once:
claude-work        # β†’ /login as work
claude-personal    # β†’ /login as personal

From now on, claude-work always opens Claude Code as work, claude-personal as personal. No switching, no re-login.

2 Β· Hit a usage limit? Continue on your other account

You're deep in a conversation on claude-work and it hits the cap. Hand the exact session to claude-personal and keep going:

aiacc handoff              # interactive: pick source β†’ session β†’ target
# or go straight there:
aiacc handoff claude claude-work claude-personal --launch

It copies just the session transcript into the other account and resumes it β€” same context, now billed to personal. Claude profiles only for now β€” the transcript format is Claude's. (In the picker, press h on the source account.)

3 Β· Rename a command

Named it claude-work but want claude-acme? In the picker, highlight it and press r β€” or:

aiacc rename claude claude-work claude-acme

The account, its directory, and the launcher command all move together; the old claude-work command is removed.

4 Β· Add a client account later
aiacc add claude claude-acme --dir ~/.claude-acme

The claude-acme command is created immediately (no re-setup needed), and shows up in the picker next time you run aiacc.

⌨️ Picker keys
Key Action Key Action
↑ ↓ / j k move a add a profile
⏎ launch the selected profile r rename
e edit endpoint, model or key h hand off a session
d remove (asks first) s run setup
q quit

On any screen that ends in a command to run β€” the hand-off result, for one β€” ctrl-c copies it to your clipboard instead of closing (q still closes). Uses pbcopy, wl-copy, xclip or xsel, whichever you have.

πŸ”— Share a session across accounts

Hit a usage limit mid-conversation? Hand the exact session to another account and keep going:

$ aiacc handoff claude claude-work claude-personal
Handed off session 2f1c… β†’ claude-personal
  "Fix the launcher"
Resume it:
  cd ~/projects/aiacc && claude-personal --resume 2f1c…

The interactive hand-off ends on a screen with the resume command and a [ ] bypass permissions checkbox. Unattended runs can need the CLI's bypass flag (--dangerously-skip-permissions for Claude Code), so space or b checks it: the command shown and the one ctrl-c copies then include the flag, and a warning line appears. It is off by default, and aiacc never saves the choice or adds the flag to a launcher.

Claude Code keeps each session as a transcript at <config-dir>/projects/<cwd>/<id>.jsonl. handoff copies that transcript into the target account (preserving its project directory) and prints the exact resume command β€” --launch runs it for you, or ctrl-c on the result screen copies it. Only the transcript moves; credentials are never touched, and each account's usage stays separate. It defaults to the most recent session; --session <id> picks a specific one.

A hand-off copies the main session transcript only, not the subagents/ run files. A subagent that had already finished has its final report in that transcript. A subagent still running or paused when you hand off does not resume in the new account, and you should not expect a notification from it after --resume; re-run it there if you still need its result.

🧠 Run an account under ai-memory

ai-memory keeps a managed workstream across sessions, but it reads a name like claude-glm as a label only: on its own it runs plain claude and looks for sessions in ~/.claude. aiacc ai-memory passes the account's launcher and config dir for you:

$ aiacc ai-memory claude-glm --dangerously-skip-permissions --resume 2f1c…

It runs ai-memory run --env CLAUDE_CONFIG_DIR=<account dir> --executable claude-glm claude-glm …, passes the arguments after the account on to ai-memory unchanged, and exits with the status the CLI leaves (128 plus the signal number when a signal ends it). Ctrl-C goes to the CLI through the terminal, as usual, and aiacc keeps waiting for it; a terminate or hangup signal sent to aiacc is passed on to the CLI. Codex accounts work the same way with CODEX_HOME. It needs ai-memory on your PATH and the account's launcher (aiacc setup). When ai-memory is on your PATH, the hand-off screen also shows this command.

By hand, the equivalent is ai-memory run --env CLAUDE_CONFIG_DIR=$HOME/.claude-glm --executable claude-glm claude-glm. ai-memory still takes its own wrapper flags (such as --yolo and --fresh) from the arguments it receives, so those do not reach the CLI.

πŸ”Œ Providers β€” any AI CLI

A provider is {env_var, command} plus its accounts: aiacc isolates each account in its own directory, points the CLI's config-dir env var at that directory, and runs the command there. Built-in presets:

Provider Env var Command
claude CLAUDE_CONFIG_DIR claude
codex CODEX_HOME codex

Any other CLI that selects its config through an environment variable works too β€” just give the env var and command the first time you add one for that provider:

aiacc add glab work --dir ~/.glab-work --env GLAB_CONFIG_DIR --command glab
#         provider account                    ^env var        ^cli to launch
# β†’ a `work` command that runs: GLAB_CONFIG_DIR=~/.glab-work glab

In the picker, pressing a lets you choose the provider (presets + any you've already configured) and defaults the directory to ~/.<provider>-<name>. A brand-new custom provider is added with the --env/--command form above.

Session hand-off is Claude-specific for now β€” it reads Claude Code's transcript format. Launch, add, rename, remove, and setup work for every provider.

🩺 Will my launchers still work?

A launcher resolves its command by name, at run time β€” that is what lets Claude Code self-update without breaking anything. The cost is that it goes quietly wrong when the ground shifts: a second claude appears on PATH and version order is decided by luck, claude migrate-installer turns the command into a shell alias a /bin/sh script cannot see, or a shared symlink outlives the directory it pointed at.

None of those look like failures. aiacc doctor makes them visible:

$ aiacc doctor
Commands
  ! claude: 2 installs of claude on PATH
      launchers run ~/.local/bin/claude (2.1.258 (Claude Code))
      also on PATH: /opt/homebrew/bin/claude (2.1.220 (Claude Code))
      PATH order alone decides which one runs, so an update to either can
      invert it silently. Put the one you want earlier on PATH, or remove
      the other install.

Launchers
  βœ“ claude-work β†’ claude CLAUDE_CONFIG_DIR=~/.claude-work
  βœ— claude-old: launcher is stale
      It no longer matches the config: should run claude with CLAUDE_CONFIG_DIR=~/.claude-old.
      aiacc setup  rewrites it

Shared assets
  βœ— claude-work: 1 dead shared link(s)
        skills
      They point into ~/.claude at names that no longer exist β€”
      the CLI is handed a broken path as if it were an asset.
      aiacc link --prune  removes them (it asks first)

βœ— 2 broken, 1 to look at.

It changes nothing, and exits non-zero only when something is actually broken β€” so it works in a shell startup file or a CI step:

aiacc doctor || echo "aiacc: profiles need attention"

🩺 Troubleshooting

claude-work: command not found

The launcher commands aren't installed yet, or the shell they were installed for isn't this one. Run aiacc setup (it prints where it put them and whether they work now). If it had to add a directory to your PATH, open a new terminal.

claude works when I type it, but a launcher says not found

claude is a shell alias, not a file on PATH β€” claude migrate-installer sets it up that way. Launchers are /bin/sh scripts and have no aliases, so they cannot see it. Run aiacc doctor: it finds the real binary (usually ~/.claude/local/claude) and names the directory to add to your PATH, so your shell and your launchers agree on which install they mean.

Upgraded from an old version and see unknown flag: --shell

A pre-v0.7 shell hook is still loaded. Just run aiacc (it prints the fix) or open a new terminal β€” the launcher commands replace the old hook.

A profile shows ⚠ no launcher in the picker

The profile's provider has no launch command configured. claude and codex ship with one; any other CLI gets one when you give it --command. Re-running aiacc add <provider> <account> --dir <path> --env <ENV_VAR> --command <cli> sets it, and the profile is then launchable. Until then it stays registered, and aiacc shows why it is blocked.

A background subagent never finished after a hand-off

A hand-off copies the main session transcript only. A subagent that had already finished has its final report there. A subagent that was still running or paused when you handed off does not resume in the new account, and you should not expect a notification from it after --resume. Re-run it in the new account if you still need its result.

🀝 Contributing

Public and open to contributions. Read CONTRIBUTING.md and the architecture decision records first.

πŸ“„ License

MIT Β© CarlosDanielDev

Documentation ΒΆ

Overview ΒΆ

Command aiacc switches and monitors multiple AI-CLI accounts via per-account config directories and environment variables.

Directories ΒΆ

Path Synopsis
internal
claude
Package claude reads the non-secret account identity (email, display name, organization) that Claude Code records for a config directory, so aiacc can show which account a directory is logged in as.
Package claude reads the non-secret account identity (email, display name, organization) that Claude Code records for a config directory, so aiacc can show which account a directory is logged in as.
cli
Package cli wires the aiacc command tree.
Package cli wires the aiacc command tree.
config
Package config persists aiacc providers and accounts as TOML.
Package config persists aiacc providers and accounts as TOML.
fsutil
Package fsutil holds the file-system helpers that more than one package needs.
Package fsutil holds the file-system helpers that more than one package needs.
provider
Package provider resolves env vars and account directories, merging built-in presets with user config (ADR-0002).
Package provider resolves env vars and account directories, merging built-in presets with user config (ADR-0002).
session
Package session reads and moves Claude Code session transcripts, which live at <CLAUDE_CONFIG_DIR>/projects/<cwd-dir>/<sessionId>.jsonl.
Package session reads and moves Claude Code session transcripts, which live at <CLAUDE_CONFIG_DIR>/projects/<cwd-dir>/<sessionId>.jsonl.
share
Package share links a provider's *authored* assets β€” skills, sub-agents, slash commands, hooks, instructions, settings β€” from the CLI's own config directory into each account's isolated directory.
Package share links a provider's *authored* assets β€” skills, sub-agents, slash commands, hooks, instructions, settings β€” from the CLI's own config directory into each account's isolated directory.
shell
Package shell builds the per-profile launcher scripts that `aiacc setup` installs onto PATH.
Package shell builds the per-profile launcher scripts that `aiacc setup` installs onto PATH.
tui
Package tui renders aiacc's interactive profile launcher: a framed, poka-yoke terminal UI shown by a bare `aiacc`.
Package tui renders aiacc's interactive profile launcher: a framed, poka-yoke terminal UI shown by a bare `aiacc`.
usage
Package usage parses Claude Code JSONL session logs and aggregates token counts.
Package usage parses Claude Code JSONL session logs and aggregates token counts.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL