Launch claude from anywhere: interactive recent-projects picker
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
When I open a new terminal, I'm always in my home directory. Running claude with no arguments just starts a blank new session — there's no way to get back to a recent project without already knowing the path, cd-ing there manually, and then running claude again.
If I have several active projects I switch between regularly, this friction adds up constantly.
Proposed Solution
When claude is run with no arguments from the home directory, show an interactive project picker listing recent projects from ~/.claude/projects/, sorted by last activity. Each row would show the project name, last active time, and number of chats. Arrow keys to
navigate, Enter to open, R to resume the last session in that project, Esc to start fresh in the current directory.
Alternative Solutions
I built a PowerShell shell wrapper that does this today by reading the existing .jsonl session files — no changes to Claude Code needed on the data side. I also wrote a bash/zsh equivalent. Both are included below as a reference implementation.
# Claude Code Project Picker — PowerShell
# ----------------------------------------
# Wraps the `claude` command. When invoked with no arguments from your home
# directory, shows an interactive menu of recent Claude projects sorted by last
# activity. Navigate with arrow keys; Enter to open, R to resume the last
# session, Esc to start a new session in the current directory.
#
# INSTALL: Add to your PowerShell profile ($PROFILE):
# . "$HOME\Documents\claude-project-picker\claude-project-picker.ps1"
function claude {
$realClaude = (Get-Command claude -CommandType Application -ErrorAction SilentlyContinue |
Select-Object -First 1).Source
if (-not $realClaude) {
Write-Host "claude: command not found" -ForegroundColor Red
return
}
if ($args.Count -gt 0 -or $PWD.Path -ne $env:USERPROFILE) {
& $realClaude @args
return
}
$projectsDir = Join-Path $env:USERPROFILE ".claude\projects"
if (-not (Test-Path $projectsDir)) {
& $realClaude
return
}
$projects = Get-ChildItem $projectsDir -Directory -ErrorAction SilentlyContinue |
ForEach-Object {
$jsonls = Get-ChildItem $_.FullName -Filter "*.jsonl" -ErrorAction SilentlyContinue
$latest = $jsonls | Sort-Object LastWriteTime -Descending | Select-Object -First 1
if (-not $latest) { return }
$line = Get-Content $latest.FullName |
Where-Object { $_ -match '"cwd"' } |
Select-Object -First 1
if ($line -match '"cwd":"((?:[^"\\]|\\.)*)"') {
$cwd = $matches[1] -replace '\\\\', '\'
if (Test-Path $cwd) {
[PSCustomObject]@{
Path = $cwd
LastWrite = $latest.LastWriteTime
Chats = $jsonls.Count
}
}
}
} |
Sort-Object LastWrite -Descending |
Group-Object Path |
ForEach-Object { $_.Group[0] }
if (-not $projects -or $projects.Count -eq 0) {
Write-Host "No Claude projects found. Starting here." -ForegroundColor DarkCyan
& $realClaude
return
}
$termWidth = [Console]::WindowWidth - 1
$maxName = ($projects |
ForEach-Object { (Split-Path $_.Path -Leaf).Length } |
Measure-Object -Maximum).Maximum
$formatLine = {
param($p, $isSelected)
$prefix = if ($isSelected) { " > " } else { " " }
$name = (Split-Path $p.Path -Leaf).PadRight($maxName)
$dt = $p.LastWrite.ToString("yyyy-MM-dd HH:mm")
$chats = if ($p.Chats -eq 1) { "1 chat" } else { "$($p.Chats) chats" }
$full = "$prefix$name $dt $chats ($($p.Path))"
if ($full.Length -gt $termWidth) { $full.Substring(0, $termWidth - 3) + "..." }
else { $full.PadRight($termWidth) }
}
Write-Host " Enter open | R resume | Esc start here`n" -ForegroundColor DarkGray
$selected = 0
$menuTop = [Console]::CursorTop
$drawMenu = {
[Console]::SetCursorPosition(0, $menuTop)
for ($i = 0; $i -lt $projects.Count; $i++) {
$line = & $formatLine $projects[$i] ($i -eq $selected)
if ($i -eq $selected) { Write-Host $line -ForegroundColor Cyan }
else { Write-Host $line }
}
}
& $drawMenu
$done = $false
while (-not $done) {
$key = [Console]::ReadKey($true)
switch ($key.Key) {
'UpArrow' { if ($selected -gt 0) { $selected--; & $drawMenu } }
'DownArrow' { if ($selected -lt $projects.Count - 1) { $selected++; & $drawMenu } }
'Enter' {
Write-Host ""
Set-Location $projects[$selected].Path
& $realClaude
$done = $true
}
'R' {
Write-Host ""
Set-Location $projects[$selected].Path
& $realClaude --resume
$done = $true
}
'Escape' {
Write-Host ""
& $realClaude
$done = $true
}
}
}
}
Priority
High - Significant impact on productivity
Feature Category
CLI commands and flags
Use Case Example
- I open a new terminal — it lands in my home directory
- I type
claude - A list appears showing my five most recently active projects with timestamps
- I arrow down to the one I want and press Enter
- Claude Code opens in that project directory, ready to go
Additional Context
https://github.com/user-attachments/assets/df2a5658-9c4a-432d-b7f6-16d5735039a9
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗