{"slug": "running-multiple-claude-code-and-codex-accounts-on-one-machine", "title": "Running multiple Claude Code and Codex accounts on one machine", "summary": "A developer shared a guide for running multiple Claude Code and Codex accounts on a single machine by using separate configuration directories and shell aliases. The approach isolates settings, plugins, and sessions per account, preventing cross-account data leaks and accidental API key usage.", "body_md": "Running multiple Claude Code and Codex accounts on one machine\n\nTip\n\nKeep your personal, work, and admin accounts signed in at once. Each command starts the CLI with its own settings folder, so you never switch accounts and never log in twice.\n\n**What you end up with**\n\n- One folder per account, so nothing leaks between them.\n- A short command for each account, which picks that folder for a single launch.\n- No stray API key reaching Codex when you meant to use your ChatGPT plan.\n\n[How isolation works](#how-isolation-works)[Before you begin](#before-you-begin)[Set up profiles](#set-up-profiles)[Daily use](#daily-use)[Calling this from mobile or a desktop app](#calling-this-from-mobile-or-a-desktop-app)[Running sessions in parallel](#running-sessions-in-parallel)[Agent-to-agent messaging](#agent-to-agent-messaging)[Invoking one CLI from the other](#invoking-one-cli-from-the-other)[Command reference](#command-reference)[Troubleshooting](#troubleshooting)[Operational notes](#operational-notes)\n\nWhen either CLI starts, it picks one folder to work from. That folder holds the account's settings, its plugins, its MCP servers, its hooks, and its past sessions. The command you type picks the folder for that one launch, and it leaves your other terminals alone.\n\n| CLI | Selector | Default profile directory |\n|---|---|---|\n| Claude Code | `CLAUDE_CONFIG_DIR` |\n`~/.claude` |\n| Codex | `CODEX_HOME` |\n`~/.codex` |\n\n``` php\nflowchart LR\n    T[Terminal] --> P[plain command]\n    T --> W[work alias]\n    T --> A[admin alias]\n    P --> CP[default profile root]\n    W --> CW[work profile root]\n    A --> CA[admin profile root]\n    classDef terminal fill:#24292f,stroke:#8b949e,color:#ffffff\n    classDef profile fill:#0a3069,stroke:#54aeff,color:#ffffff\n    classDef work fill:#116329,stroke:#56d364,color:#ffffff\n    classDef admin fill:#9a6700,stroke:#e3b341,color:#ffffff\n    class T terminal\n    class P,CP profile\n    class W,CW work\n    class A,CA admin\n```\n\nNote\n\nThe `~`\n\nin these paths means your home folder. On a Mac, `~/.codex-work`\n\nis really `/Users/yourname/.codex-work`\n\n. Names that start with a dot stay hidden in Finder, which is normal.\n\nThis guide assumes macOS or Linux with zsh. If you use Bash, everything works the same, but edit `~/.bashrc`\n\ninstead of `~/.zshrc`\n\n.\n\n```\necho $SHELL\nclaude --version\ncodex --version\n```\n\nImportant\n\nOnly set up profiles for accounts you are allowed to use. A profile keeps things separate on your own machine. It has no effect on what an account is permitted to do, and it will not get you around workspace rules or usage limits.\n\nIf you have never signed in, do that first with the plain commands. Whatever you sign in as here becomes your default account.\n\n```\nclaude auth login\ncodex login --device-auth\n```\n\nThe examples below add two accounts called `work`\n\nand `admin`\n\n. Call yours whatever you like, as long as you use the same names throughout. The Claude Code and Codex halves do not depend on each other, so do one, the other, or both, in whichever order suits you.\n\n```\nmkdir -p ~/.claude-work ~/.claude-admin\nls -d ~/.claude*\n```\n\n`mkdir -p`\n\nprints nothing when it works, and it will not complain if the folders already exist.\n\nOpen your shell configuration:\n\n```\nopen -e ~/.zshrc\n```\n\nAdd this block at the bottom:\n\n```\n# Claude Code: default remains ~/.claude\nalias claude-work='CLAUDE_CONFIG_DIR=\"$HOME/.claude-work\" command claude'\nalias claude-admin='CLAUDE_CONFIG_DIR=\"$HOME/.claude-admin\" command claude'\n```\n\n**Why**\n\n`command claude`\n\nmatters`command`\n\nskips over aliases and runs the installed program directly. Without it, an alias can end up calling itself forever.\n\nWarning\n\nDo not put `export CLAUDE_CONFIG_DIR=...`\n\non a line of its own. That applies to every command in every new terminal, and it quietly moves your default account too. An alias sets the folder for one launch and nothing else.\n\n```\nsource ~/.zshrc\nclaude-work auth login\nclaude-admin auth login\n```\n\nSign in to each one with the account you actually want. If your browser is still signed in from the previous login, sign out first, or open the link in a private window, or keep a separate browser profile per account.\n\n```\nclaude auth status --text\nclaude-work auth status --text\nclaude-admin auth status --text\n```\n\nEach command should name the account you expect. If two of them show the same person, sign out of only the one that is wrong and log in again:\n\n```\nclaude-work auth logout\nclaude-work auth login\n```\n\nCodex works the same way, using `CODEX_HOME`\n\n. It creates the folder for you the first time you sign in, so there is nothing to make by hand.\n\nOpen `~/.zshrc`\n\nand add:\n\n```\n# Codex: default remains ~/.codex. Each wrapper removes shell API credentials.\nalias codex='env -u OPENAI_API_KEY -u CODEX_API_KEY -u CODEX_ACCESS_TOKEN command codex'\nalias codex-work='env -u OPENAI_API_KEY -u CODEX_API_KEY -u CODEX_ACCESS_TOKEN CODEX_HOME=\"$HOME/.codex-work\" command codex'\nalias codex-admin='env -u OPENAI_API_KEY -u CODEX_API_KEY -u CODEX_ACCESS_TOKEN CODEX_HOME=\"$HOME/.codex-admin\" command codex'\n```\n\nImportant\n\nThe `env -u`\n\nentries only affect the Codex process being launched. Your shell keeps its variables, and so does everything else on the machine.\n\nReload the aliases:\n\n```\nsource ~/.zshrc\ncodex-work login --device-auth\ncodex-admin login --device-auth\n```\n\nCodex prints a one-time code and a link. Open the link, type the code, and approve it with the account you meant to use. If the browser is already signed in as somebody else, use a private window or a second browser profile.\n\n```\ncodex login status\ncodex-work login status\ncodex-admin login status\n```\n\nEach profile should report `Logged in using ChatGPT`\n\n.\n\nNote\n\n`codex login status`\n\nconfirms the login method and state; it does not print the account email. Keep the browser authorization flows separate and label profile directories clearly. Separate profile roots and separate successful device-auth flows establish the intended isolation.\n\n**Inspect the three separate Codex roots**\n\nThis shows that each command really does use its own folder. It will not tell you which account is signed in, since the login you completed is what decides that.\n\n```\nls -la ~/.codex/auth.json ~/.codex-work/auth.json ~/.codex-admin/auth.json\n```\n\nFor current subscription access, plan limits, and workspace controls, see [Using Codex with your ChatGPT plan](https://help.openai.com/en/articles/11369540-using-codex-with-your-chatgpt-plan).\n\nThere is no switch command. Start the account you want:\n\n```\nclaude             # default identity\nclaude-work        # work identity\nclaude-admin       # admin identity\n\ncodex              # default identity\ncodex-work         # work identity\ncodex-admin        # admin identity\n```\n\nThis guide is not CLI-only in practice. A mobile client or a desktop app's session, running on the same host as these aliases, already carries a shell tool — the same `bash`\n\nany CLI agent uses. Every command in this guide is nothing more than a shell command. There is no bridge, skill, or MCP server to build: you set up the aliases once on the host, exactly as described above, then tell the mobile or desktop session to run them there.\n\n```\nRun `codex-work exec --sandbox read-only -o /tmp/review.txt \"<delegation prompt>\"` on the host, then read back /tmp/review.txt for me.\n```\n\nThat instruction works from a phone or a desktop app exactly as it works typed into a terminal, because it is the same alias, run the same way, by a session that already knows how to call `bash`\n\n.\n\nImportant\n\nThis depends on the mobile or desktop session actually running on the host where the aliases live, with shell access to it. A session that only runs in a remote sandbox or on a different machine has no path to your local `~/.zshrc`\n\naliases — SSH into the host first, or give the session the full command inline instead of the alias name.\n\n**But what if I really need this app-to-app — can't you just build me an MCP server or a bridge?**\n\nNo.\n\n`bash`\n\nalready does this. The mobile client, the desktop app, the CLI — every one of them can already run a shell command on the host, which means every one of them can already run `codex-work exec`\n\nor `claude-work -p`\n\n. An MCP server or a bridge protocol would be a second, worse implementation of a shell call: its own transport, its own auth, its own version skew, its own outage, maintained forever, to reach a command that was already one message away.\n\nThere is exactly one situation this doesn't cover: a client with no shell access to the host at all. The fix there is `ssh`\n\n, not a protocol.\n\nIf \"tell the session to run the alias\" is somehow not a satisfying enough answer and what you actually wanted was a system to design, that's a hobby, not a requirement — and if you can't tell the difference, the agent was never the bottleneck.\n\n🤡 honk honk 🔴\n\nTip\n\n**You never log out to change accounts.** Open another terminal tab and run a different command. Both sessions keep going, both stay signed in, and neither one bothers the other.\n\nEvery launch is a separate process. The profile folder keeps logins and settings apart, but it does nothing about the things sessions share: services they both call, workspace resources, or the CLI's own session service. Stay inside what your plan, your organization, and your machine can actually take.\n\nFour tabs might look like this:\n\n| Tab | Command | Identity | Task |\n|---|---|---|---|\n| 1 | `claude` |\ndefault | Personal repository |\n| 2 | `claude-work` |\nwork | Work ticket |\n| 3 | `codex-work` |\nwork | Second opinion on the same ticket |\n| 4 | `claude-admin` |\nadmin | Scheduled maintenance |\n\n**Different profiles on one machine.** Logins and settings are kept apart by design.**Several sessions on one profile.** Fine where your CLI version and your plan allow it, and each session keeps its own context.**Both CLIs on the same task.** Useful when you want one agent checking the other's work.\n\nWarning\n\nProfiles separate **settings and accounts**. They do nothing about the **filesystem**. Two sessions pointed at the same working directory will overwrite each other, whichever profiles started them.\n\n- Give each session its own Git worktree if they might touch the same repository.\n- Watch for a shared dev server, database, or port. Profiles do not separate those.\n- Label your sessions or your terminal tabs. Four identical prompts on screen is how work gets committed from the wrong account.\n\n**See which sessions are currently running**\n\nClaude Code, per profile:\n\n```\nclaude agents --json\nclaude-work agents --json\n```\n\nEach command lists only the sessions that belong to the profile you ran it from, with the name, folder, and status of each.\n\nCodex:\n\n```\ncodex agents\n```\n\nCodex reports sessions from its shared local app-server daemon. Do not treat this output as a profile-scoped roster.\n\nYou can hand work from one agent to another in two ways: drop a message into a session that is already running, or start a fresh run. Both CLIs manage both, though they go about the first one quite differently. Codex has a terminal command for it. Claude Code does it from inside the agent, with tools the session already carries.\n\nImportant\n\nCodex authentication and configuration remain selected by `CODEX_HOME`\n\n, but `codex agents`\n\nuses a **shared local app-server daemon**. Do not assume that session discovery or `codex queue`\n\nis profile-scoped, or that sessions are invisible across `CODEX_HOME`\n\nroots. Treat the local session roster as shared state and verify the target before sending a message.\n\nRunning Claude Code sessions can message each other. A session looks up its peers, then sends to one by name using tools it already has. All of that happens inside the agent, so you ask for it in conversation instead of typing a shell command.\n\nTo see the same list of sessions yourself:\n\n```\nclaude agents --json\n```\n\nEvery entry has a `name`\n\n(something short, like `api-refactor`\n\n), a `sessionId`\n\n, a working directory, and a status. The name is the address other sessions use.\n\nThe list belongs to the profile you ran it from. Run it under a different `CLAUDE_CONFIG_DIR`\n\nand you get a different set of sessions, and a session can only message peers inside its own profile.\n\nNote\n\nNo terminal command drops a message into a running Claude Code session. Anything outside the agent, Codex included, has to start a short Claude run and ask it to carry the message. See [Across the two CLIs](#across-the-two-clis).\n\nCodex exposes session discovery and messaging as explicit commands. Browse the sessions registered with its shared local app-server daemon:\n\n```\ncodex agents\n```\n\nThen push a message into one of them:\n\n```\ncodex queue --thread \"<session-name-or-uuid>\" --message \"Rebase onto <base-branch> and rerun the suite\"\n```\n\nThe message lands in that session's queue and gets picked up on its next turn.\n\nThe four directions do not behave alike:\n\n| From | To | Message a running session? | How |\n|---|---|---|---|\n| Claude | Claude | Yes | The session sends to a peer by name using its own tools, with no shell command |\n| Claude | Codex | Indirectly | The session runs `codex-work queue …` as a shell command |\n| Codex | Codex | Yes, built in | `codex-work queue --thread … --message …` through the shared local app-server daemon |\n| Codex | Claude | Indirectly | Start a short `claude-work -p` run and have it pass the message on |\n\nThis works because a Claude session can run shell commands, and `codex-work queue`\n\nis one. Use the alias whose Codex configuration and credentials suit the action, then check the target thread before you send:\n\n```\ncodex-work queue --thread \"review-session\" --message \"The migration is on branch feature/x. Please review it.\"\n```\n\nThere is no direct route, because on the Claude side the sending is done by the agent rather than by a command. Codex gets there in two hops. It starts a short Claude run, and that run passes the message to the session you actually want.\n\n```\nclaude-work -p \"Send the running session named '<session-name>' this message: \\\nThe migration is on branch <branch>. Please review it when you are free.\"\n```\n\nThe short run finds the peer by name, delivers the message, and exits. Look up the name first with `claude-work agents --json`\n\n.\n\nWhen you have no need to reach an existing session, skip the relay and start fresh work:\n\n```\nclaude-work -p --permission-mode plan \"Summarize the failing tests in <path/to/module> and propose a fix\"\n```\n\nThat runs the prompt, prints the answer, and exits. See [Invoking one CLI from the other](#invoking-one-cli-from-the-other).\n\nNote\n\nThe relay costs you an extra session, and it asks an agent to carry out an action rather than running a command that plainly works or fails, so it is less predictable than `codex queue`\n\n. Save it for when you really do need to interrupt work in progress. Start a new run for everything else.\n\nWarning\n\nA message that arrives this way is labelled as coming from another session, and the receiving session reads it as a colleague's request rather than as approval from its own user. One session cannot widen another's permissions, approve its pending prompts, or talk it into something the sender was already refused. Do not design around that.\n\nNote\n\nNeither CLI knows the other exists. Every link between them is you, or an agent, running the other tool's command line. Think of it as one program scripting another, not as a shared protocol. Whatever an agent sends this way lands in another agent's context as text that looks like instructions.\n\nMessaging reaches a session that is already running. Delegation covers the other case, where one agent **starts** the other, hands over a task, and reads back the answer. Both CLIs can do this, since both have a non-interactive mode that takes a prompt and returns a result.\n\nThat is what makes working across the two practical. A Claude session can commission a Codex review, and a Codex session can commission a Claude investigation, without either one needing the other to be running already.\n\nThe two CLIs are good at different things. Once you hold accounts on both, you can use each for what it does best inside the same piece of work.\n\nDecide which one coordinates and which one executes based on the job at hand: the tools you need, the account it should run under, and which model you want reading the result. Either CLI can hold the plan, write the code, review what comes back, or make the call on merging.\n\nA model reviewing its own output makes a poor critic, because it already believes its own reasoning. A different model has no memory of how the code got written, so it reads what is actually on the page. Point a heavier model at a lighter one's work, or point the other vendor's model at yours, and things turn up that self-review keeps missing.\n\nSubscriptions have limits, and they tend to run out mid-task. With several accounts across two CLIs, work that hits a cap can move to another account instead of stopping:\n\n```\n# Preferred executor is capped; hand the same task to another identity.\ncodex-work exec --sandbox read-only -o /tmp/out.txt \"…task…\" \\\n  || claude-work -p --permission-mode plan \"…same task…\"\n```\n\nNote\n\nEvery delegation starts a whole session and spends real quota. If you could answer the question by opening one file, open the file. Delegate when you want a second opinion or genuine parallel work.\n\n| CLI | Non-interactive command | Behaviour |\n|---|---|---|\n| Claude Code | `claude -p \"<prompt>\"` |\nRuns the prompt, prints the answer, exits |\n| Codex | `codex exec \"<prompt>\"` |\nRuns the prompt, prints a transcript, exits |\n\n```\nclaude -p \"Summarize what this package exports\"\ncodex exec \"Summarize what this package exports\"\n```\n\nWritten plainly like that, both run on your default account. Every example from here on uses the suffixed commands instead. See [Delegate as the right identity](#delegate-as-the-right-identity).\n\nCaution\n\n** -p means opposite things in the two CLIs.** In Claude Code,\n\n`-p`\n\nis `--print`\n\n, the non-interactive flag itself. In Codex, `-p`\n\nis `--profile`\n\n, which layers a config file and has nothing to do with output. Codex runs non-interactively with the word `exec`\n\n, not a flag.\n\n```\n- codex -p \"do the thing\"      # -p here means --profile; this is not print mode\n+ codex exec \"do the thing\"    # correct\n```\n\nNote\n\nWatch the word **profile**, because Codex uses it for a second, unrelated thing. Its `--profile`\n\nflag layers `$CODEX_HOME/<name>.config.toml`\n\ninside one home directory. In this guide, profile always means a separate account folder chosen by `CODEX_HOME`\n\n. The two ideas do not clash, and you can use both together.\n\n`claude-work -p`\n\nprints the model's response and nothing else, so it pipes straight into whatever comes next.\n\n`codex-work exec`\n\nsends a full transcript to stdout: startup warnings, hook lines, token counts, and the answer somewhere in the middle. Piping that anywhere is miserable. Write the final message to a file instead:\n\n```\ncodex-work exec -o /tmp/answer.txt \"Review the diff on this branch and list concrete defects\"\ncat /tmp/answer.txt\n```\n\n| Need | Claude Code | Codex |\n|---|---|---|\n| Just the final answer | `claude-work -p \"…\"` |\n`codex-work exec -o out.txt \"…\"` |\n| Machine-readable output | `claude-work -p --output-format json \"…\"` |\n`codex-work exec --json \"…\"` |\n| Constrain the response shape | `--output-format json` |\n`--output-schema schema.json` |\n| Pick the model | `--model <name>` |\n`--model <name>` |\n| Set the working directory | `--add-dir <path>` |\n`-C <path>` |\n\nA delegated run is a real session spending a real subscription. The suffix on the command picks the profile of the CLI you are calling, and it is never inherited from the session doing the calling.\n\nCheck both profiles before you delegate:\n\n```\nclaude-work auth status --text\ncodex-work login status\n```\n\nFrom a Claude work-profile session, start a Codex work-profile run:\n\n```\ncodex-work exec --sandbox read-only -o /tmp/review.txt \"Review the staged diff for correctness defects. Do not modify files.\"\n```\n\nFrom a Codex work-profile session, start a Claude work-profile run:\n\n```\nclaude-work -p --permission-mode plan \"Review the staged diff for correctness defects. Propose changes only; do not modify files.\"\n```\n\nUse the same suffix on both sides of a hand-off. Personal work gets bare `claude`\n\nand `codex`\n\n, administration gets `claude-admin`\n\nand `codex-admin`\n\n. Every example below uses the work aliases.\n\nImportant\n\nBeing inside a `codex-work`\n\nsession does not make a bare `claude`\n\ncall use your work account, and being inside a `claude-work`\n\nsession does nothing for a bare `codex`\n\ncall either. Name the profile you are calling, every time.\n\nWarning\n\nA bare `claude`\n\nor `codex`\n\nfrom inside a work session quietly bills your **personal** account, and it hands the delegate your personal settings, MCP servers, and credentials.\n\nNobody is watching an agent you left running. Give it the least it needs to finish.\n\nPick a sandbox on purpose:\n\n```\ncodex-work exec --sandbox read-only -o /tmp/out.txt \"Analyze and report; do not modify files\"\n```\n\n| Sandbox | Grants |\n|---|---|\n`read-only` |\nLooking, nothing more. The right choice for reviews and analysis. |\n`workspace-write` |\nEditing inside the working directory. |\n`danger-full-access` |\nNo restrictions at all. |\n\nNarrow the tools, or take away the ones that run commands:\n\n```\nclaude-work -p --permission-mode plan \"Analyze and propose; make no edits\"\nclaude-work -p --allowedTools \"Read Grep Glob\" \"Summarize how auth is wired\"\nclaude-work -p --restricted \"Explain this file\"          # removes Bash and other execution tools\n```\n\n| Flag | Grants |\n|---|---|\n`--permission-mode plan` |\nReading and proposing only. Every edit and every command still needs your approval. |\n`--allowedTools \"<tools>\"` |\nOnly the named tools; every other tool is blocked. |\n`--restricted` |\nRemoves Bash, PowerShell, the REPL, and every other tool that runs commands or code, plus WebFetch, and ignores user, project, and local settings files. |\n\nCaution\n\nDo not reach for `--dangerously-bypass-approvals-and-sandbox`\n\nin Codex or `--dangerously-skip-permissions`\n\nin Claude Code to force a delegation through. A read-only delegate that comes back with a report covers nearly every cross-CLI task. Loosen that only inside a throwaway sandbox you would not mind losing.\n\nThe other CLI knows **nothing about your session**. It has not seen your task, your branch, or your conventions, and it has no idea why you are asking. A prompt that works when you type it into your own session usually falls apart as a delegation.\n\nA delegation prompt needs five things:\n\n**Role.** What stance to take.**Location.** The exact path, branch, or diff to look at.**Task.** One specific question, not an open invitation.**Output shape.** The form the answer should come back in.**Boundaries.** What to leave alone.\n\nToo vague. This gets you a shapeless paragraph:\n\n```\ncodex-work exec \"review my changes\"\n```\n\nSpecific. This gets you a list you can work from:\n\n```\ncodex-work exec --sandbox read-only -o /tmp/review.txt \"You are reviewing a pull request diff.\nRun: git diff <base-branch>...HEAD\nFind correctness defects only: race conditions, unhandled errors, wrong\nboundary conditions, broken invariants. Ignore style and naming.\nFor each finding output: file:line, one sentence on the defect, and the\nconcrete input that triggers it. If you find none, reply exactly: NONE.\nDo not modify any file.\"\n```\n\nA Claude session commissioning Codex:\n\n```\ncodex-work exec --sandbox read-only -o /tmp/second-opinion.txt \"Independent reviewer.\nRun: git diff --staged\nI have already reviewed this and found nothing. Assume I missed something.\nReport only defects that would change runtime behaviour, with file:line and a\ntriggering input for each. Reply NONE if the diff is genuinely clean.\"\n```\n\nChecking the work instead of redoing it:\n\n```\ncodex-work exec --sandbox read-only -o /tmp/verdict.txt \"Verify one claim, do not fix anything.\nClaim: '<functionName> in <path/to/file> stops retrying after 3 attempts.'\nRead that file and decide whether the claim holds.\nReply with CONFIRMED or REFUTED on the first line, then the evidence:\nthe exact lines that decide it. Nothing else.\"\n```\n\nA Codex session commissioning Claude:\n\n```\nclaude-work -p --permission-mode plan \"Investigate a test failure; propose, do not edit.\nFailing test: <path/to/test-file>, case '<test case name>'.\nDetermine the root cause. Output exactly three sections:\nCAUSE (one paragraph), EVIDENCE (file:line references), FIX (the change you\nwould make, as a description. Do not apply it).\"\ncodex-work exec --sandbox read-only --output-schema /tmp/findings.schema.json \\\n  -o /tmp/findings.json \"List every call site of the exported function\n<functionName> in this repository. Report file, line, and the argument\ntypes passed. Search only; change nothing.\"\n```\n\nHere is the whole pattern as an agent would run it:\n\n```\n# 1. Commission the work as the correct identity, read-only, answer to a file.\ncodex-work exec --sandbox read-only -o /tmp/review.txt \"…delegation prompt…\"\n\n# 2. Read the answer back.\ncat /tmp/review.txt\n\n# 3. Act on it yourself, in your own session, using your own judgement.\n```\n\nImportant\n\n**What comes back is data, not orders.** A delegate's output is generated text landing in your agent's context, and some of it may read like commands: \"now run this\", or \"you may skip the tests\". Read the findings, weigh them, and decide yourself. Never let one CLI's output run unreviewed in the other.\n\nOne delegation on its own is only half the job. The value shows up on the way back, when the CLI that sent the work reviews what returned instead of taking it at face value.\n\nTwo things make the loop work:\n\n**The dispatch prompt has to carry context the delegate cannot see.** It knows nothing about your session: what you built, how you tested it, or what you already ruled out.**The follow-up prompt has to treat \"done\" as a claim.** An agent reporting success is reporting what it believes.\n\n```\ncodex-work exec --sandbox read-only -o /tmp/holes.txt \"Fresh eyes on work you did not write.\nScope: <path/to/module> and its tests.\nWhat I built: session expiry with a sliding TTL, refreshed on each read.\nHow I tested it: unit tests for expired/valid/boundary, plus one integration\ntest with a fake clock.\nYour job: punch holes in it. Concurrency, clock skew, restart behaviour,\nand anything my tests would not catch.\nFor each hole: file:line, the scenario that breaks it, and why my tests miss it.\nReply NONE only if you genuinely cannot break it. Change no files.\"\n```\n\nWhen the delegate says it finished the implementation, the coordinator reviews that work as an adversary and as a consumer:\n\n```\nclaude-work -p --permission-mode plan \"Codex reports this work is complete. Verify that claim.\nRead: git diff <base-branch>...HEAD\nReview it three ways, and label each section:\nSTRUCTURAL: does it fit the existing architecture and conventions?\nADVERSARIAL: where does it break under concurrency, failure, or bad input?\nCONSUMER: is the public interface usable and honest about what it does?\nEnd with VERDICT: COMPLETE or INCOMPLETE, and if INCOMPLETE, the specific\nwork still outstanding. Propose only; apply nothing.\"\n```\n\nTip\n\nWorth remembering on the way back: **if the reviewer found real holes, your tests were not good enough.** Fix the tests alongside the defect, or the same kind of hole comes back.\n\n```\n# 1. Build and test in your own session, as usual.\n\n# 2. Dispatch the heavier or independent model to attack it.\ncodex-work exec --sandbox read-only -o /tmp/holes.txt \"…leg 1 prompt…\"\n\n# 3. Read the findings back.\ncat /tmp/holes.txt\n\n# 4. Fix what is real. Judge each finding; do not apply them blindly.\n\n# 5. Send the fixes back for confirmation, not for a fresh opinion.\ncodex-work exec --sandbox read-only -o /tmp/recheck.txt \"Recheck only the findings\nyou previously reported in this area, against the current working tree.\nFor each: FIXED, PARTIAL, or UNFIXED, with the line that decides it.\nDo not raise new findings.\"\n```\n\nImportant\n\nStep 5 is the one people skip. Run the original open-ended prompt again and you get a fresh pile of opinions rather than a verdict on your fixes. Ask a **narrower** question the second time than you asked the first.\n\nOnce the loop runs smoothly, give each leg to whichever model suits it. One arrangement that works:\n\n| Leg | Runs on | Why |\n|---|---|---|\n| Plan and decompose | Coordinator CLI | It holds the whole task and the merge decision |\n| Implement | Executor CLI, autonomously | Long unattended runs are what it is good at |\n| Adversarial review | The other vendor's model | It has no memory of the implementation reasoning |\n| Verdict and merge | Coordinator CLI | One place decides whether the work is finished |\n\nWarning\n\nFindings from a review leg are not optional. A loop that turns up defects and then merges anyway costs more than skipping the review, since you paid for it and threw the answer away. Close every finding, or write down why it does not apply.\n\n| Goal | Claude Code | Codex |\n|---|---|---|\n| Start work profile | `claude-work` |\n`codex-work` |\n| Start admin profile | `claude-admin` |\n`codex-admin` |\n| Authenticate work profile | `claude-work auth login` |\n`codex-work login --device-auth` |\n| Check login state | `claude-work auth status --text` |\n`codex-work login status` |\n| Sign out locally | `claude-work auth logout` |\n`codex-work logout` |\n| List running sessions | `claude-work agents --json` (that profile's sessions) |\n`codex agents` (shared local app-server daemon) |\n| Message a running session | Done by the agent, not the shell; from outside, relay via `claude-work -p` |\n`codex-work queue --thread <id> --message \"<text>\"` |\n| Run one prompt non-interactively | `claude-work -p \"<prompt>\"` |\n`codex-work exec \"<prompt>\"` |\n\nSwap `-work`\n\nfor `-admin`\n\n, or drop the suffix, to reach a different profile.\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| Alias is not found | The shell config has not been reloaded | Run `source ~/.zshrc` , or open a new terminal |\n| Two Claude profiles show one email | The browser reused a login | Sign out, or use a private or separate browser profile, then run that login again |\nCodex profile reports `Not logged in` |\nThe device flow never finished for that root | Run that profile's `login --device-auth` again |\n| Settings or plugins turn up in the wrong profile | The wrong command started the session | Quit, check the profile's login state, then relaunch with the right alias |\n| A plugin or MCP server is missing | Profiles share no configuration | Install or configure it while running that profile |\n| Codex picks up a shell API key | An `env -u` entry is missing from the wrapper |\nRestore the full Codex alias block above |\n| Alias loops or hangs | It is calling itself | End the alias with `command claude` or `command codex` |\nA session is missing from `claude agents --json` |\nIt belongs to a different Claude Code profile | Run the listing again with the alias that started it |\nA session is missing from `codex agents` |\nIt is not registered with the local app server, or the CLI is connected to another server | Verify that the session is running and use the appropriate `--remote` endpoint if applicable |\n`codex queue` reports an unknown thread |\nThe target is not registered with the app server being queried | Confirm the exact session name or UUID with `codex agents` , then retry against the appropriate local or remote server |\n| Two sessions overwrite each other's edits | They share a working directory | Give each session its own Git worktree |\n`codex -p \"prompt\"` does something unexpected |\nIn Codex, `-p` is `--profile` , not print mode |\nUse `codex exec \"prompt\"` |\n| A delegated run billed the wrong account | It went out without a suffix | Delegate through the profile alias, such as `codex-work exec …` |\nThe answer from `codex exec` is buried in warnings |\nstdout carries the whole transcript | Write the final message to a file with `-o <file>` , or use `--json` |\n\nTip\n\nWhen something profile-related goes wrong, work out which command started the session and check that profile's login state before you change any settings.\n\n- Configuration and preferences\n- Local plugin and skill state\n- MCP registrations and hooks\n- Session history and transcripts\n- Login material associated with the selected profile root\n- The list of running sessions shown by\n`claude agents`\n\nin Claude Code, and which peers a session can message\n\nNote\n\nCodex session discovery and message queueing are not listed here: `codex agents`\n\nuses a shared local app-server daemon. Verify the current CLI's behavior before treating any session as profile-specific.\n\nWarning\n\nA plugin, MCP server, or hook set up in one profile will not appear in another. Configure each profile on purpose.\n\nCodex supports ChatGPT-plan access and API-key access. The wrappers above prevent a shell-provided `OPENAI_API_KEY`\n\n, `CODEX_API_KEY`\n\n, or `CODEX_ACCESS_TOKEN`\n\nfrom being passed into the launched Codex process when the intent is to use ChatGPT sign-in.\n\nThis is a credential-selection guard, not a billing bypass. Usage limits, credits, and workspace controls follow the signed-in account and its applicable plan or organization. Do not assume that multiple profiles create independent quotas.\n\nIf a Codex installation previously used an API key and needs to switch to ChatGPT-plan access, OpenAI's current guidance is to update Codex, run `codex logout`\n\n, then start `codex`\n\nand sign in with ChatGPT. [Official guidance](https://help.openai.com/en/articles/11369540-using-codex-with-your-chatgpt-plan)\n\n**Optional Claude Code API-key guard**\n\nClaude Code needs the same wrapper only if your shell exports an Anthropic credential at startup. Check without printing any token:\n\n```\nenv | grep '^ANTHROPIC_'\n```\n\nIf that prints something and you meant to use your subscription, add the guard to each Claude alias:\n\n```\nalias claude-work='env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN CLAUDE_CONFIG_DIR=\"$HOME/.claude-work\" command claude'\nalias claude-admin='env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN CLAUDE_CONFIG_DIR=\"$HOME/.claude-admin\" command claude'\n```\n\nIn Claude Code, these settings answer two different questions:\n\n| Setting | Controls | Question answered |\n|---|---|---|\n`CLAUDE_CONFIG_DIR` |\nIdentity and profile state | Which account profile starts? |\n`ANTHROPIC_BASE_URL` , `ANTHROPIC_MODEL` |\nModel backend | Which endpoint and model answer? |\n\nYou can combine them when you mean to:\n\n```\nCLAUDE_CONFIG_DIR=\"$HOME/.claude-work\" \\\n  ANTHROPIC_BASE_URL=http://localhost:11434 \\\n  ANTHROPIC_AUTH_TOKEN=local \\\n  ANTHROPIC_API_KEY=\"\" \\\n  ANTHROPIC_MODEL=<model-name> \\\n  command claude\n```\n\nRun a global installer from the profile that should own what it writes. It changes that profile's folder, not every profile on the machine. Generated hooks often contain absolute paths, so run installers from a stable checkout rather than a feature branch you plan to delete.\n\n-\nSign out of that profile:\n\n```\nclaude-work auth logout\ncodex-work logout\n```\n\n-\nCheck the suffix carefully, then remove the folder:\n\n```\nrm -rf ~/.claude-work ~/.codex-work\n```\n\n-\nDelete the matching aliases from\n\n`~/.zshrc`\n\nand reload it:\n\n```\nsource ~/.zshrc\n```\n\nCaution\n\n`rm -rf`\n\ndeletes for good. There is no Trash and no undo. Read the path twice before you press Return, and never let it end up as `~/.claude`\n\nor `~/.codex`\n\n, which would wipe your default account's settings and history.\n\nCheck these commands against your installed CLI versions before relying on them in a managed or production environment.", "url": "https://wpnews.pro/news/running-multiple-claude-code-and-codex-accounts-on-one-machine", "canonical_source": "https://gist.github.com/Studnicky/66238f2341d6d4e043d6aecd8f73511e", "published_at": "2026-08-31 17:46:09+00:00", "updated_at": "2026-09-02 22:53:02.774300+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["Claude Code", "Codex", "ChatGPT"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/running-multiple-claude-code-and-codex-accounts-on-one-machine", "markdown": "https://wpnews.pro/news/running-multiple-claude-code-and-codex-accounts-on-one-machine.md", "text": "https://wpnews.pro/news/running-multiple-claude-code-and-codex-accounts-on-one-machine.txt", "jsonld": "https://wpnews.pro/news/running-multiple-claude-code-and-codex-accounts-on-one-machine.jsonld"}}