@ictechgy/lterm 1.0.23 → 1.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.ko.md +130 -32
  2. package/README.md +125 -35
  3. package/package.json +5 -5
package/README.ko.md CHANGED
@@ -4,14 +4,14 @@
4
4
 
5
5
  ## TL;DR
6
6
 
7
- - **무엇** — tmux처럼 터미널 세션을 백그라운드에서 오래 유지하는 데몬이지만, 기능 범위를 더 작게 좁힌 도구. AI 에이전트 도구를 위한 tmux 호환 명령 계층을 제공하며, 세션을 이름이나 pane id로 detach·reattach할 수 있습니다.
7
+ - **무엇** — tmux처럼 터미널 세션을 백그라운드에서 오래 유지하는 데몬이지만, 기능 범위를 더 작게 좁힌 도구입니다. AI 에이전트 도구를 위한 tmux 호환 명령 계층을 제공하며, 세션을 이름이나 pane id로 detach·reattach할 수 있습니다.
8
8
  - **대상** — Claude Code, Codex CLI, OpenCode, GitHub Copilot CLI, Cursor Agent, Antigravity/`agy`, Kiro, Jules, Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI, `oh-my-codex` / `oh-my-claude` 같은 terminal-first coding agent를 쓰는 사용자와, 이를 `cmux` 안에서 실행하는 사용자.
9
9
  - **사용법** — `lterm start`로 만들고 `lterm resume`으로 (재)접속합니다. shim이 적용된 agent 실행에는 `lterm agent <profile>` / `lterm claude` / `lterm codex` / `lterm opencode` / `lterm agy` / `lterm kiro` / `lterm gemini` 같은 내장 단축 명령을 사용할 수 있습니다. tmux가 켜진 세션 안에서는 `tmux` 명령이 `lterm tmux-compat`으로 해석됩니다.
10
- - **상태** — 1.0 명령/출력 호환성 경계를 문서화한 alpha MVP입니다. 같은 OS 사용자 안에서 쓰는 편의용 데몬이며, **샌드박스, escape-sequence sanitizer, 완전한 tmux 대체품 모두 아닙니다.**
10
+ - **상태** — 문서화된 1.0 명령/출력 호환성 경계를 따르는 1.x CLI입니다. 같은 OS 사용자 안에서 쓰는 편의용 데몬이며, **샌드박스도, escape-sequence sanitizer도, 완전한 tmux 대체품도 아닙니다.**
11
11
 
12
12
  ---
13
13
 
14
- `lterm`은 tmux 전체를 대체하려는 도구가 아닙니다. 오래 실행되는 PTY 세션을 유지하고, 클라이언트가 자유롭게 detach/reattach할 수 있게 하며, 터미널 escape sequence는 그대로 통과시키고, terminal-first agent 도구가 자주 사용하는 tmux 명령 일부를 호환 shim으로 제공합니다.
14
+ `lterm`은 tmux 전체를 대체하려는 도구가 아닙니다. 오래 실행되는 PTY 세션을 유지하고, 클라이언트가 자유롭게 detach/reattach할 수 있게 하며, 터미널 escape sequence는 그대로 통과시키고, terminal-first agent 도구가 자주 사용하는 tmux 명령 subset을 호환 shim으로 제공합니다.
15
15
 
16
16
  > **보안 모델:** `lterm`은 같은 OS 사용자 안에서 쓰는 편의용 데몬이며 샌드박스가 아닙니다. 다른 사용자의 Unix socket 접근은 거부하고 런타임 디렉터리는 소유자 전용 권한으로 만들지만, 같은 OS 사용자 권한으로 실행되는 프로세스는 세션을 제어할 수 있다고 보아야 합니다.
17
17
  > 전체 trust boundary와 audit policy는 [SECURITY.md](SECURITY.md)를 참고하세요.
@@ -43,10 +43,10 @@ agent가 보통 필요로 하는 더 작은 기능 범위에 집중합니다.
43
43
  다음 세 가지 요구를 충족하는 것이 목표입니다.
44
44
 
45
45
  1. **tmux와 비슷한 세션 지속성과 원격 접속** — 세션은 백그라운드 데몬에서 실행되며, 이름이나 pane id로 attach/detach할 수 있습니다. 원격 호스트에 `lterm`이 설치되어 있다면 `lterm ssh`로 접속할 수 있습니다.
46
- 2. **cmux 호환성** — cmux 안에서 실행할 때는 OSC 알림을 그대로 통과시키고 `lterm notify`를 제공하며, tmux shim은 가능한 경우 worker pane을 cmux native split으로 엽니다.
46
+ 2. **cmux 호환성** — cmux 안에서 실행할 때는 OSC 알림을 그대로 통과시키고 `lterm notify`를 제공하며, 가능한 경우 tmux-shim worker pane을 cmux native split으로 엽니다.
47
47
  3. **AI 도구 지원** — `lterm agent <profile>`, `lterm claude`, `lterm codex`, `lterm opencode`, `lterm copilot`, `lterm cursor-agent`, `lterm agy`, `lterm jules`, `lterm kiro`, `lterm aider`, `lterm goose`, `lterm amp`, `lterm crush`, `lterm kimi`, `lterm qwen`, `lterm gemini`, `lterm omx`, `lterm omc`, `lterm install-shim`은 tmux를 전제하는 agent 도구를 위해 tmux를 흉내 내는 `tmux` 명령과 `TMUX` / `TMUX_PANE` 환경 변수를 제공합니다.
48
48
 
49
- cmux 호환 동작은 cmux가 문서화한 기능을 따릅니다. cmux는 `cmux notify`와 OSC 777 / OSC 99 알림, workspace/split을 위한 Unix socket·CLI API, 그리고 tmux 명령을 cmux native pane으로 매핑하는 tmux shim 모델을 문서화하고 있습니다.
49
+ cmux 호환 동작은 cmux가 문서화한 기능을 따릅니다. cmux는 `cmux notify`와 OSC 777 / OSC 99 알림, workspace/split을 위한 Unix socket·CLI API, 그리고 tmux-shim 명령을 cmux native pane으로 매핑하는 모델을 문서화하고 있습니다.
50
50
 
51
51
  ## 설치
52
52
 
@@ -65,9 +65,11 @@ npm install -g @ictechgy/lterm
65
65
  Homebrew와 npm 모두 `PATH`에 `lterm` 명령을 설치합니다. `lterm --version`으로 확인하세요.
66
66
 
67
67
  수동 설치가 번거롭다면 [`docs/agent-install.ko.md`](docs/agent-install.ko.md)의
68
- 프롬프트를 Claude Code, Codex CLI, OpenCode, GitHub Copilot CLI, Cursor Agent, Antigravity/`agy`, Kiro, Jules, Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI 같은 terminal coding agent에
69
- 붙여 넣으세요. Agent가 platform을 감지하고, `lterm`을 설치하고, smoke test로
70
- 검증하며, shell startup file을 바꿔야 때는 먼저 diff를 보여주도록 안내합니다.
68
+ 프롬프트를 Claude Code, Codex CLI, OpenCode, GitHub Copilot CLI, Cursor Agent,
69
+ Antigravity/`agy`, Kiro, Jules, Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI
70
+ 같은 terminal coding agent에 붙여 넣으세요. Agent가 platform을 감지하고,
71
+ `lterm`을 설치하고, smoke test로 검증하며, shell startup file을 바꿔야 할
72
+ 때는 먼저 diff를 보여주도록 안내합니다.
71
73
 
72
74
  1.0 명령/출력 안정성 경계는 [public contract](docs/public-contract.md)와
73
75
  machine-readable [contract manifest](docs/contract-manifest.json)를 참고하세요.
@@ -76,7 +78,7 @@ GitHub에서 Cargo로 설치할 때는 release tag를 고정하세요. 아래
76
78
  README 릴리스 기준이며, 더 최신 tag가 있는지는 Releases 페이지에서 확인하세요:
77
79
 
78
80
  ```bash
79
- cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.23
81
+ cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.25
80
82
  ```
81
83
 
82
84
  저장소를 클론한 뒤 직접 빌드하려면 Rust 1.85 이상이 필요합니다.
@@ -107,6 +109,8 @@ lterm install-ai-statusline
107
109
 
108
110
  ## 빠른 시작
109
111
 
112
+ ![lterm quick demo](docs/assets/lterm-demo.svg)
113
+
110
114
  **세션을 만들고 바로 attach:**
111
115
 
112
116
  ```bash
@@ -134,12 +138,14 @@ lterm -a api
134
138
  | tmux 호환을 켠 상태로 명령 실행 | `lterm run -- codex exec "요약해줘"` | 없음 (`--no-tmux`로 opt out) |
135
139
  | 세션 열기 또는 생성 | `lterm open main` | `attach-or-new` |
136
140
  | 기존 세션 재개 | `lterm resume api` | `attach`, `a`, `-a` |
141
+ | 마지막으로 선택한 세션에 재접속 | `lterm reconnect --mobile` | 없음 |
137
142
  | 모바일에서 agent 출력 확인 | `LTERM_MOBILE=1 lterm resume codex-lterm` | transcript 강제는 `--mobile`, 기존 raw attach 강제는 `--raw` |
138
143
  | 세션 목록 보기 | `lterm sessions` | `list`, `ls` |
139
144
  | 프로세스 트리 확인 | `lterm processes api --json --orphans` | `ps` |
140
145
  | 세션 이름 변경 | `lterm rename api api-renamed` | 없음 |
141
146
  | 세션 status theme 설정 | `lterm status-theme api green` | `theme` |
142
147
  | 정제된 scrollback 읽기 | `lterm logs api --start=-80 --end=-1` | `capture` |
148
+ | scrollback의 최근 URL 추출 | `lterm urls api --last` | 없음 |
143
149
  | 디버깅용 raw PTY 출력 기록 | `lterm trace api --duration 5s --output trace.jsonl` | `record` |
144
150
  | 신뢰하는 raw PTY trace 재생 | `lterm trace-replay trace.jsonl` | `replay-trace` |
145
151
  | 정제된 scrollback 위에 입력 컴포저 열기 | `lterm compose api` | `mobile` |
@@ -149,6 +155,7 @@ lterm -a api
149
155
  | 세션 종료 | `lterm close api` | `kill` |
150
156
  | 데몬과 shim 상태 진단 | `lterm doctor --json` | `status` |
151
157
  | redacted 로컬 진단 bundle 수집 | `lterm diagnose --bundle` | 없음 |
158
+ | redacted 로컬 진단 inspect | `lterm inspect --json` | 없음 |
152
159
  | 로컬 설정 단계 미리 보기 | `lterm init --shell zsh` | 없음 |
153
160
  | 지원되는 AI CLI statusline badge 설치 | `lterm install-ai-statusline` | 없음 |
154
161
  | shell completion 설치 | `lterm install-completions --shell zsh` | 없음 |
@@ -163,9 +170,9 @@ lterm -a api
163
170
  | profile 기반 agent 세션 실행 | `lterm agent claude -- --help` | sibling shortcuts: `lterm claude`, `lterm codex`, `lterm opencode`, `lterm copilot`, `lterm cursor-agent`, `lterm agy`, `lterm jules`, `lterm kiro`, `lterm aider`, `lterm goose`, `lterm amp`, `lterm crush`, `lterm kimi`, `lterm qwen`, `lterm gemini`, `lterm omx`, `lterm omc` |
164
171
  | 사용 가능한 agent profile 확인 | `lterm agents --json` | 실행 시점의 `PATH` 사용 가능 여부 확인 |
165
172
  | `tmux` 호환 shim 설치 | `lterm install-shim` | `lterm tmux-compat`으로 전달하는 shim 생성 |
166
- | tmux 호환 shell export 출력 | `eval "$(lterm env)"` (`lterm env --shell fish \| source` for fish) | shim dir을 `$PATH` 앞에 추가하는 신뢰된 `export` 행 출력 |
173
+ | tmux 호환 shell export 출력 | `eval "$(lterm env)"` (fish는 `lterm env --shell fish \| source`) | shim dir을 `$PATH` 앞에 추가하는 신뢰된 `export` 행 출력 |
167
174
  | shell completion 설치 | `lterm install-completions --shell bash\|zsh\|fish` | 사용자 로컬 completion 파일을 쓰고 필요한 활성화 hint를 출력하며 daemon은 시작하지 않음 |
168
- | AI CLI statusline badge 설치 | `lterm install-ai-statusline` | 지원 statusline 통합을 설치함; Claude/OMC에는 `lt:<session>:<pane>` command wrapper를 넣고, Codex는 아직 `LTERM_SESSION` / `LTERM_PANE`용 custom item을 받지 않으므로 unsupported로 보고하고 config는 건드리지 않음 |
175
+ | AI CLI statusline badge 설치 | `lterm install-ai-statusline` | 지원 statusline 통합을 설치함; Claude/OMC에는 `lt:<session>:<pane>` command wrapper를 넣고, Codex는 아직 `LTERM_SESSION` / `LTERM_PANE`용 custom item을 받지 않으므로 skipped로 보고하고 config는 건드리지 않음 |
169
176
  | shell completion 생성 | `lterm completions bash\|zsh\|fish` | completion script만 출력하며 session을 조회하거나 daemon을 시작하지 않음 |
170
177
  | cmux-friendly 알림 보내기 | `lterm notify --title 'Done' --body 'Tests passed'` | OSC 777 fallback은 터미널 제어 문자를 제거하고 Unicode text는 보존 |
171
178
  | 원격 호스트에 attach | `lterm ssh user@host main` | 신뢰할 수 있는 host에서만 사용; host-key 확인은 SSH가 처리하고 remote PTY bytes는 정제 없이 전달 |
@@ -190,13 +197,13 @@ escape 처리가 여기에 포함됩니다. 직접 `ssh`하듯 신뢰할 수 있
190
197
 
191
198
  호환 이름은 flag 형태로 표시된 경우(`-a`)를 제외하면 모두 subcommand입니다. `-a`는 기존 shortcut 형태라 `lterm -a <target>`처럼 사용해야 합니다.
192
199
 
193
- 이 표는 사람과 agent가 직접 쓰는 제품 CLI 명령 모음입니다. `lterm tmux-compat ...`는 이미 tmux 명령을 사용하는 스크립트를 위한 별도 shim namespace이며, 모든 제품 명령에 tmux 호환 이름이 있는 것은 아닙니다. 런타임에 지원되는 shim subset은 `lterm tmux-compat list-commands`로 확인하세요.
200
+ 이 표는 사람과 agent가 직접 쓰는 제품 CLI 명령 모음입니다. `lterm tmux-compat ...`는 이미 tmux 명령을 사용하는 스크립트를 위한 별도 shim namespace이며, 모든 제품 명령에 tmux 호환 이름이 있는 것은 아닙니다. 런타임에 지원되는 shim subset은 `lterm tmux-compat list-commands`로 확인하고, compatibility version banner만 필요할 때는 `lterm tmux-compat --version`을 사용하세요.
194
201
 
195
202
  `lterm sessions`는 기본적으로 하위 pane을 숨기고, 기존 첫 5개 tab-separated 열(`name`, `pane`, `alive`, `cwd`, `command`)을 유지한 뒤 attach 상태(`attached` / `detached`)와 parent pane(`-` 또는 pane id)을 뒤에 붙입니다. JSON 출력에는 agent profile로 띄운 세션에 한해 `agent_name` metadata가 추가되고, 일반 세션에는 이 field가 생략됩니다. 호환 이름인 `lterm list`와 `lterm ls`도 같은 text 출력 형식을 유지합니다. attach된 클라이언트는 아래쪽 한 줄에 status bar를 표시하고, PTY는 그 줄을 제외한 영역으로 resize됩니다. 예전처럼 전체 터미널을 raw 모드로 강제하려면 `lterm resume --raw --no-status api`(호환 이름: `lterm attach --raw --no-status api`)를 쓰거나 `LTERM_ATTACH_MODE=raw`를 설정하세요. status line만 충돌하는 클라이언트라면 `LTERM_NO_STATUS=1`(또는 같은 의미의 `LTERM_STATUS=0`)만 설정해도 됩니다.
196
203
 
197
204
  row status 표시 여부는 attach mode와는 별개입니다. `--attach-mode=auto`는 계속 raw attach와 mobile transcript 중 어느 transport를 쓸지만 결정합니다. raw attach 경로에서 일반 세션은 기본적으로 row status를 유지하고, 내장 agent launcher와 이미 agent 세션으로 식별된 세션에 다시 붙는 `resume` / `open`은 full-height row-off 화면을 기본값으로 사용합니다.
198
205
 
199
- 직접 agent launcher를 실행할 때는 terminal이 지원하면 attach 직전에 compact terminal-title cue(`lt:<session>:<pane> · <agent>`)와 one-shot `[lterm] <session> <pane> · <agent> (status row hidden for agent TUI; use --status to show it)` banner를 표시합니다. title cue와 banner를 모두 끄려면 `LTERM_AGENT_CUE=0`, terminal-title cue는 유지하고 inline banner만 끄려면 `LTERM_AGENT_BANNER=0`을 설정하세요. row-on shell 세션 안에서 알려진 agent command가 나중에 child process로 실행된 것으로 보이면 lterm은 best-effort로 row를 suspend하고 PTY를 전체 높이로 복원했다가 agent가 끝나면 row를 되돌릴 수 있습니다. process 감지가 애매하면 안전하게 row를 유지합니다. 전역 `LTERM_NO_STATUS=1` / `LTERM_STATUS=0` kill-switch는 CLI status 요청보다 우선합니다.
206
+ 직접 agent launcher를 실행할 때는 terminal이 지원하면 attach 직전에 compact terminal-title cue(`lt:<session>:<pane> · <agent>`)와 one-shot `[lterm] <session> <pane> · <agent> (status row hidden for agent TUI; use --status to show it)` banner를 표시합니다. row-off로 attach된 동안에는 idle 구간 이후 title cue만 주기적으로 다시 표시하므로, Codex 같은 TUI가 자체 title을 덮어써도 lterm 식별 정보는 유지됩니다. title cue와 banner를 모두 끄려면 `LTERM_AGENT_CUE=0`, terminal-title cue는 유지하고 inline banner만 끄려면 `LTERM_AGENT_BANNER=0`을 설정하세요. row-on shell 세션 안에서 알려진 agent command가 나중에 child process로 실행된 것으로 보이면 lterm은 best-effort로 row를 suspend하고 PTY를 전체 높이로 복원했다가 agent가 끝나면 row를 되돌릴 수 있습니다. process 감지가 애매하면 안전하게 row를 유지합니다. 전역 `LTERM_NO_STATUS=1` / `LTERM_STATUS=0` kill-switch는 CLI status 요청보다 우선합니다.
200
207
 
201
208
  모든 lterm 세션의 child process에는 `LTERM_SESSION`과 `LTERM_PANE`도 export됩니다. `[lterm:api:%0]` 같은 shell prompt badge를 선호한다면 이 변수를 prompt에 추가하세요. `lterm init --shell zsh|bash|fish`는 shim/completion/AI statusline 단계와 함께 이 reminder를 출력합니다. 자체 statusline/HUD를 제공하는 AI CLI는 lterm의 host-side bottom row에 의존하지 말고 같은 변수를 읽어 그 statusline 안에 badge를 표시하는 편이 좋습니다. 그래야 full-screen agent TUI와 모바일 SSH renderer를 덜 방해합니다. `lterm install-ai-statusline`을 실행하면 지원 통합을 설치합니다. 현재는 Claude/OMC HUD wrapper를 만들어 `lt:<session>:<pane>`를 앞에 붙이고, `~/.claude/settings.json`은 변경 전 backup합니다. Codex는 `~/.codex/config.toml`을 건드리지 않고 skipped로 보고합니다. 현재 Codex status_line item은 built-in만 가능하고, `thread-id`는 Codex 내부 식별자라 lterm 세션 식별자로 쓰기에 부적절하기 때문입니다.
202
209
 
@@ -206,7 +213,17 @@ row status 표시 여부는 attach mode와는 별개입니다. `--attach-mode=au
206
213
 
207
214
  `lterm status-theme <target> <theme>`(alias: `lterm theme`)은 PTY를 재시작하지 않고 세션별 status bar theme을 저장합니다. pane id를 지정하면 해당 pane이 속한 세션에 적용됩니다. `default`, `clear`, `none`을 쓰면 세션 override를 지우고 attach하는 client의 기본값으로 돌아갑니다. 이미 attach된 client는 detach 후 다시 attach할 때 새 색을 반영합니다. 새 세션은 `lterm start --status-theme green -n api -- npm run dev`(또는 alias `--status-color`)처럼 생성 시점에 같은 metadata를 저장할 수 있습니다.
208
215
 
209
- `lterm doctor`(호환 이름: `lterm status`)는 client/daemon version, protocol 호환성, runtime/data/socket/shim path, shim directory가 `PATH`에 있는지 등을 보고합니다. 이 명령은 daemon을 시작하지 않습니다. 현재 socket에서 호환 daemon이 응답하지 않으면 `daemon_reachable=no` / `false`로 표시됩니다. 일반 client 동작 중 접근 가능한 daemon이 다른 lterm 또는 protocol version을 보고하면 stderr에 경고를 출력하며, 보통 binary upgrade 뒤 예전 daemon이 살아 있는 상황을 뜻합니다.
216
+ `lterm doctor`(호환 이름: `lterm status`)는 client/daemon version, protocol 호환성, runtime/data/socket/shim path, shim directory가 `PATH`에 있는지, count와 boolean/null `tmux_compat` summary 등을 보고합니다. 현재 build는 `tmux_compat`를 출력하지만, stable schema는 binary upgrade 중 예전 doctor output도 validate되도록 additive/optional로 유지합니다. 이 명령은 daemon을 시작하지 않습니다. 현재 socket에서 호환 daemon이 응답하지 않으면 `daemon_reachable=no` / `false`로 표시됩니다. 일반 client 동작 중 접근 가능한 daemon이 다른 lterm 또는 protocol version을 보고하면 stderr에 경고를 출력하며, 보통 binary upgrade 뒤 예전 daemon이 살아 있는 상황을 뜻합니다.
217
+
218
+ `lterm diagnose --bundle`은 issue 보고와 agent handoff를 위한 local-only JSON
219
+ 진단 bundle을 출력합니다. `doctor` 데이터와 redact된 환경 변수 presence flag를
220
+ 포함하고, 기존 daemon에 접근 가능한 경우에 한해 세션 metadata와 process row를
221
+ 함께 담습니다. 이 명령은 daemon을 시작하지 않으며, 기본적으로 raw PTY bytes나
222
+ scrollback은 포함하지 않습니다. inspect-style JSON entrypoint가 필요한 도구는
223
+ 같은 redacted bundle을 출력하는 `lterm inspect --json`을 사용할 수 있으며,
224
+ `--json`이 필수입니다.
225
+
226
+ Opt-in local footprint 측정은 `python3 scripts/footprint_benchmark.py --quick --json target/footprint-baseline.json --markdown target/footprint-baseline.md`로 실행합니다. 격리된 lterm-vs-tmux 측정 방법과 해석 caveat는 [`docs/footprint-benchmark.md`](docs/footprint-benchmark.md)를 참고하세요.
210
227
 
211
228
  `lterm logs <target>`은 `--start` / `-S`와 `--end` / `-E` line offset을 받습니다. 0 이상의 값은 absolute scrollback line index이고, 음수 값은 현재 scrollback line count에서 뒤로 셉니다. `--end`는 inclusive라 `lterm logs api -S0 -E0`은 첫 번째 줄만 capture합니다. Capture 출력은 계속 정제된 text입니다. 즉 terminal control은 제거하고 한국어, CJK, emoji 같은 UTF-8 text는 보존합니다. attach된 PTY stream은 raw 그대로 유지됩니다.
212
229
 
@@ -267,7 +284,7 @@ child 애플리케이션이 `CSI u` enhancement sequence로 Kitty keyboard proto
267
284
 
268
285
  **세션 확인 및 제어:**
269
286
 
270
- `--children`는 관리되는 자식 pane을 포함하고, `--all`은 기본 목록에서 숨겨지는 세션까지 포함합니다.
287
+ `--children`는 관리되는 하위 pane을 포함하고, `--all`은 기본 목록에서 숨겨지는 세션까지 포함합니다.
271
288
 
272
289
  ```bash
273
290
  lterm sessions
@@ -275,19 +292,82 @@ lterm sessions --children
275
292
  lterm sessions --all
276
293
  lterm processes api --orphans
277
294
  lterm logs api --start=-80 --end=-1
295
+ lterm urls api --last
296
+ lterm search api 'build failed'
278
297
  lterm compose api
279
298
  LTERM_MOBILE=1 lterm resume codex-lterm
299
+ lterm reconnect --mobile
280
300
  lterm resume --raw codex-lterm
281
301
  lterm wait api --contains READY --timeout 30s --json
282
302
  lterm watch api --exit --notify
283
303
  lterm input api 'echo hello' --enter
284
304
  ```
285
305
 
286
- 위의 일반 alias는 tmux 용어를 몰라도 agent terminal을 일상적으로 다룰 수 있게 해 주는 명령 집합입니다. `sessions`는 영속 작업을 나열하고, `processes`는 child process tree를 확인하고, `logs`는 정제된 scrollback을 읽고, `compose`는 정제된 scrollback과 하단 고정 prompt로 텍스트를 commit할 수 있게 하며, 모바일 transcript attach는 긴 agent 출력을 휴대폰의 기본 scrollback으로 읽을 수 있게 해 줍니다. `wait` / `watch`는 marker 또는 종료 조건을 script와 agent가 관측할 수 있게 하고, `input`은 대상 PTY에 텍스트를 씁니다. `lterm mobile`은 `lterm compose`의 visible alias이고, 별개의 attach flag인 `--mobile`은 normal-screen transcript attach 경로를 선택합니다. 호환 이름 `list` / `ls`, `ps`, `capture`, `send`는 스크립트와 기존 사용 습관에서도 계속 사용할 수 있습니다.
306
+ 위의 일반 alias는 tmux 용어를 몰라도 agent terminal을 일상적으로 다룰 수 있게 해 주는 명령 집합입니다. `sessions`는 영속 작업을 나열하고, `processes`는 child process tree를 확인하고, `logs`는 정제된 scrollback을 읽고, `compose`는 정제된 scrollback과 하단 고정 prompt로 텍스트를 commit할 수 있게 하며, 모바일 transcript attach는 긴 agent 출력을 휴대폰의 기본 scrollback으로 읽을 수 있게 해 줍니다. `reconnect`는 SSH 재접속 뒤 마지막으로 선택했던 로컬 lterm 세션을 다시 엽니다. `wait` / `watch`는 marker 또는 종료 조건을 script와 agent가 관측할 수 있게 하고, `input`은 대상 PTY에 텍스트를 씁니다. `lterm mobile`은 `lterm compose`의 visible alias이고, 별개의 attach flag인 `--mobile`은 normal-screen transcript attach 경로를 선택합니다. 호환 이름 `list` / `ls`, `ps`, `capture`, `send`는 스크립트와 기존 사용 습관에서도 계속 사용할 수 있습니다.
307
+
308
+ `lterm reconnect [fallback]`는 마지막으로 선택한 세션을 가리키는 비공개
309
+ 최소 pointer(`session_id`, pane id, 사용자가 붙인 session name, timestamp)만
310
+ 저장하고, 다음 실행 때 그 pointer를 사용합니다. pointer가 없거나 손상됐거나
311
+ 오래되어 더 이상 맞지 않으면 `fallback`(기본값: `main`)으로 돌아가며,
312
+ 동작은 `lterm open`과 같은 attach-or-create 방식입니다.
313
+
314
+ 세션 이름에는 secret을 넣지 마세요. `reconnect`도 raw attach가 가능하므로,
315
+ 휴대폰 SSH client에서 정제된 normal-screen transcript를 원하면 `--mobile`을
316
+ 함께 사용하세요. 모바일 SSH 로그인용 optional snippet은
317
+ `lterm init --mobile-reconnect --shell zsh`(`bash`, `fish`, `posix`도 가능)로
318
+ 미리 볼 수 있고, `--shell`을 생략하면 `$SHELL`에서 감지합니다. snippet은
319
+ 자동 설치되지 않습니다. 검토한 뒤 직접 복사하고, 되돌릴 때는 복사한 block을
320
+ 삭제하거나 `LTERM_RECONNECT_DISABLE=1`로 건너뛰세요.
321
+
322
+ `lterm urls <target>`는 raw attach PTY stream을 건드리지 않고, 마지막
323
+ 120줄의 정제된 scrollback에서 `http://`와 `https://` link를 추출합니다.
324
+ 기본 출력은 link마다 한 줄씩 `N<TAB>URL`입니다. 최신 유효 URL만 보려면
325
+ `--last`, JSON 배열이 필요하면 `--json`, 검색 범위를 바꾸려면 `--tail N`을
326
+ 사용하세요. text mode에서 link가 없으면 성공 종료하며 아무것도 출력하지 않고,
327
+ JSON mode에서는 `[]`를 출력합니다. URL 추출은 unique ASCII URL token 256개로
328
+ 제한되며, 4096 byte를 넘는 raw candidate는 자르지 않고 건너뜁니다.
329
+
330
+ mobile transcript mode에서는 `/links` 또는 `/urls`를 입력하면 같은 번호 목록을
331
+ PTY로 보내지 않고 로컬에서 보여 줍니다. Termius 계열 모바일 SSH client에서
332
+ Claude/OAuth login URL을 복사할 때 유용하며, Claude 전용 모바일
333
+ 제어에는 Claude Code Remote Control flow가 URL 복사 왕복을 줄여 줄 수도
334
+ 있습니다. 추출된 link는 신뢰할 수 없는 terminal output으로 취급하세요. 악성
335
+ 프로그램이 피싱 URL을 출력할 수 있고, OAuth/magic-login/device-code link는
336
+ 짧게 살아 있는 secret을 포함할 수 있습니다. 예상한 link만 열고, 공유 로그나
337
+ 채팅에 붙여 넣지 말며, `--last`는 최신 link가 원하는 link임을 알 때만
338
+ 사용하세요.
287
339
 
288
- 자동화와 테스트에는 `lterm compose api --once --message 'hello'`를 사용하면 한 번의 정제된 capture/send 사이클을 실행합니다. `logs`와 같은 session-or-pane target 모델에서 마지막 `--tail` 정제 라인(기본값: 80)을 capture한 뒤, 기본으로 Enter(`\r`)를 붙여 `lterm input --enter`와 맞추며, `--no-enter`를 추가하면 message byte만 정확히 보냅니다. `compose` / `mobile`은 attach client가 아니며 attached-client 수나 PTY geometry를 바꾸지 않습니다.
289
- Interactive compose 화면은 `--refresh`(기본값: 500ms), 로컬 입력, 터미널 resize 이벤트마다 갱신됩니다. Enter 누르면 현재 입력 buffer를 commit하고(빈 buffer도 commit됨), 위 one-shot 규칙처럼 기본으로 `\r`을 덧붙입니다. Ctrl-C, Ctrl-D, Esc는 PTY로 전달하지 않고 로컬 composer를 종료합니다.
290
- `lterm compose api --transcript`를 사용하면 모바일 auto attach가 쓰는 것과 같은 normal-screen transcript UI를 직접 열 수 있습니다. alternate-screen composer 없이 정제된 scrollback과 간단한 line input만 쓰고 싶을 때 적합합니다. 출력만 보고 싶으면 `--read-only`를 추가하세요.
340
+ `lterm search <target> QUERY`는 raw attach PTY stream을 건드리지 않고,
341
+ 마지막 120줄의 정제된 scrollback에서 대소문자를 구분하는 literal match
342
+ 찾습니다. 기본 출력은 1부터 시작하는 번호를 붙인 `N<TAB>LINE`입니다. `--json`은
343
+ 같은 정제된 match를 JSON 배열로 출력하고, `--tail N`은 검색 범위를
344
+ 바꿉니다. text mode에서 match가 없으면 성공 종료하며 아무것도 출력하지 않고,
345
+ 빈 `QUERY`는 거부합니다. mobile transcript mode에서는 `/grep QUERY`를 입력해
346
+ active transcript tail window의 match를 PTY로 보내지 않고 로컬에서 볼 수
347
+ 있습니다. query 없는 `/grep`은 `Usage: /grep QUERY`를 출력하고, match가 없으면
348
+ `No matches found in current transcript.`를 출력합니다.
349
+
350
+ 자동화와 테스트에서 `lterm compose api --once --message 'hello'`는 정제된
351
+ capture/send cycle을 한 번 수행합니다. `logs`와 같은 session-or-pane target
352
+ 모델로 마지막 `--tail`줄(기본값: 80)의 정제된 output을 캡처한 뒤, 기본적으로
353
+ Enter(`\r`)를 덧붙여 `lterm input --enter`와 같은 방식으로 보냅니다. 정확한
354
+ message byte만 보내려면 `--no-enter`를 추가하세요. `compose` / `mobile`은 attach
355
+ client가 아니며 attached-client 수나 PTY geometry를 바꾸지 않습니다.
356
+
357
+ interactive compose에서는 `--refresh`(기본값: 500ms), local input, resize event에
358
+ 맞춰 view를 갱신합니다. Enter는 현재 input buffer를 commit하며, 빈 buffer도
359
+ commit 대상입니다. 기본적으로 `\r`을 덧붙입니다. Ctrl-C, Ctrl-D, Esc는 PTY로
360
+ 전달하지 않고 local composer를 종료합니다.
361
+
362
+ `lterm compose api --transcript`는 mobile auto attach와 같은 normal-screen
363
+ transcript UI를 엽니다. alternate-screen composer 없이 정제된 scrollback과
364
+ 간단한 line input만 쓰고 싶을 때 사용하고, 출력만 보려면 `--read-only`를
365
+ 추가하세요. transcript-local command는 `/refresh`, `/raw`, `/links` / `/urls`,
366
+ `/grep QUERY`, `/exit` / `/quit`입니다. `/links`, `/urls`, `/grep`은 로컬에서만
367
+ 처리되고 PTY로 전달되지 않습니다. link가 없으면 `No URLs found in current
368
+ transcript.`를 출력하고, query 없는 `/grep`은 `Usage: /grep QUERY`, match가
369
+ 없으면 `No matches found in current transcript.`를 출력합니다. 알 수 없는 줄은
370
+ PTY로 전송됩니다.
291
371
 
292
372
  **세션 종료:**
293
373
 
@@ -297,17 +377,17 @@ lterm close api
297
377
 
298
378
  `kill`은 `close`의 visible compatibility alias입니다. 두 이름 모두 같은 session/pane 종료 경로를 사용합니다.
299
379
 
300
- **daemon 명시 실행 (고급):**
380
+ **데몬 명시 실행 (고급):**
301
381
 
302
382
  ```bash
303
- # 일반 client 명령은 필요할 때 daemon을 시작합니다. supervisor/debugging 용도로 직접 실행하세요.
383
+ # 일반 client 명령은 필요할 때 데몬을 시작합니다. supervisor/debugging 용도로 직접 실행하세요.
304
384
  lterm daemon
305
385
  ```
306
386
 
307
- **daemon과daemon이 소유한 모든 세션 종료:**
387
+ **데몬과데몬이 소유한 모든 세션 종료:**
308
388
 
309
389
  ```bash
310
- # 단일 세션 close가 아니라 daemon-wide 종료입니다.
390
+ # 단일 세션 close가 아니라 데몬 전체 종료입니다.
311
391
  lterm shutdown
312
392
  ```
313
393
 
@@ -402,6 +482,7 @@ lterm omx --madmax --xhigh
402
482
 
403
483
  ```bash
404
484
  lterm omc team
485
+ # 여기서 테스트한 OMC 빌드는 --xhigh를 거부합니다.
405
486
  # 설치된 `omc --help`에 --xhigh가 보이지 않는다면 --xhigh 없이 --madmax만 사용하세요.
406
487
  lterm omc --madmax
407
488
  ```
@@ -416,7 +497,7 @@ lterm run -- codex exec "저장소를 요약해줘"
416
497
 
417
498
  이 세션 안에서는 `tmux`가 `lterm tmux-compat` shim으로 해석됩니다. 이 shim은 호환 계층이지 모든 `lterm` 제품 명령의 두 번째 철자가 아닙니다. 현재 shim은 AI orchestration 스크립트가 자주 사용하는 다음 명령 subset을 구현합니다.
418
499
 
419
- - **세션** — `new-session`, `attach-session`, `has-session`, `list-sessions`, `rename-session`, `kill-session`
500
+ - **세션** — `new-session`, `new-window`, `attach-session`, `has-session`, `list-sessions`, `rename-session`, `kill-session`
420
501
  - **조회** — `list-windows`, `list-clients`, `list-commands`, `show-options`, `show-window-options`
421
502
  - **Pane** — `split-window`, `list-panes`, `display-message`, `capture-pane`, `send-keys`, `kill-pane`, `resize-pane`
422
503
  - **Buffer / popup** — `display-popup`, `wait-for`, `load-buffer`, `save-buffer`, `paste-buffer`
@@ -425,19 +506,26 @@ lterm run -- codex exec "저장소를 요약해줘"
425
506
  호환성 참고: lterm은 각 root session을 하나의 pseudo-window로 모델링합니다
426
507
  (`window_index=0`, `window_panes=1`). lterm은 client별 process/TTY metadata를
427
508
  노출하지 않기 때문에 `client_pid`와 `client_tty`는 빈 문자열로 확장됩니다.
509
+ `#{history_size}`는 현재 `0`으로 확장됩니다. lterm이 tmux식 pane history 길이를
510
+ 아직 노출하지 않더라도 tmux format 소비자가 numeric 값을 받도록 하기 위한
511
+ 명시적인 호환 동작입니다. tmux `-f` filter는 조용히 무시하지 않고 의도적으로
512
+ 거부합니다.
428
513
  `set-hook`은 OMX `client-resized[...]` handler처럼 agent runtime이 쓰는 hook
429
514
  등록/해제 형태를 받아들이지만, lterm이 tmux hook dispatcher를 실행하지는 않습니다.
430
515
  Detached `split-window -d -t <target>`은 같은 daemon socket 안에서 기존 live lterm
431
516
  target이면 현재 pane이 아니어도 허용합니다. 이는 tmux의 cross-pane helper launch
432
517
  동작을 맞추기 위한 것이며, daemon은 요청 처리 전에 같은 OS 사용자 peer credential을
433
518
  검증합니다. detached helper는 target pane 안에 붙지 않고 별도 lterm session으로
434
- 생성됩니다.
519
+ 생성됩니다. `split-window -b -h`와 `split-window -b -v`는 visible cmux split을
520
+ 만들 때 각각 cmux `left`, `up` placement로 매핑됩니다. Detached `new-window -d` /
521
+ `neww -d`는 의도적으로 partial 지원입니다. standalone lterm helper session을
522
+ 만들고, tmux 스타일 `-P`/`-F` target 출력을 지원하며, attached-window mode는
523
+ 현재 pane을 조용히 바꾸는 대신 거부합니다.
435
524
  `lterm tmux-compat list-commands --verbose`는 `command`, alias, support tier,
436
525
  usage를 tab-separated로 출력하고, `--json`은 machine-readable row를 출력합니다.
437
526
  Support tier는 lterm compatibility boundary 안에서 `full`, `partial`, `noop`
438
527
  중 하나입니다. `LTERM_DEBUG_TMUX=1`을 설정하면 지원하지 않는 tmux command가
439
528
  shim에 도달했을 때 opt-in stderr diagnostic row를 출력합니다.
440
- tmux `-f` filter는 조용히 무시하지 않고 의도적으로 거부합니다.
441
529
 
442
530
  Status bar redraw는 보수적으로 allowlist된 terminal client(예: xterm/iTerm2/WezTerm
443
531
  identity)에서만 xterm SGR stack control을 사용해 실행 중인 TUI의
@@ -447,15 +535,19 @@ foreground/background color state를 빼앗지 않도록 합니다.
447
535
  Kitty, Alacritty, Ghostty, Termius, generic `TERM=xterm-*` 값은 SGR-stack 동작이
448
536
  검증될 때까지 opt-in 경로로 둡니다.
449
537
 
538
+ lterm이 session identity를 cmux understatus pill로 미러링할 때는 `cmux set-status --help`를
539
+ 비파괴적으로 probe합니다. `--label`을 advertise하는 build에는 label 있는 status row를
540
+ 보내고, 구버전 cmux에는 지원하지 않는 flag를 생략해 계속 동작하게 합니다.
541
+
450
542
  ## cmux 동작
451
543
 
452
544
  `lterm tmux-compat split-window`가 cmux 환경(`CMUX_WORKSPACE_ID`, `CMUX_SURFACE_ID`, 또는 cmux socket)을 감지하면 다음 순서로 동작합니다.
453
545
 
454
546
  1. worker 명령을 위한 새 `lterm` PTY 세션을 시작합니다.
455
- 2. cmux에 native split 생성을 요청합니다 (`cmux new-split right/down`).
547
+ 2. cmux에 native split 생성을 요청합니다 (`cmux new-split right/down`, tmux backward split은 `left/up`).
456
548
  3. 생성된 split에는 호환 명령인 `lterm attach <pane>`을 보냅니다. 안전한 absolute executable이 `LTERM_BIN`으로 지정되어 있으면 그 값을 사용하고, 아니면 현재 executable로 fallback합니다. 이 호환 명령 덕분에 `resume`을 모르는 구버전 build에서도 cmux pane이 계속 동작합니다.
457
549
 
458
- 이렇게 하면 실제 pane은 cmux가 그리고, scrollback capture `send-keys` 호환은 `lterm`이 유지합니다.
550
+ 이렇게 하면 실제 pane은 cmux가 그리고, scrollback capture, `send-keys` 호환, cmux 버전별 status-label fallback은 `lterm`이 유지합니다.
459
551
 
460
552
  **알림:**
461
553
 
@@ -481,9 +573,14 @@ lterm ssh user@host main
481
573
  lterm ssh devbox main -- -p 2222 -i ~/.ssh/id_ed25519
482
574
  ```
483
575
 
576
+ 일반 모바일 SSH로 호스트에 로그인한 뒤에는 `lterm reconnect --mobile`을 실행해
577
+ 그 호스트에서 마지막으로 선택했던 lterm 세션을 다시 열 수 있습니다. `lterm ssh`
578
+ 자체는 구버전 원격 설치와의 호환성을 위해 기존 `attach-or-new` wire command를
579
+ 그대로 유지합니다.
580
+
484
581
  ## 구조
485
582
 
486
- - **Daemon** — 사용자별 Unix socket 하나를 `$XDG_RUNTIME_DIR` 아래에 만들고, 없으면 `/tmp` 아래 소유자 전용 fallback 경로를 사용합니다.
583
+ - **데몬** — 사용자별 Unix socket 하나를 `$XDG_RUNTIME_DIR` 아래에 만들고, 없으면 `/tmp` 아래 소유자 전용 fallback 경로를 사용합니다.
487
584
  - **PTY 세션** — `portable-pty`로 실행하며 ring-buffer scrollback을 유지합니다.
488
585
  - **Attach protocol** — CLI가 Unix socket으로 JSON을 보낸 뒤, 선택적으로 로컬 상태 바를 위해 아래쪽 한 줄을 예약하고 PTY byte stream을 전달합니다.
489
586
  - **tmux shim** — `tmux`라는 작은 shell script가 명령을 `lterm tmux-compat`으로 넘깁니다.
@@ -497,7 +594,7 @@ lterm ssh devbox main -- -p 2222 -i ~/.ssh/id_ed25519
497
594
 
498
595
  **터미널 출력은 그대로 전달됩니다.** `lterm resume`(호환 이름: `lterm attach`)은 full-screen 터미널 프로그램과 cmux/OSC 알림이 정상 동작하도록 PTY byte를 그대로 통과시킵니다. 로컬 상태 바는 클라이언트 쪽 표시 요소일 뿐이며, 완전한 raw 모드 터미널이 필요하면 `--no-status`를 사용하세요. nested agent row suspension은 host-side geometry/status 관리일 뿐 attach된 PTY byte를 정제하거나 다시 쓰지 않습니다. 신뢰할 수 없는 child 프로그램은 tmux/screen에서와 마찬가지로 attach된 터미널에 escape sequence를 출력할 수 있습니다. **`lterm`을 escape-sequence sanitizer나 sandbox로 사용하지 마세요.**
499
596
 
500
- **Capture 출력은 표시/로깅 전에 terminal control sequence를 제거합니다.** `lterm logs`(호환 이름: `lterm capture`), `lterm compose`(alias: `lterm mobile`), `tmux capture-pane`은 captured scrollback 출력할 raw 또는 UTF-8 encoded C1 control을 포함한 터미널 제어 시퀀스를 제거합니다. 정상 UTF-8 text인 한국어, CJK, emoji는 보존합니다. 그래도 scrollback text는 신뢰할 수 없는 프로그램 출력일 수 있으므로 사람이나 agent에게 넘기기 전에 확인하세요. `compose`는 attach가 아닌 view에서 기존 input/send 경로로 텍스트를 commit하며, raw attached PTY stream을 변환하지 않습니다.
597
+ **Capture report 출력은 표시/로깅 전에 terminal control sequence를 제거합니다.** `lterm logs`(호환 이름: `lterm capture`), `lterm compose`(alias: `lterm mobile`), `lterm search`, `lterm urls`, 진단 출력, `tmux capture-pane`은 scrollback에서 나온 text를 출력하기 전에 raw 또는 UTF-8 encoded C1 control을 포함한 터미널 제어 시퀀스를 제거합니다. 정상 UTF-8 text인 한국어, CJK, emoji는 보존합니다. 그래도 scrollback text는 신뢰할 수 없는 프로그램 출력일 수 있으므로 사람이나 agent에게 넘기기 전에 확인하세요. `compose`는 attach가 아닌 view에서 기존 input/send 경로로 텍스트를 commit하며, raw attach PTY stream을 변환하지 않습니다.
501
598
 
502
599
  **프로세스 가시성.** `lterm processes [session]`(호환 이름: `lterm ps [session]`)은 process-group id와 함께 각 세션 child 아래의 process tree를 보여 줍니다. `--orphans`를 추가하면 기록된 session root의 descendant가 아니지만 같은 process group에 남아 있는 row도 함께 보여 주므로, Codex/OMX/MCP subprocess가 누적되어 메모리 누수처럼 커지기 전에 확인할 수 있습니다. 시스템 `ps`는 절대 경로로 호출하며, 형식이 잘못된 process row는 추측하지 않고 건너뜁니다.
503
600
 
@@ -518,7 +615,7 @@ override로 인정합니다. 유효하지 않은 값은 무시하고 현재 exec
518
615
 
519
616
  - 세션 지속성은 데몬과 호스트가 동작 중일 때만 유지됩니다. 재부팅 후 프로세스 상태 복원은 아직 구현하지 않았습니다.
520
617
  - cmux 밖에서 `split-window`는 추가 managed PTY 세션을 만들지만, 터미널 안에 tiled UI를 직접 그리지는 않습니다.
521
- - 이 프로젝트는 완전한 tmux server가 아니라 호환 subset만 제공합니다. 고급 tmux format/option을 사용하는 스크립트는 shim 명령 추가가 필요할 수 있습니다.
618
+ - 이 프로젝트는 완전한 tmux server가 아니라 호환 subset만 제공합니다. 고급 tmux format, hook, layout, option을 사용하는 스크립트는 shim 명령 추가가 필요할 수 있습니다.
522
619
  - cmux pane capture는 cmux scrollback API가 아니라 `lterm` 세션을 통해 처리합니다.
523
620
  - 데몬은 로컬 클라이언트를 OS peer credential과 소유자 전용 socket 경로로 인증합니다. 세션별 ACL은 아직 없습니다.
524
621
  - 세션 종료는 verified process-group signaling을 사용하므로 `shell → OMX → Codex → MCP` 같은 child tree는 가능한 한 함께 정리됩니다. 의도적으로 다른 session/process group으로 detach한 프로세스는 `lterm close` / `lterm kill` 이후에도 살아 있을 수 있으니, `lterm processes` / `lterm ps`나 OS process 도구로 확인하세요.
@@ -527,8 +624,9 @@ override로 인정합니다. 유효하지 않은 값은 무시하고 현재 exec
527
624
 
528
625
  ```bash
529
626
  cargo fmt
627
+ cargo clippy --all-targets -- -D warnings
530
628
  cargo test
531
- cargo build --locked
629
+ cargo build --release --locked
532
630
  ```
533
631
 
534
632
  시스템 패키지 매니저로 설치한 Rust toolchain이 Cargo 시작 전에 실패한다면
package/README.md CHANGED
@@ -4,14 +4,14 @@
4
4
 
5
5
  ## TL;DR
6
6
 
7
- - **What** — A persistent terminal session daemon (like tmux, but smaller) with a tmux-compatible command layer for AI agent tooling. Detach and reattach by name or pane id.
7
+ - **What** — A persistent terminal session daemon (like tmux, but smaller) with a tmux-compatible command layer for AI-agent tooling. Detach and reattach by name or pane id.
8
8
  - **Who it's for** — Terminal-first coding agents such as Claude Code, Codex CLI, OpenCode, GitHub Copilot CLI, Cursor Agent, Antigravity/`agy`, Kiro, Jules, Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI, `oh-my-codex` / `oh-my-claude`, and users running them inside `cmux`.
9
- - **How** — `lterm start` to create, `lterm resume` to (re)connect, and `lterm agent <profile>` / `lterm claude` / `lterm codex` / `lterm opencode` / `lterm agy` / `lterm kiro` / `lterm gemini` as examples of built-in shortcuts for shimmed agent runs. Inside a tmux-enabled session, the `tmux` command resolves to `lterm tmux-compat`.
10
- - **Status** — alpha MVP with a documented 1.0 command/output compatibility boundary. It is a same-user convenience daemon — **not** a sandbox, an escape-sequence sanitizer, or a full tmux replacement.
9
+ - **How** — Use `lterm start` to create a session, `lterm resume` to reconnect, and `lterm agent <profile>` / `lterm claude` / `lterm codex` / `lterm opencode` / `lterm agy` / `lterm kiro` / `lterm gemini` for built-in shimmed agent launchers. Inside a tmux-enabled session, the `tmux` command resolves to `lterm tmux-compat`.
10
+ - **Status** — 1.x CLI with a documented 1.0 command/output compatibility boundary. It is a same-user convenience daemon — **not** a sandbox, an escape-sequence sanitizer, or a full tmux replacement.
11
11
 
12
12
  ---
13
13
 
14
- `lterm` is intentionally smaller than tmux. It keeps long-running PTY sessions alive, lets clients detach and reattach at will, forwards terminal escape sequences unchanged, and translates the subset of tmux commands commonly used by terminal-first agent tooling.
14
+ `lterm` is intentionally smaller than tmux. It keeps long-running PTY sessions alive, lets clients detach and reattach at will, forwards terminal escape sequences unchanged, and translates the tmux command subset commonly used by terminal-first agent tooling.
15
15
 
16
16
  > **Security model:** `lterm` is a same-user convenience daemon, not a sandbox. It rejects cross-user Unix-socket peers and uses owner-only runtime directories, but any process running as your OS user should be considered capable of controlling your sessions.
17
17
  > See [SECURITY.md](SECURITY.md) for the full trust-boundary and audit policy details.
@@ -43,11 +43,11 @@ need:
43
43
 
44
44
  The project addresses three constraints:
45
45
 
46
- 1. **tmux-like persistence and remote access** — sessions run inside a background daemon and can be attached or detached by name or pane id. Remote access is available through `lterm ssh`, provided `lterm` is installed on the remote host.
47
- 2. **cmux compatibility** — when running inside cmux, `lterm` preserves OSC notifications, exposes `lterm notify`, and the tmux shim opens worker panes as native cmux splits when possible.
48
- 3. **AI tooling support** — `lterm agent <profile>`, `lterm claude`, `lterm codex`, `lterm opencode`, `lterm copilot`, `lterm cursor-agent`, `lterm agy`, `lterm jules`, `lterm kiro`, `lterm aider`, `lterm goose`, `lterm amp`, `lterm crush`, `lterm kimi`, `lterm qwen`, `lterm gemini`, `lterm omx`, `lterm omc`, and `lterm install-shim` provide a fake `tmux` command and the `TMUX` / `TMUX_PANE` environment variables that agent tools expect.
46
+ 1. **tmux-like persistence and remote access** — sessions run inside a background daemon and can be attached or detached by name or pane id. Remote access is available through `lterm ssh` when `lterm` is installed on the remote host.
47
+ 2. **cmux compatibility** — inside cmux, `lterm` preserves OSC notifications, exposes `lterm notify`, and opens tmux-shim worker panes as native cmux splits when possible.
48
+ 3. **AI tooling support** — `lterm agent <profile>`, `lterm claude`, `lterm codex`, `lterm opencode`, `lterm copilot`, `lterm cursor-agent`, `lterm agy`, `lterm jules`, `lterm kiro`, `lterm aider`, `lterm goose`, `lterm amp`, `lterm crush`, `lterm kimi`, `lterm qwen`, `lterm gemini`, `lterm omx`, `lterm omc`, and `lterm install-shim` provide the fake `tmux` command plus the `TMUX` / `TMUX_PANE` environment variables that agent tools expect.
49
49
 
50
- cmux compatibility is grounded in cmux's documented behavior: notifications via `cmux notify` and OSC 777 / OSC 99, a Unix-socket/CLI API for workspaces and splits, and a tmux shim that maps tmux commands into native cmux panes.
50
+ cmux compatibility is grounded in cmux's documented behavior: notifications via `cmux notify` and OSC 777 / OSC 99, a Unix-socket/CLI API for workspaces and splits, and tmux-shim commands that map into native cmux panes.
51
51
 
52
52
  ## Install
53
53
 
@@ -67,9 +67,11 @@ Homebrew and npm both install the `lterm` command on your `PATH`; verify with `l
67
67
 
68
68
  Prefer an agent-assisted install? Copy the prompt in
69
69
  [`docs/agent-install.md`](docs/agent-install.md) into Claude Code, Codex CLI,
70
- OpenCode, GitHub Copilot CLI, Cursor Agent, Antigravity/`agy`, Kiro, Jules, Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI, or another terminal coding agent. It asks the agent to detect your
71
- platform, install `lterm`, verify it with a smoke test, and avoid modifying
72
- shell startup files without showing you the change.
70
+ OpenCode, GitHub Copilot CLI, Cursor Agent, Antigravity/`agy`, Kiro, Jules,
71
+ Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI, or another terminal coding
72
+ agent. It asks the agent to detect your platform, install `lterm`, verify it
73
+ with a smoke test, and avoid modifying shell startup files without showing you
74
+ the change.
73
75
 
74
76
  For the 1.0 command/output stability boundary, see the
75
77
  [public contract](docs/public-contract.md) and its machine-readable
@@ -79,7 +81,7 @@ With Cargo from GitHub, pin a release tag. The example below uses the current
79
81
  README release; check the Releases page for newer tags:
80
82
 
81
83
  ```bash
82
- cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.23
84
+ cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.25
83
85
  ```
84
86
 
85
87
  Building from this checkout requires Rust 1.85 or newer:
@@ -139,12 +141,14 @@ lterm -a api
139
141
  | Run a command with tmux compatibility enabled | `lterm run -- codex exec "summarize"` | None (`--no-tmux` opts out) |
140
142
  | Open or create a session | `lterm open main` | `attach-or-new` |
141
143
  | Resume an existing session | `lterm resume api` | `attach`, `a`, `-a` |
142
- | Review an agent session from mobile scrollback | `LTERM_MOBILE=1 lterm resume codex-lterm` | Force with `--mobile`; bypass with `--raw` |
144
+ | Reconnect to the last selected session | `lterm reconnect --mobile` | None |
145
+ | Review an agent session in mobile scrollback | `LTERM_MOBILE=1 lterm resume codex-lterm` | Force with `--mobile`; force raw with `--raw` |
143
146
  | List sessions | `lterm sessions` | `list`, `ls` |
144
147
  | Inspect process trees | `lterm processes api --json --orphans` | `ps` |
145
148
  | Rename a session | `lterm rename api api-renamed` | None |
146
149
  | Set a session status theme | `lterm status-theme api green` | `theme` |
147
150
  | Read sanitized scrollback | `lterm logs api --start=-80 --end=-1` | `capture` |
151
+ | Extract recent URLs from scrollback | `lterm urls api --last` | None |
148
152
  | Record raw PTY output for debugging | `lterm trace api --duration 5s --output trace.jsonl` | `record` |
149
153
  | Replay a trusted raw PTY trace | `lterm trace-replay trace.jsonl` | `replay-trace` |
150
154
  | Open a sanitized scrollback composer for input | `lterm compose api` | `mobile` |
@@ -154,6 +158,7 @@ lterm -a api
154
158
  | Stop a session | `lterm close api` | `kill` |
155
159
  | Diagnose daemon and shim state | `lterm doctor --json` | `status` |
156
160
  | Collect a redacted local diagnostic bundle | `lterm diagnose --bundle` | None |
161
+ | Inspect redacted local diagnostics | `lterm inspect --json` | None |
157
162
  | Preview local setup steps | `lterm init --shell zsh` | None |
158
163
  | Install supported AI CLI statusline badges | `lterm install-ai-statusline` | None |
159
164
  | Install shell completions | `lterm install-completions --shell zsh` | None |
@@ -170,7 +175,7 @@ Agent and shim utilities are also product CLI commands, not tmux aliases:
170
175
  | Install the `tmux` compatibility shim | `lterm install-shim` | Creates a shim that forwards to `lterm tmux-compat` |
171
176
  | Print shell exports for tmux compatibility | `eval "$(lterm env)"` (`lterm env --shell fish \| source` for fish) | Emits trusted shell setup that prepends the shim dir to `$PATH` |
172
177
  | Install shell completions | `lterm install-completions --shell bash\|zsh\|fish` | Writes a user-local completion file and prints any activation hint; it does not start the daemon |
173
- | Install AI CLI statusline badges | `lterm install-ai-statusline` | Installs supported statusline integrations; Claude/OMC gets an `lt:<session>:<pane>` command wrapper, while Codex is reported as unsupported because its TUI does not yet accept custom `LTERM_SESSION` / `LTERM_PANE` statusline items |
178
+ | Install AI CLI statusline badges | `lterm install-ai-statusline` | Installs supported statusline integrations; Claude/OMC gets an `lt:<session>:<pane>` command wrapper, while Codex is reported as skipped because its TUI does not yet accept custom `LTERM_SESSION` / `LTERM_PANE` statusline items |
174
179
  | Generate shell completions | `lterm completions bash\|zsh\|fish` | Prints completion scripts only; it does not inspect sessions or start the daemon |
175
180
  | Send a cmux-friendly notification | `lterm notify --title 'Done' --body 'Tests passed'` | OSC 777 fallback strips terminal controls while preserving Unicode text |
176
181
  | Attach to a remote host | `lterm ssh user@host main` | Use trusted hosts; SSH handles host-key checks, and remote PTY bytes pass through without sanitization |
@@ -194,7 +199,7 @@ Unicode bidi, format, or zero-width characters inside trusted title/body text.
194
199
 
195
200
  Compatibility names are subcommands unless shown as a leading flag: `-a` is the legacy shortcut form and must be used as `lterm -a <target>`.
196
201
 
197
- This table is the product CLI surface for humans and agents. `lterm tmux-compat ...` is a separate shim namespace for scripts that already speak tmux; not every product command has a tmux-compatible spelling. Use `lterm tmux-compat list-commands` to inspect the supported shim subset at runtime.
202
+ This table is the product CLI surface for humans and agents. `lterm tmux-compat ...` is a separate shim namespace for scripts that already speak tmux; not every product command has a tmux-compatible spelling. Use `lterm tmux-compat list-commands` to inspect the supported shim subset at runtime, and `lterm tmux-compat --version` when you only need the compatibility version banner.
198
203
 
199
204
  `lterm sessions` hides child panes by default, preserves the original first five tab-separated columns (`name`, `pane`, `alive`, `cwd`, `command`), then appends attach state (`attached` / `detached`) and parent pane (`-` or a pane id). The JSON form also includes optional `agent_name` metadata for sessions launched through an agent profile; non-agent sessions omit that field. The compatibility names `lterm list` and `lterm ls` keep the same text output shape. Attached clients render a small status bar on the bottom row showing the current session and pane; the PTY is resized to the remaining rows. To force the older raw full-terminal resume, use `lterm resume --raw --no-status api` (or compatibility name `lterm attach --raw --no-status api`) or set `LTERM_ATTACH_MODE=raw`; add `LTERM_NO_STATUS=1` or `LTERM_STATUS=0` when only the status line conflicts with the client.
200
205
 
@@ -208,13 +213,16 @@ Every lterm session also exports `LTERM_SESSION` and `LTERM_PANE` inside the chi
208
213
 
209
214
  `lterm status-theme <target> <theme>` (alias: `lterm theme`) stores a per-session status bar theme without restarting the PTY; pane ids resolve to their session. Use `default`, `clear`, or `none` to remove the session override and return to the attaching client's default. Already-attached clients keep their current status color until they detach and reattach. New sessions can set the same metadata at creation time with `lterm start --status-theme green -n api -- npm run dev` (or alias `--status-color`).
210
215
 
211
- `lterm doctor` (compatibility name: `lterm status`) reports client/daemon versions, protocol compatibility, runtime/data/socket/shim paths, and whether the shim directory is on `PATH`. It does not start the daemon; `daemon_reachable=no` / `false` means no compatible daemon answered on the current socket. Normal client operations warn on stderr when a reachable daemon reports a different lterm or protocol version, which usually means an old daemon survived a binary upgrade.
216
+ `lterm doctor` (compatibility name: `lterm status`) reports client/daemon versions, protocol compatibility, runtime/data/socket/shim paths, whether the shim directory is on `PATH`, and a count plus boolean/null `tmux_compat` summary. Current builds emit `tmux_compat`, but the stable schema keeps it additive/optional so older doctor outputs still validate during mixed-version upgrades. It does not start the daemon; `daemon_reachable=no` / `false` means no compatible daemon answered on the current socket. Normal client operations warn on stderr when a reachable daemon reports a different lterm or protocol version, which usually means an old daemon survived a binary upgrade.
212
217
 
213
218
  `lterm diagnose --bundle` prints a local-only JSON diagnostic bundle for issues
214
219
  and agent handoffs. It includes `doctor` data, redacted environment presence
215
220
  flags, and — only when an existing daemon is reachable — session metadata plus
216
221
  process rows. It does not start the daemon and does not include raw PTY bytes or
217
- scrollback by default.
222
+ scrollback by default. `lterm inspect --json` prints the same redacted bundle for
223
+ tools that expect an inspect-style JSON entrypoint; it requires `--json`.
224
+
225
+ For opt-in local footprint measurements, run `python3 scripts/footprint_benchmark.py --quick --json target/footprint-baseline.json --markdown target/footprint-baseline.md`. See [`docs/footprint-benchmark.md`](docs/footprint-benchmark.md) for the isolated lterm-vs-tmux methodology and interpretation caveats.
218
226
 
219
227
  `lterm logs <target>` accepts `--start` / `-S` and `--end` / `-E` line offsets. Non-negative values are absolute scrollback line indexes; negative values count back from the current scrollback line count. `--end` is inclusive, so `lterm logs api -S0 -E0` captures only the first line. Capture output remains sanitized text: terminal controls are removed, while UTF-8 text such as Korean, CJK, and emoji is preserved. Attached PTY streams remain raw.
220
228
 
@@ -245,9 +253,9 @@ Use the narrowest scope that matches what you want:
245
253
 
246
254
  | Scope | Example | When to use it |
247
255
  | --- | --- | --- |
248
- | One new session | `lterm start --status-theme green -n api -- npm run dev` | Keep a service or agent session recognizable across future attaches. |
256
+ | New session | `lterm start --status-theme green -n api -- npm run dev` | Keep a service or agent session recognizable across future attaches. |
249
257
  | Existing session | `lterm status-theme api amber` | Recolor a running session without restarting its process. |
250
- | Agent launcher session | `lterm codex --status --status-color cyan -- exec "summarize"` | Give an agent-owned session a persistent color while preserving long-only launcher controls. |
258
+ | Agent launcher session | `lterm codex --status --status-color cyan -- exec "summarize"` | Give an agent-owned session a persistent color while preserving launcher controls. |
251
259
  | Attaching client default | `export LTERM_STATUS_THEME=magenta` | Change the default for sessions that do not have their own override. |
252
260
  | Plain/minimal clients | `export LTERM_STATUS_STYLE=minimal` | Prefer text-only status on mobile SSH clients or terminals with fragile color mapping. |
253
261
 
@@ -284,19 +292,83 @@ lterm sessions --children
284
292
  lterm sessions --all
285
293
  lterm processes api --orphans
286
294
  lterm logs api --start=-80 --end=-1
295
+ lterm urls api --last
296
+ lterm search api 'build failed'
287
297
  lterm compose api
288
298
  LTERM_MOBILE=1 lterm resume codex-lterm
299
+ lterm reconnect --mobile
289
300
  lterm resume --raw codex-lterm
290
301
  lterm wait api --contains READY --timeout 30s --json
291
302
  lterm watch api --exit --notify
292
303
  lterm input api 'echo hello' --enter
293
304
  ```
294
305
 
295
- The generic aliases above are meant for day-to-day agent-terminal use: `sessions` lists persistent work, `processes` inspects child process trees, `logs` reads sanitized scrollback, `compose` shows sanitized scrollback with a fixed bottom prompt for committing text, mobile transcript attach gives phone clients native scrollback for long agent output, `wait` / `watch` make marker-or-exit conditions observable for scripts and agents, and `input` writes text to the target PTY. `lterm mobile` is a visible alias for `lterm compose`; separately, the `--mobile` attach flag selects the normal-screen transcript attach path. The compatibility names `list` / `ls`, `ps`, `capture`, and `send` remain available for scripts and muscle memory.
296
-
297
- For automation and tests, `lterm compose api --once --message 'hello'` performs one sanitized capture/send cycle. It captures the last `--tail` sanitized lines (default: 80) from the same session-or-pane target model as `logs`, then appends Enter (`\r`) by default, matching `lterm input --enter`; add `--no-enter` to send the exact message bytes. `compose` / `mobile` is not an attach client and does not change attached-client counts or PTY geometry.
298
- In interactive compose, the view refreshes on `--refresh` (default: 500ms) and after local input or resize events. Pressing Enter commits the current input buffer (empty buffers are committed too) and appends `\r` by default, matching the one-shot rule above. Ctrl-C, Ctrl-D, and Esc exit the local composer instead of forwarding to the PTY.
299
- `lterm compose api --transcript` opens the same normal-screen transcript UI used by mobile auto attach. It is useful when you want sanitized scrollback and simple line input without the alternate-screen composer; add `--read-only` when you only want to watch output.
306
+ The generic aliases above are meant for day-to-day agent-terminal use: `sessions` lists persistent work, `processes` inspects child process trees, `logs` reads sanitized scrollback, `compose` shows sanitized scrollback with a fixed bottom prompt for committing text, mobile transcript attach gives phone clients native scrollback for long agent output, `reconnect` resumes the last selected local lterm session after an SSH reconnect, `wait` / `watch` make marker-or-exit conditions observable for scripts and agents, and `input` writes text to the target PTY. `lterm mobile` is a visible alias for `lterm compose`; separately, the `--mobile` attach flag selects the normal-screen transcript attach path. The compatibility names `list` / `ls`, `ps`, `capture`, and `send` remain available for scripts and muscle memory.
307
+
308
+ `lterm reconnect [fallback]` stores a private, minimal pointer to the last
309
+ selected session (`session_id`, pane id, user-chosen session name, and
310
+ timestamp), then uses that pointer on the next run. Missing, corrupt, or stale
311
+ pointers fall back to `fallback` (default: `main`) with the same
312
+ attach-or-create behavior as `lterm open`.
313
+
314
+ Do not put secrets in session names. `reconnect` can still raw-attach, so use
315
+ `--mobile` on phone SSH clients when you want the sanitized normal-screen
316
+ transcript instead of the raw PTY stream. Preview the optional SSH-login snippet
317
+ with `lterm init --mobile-reconnect --shell zsh` (or `bash`, `fish`, `posix`);
318
+ omit `--shell` to detect from `$SHELL`. The snippet is not installed
319
+ automatically: copy it only after review, remove the copied block to undo it, or
320
+ set `LTERM_RECONNECT_DISABLE=1` to skip it.
321
+
322
+ `lterm urls <target>` extracts `http://` and `https://` links from the last
323
+ 120 sanitized scrollback lines without touching the raw attached PTY stream.
324
+ Default output is `N<TAB>URL`, one link per line. Use `--last` for the newest
325
+ valid URL, `--json` for a JSON array, and `--tail N` to change the scan range.
326
+ Empty text modes exit successfully with no output; JSON mode prints `[]`. URL
327
+ extraction is bounded to 256 unique ASCII URL tokens and skips raw candidates
328
+ longer than 4096 bytes instead of truncating them.
329
+
330
+ In mobile transcript mode, type `/links` or `/urls` to show the same numbered
331
+ list locally instead of sending that text to the PTY. This is useful for
332
+ Claude/OAuth login URLs on Termius-style mobile SSH clients; for
333
+ Claude-specific mobile control, Claude Code's Remote Control flow can also
334
+ reduce URL-copy round trips. Treat extracted links as untrusted terminal
335
+ output: a malicious program can print phishing URLs, and OAuth, magic-login, or
336
+ device-code links may carry short-lived secrets. Open only links you expect,
337
+ avoid pasting them into shared logs or chat, and use `--last` only when you
338
+ know the newest link is the one you intend to open.
339
+
340
+ `lterm search <target> QUERY` searches the last 120 sanitized scrollback lines
341
+ for case-sensitive literal matches without touching the raw attached PTY stream.
342
+ Default output is `N<TAB>LINE` with 1-based numbering; `--json` emits the same
343
+ sanitized matching lines as a JSON array, and `--tail N` changes the scan range.
344
+ No-match text mode exits successfully with no output, while an empty `QUERY` is
345
+ rejected. In mobile transcript mode, type `/grep QUERY` to show matching lines
346
+ from the active transcript tail window locally instead of sending that text to
347
+ the PTY. `/grep` without a query prints `Usage: /grep QUERY`; no matches print
348
+ `No matches found in current transcript.`
349
+
350
+ For automation and tests, `lterm compose api --once --message 'hello'` performs
351
+ one sanitized capture/send cycle. It captures the last `--tail` sanitized lines
352
+ (default: 80) from the same session-or-pane target model as `logs`, then appends
353
+ Enter (`\r`) by default, matching `lterm input --enter`; add `--no-enter` to
354
+ send the exact message bytes. `compose` / `mobile` is not an attach client and
355
+ does not change attached-client counts or PTY geometry.
356
+
357
+ In interactive compose, the view refreshes on `--refresh` (default: 500ms) and
358
+ after local input or resize events. Pressing Enter commits the current input
359
+ buffer, including an empty buffer, and appends `\r` by default. Ctrl-C, Ctrl-D,
360
+ and Esc exit the local composer instead of forwarding to the PTY.
361
+
362
+ `lterm compose api --transcript` opens the same normal-screen transcript UI used
363
+ by mobile auto attach. Use it when you want sanitized scrollback and simple line
364
+ input without the alternate-screen composer; add `--read-only` when you only
365
+ want to watch output. Transcript-local commands include `/refresh`, `/raw`,
366
+ `/links` / `/urls`, `/grep QUERY`, and `/exit` / `/quit`. `/links`, `/urls`,
367
+ and `/grep` are handled locally and are never forwarded to the PTY. When no
368
+ links are present they print `No URLs found in current transcript.`; `/grep`
369
+ without a query prints `Usage: /grep QUERY`; no matches print
370
+ `No matches found in current transcript.` Unrecognized lines are sent to the
371
+ PTY.
300
372
 
301
373
  **Stop a session:**
302
374
 
@@ -343,7 +415,7 @@ lterm gemini -- -p "summarize this repo" # Gemini CLI also accepts -p
343
415
  lterm agents
344
416
  ```
345
417
 
346
- These are thin profile aliases for:
418
+ These are thin profile aliases for example:
347
419
 
348
420
  ```bash
349
421
  lterm agent claude
@@ -364,7 +436,7 @@ lterm codex --mobile --tail 200 --refresh 1s --read-only
364
436
  lterm agy --status -- -p "keep lterm status visible"
365
437
  ```
366
438
 
367
- Known Claude/Codex/OpenCode/Copilot/Cursor Agent/Antigravity/Kiro/Jules/Aider/Goose/Amp/Crush/Kimi/Qwen/Gemini/OMX/OMC profiles default to the `auto` attach policy. On desktop that means a raw full-terminal attach without the lterm status bar, so their own TUI/status/alternate-screen rendering stays in control. Reattaching those agent sessions later with `lterm resume` or `lterm open` keeps the same row-off default. On Termius-style mobile clients, `auto` uses the normal-screen transcript described above so long agent output can be reviewed with native mobile scrollback. Use `--raw` to force raw attach, `--mobile` to force transcript attach, `--status` to request the lterm status bar on the raw path during direct agent launch, or `--no-status` to suppress it for any raw launch/profile that would otherwise show it. `--status` is intentionally a best-effort override for agent debugging and can still conflict with agent TUIs; `--mobile --status` does not create a raw status row because mobile transcript owns its own UI. Put `--` before agent arguments that could be parsed as lterm launch options. `lterm agent <name>` also works for any safe bare command name available in `PATH` (for example `lterm agent qwen-code`); use `lterm run -- <command>` only when you want the lower-level tmux-compatible primitive directly.
439
+ Known Claude/Codex/OpenCode/Copilot/Cursor Agent/Antigravity/Kiro/Jules/Aider/Goose/Amp/Crush/Kimi/Qwen/Gemini/OMX/OMC profiles default to the `auto` attach policy. On desktop, that means a raw full-terminal attach without the lterm status bar, so the agent's own TUI, status, and alternate-screen rendering stay in control. Reattaching those agent sessions later with `lterm resume` or `lterm open` keeps the same row-off default. On Termius-style mobile clients, `auto` uses the normal-screen transcript described above so long agent output can be reviewed with native mobile scrollback. Use `--raw` to force raw attach, `--mobile` to force transcript attach, `--status` to request the lterm status bar on the raw path during direct agent launch, or `--no-status` to suppress it for any raw launch/profile that would otherwise show it. `--status` is intentionally a best-effort override for agent debugging and can still conflict with agent TUIs; `--mobile --status` does not create a raw status row because mobile transcript owns its own UI. Put `--` before agent arguments that could be parsed as lterm launch options. `lterm agent <name>` also works for any safe bare command name available in `PATH` (for example `lterm agent qwen-code`); use `lterm run -- <command>` only when you want the lower-level tmux-compatible primitive directly.
368
440
 
369
441
  Agent launchers also keep host/application color policy separate from the agent child. Ambient `NO_COLOR`, `FORCE_COLOR`, `CLICOLOR`, and `CLICOLOR_FORCE` from the client or long-lived daemon are not forwarded to sessions marked with `LTERM_AGENT`, because mobile SSH or host status preferences can otherwise force full-screen agent TUIs into monochrome output. Ordinary non-agent sessions (`lterm start` / `lterm new` / `lterm run`) still preserve those variables for child processes, and lterm's own status style continues to honor `NO_COLOR`.
370
442
 
@@ -426,7 +498,7 @@ lterm run -- codex exec "summarize the repository"
426
498
 
427
499
  Inside that session, `tmux` resolves to the `lterm tmux-compat` shim. This is a compatibility layer, not a second spelling of every `lterm` product command. The shim implements the command subset most AI orchestration scripts rely on:
428
500
 
429
- - **Sessions** — `new-session`, `attach-session`, `has-session`, `list-sessions`, `rename-session`, `kill-session`
501
+ - **Sessions** — `new-session`, `new-window`, `attach-session`, `has-session`, `list-sessions`, `rename-session`, `kill-session`
430
502
  - **Queries** — `list-windows`, `list-clients`, `list-commands`, `show-options`, `show-window-options`
431
503
  - **Panes** — `split-window`, `list-panes`, `display-message`, `capture-pane`, `send-keys`, `kill-pane`, `resize-pane`
432
504
  - **Buffers / popups** — `display-popup`, `wait-for`, `load-buffer`, `save-buffer`, `paste-buffer`
@@ -435,6 +507,8 @@ Inside that session, `tmux` resolves to the `lterm tmux-compat` shim. This is a
435
507
  Compatibility notes: lterm models each root session as one pseudo-window
436
508
  (`window_index=0`, `window_panes=1`). `client_pid` and `client_tty` expand to
437
509
  empty strings because lterm does not expose per-client process or TTY metadata.
510
+ `#{history_size}` currently expands to `0`, which keeps tmux-format consumers
511
+ numeric even though lterm does not expose a tmux-style pane history length yet.
438
512
  tmux `-f` filters are intentionally rejected instead of being silently ignored.
439
513
  `set-hook` accepts hook set/unset forms used by agent runtimes such as OMX
440
514
  `client-resized[...]` handlers, but lterm does not run a tmux hook dispatcher.
@@ -442,20 +516,30 @@ Detached `split-window -d -t <target>` accepts any existing live lterm target,
442
516
  matching tmux's cross-pane helper launch behavior inside the same daemon socket;
443
517
  the daemon verifies same-OS-user peer credentials before honoring requests, and
444
518
  the detached helper is created as a separate lterm session rather than being
445
- attached into the target pane.
446
- Use `lterm tmux-compat list-commands --verbose` for tab-separated `command`, alias, support tier, and usage fields, or `--json` for machine-readable rows. Support tiers are `full`, `partial`, and `noop` within lterm's compatibility boundary. Set `LTERM_DEBUG_TMUX=1` to emit an opt-in stderr diagnostic row when an unsupported tmux command reaches the shim.
519
+ attached into the target pane. `split-window -b -h` and `split-window -b -v` map
520
+ to cmux `left` and `up` placements respectively when a visible cmux split is
521
+ created. Detached `new-window -d` / `neww -d` is intentionally partial: it creates
522
+ a standalone lterm helper session, supports tmux-style `-P`/`-F` target printing,
523
+ and rejects attached-window mode instead of silently changing the current pane.
524
+ Use `lterm tmux-compat list-commands --verbose` for tab-separated `command`,
525
+ alias, support tier, and usage fields, or `--json` for machine-readable rows.
526
+ Support tiers are `full`, `partial`, and `noop` within lterm's compatibility
527
+ boundary. Set `LTERM_DEBUG_TMUX=1` to emit an opt-in stderr diagnostic row when
528
+ an unsupported tmux command reaches the shim.
529
+
530
+ Status bar redraws use xterm SGR stack controls only on conservatively allowlisted terminal clients (for example xterm/iTerm2/WezTerm identities) to avoid stealing the foreground/background color state of the running TUI. Set `LTERM_STATUS_SGR_STACK=0` to disable `CSI # {` / `CSI # }`; set it to `1` to force the stack after verifying your client supports or safely ignores those private CSI sequences. Kitty, Alacritty, Ghostty, Termius, and generic `TERM=xterm-*` values stay opt-in until their SGR-stack behavior is verified.
447
531
 
448
- Status-bar redraws use xterm SGR stack controls only on conservatively allowlisted terminal clients (for example xterm/iTerm2/WezTerm identities) to avoid stealing the foreground/background color state of the running TUI. Set `LTERM_STATUS_SGR_STACK=0` to disable `CSI # {` / `CSI # }`; set it to `1` to force the stack after verifying your client supports or safely ignores those private CSI sequences. Kitty, Alacritty, Ghostty, Termius, and generic `TERM=xterm-*` values stay opt-in until their SGR-stack behavior is verified.
532
+ When lterm mirrors session identity into cmux understatus pills, it probes `cmux set-status --help` without mutating cmux state. Builds that advertise `--label` receive labeled status rows; older cmux builds keep working because lterm omits the unsupported flag.
449
533
 
450
534
  ## cmux behavior
451
535
 
452
536
  When `lterm tmux-compat split-window` detects cmux (via `CMUX_WORKSPACE_ID`, `CMUX_SURFACE_ID`, or a cmux socket), it:
453
537
 
454
538
  1. Starts a new `lterm` PTY session for the worker command.
455
- 2. Asks cmux to create a native split (`cmux new-split right/down`).
539
+ 2. Asks cmux to create a native split (`cmux new-split right/down`, or `left/up` for tmux backward splits).
456
540
  3. Sends the compatibility command `lterm attach <pane>` into that split. If a safe absolute executable is supplied through `LTERM_BIN`, lterm uses it; otherwise it falls back to the current executable. The compatibility command keeps cmux panes working even with older builds that predate `resume`.
457
541
 
458
- This gives cmux a real pane to decorate while `lterm` retains scrollback capture and `send-keys` compatibility.
542
+ This gives cmux a real pane to decorate while `lterm` retains scrollback capture, `send-keys` compatibility, and safe status-label fallback behavior across cmux versions.
459
543
 
460
544
  **Notifications:**
461
545
 
@@ -481,6 +565,11 @@ This uses the same attach-or-create behavior as `lterm open main` on the remote
481
565
  lterm ssh devbox main -- -p 2222 -i ~/.ssh/id_ed25519
482
566
  ```
483
567
 
568
+ After a plain mobile SSH login to a host, run `lterm reconnect --mobile` to
569
+ resume the last lterm session selected on that host. `lterm ssh` itself keeps
570
+ the legacy `attach-or-new` remote command for compatibility with older remote
571
+ installs.
572
+
484
573
  ## Architecture
485
574
 
486
575
  - **Daemon** — one Unix socket per user under `$XDG_RUNTIME_DIR`, with an owner-only fallback under `/tmp`.
@@ -497,7 +586,7 @@ the old code until they are stopped.
497
586
 
498
587
  **Terminal output is forwarded as-is.** `lterm resume` (compatibility name: `lterm attach`) passes PTY bytes through so full-screen terminal programs and cmux/OSC notifications keep working. The local status bar is purely a client-side decoration; use `--no-status` for a fully raw terminal surface. Any nested-agent row suspension is host-side geometry/status management only and does not sanitize or rewrite attached PTY bytes. Untrusted child programs can still emit terminal escape sequences to an attached terminal — exactly as under tmux/screen. **Do not use `lterm` as an escape-sequence sanitizer or sandbox.**
499
588
 
500
- **Capture output is terminal-control-sanitized before display/logging.** `lterm logs` (compatibility name: `lterm capture`), `lterm compose` (alias: `lterm mobile`), and `tmux capture-pane` strip terminal control sequences, including raw or UTF-8-encoded C1 controls, before printing scrollback. Valid UTF-8 text such as Korean, CJK, and emoji is preserved. Scrollback text can still be untrusted program output, so review it before feeding it to humans or agents. `compose` is a non-attached view that commits text through the existing input/send path; it does not transform raw attached PTY streams.
589
+ **Capture and report output is terminal-control-sanitized before display/logging.** `lterm logs` (compatibility name: `lterm capture`), `lterm compose` (alias: `lterm mobile`), `lterm search`, `lterm urls`, diagnostics, and `tmux capture-pane` strip terminal control sequences, including raw or UTF-8-encoded C1 controls, before printing scrollback-derived text. Valid UTF-8 text such as Korean, CJK, and emoji is preserved. Scrollback text can still be untrusted program output, so review it before feeding it to humans or agents. `compose` is a non-attached view that commits text through the existing input/send path; it does not transform raw attached PTY streams.
501
590
 
502
591
  **Process visibility.** `lterm processes [session]` (or compatibility name `lterm ps [session]`) shows the process tree rooted at each session child, including process-group ids. Add `--orphans` to also include same-process-group rows that are no longer descendants of the recorded session root, so long-running Codex/OMX/MCP subprocess buildup stays visible before it becomes a memory-leak surprise. The system `ps` is invoked by absolute path, and malformed process rows are skipped rather than guessed at.
503
592
 
@@ -517,7 +606,7 @@ executable or `lterm` on `PATH`. Do not set it from untrusted environment data.
517
606
 
518
607
  - Session persistence lasts only while the daemon and host are alive — reboot/process-state restore is not implemented.
519
608
  - Outside cmux, `split-window` creates additional managed PTY sessions but does not draw a tiled in-terminal UI.
520
- - This is a compatibility subset, not a full tmux server. Scripts using advanced tmux formats or options may need additional shim commands.
609
+ - This is a compatibility subset, not a full tmux server. Scripts using advanced tmux formats, hooks, layouts, or options may need additional shim commands.
521
610
  - cmux pane capture is handled through `lterm` sessions, not cmux scrollback APIs.
522
611
  - The daemon authenticates local clients via OS peer credentials and owner-only socket paths — there are no per-session ACLs yet.
523
612
  - Session shutdown uses verified process-group signaling, so child trees like `shell → OMX → Codex → MCP` are cleaned up together when possible. Processes that intentionally detach into a different session/process group can outlive `lterm close` / `lterm kill`; inspect them with `lterm processes` / `lterm ps` or OS process tools.
@@ -526,8 +615,9 @@ executable or `lterm` on `PATH`. Do not set it from untrusted environment data.
526
615
 
527
616
  ```bash
528
617
  cargo fmt
618
+ cargo clippy --all-targets -- -D warnings
529
619
  cargo test
530
- cargo build --locked
620
+ cargo build --release --locked
531
621
  ```
532
622
 
533
623
  If a system package-manager Rust toolchain fails before Cargo starts (for
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ictechgy/lterm",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "Lightweight tmux-compatible terminal session daemon with cmux-friendly notifications.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "homepage": "https://github.com/ictechgy/light_terminal#readme",
@@ -36,10 +36,10 @@
36
36
  "scripts/validate_npm_packages.mjs"
37
37
  ],
38
38
  "optionalDependencies": {
39
- "lterm-darwin-arm64": "1.0.23",
40
- "lterm-darwin-x64": "1.0.23",
41
- "lterm-linux-arm64": "1.0.23",
42
- "lterm-linux-x64": "1.0.23"
39
+ "lterm-darwin-arm64": "1.0.25",
40
+ "lterm-darwin-x64": "1.0.25",
41
+ "lterm-linux-arm64": "1.0.25",
42
+ "lterm-linux-x64": "1.0.25"
43
43
  },
44
44
  "engines": {
45
45
  "node": ">=16"