Launch, watch, search and resume your coding CLI sessions: Claude Code conversations and the Codex sessions beside them.
- Search through all your Claude Code conversations, and your Codex sessions beside them (each row starts with its agent: an orange
✻for Claude,⬡for Codex; a Codex row's grey line startscodex, so searchingcodexfinds them all) - See session names (your custom titles or Claude's auto-generated ones) in the list
- Preview conversation context with search term highlighting
- See context size (tokens as of the last reply), message counts, hit counts, and file size per conversation
- Resume conversations directly from the search interface
- Background tasks and subagents: a session open in
claudeshows⧗Nfor its running background commands and monitors and a pink◆Nfor its running subagents, and the preview lists both with how long each has run - Auto-refreshes every minute; a green
●marks conversations open in a runningclaude, and ones started by another session'sclaude -psit└under it - Rename conversations (
Ctrl+X E) - Delete conversations with confirmation prompt
- Prune bloated conversations losslessly (
ccs prune) - Codex sessions: read from
$CODEX_HOME/sessions(default~/.codex), with their model and context, PRs theirgh pr create/mergeprinted, and a live●(green idle, amber busy) while acodextab has the thread open. Enter switches to that tab, else openscodex resume <id>in a new tab withccs launch --codex's sandbox (network on, your approval mode);Ctrl+Frunscodex fork <id>; the message box sends withcodex queue. A headlesscodex execrun sits└under the Claude session that ran it (when its prompt is on the command line), and a Codex subagent under its parent thread. ccs never renames, deletes or prunes a Codex session's files Their preview shows tokens and an estimated cost at OpenAI's published per-token prices (requests over the long-context threshold at its rate; a model ccs has no price for shows tokens only). - A coordinator session at the top of the list that starts one named session per task, tracks their PRs and merge order, and closes them when they finish (
ccs coordinator, orCtrl+X Oin the list) - Start and close named sessions in iTerm tabs or tmux windows (
ccs launch,ccs close, orCtrl+X N/Ctrl+X Kin the list) - Watch your open PRs and get one JSON line per change (
ccs watch) - Record which session owns each PR, and list your open PRs with their owners (
ccs claim,ccs prs) - Tell the session that claimed a PR when its checks fail, it conflicts or it gains unresolved threads (
ccs watch) - Pass flags through to
claude(e.g.,--plan) - Usage screen (
Tab): the last 12 hours of token usage across all sessions (including subagents) as three charts (cache-write disposition, context assembly, output), a summary with effective tokens, and your live 5-hour and weekly allowance. The allowance reads Claude Code's stored login read-only (macOS Keychain, else~/.claude/.credentials.json); ccs never refreshes or writes it, so if it has expired, openclaudeto refresh it - Checks for new releases at startup and every 2 minutes (update steps are logged to
~/Library/Logs/ccs/update.log) and offers to update and restart from a popup (viabrew upgradefor Homebrew installs, otherwise by replacing the binary with the checksum-verified release). Every update, Homebrew included, is checked against a signature that only ccs's release pipeline onmaincan make, so a release uploaded any other way is refused
ccs mcp is an MCP server that lets Claude find and read your earlier Claude Code sessions. Add it once:
claude mcp add --scope user ccs -- ccs mcpClaude starts it when needed (no ccs window has to be open, no network port). It has six tools: search_sessions (every word must appear; sessions named after the query first, then by matching messages and recency, each with a snippet and its resume command), list_sessions (most recent first; both leave out headless runs unless include_headless) read_session (a session's messages, paged, optionally only those around a search term), launch_session / close_session, which do what ccs launch and ccs close do (below), and list_prs, which is ccs prs --json. It searches the same window as the TUI (60 days, files under 1GB); use ccs mcp --all or --max-age=N to change it.
ccs launch --name fix-login --brief brief.md --cwd ~/code/app # claude, the brief as its first prompt
ccs launch --name fix-login --resume <session-id> # resume one under a name (refused, with no tab opened, when there's no such session)
ccs launch --name tests --brief brief.md --codex # codex instead
ccs close fix-loginccs launch needs zsh at /bin/zsh. It opens a background tmux window when run inside tmux, otherwise an iTerm tab (at the end of the tab strip if iTerm's "new tabs at the end" setting is on, focus staying where it was), clears the prompt and runs a launcher kept in ~/Library/Caches/ccs/launch/<name>/: a login zsh that sources ~/.claude.secret when there is one and runs claude "<brief>" --name <name> $CCS_CLAUDE_ARGS, the brief first since --channels takes every word after it. It then waits up to 20 seconds for a session with that name to start, printing its pid and tty, and fails if none does. A name already running is refused. With --codex it runs codex -s workspace-write -a on-request -c sandbox_workspace_write.network_access=true --add-dir <that folder> --add-dir <ccs's settings folder>: your usual approval mode, network on (Codex's sandbox has none by default, so git and gh would fail), the launch folder (how ccs finds the session again) and ccs's settings folder (so ccs claim can write) writable. It also waits for Codex's transcript of the session and prints its thread id, which nudges need; a Codex session that writes none in time fails the launch.
ccs close <name> finds the one running session with that name (two with the same name are left alone), stops it, confirms its process has exited, then closes its iTerm tab (or tmux pane). A session with no terminal (an app's, or claude --bg) is refused.
On macOS, ccs://session/<name> switches to that running session's iTerm tab or tmux window, so a session can mention another one as something you can click:
ccs link install # once: creates ~/Applications/CCS Links.app and registers it for ccs:// links
ccs link status # which app opens ccs:// links, and which ccs it runs
ccs link uninstall # removes the appOpening a link only ever focuses. A session that isn't running, or a name two sessions share, shows a short alert saying so; nothing is started or resumed. Any web page or message can send you one of these links, so all it can do is bring one of your tabs to the front. The link has to be exactly ccs://session/<name>, with the name in the form ccs launch accepts (letters, digits, ., _ and -, starting with a letter or digit, at most 64 characters). Anything else is refused, so a session named with spaces can't be linked. The name is only compared with the running sessions' names; it never reaches a shell or AppleScript.
The first click asks you to let CCS Links control iTerm, which it needs to pick the tab. If you refuse, you can change it under Privacy & Security, Automation in System Settings. A session in tmux needs an attached tmux client; its iTerm tab is brought forward too, but tmux in another terminal only switches window, without bringing that terminal to the front. iTerm is never started: a session in any other terminal is refused.
The app runs Homebrew's bin/ccs link, which stays put when brew upgrade or ccs's own update replaces the keg, so upgrades keep it working with nothing to redo. If a new ccs changes the handler or the ccs it points at has gone, ccs rebuilds an installed one when it next starts; it never installs one you didn't ask for. brew uninstall ccs leaves the app behind, so run ccs link uninstall first.
Whether a link is clickable depends on the app showing it. Browsers ask before opening it. Apps that only linkify http addresses show it as plain text, where you can run open ccs://session/<name> instead.
The coordinator is one Claude Code session that keeps your other sessions moving and never does the work itself. Tell it what you want done; it starts a named session for each ask, tracks who owns which PR and what order they must merge in, tells you what needs you, and closes sessions when they finish.
ccs coordinator # open it: its tab if it's running, resumed if not, set up if there is none
ccs coordinator --adopt my-hub # make an existing session the coordinator instead
ccs coordinator --release # make it an ordinary session again; it keeps runningccs offers it once, in a popup, in iTerm or tmux when you have none (Esc doesn't ask again; Ctrl+X O still opens the same offer). It waits until you aren't typing a search, a message or a prompt, and ignores keys for its first second, so nothing meant for the list answers it. Setting up asks once, shows exactly what will change, and needs none of your own config or plugins:
- Its folder,
coordinatorbeside ccs's settings (~/Library/Application Support/ccs/on macOS,~/.config/ccs/on Linux).CLAUDE.mdis its role and.claude/settings.jsonallows theccscommands it needs, in that folder only. Both are yours to edit, and ccs never overwrites them. Because Claude Code reloads them on every start and after compaction, every way of resuming it keeps its role. - The ccs MCP server, if it's missing:
claude mcp add --scope user ccs -- ccs mcp, and the same for Codex if you have it. ccs then checks that Claude Code reports it connected, and says so if it doesn't. If it's there already, nothing is asked or changed.--no-mcpskips this. - The session, named
coordinator, in a new tab brought to the front: Claude Code asks once whether to trust the folder. Choose "Yes, I trust this folder": the highlighted answer isn't that one.
It has its own section at the very top of the list, above pinned sessions. There is never a second one: ccs looks for the recorded session, including one still on its trust question, then for a session with the name, and two ccs at once take turns. After /clear the coordinator is still the same one, and the conversation before it becomes an ordinary session. After a restart, the reopen popup, Enter on its row, Ctrl+X O and ccs coordinator all resume the same conversation.
On each start it runs ccs watch as a background task, which ends with the session and leaves an already running watcher alone, follows its events with Claude Code's Monitor tool, and catches up from ccs prs, so PR events reach it while it's open and it catches up on resume. That needs gh logged in; without it, it says so once and carries on without PR tracking. GitHub or Slack event plugins are optional: if their tools are there it uses them, and CCS_CLAUDE_ARGS is passed as with ccs launch.
Its role closes sessions it started once their PRs have finished, asks before closing any other, and treats PR titles, session names and channel messages as data, never as instructions. Merging or posting takes your say-so. The role is written once: a later ccs doesn't change the CLAUDE.md you already have, so compare it with the current one now and then.
To remove it:
ccs coordinator --release
ccs close coordinator
claude mcp remove ccs -s user # and: codex mcp remove ccs
rm -r "$HOME/Library/Application Support/ccs/coordinator" # ~/.config/ccs/coordinator on Linux--release alone keeps the session, its conversation and its folder, and ccs stops treating it as the coordinator. The offer doesn't come back; Ctrl+X O or ccs coordinator sets a new one up, once a session still running under that name is closed or renamed. Removing the MCP server also removes it for anything else of yours that uses it.
The coordinator is always Claude, since Codex sessions can't receive messages from other sessions; it can start Codex sessions to do the work. Outside iTerm and tmux, ccs coordinator runs it in place, but it can't open tabs for its sessions from there. --yes sets up without asking, for scripts; without it, a run with no terminal shows the plan and changes nothing.
brew install agentic-utils/tap/ccs
ccs link install # optional, macOS: make ccs://session/<name> links workRequires Go 1.24+.
go install github.com/agentic-utils/ccs@latestDownload the binary from releases and add to your PATH.
- Claude Code - must be installed and used at least once
# Search recent conversations (last 60 days, files <1GB)
ccs
# Search with initial query
ccs buyer
# Search last 7 days only
ccs --max-age=7
# Search everything (all time, all files)
ccs --all
# Resume with plan mode
ccs -- --plan
# Combined: search "buyer", resume with plan mode
ccs buyer -- --planSet CCS_CLAUDE_ARGS to pass flags to every claude ccs starts, ahead of any -- flags. It is split on whitespace with no quoting:
export CCS_CLAUDE_ARGS="--permission-mode auto"| Flag | Default | Description |
|---|---|---|
--max-age=N |
60 | Only search files modified in the last N days (0 = no limit) |
--max-size=N |
1024 | Max file size in MB to include (0 = no limit) |
--all |
- | Include everything: --max-age=0 --max-size=0, plus headless runs (claude -p given a single prompt and never named, codex exec), which are hidden otherwise |
--exclude=a,b |
observer-sessions | Exclude project dirs whose path contains any of these substrings |
- Text boxes (the search, the message box) edit like Claude Code's prompt:
Ctrl+A/Ctrl+Estart/end,Ctrl+K/Ctrl+Udelete to the end/start,Ctrl+Wthe word before,Ctrl+Yputs back what they deleted,Alt+B/Alt+Fmove by word. So ccs's own actions areCtrl+Xthen a letter (Ctrl+X Ctrl+Wworks too) ↑/↓orCtrl+P/N- Move through the list- Background sessions (
claude --bg) showbg <state>on the grey row: Enter opens one withclaude attachin a new tmux window or iTerm tab, andCtrl+X Ktwice stops it (on a session in a terminal tab,Ctrl+X Ktwice stops it and closes the tab). One started from another session'sclaude --bgsits under it - Messages between sessions show at both ends: the sender's preview shows each
SendMessageasTo <session>(✓ arrivedonce it's in that session's transcript), the recipient'sFrom <session> - A live session run by an app without a terminal shows
in <app>. One in T3 Code opens in T3 Code with Enter, at its thread; any other app gets a hollow○, since ccs can't switch to it, and Enter says to open it there. Messaging it (Ctrl+S) and forking it (Ctrl+F) work either way - Each open session has a circle,
●(or○in an app ccs can't open), coloured by its state: magenta waiting on you, light magenta asked you something, cyan done, green idle, amber busy. Under a section heading, which already names the state, it shows only when it adds something: a done session, one in another app, or a nested one in a different state; pinned sessions always have it - The list is in sections by state, each with a header: waiting on you, asked you something, idle (a cyan
●marks one finished since you last looked at it in ccs; it turns green once you select it and move on, without moving), busy, not open inclaude Ctrl+X W- Sessions waiting on you: answer, open or snooze them. Shows their question, a box to answer, Enter opens the session's tab, Esc snoozesCtrl+X R- Record a CPU profile while you do whatever feels slow, thenCtrl+X Ragain to save it beside the update log (~/Library/Logs/ccs/cpu-<time>.pprofon macOS; read it withgo tool pprof -top). The header saysrecording profileuntil you stop it.CCS_CPUPROFILE=path ccsrecords the whole run insteadCtrl+X I- Automatic updates, off by default: turned on, a new ccs release downloads in the background and installs once you're away (ccs not focused, or no key for 3 minutes, with nothing unsent), then ccs restarts where you were and says it updated itself, with what changed. Off, new versions are offered in a popup instead. Installs from before this was opt-in keep the setting they had. The header shows which (auto-update on), remembered across restarts- The modes these keys toggle (auto-focus, auto-update) sit on the right of the header, in grey with their keys, and only
onis green;offstays grey Ctrl+X H- Show or hide headless runs (claude -pgiven a single prompt and never named,codex exec), hidden unless ccs started with--all. Not shown in the header. Not saved: the next ccs starts as its flags sayCtrl+X A- Auto-focus: when a session starts waiting on a question or permission prompt, switch to its iTerm tab or tmux pane (without pulling iTerm in front of another app), once you've stopped typing for 2 seconds (moving the mouse doesn't count), and not again until that question is answered. Questions already waiting when ccs starts count too; one it already switched to before a restart doesn't. Off by default, remembered across restartsCtrl+X P- Pin the selected session: pinned sessions sit in their own section at the top, whatever their state, in the order you pinned them;Alt+↑/Alt+↓move one among them. Again to unpin. Kept across restartsCtrl+X C- With folders grouped, collapse the selected session's folder to its most urgent session, its header counting the rest (▸ api 5 · 4 more). Again to expand. Kept across restartsCtrl+X S- Put the selected session away: settle it (until its next message) or snooze it (an hour, 4 hours, tomorrow 9:00). It moves to the settled or snoozed section at the bottom, and comes back early if it waits on you. Again to bring it backCtrl+X G- Group the list by folder within each state section (a worktree under.claude/worktreescounts as its repo), the most urgent group first. Again to ungroup. ccs remembers this and the ^X T layout, and reopens the way you left itCtrl+X D- Fold the details above the conversation to one line (name, project, model, context %, PR, task and subagent counts, size), or show them in full; clicking them does the same, unless the click is on a link. One line by default, remembered across restartsCtrl+X T- Switch between the sidebar (sessions in a narrow column beside the conversation, the default; each on two rows: the title, then a grey line of when it was last active, its context, project and PR counts) and the full-width table with every column (when, project, model, size, context, messages, hits, PRs). The list and the conversation each have a scrollbar whose thumb is the share in viewEnter- Resume it in claude, in a new tab in tmux or iTerm. On one already open inclaude(●), go to its iTerm tab / tmux pane insteadCtrl+F- Fork it: a new session with the same history, in a new tab (claude --resume <id> --fork-session); the original is left as it wasCtrl+D- Delete its transcript file; asks first, can't be undone (the file is removed, not moved to the bin)Ctrl+X N- Start a new session in an iTerm tab or tmux window, in the selected session's folder: type its name, Enter, then its brief, Enter (ccs launch)Ctrl+X O- Open the coordinator, resuming it if it isn't running, or offer to set one up if there is none (see The coordinator)Ctrl+X E- Edit its name, as/renamedoes (not while it's open inclaude; use/renamethere)Ctrl+R- Refresh sessions, PRs and allowance now; check for an updateCtrl+X X- Shrink its file, keeping the dialogue; loses rewind history. It drops the copies of tool output Claude Code stores twice and the rewind checkpoints, so the conversation still resumes in full but/rewindhas nothing to go back to. Asks first, can't be undone, not while it's open inclaude(see Pruning)PgUp/PgDn- Scroll the conversation (the mouse wheel too)- Mouse wheel - scrolls whatever is under the pointer (the conversation or the list); click a session to select it, click a link in the conversation to open it. Hold
⌥ Optionwhile dragging to select text in iTerm Esc- Clear the search and go back to the top- Message box - select an open (
●) session and pressCtrl+S(or click the box) to type in the box under its conversation;Entersends (through Claude Code's message socket, or typed into its iTerm tab / tmux pane if the socket isn't reachable),Escreturns to the search. A screenshot goes in withCtrl+Vfrom the clipboard (macOS), or by pasting or dropping its file anywhere in ccs: it shows as[Image #1], and the session gets a copy to read Tab- Token use of every session in the last 12h, and your allowance: charts over time, totals, cache mix and the 5-hour and weekly limits.Tabagain to go backCtrl+X U- Switch Claude account (needs cswap, e.g.uv tool install claude-swap); clicking the account email does the same?- Show the shortcuts that apply right now (the header lists only the common ones, in compact form:^Sfor Ctrl+S, and drops hints on narrow terminals rather than wrapping)Ctrl+L- What changed in each ccs release, newest first, the installed and newer ones marked; scroll with ↑↓, PgUp/PgDn or the wheelCtrl+O- Links: the sessions the selected one messaged or heard from (Enter selects that session in the list), its PRs, then the links in the visible part of the conversation, each PR with its status; type to filter them (text, address or status, e.g.merged), ↑↓ and Enter to open one in the browser, staying open for the next (clicking a link works too)Ctrl+]/Ctrl+\- With a search typed, jump to the next / previous matching message in the conversation (wraps round); the preview showshit 2/5Ctrl+C- Quit
Conversation files grow large over time. ccs prune shrinks them by removing data that duplicates content kept elsewhere, so pruned conversations still resume with their full dialogue intact:
toolUseResultfields - a copy of the tool result already present inmessage.contentfile-history-snapshotlines - rewind/checkpoint backups (pruning loses rewind history, not the conversation)
User and assistant messages are never modified, and a file is only rewritten if its conversation line count is unchanged.
ccs prune is a dry-run preview by default - it only reports what it would reclaim. Pass --apply to actually rewrite the files.
ccs prune # preview savings, change nothing (files >= 50MB)
ccs prune --apply # prune after a confirmation prompt
ccs prune --apply --min-size=200 # only files >= 200MB
ccs prune --apply --no-tool-results # keep tool results, only drop snapshot backupsRun ccs prune --help for all flags.
You can also prune a single conversation from the search interface: select it and press Ctrl+X X (with confirmation).
ccs watch checks one author's open PRs (by default the user gh is logged in as, in every owner's repos; --owner narrows it to one org or user) every 3 minutes and appends a JSON line for each change to ~/Library/Logs/ccs/pr-events.jsonl (and prints it), for a script or a coordinating Claude session to follow with tail -F. It uses gh and GitHub's REST API.
ccs watch # your PRs (the gh user's), every 3 minutes
ccs watch --author me --owner my-org --interval 5m
ccs watch --once # one pass, then exitEvents: new, checks_failing (with the failing checks), checks_passed, needs_review (awaiting review now: see below), review_not_needed, ready (approved, checks green, not a draft), conflicts, threads_unresolved (with unresolved, when the count of unresolved review threads rises), threads_resolved (back to none), threads_unanswered (with count and the thread ids in threads, when an unresolved thread's last comment isn't yours: a new one, or a reviewer's new comment on one), merged, closed. Any failed check, optional or not, counts as failing, and so does an unresolved review thread: such a PR is never ready or needs_review. Threads are counted only for PRs whose checks pass, with one small GraphQL query each (REST doesn't say whether a thread is resolved). Each line has at, event, pr, repo, number, title and head.
{"at":"2026-11-03T09:12:51Z","event":"checks_failing","pr":"https://github.com/o/r/pull/220","repo":"o/r","number":220,"title":"...","head":"0fc4f95...","checks":["setup"]}The first run records what it finds and writes one watch_started line, plus needs_review for PRs already awaiting review; it doesn't report every PR as news. Its state is kept beside ccs's settings (pr-watch.json), so a restart reports what changed while it was stopped, without repeating anything. Only one ccs watch runs at a time.
A consumer that asks people for reviews (the two-slack plugin's does) needs only these two events, plus merged and closed. Their fields won't change without a major release.
needs_review:{at, event, pr, repo, number, title, head, review: "required"}. The PR is awaiting review right now: checks green (optional ones included), not a draft, no unresolved review thread, review required, not approved. ccs watch asks GitHub again just before emitting it, so stale data never says a PR is waiting. Once per head commit. The first run emits it for PRs already waiting.review_not_needed:{at, event, pr, repo, number, title, head, reason}. A PR that last gotneeds_reviewno longer awaits review.headis the commitneeds_reviewwas for.reasonis one ofapproved,changes_requested,new_head,draft,checks,threads,mergedorclosed. It's emitted once, as soon as the change is seen. For a new head that still needs review, it comes before that head'sneeds_review. For a merge or close, it comes just beforemergedorclosed.
Drop a queued PR when review_not_needed, merged or closed for it arrives before you post. Whether a PR awaits review is kept in pr-watch.json, so a restart neither misses nor repeats either event. ccs prs --json rows carry head and needs_review for a consumer's start-up sweep.
ccs doesn't post review requests itself: the two-slack plugin's review-requests consumer does, from these events or from GitHub directly.
After each pass, ccs watch tells the session that claimed a PR (ccs claim, below) what's wrong with it: checks failing (by name), conflicts with its base, or review threads waiting on a reply: unresolved, with the last comment not yours. Yours means the account ccs watch runs as (--author, by default the gh login, which the sessions reply through too) and any --self-logins (comma separated, for a bot or co-author acting for you). A thread the session has replied to stops counting even while it waits for you to resolve it, and the same threads are never told twice: only a new one, or a reviewer's new comment on one, is. Failing checks and conflicts are told once per PR, head commit and reason, so it isn't nagged every pass; a new commit that still fails is told again. A session that isn't running, or a PR nobody claimed, gets nothing beyond the usual events.
The notice goes over the session's own message socket, as ccs watch, and says it's an automatic status notice, not typed by you, so the session treats it as information rather than your instruction. A Codex session has no socket: its notice goes in with codex queue --thread <id>, which hands it to the running session at its next turn, opening with the same "automatic status notice, not typed by the user" line, since Codex shows it as a user message:
<PR URL> (<title>) has 2 review threads waiting on a reply; checks failing: setup.
This session claimed it with ccs claim. If it's yours, deal with it; if not, run: ccs claim <PR URL> --release
Events: nudged (pr, head, session, reasons) and nudge_failed (the same plus the error; tried again next pass). What was sent is kept in nudges.json beside ccs's settings, so a restart never sends it again. --no-nudge turns this off.
A session that owns a PR says so by running ccs claim <PR URL> (--release to give it up). ccs works out which session ran it from the claude process it runs under, and records the session's id and name in claims.json beside its settings. In Codex it uses the CODEX_THREAD_ID Codex gives every command (Codex's sandbox can't run ps), named by its ccs launch name, else Codex's title for the thread; such a claim counts as running while its ccs launch codex process runs, or, for one ccs didn't launch, while Codex wrote to its transcript within 12 hours. A claim ends by itself when the PR merges or closes, or the session stops.
ccs prs lists your open PRs with their owners, needing you first, and flags any PR nobody has claimed (UNOWNED) and any PR two running sessions both claim (CONTESTED). It uses ccs watch's state when that is under 10 minutes old, and otherwise asks GitHub (REST) itself. Without --author, it lists the running ccs watch's author and owner, else the gh user's PRs in every owner's repos; --statusline never asks gh. A PR with a failed check, optional or not, needs you.
ccs claim https://github.com/o/r/pull/12
ccs prs # one line per PR
ccs prs --json # the same, for scripts
ccs prs --statusline # e.g. "PRs 3 ready · 1 need you · 2 unowned", from saved state only
ccs prs --claude-session-id <id> --statusline # one session's PRs: "PRs ✓1 ✗1 2" (ready, need you, waiting)
ccs prs --codex-session-id <thread id> --json # a Codex session's--claude-session-id keeps only the PRs a Claude Code session claims (its id is the session_id in Claude Code's status line input), and --codex-session-id a Codex session's (its thread id); each matches only claims of its own kind, by id, not name, so a /rename or two sessions with one name can't confuse it. --json gives each PR's owners (names) and owners_detail (name, kind claude or codex, session id).
--statusline never asks GitHub, so it is quick enough for Claude Code's status line; it prints nothing when there is nothing to count, and adds (stale) when ccs watch hasn't refreshed the state for 10 minutes.
ccs reads conversation history from ~/.claude/projects/ and presents them in an interactive TUI. Live sessions come from ~/.claude/sessions/<pid>.json, counted only while that pid is still running. When you select a conversation, it changes to the original project directory and runs claude --resume <session-id>.
MIT
