saikai 0.2.1__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.
- saikai-0.2.1/.gitignore +12 -0
- saikai-0.2.1/LICENSE +21 -0
- saikai-0.2.1/PKG-INFO +308 -0
- saikai-0.2.1/README.md +260 -0
- saikai-0.2.1/THIRD-PARTY-NOTICES.md +26 -0
- saikai-0.2.1/pyproject.toml +61 -0
- saikai-0.2.1/saikai.py +7356 -0
- saikai-0.2.1/saikai_provider.py +206 -0
- saikai-0.2.1/saikai_terminal.py +1598 -0
saikai-0.2.1/.gitignore
ADDED
saikai-0.2.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 saikai contributors
|
|
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.
|
saikai-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: saikai
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: A terminal session browser for Claude Code — browse, search, group, and resume past sessions, with a built-in split-live pane (on by default).
|
|
5
|
+
Project-URL: Homepage, https://github.com/m-morino/saikai
|
|
6
|
+
Project-URL: Repository, https://github.com/m-morino/saikai
|
|
7
|
+
Project-URL: Issues, https://github.com/m-morino/saikai/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/m-morino/saikai/blob/master/CHANGELOG.md
|
|
9
|
+
Author: saikai contributors
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 saikai contributors
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: claude,claude-code,cli,sessions,textual,tui
|
|
33
|
+
Classifier: Environment :: Console
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
40
|
+
Classifier: Topic :: Utilities
|
|
41
|
+
Requires-Python: >=3.11
|
|
42
|
+
Requires-Dist: platformdirs>=3.6
|
|
43
|
+
Requires-Dist: ptyprocess>=0.7; sys_platform != 'win32'
|
|
44
|
+
Requires-Dist: pyte>=0.8
|
|
45
|
+
Requires-Dist: pywinpty>=2.0; sys_platform == 'win32'
|
|
46
|
+
Requires-Dist: textual>=0.50
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# saikai
|
|
50
|
+
|
|
51
|
+
[](https://github.com/m-morino/saikai/actions/workflows/ci.yml)
|
|
52
|
+
[](https://pypi.org/project/saikai/)
|
|
53
|
+
[](https://github.com/m-morino/saikai/releases/latest)
|
|
54
|
+
[](LICENSE)
|
|
55
|
+
[](https://www.python.org/downloads/)
|
|
56
|
+
|
|
57
|
+
**English** | [日本語](README.ja.md)
|
|
58
|
+
|
|
59
|
+
Dozens of Claude Code sessions, one searchable table. saikai scans your entire
|
|
60
|
+
`~/.claude/projects` history, lets you filter and group by date / project /
|
|
61
|
+
topic, and resumes any session with `Enter`. By default (**split-live**) it keeps
|
|
62
|
+
several sessions running live in tabs beside the list — jump between conversations
|
|
63
|
+
without closing anything or losing scrollback.
|
|
64
|
+
|
|
65
|
+
*saikai* = 再開 "resume" + 再会 "reunion" (Japanese). Complements
|
|
66
|
+
[ccmanager](https://github.com/kbwo/ccmanager), which manages a live multi-agent
|
|
67
|
+
roster; saikai is for navigating and resuming the history.
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
<sub>The demo uses fictional, leak-checked data. Regenerate the animated GIF
|
|
72
|
+
headlessly with `uv run scripts/make_demo_gif.py`; use
|
|
73
|
+
`uv run scripts/record_demo.py --guide` for a native-terminal recording.</sub>
|
|
74
|
+
|
|
75
|
+
## Highlights
|
|
76
|
+
|
|
77
|
+
- **Every session, one table** — every Claude Code conversation on your
|
|
78
|
+
machine, sorted by real last activity, grouped by date / project / topic,
|
|
79
|
+
filtered as you type.
|
|
80
|
+
- **Resume in place** — `Enter` reopens a session with `claude --resume` in the
|
|
81
|
+
working directory it was started from (worktree-aware).
|
|
82
|
+
- **Split-live panes** — host several live `claude` sessions in tabs beside the
|
|
83
|
+
list; markers show at a glance who is busy `~`, waiting for your input `?`,
|
|
84
|
+
or finished `!`. Quit and `Shift+F4` restores the whole pane set later.
|
|
85
|
+
- **Session hygiene** — favorite `★`, hide, rename; AI one-line titles; an
|
|
86
|
+
inferred parent/child tree and LLM topic clusters for big histories.
|
|
87
|
+
- **RAM-aware** — a memory gate (commit headroom + load + physical floor)
|
|
88
|
+
warns before a new pane would push the machine into thrashing.
|
|
89
|
+
- **Keyboard-first** — everything works without a mouse: `Space` opens a
|
|
90
|
+
mnemonic command menu (`Space f` = favorite, `Space s` = sort …),
|
|
91
|
+
`Alt+←/→` resizes the split, `?` shows the live key map. The mouse is a
|
|
92
|
+
bonus (click to sort, drag the divider), never a requirement.
|
|
93
|
+
- **Unintrusive by design** — read-only over claude's own transcript files; no
|
|
94
|
+
daemon, no database. Two Python files on top of
|
|
95
|
+
[Textual](https://github.com/Textualize/textual), MIT-licensed.
|
|
96
|
+
|
|
97
|
+
> The live pane uses ConPTY on Windows and a POSIX PTY elsewhere — see
|
|
98
|
+
> [Platform support](#platform-support) for the per-OS verification status
|
|
99
|
+
> (Windows is the verified platform today).
|
|
100
|
+
|
|
101
|
+
## Install
|
|
102
|
+
|
|
103
|
+
Requires **Python ≥ 3.11**. The easiest path is
|
|
104
|
+
[uv](https://docs.astral.sh/uv/) — it installs the PyPI package in an isolated
|
|
105
|
+
environment, no manual venv:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
uv tool install saikai # stable release → `saikai` on PATH
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
From a clone:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
uv run saikai.py # run in place (deps auto-installed)
|
|
115
|
+
uv tool install . # install the `saikai` command on your PATH, then: saikai
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Prefer pip / pipx? Both work (deps come from `pyproject.toml`):
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pipx install saikai # isolated + on PATH
|
|
122
|
+
pip install saikai # into the active environment
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The split-live pane needs the PTY deps (`pyte`, and `pywinpty` on Windows /
|
|
126
|
+
`ptyprocess` elsewhere); they install automatically with any command above. If
|
|
127
|
+
they're somehow missing, saikai still runs in list-only mode (see below).
|
|
128
|
+
|
|
129
|
+
## Usage
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
saikai # every project, full history (the default)
|
|
133
|
+
saikai --here # only the current project (git repo)
|
|
134
|
+
saikai --days 7 # only the last 7 days (one-shot; --save-defaults persists)
|
|
135
|
+
saikai --table # static, non-interactive table
|
|
136
|
+
saikai --help
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Keys — learn three things
|
|
140
|
+
|
|
141
|
+
Everything else is on screen (the footer, the dropdowns, and the `␣` menu
|
|
142
|
+
that pops up when you pause).
|
|
143
|
+
|
|
144
|
+
1. **Keys you already know.** `↑` `↓` move · `Enter` resumes · `/` or just
|
|
145
|
+
typing searches · `Tab` toggles the preview · `?` full key list · `Esc`
|
|
146
|
+
leaves the current context (search → list → quit).
|
|
147
|
+
2. **`Space` is the menu.** Press `Space` in the list, then one mnemonic
|
|
148
|
+
letter. Hesitate after `Space` and the whole menu appears in place,
|
|
149
|
+
grouped by family (which-key style) — nothing to memorise:
|
|
150
|
+
|
|
151
|
+
| Session | View | Panes |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `f` ★ favorite | `s` cycle **s**ort column | `n` new session |
|
|
154
|
+
| `h` hide | `o` flip sort **o**rder | `p` restore panes |
|
|
155
|
+
| `e` rename (edit) | `g` cycle grouping | `z` freeze pane |
|
|
156
|
+
| `y` copy prompt (yank) | `t` tree · `c` cluster | `a` next attention |
|
|
157
|
+
| `d` diff (changes) | `l` hide/show list | `x` close tab · `[` `]` tabs |
|
|
158
|
+
| `r` refresh | `,` settings · `/` hide/show bar | `Space` mark for batch launch |
|
|
159
|
+
|
|
160
|
+
Space is a deliberate menu key, not a claim that every TUI should use a
|
|
161
|
+
Space leader: it only arms while the session list owns focus, so search
|
|
162
|
+
fields and live agent panes keep a literal Space. It also avoids taking a
|
|
163
|
+
letter away from type-to-search. The trade-off is that list marking becomes
|
|
164
|
+
`Space Space`; set `[keys] leader = "none"` if conventional Space-to-mark is
|
|
165
|
+
more important to you.
|
|
166
|
+
|
|
167
|
+
3. **`Ctrl+]` returns focus** from a live claude pane to the list (the pane
|
|
168
|
+
owns every other key, so claude works normally inside it).
|
|
169
|
+
|
|
170
|
+
**Search tokens** (combine with text and each other): `:fav` `:hidden` `:open`
|
|
171
|
+
`:active` `:recent`. The filter bar — search box plus the Group / Sort /
|
|
172
|
+
Status / Age dropdowns — is visible by default: `Tab`/`Shift+Tab` walk into
|
|
173
|
+
the dropdowns, `Enter` opens one, `␣/` reclaims the rows (persists).
|
|
174
|
+
|
|
175
|
+
More keyboard parity: `Alt+←/→` nudges the list/pane divider (persists, like
|
|
176
|
+
dragging it). Every menu action also has a legacy F-key alias — `?` lists
|
|
177
|
+
them all, including your `[keys]` remaps.
|
|
178
|
+
|
|
179
|
+
Don't like the defaults? In `config.toml`: `[keys] leader = "none"` turns the
|
|
180
|
+
mode off (Space then marks directly, as before), `leader = "ctrl+g"` moves it,
|
|
181
|
+
`leader_defaults = false` empties the map, and any `action = "x"` single-letter
|
|
182
|
+
entry remaps one sequence. **Mouse extras** (never required): click a column
|
|
183
|
+
header to sort, drag the divider, click rows and dropdowns.
|
|
184
|
+
|
|
185
|
+
### Split-live (default)
|
|
186
|
+
|
|
187
|
+

|
|
188
|
+
|
|
189
|
+
saikai runs real interactive `claude` processes in tabs beside the list whenever
|
|
190
|
+
its PTY deps (`pyte`, `pywinpty`/`ptyprocess`) are present — they ship as
|
|
191
|
+
dependencies, so this is the default. To opt out and use the lightweight
|
|
192
|
+
list-only browser (`Enter` = full-screen takeover resume), set the env var:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
SAIKAI_SPLIT_LIVE=0 saikai # also: false / no / off
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
| Key | Action |
|
|
199
|
+
|-----|--------|
|
|
200
|
+
| `Enter` | open / focus a live pane for the selected session |
|
|
201
|
+
| `Shift+F8` | start a NEW claude session in any folder / git worktree |
|
|
202
|
+
| `Shift+F4` | reopen the panes from your last session (snapshot + resume) — anytime |
|
|
203
|
+
| `F2` / `F3` | previous / next live tab |
|
|
204
|
+
| `Shift+F3` | jump to the next pane needing attention (`?` waiting / `!` finished) |
|
|
205
|
+
| `F4` | hide / show the session list (full-width pane) |
|
|
206
|
+
| `Ctrl+]` | return focus from a pane back to the list (`SAIKAI_RELEASE_KEY` to change) |
|
|
207
|
+
| `F10` / `Shift+F10` | close the active tab / close all tabs (explicit close — *not* restored) |
|
|
208
|
+
| `Esc` / `Ctrl+C` | quit: snapshot the open panes, then kill them all (`Shift+F4` reopens them next launch) |
|
|
209
|
+
| scroll up | freeze the pane (copy mode): select/copy while claude keeps running |
|
|
210
|
+
|
|
211
|
+
Markers in the list: `~` busy · `?` waiting for input · `!` finished (unanswered)
|
|
212
|
+
· `@` open · `+` active · `.` recent · `*` favorite · `x` hidden.
|
|
213
|
+
|
|
214
|
+
## Configuration (environment variables)
|
|
215
|
+
|
|
216
|
+
| Variable | Default | Meaning |
|
|
217
|
+
|---|---|---|
|
|
218
|
+
| `SAIKAI_SPLIT_LIVE` | on | live-pane mode; set `0`/`false`/`no`/`off` to disable → list-only browser + full-takeover resume |
|
|
219
|
+
| `SAIKAI_AUTO_REFRESH` | off | seconds between background re-scans |
|
|
220
|
+
| `SAIKAI_SUMMARIZE_CMD` | — | command to summarize with (prompt on stdin → summary on stdout) instead of `claude -p` |
|
|
221
|
+
| `SAIKAI_AUTO_PERMISSION` | off | opt in to adding `--permission-mode auto` for frequently used workspaces |
|
|
222
|
+
| `SAIKAI_MAX_MEM_LOAD` | 85 | refuse/warn opening a pane above this memory-load % (Win `dwMemoryLoad`; Linux/macOS derived) |
|
|
223
|
+
| `SAIKAI_MIN_COMMIT_MB` | 2048 | keep this much **commit headroom** free — the system-freeze guard (Win/Linux) |
|
|
224
|
+
| `SAIKAI_MIN_FREE_PHYS_PCT` | 8 | keep ≥ this % of physical RAM available (anti-thrash floor, machine-relative) |
|
|
225
|
+
| `SAIKAI_CLAUDE_MB` | 600 | estimated RAM per live pane |
|
|
226
|
+
| `SAIKAI_MIN_FREE_MB` | 0 | optional absolute physical floor (legacy; max'd with the % floor) |
|
|
227
|
+
| `SAIKAI_HARD_RAM_GATE` | off | `1` refuses (vs warns) when the gate would be crossed |
|
|
228
|
+
| `SAIKAI_MAX_LIVE` | 64 | hard cap on concurrent live panes (backstop) |
|
|
229
|
+
| `SAIKAI_SCROLLBACK` | 2000 | per-pane scrollback lines kept in memory. **Biggest lever on the live process's RAM** (a full pane ≈ cols×lines pyte cells); lower it (e.g. 1000) on a memory-tight machine, raise for deeper history |
|
|
230
|
+
| `SAIKAI_COLOR_BY` | project | what tints the session title: `project` / `worktree` / `topic` / `none` |
|
|
231
|
+
| `SAIKAI_SPLIT_RATIO` | 0.34 | initial list/pane split (drag the divider to change; the dragged value persists) |
|
|
232
|
+
| `SAIKAI_RELEASE_KEY` | `ctrl+]` | key that returns focus from a live pane to the list |
|
|
233
|
+
|
|
234
|
+
saikai also reads an optional **TOML config file** for these same knobs (with
|
|
235
|
+
`env > config > default` precedence) plus `[keys]` rebinds. Run `saikai
|
|
236
|
+
--init-config` to write a documented template, `saikai --print-config` to see the
|
|
237
|
+
resolved location and values — or press **`Space ,`** inside the app: the
|
|
238
|
+
Settings screen edits the list options in place and shows every config knob
|
|
239
|
+
with its resolved value and source (`e` there opens config.toml in your editor).
|
|
240
|
+
|
|
241
|
+
Claude Code is the currently integrated provider. Agent-specific launch and
|
|
242
|
+
status contracts live in `saikai_provider.py`; a Codex contract validates the
|
|
243
|
+
extension boundary, but Codex is not selectable until its history discovery and
|
|
244
|
+
live-state integration are complete. Claude history discovery respects
|
|
245
|
+
`CLAUDE_CONFIG_DIR`.
|
|
246
|
+
|
|
247
|
+
## Platform support
|
|
248
|
+
|
|
249
|
+
**Verified support is deliberately bounded to Windows 10 / 11 on Python ≥
|
|
250
|
+
3.11.** Linux, WSL2, and macOS remain implemented but experimental until their
|
|
251
|
+
real PTY paths receive sustained native testing. Other platforms are unsupported.
|
|
252
|
+
|
|
253
|
+
saikai itself is pure Python + Textual; the **split-live pane** is the only
|
|
254
|
+
platform-specific part (it drives a real PTY and the clipboard). Honest status:
|
|
255
|
+
|
|
256
|
+
| OS | Live-pane PTY | Clipboard (from a frozen pane) | RAM gate source | Status |
|
|
257
|
+
|---|---|---|---|---|
|
|
258
|
+
| **Windows** 10 / 11 | ConPTY (`pywinpty`) | Win32 `CF_UNICODETEXT` (codepage-safe) | `GlobalMemoryStatusEx` | ✅ **developed & daily-driven** (on WezTerm) |
|
|
259
|
+
| **Linux** *(incl. WSL2)* | POSIX PTY (`ptyprocess`) | OSC-52 *(terminal / tmux / SSH policy must allow it)* | `/proc/meminfo` | ⚠️ **experimental; native reviewers wanted** |
|
|
260
|
+
| **macOS** | POSIX PTY (`ptyprocess`) | local `pbcopy`; OSC-52 fallback for remote-capable terminals | `sysctl` + `vm_stat` *(load + physical; no commit limit)* | ⚠️ **experimental; macOS reviewers wanted** |
|
|
261
|
+
|
|
262
|
+
- **Terminal-agnostic on Windows:** the clipboard goes through the Win32
|
|
263
|
+
`CF_UNICODETEXT` API and the PTY through ConPTY, neither of which depends on
|
|
264
|
+
the host terminal — so **Windows Terminal** uses the same code paths as WezTerm
|
|
265
|
+
(verified terminal) and is expected to behave identically.
|
|
266
|
+
- **List-only mode** (`SAIKAI_SPLIT_LIVE=0`) has no PTY dependency and should run
|
|
267
|
+
anywhere Textual runs.
|
|
268
|
+
- The headless regression tests are platform-independent (they stub out
|
|
269
|
+
textual / pyte / pywinpty) and pass on the dev machine — run them with plain
|
|
270
|
+
`python` (no deps needed):
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
python tests/test_config.py
|
|
274
|
+
python tests/test_providers.py
|
|
275
|
+
python tests/test_sort_recency.py
|
|
276
|
+
python tests/test_split_divider.py
|
|
277
|
+
python tests/test_terminal_concurrency.py
|
|
278
|
+
python tests/test_resource_bounds.py
|
|
279
|
+
python tests/test_terminal_watchdog.py
|
|
280
|
+
python tests/test_keyboard_leader.py
|
|
281
|
+
python tests/test_pty_backend.py
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- Linux/WSL2/macOS reviewers are wanted. Please report the terminal, local vs
|
|
285
|
+
SSH/tmux setup, PTY teardown result, key quirks, and clipboard behavior.
|
|
286
|
+
- CI installs each OS's real PTY backend and smoke-tests spawn, resize, output,
|
|
287
|
+
and EOF on Windows, Linux, and macOS. This is not a substitute for interactive
|
|
288
|
+
review across terminal emulators, SSH, tmux, IMEs, and clipboard policies.
|
|
289
|
+
|
|
290
|
+
## Contributing
|
|
291
|
+
|
|
292
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for the dev
|
|
293
|
+
setup, how to run the test suites, and the **concurrency invariants** that keep
|
|
294
|
+
the split-live pane from deadlocking (read those before touching threading code).
|
|
295
|
+
Changes are documented in [CHANGELOG.md](CHANGELOG.md).
|
|
296
|
+
|
|
297
|
+
## Security
|
|
298
|
+
|
|
299
|
+
Please report vulnerabilities privately — see [SECURITY.md](SECURITY.md). Don't
|
|
300
|
+
open a public issue for a security problem.
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
saikai is released under the [MIT License](LICENSE). It depends on a few
|
|
305
|
+
third-party packages installed separately (textual, pyte, pywinpty/ptyprocess) —
|
|
306
|
+
see [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md). Note `pyte` is LGPL-3.0; it
|
|
307
|
+
is used as an unmodified, separately-installed dependency, which keeps saikai's
|
|
308
|
+
own code MIT.
|
saikai-0.2.1/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# saikai
|
|
2
|
+
|
|
3
|
+
[](https://github.com/m-morino/saikai/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/saikai/)
|
|
5
|
+
[](https://github.com/m-morino/saikai/releases/latest)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://www.python.org/downloads/)
|
|
8
|
+
|
|
9
|
+
**English** | [日本語](README.ja.md)
|
|
10
|
+
|
|
11
|
+
Dozens of Claude Code sessions, one searchable table. saikai scans your entire
|
|
12
|
+
`~/.claude/projects` history, lets you filter and group by date / project /
|
|
13
|
+
topic, and resumes any session with `Enter`. By default (**split-live**) it keeps
|
|
14
|
+
several sessions running live in tabs beside the list — jump between conversations
|
|
15
|
+
without closing anything or losing scrollback.
|
|
16
|
+
|
|
17
|
+
*saikai* = 再開 "resume" + 再会 "reunion" (Japanese). Complements
|
|
18
|
+
[ccmanager](https://github.com/kbwo/ccmanager), which manages a live multi-agent
|
|
19
|
+
roster; saikai is for navigating and resuming the history.
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
<sub>The demo uses fictional, leak-checked data. Regenerate the animated GIF
|
|
24
|
+
headlessly with `uv run scripts/make_demo_gif.py`; use
|
|
25
|
+
`uv run scripts/record_demo.py --guide` for a native-terminal recording.</sub>
|
|
26
|
+
|
|
27
|
+
## Highlights
|
|
28
|
+
|
|
29
|
+
- **Every session, one table** — every Claude Code conversation on your
|
|
30
|
+
machine, sorted by real last activity, grouped by date / project / topic,
|
|
31
|
+
filtered as you type.
|
|
32
|
+
- **Resume in place** — `Enter` reopens a session with `claude --resume` in the
|
|
33
|
+
working directory it was started from (worktree-aware).
|
|
34
|
+
- **Split-live panes** — host several live `claude` sessions in tabs beside the
|
|
35
|
+
list; markers show at a glance who is busy `~`, waiting for your input `?`,
|
|
36
|
+
or finished `!`. Quit and `Shift+F4` restores the whole pane set later.
|
|
37
|
+
- **Session hygiene** — favorite `★`, hide, rename; AI one-line titles; an
|
|
38
|
+
inferred parent/child tree and LLM topic clusters for big histories.
|
|
39
|
+
- **RAM-aware** — a memory gate (commit headroom + load + physical floor)
|
|
40
|
+
warns before a new pane would push the machine into thrashing.
|
|
41
|
+
- **Keyboard-first** — everything works without a mouse: `Space` opens a
|
|
42
|
+
mnemonic command menu (`Space f` = favorite, `Space s` = sort …),
|
|
43
|
+
`Alt+←/→` resizes the split, `?` shows the live key map. The mouse is a
|
|
44
|
+
bonus (click to sort, drag the divider), never a requirement.
|
|
45
|
+
- **Unintrusive by design** — read-only over claude's own transcript files; no
|
|
46
|
+
daemon, no database. Two Python files on top of
|
|
47
|
+
[Textual](https://github.com/Textualize/textual), MIT-licensed.
|
|
48
|
+
|
|
49
|
+
> The live pane uses ConPTY on Windows and a POSIX PTY elsewhere — see
|
|
50
|
+
> [Platform support](#platform-support) for the per-OS verification status
|
|
51
|
+
> (Windows is the verified platform today).
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
Requires **Python ≥ 3.11**. The easiest path is
|
|
56
|
+
[uv](https://docs.astral.sh/uv/) — it installs the PyPI package in an isolated
|
|
57
|
+
environment, no manual venv:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
uv tool install saikai # stable release → `saikai` on PATH
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
From a clone:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv run saikai.py # run in place (deps auto-installed)
|
|
67
|
+
uv tool install . # install the `saikai` command on your PATH, then: saikai
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Prefer pip / pipx? Both work (deps come from `pyproject.toml`):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pipx install saikai # isolated + on PATH
|
|
74
|
+
pip install saikai # into the active environment
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The split-live pane needs the PTY deps (`pyte`, and `pywinpty` on Windows /
|
|
78
|
+
`ptyprocess` elsewhere); they install automatically with any command above. If
|
|
79
|
+
they're somehow missing, saikai still runs in list-only mode (see below).
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
saikai # every project, full history (the default)
|
|
85
|
+
saikai --here # only the current project (git repo)
|
|
86
|
+
saikai --days 7 # only the last 7 days (one-shot; --save-defaults persists)
|
|
87
|
+
saikai --table # static, non-interactive table
|
|
88
|
+
saikai --help
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Keys — learn three things
|
|
92
|
+
|
|
93
|
+
Everything else is on screen (the footer, the dropdowns, and the `␣` menu
|
|
94
|
+
that pops up when you pause).
|
|
95
|
+
|
|
96
|
+
1. **Keys you already know.** `↑` `↓` move · `Enter` resumes · `/` or just
|
|
97
|
+
typing searches · `Tab` toggles the preview · `?` full key list · `Esc`
|
|
98
|
+
leaves the current context (search → list → quit).
|
|
99
|
+
2. **`Space` is the menu.** Press `Space` in the list, then one mnemonic
|
|
100
|
+
letter. Hesitate after `Space` and the whole menu appears in place,
|
|
101
|
+
grouped by family (which-key style) — nothing to memorise:
|
|
102
|
+
|
|
103
|
+
| Session | View | Panes |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `f` ★ favorite | `s` cycle **s**ort column | `n` new session |
|
|
106
|
+
| `h` hide | `o` flip sort **o**rder | `p` restore panes |
|
|
107
|
+
| `e` rename (edit) | `g` cycle grouping | `z` freeze pane |
|
|
108
|
+
| `y` copy prompt (yank) | `t` tree · `c` cluster | `a` next attention |
|
|
109
|
+
| `d` diff (changes) | `l` hide/show list | `x` close tab · `[` `]` tabs |
|
|
110
|
+
| `r` refresh | `,` settings · `/` hide/show bar | `Space` mark for batch launch |
|
|
111
|
+
|
|
112
|
+
Space is a deliberate menu key, not a claim that every TUI should use a
|
|
113
|
+
Space leader: it only arms while the session list owns focus, so search
|
|
114
|
+
fields and live agent panes keep a literal Space. It also avoids taking a
|
|
115
|
+
letter away from type-to-search. The trade-off is that list marking becomes
|
|
116
|
+
`Space Space`; set `[keys] leader = "none"` if conventional Space-to-mark is
|
|
117
|
+
more important to you.
|
|
118
|
+
|
|
119
|
+
3. **`Ctrl+]` returns focus** from a live claude pane to the list (the pane
|
|
120
|
+
owns every other key, so claude works normally inside it).
|
|
121
|
+
|
|
122
|
+
**Search tokens** (combine with text and each other): `:fav` `:hidden` `:open`
|
|
123
|
+
`:active` `:recent`. The filter bar — search box plus the Group / Sort /
|
|
124
|
+
Status / Age dropdowns — is visible by default: `Tab`/`Shift+Tab` walk into
|
|
125
|
+
the dropdowns, `Enter` opens one, `␣/` reclaims the rows (persists).
|
|
126
|
+
|
|
127
|
+
More keyboard parity: `Alt+←/→` nudges the list/pane divider (persists, like
|
|
128
|
+
dragging it). Every menu action also has a legacy F-key alias — `?` lists
|
|
129
|
+
them all, including your `[keys]` remaps.
|
|
130
|
+
|
|
131
|
+
Don't like the defaults? In `config.toml`: `[keys] leader = "none"` turns the
|
|
132
|
+
mode off (Space then marks directly, as before), `leader = "ctrl+g"` moves it,
|
|
133
|
+
`leader_defaults = false` empties the map, and any `action = "x"` single-letter
|
|
134
|
+
entry remaps one sequence. **Mouse extras** (never required): click a column
|
|
135
|
+
header to sort, drag the divider, click rows and dropdowns.
|
|
136
|
+
|
|
137
|
+
### Split-live (default)
|
|
138
|
+
|
|
139
|
+

|
|
140
|
+
|
|
141
|
+
saikai runs real interactive `claude` processes in tabs beside the list whenever
|
|
142
|
+
its PTY deps (`pyte`, `pywinpty`/`ptyprocess`) are present — they ship as
|
|
143
|
+
dependencies, so this is the default. To opt out and use the lightweight
|
|
144
|
+
list-only browser (`Enter` = full-screen takeover resume), set the env var:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
SAIKAI_SPLIT_LIVE=0 saikai # also: false / no / off
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
| Key | Action |
|
|
151
|
+
|-----|--------|
|
|
152
|
+
| `Enter` | open / focus a live pane for the selected session |
|
|
153
|
+
| `Shift+F8` | start a NEW claude session in any folder / git worktree |
|
|
154
|
+
| `Shift+F4` | reopen the panes from your last session (snapshot + resume) — anytime |
|
|
155
|
+
| `F2` / `F3` | previous / next live tab |
|
|
156
|
+
| `Shift+F3` | jump to the next pane needing attention (`?` waiting / `!` finished) |
|
|
157
|
+
| `F4` | hide / show the session list (full-width pane) |
|
|
158
|
+
| `Ctrl+]` | return focus from a pane back to the list (`SAIKAI_RELEASE_KEY` to change) |
|
|
159
|
+
| `F10` / `Shift+F10` | close the active tab / close all tabs (explicit close — *not* restored) |
|
|
160
|
+
| `Esc` / `Ctrl+C` | quit: snapshot the open panes, then kill them all (`Shift+F4` reopens them next launch) |
|
|
161
|
+
| scroll up | freeze the pane (copy mode): select/copy while claude keeps running |
|
|
162
|
+
|
|
163
|
+
Markers in the list: `~` busy · `?` waiting for input · `!` finished (unanswered)
|
|
164
|
+
· `@` open · `+` active · `.` recent · `*` favorite · `x` hidden.
|
|
165
|
+
|
|
166
|
+
## Configuration (environment variables)
|
|
167
|
+
|
|
168
|
+
| Variable | Default | Meaning |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `SAIKAI_SPLIT_LIVE` | on | live-pane mode; set `0`/`false`/`no`/`off` to disable → list-only browser + full-takeover resume |
|
|
171
|
+
| `SAIKAI_AUTO_REFRESH` | off | seconds between background re-scans |
|
|
172
|
+
| `SAIKAI_SUMMARIZE_CMD` | — | command to summarize with (prompt on stdin → summary on stdout) instead of `claude -p` |
|
|
173
|
+
| `SAIKAI_AUTO_PERMISSION` | off | opt in to adding `--permission-mode auto` for frequently used workspaces |
|
|
174
|
+
| `SAIKAI_MAX_MEM_LOAD` | 85 | refuse/warn opening a pane above this memory-load % (Win `dwMemoryLoad`; Linux/macOS derived) |
|
|
175
|
+
| `SAIKAI_MIN_COMMIT_MB` | 2048 | keep this much **commit headroom** free — the system-freeze guard (Win/Linux) |
|
|
176
|
+
| `SAIKAI_MIN_FREE_PHYS_PCT` | 8 | keep ≥ this % of physical RAM available (anti-thrash floor, machine-relative) |
|
|
177
|
+
| `SAIKAI_CLAUDE_MB` | 600 | estimated RAM per live pane |
|
|
178
|
+
| `SAIKAI_MIN_FREE_MB` | 0 | optional absolute physical floor (legacy; max'd with the % floor) |
|
|
179
|
+
| `SAIKAI_HARD_RAM_GATE` | off | `1` refuses (vs warns) when the gate would be crossed |
|
|
180
|
+
| `SAIKAI_MAX_LIVE` | 64 | hard cap on concurrent live panes (backstop) |
|
|
181
|
+
| `SAIKAI_SCROLLBACK` | 2000 | per-pane scrollback lines kept in memory. **Biggest lever on the live process's RAM** (a full pane ≈ cols×lines pyte cells); lower it (e.g. 1000) on a memory-tight machine, raise for deeper history |
|
|
182
|
+
| `SAIKAI_COLOR_BY` | project | what tints the session title: `project` / `worktree` / `topic` / `none` |
|
|
183
|
+
| `SAIKAI_SPLIT_RATIO` | 0.34 | initial list/pane split (drag the divider to change; the dragged value persists) |
|
|
184
|
+
| `SAIKAI_RELEASE_KEY` | `ctrl+]` | key that returns focus from a live pane to the list |
|
|
185
|
+
|
|
186
|
+
saikai also reads an optional **TOML config file** for these same knobs (with
|
|
187
|
+
`env > config > default` precedence) plus `[keys]` rebinds. Run `saikai
|
|
188
|
+
--init-config` to write a documented template, `saikai --print-config` to see the
|
|
189
|
+
resolved location and values — or press **`Space ,`** inside the app: the
|
|
190
|
+
Settings screen edits the list options in place and shows every config knob
|
|
191
|
+
with its resolved value and source (`e` there opens config.toml in your editor).
|
|
192
|
+
|
|
193
|
+
Claude Code is the currently integrated provider. Agent-specific launch and
|
|
194
|
+
status contracts live in `saikai_provider.py`; a Codex contract validates the
|
|
195
|
+
extension boundary, but Codex is not selectable until its history discovery and
|
|
196
|
+
live-state integration are complete. Claude history discovery respects
|
|
197
|
+
`CLAUDE_CONFIG_DIR`.
|
|
198
|
+
|
|
199
|
+
## Platform support
|
|
200
|
+
|
|
201
|
+
**Verified support is deliberately bounded to Windows 10 / 11 on Python ≥
|
|
202
|
+
3.11.** Linux, WSL2, and macOS remain implemented but experimental until their
|
|
203
|
+
real PTY paths receive sustained native testing. Other platforms are unsupported.
|
|
204
|
+
|
|
205
|
+
saikai itself is pure Python + Textual; the **split-live pane** is the only
|
|
206
|
+
platform-specific part (it drives a real PTY and the clipboard). Honest status:
|
|
207
|
+
|
|
208
|
+
| OS | Live-pane PTY | Clipboard (from a frozen pane) | RAM gate source | Status |
|
|
209
|
+
|---|---|---|---|---|
|
|
210
|
+
| **Windows** 10 / 11 | ConPTY (`pywinpty`) | Win32 `CF_UNICODETEXT` (codepage-safe) | `GlobalMemoryStatusEx` | ✅ **developed & daily-driven** (on WezTerm) |
|
|
211
|
+
| **Linux** *(incl. WSL2)* | POSIX PTY (`ptyprocess`) | OSC-52 *(terminal / tmux / SSH policy must allow it)* | `/proc/meminfo` | ⚠️ **experimental; native reviewers wanted** |
|
|
212
|
+
| **macOS** | POSIX PTY (`ptyprocess`) | local `pbcopy`; OSC-52 fallback for remote-capable terminals | `sysctl` + `vm_stat` *(load + physical; no commit limit)* | ⚠️ **experimental; macOS reviewers wanted** |
|
|
213
|
+
|
|
214
|
+
- **Terminal-agnostic on Windows:** the clipboard goes through the Win32
|
|
215
|
+
`CF_UNICODETEXT` API and the PTY through ConPTY, neither of which depends on
|
|
216
|
+
the host terminal — so **Windows Terminal** uses the same code paths as WezTerm
|
|
217
|
+
(verified terminal) and is expected to behave identically.
|
|
218
|
+
- **List-only mode** (`SAIKAI_SPLIT_LIVE=0`) has no PTY dependency and should run
|
|
219
|
+
anywhere Textual runs.
|
|
220
|
+
- The headless regression tests are platform-independent (they stub out
|
|
221
|
+
textual / pyte / pywinpty) and pass on the dev machine — run them with plain
|
|
222
|
+
`python` (no deps needed):
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
python tests/test_config.py
|
|
226
|
+
python tests/test_providers.py
|
|
227
|
+
python tests/test_sort_recency.py
|
|
228
|
+
python tests/test_split_divider.py
|
|
229
|
+
python tests/test_terminal_concurrency.py
|
|
230
|
+
python tests/test_resource_bounds.py
|
|
231
|
+
python tests/test_terminal_watchdog.py
|
|
232
|
+
python tests/test_keyboard_leader.py
|
|
233
|
+
python tests/test_pty_backend.py
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
- Linux/WSL2/macOS reviewers are wanted. Please report the terminal, local vs
|
|
237
|
+
SSH/tmux setup, PTY teardown result, key quirks, and clipboard behavior.
|
|
238
|
+
- CI installs each OS's real PTY backend and smoke-tests spawn, resize, output,
|
|
239
|
+
and EOF on Windows, Linux, and macOS. This is not a substitute for interactive
|
|
240
|
+
review across terminal emulators, SSH, tmux, IMEs, and clipboard policies.
|
|
241
|
+
|
|
242
|
+
## Contributing
|
|
243
|
+
|
|
244
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for the dev
|
|
245
|
+
setup, how to run the test suites, and the **concurrency invariants** that keep
|
|
246
|
+
the split-live pane from deadlocking (read those before touching threading code).
|
|
247
|
+
Changes are documented in [CHANGELOG.md](CHANGELOG.md).
|
|
248
|
+
|
|
249
|
+
## Security
|
|
250
|
+
|
|
251
|
+
Please report vulnerabilities privately — see [SECURITY.md](SECURITY.md). Don't
|
|
252
|
+
open a public issue for a security problem.
|
|
253
|
+
|
|
254
|
+
## License
|
|
255
|
+
|
|
256
|
+
saikai is released under the [MIT License](LICENSE). It depends on a few
|
|
257
|
+
third-party packages installed separately (textual, pyte, pywinpty/ptyprocess) —
|
|
258
|
+
see [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md). Note `pyte` is LGPL-3.0; it
|
|
259
|
+
is used as an unmodified, separately-installed dependency, which keeps saikai's
|
|
260
|
+
own code MIT.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
saikai is licensed under the MIT License (see `LICENSE`). It depends on the
|
|
4
|
+
following third-party packages, installed separately via your package manager
|
|
5
|
+
(pip / uv) — saikai does **not** bundle or modify their source.
|
|
6
|
+
|
|
7
|
+
| Package | License | Role |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| [textual](https://github.com/Textualize/textual) | MIT | TUI framework |
|
|
10
|
+
| [rich](https://github.com/Textualize/rich) | MIT | text rendering (via textual) |
|
|
11
|
+
| [pyte](https://github.com/selectel/pyte) | **LGPL-3.0** | in-memory terminal emulator (split-live pane) |
|
|
12
|
+
| [pywinpty](https://github.com/andfoy/pywinpty) | MIT | Windows ConPTY backend (`sys_platform == 'win32'`) |
|
|
13
|
+
| [ptyprocess](https://github.com/pexpect/ptyprocess) | ISC | POSIX PTY backend (non-Windows) |
|
|
14
|
+
|
|
15
|
+
## Note on pyte (LGPL-3.0)
|
|
16
|
+
|
|
17
|
+
saikai imports `pyte` as an ordinary, unmodified dependency installed by the user
|
|
18
|
+
(pip/uv). It is **not** copied into this repository or statically combined with
|
|
19
|
+
saikai's source. Under the LGPL-3.0 this "use as a separately-installed library"
|
|
20
|
+
case does not impose the LGPL on saikai's own code, and the dynamic Python import
|
|
21
|
+
satisfies the requirement that the library remain user-replaceable. saikai's own
|
|
22
|
+
source therefore remains under the MIT License.
|
|
23
|
+
|
|
24
|
+
If you redistribute saikai together with a copy of pyte (e.g. a vendored bundle
|
|
25
|
+
or a frozen binary), review the LGPL-3.0 terms — in that case you must keep pyte
|
|
26
|
+
under the LGPL and allow it to be replaced.
|