cue — Agent Profile Manager for Claude Code & Codex. This doc explains the resolve → materialize → exec hot path that runs every time you type
claudeorcodexin a shell wherecue shell installhas been run.
When you type claude or codex in a shell where cue shell install has
been run, the shim at ~/.local/bin/claude (or codex) delegates immediately
to cue launch <agent> "$@". This is the hot path:
~/.local/bin/claude
└─exec──► cue launch claude $@
│
▼
1. resolve(cwd) ← pick a profile name
│
▼
2. picker (first time) ← TUI opens if no profile resolved
│
▼
3. materialize(profile) ← build ~/.config/cue/runtime/<profile>/claude/
│
▼
4. exec real claude ← with CLAUDE_CONFIG_DIR set
Profile resolution stops at the first match, in this order:
--cue-profile <name>flag passed toclaude(orcue launch)..cue-profilefile found by walking up from cwd; walk stops at the git repo root or$HOME, whichever comes first.~/.config/cue/repo-defaults.json— a JSON map of git-repo-root absolute paths to profile names, consulted when cwd is inside a git repo.~/.config/cue/default-profile— single-line file with a global default.- TUI picker — opens when none of the above matched.
On first launch in a new directory, the picker opens in the terminal. Arrow keys
navigate; Enter selects. By default the chosen profile is written to
.cue-profile in the current directory so the next launch is instant. Pass
--cue-pick to force the picker open even when a pin is present.
Given a resolved profile, cue builds (or reuses) a fully isolated config tree:
~/.config/cue/runtime/<profile>/claude/
├── .cue-hash sha256(resolved profile JSON, sorted keys)
├── settings.json enabledPlugins, mcpServers
├── CLAUDE.md profile stamp + user's ~/.claude/CLAUDE.md appended
└── skills/ symlinks to skill dirs in resources/skills/
The hash is checked before any writes. If the profile hasn't changed since the
last run, materialize is a no-op (sub-millisecond). When the profile changes,
cue writes to a sibling .tmp directory and atomically swaps it in, so a
concurrent running session never sees a partial state.
For Codex the shape is identical under runtime/<profile>/codex/ with
CODEX_HOME and a config.toml instead of settings.json.
Each profile can declare two icon fields:
icon: "🦊"— a 1-2 char emoji shown in any terminal (the picker label)iconImage: "logo.png"— a path (relative to the profile dir) to a real PNG/JPG logo. Rendered inline via the Kitty graphics protocol when the picker detects a Kitty terminal; otherwise falls back to the emoji.
Cue tries, in order:
CUE_KITTY=1env var — explicit opt-in (recommended for tmux setups)CUE_DISABLE_KITTY_IMAGES=1— explicit opt-outTERM=xterm-kittyorKITTY_WINDOW_IDset — direct KittyKITTY_PID,TERM_PROGRAM=kitty,LC_TERMINAL=kitty- Inside tmux/screen: walk
/proc/<pid>/commparent chain looking for akittyprocess (works only when not detached behind a tmux server)
When inside tmux, two things are required for Kitty images to render:
set -g allow-passthrough onin~/.tmux.conf(default in tmux 3.3+). This forwards graphics-protocol escapes from cue down to the terminal — but note: tmux's passthrough is one-way. Terminal responses (used by the auto-probe) do not reliably travel back, so the probe usually times out inside tmux even when Kitty is the actual frontend.- Set
CUE_KITTY=1explicitly so cue skips the probe and trusts the signal:If you also use non-Kitty terminals occasionally, override per-session with# in ~/.bashrc (set unconditionally if you primarily use Kitty) export CUE_KITTY=1 # also tell tmux to expose it to existing panes tmux set-environment -g CUE_KITTY 1
CUE_DISABLE_KITTY_IMAGES=1 claudeto force emoji fallback.
If the wrapped passthrough sequence renders as garbage in your terminal, set
CUE_DISABLE_KITTY_IMAGES=1 to fall back to emoji icons.
When CLAUDE_CONFIG_DIR is set in the environment before launching cue
(typically via a shell alias like claude-account2), cue treats this as
account-alias mode:
- The path in
CLAUDE_CONFIG_DIRis the credentials source. - cue copies
.credentials.jsonfrom there into the materialized runtime so you don't have to log in again. - cue reads the source's
settings.jsonand merges the profile's plugins + MCPs on top — preservingpermissions,trustedDirectories, andskipAutoPermissionPromptfrom the account. - Both files are refreshed on every launch (even on cache hit) so switching accounts on the same profile doesn't leak settings between accounts.
- The picker is always shown in account-alias mode, with the previously pinned profile on top — so each session can use a different profile without losing the auth.
Example alias:
alias claude-account2="CLAUDE_CONFIG_DIR=$HOME/.claude-accounts/account2 cue launch claude"The detection compares realpath(CLAUDE_CONFIG_DIR) against
realpath($HOME/.claude) — so trailing slashes and symlinks don't accidentally
trigger account-alias mode.
claude --cue-profile frontend— skip resolve, usefrontenddirectly.claude --cue-pick— always open the picker (ignore pin files).CUE_BYPASS=1 claude— exec the real binary directly; no resolve, no materialize, no profile.- Absolute path (
/usr/local/bin/claude) — bypasses the shim entirely via PATH.
See the full spec at docs/superpowers/specs/2026-05-22-cue-agent-profile-manager-design.md.