Unified session browser for coding agents. Fuzzy search across OpenCode, Claude Code, and any other agent, then resume directly.
npx skills add https://github.com/dru89/sesh --skill seshInstale esta skill com a CLI e comece a usar o fluxo de trabalho SKILL.md em seu espaço de trabalho.
A unified session browser for coding agents. Search across OpenCode, Claude Code, and any other agent with a single fuzzy picker, then resume directly into the session.

brew install --cask dru89/tap/sesh
Download a prebuilt binary from GitHub Releases, or install with Go (1.25+):
go install github.com/dru89/sesh/cmd/sesh@latest
To update a non-Homebrew install, run sesh update.
sesh outputs a shell command (cd + resume) that needs to run in your current shell. The easiest way to set this up:
# bash
echo 'eval "$(sesh init bash)"' >> ~/.bashrc
# zsh
echo 'eval "$(sesh init zsh)"' >> ~/.zshrc
# fish
echo 'sesh init fish | source' >> ~/.config/fish/config.fish
# PowerShell
echo 'sesh init powershell | Invoke-Expression' >> $PROFILE
Or source the pre-made wrapper files in shell/ directly. Run sesh init --help to see all options.
sesh # open the picker with all sessions
sesh auth refactor # pre-fill search with "auth refactor"
sesh --agent opencode # only show OpenCode sessions
sesh --json # dump all sessions as JSON (for Raycast, scripts, etc.)
sesh list # non-interactive session list
sesh list --since monday -n 20
sesh show ses_abc # show details for a session (partial ID works)
sesh resume ses_abc # resume a session directly (partial ID works)
sesh stats # session statistics across all agents
sesh index # generate summaries for all sessions
sesh index --agent omp # generate summaries for one agent only
sesh recap --days 7 # summarize what you worked on this week
sesh ask "What did I work on around login with claude code?"
sesh list
sesh show
sesh stats
In the picker: type to filter, arrow keys to navigate, enter to select, tab to toggle detail pane, esc to cancel.

OpenCode reads ~/.local/share/opencode/opencode.db (SQLite). Pulls session title, slug, working directory, and first user prompts for search.
Claude Code reads ~/.claude/history.jsonl and scans ~/.claude/projects/ for session slugs. Pulls the first prompt text, working directory, and timestamps.
Both providers work automatically if the agent is installed. If the data files don't exist, the provider returns nothing and sesh continues with the others.
Optional. Create ~/.config/sesh/config.json to override resume commands or add external providers. Add the $schema field for autocomplete and validation in your editor:
{
"$schema": "https://raw.githubusercontent.com/dru89/sesh/main/schema.json"
}
If you use a wrapper script (like ca) instead of calling the agent binary directly:
{
"providers": {
"opencode": {
"resume_command": "ca opencode -s {{ID}}"
},
"claude": {
"resume_command": "ca -r {{ID}}"
}
}
}
{{ID}} is replaced with the session ID. The default commands are opencode --session {{ID}} and claude --resume {{ID}}.
{
"providers": {
"claude": {
"enabled": false
}
}
}
Any coding agent can integrate with sesh through the external provider protocol. You write a script that outputs JSON, register it in config, and it appears in the picker alongside the built-ins. If you're setting this up from inside a coding agent, see AGENTS.md for instructions you can give it directly.
{
"providers": {
"omp": {
"list_command": ["omp-sesh"],
"resume_command": "omp --resume {{ID}}"
}
}
}
list_command is an executable (plus arguments) that outputs a JSON array to stdout. resume_command is a template with {{ID}} and optional {{DIR}} placeholders.
The list command must output a JSON array of session objects:
[
{
"id": "session-id",
"title": "human-readable title or first prompt",
"slug": "optional-short-name",
"created": "2026-01-15T10:30:00Z",
"last_used": "2026-01-15T11:45:00Z",
"directory": "/absolute/path/to/working/directory",
"text": "optional extra searchable text"
}
]
| Field | Required | Notes |
|---|---|---|
id |
yes | Whatever the agent uses to identify a session for resuming |
title |
yes | Display name: session title, first prompt (truncated), or slug |
slug |
no | Short human-readable name |
created |
yes | RFC 3339 or Unix milliseconds as string |
last_used |
yes | RFC 3339 or Unix milliseconds as string |
directory |
no | Working directory where the session was started |
text |
no | Additional searchable text (first few prompts work well) |
Rules:
[]sesh --json returns an array of all sessions with an added resume_command field:
[
{
"agent": "opencode",
"id": "ses_abc123",
"title": "Fix auth middleware",
"slug": "eager-cactus",
"created": "2026-04-07T09:43:39Z",
"last_used": "2026-04-07T09:47:37Z",
"directory": "/Users/you/project",
"resume_command": "cd /Users/you/project && opencode --session ses_abc123"
}
]
This is the integration point for Raycast extensions or other tools that want to present session data in their own UI.
sesh uses LLMs for title generation, session search, recaps, and natural language queries. Each subcommand can use a different model — fast/cheap for high-volume tasks, heavier for prose generation.
Configure one command and everything uses it:
{
"index": {
"command": ["llm", "-m", "haiku"]
}
}
The command receives input on stdin and writes output to stdout. Any executable works: llm, claude -p, a script that calls a local model, etc.
Use a fast model for title generation and filtering, a heavier model for prose:
{
"index": {
"command": ["llm", "-m", "haiku"]
},
"ask": {
"command": ["llm", "-m", "sonnet"]
},
"recap": {
"command": ["llm", "-m", "sonnet"]
}
}
{
"index": {
"command": ["llm", "-m", "haiku"],
"prompt": "Summarize this coding session in one sentence, under 20 words."
},
"ask": {
"command": ["llm", "-m", "sonnet"],
"prompt": "custom prompt for answer generation",
"filter_command": ["llm", "-m", "haiku"]
},
"recap": {
"command": ["llm", "-m", "sonnet"],
"prompt": "custom recap prompt"
},
"providers": { ... }
}
Each subcommand falls back through other configured commands so you only need to set up the ones you care about:
| Task | Tries in order |
|---|---|
index (title generation) |
index -> recap -> ask -> ask.filter_command |
ask (prose answer) |
ask -> recap -> index |
ask (session filtering) |
ask.filter_command -> index -> ask -> recap |
recap (prose summary) |
recap -> ask -> index |
The pattern: heavy tasks prefer other heavy commands, light tasks prefer other light commands.
sesh can generate one-line summaries for each session. Summaries replace ugly or auto-generated titles in the picker and are included in the fuzzy search corpus.
Bulk (recommended for first run):
sesh index
Shows a progress line per session. Run this once to backfill, then sesh keeps up incrementally.
Lazy background generation: During normal sesh usage, up to 10 unsummarized sessions are processed in the background while the picker is open. Summaries won't appear in the current invocation but will be there next time.
Summaries are cached at ~/.cache/sesh/summaries.json. A cached summary is considered stale when the session's last_used timestamp changes and the summary is more than an hour old. This avoids re-summarizing active sessions on every run while keeping finished sessions up to date.
If summary generation fails (expired credentials, command not found, timeout), sesh logs a warning and continues with the raw title. Nothing crashes.
Generate a prose summary of what you worked on across all agents over a time period:
sesh recap --days 7 # last 7 days
sesh recap --since monday # since Monday
sesh recap --since 2026-04-01 --until 2026-04-07
sesh recap --agent opencode # only OpenCode sessions
Output goes to stdout as plain text. Use --raw to get the raw markdown without terminal formatting.

When the fuzzy picker returns no results and an LLM command is configured, sesh automatically triggers an AI-powered search. The LLM receives your query along with all session titles/summaries and returns the most relevant matches.
The fallback activates after 3+ characters with no fuzzy matches. A "Searching with AI..." indicator appears while the LLM processes. Results are marked with "(AI)" in the match count. If the LLM call fails, the picker stays on the empty state.
Ask a natural language question about your sessions:
sesh ask "What did I work on around login with claude code since last Monday?"
sesh ask "Show me everything related to the API gateway"
sesh ask --agent opencode "What refactoring have I done recently?"
Uses a two-pass approach: first filters sessions to the relevant subset (fast model), then generates a prose answer from just those sessions (heavy model). Output goes to stdout. Use --raw to get the raw markdown without terminal formatting.

sesh ships with a skill that teaches coding agents (Claude Code, OpenCode, Cursor, etc.) how to search and load past sessions on your behalf. Once installed, your agent can find previous sessions by topic, pull in conversation context, and answer questions like "what did we decide about auth last week?"
npx skills add dru89/sesh -g
The installer will prompt you to choose which agents to configure. You can also target specific agents with --agent claude-code opencode or drop the -g flag to install at the project level instead.
A Raycast extension is included in the raycast/ directory. It provides the same session browsing experience from Raycast's launcher, with configurable terminal support (Terminal.app, iTerm2, Ghostty, Warp, or custom). See raycast/README.md for setup instructions.