cc-session-browser 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. cc_session_browser-0.1.0/.gitignore +6 -0
  2. cc_session_browser-0.1.0/LICENSE +21 -0
  3. cc_session_browser-0.1.0/PKG-INFO +143 -0
  4. cc_session_browser-0.1.0/README.md +114 -0
  5. cc_session_browser-0.1.0/pyproject.toml +115 -0
  6. cc_session_browser-0.1.0/src/cc_session_browser/__init__.py +3 -0
  7. cc_session_browser-0.1.0/src/cc_session_browser/__main__.py +115 -0
  8. cc_session_browser-0.1.0/src/cc_session_browser/app.py +357 -0
  9. cc_session_browser-0.1.0/src/cc_session_browser/config.py +247 -0
  10. cc_session_browser-0.1.0/src/cc_session_browser/index.py +353 -0
  11. cc_session_browser-0.1.0/src/cc_session_browser/launcher.py +276 -0
  12. cc_session_browser-0.1.0/src/cc_session_browser/render.py +121 -0
  13. cc_session_browser-0.1.0/src/cc_session_browser/static/app.css +270 -0
  14. cc_session_browser-0.1.0/src/cc_session_browser/static/htmx.min.js +1 -0
  15. cc_session_browser-0.1.0/src/cc_session_browser/templates/_chunk.html +14 -0
  16. cc_session_browser-0.1.0/src/cc_session_browser/templates/_entry.html +40 -0
  17. cc_session_browser-0.1.0/src/cc_session_browser/templates/_help.html +19 -0
  18. cc_session_browser-0.1.0/src/cc_session_browser/templates/_projects.html +18 -0
  19. cc_session_browser-0.1.0/src/cc_session_browser/templates/_recent.html +11 -0
  20. cc_session_browser-0.1.0/src/cc_session_browser/templates/_results.html +24 -0
  21. cc_session_browser-0.1.0/src/cc_session_browser/templates/_sessions.html +17 -0
  22. cc_session_browser-0.1.0/src/cc_session_browser/templates/_subagent.html +2 -0
  23. cc_session_browser-0.1.0/src/cc_session_browser/templates/_transcript.html +37 -0
  24. cc_session_browser-0.1.0/src/cc_session_browser/templates/layout.html +149 -0
  25. cc_session_browser-0.1.0/src/cc_session_browser/transcript.py +254 -0
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ dist/
4
+ .venv/
5
+ .pytest_cache/
6
+ .ruff_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Martin Mahner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.5
2
+ Name: cc-session-browser
3
+ Version: 0.1.0
4
+ Summary: Three-pane browser for your local Claude Code sessions
5
+ Project-URL: Homepage, https://github.com/bartTC/cc-session-browser
6
+ Project-URL: Issues, https://github.com/bartTC/cc-session-browser/issues
7
+ Author-email: Martin Mahner <martin@elephant.house>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: browser,claude,claude-code,sessions,transcript
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: Web Environment
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Documentation
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: jinja2>=3.1
24
+ Requires-Dist: markdown-it-py>=3.0
25
+ Requires-Dist: pygments>=2.18
26
+ Requires-Dist: starlette>=0.40
27
+ Requires-Dist: uvicorn>=0.30
28
+ Description-Content-Type: text/markdown
29
+
30
+ # cc-session-browser
31
+
32
+ A browser for your Claude Code sessions.
33
+
34
+ ```sh
35
+ uvx cc-session-browser
36
+ ```
37
+
38
+ No install, no configuration. It indexes `~/.claude/projects` and opens a
39
+ browser.
40
+
41
+ ![cc-session-browser](https://raw.githubusercontent.com/bartTC/cc-session-browser/main/docs/screenshot.png)
42
+
43
+ ## Features
44
+
45
+ - **Browse** every project and session Claude Code has recorded, with the real
46
+ project path recovered from the transcripts rather than the dashed directory
47
+ name.
48
+ - **Read** transcripts with rendered markdown, syntax-highlighted code,
49
+ expandable tool calls and their output, inline screenshots, and subagent
50
+ transcripts shown where they were spawned.
51
+ - **Search** across all sessions — titles, prompts, replies and tool
52
+ invocations — or within a single project.
53
+ - **Resume, fork, or start** a session in your terminal. Forking uses
54
+ `--fork-session`, so the original transcript is never touched.
55
+
56
+ Nothing is sent anywhere: the tool reads local files and serves them on
57
+ `127.0.0.1`.
58
+
59
+ ## Configuration
60
+
61
+ Optional. Everything has a working default.
62
+
63
+ ```sh
64
+ cc-session-browser --help-config # every option, with your paths filled in
65
+ cc-session-browser --write-config # write a commented starter file
66
+ ```
67
+
68
+ The config file is read from the first of these that exists:
69
+
70
+ 1. `--config PATH`
71
+ 2. `$CC_SESSION_BROWSER_CONFIG`
72
+ 3. `./cc-session-browser.toml`
73
+ 4. `~/.config/cc-session-browser/config.toml` (`%APPDATA%` on Windows)
74
+
75
+ `$CLAUDE_CONFIG_DIR` is honoured, so a non-standard Claude Code location needs
76
+ no configuration at all.
77
+
78
+ ```toml
79
+ # cc-session-browser configuration
80
+
81
+
82
+ # Where Claude Code keeps its session transcripts. $CLAUDE_CONFIG_DIR is
83
+ # honoured automatically, so you rarely need to set this.
84
+ #
85
+ # projects_dir = "~/.claude/projects"
86
+
87
+
88
+ # Projects to leave out of the sidebar. Each entry is a glob, matched against
89
+ # the project name, its full path, and its Claude Code slug -- so you never
90
+ # have to know what a slug looks like.
91
+ #
92
+ # hide = [
93
+ # "scratch",
94
+ # "*/Workspace/throwaway-*",
95
+ # ]
96
+
97
+
98
+ [server]
99
+
100
+ # Bind address. Leave this on loopback: the endpoint that opens a terminal
101
+ # starts processes on your machine.
102
+ #
103
+ # host = "127.0.0.1"
104
+
105
+ # Port to serve on.
106
+ #
107
+ # port = 8765
108
+
109
+ # Open a browser window on startup.
110
+ #
111
+ # open_browser = true
112
+
113
+
114
+ [launch]
115
+
116
+ # Open a session in a new "window" or a new "tab".
117
+ # Tabs are supported for: gnome-terminal, iterm, kitty, konsole, wezterm, wt
118
+ # (kitty needs allow_remote_control). Every other terminal falls back to a
119
+ # window.
120
+ #
121
+ # mode = "window"
122
+
123
+ # Which terminal to use. Auto-detected from $TERM_PROGRAM when unset.
124
+ # Known terminals: ghostty, gnome-terminal, iterm, kitty, konsole, terminal, wezterm, wt
125
+ #
126
+ # terminal = "iterm"
127
+
128
+ # Full override, for a terminal that is not in that list. {script} is a
129
+ # generated shell script that cds into the project and runs claude; {cwd} is
130
+ # the project directory.
131
+ #
132
+ # terminal_argv = ["alacritty", "--working-directory", "{cwd}", "-e", "{script}"]
133
+
134
+ # Path to the claude CLI. Found on PATH when unset.
135
+ #
136
+ # claude_bin = "/usr/local/bin/claude"
137
+ ```
138
+
139
+ ## Requirements
140
+
141
+ Python 3.11+. Terminal integration supports iTerm, Terminal.app, Ghostty,
142
+ kitty, WezTerm, GNOME Terminal, Konsole and Windows Terminal; anything else can
143
+ be driven with a `terminal_argv` template.
@@ -0,0 +1,114 @@
1
+ # cc-session-browser
2
+
3
+ A browser for your Claude Code sessions.
4
+
5
+ ```sh
6
+ uvx cc-session-browser
7
+ ```
8
+
9
+ No install, no configuration. It indexes `~/.claude/projects` and opens a
10
+ browser.
11
+
12
+ ![cc-session-browser](https://raw.githubusercontent.com/bartTC/cc-session-browser/main/docs/screenshot.png)
13
+
14
+ ## Features
15
+
16
+ - **Browse** every project and session Claude Code has recorded, with the real
17
+ project path recovered from the transcripts rather than the dashed directory
18
+ name.
19
+ - **Read** transcripts with rendered markdown, syntax-highlighted code,
20
+ expandable tool calls and their output, inline screenshots, and subagent
21
+ transcripts shown where they were spawned.
22
+ - **Search** across all sessions — titles, prompts, replies and tool
23
+ invocations — or within a single project.
24
+ - **Resume, fork, or start** a session in your terminal. Forking uses
25
+ `--fork-session`, so the original transcript is never touched.
26
+
27
+ Nothing is sent anywhere: the tool reads local files and serves them on
28
+ `127.0.0.1`.
29
+
30
+ ## Configuration
31
+
32
+ Optional. Everything has a working default.
33
+
34
+ ```sh
35
+ cc-session-browser --help-config # every option, with your paths filled in
36
+ cc-session-browser --write-config # write a commented starter file
37
+ ```
38
+
39
+ The config file is read from the first of these that exists:
40
+
41
+ 1. `--config PATH`
42
+ 2. `$CC_SESSION_BROWSER_CONFIG`
43
+ 3. `./cc-session-browser.toml`
44
+ 4. `~/.config/cc-session-browser/config.toml` (`%APPDATA%` on Windows)
45
+
46
+ `$CLAUDE_CONFIG_DIR` is honoured, so a non-standard Claude Code location needs
47
+ no configuration at all.
48
+
49
+ ```toml
50
+ # cc-session-browser configuration
51
+
52
+
53
+ # Where Claude Code keeps its session transcripts. $CLAUDE_CONFIG_DIR is
54
+ # honoured automatically, so you rarely need to set this.
55
+ #
56
+ # projects_dir = "~/.claude/projects"
57
+
58
+
59
+ # Projects to leave out of the sidebar. Each entry is a glob, matched against
60
+ # the project name, its full path, and its Claude Code slug -- so you never
61
+ # have to know what a slug looks like.
62
+ #
63
+ # hide = [
64
+ # "scratch",
65
+ # "*/Workspace/throwaway-*",
66
+ # ]
67
+
68
+
69
+ [server]
70
+
71
+ # Bind address. Leave this on loopback: the endpoint that opens a terminal
72
+ # starts processes on your machine.
73
+ #
74
+ # host = "127.0.0.1"
75
+
76
+ # Port to serve on.
77
+ #
78
+ # port = 8765
79
+
80
+ # Open a browser window on startup.
81
+ #
82
+ # open_browser = true
83
+
84
+
85
+ [launch]
86
+
87
+ # Open a session in a new "window" or a new "tab".
88
+ # Tabs are supported for: gnome-terminal, iterm, kitty, konsole, wezterm, wt
89
+ # (kitty needs allow_remote_control). Every other terminal falls back to a
90
+ # window.
91
+ #
92
+ # mode = "window"
93
+
94
+ # Which terminal to use. Auto-detected from $TERM_PROGRAM when unset.
95
+ # Known terminals: ghostty, gnome-terminal, iterm, kitty, konsole, terminal, wezterm, wt
96
+ #
97
+ # terminal = "iterm"
98
+
99
+ # Full override, for a terminal that is not in that list. {script} is a
100
+ # generated shell script that cds into the project and runs claude; {cwd} is
101
+ # the project directory.
102
+ #
103
+ # terminal_argv = ["alacritty", "--working-directory", "{cwd}", "-e", "{script}"]
104
+
105
+ # Path to the claude CLI. Found on PATH when unset.
106
+ #
107
+ # claude_bin = "/usr/local/bin/claude"
108
+ ```
109
+
110
+ ## Requirements
111
+
112
+ Python 3.11+. Terminal integration supports iTerm, Terminal.app, Ghostty,
113
+ kitty, WezTerm, GNOME Terminal, Konsole and Windows Terminal; anything else can
114
+ be driven with a `terminal_argv` template.
@@ -0,0 +1,115 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "cc-session-browser"
7
+ version = "0.1.0"
8
+ description = "Three-pane browser for your local Claude Code sessions"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Martin Mahner", email = "martin@elephant.house" }]
14
+ keywords = ["claude", "claude-code", "sessions", "browser", "transcript"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Environment :: Console",
18
+ "Environment :: Web Environment",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: MacOS",
21
+ "Operating System :: POSIX :: Linux",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Topic :: Software Development :: Documentation",
27
+ ]
28
+ dependencies = [
29
+ "starlette>=0.40",
30
+ "uvicorn>=0.30",
31
+ "jinja2>=3.1",
32
+ "markdown-it-py>=3.0",
33
+ "pygments>=2.18",
34
+ ]
35
+
36
+ [dependency-groups]
37
+ dev = [
38
+ "pytest>=8.0",
39
+ "httpx2>=0.28",
40
+ ]
41
+
42
+ [tool.pytest.ini_options]
43
+ testpaths = ["tests"]
44
+ addopts = "-q"
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/bartTC/cc-session-browser"
48
+ Issues = "https://github.com/bartTC/cc-session-browser/issues"
49
+
50
+ [project.scripts]
51
+ cc-session-browser = "cc_session_browser.__main__:main"
52
+ ccsb = "cc_session_browser.__main__:main"
53
+
54
+ [tool.hatch.build.targets.wheel]
55
+ packages = ["src/cc_session_browser"]
56
+
57
+ [tool.hatch.build.targets.sdist]
58
+ include = ["src", "README.md"]
59
+
60
+ [tool.ruff]
61
+ target-version = "py311"
62
+ lint.select = ["ALL"]
63
+ lint.ignore = [
64
+ # Valid exclusions.
65
+ "COM812", # Conflicts with ruff format
66
+ "E501", # Line too long (>88)
67
+ "D203", # incorrect-blank-line-before-class (conflicts with D211)
68
+ "D212", # Don't require summary on first line
69
+ "D401", # First line of docstring should be in imperative mood
70
+ "ERA001", # Found commented-out code
71
+ "FBT", # Flake Boolean Trap (don't use arg=True in functions)
72
+ "ANN401", # Any is legitimate for the recursive tree dicts
73
+ "CPY001", # Copyright header per file — the LICENSE file covers it
74
+
75
+ # Size and complexity metrics. The request handlers, the transcript parser
76
+ # and the indexer are long because the work is genuinely sequential, not
77
+ # because they are tangled; splitting them to satisfy a counter would make
78
+ # them harder to follow.
79
+ "C901", # Function is too complex (mccabe)
80
+ "PLR0911", # Too many return statements
81
+ "PLR0912", # Too many branches
82
+ "PLR0913", # Too many arguments
83
+ "PLR0914", # Too many local variables
84
+ "PLR0915", # Too many statements
85
+ "PLR0916", # Too many boolean expressions
86
+ "PLR0917", # Too many positional arguments
87
+ "PLR1702", # Too many nested blocks
88
+ "PLR0904", # Too many public methods
89
+ ]
90
+
91
+ [tool.ruff.lint.extend-per-file-ignores]
92
+ # A CLI writes to stdout; that is its job. Ruff's fix for T201 deletes the
93
+ # call, which silently turned every message in here into nothing.
94
+ "src/cc_session_browser/__main__.py" = ["T201"]
95
+ # The only values interpolated into SQL here are module-level constants and
96
+ # generated "?" placeholders; every user value is a bound parameter.
97
+ "src/cc_session_browser/index.py" = ["S608"]
98
+ "tests/*.py" = [
99
+ "S101", # Use of `assert` detected
100
+ "PLR2004", # Magic value in comparison — tests compare to literal counts/percentages
101
+ "D", # Tests don't need docstrings on every class/method
102
+ "ANN", # Fake objects and inline helpers don't need full type annotations
103
+ "SLF001", # Tests routinely reach into implementation internals
104
+ "S314", # xml.etree parses our own generated output, not untrusted input
105
+ "ARG001", # pytester/tmp_path fixtures accepted for their side effects
106
+ "ARG002", # Same for unused parameters on fake callables
107
+ "N806", # MagicMock instances are conventionally named like classes
108
+ "S108", # /tmp paths here are fixture strings, never touched on disk
109
+ "TRY003", # Test doubles raise with a literal message on purpose
110
+ "EM101", # Same
111
+ ]
112
+ "tests/conftest.py" = [
113
+ "D", "ANN",
114
+ ]
115
+ "tests/__init__.py" = ["D104"]
@@ -0,0 +1,3 @@
1
+ """Three-pane browser for local Claude Code sessions."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,115 @@
1
+ """Command line entry point."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import sys
7
+ import threading
8
+ import webbrowser
9
+ from pathlib import Path
10
+
11
+ import uvicorn
12
+
13
+ from . import config as config_mod
14
+ from .app import build_app
15
+
16
+
17
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
18
+ """Parse the command line."""
19
+ parser = argparse.ArgumentParser(
20
+ prog="cc-session-browser",
21
+ description="Three-pane browser for your local Claude Code sessions.",
22
+ epilog="Run --help-config for the configuration reference.",
23
+ )
24
+ parser.add_argument(
25
+ "--config",
26
+ type=Path,
27
+ metavar="PATH",
28
+ help=f"config file (default: {config_mod.config_path()})",
29
+ )
30
+ parser.add_argument(
31
+ "--projects-dir",
32
+ type=Path,
33
+ metavar="PATH",
34
+ help="where Claude Code keeps its sessions",
35
+ )
36
+ parser.add_argument(
37
+ "--host", help=f"bind address (default {config_mod.DEFAULT_HOST})"
38
+ )
39
+ parser.add_argument(
40
+ "--port", type=int, help=f"port (default {config_mod.DEFAULT_PORT})"
41
+ )
42
+ parser.add_argument(
43
+ "--no-browser", action="store_true", help="do not open a browser"
44
+ )
45
+ parser.add_argument(
46
+ "--write-config",
47
+ action="store_true",
48
+ help="write a commented starter config and exit",
49
+ )
50
+ parser.add_argument(
51
+ "--help-config",
52
+ action="store_true",
53
+ help="print the documented sample config and exit",
54
+ )
55
+ return parser.parse_args(argv)
56
+
57
+
58
+ def write_config() -> int:
59
+ """Write the sample config to the per-user location, refusing to overwrite."""
60
+ path = config_mod.config_path()
61
+ if path.exists():
62
+ print(f"config already exists: {path}", file=sys.stderr)
63
+ return 1
64
+ path.parent.mkdir(parents=True, exist_ok=True)
65
+ path.write_text(config_mod.example_config())
66
+ print(f"wrote {path}")
67
+ return 0
68
+
69
+
70
+ def main(argv: list[str] | None = None) -> int:
71
+ """Run the browser, or handle one of the exit-early flags."""
72
+ args = parse_args(argv)
73
+ if args.help_config:
74
+ print(config_mod.preamble())
75
+ print(config_mod.example_config())
76
+ return 0
77
+ if args.write_config:
78
+ return write_config()
79
+
80
+ try:
81
+ cfg = config_mod.load(
82
+ args.config,
83
+ projects_dir=args.projects_dir,
84
+ host=args.host,
85
+ port=args.port,
86
+ open_browser=False if args.no_browser else None,
87
+ )
88
+ except FileNotFoundError as exc:
89
+ print(f"config file not found: {exc}", file=sys.stderr)
90
+ return 2
91
+
92
+ if not cfg.projects_dir.is_dir():
93
+ print(
94
+ f"no Claude Code sessions at {cfg.projects_dir}\n"
95
+ f"point --projects-dir, or projects_dir in the config, at the right place.",
96
+ file=sys.stderr,
97
+ )
98
+ return 2
99
+
100
+ url = f"http://{cfg.host}:{cfg.port}/"
101
+ print(f"cc-session-browser \N{RIGHTWARDS ARROW} {url}")
102
+ print(f" sessions: {cfg.projects_dir}")
103
+ print(
104
+ f" config: {cfg.source or '(defaults)'} \N{EM DASH} --help-config for options"
105
+ )
106
+
107
+ if cfg.open_browser:
108
+ threading.Timer(0.6, webbrowser.open, args=(url,)).start()
109
+
110
+ uvicorn.run(build_app(cfg), host=cfg.host, port=cfg.port, log_level="warning")
111
+ return 0
112
+
113
+
114
+ if __name__ == "__main__":
115
+ raise SystemExit(main())