# A native Linux app to manage Claude Code sessions

> Source: <https://dev.to/matemiller/a-native-linux-app-to-manage-my-claude-code-sessions-2emp>
> Published: 2026-06-05 17:11:00+00:00

If you use [Claude Code](https://claude.com/claude-code) daily, you know the problem: after a few weeks you have *dozens* of sessions scattered across every project you've touched. They live as JSONL files under `~/.claude/projects/`

, named by UUID. Which one was the JWT refactor? Which one is still mid-task? `claude --resume`

shows you a picker for the current directory — but there's no overview of everything, no naming, no "this one matters, pin it".

So I built **Claude Session Manager** — a native Linux desktop app that gives Claude Code sessions a proper home.

GitHub: [https://github.com/r4nd3l/claude-session-manager](https://github.com/r4nd3l/claude-session-manager)

`claude --resume <id>`

in the session's original project directory, inside your own shellImportantly: it **never touches Claude Code's own data**. Names, favorites, everything app-side lives in its own config file. Transcripts are read-only to this app (unless you explicitly trash one — and that goes to the system trash, recoverable).

I wanted a *native* app, and the deciding factor turned out to be one component: **the terminal widget**.

Claude Code is a heavy TUI — alternate screens, spinners, constant redraws. A half-baked terminal emulator widget will mangle it. On Linux there's exactly one production-grade embeddable terminal: **VTE**, the widget behind GNOME Terminal and Ptyxis. That decision cascaded into the rest of the stack:

`AdwTabView`

/`AdwTabBar`

gave me the tab system basically for free, `AdwOverlaySplitView`

the sidebar layout**1. Some libadwaita types are final.** `class SessionSidebar(Adw.ToolbarView)`

compiles fine and explodes at runtime with `could not create new GType`

. `AdwToolbarView`

can't be subclassed — wrap it in a `Gtk.Box`

instead.

**2. GtkListBox headers belong to rows.** I implemented collapsible project groups by filtering out the group's rows... and the group

**3. Bind properties, don't rebuild lists.** The first version rebuilt the whole sidebar on every change — fine at 10 sessions, scroll-position-destroying at 50+ with live file monitoring. The fix was a proper model layer: a `GObject`

item per session with bindable properties, reused across refreshes. Renames, stars and status dots now update in place, and the list is only re-spliced when the *order* actually changes.

```
sessions.py   # transcript discovery + parsing (pure Python, fully testable)
state.py      # app-side persistence (names, favorites, settings)
store.py      # single source of truth: threaded scans, file monitors, diffing
sidebar.py    # the session list widget
window.py     # tabs + actions + composition
```

The data layer is GTK-free, which means the test suite runs on a bare `python:3.12-slim`

container in CI — no display server, no GTK packages.

There's a `.deb`

on the [release page](https://github.com/r4nd3l/claude-session-manager/releases/latest):

```
sudo apt install ./claude-session-manager_0.1.0_all.deb
```

Or run from source (Fedora/Arch package names in the README):

```
git clone https://github.com/r4nd3l/claude-session-manager.git
cd claude-session-manager
python3 -m claude_session_manager
```

It's GPL-3, unofficial, and not affiliated with Anthropic. Issues and PRs welcome — the next feature on my list is *transcript peek*: reading the last few messages of a session in the details dialog, so you can identify a session without resuming it.

If you try it, I'd genuinely like to know what breaks on your distro. 🐧

Enjoying the content? If you'd like to support my work and keep the ideas flowing, consider buying me a coffee! Your support means the world to me!
