Metadata-Version: 2.4
Name: textsessions
Version: 0.8.10
Summary: A Textual TUI for managing Claude Code sessions
Project-URL: Homepage, https://github.com/paperworlds/textsessions
Project-URL: Repository, https://github.com/paperworlds/textsessions
Project-URL: Issues, https://github.com/paperworlds/textsessions/issues
Author-email: Paolo D'Onorio De Meo <p.donoriodemeo@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: agents,anthropic,claude,claude-code,sessions,textual,tui
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console :: Curses
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: Terminals
Classifier: Topic :: Utilities
Requires-Python: >=3.13
Requires-Dist: click>=8.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0
Requires-Dist: textual>=0.70
Requires-Dist: tomli-w>=1.0
Requires-Dist: tomli>=2.0; python_version < '3.11'
Provides-Extra: accounts
Requires-Dist: textaccounts>=0.4.1; extra == 'accounts'
Description-Content-Type: text/markdown

# textsessions

A terminal UI and CLI for managing [Claude Code](https://claude.ai/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](https://claude.ai/code). It reads the `.jsonl` session files that Claude Code writes to disk and is not compatible with other AI coding assistants.

---

## Requirements

- Python 3.12+
- [fish shell](https://fishshell.com/) — required for `--resume` and new session launch
- Claude Code CLI (`claude`)

Optional integrations (auto-detected at runtime):
- [textaccounts](#textaccounts) — profile isolation (separate optional package)
- [textproxy](https://github.com/paperworlds/textproxy) — local token proxy for tracking context consumption

---

## Install

```sh
pip install textsessions
```

With multi-account support ([textaccounts](https://github.com/paperworlds/textaccounts)):

```sh
pip install textsessions[accounts]
```

Or from source:

```sh
git clone https://github.com/paperworlds/textsessions
cd textsessions
pip install -e ".[accounts]"
```

---

## Quick start

```sh
# 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

```sh
textsessions view             # launch the TUI
textsessions view --config    # open repo config view
```

### Add repos

```sh
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

```sh
# 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

```sh
# 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

```sh
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

```sh
# 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:

```sh
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

```sh
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

```sh
textsessions tree                          # YAML tree of all repos + sessions
textsessions tree --format json -o out.json
textsessions tree --repo mono --include-archived
```

### Proxy stats

```sh
textsessions proxy    # token usage + cost for today, by model
```

Reads from textproxy's cache. Shows nothing if textproxy is not running.

### Config

```sh
textsessions config   # show current config path and repo list
```

---

## Configuration

`~/.config/textsessions/config.toml`

```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:

```toml
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](https://github.com/paperworlds/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](https://github.com/paperworlds/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:**

```sh
textaccounts install        # writes fish function + completions to ~/.config/fish/
```

**2. Register your existing Claude config dirs** — nothing moves, just registers the paths:

```sh
textaccounts adopt work ~/.claude-work
textaccounts adopt personal ~/.claude-personal
```

**3. Switch profiles:**

```sh
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:

```toml
[[repos]]
path = "/Users/you/work/myrepo"
label = "myrepo"
profile = "work"        # textsessions will inject CLAUDE_CONFIG_DIR for this profile
```

#### All commands

```sh
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 `c` key, enables Enter-to-filter)
- [ ] Polish rename flow — reindex now auto-renames hex sessions from `/rename`, but edge cases remain: TUI `r` key doesn't update the tmux window name, stale tab-completion names after rename, and `auto-rename --dry-run` output could be clearer

> [!NOTE]
> **Part of Paperworlds**
>
> textsessions is part of [Paperworlds](https://github.com/paperworlds) — an open org building tools and games around AI agents and text interfaces.

## License

MIT
