diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index d0601412c0..41530bfe59 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -145,6 +145,17 @@ }, "source": "./plugins/security-guidance", "category": "security" + }, + { + "name": "sessions", + "description": "List, inspect, and delete Claude Code sessions stored locally. Project-scoped by default with cross-platform support.", + "version": "1.0.0", + "author": { + "name": "Venkat Chinni", + "email": "nithinchinni2002@gmail.com" + }, + "source": "./plugins/session-manager", + "category": "productivity" } ] } diff --git a/plugins/session-manager/.claude-plugin/plugin.json b/plugins/session-manager/.claude-plugin/plugin.json new file mode 100644 index 0000000000..346d91eb7a --- /dev/null +++ b/plugins/session-manager/.claude-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "sessions", + "description": "List, inspect, and delete Claude Code sessions stored locally", + "version": "1.0.0", + "author": { + "name": "Venkat Chinni", + "email": "nithinchinni2002@gmail.com" + } +} diff --git a/plugins/session-manager/README.md b/plugins/session-manager/README.md new file mode 100644 index 0000000000..e374dd196b --- /dev/null +++ b/plugins/session-manager/README.md @@ -0,0 +1,76 @@ +# Sessions Plugin + +Manage Claude Code sessions stored on your local machine. List, inspect, and delete sessions that accumulate over time. + +## Why? + +Claude Code stores every conversation as session files locally. Over time these accumulate and there's no built-in way to clean them up. This plugin adds that capability. + +## Commands + +### `/sessions:list [--all | search term]` + +List sessions for the **current project** by default. Pass `--all` to see sessions across all projects. + +Shows: +- Session title and ID +- Start date +- Disk usage +- Orphan status (sessions with conversation data but no metadata) + +### `/sessions:delete [session-id | search term | --all]` + +Delete one or more sessions from the **current project**. Pass `--all` to operate across all projects. + +Supports: +- Deleting by session ID (UUID) +- Searching by title +- Interactive selection from a numbered list +- Bulk deletion + +Always asks for confirmation before deleting. Will not delete the currently active session. + +**Files removed per session:** +- `{config_dir}/projects/{path}/{sessionId}/` (subagent logs directory) +- `{config_dir}/projects/{path}/{sessionId}.jsonl` (conversation data) +- `{config_dir}/sessions/{pid}.json` (metadata) + +## Cross-Platform Support + +The plugin automatically detects the correct config directory: + +| Platform | Config Directory | Notes | +|----------|-----------------|-------| +| macOS | `~/.claude` | Default location | +| Linux | `$XDG_CONFIG_HOME/claude` | Falls back to `~/.claude` | +| Windows | `%APPDATA%\claude` | Falls back to `%LOCALAPPDATA%\claude`, then `~\.claude` | +| Any | `$CLAUDE_CONFIG_DIR` | Override via environment variable (highest priority) | + +## Session Storage Layout + +``` +{config_dir}/ +├── sessions/ +│ └── {pid}.json # Session metadata (pid, sessionId, cwd, startedAt) +├── projects/ +│ └── {encoded-cwd}/ +│ ├── {sessionId}.jsonl # Full conversation history +│ └── {sessionId}/ # Subagent logs (tied to session) +│ └── subagents/ +│ └── agent-*.jsonl +└── history.jsonl # All user prompts across sessions +``` + +## Installation + +Launch Claude Code with the plugin directory: + +```bash +claude --plugin-dir /path/to/plugins/session-manager +``` + +Or to always have it available, add a shell alias: + +```bash +alias claude='claude --plugin-dir /path/to/plugins/session-manager' +``` diff --git a/plugins/session-manager/commands/delete.md b/plugins/session-manager/commands/delete.md new file mode 100644 index 0000000000..d3f7b6a354 --- /dev/null +++ b/plugins/session-manager/commands/delete.md @@ -0,0 +1,92 @@ +--- +allowed-tools: Read, Glob, Bash(rm:*), Bash(rm -r:*) +description: Delete Claude Code sessions for the current project +argument-hint: "[session-id, search term, or --all]" +--- + +## Context + +You are helping the user delete Claude Code sessions stored on their local machine. By default, only show and delete sessions for the **current project directory**. If the user passes `--all` as part of `$ARGUMENTS`, operate across all projects. + +### How to find the config directory + +The Claude Code config directory varies by platform: +- **Override**: `$CLAUDE_CONFIG_DIR` (if set) +- **macOS**: `~/.claude` +- **Linux**: `$XDG_CONFIG_HOME/claude` (fallback: `~/.claude`) +- **Windows**: `%APPDATA%\claude` (fallback: `%LOCALAPPDATA%\claude`, then `~\.claude`) + +### How sessions are stored + +1. **Session metadata**: `{config_dir}/sessions/{pid}.json` — contains `pid`, `sessionId`, `cwd`, `startedAt` +2. **Session conversation data**: `{config_dir}/projects/{encoded-path}/{sessionId}.jsonl` — the actual conversation log. The `{encoded-path}` is the working directory with `/` replaced by `-` and a leading `-` (e.g., `/Users/me/project` becomes `-Users-me-project`). +3. **Session history**: `{config_dir}/history.jsonl` — contains all user prompts with their `sessionId` + +### How to scope to current project + +Convert the current working directory to the encoded path format. For example: +- CWD: `/Users/jane/projects/my-app` +- Encoded: `-Users-jane-projects-my-app` +- JSONL location: `{config_dir}/projects/-Users-jane-projects-my-app/*.jsonl` + +## Steps + +### Step 1: Find sessions + +**IMPORTANT**: Session JSONL files are UUID-named files directly under the project directory (e.g., `a1b2c3d4-e5f6-7890-abcd-ef1234567890.jsonl`). There are also `subagents/` subdirectories containing agent log files — **ignore those**. Use a UUID glob pattern to match only session files: + +Use **Glob** to find session JSONL files: +- **Project-scoped** (default): `{config_dir}/projects/{encoded-cwd}/????????-????-????-????-????????????.jsonl` +- **All projects** (if `--all` in arguments): `{config_dir}/projects/*/????????-????-????-????-????????????.jsonl` + +Then use **Read** to get the title from the first few lines of each JSONL (look for `"type": "custom-title"`). + +Also use **Glob** and **Read** on `{config_dir}/sessions/*.json` to find matching metadata files. + +### Step 2: Identify which session(s) to delete + +If the user provided `$ARGUMENTS` (besides `--all`): +- If it looks like a UUID, match it against session IDs +- If it's a number, treat it as a selection from the list +- Otherwise, search session titles for the term + +If no specific session was identified, present a numbered list and ask the user which session(s) they want to delete. Support: +- A single number (e.g., "3") +- Multiple numbers (e.g., "1, 3, 5") +- "all" to delete all listed sessions +- A search term to filter + +### Step 3: Confirm before deleting + +**IMPORTANT**: Before deleting, clearly show the user: +- Session ID +- Session title (if available) +- Start date +- Files that will be deleted (full paths) + +Ask for explicit confirmation. Do NOT delete without the user saying yes. + +**Do not delete the current session.** You can identify the current session because its session ID matches the one in the most recent metadata file for the current working directory. + +### Step 4: Delete the session files + +For each confirmed session, delete these in order: +1. The subagents directory (if it exists): `rm -r {config_dir}/projects/{encoded-path}/{sessionId}/` — this contains subagent log files tied to the session +2. The conversation JSONL: `rm {config_dir}/projects/{encoded-path}/{sessionId}.jsonl` +3. The matching metadata file (if any): `rm {config_dir}/sessions/{pid}.json` — find the right one by reading each metadata JSON and matching the `sessionId` field + +Delete one item at a time. Only use `rm -r` on the `{sessionId}/` subagents directory — never on anything else. + +### Step 5: Summary + +Report: +- How many sessions were deleted +- Which files were removed +- Any errors encountered + +### Important notes + +- Use **Read** and **Glob** for discovery. Only use **Bash** for the actual `rm` deletion step. +- Read multiple files in parallel when possible for speed. +- Never delete the currently active session. +- Never use `rm -rf` or wildcards — only delete specific named files. diff --git a/plugins/session-manager/commands/list.md b/plugins/session-manager/commands/list.md new file mode 100644 index 0000000000..ed33b4e548 --- /dev/null +++ b/plugins/session-manager/commands/list.md @@ -0,0 +1,84 @@ +--- +allowed-tools: Read, Glob +description: List Claude Code sessions for the current project +argument-hint: "[--all to show all projects]" +--- + +## Context + +You are listing Claude Code sessions stored on the user's local machine. By default, only show sessions for the **current project directory**. If the user passes `--all` as `$ARGUMENTS`, show sessions across all projects. + +### How to find the config directory + +The Claude Code config directory varies by platform: +- **Override**: `$CLAUDE_CONFIG_DIR` (if set) +- **macOS**: `~/.claude` +- **Linux**: `$XDG_CONFIG_HOME/claude` (fallback: `~/.claude`) +- **Windows**: `%APPDATA%\claude` (fallback: `%LOCALAPPDATA%\claude`, then `~\.claude`) + +### How sessions are stored + +1. **Session metadata**: `{config_dir}/sessions/{pid}.json` — contains `pid`, `sessionId`, `cwd`, `startedAt` +2. **Session conversation data**: `{config_dir}/projects/{encoded-path}/{sessionId}.jsonl` — the actual conversation log. The `{encoded-path}` is the working directory with `/` replaced by `-` and a leading `-` (e.g., `/Users/me/project` becomes `-Users-me-project`). +3. **Session history**: `{config_dir}/history.jsonl` — contains all user prompts with their `sessionId` + +### How to scope to current project + +Convert the current working directory to the encoded path format used in `{config_dir}/projects/`. For example: +- CWD: `/Users/jane/projects/my-app` +- Encoded: `-Users-jane-projects-my-app` +- JSONL location: `{config_dir}/projects/-Users-jane-projects-my-app/*.jsonl` + +## Steps + +### Step 1: Determine the config directory + +Use the platform detection logic above. For most users this will be `~/.claude`. + +### Step 2: Find session JSONL files + +**IMPORTANT**: Session JSONL files are UUID-named files directly under the project directory (e.g., `a1b2c3d4-e5f6-7890-abcd-ef1234567890.jsonl`). There are also `subagents/` subdirectories containing agent log files — **ignore those**. Use a UUID glob pattern to match only session files: + +Use the **Glob** tool to find session files: +- **Project-scoped** (default): Glob for `{config_dir}/projects/{encoded-cwd}/????????-????-????-????-????????????.jsonl` +- **All projects** (if `$ARGUMENTS` contains `--all`): Glob for `{config_dir}/projects/*/????????-????-????-????-????????????.jsonl` + +This UUID pattern ensures subagent files in nested directories are excluded. + +### Step 3: Read session details + +For each JSONL file found: +1. Use **Read** to read the first 5 lines of each JSONL file to find the `custom-title` entry (it's typically the first line with `"type": "custom-title"`) +2. Note the file size from the Glob results or by reading the file + +Also use **Glob** to find `{config_dir}/sessions/*.json`, then **Read** each one to get metadata (`sessionId`, `cwd`, `startedAt`). Match these to the JSONL files by `sessionId`. + +JSONL files that have no matching metadata JSON are **orphaned sessions** — mark them as `[orphan]`. + +### Step 4: Display results + +Present a clean numbered list: + +``` +Sessions for /Users/jane/projects/my-app: + +1. Add authentication flow + ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890 + Started: 2026-03-13 14:53 + Size: 678.0 KB + +2. (no title) [orphan] + ID: f9e8d7c6-b5a4-3210-fedc-ba0987654321 + Started: 2026-03-10 09:00 + Size: 12.5 KB + +Found 2 session(s): 1 active, 1 orphaned (total: 690.5 KB) +``` + +If `$ARGUMENTS` contains a search term (not `--all`), filter sessions by matching the term against title, session ID, or directory. + +### Important notes + +- Use **only** the Read and Glob tools. Do NOT use Bash. +- Read multiple files in parallel when possible for speed. +- Do not include the currently active session's ID in the output — note it as "(current session)" instead.