A Textual TUI for managing Claude Code sessions
Project description
textsessions
A terminal UI and CLI for managing Claude Code sessions across multiple Git repos.
If you work with Claude across many projects, sessions accumulate fast. textsessions gives you a searchable, filterable view of all of them — with resume, tagging, priority, and cleanup built in.
textsessions view
![TUI showing session list with repo, profile, tags, priority, and last-active columns]
Claude Code only. textsessions is built and tested exclusively with Claude Code. It reads the
.jsonlsession files that Claude Code writes to disk and is not compatible with other AI coding assistants.
Requirements
- Python 3.12+
- fish shell — required for
--resumeand new session launch - Claude Code CLI (
claude)
Optional integrations (auto-detected at runtime):
- textaccounts — profile isolation (separate optional package)
- textproxy — local token proxy for tracking context consumption
Install
pip install textsessions
With multi-account support (textaccounts):
pip install textsessions[accounts]
Or from source:
git clone https://github.com/paperworlds/textsessions
cd textsessions
pip install -e ".[accounts]"
Quick start
# 1. Detect repos from existing Claude session history
textsessions init
# 2. Build session indexes from .jsonl files
textsessions reindex
# 3. Launch the TUI
textsessions view
TUI
Launch with textsessions view (or alias ts).
Sessions are grouped by repo and sorted by last-active. The right panel shows full detail for the selected session, including token proxy stats if textproxy is running.
When resuming a session inside tmux, the tmux window is automatically renamed to the session name for easy identification across panes.
Keyboard shortcuts
| Key | Action |
|---|---|
Enter |
Resume session (suspends TUI, launches Claude, returns; renames tmux window) |
n |
New session (profile, repo, optional name) |
/ |
Filter by name, description, or slug |
a |
Toggle: current repo ↔ all repos |
t |
Tag / untag (comma-separated; prefix - to remove) |
p |
Set priority (H0 = urgent, 1–3, or clear) |
r |
Rename (sets a short display name + description) |
x |
Pin / unpin session |
y |
Toggle pinned sessions visibility |
d |
Archive (hidden but recoverable) |
D |
Hard delete (confirmation required) |
g |
Toggle ghosts & orphans only view |
s |
Sort by priority instead of last-active |
ctrl+r |
Reindex current repo |
c |
Open repo config view |
? |
Help |
q |
Quit |
CLI reference
View
textsessions view # launch the TUI
textsessions view --config # open repo config view
Add repos
textsessions add /path/to/repo # auto-label from dirname
textsessions add /path/to/repo --label myrepo # custom label
textsessions add /path/to/repo --profile work # assign a profile
textsessions add /path/to/projects --recursive # scan one level deep
Sessions
# List sessions
textsessions sessions
textsessions sessions --repo mono --tag auth --limit 10
# Resume a session by name (tab-completion supported)
textsessions sessions --resume my-feature-work
# Filter to current folder's repo
textsessions sessions --current-folder
The table shows: Name, Info (description if set, otherwise the auto-generated slug), Repo, Profile, Tags, Priority, Last Active.
Rename and tag
# Rename a session (tab-completes session names)
textsessions rename my-feature-work "Better title for this session"
# Add tags
textsessions tag my-feature-work auth,api
# Remove tags (prefix with -)
textsessions tag my-feature-work -auth
# Add and remove in one shot
textsessions tag my-feature-work api,-old,keep
AI search
textsessions search "add client to privatelink"
textsessions search "auth refactor" --repo mono --limit 5 --json
Sends session metadata to Claude and returns ranked matches. Requires a Claude command to be configured as ui.ai_search_profile (default: claude).
Cleanup
# Dry-run report of ghosts (dead repos) and orphans (throwaway hex-named sessions)
textsessions scan-ghosts
# Archive all (reversible — hides from normal view)
textsessions scan-ghosts --archive
# Bulk archive for one repo without confirmation
textsessions scan-ghosts --repo mono --discard
# Mark a hex-named session as "keep" (exclude from future orphan detection)
textsessions scan-ghosts --keep abc123 --repo mono
# Hard delete (irreversible)
textsessions scan-ghosts --delete --yes
Rename hex-named sessions
Claude auto-names new sessions with a hex ID. When you use /rename inside a session, textsessions can pick that up:
textsessions index auto-rename --dry-run # preview
textsessions index auto-rename # apply to all repos
Only renames sessions that have a /rename entry in their .jsonl — never guesses.
Reindex
textsessions reindex # all configured repos
textsessions reindex --repo mono # one repo
Rebuilds YAML indexes from .jsonl files. Preserves tags, priority, pinned state, and custom names.
Export
textsessions tree # YAML tree of all repos + sessions
textsessions tree --format json -o out.json
textsessions tree --repo mono --include-archived
Proxy stats
textsessions proxy # token usage + cost for today, by model
Reads from textproxy's cache. Shows nothing if textproxy is not running.
Config
textsessions config # show current config path and repo list
Configuration
~/.config/textsessions/config.toml
[[repos]]
path = "/Users/you/projects/myrepo"
label = "myrepo"
profile = "default" # maps to a textaccounts profile (optional)
[[repos]]
path = "/Users/you/projects"
label = "personal"
profile = "personal"
recursive = true # scan all git repos one level deep
[ui]
startup_repo = "current" # "current" = auto-filter TUI to cwd repo | "all" = show everything
claude_cmd = "claude" # command to launch Claude; {profile} is substituted if present
# e.g. "claude-{profile}" dispatches to fish functions like claude-work
ai_search_profile = "claude" # command used for `textsessions search`
[integrations]
textaccounts = true # use textaccounts for profile isolation if configured (see below)
textproxy = true # inject ANTHROPIC_BASE_URL if textproxy is running on :7474
[proxy]
cache_dir = "~/.cache/textproxy"
Profiles and the claude_cmd template
Each repo has a profile. When launching or resuming a session, textsessions resolves the command to run via claude_cmd with {profile} substituted:
claude_cmd = "claude-{profile}"
# mono (profile=work) → runs: claude-work
# blog (profile=default) → runs: claude-default
This lets you define fish functions (claude-work, claude-personal, etc.) that set environment or flags before calling claude. Useful for routing to different API keys or base URLs without textaccounts, or alongside it.
Integrations
textproxy
textproxy is a companion paperworlds project — a lightweight local MITM proxy that captures token consumption stats from Claude Code API traffic. It gives subscription users (Claude Team, Claude.ai) visibility into how much context window each session is actually consuming, without modifying Claude Code itself.
If textproxy is running on localhost:7474, textsessions automatically sets ANTHROPIC_BASE_URL before launching Claude. Token usage and cost appear in the TUI detail panel and textsessions proxy.
textaccounts
textaccounts is an optional profile manager that isolates Claude accounts by pointing CLAUDE_CONFIG_DIR at separate config directories — keeping sessions, memory, and auth separate per profile.
Install with pip install textsessions[accounts] to enable. When configured, textsessions automatically injects CLAUDE_CONFIG_DIR before launching or resuming any session whose repo profile matches a registered profile name. Without textaccounts, you can still use custom commands (see Custom Commands section above) or a single default account.
Setup flow
1. Install shell integration:
textaccounts install # writes fish function + completions to ~/.config/fish/
2. Register your existing Claude config dirs — nothing moves, just registers the paths:
textaccounts adopt work ~/.claude-work
textaccounts adopt personal ~/.claude-personal
3. Switch profiles:
textaccounts switch work # sets CLAUDE_CONFIG_DIR=~/.claude-work in your shell
textaccounts switch personal # sets CLAUDE_CONFIG_DIR=~/.claude-personal
textaccounts switch default # unsets CLAUDE_CONFIG_DIR (back to ~/.claude)
4. Wire repos to profiles in your config:
[[repos]]
path = "/Users/you/work/myrepo"
label = "myrepo"
profile = "work" # textsessions will inject CLAUDE_CONFIG_DIR for this profile
All commands
textaccounts list # show all profiles with path, email, session count, size
textaccounts status # active profile, env var sync check, session count
textaccounts adopt <name> <path> # register an existing dir
textaccounts create <name> # snapshot current config dir into ~/.textaccounts/profiles/
textaccounts create <name> --worker \
--from <parent> # minimal copy: .claude.json + settings.json only
textaccounts switch <name> # switch profile (sets CLAUDE_CONFIG_DIR)
textaccounts show <name> # print the shell command without executing
textaccounts rename <old> <new> # rename a profile
textaccounts alias <profile> <alias> # add a short alias
textaccounts view # interactive profile view
textaccounts install # install shell integration
Set textaccounts = false or textproxy = false under [integrations] to disable either integration.
How it works
Claude Code stores every conversation as a .jsonl file under ~/.claude*/projects/<repo-key>/. textsessions reads these files and builds a lightweight YAML index per repo at ~/.local/state/claude-sessions/<repo-key>.yaml.
The index stores: session name, profile, last-active timestamp, slug, tags, priority, pinned state, and description. It is rebuilt with textsessions reindex and preserves all user-set metadata across rebuilds.
Ask Claude about this tool
If you use Claude Code, you can paste this prompt to get a quick orientation:
Read the file at docs/features.yaml in this repo and tell me:
1. What textsessions does and who it's for
2. Which features are most relevant to my workflow (ask me 2-3 questions first)
3. The first 3 commands I should run to get started
Or for a deeper dive:
Read docs/features.yaml and give me a tour of textsessions.
For each feature, tell me when I'd use it and show me the exact command.
Start with the ones that solve the most common pain points for heavy Claude Code users.
Roadmap
- Publish to PyPI
- Upgrade to Python 3.13
- Bash/zsh shell support (currently fish only)
-
textsessions doctor— validate config, check for stale paths - Session export to markdown
- Refactor config screen from subprocess to pushed Screen (removes brief flash on
ckey, enables Enter-to-filter) - Polish rename flow — reindex now auto-renames hex sessions from
/rename, but edge cases remain: TUIrkey doesn't update the tmux window name, stale tab-completion names after rename, andauto-rename --dry-runoutput could be clearer
[!NOTE] Part of Paperworlds
textsessions is part of Paperworlds — an open org building tools and games around AI agents and text interfaces.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file textsessions-0.8.10.tar.gz.
File metadata
- Download URL: textsessions-0.8.10.tar.gz
- Upload date:
- Size: 98.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3542f9121ff4259159891c374c62eb716d5b4ae2ae64a5f8118878ad2afab551
|
|
| MD5 |
5404c6c10bd6ec7bcfedd064f67a0baa
|
|
| BLAKE2b-256 |
7af75939fc330fff1af81a72a4ca688c2e755334c06decc6ab3bb9418e2a076b
|
File details
Details for the file textsessions-0.8.10-py3-none-any.whl.
File metadata
- Download URL: textsessions-0.8.10-py3-none-any.whl
- Upload date:
- Size: 50.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6859cde549af1dfc5312a8477ef6aa412bf18aa05ccd09bd0dc7c7a8ba9c0085
|
|
| MD5 |
4ace76234bdbd5b61a6f098f49de7c74
|
|
| BLAKE2b-256 |
59cb47482c0cbf279f80e7e9728040b789086526618fb69fe07cf3ea038142de
|