ring-cli 0.2.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.
- ring_cli-0.2.0/LICENSE +21 -0
- ring_cli-0.2.0/PKG-INFO +334 -0
- ring_cli-0.2.0/README.en.md +309 -0
- ring_cli-0.2.0/pyproject.toml +124 -0
- ring_cli-0.2.0/src/ring/__init__.py +12 -0
- ring_cli-0.2.0/src/ring/__main__.py +6 -0
- ring_cli-0.2.0/src/ring/cli.py +685 -0
- ring_cli-0.2.0/src/ring/config.py +276 -0
- ring_cli-0.2.0/src/ring/focus/__init__.py +65 -0
- ring_cli-0.2.0/src/ring/focus/applescript.py +34 -0
- ring_cli-0.2.0/src/ring/focus/base.py +19 -0
- ring_cli-0.2.0/src/ring/focus/iterm2.py +28 -0
- ring_cli-0.2.0/src/ring/focus/terminal.py +25 -0
- ring_cli-0.2.0/src/ring/focus/tmux.py +38 -0
- ring_cli-0.2.0/src/ring/hook.py +482 -0
- ring_cli-0.2.0/src/ring/hook_protocol.py +264 -0
- ring_cli-0.2.0/src/ring/i18n.py +52 -0
- ring_cli-0.2.0/src/ring/ipc.py +220 -0
- ring_cli-0.2.0/src/ring/labels.py +50 -0
- ring_cli-0.2.0/src/ring/locale/en/LC_MESSAGES/ring.mo +0 -0
- ring_cli-0.2.0/src/ring/locale/en/LC_MESSAGES/ring.po +395 -0
- ring_cli-0.2.0/src/ring/locale/ring.pot +484 -0
- ring_cli-0.2.0/src/ring/notify/__init__.py +120 -0
- ring_cli-0.2.0/src/ring/notify/base.py +37 -0
- ring_cli-0.2.0/src/ring/notify/command.py +18 -0
- ring_cli-0.2.0/src/ring/notify/notify_send.py +30 -0
- ring_cli-0.2.0/src/ring/notify/osascript_notifier.py +32 -0
- ring_cli-0.2.0/src/ring/notify/terminal_notifier.py +64 -0
- ring_cli-0.2.0/src/ring/osascript.py +17 -0
- ring_cli-0.2.0/src/ring/registry.py +851 -0
- ring_cli-0.2.0/src/ring/sources/__init__.py +94 -0
- ring_cli-0.2.0/src/ring/sources/base.py +17 -0
- ring_cli-0.2.0/src/ring/sources/claude_code.py +23 -0
- ring_cli-0.2.0/src/ring/sources/codex.py +16 -0
- ring_cli-0.2.0/src/ring/sources/hook_registry.py +16 -0
- ring_cli-0.2.0/src/ring/tui.py +360 -0
- ring_cli-0.2.0/src/ring/watcher.py +107 -0
ring_cli-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wei Lee
|
|
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.
|
ring_cli-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ring-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: RiNG — Realtime Instance Notification Grid for active agent CLI sessions.
|
|
5
|
+
Keywords: claude-code,codex,tui,dashboard,session,monitor,rich
|
|
6
|
+
Author: Wei Lee
|
|
7
|
+
Author-email: Wei Lee <weilee.rx@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: MacOS
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Software Development
|
|
17
|
+
Classifier: Topic :: Utilities
|
|
18
|
+
Requires-Dist: rich>=13
|
|
19
|
+
Requires-Dist: textual>=0.80 ; extra == 'tui'
|
|
20
|
+
Requires-Python: >=3.13
|
|
21
|
+
Project-URL: Homepage, https://github.com/Lee-W/ring
|
|
22
|
+
Project-URL: Repository, https://github.com/Lee-W/ring
|
|
23
|
+
Provides-Extra: tui
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# RiNG 🎤
|
|
27
|
+
|
|
28
|
+
[台灣漢語](https://github.com/Lee-W/ring/blob/main/README.md) · **English**
|
|
29
|
+
|
|
30
|
+
> **R**ealtime **I**nstance **N**otification **G**rid
|
|
31
|
+
> — a local dashboard for active agent-CLI sessions. Claude Code and Codex are built in; other tools can plug in.
|
|
32
|
+
|
|
33
|
+
When you run several Claude Code / Codex sessions at the same time, it is easy to lose track of
|
|
34
|
+
which one is still working, which one has finished a turn, and which one needs your response.
|
|
35
|
+
RiNG puts them on one board, with sessions waiting for you sorted first.
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
🎤 RiNG — 3 sessions on stage · 2 agent processes running
|
|
39
|
+
|
|
40
|
+
🔴 maigo 12s → waiting for permission
|
|
41
|
+
🟢 pelican-osm 3s → Edit
|
|
42
|
+
🟡 commitizen 8m turn finished, idle
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Who It Is For
|
|
46
|
+
|
|
47
|
+
- You run multiple Claude Code / Codex sessions in parallel.
|
|
48
|
+
- You want one board for “working”, “idle”, “waiting for me”, and “ended”.
|
|
49
|
+
- You want to jump from a TUI row back to the terminal where the session lives.
|
|
50
|
+
- You are willing to install hooks for precise waiting-state detection and system notifications.
|
|
51
|
+
|
|
52
|
+
## Key Features
|
|
53
|
+
|
|
54
|
+
- **One board for every session**: Claude Code / Codex are built in; other tools can feed `ring hook`.
|
|
55
|
+
- **Waiting first**: sessions that need your response are highlighted and sorted above the rest.
|
|
56
|
+
- **Jump back to the terminal**: in the TUI, select a session and press `Enter` / `Space` to focus tmux, iTerm2, or Terminal.app.
|
|
57
|
+
- **System notifications**: hook mode can beep and notify when a session starts waiting; with `terminal-notifier`, clicking the notification jumps back.
|
|
58
|
+
- **Name your sessions**: press `n` in the TUI to add a local label such as `maigo · auth refactor`.
|
|
59
|
+
- **Local and extensible**: RiNG only reads local Claude Code / Codex data and writes `~/.config/ring/`; session sources, focusers, and notifiers are pluggable.
|
|
60
|
+
|
|
61
|
+
## Run
|
|
62
|
+
|
|
63
|
+
Requires Python 3.13+. The PyPI package is named `ring-cli`, while the import module and CLI command are both `ring`.
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
# Recommended: install the command from PyPI
|
|
67
|
+
uv tool install 'ring-cli[tui]'
|
|
68
|
+
|
|
69
|
+
# Or use pipx
|
|
70
|
+
pipx install 'ring-cli[tui]'
|
|
71
|
+
|
|
72
|
+
# Then run it
|
|
73
|
+
ring
|
|
74
|
+
ring --watch
|
|
75
|
+
ring --watch --interval 1
|
|
76
|
+
|
|
77
|
+
# Module form also works after installation
|
|
78
|
+
python -m ring
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The `[tui]` extra installs the Textual interactive UI. Without it, `--watch` falls back to Rich polling, then plain text.
|
|
82
|
+
|
|
83
|
+
For development inside the repository:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
uv run ring
|
|
87
|
+
uv run ring --watch
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Zero-config mode can discover local Claude Code / Codex sessions without setup. For precise 🔴 waiting detection, install hooks:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
ring install-hooks # merges into Claude Code / Codex hook settings
|
|
94
|
+
ring install-hooks --dry-run # preview without writing
|
|
95
|
+
ring doctor # inspect hooks, notification backends, focusers, and config
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Hooks only apply to new sessions, so restart Claude Code / Codex sessions after installing.
|
|
99
|
+
|
|
100
|
+
## Common Commands
|
|
101
|
+
|
|
102
|
+
| Command | Purpose |
|
|
103
|
+
|---------|---------|
|
|
104
|
+
| `ring` | Print a one-shot snapshot |
|
|
105
|
+
| `ring --watch` | Keep refreshing; enters the TUI when Textual is installed |
|
|
106
|
+
| `ring --watch --interval 1` | Refresh every second |
|
|
107
|
+
| `ring --watch --count N` | Stop after N frames, useful for tests / CI |
|
|
108
|
+
| `ring --all` | Show ended sessions too |
|
|
109
|
+
| `ring --no-legend` | Hide the legend |
|
|
110
|
+
| `ring --lang zh-Hant` | Switch UI language |
|
|
111
|
+
| `ring focus SESSION_ID` | Focus a specific session |
|
|
112
|
+
| `ring config` | Show config path and effective settings |
|
|
113
|
+
| `ring config set KEY VALUE` | Write one config value |
|
|
114
|
+
| `ring doctor` | Read-only environment diagnosis |
|
|
115
|
+
|
|
116
|
+
## Watch Mode
|
|
117
|
+
|
|
118
|
+
- With **Textual** (`[tui]` extra) in a real terminal: interactive TUI.
|
|
119
|
+
Use `↑/↓` to select, `Enter` / `Space` to jump, `n` to name a session, `a` to toggle ended sessions, `r` to refresh, and `q` to quit.
|
|
120
|
+
If you have vim muscle memory like I do, `j/k` move up/down and `g/G` jump to the first/last row.
|
|
121
|
+
- Otherwise: Rich polling; without Rich, plain text.
|
|
122
|
+
|
|
123
|
+
### Jump To A Session
|
|
124
|
+
|
|
125
|
+
Select a session and press `Enter`. RiNG focuses the terminal where that session is running.
|
|
126
|
+
|
|
127
|
+
- **tmux**: switches directly to the pane via `switch-client`.
|
|
128
|
+
- **iTerm2 / Terminal.app** on macOS: uses the session `tty` and AppleScript to focus the matching tab. The first run may ask for macOS Automation permission.
|
|
129
|
+
|
|
130
|
+
TTY matching is most accurate in hook mode. Without hooks, Codex falls back to zero-config matching:
|
|
131
|
+
one live Codex session per cwd can jump correctly; multiple live Codex sessions in the same cwd are shown conservatively to avoid focusing the wrong tab.
|
|
132
|
+
|
|
133
|
+
### Notifications
|
|
134
|
+
|
|
135
|
+
Default behavior: with hooks installed, when a session changes to 🔴 waiting, RiNG beeps and sends
|
|
136
|
+
a system notification. If it keeps waiting, RiNG reminds you again at 30s / 120s / 300s by default.
|
|
137
|
+
|
|
138
|
+
For clickable notifications on macOS, install `terminal-notifier`:
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
brew install terminal-notifier
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Without it, RiNG falls back to macOS text notifications without click-to-focus.
|
|
145
|
+
Notification sound, repeat timing, and backend selection are configurable; notification backends
|
|
146
|
+
are also pluggable via the `Notifier` extension point.
|
|
147
|
+
|
|
148
|
+
## Session Sources
|
|
149
|
+
|
|
150
|
+
RiNG collects sessions from registered sources. Built-ins:
|
|
151
|
+
|
|
152
|
+
| Source | Reads From | Precision |
|
|
153
|
+
|--------|------------|-----------|
|
|
154
|
+
| **Claude Code zero-config** | `~/.claude/projects/**/*.jsonl`, mtimes, and `cwd` fields | no setup; detects recent activity and turn completion. Precise user-action prompts require hooks |
|
|
155
|
+
| **Codex zero-config** | `~/.codex/state_5.sqlite`, rollout JSONL, and live `codex` processes | no setup; detects live / ended / turn completion. Use hooks for precise jumps when multiple sessions share a cwd |
|
|
156
|
+
| **hook registry** | `~/.config/ring/sessions/`, written by `ring hook` | precise: 🔴 waiting / 🟢 working / 🟡 idle / ⚫ ended |
|
|
157
|
+
|
|
158
|
+
Zero-config needs no setup. For precise “who needs me”, install hooks so provider events feed the RiNG registry.
|
|
159
|
+
RiNG includes installers for Claude Code and Codex; other tools can use the provider-neutral `ring hook` protocol.
|
|
160
|
+
|
|
161
|
+
## States
|
|
162
|
+
|
|
163
|
+
RiNG reduces every session to four user-facing states. 🔴 waiting is sorted first.
|
|
164
|
+
|
|
165
|
+
| State | Meaning | What RiNG Saw |
|
|
166
|
+
|-------|---------|---------------|
|
|
167
|
+
| 🔴 waiting | You should return now | hook event requiring a user response, such as permission or choices |
|
|
168
|
+
| 🟢 working | Agent is running | prompt submitted or recent activity |
|
|
169
|
+
| 🟡 idle | The current turn finished | `Stop`, or no new activity past `working_threshold_seconds` |
|
|
170
|
+
| ⚫ ended | Session is over | `SessionEnd`, process ended, or local records aged out |
|
|
171
|
+
|
|
172
|
+
🔴 waiting requires hook mode. Zero-config can tell whether a session was recently active, but not whether it needs a decision from you.
|
|
173
|
+
|
|
174
|
+
## Hook Mode
|
|
175
|
+
|
|
176
|
+
Zero-config only has filesystem mtimes and local state snapshots, so it cannot reliably distinguish “needs a decision” from “just finished”.
|
|
177
|
+
Hooks send agent-CLI events directly to RiNG, making 🔴 waiting and notifications precise.
|
|
178
|
+
|
|
179
|
+
### Claude Code / Codex Installer
|
|
180
|
+
|
|
181
|
+
Hooks run `ring hook`, so install `ring` somewhere stable on `PATH` first:
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
uv tool install 'ring-cli[tui]'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Then register hooks:
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
ring install-hooks
|
|
191
|
+
ring install-hooks --dry-run
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Claude Code hooks are written to `~/.claude/settings.json`. If `~/.codex` exists, Codex hooks are also written to
|
|
195
|
+
`~/.codex/hooks.json`; Codex will ask you to trust the hook before it runs it.
|
|
196
|
+
|
|
197
|
+
Claude Code events:
|
|
198
|
+
|
|
199
|
+
| Claude Code Event | RiNG State |
|
|
200
|
+
|-------------------|------------|
|
|
201
|
+
| `SessionStart` / `UserPromptSubmit` | 🟢 working |
|
|
202
|
+
| `Stop` | 🟡 idle |
|
|
203
|
+
| `Notification` with `permission_prompt` / `elicitation_dialog` | 🔴 waiting |
|
|
204
|
+
| `PermissionRequest` / `PreToolUse` with `AskUserQuestion` | 🔴 waiting |
|
|
205
|
+
| `SessionEnd` | removed from the board |
|
|
206
|
+
|
|
207
|
+
Codex currently installs the supported interactive events: `PreToolUse`, `PermissionRequest`, and `Stop`.
|
|
208
|
+
|
|
209
|
+
Verify that hooks are writing:
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
ls ~/.config/ring/sessions/
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Other Providers
|
|
216
|
+
|
|
217
|
+
Any tool can feed JSON into `ring hook`:
|
|
218
|
+
|
|
219
|
+
```sh
|
|
220
|
+
ring hook --provider codex
|
|
221
|
+
# shorthand:
|
|
222
|
+
ring hook codex
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Payload field names are intentionally loose. At minimum, provide a session id, event, and cwd:
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"provider": "codex",
|
|
230
|
+
"session_id": "thread-123",
|
|
231
|
+
"event": "Notification",
|
|
232
|
+
"notification_type": "permission_prompt",
|
|
233
|
+
"requires_action": true,
|
|
234
|
+
"waiting_for": "permission",
|
|
235
|
+
"cwd": "/repo/app",
|
|
236
|
+
"tty": "/dev/ttys003",
|
|
237
|
+
"last_action": "waiting for permission"
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
If a provider can distinguish “needs user action now” from “just waiting for the next prompt”,
|
|
242
|
+
send `requires_action = true/false` or `waiting_for = "permission" | "options" | "next_step"`.
|
|
243
|
+
|
|
244
|
+
### agent-hooks
|
|
245
|
+
|
|
246
|
+
Notification details: `--watch` and the TUI both send notifications. The default backend is `auto`:
|
|
247
|
+
RiNG prefers clickable `terminal-notifier`, then falls back to `osascript` on macOS or `notify-send`
|
|
248
|
+
on Linux. If none are available, RiNG keeps the board running and skips notifications.
|
|
249
|
+
|
|
250
|
+
Config keys include `notify_sound`, `notify_sound_name`, `notify_ignore_dnd`,
|
|
251
|
+
`notify_repeat_seconds`, `notify_repeat_max`, and `notify_backend`. Custom notification channels
|
|
252
|
+
can be added by registering another `Notifier`.
|
|
253
|
+
|
|
254
|
+
`agent-hooks` is an optional external hook helper / decision UI. If it is installed and
|
|
255
|
+
`notify_backend = "agent-hooks"`, `ring hook` still writes RiNG registry state, then passes the
|
|
256
|
+
raw payload to `agent-hooks callback` for the synchronous decision UI. RiNG `--watch` will not send
|
|
257
|
+
a duplicate notification. If `agent-hooks` is not on `PATH`, RiNG automatically falls back to `auto`.
|
|
258
|
+
|
|
259
|
+
### Remove Hooks
|
|
260
|
+
|
|
261
|
+
```sh
|
|
262
|
+
ring remove-hooks
|
|
263
|
+
ring remove-hooks --dry-run
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
This removes RiNG-installed hook entries from Claude Code / Codex settings. It does not delete
|
|
267
|
+
`~/.config/ring/` session records and does not touch other hooks.
|
|
268
|
+
|
|
269
|
+
## Configuration
|
|
270
|
+
|
|
271
|
+
`~/.config/ring/config.toml`, all optional:
|
|
272
|
+
|
|
273
|
+
```toml
|
|
274
|
+
lang = "en"
|
|
275
|
+
interval = 2.0
|
|
276
|
+
show_all = false
|
|
277
|
+
legend = true
|
|
278
|
+
active_window_seconds = 21600
|
|
279
|
+
working_threshold_seconds = 90
|
|
280
|
+
waiting_window_seconds = 1800
|
|
281
|
+
notify_sound = true
|
|
282
|
+
notify_sound_name = "Glass"
|
|
283
|
+
notify_ignore_dnd = false
|
|
284
|
+
notify_backend = "auto" # auto / terminal-notifier / osascript / notify-send / agent-hooks / none
|
|
285
|
+
notify_repeat_seconds = [30, 120, 300]
|
|
286
|
+
notify_repeat_max = 3
|
|
287
|
+
focusers = ["tmux", "iTerm2", "Terminal"]
|
|
288
|
+
|
|
289
|
+
[colors]
|
|
290
|
+
waiting = "bold red"
|
|
291
|
+
working = "green"
|
|
292
|
+
idle = "yellow"
|
|
293
|
+
ended = "grey50"
|
|
294
|
+
project = "cyan"
|
|
295
|
+
location = "bright_blue"
|
|
296
|
+
muted = "grey50"
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Extending
|
|
300
|
+
|
|
301
|
+
RiNG is not tied to a specific tool or terminal.
|
|
302
|
+
|
|
303
|
+
| Extension Point | Purpose | Built-ins |
|
|
304
|
+
|-----------------|---------|-----------|
|
|
305
|
+
| `SessionSource` | find sessions | Claude Code, Codex, hook registry |
|
|
306
|
+
| `Focuser` | jump to terminals | tmux, iTerm2, Terminal.app |
|
|
307
|
+
| `Notifier` | notify when sessions are waiting | terminal-notifier, osascript, notify-send |
|
|
308
|
+
|
|
309
|
+
Each backend is a small module under `ring/sources/`, `ring/focus/`, or `ring/notify/`, registered via `register_*()`.
|
|
310
|
+
|
|
311
|
+
## Platform & Privacy
|
|
312
|
+
|
|
313
|
+
- **Platform**: macOS / Linux. Windows is not supported.
|
|
314
|
+
- **Privacy**: entirely local. RiNG only reads local `~/.claude/` and `~/.codex/` data and writes
|
|
315
|
+
`~/.config/ring/`. No network, uploads, or telemetry.
|
|
316
|
+
|
|
317
|
+
## Name
|
|
318
|
+
|
|
319
|
+
The name is a triple pun:
|
|
320
|
+
|
|
321
|
+
1. It **rings** you when a session needs a response.
|
|
322
|
+
2. “RiNG” is the live house from *BanG Dream!*.
|
|
323
|
+
3. **R**ealtime **I**nstance **N**otification **G**rid describes what it is.
|
|
324
|
+
|
|
325
|
+
## Non-Goals
|
|
326
|
+
|
|
327
|
+
RiNG tracks session state. It is not a token or cost dashboard.
|
|
328
|
+
|
|
329
|
+
Claude Code JSONL token counts are currently unreliable enough to make cost accounting misleading,
|
|
330
|
+
so RiNG deliberately avoids that surface.
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
MIT
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# RiNG 🎤
|
|
2
|
+
|
|
3
|
+
[台灣漢語](https://github.com/Lee-W/ring/blob/main/README.md) · **English**
|
|
4
|
+
|
|
5
|
+
> **R**ealtime **I**nstance **N**otification **G**rid
|
|
6
|
+
> — a local dashboard for active agent-CLI sessions. Claude Code and Codex are built in; other tools can plug in.
|
|
7
|
+
|
|
8
|
+
When you run several Claude Code / Codex sessions at the same time, it is easy to lose track of
|
|
9
|
+
which one is still working, which one has finished a turn, and which one needs your response.
|
|
10
|
+
RiNG puts them on one board, with sessions waiting for you sorted first.
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
🎤 RiNG — 3 sessions on stage · 2 agent processes running
|
|
14
|
+
|
|
15
|
+
🔴 maigo 12s → waiting for permission
|
|
16
|
+
🟢 pelican-osm 3s → Edit
|
|
17
|
+
🟡 commitizen 8m turn finished, idle
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Who It Is For
|
|
21
|
+
|
|
22
|
+
- You run multiple Claude Code / Codex sessions in parallel.
|
|
23
|
+
- You want one board for “working”, “idle”, “waiting for me”, and “ended”.
|
|
24
|
+
- You want to jump from a TUI row back to the terminal where the session lives.
|
|
25
|
+
- You are willing to install hooks for precise waiting-state detection and system notifications.
|
|
26
|
+
|
|
27
|
+
## Key Features
|
|
28
|
+
|
|
29
|
+
- **One board for every session**: Claude Code / Codex are built in; other tools can feed `ring hook`.
|
|
30
|
+
- **Waiting first**: sessions that need your response are highlighted and sorted above the rest.
|
|
31
|
+
- **Jump back to the terminal**: in the TUI, select a session and press `Enter` / `Space` to focus tmux, iTerm2, or Terminal.app.
|
|
32
|
+
- **System notifications**: hook mode can beep and notify when a session starts waiting; with `terminal-notifier`, clicking the notification jumps back.
|
|
33
|
+
- **Name your sessions**: press `n` in the TUI to add a local label such as `maigo · auth refactor`.
|
|
34
|
+
- **Local and extensible**: RiNG only reads local Claude Code / Codex data and writes `~/.config/ring/`; session sources, focusers, and notifiers are pluggable.
|
|
35
|
+
|
|
36
|
+
## Run
|
|
37
|
+
|
|
38
|
+
Requires Python 3.13+. The PyPI package is named `ring-cli`, while the import module and CLI command are both `ring`.
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
# Recommended: install the command from PyPI
|
|
42
|
+
uv tool install 'ring-cli[tui]'
|
|
43
|
+
|
|
44
|
+
# Or use pipx
|
|
45
|
+
pipx install 'ring-cli[tui]'
|
|
46
|
+
|
|
47
|
+
# Then run it
|
|
48
|
+
ring
|
|
49
|
+
ring --watch
|
|
50
|
+
ring --watch --interval 1
|
|
51
|
+
|
|
52
|
+
# Module form also works after installation
|
|
53
|
+
python -m ring
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The `[tui]` extra installs the Textual interactive UI. Without it, `--watch` falls back to Rich polling, then plain text.
|
|
57
|
+
|
|
58
|
+
For development inside the repository:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
uv run ring
|
|
62
|
+
uv run ring --watch
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Zero-config mode can discover local Claude Code / Codex sessions without setup. For precise 🔴 waiting detection, install hooks:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
ring install-hooks # merges into Claude Code / Codex hook settings
|
|
69
|
+
ring install-hooks --dry-run # preview without writing
|
|
70
|
+
ring doctor # inspect hooks, notification backends, focusers, and config
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Hooks only apply to new sessions, so restart Claude Code / Codex sessions after installing.
|
|
74
|
+
|
|
75
|
+
## Common Commands
|
|
76
|
+
|
|
77
|
+
| Command | Purpose |
|
|
78
|
+
|---------|---------|
|
|
79
|
+
| `ring` | Print a one-shot snapshot |
|
|
80
|
+
| `ring --watch` | Keep refreshing; enters the TUI when Textual is installed |
|
|
81
|
+
| `ring --watch --interval 1` | Refresh every second |
|
|
82
|
+
| `ring --watch --count N` | Stop after N frames, useful for tests / CI |
|
|
83
|
+
| `ring --all` | Show ended sessions too |
|
|
84
|
+
| `ring --no-legend` | Hide the legend |
|
|
85
|
+
| `ring --lang zh-Hant` | Switch UI language |
|
|
86
|
+
| `ring focus SESSION_ID` | Focus a specific session |
|
|
87
|
+
| `ring config` | Show config path and effective settings |
|
|
88
|
+
| `ring config set KEY VALUE` | Write one config value |
|
|
89
|
+
| `ring doctor` | Read-only environment diagnosis |
|
|
90
|
+
|
|
91
|
+
## Watch Mode
|
|
92
|
+
|
|
93
|
+
- With **Textual** (`[tui]` extra) in a real terminal: interactive TUI.
|
|
94
|
+
Use `↑/↓` to select, `Enter` / `Space` to jump, `n` to name a session, `a` to toggle ended sessions, `r` to refresh, and `q` to quit.
|
|
95
|
+
If you have vim muscle memory like I do, `j/k` move up/down and `g/G` jump to the first/last row.
|
|
96
|
+
- Otherwise: Rich polling; without Rich, plain text.
|
|
97
|
+
|
|
98
|
+
### Jump To A Session
|
|
99
|
+
|
|
100
|
+
Select a session and press `Enter`. RiNG focuses the terminal where that session is running.
|
|
101
|
+
|
|
102
|
+
- **tmux**: switches directly to the pane via `switch-client`.
|
|
103
|
+
- **iTerm2 / Terminal.app** on macOS: uses the session `tty` and AppleScript to focus the matching tab. The first run may ask for macOS Automation permission.
|
|
104
|
+
|
|
105
|
+
TTY matching is most accurate in hook mode. Without hooks, Codex falls back to zero-config matching:
|
|
106
|
+
one live Codex session per cwd can jump correctly; multiple live Codex sessions in the same cwd are shown conservatively to avoid focusing the wrong tab.
|
|
107
|
+
|
|
108
|
+
### Notifications
|
|
109
|
+
|
|
110
|
+
Default behavior: with hooks installed, when a session changes to 🔴 waiting, RiNG beeps and sends
|
|
111
|
+
a system notification. If it keeps waiting, RiNG reminds you again at 30s / 120s / 300s by default.
|
|
112
|
+
|
|
113
|
+
For clickable notifications on macOS, install `terminal-notifier`:
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
brew install terminal-notifier
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Without it, RiNG falls back to macOS text notifications without click-to-focus.
|
|
120
|
+
Notification sound, repeat timing, and backend selection are configurable; notification backends
|
|
121
|
+
are also pluggable via the `Notifier` extension point.
|
|
122
|
+
|
|
123
|
+
## Session Sources
|
|
124
|
+
|
|
125
|
+
RiNG collects sessions from registered sources. Built-ins:
|
|
126
|
+
|
|
127
|
+
| Source | Reads From | Precision |
|
|
128
|
+
|--------|------------|-----------|
|
|
129
|
+
| **Claude Code zero-config** | `~/.claude/projects/**/*.jsonl`, mtimes, and `cwd` fields | no setup; detects recent activity and turn completion. Precise user-action prompts require hooks |
|
|
130
|
+
| **Codex zero-config** | `~/.codex/state_5.sqlite`, rollout JSONL, and live `codex` processes | no setup; detects live / ended / turn completion. Use hooks for precise jumps when multiple sessions share a cwd |
|
|
131
|
+
| **hook registry** | `~/.config/ring/sessions/`, written by `ring hook` | precise: 🔴 waiting / 🟢 working / 🟡 idle / ⚫ ended |
|
|
132
|
+
|
|
133
|
+
Zero-config needs no setup. For precise “who needs me”, install hooks so provider events feed the RiNG registry.
|
|
134
|
+
RiNG includes installers for Claude Code and Codex; other tools can use the provider-neutral `ring hook` protocol.
|
|
135
|
+
|
|
136
|
+
## States
|
|
137
|
+
|
|
138
|
+
RiNG reduces every session to four user-facing states. 🔴 waiting is sorted first.
|
|
139
|
+
|
|
140
|
+
| State | Meaning | What RiNG Saw |
|
|
141
|
+
|-------|---------|---------------|
|
|
142
|
+
| 🔴 waiting | You should return now | hook event requiring a user response, such as permission or choices |
|
|
143
|
+
| 🟢 working | Agent is running | prompt submitted or recent activity |
|
|
144
|
+
| 🟡 idle | The current turn finished | `Stop`, or no new activity past `working_threshold_seconds` |
|
|
145
|
+
| ⚫ ended | Session is over | `SessionEnd`, process ended, or local records aged out |
|
|
146
|
+
|
|
147
|
+
🔴 waiting requires hook mode. Zero-config can tell whether a session was recently active, but not whether it needs a decision from you.
|
|
148
|
+
|
|
149
|
+
## Hook Mode
|
|
150
|
+
|
|
151
|
+
Zero-config only has filesystem mtimes and local state snapshots, so it cannot reliably distinguish “needs a decision” from “just finished”.
|
|
152
|
+
Hooks send agent-CLI events directly to RiNG, making 🔴 waiting and notifications precise.
|
|
153
|
+
|
|
154
|
+
### Claude Code / Codex Installer
|
|
155
|
+
|
|
156
|
+
Hooks run `ring hook`, so install `ring` somewhere stable on `PATH` first:
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
uv tool install 'ring-cli[tui]'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Then register hooks:
|
|
163
|
+
|
|
164
|
+
```sh
|
|
165
|
+
ring install-hooks
|
|
166
|
+
ring install-hooks --dry-run
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Claude Code hooks are written to `~/.claude/settings.json`. If `~/.codex` exists, Codex hooks are also written to
|
|
170
|
+
`~/.codex/hooks.json`; Codex will ask you to trust the hook before it runs it.
|
|
171
|
+
|
|
172
|
+
Claude Code events:
|
|
173
|
+
|
|
174
|
+
| Claude Code Event | RiNG State |
|
|
175
|
+
|-------------------|------------|
|
|
176
|
+
| `SessionStart` / `UserPromptSubmit` | 🟢 working |
|
|
177
|
+
| `Stop` | 🟡 idle |
|
|
178
|
+
| `Notification` with `permission_prompt` / `elicitation_dialog` | 🔴 waiting |
|
|
179
|
+
| `PermissionRequest` / `PreToolUse` with `AskUserQuestion` | 🔴 waiting |
|
|
180
|
+
| `SessionEnd` | removed from the board |
|
|
181
|
+
|
|
182
|
+
Codex currently installs the supported interactive events: `PreToolUse`, `PermissionRequest`, and `Stop`.
|
|
183
|
+
|
|
184
|
+
Verify that hooks are writing:
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
ls ~/.config/ring/sessions/
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Other Providers
|
|
191
|
+
|
|
192
|
+
Any tool can feed JSON into `ring hook`:
|
|
193
|
+
|
|
194
|
+
```sh
|
|
195
|
+
ring hook --provider codex
|
|
196
|
+
# shorthand:
|
|
197
|
+
ring hook codex
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Payload field names are intentionally loose. At minimum, provide a session id, event, and cwd:
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"provider": "codex",
|
|
205
|
+
"session_id": "thread-123",
|
|
206
|
+
"event": "Notification",
|
|
207
|
+
"notification_type": "permission_prompt",
|
|
208
|
+
"requires_action": true,
|
|
209
|
+
"waiting_for": "permission",
|
|
210
|
+
"cwd": "/repo/app",
|
|
211
|
+
"tty": "/dev/ttys003",
|
|
212
|
+
"last_action": "waiting for permission"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
If a provider can distinguish “needs user action now” from “just waiting for the next prompt”,
|
|
217
|
+
send `requires_action = true/false` or `waiting_for = "permission" | "options" | "next_step"`.
|
|
218
|
+
|
|
219
|
+
### agent-hooks
|
|
220
|
+
|
|
221
|
+
Notification details: `--watch` and the TUI both send notifications. The default backend is `auto`:
|
|
222
|
+
RiNG prefers clickable `terminal-notifier`, then falls back to `osascript` on macOS or `notify-send`
|
|
223
|
+
on Linux. If none are available, RiNG keeps the board running and skips notifications.
|
|
224
|
+
|
|
225
|
+
Config keys include `notify_sound`, `notify_sound_name`, `notify_ignore_dnd`,
|
|
226
|
+
`notify_repeat_seconds`, `notify_repeat_max`, and `notify_backend`. Custom notification channels
|
|
227
|
+
can be added by registering another `Notifier`.
|
|
228
|
+
|
|
229
|
+
`agent-hooks` is an optional external hook helper / decision UI. If it is installed and
|
|
230
|
+
`notify_backend = "agent-hooks"`, `ring hook` still writes RiNG registry state, then passes the
|
|
231
|
+
raw payload to `agent-hooks callback` for the synchronous decision UI. RiNG `--watch` will not send
|
|
232
|
+
a duplicate notification. If `agent-hooks` is not on `PATH`, RiNG automatically falls back to `auto`.
|
|
233
|
+
|
|
234
|
+
### Remove Hooks
|
|
235
|
+
|
|
236
|
+
```sh
|
|
237
|
+
ring remove-hooks
|
|
238
|
+
ring remove-hooks --dry-run
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
This removes RiNG-installed hook entries from Claude Code / Codex settings. It does not delete
|
|
242
|
+
`~/.config/ring/` session records and does not touch other hooks.
|
|
243
|
+
|
|
244
|
+
## Configuration
|
|
245
|
+
|
|
246
|
+
`~/.config/ring/config.toml`, all optional:
|
|
247
|
+
|
|
248
|
+
```toml
|
|
249
|
+
lang = "en"
|
|
250
|
+
interval = 2.0
|
|
251
|
+
show_all = false
|
|
252
|
+
legend = true
|
|
253
|
+
active_window_seconds = 21600
|
|
254
|
+
working_threshold_seconds = 90
|
|
255
|
+
waiting_window_seconds = 1800
|
|
256
|
+
notify_sound = true
|
|
257
|
+
notify_sound_name = "Glass"
|
|
258
|
+
notify_ignore_dnd = false
|
|
259
|
+
notify_backend = "auto" # auto / terminal-notifier / osascript / notify-send / agent-hooks / none
|
|
260
|
+
notify_repeat_seconds = [30, 120, 300]
|
|
261
|
+
notify_repeat_max = 3
|
|
262
|
+
focusers = ["tmux", "iTerm2", "Terminal"]
|
|
263
|
+
|
|
264
|
+
[colors]
|
|
265
|
+
waiting = "bold red"
|
|
266
|
+
working = "green"
|
|
267
|
+
idle = "yellow"
|
|
268
|
+
ended = "grey50"
|
|
269
|
+
project = "cyan"
|
|
270
|
+
location = "bright_blue"
|
|
271
|
+
muted = "grey50"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Extending
|
|
275
|
+
|
|
276
|
+
RiNG is not tied to a specific tool or terminal.
|
|
277
|
+
|
|
278
|
+
| Extension Point | Purpose | Built-ins |
|
|
279
|
+
|-----------------|---------|-----------|
|
|
280
|
+
| `SessionSource` | find sessions | Claude Code, Codex, hook registry |
|
|
281
|
+
| `Focuser` | jump to terminals | tmux, iTerm2, Terminal.app |
|
|
282
|
+
| `Notifier` | notify when sessions are waiting | terminal-notifier, osascript, notify-send |
|
|
283
|
+
|
|
284
|
+
Each backend is a small module under `ring/sources/`, `ring/focus/`, or `ring/notify/`, registered via `register_*()`.
|
|
285
|
+
|
|
286
|
+
## Platform & Privacy
|
|
287
|
+
|
|
288
|
+
- **Platform**: macOS / Linux. Windows is not supported.
|
|
289
|
+
- **Privacy**: entirely local. RiNG only reads local `~/.claude/` and `~/.codex/` data and writes
|
|
290
|
+
`~/.config/ring/`. No network, uploads, or telemetry.
|
|
291
|
+
|
|
292
|
+
## Name
|
|
293
|
+
|
|
294
|
+
The name is a triple pun:
|
|
295
|
+
|
|
296
|
+
1. It **rings** you when a session needs a response.
|
|
297
|
+
2. “RiNG” is the live house from *BanG Dream!*.
|
|
298
|
+
3. **R**ealtime **I**nstance **N**otification **G**rid describes what it is.
|
|
299
|
+
|
|
300
|
+
## Non-Goals
|
|
301
|
+
|
|
302
|
+
RiNG tracks session state. It is not a token or cost dashboard.
|
|
303
|
+
|
|
304
|
+
Claude Code JSONL token counts are currently unreliable enough to make cost accounting misleading,
|
|
305
|
+
so RiNG deliberately avoids that surface.
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT
|