derot 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.
- derot-0.1.0/LICENSE +21 -0
- derot-0.1.0/PKG-INFO +272 -0
- derot-0.1.0/README.md +241 -0
- derot-0.1.0/derot/__init__.py +3 -0
- derot-0.1.0/derot/__main__.py +5 -0
- derot-0.1.0/derot/cli.py +287 -0
- derot-0.1.0/derot/config.py +359 -0
- derot-0.1.0/derot/example_config.yaml +43 -0
- derot-0.1.0/derot/forms.py +713 -0
- derot-0.1.0/derot/hook.py +342 -0
- derot-0.1.0/derot/installer.py +335 -0
- derot-0.1.0/derot/log.py +65 -0
- derot-0.1.0/derot/notify.py +172 -0
- derot-0.1.0/derot/remote.py +174 -0
- derot-0.1.0/derot/sessions.py +1032 -0
- derot-0.1.0/derot/tui.py +978 -0
- derot-0.1.0/derot.egg-info/PKG-INFO +272 -0
- derot-0.1.0/derot.egg-info/SOURCES.txt +34 -0
- derot-0.1.0/derot.egg-info/dependency_links.txt +1 -0
- derot-0.1.0/derot.egg-info/entry_points.txt +2 -0
- derot-0.1.0/derot.egg-info/requires.txt +7 -0
- derot-0.1.0/derot.egg-info/top_level.txt +1 -0
- derot-0.1.0/pyproject.toml +54 -0
- derot-0.1.0/setup.cfg +4 -0
- derot-0.1.0/tests/test_bugfixes.py +357 -0
- derot-0.1.0/tests/test_bughunt_new.py +551 -0
- derot-0.1.0/tests/test_codex.py +270 -0
- derot-0.1.0/tests/test_config.py +74 -0
- derot-0.1.0/tests/test_forms.py +266 -0
- derot-0.1.0/tests/test_hook.py +78 -0
- derot-0.1.0/tests/test_log.py +96 -0
- derot-0.1.0/tests/test_preview.py +279 -0
- derot-0.1.0/tests/test_resume.py +163 -0
- derot-0.1.0/tests/test_sessions.py +199 -0
- derot-0.1.0/tests/test_setup.py +134 -0
- derot-0.1.0/tests/test_tui.py +214 -0
derot-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rootonchair
|
|
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.
|
derot-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: derot
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: One terminal console for every Claude Code and Codex session across projects, accounts and machines
|
|
5
|
+
Author: rootonchair
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/rootonchair/derot
|
|
8
|
+
Project-URL: Issues, https://github.com/rootonchair/derot/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/rootonchair/derot/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: claude,claude-code,codex,tmux,tui,terminal,ssh
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console :: Curses
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Software Development
|
|
20
|
+
Classifier: Topic :: Terminals
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: textual>=4.0
|
|
25
|
+
Requires-Dist: pyyaml>=6
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "test"
|
|
29
|
+
Requires-Dist: pyflakes; extra == "test"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# derot
|
|
33
|
+
|
|
34
|
+
[](https://github.com/rootonchair/derot/actions/workflows/tests.yml)
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
|
|
37
|
+
**Stop coding-agent sessions rotting in forgotten terminals.** derot is one terminal console
|
|
38
|
+
for every **Claude Code** and **Codex** session you run: across **projects**, **accounts** and
|
|
39
|
+
**machines** (this computer plus any machine you can SSH into), in one list.
|
|
40
|
+
See which sessions need you, watch the agent work, and type into any of them without leaving
|
|
41
|
+
the console.
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
**Every session at a glance.** Sessions that need you (a permission prompt or a question
|
|
48
|
+
with options) sort to the top, then finished ones, then the ones still working. The summary
|
|
49
|
+
bar counts them, and you get a desktop notification when a session needs you.
|
|
50
|
+
|
|
51
|
+
**Watch the agent work.** The right-hand panel shows the selected session's details and
|
|
52
|
+
its live screen, exactly as Claude Code or Codex draws it, for local and SSH sessions alike.
|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
**Type into any session from the console.** Press Enter or click the right panel and every
|
|
57
|
+
key goes straight to Claude: slash commands, `/model`, menus, autocomplete, Esc, paste. Press
|
|
58
|
+
`1`–`9` on the list to answer a prompt in one keystroke, or `f` for Claude's own full-screen
|
|
59
|
+
UI. `Ctrl-q` always brings you back.
|
|
60
|
+
|
|
61
|
+

|
|
62
|
+
|
|
63
|
+
**Pick up old conversations.** `R` lists a session's past conversations with their titles,
|
|
64
|
+
age and last prompt, and resumes the one you pick. `c` continues the session's own last
|
|
65
|
+
conversation.
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
**No YAML required.** Add sessions, machines and accounts from forms. The project folder
|
|
70
|
+
field lists matching folders as you type, on the chosen machine (over SSH for remote ones),
|
|
71
|
+
and the SSH target field lists hosts from your `~/.ssh/config` and `known_hosts`.
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
**Claude Code and Codex side by side.** Each account belongs to an agent, so Claude Code
|
|
78
|
+
and OpenAI Codex sessions share one list, with the same status, preview, typing and resume.
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
**Sessions outlive the console.** Every session runs in tmux, so it keeps going when you
|
|
83
|
+
quit derot, close the laptop lid or lose the SSH connection.
|
|
84
|
+
|
|
85
|
+
## How it works
|
|
86
|
+
|
|
87
|
+
- **tmux**: each session is a tmux session `cc-<name>` on a private tmux server
|
|
88
|
+
(`tmux -L derot`), so it survives detaching and never touches your own tmux setup.
|
|
89
|
+
- **SSH**: remote hosts are reached with plain `ssh` (shared ControlMaster connection, one
|
|
90
|
+
call per host per refresh). Nothing runs on the VM besides tmux, python3 and the agent.
|
|
91
|
+
- **Hooks**: `derot setup` installs a tiny stdlib-only script, `~/.derot/hook.py`, and
|
|
92
|
+
registers it as a Claude Code or Codex hook (both agents have the same hook events). It writes `~/.derot/state/<name>.json` on each event
|
|
93
|
+
(prompt submitted, tool use, permission prompt, stop), so status is accurate without screen
|
|
94
|
+
scraping.
|
|
95
|
+
- **Accounts**: each account is an agent's config folder, with its own login and settings:
|
|
96
|
+
a Claude Code folder passed via `CLAUDE_CONFIG_DIR`, or a Codex folder passed via
|
|
97
|
+
`CODEX_HOME`. For Codex, setup registers the same hook in that folder's `hooks.json`.
|
|
98
|
+
|
|
99
|
+
## Install
|
|
100
|
+
|
|
101
|
+
Requirements: Python 3.9+, [tmux](https://github.com/tmux/tmux), and
|
|
102
|
+
[Claude Code](https://docs.anthropic.com/en/docs/claude-code) and/or
|
|
103
|
+
[Codex](https://developers.openai.com/codex) on every machine you use.
|
|
104
|
+
Developed and used on macOS; the Linux code paths (tmux, `notify-send` notifications) are
|
|
105
|
+
covered by CI but haven't seen much real use yet.
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
pipx install git+https://github.com/rootonchair/derot # or: uv tool install git+https://github.com/rootonchair/derot
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
On macOS, `brew install tmux pipx` first. Each SSH machine needs `tmux`, `python3`, the
|
|
112
|
+
agent(s) you use there, and key-based SSH access (`ssh my-vm true` works without a password
|
|
113
|
+
prompt).
|
|
114
|
+
|
|
115
|
+
## Setup
|
|
116
|
+
|
|
117
|
+
1. Run `derot`. On first run it creates `~/.config/derot/config.yaml` (override with
|
|
118
|
+
`DEROT_CONFIG`) and opens the console.
|
|
119
|
+
2. Press `n` to add a session: pick a machine, a project folder (matching folders are listed
|
|
120
|
+
as you type) and a Claude account. Choose **+ add a machine (SSH)…** or **+ add an account…** in the dropdowns
|
|
121
|
+
to create those on the spot. Saving installs the status hooks for any new machine/account
|
|
122
|
+
automatically, and offers to log in to a new account right away.
|
|
123
|
+
3. Press `Enter` on a session to start it and type into it from the right panel; `Ctrl-q`
|
|
124
|
+
stops typing. `f` opens Claude's own full-screen UI instead.
|
|
125
|
+
|
|
126
|
+
No YAML editing needed. `e` edits the selected session, `d` removes it, `l` logs in to the
|
|
127
|
+
session's account (Claude Code opens so you can `/login`; for Codex it runs `codex login`). The config file is still plain YAML if you
|
|
128
|
+
prefer it (`E` opens it in `$EDITOR`); saving from the console rewrites it without comments
|
|
129
|
+
and keeps your original as `config.yaml.bak`.
|
|
130
|
+
|
|
131
|
+
A VM needs tmux, python3, Claude Code and/or Codex, and key-based SSH (`ssh my-vm true`
|
|
132
|
+
works without a password prompt). From the command line, the same setup is `derot login ACCOUNT [--host H]`
|
|
133
|
+
and `derot setup`.
|
|
134
|
+
|
|
135
|
+
<details><summary>Config file reference</summary>
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
hosts:
|
|
139
|
+
vm:
|
|
140
|
+
ssh: user@my-vm # anything `ssh` accepts, incl. ~/.ssh/config aliases
|
|
141
|
+
claude: claude # optional: command/full path for Claude Code there
|
|
142
|
+
codex: codex # optional: command/full path for Codex there
|
|
143
|
+
accounts:
|
|
144
|
+
personal: {config_dir: ~/.claude}
|
|
145
|
+
openai: {agent: codex, config_dir: ~/.codex} # agent: claude (default) or codex
|
|
146
|
+
work:
|
|
147
|
+
config_dir: ~/.claude-work
|
|
148
|
+
env: {ANTHROPIC_API_KEY: sk-ant-...} # optional
|
|
149
|
+
sessions:
|
|
150
|
+
- {name: shop-api, host: local, dir: ~/code/shop-api, account: work, note: payments refactor}
|
|
151
|
+
- {name: infra, host: vm, dir: ~/infra, account: work, args: "--model opus"}
|
|
152
|
+
notify: {on_waiting: true, on_done: true, sound: Glass}
|
|
153
|
+
refresh: 3
|
|
154
|
+
detach_key: C-q
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
</details>
|
|
158
|
+
|
|
159
|
+
## Keys
|
|
160
|
+
|
|
161
|
+
The console has the session list on the left. On the right are the selected session's
|
|
162
|
+
details and a **preview**. The preview shows the session's live screen, exactly as Claude draws
|
|
163
|
+
it (the same view you get when typing live or attaching); stopped sessions show their last
|
|
164
|
+
conversation instead. Press Enter (or click the right panel) to type straight into the
|
|
165
|
+
session from the preview (slash commands, `/model` and menus all work), or `1`–`9` to pick a
|
|
166
|
+
prompt option. Go full screen (`f`) only for longer work.
|
|
167
|
+
|
|
168
|
+
| Key | Action |
|
|
169
|
+
|---|---|
|
|
170
|
+
| `Enter` / click the right panel | Type into the selected session: every key (letters, `/`, arrows, Tab, Esc, Ctrl-C, paste) goes straight to Claude, and the preview shows Claude's own UI updating as you type, including slash-command menus, `/model`, autocomplete and pickers. Starts the session first if it's stopped. `Ctrl-q` stops typing. A click on a row only selects it |
|
|
171
|
+
| `f` | Full screen: Claude's own UI in this terminal (attach; starts it first if stopped). `Ctrl-q` comes back |
|
|
172
|
+
| `1`–`9` | When a session needs you: pick that numbered option in its prompt |
|
|
173
|
+
| `p` | Preview: switch between auto (screen while running, conversation once stopped), conversation (from Claude's transcript) and screen |
|
|
174
|
+
| `s` | Start fresh in the background and stay in derot (watch it in the preview, Enter to type) |
|
|
175
|
+
| `c` | Continue this session's last conversation (falls back to the folder's newest, `claude --continue`), in the background like `s` |
|
|
176
|
+
| `R` | Resume: pick any past conversation of the session's folder and account (title, age, last prompt), then start it with `claude --resume` |
|
|
177
|
+
| `x` `x` | Stop (press twice within 3 s) |
|
|
178
|
+
| `n` | New session (form) |
|
|
179
|
+
| `e` | Edit the selected session (form) |
|
|
180
|
+
| `d` | Remove the selected session from derot |
|
|
181
|
+
| `l` | Log in to the selected session's account (`/login`) |
|
|
182
|
+
| `E` | Open the config file in `$VISUAL`/`$EDITOR`, reload on exit |
|
|
183
|
+
| `u` | Run setup (install hooks) |
|
|
184
|
+
| `r` | Refresh now |
|
|
185
|
+
| `q` | Quit (sessions keep running) |
|
|
186
|
+
|
|
187
|
+
Inside a session, `Ctrl-q` (configurable with `detach_key`) returns to derot. `Ctrl-b d`
|
|
188
|
+
always works too. Coming back from a finished session marks it as seen (done → idle).
|
|
189
|
+
|
|
190
|
+
## Command line
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
derot open the console (creates the config on first run)
|
|
194
|
+
derot init create the config file
|
|
195
|
+
derot setup [--remove] install / remove status hooks on every host+account
|
|
196
|
+
derot ls print a status table
|
|
197
|
+
derot start NAME [-c] [-r ID] [-d] start (-c continue last conversation, -r resume that
|
|
198
|
+
conversation, -d don't attach)
|
|
199
|
+
derot history NAME [-n N] list past conversations (ids for -r)
|
|
200
|
+
derot attach NAME attach, then mark seen
|
|
201
|
+
derot stop NAME
|
|
202
|
+
derot watch poll + notifications only, for when the console is closed
|
|
203
|
+
derot login ACCOUNT [--host H]
|
|
204
|
+
derot log [-f] [-n N] show the log, for tracing errors
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`derot watch` gives you desktop alerts without keeping the console open, e.g. in a spare
|
|
208
|
+
terminal tab or a login item.
|
|
209
|
+
|
|
210
|
+
## Troubleshooting
|
|
211
|
+
|
|
212
|
+
Start with the log: **`derot log`** shows the last lines of `~/.derot/derot.log`
|
|
213
|
+
(`derot log -f` follows it live). It records every action, every failure with the full error
|
|
214
|
+
output, and tracebacks for anything unexpected. Error toasts in the console are logged too, so
|
|
215
|
+
a message that disappeared can still be read there. For even more detail, run with
|
|
216
|
+
`DEROT_DEBUG=1 derot` to log every command derot runs (API keys are masked). Errors inside
|
|
217
|
+
the status hook itself go to `~/.derot/hook-errors.log` on that machine.
|
|
218
|
+
|
|
219
|
+
- **`claude` not found**: sessions run in your login shell, but if it still isn't found set
|
|
220
|
+
`claude:` to the full path for that host (`which claude` on that machine).
|
|
221
|
+
- **Session shows "needs you: Claude hasn't started yet"**: Claude is on a screen that comes
|
|
222
|
+
before the session, such as "trust this folder?" or a new account's login. Press Enter (or
|
|
223
|
+
click the right panel) and answer it. If nothing is there, press `u` to reinstall the hooks.
|
|
224
|
+
- **Codex session shows "needs you: Codex isn't running derot's hooks yet"**: Codex only
|
|
225
|
+
runs hooks you've approved. Press Enter on the session (or click the right panel), type
|
|
226
|
+
`/hooks`, and trust derot's hooks (`t`). It's once per account folder. A Codex session that
|
|
227
|
+
has started but hasn't had a prompt yet shows idle: Codex reports nothing before the first
|
|
228
|
+
prompt.
|
|
229
|
+
- **Codex session shows "needs you: Codex isn't logged in"**: a new Codex account folder
|
|
230
|
+
has no login yet. Press `l` (on an SSH machine it signs in with a one-time code), or press
|
|
231
|
+
Enter and answer Codex's sign-in screen. An account with `OPENAI_API_KEY` in its `env` logs
|
|
232
|
+
in with that key when a session starts (Codex ignores the variable on its own).
|
|
233
|
+
- **Session stuck on idle**: status hooks are missing for that account/host. Starting a
|
|
234
|
+
session sets them up; otherwise press `u` (or run `derot setup`).
|
|
235
|
+
- **Two accounts log each other out on the Mac**: Claude Code stores logins in the macOS
|
|
236
|
+
keychain, so two subscription logins can clash. Give one account an API key via its `env`
|
|
237
|
+
(`ANTHROPIC_API_KEY: ...`).
|
|
238
|
+
- **Detach key conflicts** with an app you use inside sessions: change `detach_key` (e.g.
|
|
239
|
+
`C-]`). `Ctrl-b d` always works.
|
|
240
|
+
- **Sessions started outside derot don't appear**: derot only tracks sessions it starts.
|
|
241
|
+
Add them with `n`, exit the old `claude`, then press `c` to continue the same conversation.
|
|
242
|
+
|
|
243
|
+
## Known issues
|
|
244
|
+
|
|
245
|
+
See [tracking/](tracking/README.md) for everything open. The main ones:
|
|
246
|
+
|
|
247
|
+
- Quitting waits silently for background work to finish (up to a minute while hooks are
|
|
248
|
+
being set up).
|
|
249
|
+
- After the console quits, a session stays at the preview's size if you attach with plain
|
|
250
|
+
tmux instead of derot.
|
|
251
|
+
- An SSH machine whose login shell is csh/tcsh isn't supported yet.
|
|
252
|
+
- Claude Code features that need a hook derot doesn't use (for example compaction) are
|
|
253
|
+
handled from Claude Code's documentation and haven't been seen live.
|
|
254
|
+
|
|
255
|
+
## Development
|
|
256
|
+
|
|
257
|
+
```sh
|
|
258
|
+
uv venv && uv pip install -e '.[test]'
|
|
259
|
+
.venv/bin/pytest # needs tmux; uses a fake `claude` and fake `ssh`, no VM needed
|
|
260
|
+
.venv/bin/pyflakes derot tests scripts
|
|
261
|
+
.venv/bin/python scripts/screenshots.py # regenerate docs/screenshots from demo data
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Releases are published to PyPI from GitHub Actions; see [RELEASING.md](RELEASING.md).
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
[MIT](LICENSE).
|
|
269
|
+
|
|
270
|
+
derot is an independent project. It is not affiliated with, endorsed by or sponsored by
|
|
271
|
+
Anthropic or OpenAI. Claude and Claude Code are trademarks of Anthropic; Codex and OpenAI are
|
|
272
|
+
trademarks of OpenAI.
|
derot-0.1.0/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# derot
|
|
2
|
+
|
|
3
|
+
[](https://github.com/rootonchair/derot/actions/workflows/tests.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
**Stop coding-agent sessions rotting in forgotten terminals.** derot is one terminal console
|
|
7
|
+
for every **Claude Code** and **Codex** session you run: across **projects**, **accounts** and
|
|
8
|
+
**machines** (this computer plus any machine you can SSH into), in one list.
|
|
9
|
+
See which sessions need you, watch the agent work, and type into any of them without leaving
|
|
10
|
+
the console.
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
**Every session at a glance.** Sessions that need you (a permission prompt or a question
|
|
17
|
+
with options) sort to the top, then finished ones, then the ones still working. The summary
|
|
18
|
+
bar counts them, and you get a desktop notification when a session needs you.
|
|
19
|
+
|
|
20
|
+
**Watch the agent work.** The right-hand panel shows the selected session's details and
|
|
21
|
+
its live screen, exactly as Claude Code or Codex draws it, for local and SSH sessions alike.
|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
**Type into any session from the console.** Press Enter or click the right panel and every
|
|
26
|
+
key goes straight to Claude: slash commands, `/model`, menus, autocomplete, Esc, paste. Press
|
|
27
|
+
`1`–`9` on the list to answer a prompt in one keystroke, or `f` for Claude's own full-screen
|
|
28
|
+
UI. `Ctrl-q` always brings you back.
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
**Pick up old conversations.** `R` lists a session's past conversations with their titles,
|
|
33
|
+
age and last prompt, and resumes the one you pick. `c` continues the session's own last
|
|
34
|
+
conversation.
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
**No YAML required.** Add sessions, machines and accounts from forms. The project folder
|
|
39
|
+
field lists matching folders as you type, on the chosen machine (over SSH for remote ones),
|
|
40
|
+
and the SSH target field lists hosts from your `~/.ssh/config` and `known_hosts`.
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
**Claude Code and Codex side by side.** Each account belongs to an agent, so Claude Code
|
|
47
|
+
and OpenAI Codex sessions share one list, with the same status, preview, typing and resume.
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
**Sessions outlive the console.** Every session runs in tmux, so it keeps going when you
|
|
52
|
+
quit derot, close the laptop lid or lose the SSH connection.
|
|
53
|
+
|
|
54
|
+
## How it works
|
|
55
|
+
|
|
56
|
+
- **tmux**: each session is a tmux session `cc-<name>` on a private tmux server
|
|
57
|
+
(`tmux -L derot`), so it survives detaching and never touches your own tmux setup.
|
|
58
|
+
- **SSH**: remote hosts are reached with plain `ssh` (shared ControlMaster connection, one
|
|
59
|
+
call per host per refresh). Nothing runs on the VM besides tmux, python3 and the agent.
|
|
60
|
+
- **Hooks**: `derot setup` installs a tiny stdlib-only script, `~/.derot/hook.py`, and
|
|
61
|
+
registers it as a Claude Code or Codex hook (both agents have the same hook events). It writes `~/.derot/state/<name>.json` on each event
|
|
62
|
+
(prompt submitted, tool use, permission prompt, stop), so status is accurate without screen
|
|
63
|
+
scraping.
|
|
64
|
+
- **Accounts**: each account is an agent's config folder, with its own login and settings:
|
|
65
|
+
a Claude Code folder passed via `CLAUDE_CONFIG_DIR`, or a Codex folder passed via
|
|
66
|
+
`CODEX_HOME`. For Codex, setup registers the same hook in that folder's `hooks.json`.
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
Requirements: Python 3.9+, [tmux](https://github.com/tmux/tmux), and
|
|
71
|
+
[Claude Code](https://docs.anthropic.com/en/docs/claude-code) and/or
|
|
72
|
+
[Codex](https://developers.openai.com/codex) on every machine you use.
|
|
73
|
+
Developed and used on macOS; the Linux code paths (tmux, `notify-send` notifications) are
|
|
74
|
+
covered by CI but haven't seen much real use yet.
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
pipx install git+https://github.com/rootonchair/derot # or: uv tool install git+https://github.com/rootonchair/derot
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
On macOS, `brew install tmux pipx` first. Each SSH machine needs `tmux`, `python3`, the
|
|
81
|
+
agent(s) you use there, and key-based SSH access (`ssh my-vm true` works without a password
|
|
82
|
+
prompt).
|
|
83
|
+
|
|
84
|
+
## Setup
|
|
85
|
+
|
|
86
|
+
1. Run `derot`. On first run it creates `~/.config/derot/config.yaml` (override with
|
|
87
|
+
`DEROT_CONFIG`) and opens the console.
|
|
88
|
+
2. Press `n` to add a session: pick a machine, a project folder (matching folders are listed
|
|
89
|
+
as you type) and a Claude account. Choose **+ add a machine (SSH)…** or **+ add an account…** in the dropdowns
|
|
90
|
+
to create those on the spot. Saving installs the status hooks for any new machine/account
|
|
91
|
+
automatically, and offers to log in to a new account right away.
|
|
92
|
+
3. Press `Enter` on a session to start it and type into it from the right panel; `Ctrl-q`
|
|
93
|
+
stops typing. `f` opens Claude's own full-screen UI instead.
|
|
94
|
+
|
|
95
|
+
No YAML editing needed. `e` edits the selected session, `d` removes it, `l` logs in to the
|
|
96
|
+
session's account (Claude Code opens so you can `/login`; for Codex it runs `codex login`). The config file is still plain YAML if you
|
|
97
|
+
prefer it (`E` opens it in `$EDITOR`); saving from the console rewrites it without comments
|
|
98
|
+
and keeps your original as `config.yaml.bak`.
|
|
99
|
+
|
|
100
|
+
A VM needs tmux, python3, Claude Code and/or Codex, and key-based SSH (`ssh my-vm true`
|
|
101
|
+
works without a password prompt). From the command line, the same setup is `derot login ACCOUNT [--host H]`
|
|
102
|
+
and `derot setup`.
|
|
103
|
+
|
|
104
|
+
<details><summary>Config file reference</summary>
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
hosts:
|
|
108
|
+
vm:
|
|
109
|
+
ssh: user@my-vm # anything `ssh` accepts, incl. ~/.ssh/config aliases
|
|
110
|
+
claude: claude # optional: command/full path for Claude Code there
|
|
111
|
+
codex: codex # optional: command/full path for Codex there
|
|
112
|
+
accounts:
|
|
113
|
+
personal: {config_dir: ~/.claude}
|
|
114
|
+
openai: {agent: codex, config_dir: ~/.codex} # agent: claude (default) or codex
|
|
115
|
+
work:
|
|
116
|
+
config_dir: ~/.claude-work
|
|
117
|
+
env: {ANTHROPIC_API_KEY: sk-ant-...} # optional
|
|
118
|
+
sessions:
|
|
119
|
+
- {name: shop-api, host: local, dir: ~/code/shop-api, account: work, note: payments refactor}
|
|
120
|
+
- {name: infra, host: vm, dir: ~/infra, account: work, args: "--model opus"}
|
|
121
|
+
notify: {on_waiting: true, on_done: true, sound: Glass}
|
|
122
|
+
refresh: 3
|
|
123
|
+
detach_key: C-q
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
</details>
|
|
127
|
+
|
|
128
|
+
## Keys
|
|
129
|
+
|
|
130
|
+
The console has the session list on the left. On the right are the selected session's
|
|
131
|
+
details and a **preview**. The preview shows the session's live screen, exactly as Claude draws
|
|
132
|
+
it (the same view you get when typing live or attaching); stopped sessions show their last
|
|
133
|
+
conversation instead. Press Enter (or click the right panel) to type straight into the
|
|
134
|
+
session from the preview (slash commands, `/model` and menus all work), or `1`–`9` to pick a
|
|
135
|
+
prompt option. Go full screen (`f`) only for longer work.
|
|
136
|
+
|
|
137
|
+
| Key | Action |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `Enter` / click the right panel | Type into the selected session: every key (letters, `/`, arrows, Tab, Esc, Ctrl-C, paste) goes straight to Claude, and the preview shows Claude's own UI updating as you type, including slash-command menus, `/model`, autocomplete and pickers. Starts the session first if it's stopped. `Ctrl-q` stops typing. A click on a row only selects it |
|
|
140
|
+
| `f` | Full screen: Claude's own UI in this terminal (attach; starts it first if stopped). `Ctrl-q` comes back |
|
|
141
|
+
| `1`–`9` | When a session needs you: pick that numbered option in its prompt |
|
|
142
|
+
| `p` | Preview: switch between auto (screen while running, conversation once stopped), conversation (from Claude's transcript) and screen |
|
|
143
|
+
| `s` | Start fresh in the background and stay in derot (watch it in the preview, Enter to type) |
|
|
144
|
+
| `c` | Continue this session's last conversation (falls back to the folder's newest, `claude --continue`), in the background like `s` |
|
|
145
|
+
| `R` | Resume: pick any past conversation of the session's folder and account (title, age, last prompt), then start it with `claude --resume` |
|
|
146
|
+
| `x` `x` | Stop (press twice within 3 s) |
|
|
147
|
+
| `n` | New session (form) |
|
|
148
|
+
| `e` | Edit the selected session (form) |
|
|
149
|
+
| `d` | Remove the selected session from derot |
|
|
150
|
+
| `l` | Log in to the selected session's account (`/login`) |
|
|
151
|
+
| `E` | Open the config file in `$VISUAL`/`$EDITOR`, reload on exit |
|
|
152
|
+
| `u` | Run setup (install hooks) |
|
|
153
|
+
| `r` | Refresh now |
|
|
154
|
+
| `q` | Quit (sessions keep running) |
|
|
155
|
+
|
|
156
|
+
Inside a session, `Ctrl-q` (configurable with `detach_key`) returns to derot. `Ctrl-b d`
|
|
157
|
+
always works too. Coming back from a finished session marks it as seen (done → idle).
|
|
158
|
+
|
|
159
|
+
## Command line
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
derot open the console (creates the config on first run)
|
|
163
|
+
derot init create the config file
|
|
164
|
+
derot setup [--remove] install / remove status hooks on every host+account
|
|
165
|
+
derot ls print a status table
|
|
166
|
+
derot start NAME [-c] [-r ID] [-d] start (-c continue last conversation, -r resume that
|
|
167
|
+
conversation, -d don't attach)
|
|
168
|
+
derot history NAME [-n N] list past conversations (ids for -r)
|
|
169
|
+
derot attach NAME attach, then mark seen
|
|
170
|
+
derot stop NAME
|
|
171
|
+
derot watch poll + notifications only, for when the console is closed
|
|
172
|
+
derot login ACCOUNT [--host H]
|
|
173
|
+
derot log [-f] [-n N] show the log, for tracing errors
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`derot watch` gives you desktop alerts without keeping the console open, e.g. in a spare
|
|
177
|
+
terminal tab or a login item.
|
|
178
|
+
|
|
179
|
+
## Troubleshooting
|
|
180
|
+
|
|
181
|
+
Start with the log: **`derot log`** shows the last lines of `~/.derot/derot.log`
|
|
182
|
+
(`derot log -f` follows it live). It records every action, every failure with the full error
|
|
183
|
+
output, and tracebacks for anything unexpected. Error toasts in the console are logged too, so
|
|
184
|
+
a message that disappeared can still be read there. For even more detail, run with
|
|
185
|
+
`DEROT_DEBUG=1 derot` to log every command derot runs (API keys are masked). Errors inside
|
|
186
|
+
the status hook itself go to `~/.derot/hook-errors.log` on that machine.
|
|
187
|
+
|
|
188
|
+
- **`claude` not found**: sessions run in your login shell, but if it still isn't found set
|
|
189
|
+
`claude:` to the full path for that host (`which claude` on that machine).
|
|
190
|
+
- **Session shows "needs you: Claude hasn't started yet"**: Claude is on a screen that comes
|
|
191
|
+
before the session, such as "trust this folder?" or a new account's login. Press Enter (or
|
|
192
|
+
click the right panel) and answer it. If nothing is there, press `u` to reinstall the hooks.
|
|
193
|
+
- **Codex session shows "needs you: Codex isn't running derot's hooks yet"**: Codex only
|
|
194
|
+
runs hooks you've approved. Press Enter on the session (or click the right panel), type
|
|
195
|
+
`/hooks`, and trust derot's hooks (`t`). It's once per account folder. A Codex session that
|
|
196
|
+
has started but hasn't had a prompt yet shows idle: Codex reports nothing before the first
|
|
197
|
+
prompt.
|
|
198
|
+
- **Codex session shows "needs you: Codex isn't logged in"**: a new Codex account folder
|
|
199
|
+
has no login yet. Press `l` (on an SSH machine it signs in with a one-time code), or press
|
|
200
|
+
Enter and answer Codex's sign-in screen. An account with `OPENAI_API_KEY` in its `env` logs
|
|
201
|
+
in with that key when a session starts (Codex ignores the variable on its own).
|
|
202
|
+
- **Session stuck on idle**: status hooks are missing for that account/host. Starting a
|
|
203
|
+
session sets them up; otherwise press `u` (or run `derot setup`).
|
|
204
|
+
- **Two accounts log each other out on the Mac**: Claude Code stores logins in the macOS
|
|
205
|
+
keychain, so two subscription logins can clash. Give one account an API key via its `env`
|
|
206
|
+
(`ANTHROPIC_API_KEY: ...`).
|
|
207
|
+
- **Detach key conflicts** with an app you use inside sessions: change `detach_key` (e.g.
|
|
208
|
+
`C-]`). `Ctrl-b d` always works.
|
|
209
|
+
- **Sessions started outside derot don't appear**: derot only tracks sessions it starts.
|
|
210
|
+
Add them with `n`, exit the old `claude`, then press `c` to continue the same conversation.
|
|
211
|
+
|
|
212
|
+
## Known issues
|
|
213
|
+
|
|
214
|
+
See [tracking/](tracking/README.md) for everything open. The main ones:
|
|
215
|
+
|
|
216
|
+
- Quitting waits silently for background work to finish (up to a minute while hooks are
|
|
217
|
+
being set up).
|
|
218
|
+
- After the console quits, a session stays at the preview's size if you attach with plain
|
|
219
|
+
tmux instead of derot.
|
|
220
|
+
- An SSH machine whose login shell is csh/tcsh isn't supported yet.
|
|
221
|
+
- Claude Code features that need a hook derot doesn't use (for example compaction) are
|
|
222
|
+
handled from Claude Code's documentation and haven't been seen live.
|
|
223
|
+
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
```sh
|
|
227
|
+
uv venv && uv pip install -e '.[test]'
|
|
228
|
+
.venv/bin/pytest # needs tmux; uses a fake `claude` and fake `ssh`, no VM needed
|
|
229
|
+
.venv/bin/pyflakes derot tests scripts
|
|
230
|
+
.venv/bin/python scripts/screenshots.py # regenerate docs/screenshots from demo data
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Releases are published to PyPI from GitHub Actions; see [RELEASING.md](RELEASING.md).
|
|
234
|
+
|
|
235
|
+
## License
|
|
236
|
+
|
|
237
|
+
[MIT](LICENSE).
|
|
238
|
+
|
|
239
|
+
derot is an independent project. It is not affiliated with, endorsed by or sponsored by
|
|
240
|
+
Anthropic or OpenAI. Claude and Claude Code are trademarks of Anthropic; Codex and OpenAI are
|
|
241
|
+
trademarks of OpenAI.
|