Skip to content
BlueRaddishPublic

About

Launch Claude Code from one fixed directory, whatever directory you are in - so its per-directory memory store always loads

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

59 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cly

One command for managing agentic CLI workflows: launch agents, save open sessions, restore a workspace, and collect session memories across clients. A bare cly offers a menu of agents; cly --resume lists their available sessions, newest first; -x adds the agent's own skip-the-prompts flag. A profile pins an executable, standing flags and a launch directory under a name.

$ cly                # a menu: claude, codex, antigrav, muse, kimi, qwen, opencode, deepseek, meta
$ cly .              # the default profile — Claude Code, in ~/claude
$ cly -x codex       # codex, right here, with its approval prompts off
$ cly -r             # every agent's sessions on one screen; Enter resumes the one in hand
$ cly -x -c          # the newest session of any agent, resumed, prompts off
$ cly snapshot       # save active tracked launches
$ cly snapshot restore latest --dry-run
$ cly snapshot reload latest --dry-run   # preview stopping and reopening tracked agents
$ cly snapshot auto enable              # checkpoint tracked sessions; restore after reboot
$ cly snapshot auto status
$ cly document start # maintain a local session-prose library every 15 minutes
$ cly document catch-up --profile codex # one model reviews pending memories across agents

Snapshots and documentation are an optional Python 3.9+ extension, with no third-party Python dependencies. Exact resume IDs and the original native histories are required for restore; new sessions that cannot expose their ID must be bound explicitly. See the workflow guide for binding, date-based restore, provider coverage, verified PARA publication and curated filing plans. An optional GUI is recorded in the roadmap.

cly snapshot auto enable checks tracked sessions every 60 seconds and keeps one atomic, nonempty checkpoint when the inventory changes. Empty inventories and capture errors preserve it. Login restore after a new boot skips active conversations and prior launches without stopping agents; status records failures for review. Use --interval SECONDS or --no-restore-on-login to change capture behavior. This covers tracked or adopted agent conversations, not Terminal panes, layout or scrollback. See automatic snapshots for commands and restart safety.

Why

Claude Code keys its memory store off the directory it was launched from:

~/.claude/projects/<launch-dir-with-separators-mangled>/memory/

There is one store per directory. If you keep your memories in one place — and you probably should — then launching from anywhere else loads none of them. Nothing errors. The memories are simply not there, and the first sign is Claude not knowing something you are certain you told it.

cly removes the failure mode by pinning the launch directory, and carries your standing flags so those cannot be forgotten either. A profile does the same for every other tool you run. And because every one of those tools keeps its own session store in its own shape, cly -r reads all of them and shows one list.

Install

git clone https://github.com/BlueRaddish/cly
cd cly
./install.sh          # PowerShell or cmd: .\install

That writes a stub into ~/bin that runs this clone in place, so git pull here is the whole of an upgrade. On Windows a cly.cmd goes in beside it, because PowerShell and cmd will not run an extensionless file. Re-running is safe; --uninstall removes the stubs; --prefix DIR puts them somewhere else.

~/bin has to be on your PATH. On Windows that means the User PATH in the registry — a line in ~/.bashrc is invisible to PowerShell, cmd and anything started from the Start menu. install.sh checks, and prints the one-liner if it is missing.

Nothing is configured by the install. The first cly, cly init, or cly . asks.

First run

For example, on macOS (installed tools depend on your machine):

$ cly
cly 4.3.0 — which agent?

    1  claude    Claude Code  installed, no profile yet
    2  codex     Codex        installed, no profile yet
    3  antigrav  Antigravity  not installed: native installer; Enter for command
    4  muse      Muse Code    installed, no profile yet
    5  kimi      Kimi Code    not installed: native installer; Enter for command
    6  qwen      Qwen Code    not installed: native installer; Enter for command
    7  opencode  OpenCode     not installed: brew install anomalyco/tap/opencode
    8  deepseek  DeepSeek     not installed: native installer; Enter for command
    9  meta      Llama        not installed: Ollama + model; Enter for commands

Install hints follow the current OS: macOS and Linux use native installers where available, while native Windows hints name PowerShell. Gemini CLI still needs Node.js and npm on Windows and Linux; its macOS hint uses Homebrew. Move with the arrows and press Enter, or x to launch with the agent's prompts skipped; / searches the list. Picking a tool that is installed but has no profile asks the setup questions and then launches it; picking one that is not installed prints the full install command and how to sign in. cly init NAME asks the same questions on their own:

$ cly init claude
  Which flags should claude be given on every launch?
  Enter flags, 'none' for no flags, or press Enter to keep the default.
  (Catalog defaults skip prompts; Claude/Codex also enable remote control.)
  [--remote-control --dangerously-skip-permissions] >

  Claude Code keeps a separate memory store for every directory it is
  launched from, so pinning one means the same memories load each time.
  Which directory should claude launch from?
  Enter a path, or press Enter to launch wherever you are standing.
  [current directory: /home/you] > ~/claude

Two questions per profile, three if the name is not something on your PATH. The first profile you make becomes the one cly . launches, and a later one never takes that over silently.

The grammar

cly [OPTION...] [PROFILE|.] [AGENT-ARG...]

The first word is always cly's. Everything after the profile name is always the agent's. Neither can claim the other's flags, which is why nothing here needs a --cly- prefix. With no profile named at all, cly offers the menu.

$ cly claude --model opus   # claude --remote-control --dangerously-skip-permissions --model opus
$ cly -x claude             # claude --remote-control --dangerously-skip-permissions
$ cly -x codex --search     # starts remote control, then codex --remote unix:// --dangerously-bypass-approvals-and-sandbox --search
$ cly --dir ~/work codex    # cly takes --dir; codex gets nothing extra
$ cly one --help            # the agent's help, because it is after the name
$ cly --help                # cly's help, because it is before one
Command Meaning
cly pick an agent from the menu, then launch it
cly . launch the default profile
cly NAME launch the profile called NAME
cly init [NAME] set up a profile; with no NAME, the one . launches
cly config [NAME] show what is configured, and what would run
cly help the full help
cly version the version
Option Meaning
-x, --bypass skip the agent's permission prompts, with its own flag
-r, --resume list every agent's sessions and resume the one picked; with a PROFILE, only that agent's
-c, --continue resume the newest session without asking
-d, --dir DIR launch from DIR, this call only
--here launch from the current directory, this call only
-h, --help show cly's help
-V, --version show the version

Options go before the profile name. Exit status is 0 when the agent was launched or a command did its work, 1 when the config file could not be read or written, and 2 for a usage error, nothing picked, or a profile that could not be set up.

Resuming

$ cly -r
cly 4.3.0 — which session?                                                      1/30
up/down move · type to filter · Enter resume · Esc quit · 30 of 76 · CLY_ROWS=60 shows more
    #  agent     last      where                       title
    1  claude    2m ago    ~/claude                    Upgrade cly into a funnel for multiple agents
    2  claude    7m ago    ~/claude                    the shell is still running the review right
    3  codex     2d ago    ~                           Continue interrupted conversation
    4  gemini    3d ago    ~/work/site                 Refactor the header component
    5  kimi      4d ago    ~/work/api                  Kimi fixes the build

The screen is modelled on the one claude --resume shows. Arrows, PgUp/PgDn, Home/End move the bar; Enter resumes; x resumes with the agent's prompts skipped, as if -x had been typed; / starts a search (codex keeps only Codex's rows, a word keeps the rows whose title has it); digits go to a row by number; Esc steps back — out of the search with the list as it left it, then clearing it, then leaving the screen. Outside a search, letters do nothing, so nothing typed by accident is a command. cly -c skips the screen and resumes the newest session; -x before either adds the bypass flag.

A session is resumed in the directory it was started in — every agent keys its store or its own picker on that directory — by the profile of its kind, with that profile's standing flags, or by the bare agent when no profile has that kind. cly -r NAME narrows the list to one agent; cly -r . to the default profile's. Without a terminal (cly -r < /dev/null, a script) the list is printed once and the exit status is 2.

Each kind's store, and what cly reads from it:

Kind Index read Resume words
claude ~/.claude/history.jsonl — every typed prompt with its session id, directory and time; the name from /rename (custom-title.json beside the transcript) is the title; a session whose transcript has been cleaned up is not offered --resume ID
codex Thread SQLite metadata and rollout headers; native custom names, then session_index.jsonl names, then native titles. Confirmed subagents are excluded resume ID
gemini ~/.gemini/tmp/*/chats/session-*.json*, newest first by name; the directory from the project's .project_root or ~/.gemini/projects.json --resume ID
kimi ~/.kimi-code/session_index.jsonl, then each session's state.json for title, directory and time --session ID
muse, qwen, opencode Native metadata adapters with Python; unsupported transcript variants remain visible in capability reports resume ID, --resume ID, --session ID

The screen shows CLY_ROWS rows at once (default 15) and scrolls. With Python 3.9+ the picker reads metadata from profile-specific stores, preserves native names, and excludes Codex subagents. Press n to search session names, or start with cly --find "session name"; / searches the whole row. --list-sessions keeps its five-column machine format. Without Python, the Bash reader supports the four original stores; CLY_SESSION_READER=bash selects that fallback explicitly. See session tracking for capability reports and limits.

Agents

-x knows the skip-the-prompts flag of eight kinds. The Python inventory adds Muse, compatible Qwen and OpenCode stores to the original four:

Kind Skip prompts Sign in
claude --dangerously-skip-permissions claude, then /login
codex --dangerously-bypass-approvals-and-sandbox codex login
antigrav (agy) --dangerously-skip-permissions agy, then follow the sign-in prompts
gemini (legacy) --yolo gemini, then pick "Login with Google"
muse --yolo (approvals and sandbox) muse login
kimi --auto (Never Ask) kimi, then /login
qwen --yolo qwen, then /auth (a key or a coding plan)
opencode --auto opencode auth login

Muse Code is fourth in the catalog (configured profiles appear first). It supports normal launch and -x; use cly muse resume for its native session picker. Its metadata is included in cly -r with Python; current prose capture requires export/import.

Muse runs natively on Windows. Install it from PowerShell with irm https://dev.meta.ai/install.ps1 | iex, then run muse login and cly init muse. Its installer adds %LOCALAPPDATA%\Programs\muse to the User PATH; open a new terminal after installing. cly recognizes the official muse.cmd launcher from both its menu and a profile named muse, and an explicit Windows path to muse.cmd still has kind muse for -x. cly muse resume, cly muse exec ..., and cly muse serve put standing flags after the subcommand. Account and utility commands such as cly muse login receive only the arguments you pass, because session flags do not apply there.

A profile's kind is its executable's name, so profile.codex.bin=codex needs nothing more; profile.NAME.kind=KIND says otherwise when the executable is not the agent.

DeepSeek and Llama are routes, not kinds. No terminal agent signs you in with a DeepSeek account, and the Llama entry runs through Ollama. Meta’s Muse Code is a separate native agent. The menu's deepseek and meta entries set up Claude Code through Ollama — ollama signin for DeepSeek's hosted models, ollama pull llama3.1 for Llama on your own machine — as a profile of kind claude:

profile.deepseek.bin=ollama
profile.deepseek.flags=launch claude --model deepseek-v4-pro -- --dangerously-skip-permissions
profile.deepseek.dir=none
profile.deepseek.kind=claude

Everything after the -- is Claude Code's, which is where -x and --resume land, and the sessions appear under claude in the list. The model name is whatever ollama.com/search?c=cloud lists; the setup question offers one and Enter keeps it. The key-based route exists too — DeepSeek's Anthropic-compatible endpoint, with the key kept out of the config:

profile.deepseek.bin=claude
profile.deepseek.env=ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic ANTHROPIC_AUTH_TOKEN=$DEEPSEEK_API_KEY

Claude Code and Codex are exercised on the machine this was written on. Gemini CLI, Kimi Code, Qwen Code and OpenCode are handled from their documentation and source as of September 2026 — the flags and the store layouts — and the Ollama routes from Ollama's; the suite feeds cly stores shaped that way, but a real one may have moved. If one has, cly -r NAME says so by listing nothing, and the fix is one of the small functions named after the kind in bin/cly.

Antigravity replaces Gemini in the new-profile menu and runs the official agy CLI. Existing Gemini profiles and their session history remain supported. Antigravity session listing is not yet supported; use its native /resume picker or pass --conversation ID after cly antigrav. Pin a launch folder with cly init NAME; unpinned menu entries show the actual current directory.

Profiles

A profile is a name with an executable, flags and a launch directory of its own, and optionally a kind and an environment:

default=claude

profile.claude.bin=claude
profile.claude.flags=--remote-control --dangerously-skip-permissions
profile.claude.dir=/c/Users/me/claude

profile.codex.bin=codex
profile.codex.flags=--remote-control --dangerously-bypass-approvals-and-sandbox
profile.codex.dir=none

Every line but the name is optional. A profile with no bin= is named after the tool it runs, so profile.codex.dir=none alone is enough for cly codex. A profile with no dir= launches wherever you are standing, and none says so explicitly — usually what you want for a tool with no memory store to pin. A profile gets no flags it did not ask for: standing flags belong to the profile that asked for them, and another tool would choke on them. kind= and env= are described above; env= values of the form $NAME are read from your environment at launch, so a key never has to sit in the file.

default=NAME is which profile cly . launches, and the row the menu starts on. With exactly one profile configured you can leave it out — there is nothing else . could mean. With several and no default= line, cly . says so and asks you to run cly init.

Configuration

Launch directory, most specific first: --here / --dir, then CLY_DIR, then the profile — or, when resuming, the session's own directory. Flags: CLY_FLAGS, then the profile. Executable: CLY_BIN, then the profile's bin=, then the profile's own name.

Variable Default Meaning
CLY_DIR — launch directory, overriding the profile
CLY_FLAGS — flags, overriding the profile; empty means none
CLY_BIN — the executable, overriding the profile
CLY_CONFIG ~/.config/cly/config where the config lives
CLY_ROWS 15 rows the screen shows at once; twice that many files opened per store without an index
CLY_BASH — Windows only: the bash.exe the shim should use

The agents' own variables are honoured for their stores: CLAUDE_CONFIG_DIR, CODEX_HOME, GEMINI_CLI_HOME, KIMI_CODE_HOME.

The config file is key=value lines and safe to edit by hand; cly init rewrites the profile it was given and leaves every other line — comments, other profiles, the profile's own kind= and env= — exactly where it was. A Windows path is understood wherever a path is read, so dir=C:\Users\me\claude means the same thing.

Coming from v3

v4 gave the bare cly and --resume to cly itself, and moved the permission bypass out of the standing flags and onto -x.

v3 v4
cly — a help screen cly — the menu (the help screen when there is no terminal)
cly . --resume — the agent's own picker still the agent's own picker; cly -r is the one across every agent
profile.claude.flags=--remote-control --dangerously-skip-permissions profile.claude.flags=--remote-control, and cly -x .

A v3 config keeps working unchanged: a bypass flag left in flags= still applies on every launch, and -x does not add it twice. Taking it out of the file is what makes -x mean something. A v2 config (top-level dir= and flags=) is still read as the claude profile, as before.

One implementation

bin/cly is the Bash 4.2+ launcher; macOS ships 3.2 and needs Homebrew's Bash. Bash, MSYS2 and WSL run it directly; PowerShell and cmd reach it through bin/cly.cmd. The optional lib/cly workflow extension uses Python 3.9+ and its standard library. Basic launching and the existing session picker still work without Python; CLY_TRACK=0 disables managed-launch tracking.

The script uses shell builtins and mkdir and nothing else — not even cat, whose absence would otherwise break writing the config file — because the shim may hand it a bash whose PATH carries none of them. cygpath is the one exception, reached through command -v and falling back to parameter expansion when it is missing. test.sh checks that it stays that way, and the suite itself runs with a PATH it owns so it tests cly rather than the machine.

The default session inventory uses the optional Python metadata adapters; the fallback reads indexes with Bash builtins. The screen uses ANSI escapes and read -n1, and asks the terminal for its size. Each redraw moves back over the previous frame because Git Bash in a plain conhost window does not honor an alternate screen. Workflow commands, lifecycle tracking, context handoffs and optional collector startup are described in session tracking.

cly.cmd prefers Git for Windows' bin\bash.exe, which starts with both /usr/bin and the Windows PATH already on PATH and stays in the caller's directory, so no login shell is needed. MSYS2's usr\bin\bash.exe is the fallback and does need -l. where bash is deliberately never consulted: on a machine with WSL it answers C:\Windows\System32\bash.exe, a Linux shell that cannot launch a Windows claude.exe.

Behaviour in the awkward cases

  • The configured directory has been deleted — warns, names it, and starts in the current directory. Staying quiet here looks exactly like memories mysteriously failing to load.
  • The session's directory has been deleted — the same: warns, and resumes where you are standing.
  • A name with no profile, and no terminal to ask at (a script, a hook, a cron job) — exits 2 and names the profiles that do exist, rather than blocking on a question nobody can answer, or eating the stdin meant for claude -p.
  • A name that is neither a profile nor a program — exits 2 and says both — and, for a name from the menu, what to install and how to sign in.
  • -x on a kind cly does not know — exits 2 and names the config key that would teach it, or says to put the flag in flags= instead.
  • Several profiles and no default — exits 2 rather than picking one.

Your shell's own working directory is untouched: cly is a script, so the cd happens in its own process.

Tests

./test.sh

No agent is launched — CLY_BIN points at a stub that prints its working directory, its arguments and the environment it was given, which is the whole of what cly decides — and CLY_CONFIG and the four store variables point into a scratch directory, so the real config and the real session stores are unreachable from the suite. The stores it builds are shaped as the agents write theirs. A dropping check count means a check stopped running, not that it started passing.

Remote control and permission defaults

New catalog profiles default to their supported permission-bypass or auto-approval mode. Claude and Codex also default to remote control. cly init displays these flags before saving; enter none to disable both, or supply your own flags. Existing profiles keep their explicit flags. -x remains available for other profiles and does not duplicate an existing bypass flag.

Claude receives --remote-control --dangerously-skip-permissions. For Codex, the standing --remote-control marker tells cly to run codex remote-control start, then connect the terminal using --remote unix:// with --dangerously-bypass-approvals-and-sandbox. Startup failure stops the launch. This requires a Codex version supporting these commands. When resuming a remote Codex session (cly --resume, cly --continue, or cly codex resume), cly omits its standing bypass flag and any bypass requested with -x or the picker’s x key: Codex requires remote resumes to retain the session’s existing permissions. Remote control stays enabled, and new sessions still receive the bypass default. Explicit native arguments after the profile name remain unchanged. Arguments after the profile name remain native agent arguments; put the Codex marker in profile.NAME.flags, not after the profile name.

Defaults checked on 2026-09-21:

Entry Standing defaults Remote access
Claude --remote-control --dangerously-skip-permissions Same terminal session
Codex --remote-control --dangerously-bypass-approvals-and-sandbox Daemon + connected terminal, as above
Gemini --yolo No verified remote-control startup flag
Muse --yolo No remote-control flag in installed CLI help
Kimi --auto Use /remote-control within the session; kimi rc is a separate foreground mode
Qwen --yolo No verified remote-control startup flag
OpenCode --auto Native server/attach workflow; no cloud relay enabled by cly
DeepSeek / Llama Ollama launch prefix, then --dangerously-skip-permissions Claude remote control does not support custom API endpoints

Kimi’s current CLI reference distinguishes --auto (Never Ask) from --yolo (Ask When Needed). cly -x kimi replaces a saved YOLO flag for that launch; the config is preserved. Kimi remote control is a separate foreground mode or an in-session command, so cly does not silently replace the terminal with a web server.

OpenCode’s --auto still respects explicit deny rules. Gemini’s YOLO mode auto-approves tool calls but can retain sandbox/policy restrictions. These native flags do not override administrator policies. Claude remote-control requirements exclude the custom endpoints used by Ollama, so those routes receive only the bypass flag.

These defaults skip ordinary approval prompts; Codex and Muse also disable their sandboxes. Use explicit profile flags or CLY_FLAGS='' for launches that should retain permission checks. See the Codex command reference for remote-control setup.

Portability follow-ups

See the cross-platform reliability review for reproduced installation failures and prioritized macOS, Linux, and Windows improvements.

License

MIT

Dashboard integration

Use cly -x --session KIND:ID to resume an exact locally available session through the same profile and directory logic as the picker. cly --list-sessions emits newline-delimited records with ASCII 31 between epoch, kind, ID, directory, and title. It uses the same readers and Gemini/Kimi scan limits as the picker. Consumers should sort by epoch and treat fields as data, never shell commands.

About

Launch Claude Code from one fixed directory, whatever directory you are in - so its per-directory memory store always loads

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages