- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
cmd_tmp already appended an args.claude_args to the command line, but no parser ever defined it: the only caller passed a hardcoded empty list, so `sxcc --tmp -- --model opus` died on the very flag it was meant to hand over. The other three call sites built the command line without it at all. argv is now split at the first `--` before argparse runs, since argparse would claim those flags as sxcc's own, and the tail reaches all four invocations. Flags pass unfiltered — whether one makes sense next to --resume is claude's call, and a filter here would only go stale. Passing them to a subcommand that never launches claude is an error rather than a silent drop. |
||
| .gitignore | ||
| install | ||
| LICENSE | ||
| README.md | ||
| sxcc | ||
sxcc — snix Claude Code
A command-line tool to manage Claude Code projects, sessions, memory files, and configuration.
Requirements
- Python 3.10+
- rich:
pip install rich
Installation
curl -sL https://sh.snix.me/sxcc | sh
The installer writes sxcc to /usr/local/bin by default; pass a
directory to install elsewhere:
curl -sL https://sh.snix.me/sxcc | sh -s ~/.local/bin
sxcc reads what Claude Code has already written, so on a machine where no
session has ever run there is nothing to read: Claude Code creates
~/.claude/projects/ when the first session starts. Until then the commands
that read data answer No sessions found. and exit 1. sxcc, sxcc --tmp
and sxcc version work regardless — the first two are what create the
directory in the first place.
The same message appears when CLAUDE_CONF or --conf points somewhere
without a .claude/, which is worth checking first if a machine that does
have sessions reports none.
Usage
Naming a project
Commands that take a project — run, sessions, show, stats, rename —
accept the same forms and resolve them the same way. Matches are ranked by how
precisely they identify one project:
| Rank | Matches |
|---|---|
| 1 | Full MD5 hash, or the exact absolute path |
| 2 | Hash prefix, at least 6 characters |
| 3 | Exact directory name — myproject for /home/sam/code/myproject |
| 4 | Exact /rename title |
| 5 | Directory name or path prefix |
| 6 | Partial title |
Only the strongest rank is considered, so an exact directory name is never
shadowed by another project that happens to carry it as a title. If two
projects tie there, a selection list is shown — except when the output is
JSON or the command runs under --force, where the ambiguity is reported
along with the hashes instead of blocking on a prompt.
Short hash prefixes are refused below 6 characters, since they collide often enough that a typo would select a neighbouring project.
The destructive commands are stricter: delete and merge accept only an
exact, unambiguous identifier, and all three of move, merge and delete
can be rehearsed first with --dry-run.
Launch Claude (run)
sxcc # launch claude in current directory
sxcc --tmp # launch in a temporary session (auto-deleted on exit)
sxcc myproject # resume latest session of project "myproject"
sxcc myproject --num 3 # resume 3rd oldest session of project "myproject"
sxcc <session-id> # resume a specific session by ID
sxcc run myproject # explicit run (use when project name matches a subcommand)
sxcc run --tmp # explicit temporary session
A session ID is resolved as a session; anything else names a project (see Naming a project).
Anything after -- goes to claude itself:
sxcc -- --model opus # new session, with claude's own flags
sxcc myproject -- --model opus # resume, with flags
sxcc --tmp -- --add-dir /elsewhere # temporary session, with flags
They are forwarded unfiltered — whether a flag makes sense alongside
--resume is claude's judgement, not sxcc's. Passing them to a command that
does not launch claude is an error rather than silently ignored.
After each session, allowedTools is automatically reset in ~/.claude.json.
Each temporary session runs in its own subdirectory /tmp/claude-tmp/<uuid>, so multiple --tmp sessions can run concurrently. On exit it cleans up its own /tmp/claude-tmp/<uuid>, the matching ~/.claude/projects/-tmp-claude-tmp-<uuid> and ~/.cache/claude-cli-nodejs/ directories, and the project entry in ~/.claude.json; the shared /tmp/claude-tmp parent is removed only when empty.
The cleanup runs on a normal exit, on Ctrl-C, and on SIGTERM — closing the
terminal or logging out included. Only SIGKILL can bypass it, and the next
--tmp run clears whatever a killed one left behind.
List projects
sxcc list # list all projects with memory count and last title
sxcc list --json
A project whose sessions are gone but whose memory files remain is listed as
! no sessions. Its path column shows the encoded directory name, since the
real path is read from the sessions and there are none left. sxcc delete <hash> removes such a project and its memories.
Sessions
sxcc sessions # sessions for current project
sxcc sessions myproject # sessions for project "myproject", grouped by cwd
sxcc sessions --json
See Naming a project for what the argument accepts.
Show session details
sxcc show # details of latest session in current project
sxcc show myproject # latest session of project "myproject"
sxcc show <session-id> # specific session
sxcc show myproject --memory # include project memories
sxcc show --json
Dump transcript
sxcc dump <session-id> # full transcript
sxcc dump <session-id> --user # only user messages
sxcc dump <session-id> --claude # only Claude messages
sxcc dump <session-id> --no-tools # hide tool calls
sxcc dump <session-id> --grep text # filter by content
sxcc dump <session-id> --msg 5 # show message #5
sxcc dump <session-id> --msg 3-7 # show messages #3 to #7
sxcc dump <session-id> --json
dump takes a session ID, and a leading fragment of one is enough — the eight
characters sxcc history prints will do.
Stats
sxcc stats # token usage and cost for all projects
sxcc stats myproject # stats per session for a specific project
sxcc stats <session-id> # stats for a single session
sxcc stats --all # include projects with zero tokens
sxcc stats --json
Prices are fetched from LiteLLM and cached for 24h in /tmp/lite_llm_prices.json.
History (search every prompt)
sxcc history firewall # every prompt containing "firewall"
sxcc history --project dnsleak # every prompt from a project
sxcc history --session <id> # every prompt from one session
sxcc history # the most recent prompts
sxcc history firewall --full # full text, with pasted blocks
sxcc history firewall -n 100 # at most 100 results (default 40)
sxcc history --json
Searches ~/.claude/history.jsonl, which Claude Code keeps across every
project and which outlives the transcripts — most of what it holds belongs to
sessions that have since been deleted. Session ids shown in yellow no longer
exist: those prompts are all that remains of them. For the ones that do, take
the id to sxcc dump.
Only your side of the conversation is recorded there — no replies, no tool
calls. Pasted blocks are stored separately and pruned over time; --full
prints them where they survive and says so where they do not.
Rename (set title on all sessions)
sxcc rename myproject "new title"
Sets the /rename title on all sessions of a project at once. The project can
be named any of the ways above, or by one of its session IDs.
Move (copy project with new path)
sxcc move /path/to/myproject /path/to/myproject-new # copy project, keep original
sxcc move /path/to/myproject /path/to/myproject-new --delete # delete source after move
sxcc move /path/to/myproject /path/to/myproject-new --force # skip confirmation
sxcc move /path/to/myproject /path/to/myproject-new --dry-run # show what would happen
sxcc move <session-id> /path/to/newproject # copy session to new project
sxcc move <session-id> /path/to/newproject --delete # move session (remove from source)
Copies the project folder (or session) in ~/.claude/projects/ to the new encoded path and rewrites the cwd in all session files. If the destination project already exists when moving a single session, the session is added to it.
Merge
sxcc merge <src> <dst> # merge src sessions into dst
sxcc merge <src> <dst> --delete # delete source after merge
sxcc merge <src> <dst> --force # skip confirmation
sxcc merge <src> <dst> --dry-run # show what would happen
src and dst accept: absolute path, project hash (MD5), or session ID.
Delete
sxcc delete <session-id> # delete a single session
sxcc delete <project-hash> # delete all sessions of a project
sxcc delete <project-hash> --keep <session-id-1> <session-id-2> # keep listed sessions
sxcc delete <project-hash> --force # skip confirmation
sxcc delete <project-hash> --dry-run # show what would happen
Deleting a session also removes what Claude Code stores for it outside the
project folder: ~/.claude/file-history/<session-id>, which holds the previous
versions of every file that session edited and is usually the largest part, and
~/.claude/session-env/<session-id>. The confirmation names their total size
before anything is removed.
Deleting every session of a project removes the project itself: its folder in
~/.claude/projects/, the memory files under it, and its entry in
~/.claude.json. The same happens when the session you delete is the last one
left. With --keep, the project survives and so do its memories — they belong
to the project, not to the sessions being removed.
Use sxcc list to find the project hash. Unlike the other commands, delete
takes only a full 32-character hash or an exact session ID — deliberately, so
a partial name cannot wipe a project that merely resembles the one you meant.
merge is restricted the same way, to an absolute path, a full hash, or a
session ID.
Automatically updates ~/.claude.json: removes the project entry if no sessions remain, or updates last* fields if some sessions are kept.
Dry run
move, merge, and delete take --dry-run. The command resolves its
arguments and reports exactly what it would do, then stops before writing
anything:
$ sxcc delete 1f7709c6ff2d65bac115f71839344059 --dry-run
Sessions to delete (3):
44444444-1111-1111-1111-111111111111 2026-09-03 22:17 184.2K
33333333-1111-1111-1111-111111111111 2026-09-02 09:41 12.9K
55555555-1111-1111-1111-111111111111 2026-08-30 18:03 1.1K
Dry run: 3 session(s) would be deleted. Nothing was changed.
move also names the working directory it would rename, which is the part of
the operation that happens outside ~/.claude:
$ sxcc move /home/sam/code/myproject /home/sam/code/renamed --dry-run
Source: ~/.claude/projects/-home-sam-code-myproject
Destination: ~/.claude/projects/-home-sam-code-renamed
Directory will be renamed: /home/sam/code/myproject → /home/sam/code/renamed
Dry run: 3 session(s) would be copied to
~/.claude/projects/-home-sam-code-renamed, and /home/sam/code/myproject
renamed to /home/sam/code/renamed. Nothing was changed.
--dry-run takes precedence over --force: passing both still changes
nothing. Without either flag, these commands ask for confirmation.
Config
sxcc config # global Claude Code configuration overview
sxcc config projects # list all projects from ~/.claude.json
sxcc config project myproject # configuration for a specific project
sxcc config --json
Shell completion
sxcc config bash # print the bash completion script
sxcc config zsh # print the zsh completion script
Completes subcommands, flags, and the project names, hashes, and session IDs
taken from your own data. To enable it, add to ~/.bashrc:
source <(sxcc config bash)
or to ~/.zshrc:
source <(sxcc config zsh)
Version
sxcc version
Configuration
| Environment variable | Default | Description |
|---|---|---|
CLAUDE_CONF |
~ |
Base directory containing .claude/ |
Or use --conf <dir>, which accepts ~, ~/.claude, or ~/.claude/projects
and works either before or after the subcommand. It redirects everything sxcc
touches: .claude/projects/, .claude.json, .claude/history.jsonl, and the
.cache/claude-cli-nodejs/ directories that --tmp cleans up.
The reading commands — list, sessions, show, dump, stats, history,
config — take -j/--json. Output is highlighted on a terminal and written
plain when redirected, so sxcc list --json | jq and
sxcc list --json > file behave as expected.
history.jsonl is only ever read, never written. The two commands that reach
outside ~/.claude say so where they are documented: move renames the
working directory itself, and --tmp removes its own /tmp/claude-tmp/<uuid>
and cache directory on exit.
License
GNU General Public License v3.0 — see LICENSE.