# HANDOFF — understatus (+ lterm statusline 통합)
> 다음 세션/에이전트용 핸드오프. 제품은 원래 **statusticon** 코드네임이었다가 출시 시 **understatus**로 개명. 온디스크 디렉터리는 여전히 `statusticon/`이지만 제품/크레이트/레포/바이너리는 전부 **understatus**.
>
> **최신 세션 작업 = §0 (lterm 경로 git branch pill — understatus 단독, PR #14 OPEN).** 직전 세션(06-09, cmux 네이티브 status pills 실렌더)은 §0A, 그 전(06-08, ctx 소멸 fix + 라우팅 인프라)은 §0B, 그 전(06-07)은 §0C, Phase 1 배경은 §A, v0.3.0 릴리스 배경은 §C.
---
## ⚠️ 먼저 읽기 — 로컬 툴체인 깨짐 (양쪽 레포 공통)
**Homebrew `rustc`/`cargo`가 깨져 있다.** `/opt/homebrew/bin/rustc`가 없는 `libLLVM.dylib`를 참조 → bare `cargo`/`rustc`/`clippy`/`rust-analyzer` 실패(dyld 에러, 가끔 오해의 exit 0). `/opt/homebrew/bin`이 `~/.cargo/bin`보다 PATH 앞이라 **bare `cargo`는 깨진 쪽으로 resolve됨.**
**항상 rustup 툴체인 사용** (understatus·lterm **둘 다**):
```bash
export PATH="$HOME/.cargo/bin:$PATH" # ~/.cargo/bin/cargo = stable-aarch64, 정상
```
- **rust-analyzer/IDE 진단은 가짜다**(phantom E0308, 실제 사용 중인 항목에 dead_code 등). **IDE 진단 무시, rustup `cargo`/`clippy` 출력만 신뢰.** (이번 세션에도 IDE가 `parse_lterm_input` 등을 dead로 표시했으나 rustup clippy는 클린.)
- `gtimeout` 없음 → 타임아웃은 background+polling kill 패턴으로.
- x86_64 크로스빌드는 로컬 실패 → CI(macos-14). 네이티브 arm64 빌드/테스트는 rustup으로 정상.
---
## §0. 최신 세션 (2026-06-10) — lterm 경로 git branch pill (구현·검증·라이브·quad-review-loop·**머지 완료**) ← **여기부터 읽기**
> 이번 세션: cmux pills 후속 트랙(§0A 이월 #3(b) "cost·git payload 확장")을 ralplan 합의로 **스코프 재정의**해 구현 → 라이브 검증 → **quad-review-loop**로 실재 보안 blocker 1건 수정 → **PR #14 머지**. lterm 경로(`--source lterm --surface-format cmux-status`)의 cmux 사이드바에 **git branch pill 추가**. **understatus 단독 변경**(lterm 무변경).
>
> **현재 상태: PR #14 MERGED(main `4baf1c5` feat + `21f83e8` fix, rebase), 열린 PR 0, CI 그린, 라이브 cmux 검증 통과, feature 브랜치 정리됨.**
>
> **✅ 릴리스 완료 (2026-06-11): understatus v0.5.0 4채널 전부 라이브.** PR #15(버전 범프, rebase-merge `29ca989`) + PR #16(homebrew 사본 동기화 `1569466`). 태그 v0.5.0(`29ca989`). 채널: **crates.io v0.5.0** · **GitHub Release v0.5.0**(arm64+x64 tar.gz+sha256) · **Homebrew tap `ictechgy/homebrew-understatus`**(commit `ffc292a`, 소스 아카이브 sha256 `4fe6384c…`, `brew info`가 stable 0.5.0 인식) · **npm `understatus@0.5.0`**(latest 태그, 사용자가 passkey로 publish; 레지스트리 클린설치 E2E 통과 — install.js가 v0.5.0 바이너리 SHA-256 검증·수신·`understatus 0.5.0` 실행 확인). 4게이트 그린(318+14=332 테스트). gh GraphQL이 세션 중 간헐 401(토큰 flaky) → 재시도로 통과, git push는 osxkeychain으로 무영향.
### quad-review-loop 결과 (2라운드 수렴)
- **R1 blocker(2/3 합의, 수정됨)**: `read_branch_from_git_dir`이 신뢰 불가 `.git/HEAD` 내용(악성 repo의 `ref: refs/heads/main␛[31m…`)을 검증 없이 반환 → oneline SGR/cmux pill 터미널 인젝션. **`char::is_control` 거부**로 source chokepoint에서 차단(lterm+Claude 경로 동시). 동반: 상대경로 cwd 거부(절대경로 요구), 고정경로 테스트 hermetic화. commit `21f83e8`.
- **R2 수렴**: Codex APPROVE. Claude 유일 HIGH(pill value 셸 메타문자 인젝션)는 **lterm sink가 `cmd.arg(value)` 셸 미경유(tmux_compat.rs)임을 코드로 확인 → false-positive 확정**(기존 model/cpu/mem pill과 동일 sink, 이 PR 도입 아님). consensus blocker 0.
- **교훈**: ralplan은 path traversal만 봤고 **content 살균(제어문자)을 놓침** → quad-review가 실재 보안 갭을 메움. 반대로 단일트랙 HIGH는 교차레포 코드 검증으로 false-positive를 걸러 불필요 수정 회피. Forge는 R2에서 reasoning-only 출력으로 폐기(flaky), Antigravity는 21~28KB 프롬프트 hang으로 양 라운드 SKIP → 사실상 Claude+Codex 듀얼.
### 핵심 발견 / 결정 (다음 세션이 알아야 할 것)
- **cost 영구 제외(데이터 소스 부재)**: codex rollout JSONL에 **cost 필드 자체가 없음**(understatus `codex.rs` CodexExtras/TokenSnapshot은 rate-limit %·plan·effort만). lterm은 PTY 래퍼라 자식(codex) 내부 cost 미접근. → "cost·git payload 확장"의 **cost는 구조적 불가**. git만 진행.
- **git은 understatus 단독으로 실현(lterm payload 확장 불필요)**: lterm이 이미 보내는 `cwd`로 understatus가 직접 `.git/HEAD`를 읽으면 됨. lterm `SessionInfo.cwd`는 세션 시작 dir(셸 cd 추적 안 됨)이나 codex는 보통 repo 루트 고정이라 실용상 OK(수용 한계).
- **cwd-only 채택, 부모 walk-up 기각(Architect 적발)**: walk-up은 `read_branch_from_git_dir`의 canonicalize가 `<base>/.git/HEAD` **파일만** 보호하고 디렉터리 체인은 검증 못 해, 심볼릭 cwd에서 **타 repo branch를 확신 표시하는 false-positive(오정보)** 위험. status 표면에선 빈 pill(false-negative) ≪ 틀린 pill. → cwd-only(`<cwd>/.git/HEAD` 1회)만, 정탐률 보완은 v2 이월.
- **Q4 코드 확정**: lterm `is_valid_pill_key("git")`==true(`tmux_compat.rs:1673` ref-segment `[A-Za-z0-9_-]` + `:3999` len≤64). lterm sink가 "git" 키를 제네릭 set-status → **lterm 변경 불필요 전제 성립**.
- **cmux 네이티브 branch 표시 발견(라이브)**: cmux가 워크스페이스마다 `branch • cwd` 줄을 **자체 표시**(우리 pill엔 cwd 없음). 단 **다른 세션에선 누락되기도 함**(불안정) → 우리 pill이 일관된 폴백으로 별개 가치. 사용자가 유지 결정.
- **git-branch 아이콘 drop(R4 예측대로)**: cmux가 `git-branch` 아이콘명 미지원 → 아이콘 누락(주황 텍스트는 정상 렌더). model의 `sparkles`(✨)는 지원. 아이콘 띄우려면 cmux 지원 아이콘명 조사 필요(폴리시 follow-up).
### ✅ 완료 (feature 브랜치, PR #14)
- **claude.rs**: `derive_git_branch_from_cwd(cwd: &str) -> Option<String>` 신규(cwd-only, `is_safe_base_path`+`read_branch_from_git_dir` 재사용, **부모 walk-up 없음** — doc에 v2 이월 명시). `parse_lterm_input`이 `cwd.as_deref().and_then(derive_git_branch_from_cwd)`로 도출(기존 영구 None 제거). 거짓 "항상 None" 주석 정정.
- **render.rs**: git 세그먼트 pill화(`key=git`, `value=branch`, `color=#F1502F` `pill_git_color()`, `icon=git-branch`, `priority=40`). `label_value_segment` 시그니처 불변 → oneline 바이트 보존.
- **회귀 0**: 기존 4 pill 키(model/ctx/cpu/mem) 불변, oneline 불변, Claude 경로 무영향, version bump 없음, 신규 의존성 없음.
- **검증**: 4게이트 그린(fmt/clippy -D warnings/test/release --locked). **lib 316 + oneline 14 통과**. AC1-AC9 테스트 실증, Guardrail 위반 0(독립 verifier 재실행). 보안: traversal/외부향 심볼릭 HEAD/detached/.git 부재 → 전부 None(패닉 0).
- **라이브 cmux 검증 통과**: 사이드바 `더 보기` 펼치면 `feature/lterm-git-branch-pill` git pill 주황(#F1502F) 렌더 확인(사용자 육안). 아이콘만 drop(무해).
### 워크플로 / 교훈
- brainstorming 없이 바로 ralplan(후속 트랙 택1) → explore×2(양 레포 payload 파이프라인) → ralplan 합의(Planner→Architect→Critic **3라운드**, APPROVE) → executor(opus) 구현 → verifier(sonnet) **독립 게이트 재실행** → 라이브 육안.
- **멀티에이전트가 단일 리뷰 사각을 메움**: ① Architect가 walk-up의 보안 false-positive(심볼릭 cwd→타 repo) 적발 → Option 1로 전환. ② Critic 라운드2가 `sample_input`(render.rs:799 `git_branch:Some("main")`) 기반 **render.rs 테스트 3개 깨짐** + claude.rs lterm 테스트 4개 **거짓 계약화**(주석 "항상 None"이 T2 후 거짓) 적발 → T4-a/T4-e로 처리. Planner 단독으론 전부 누락.
- **"cost·git payload 확장" 프레이밍이 코드와 불일치**: explore가 cost 데이터 소스 부재 + git은 lterm 변경 불필요를 밝혀 스코프를 git-only·understatus-only로 재정의. **HANDOFF 이월 항목도 코드로 재검증 필요**.
### ⏭ 다음 세션 이월
1. ~~**understatus 릴리스**~~ ✅ **완료(2026-06-11, v0.5.0)** — crates.io·GitHub Release·Homebrew tap·npm 4채널 전부 라이브. 상세는 위 §0 "릴리스 완료" 줄.
2. **git-branch 아이콘 폴리시**(선택): cmux 지원 아이콘명 조사해 git pill에 아이콘 부착(현재 주황 텍스트만 — cmux가 `git-branch` 미지원해 drop, R4).
3. **v2 false-positive-free walk-up**(선택): `base_path` 디렉터리를 canonicalize해 repo 경계 확인하는 안전한 walk-up → codex가 repo 하위 dir 시작 시도 branch 도출. 또는 lterm payload에 `git_worktree` 추가.
4. **quad-review 잔여 MEDIUM/LOW**(비차단, 추적): (a) branch명 길이 cap(source defense-in-depth — 단 lterm `cap_field`가 다운스트림 절단). (b) symlinked `<cwd>/.git`→other-repo HEAD 누출(`.git` 심볼릭 추종은 표준 git 동작이라 과수정 위험 — 문서화/의도 테스트 권장). (c) 동기 fs read 지연(느린 마운트 cwd). (d) `unique_test_dir` 교차-run cleanup(RAII).
5. **linked worktree gitfile**(`.git`이 파일) 지원(현재 표준 워크트리만).
6. 설계/계획 문서: `.omc/plans/lterm-git-branch-pill.md`(ralplan 합의 확정본, ADR 포함 — **단 `.omc`는 gitignored 로컬**). quad-review-loop 레저: `~/.claude/logs/quad-review-loop/ictechgy-understatus-14-*.md`.
### 검증 수치
- understatus main(머지 후): clippy `-D warnings` 클린, **318(lib) + 14(oneline) = 332 테스트** 통과, release `--locked` 빌드 클린, CI 그린. (구현 시점 316 → quad-review 보안수정으로 신규 테스트 +2 = 318.)
---
## §0A. 직전 세션 (2026-06-09) — cmux 네이티브 status pills 실렌더 (완료/머지)
> 이번 세션: lterm-in-cmux의 codex status를 **DECSTBM 인라인 행 대신 cmux 네이티브 사이드바 pill(`set-status`)**로 렌더하는 실렌더 트랙. §0A(06-08)의 "다음 세션 이월 = lterm 실렌더 트랙"을 완수. understatus **PR #13** + lterm **PR #123** 둘 다 머지.
>
> **현재 상태: 열린 PR 0, 양 레포 main 머지·CI 그린, 라이브 cmux 검증 통과.** 양쪽 **미릴리스**(understatus v0.4.0 / lterm v1.0.22 이후 누적 — 릴리스하려면 §C 절차).
### 핵심 발견 (다음 세션이 알아야 할 것)
- **cmux 네이티브 status API 존재**: `cmux set-status <key> <value> [--icon][--color #hex][--priority]` → 좌측 사이드바 워크스페이스 항목에 pill 렌더. `clear-status`/`list-status` 동작. HANDOFF가 몰랐던 경로(과거 "write 핸들 없음"으로 오판). **`cmux send`는 키보드 입력 주입이지 화면 페인트 아님** → split 렌더러 대신 set-status 채택.
- **`set-progress`는 워크스페이스 전역**(pane-keyed 아님) + `list-progress` 부재 → SIGKILL 시 stale progress 청소 불가(누수). **진행바 채택했다가 quad-review에서 제거, ctx는 pill만.**
- **워크스페이스 식별 함정**: `$CMUX_WORKSPACE_ID` env는 lterm 세션에서 stale(죽은 ws). runtime `cmux identify` focused는 포커스 드리프트 → **attach 시점 `cmux identify --id-format uuids`로 UUID 캡처**(stored split-time 컨텍스트 우선, `tmux_compat::cmux_status_identity`).
- **codex는 RowOff**(`show_status:false`, attach 경로 `likely_agent_session→RowOff` `main.rs:2258`)라 `requests_row()==false`. cmux pill은 off-grid라 **`sink_enabled`를 `requests_row()`에 묶으면 1차 표적 codex에서 영구 OFF**(Architect R3 BLOCKER). 정답: `sink_enabled = matches(Cmux) && LTERM_STATUS_COMMAND set && !--no-status`; `in_grid = !sink_enabled && backend!=Disabled && requests_row()`(pill 미사용 cmux 셸은 기존 DECSTBM 보존, 회귀 0).
### ✅ 완료 (양쪽 main 머지)
- **understatus #13**(rebase): `--surface-format cmux-status` 출력 모드 — oneline과 동일 `collect_segments` 재사용해 `model·ctx·cpu·mem` pill JSON 방출. `Segment`에 additive `pill: Option<PillMeta>`(oneline 바이트 불변). 색 신규 매핑(cpu만 `band_tint` 재사용). ctx 0..=100 클램프+정수% 양자화. cost·git은 lterm 파서 영구 None(`claude.rs:288-289`)이라 제외. 핵심: `src/render.rs`(to_cmux_pills/PillMeta/color_to_hex), `src/main.rs`(SurfaceFormat/--surface-format). 설계/계획: `docs/superpowers/specs/2026-06-08-cmux-native-status-pills-design.md`, `.../plans/...-plan.md`.
- **lterm #123**(merge): `CmuxStatusSink`(`src/tmux_compat.rs` cmux_status 모듈) — pill JSON diff→`cmux set-status/clear-status` 변경분만. 라우팅 `in_grid`/`sink_enabled` 분리(`client.rs:3096`), 소비점 `client.rs:3421` 분기(StatusBar 미진입, in_grid 경로 바이트 불변), `cmux_status_identity`(UUID), 고아 재조정(attach 시 list-status, 실패 시 best-effort), Drop 청소, 서킷브레이커(3연속 실패→blackout), cmux 호출 **3s 타임아웃**(`run_cmux_command` `wait_with_timeout`), pill key 검증(`is_valid_pill_key`)+value/color/icon cap.
- **라이브 검증 통과**: 실제 `lterm codex`에서 사이드바 pill(cpu/mem/✨codex) 렌더 + **codex 입력칸 무손상**(DECSTBM 제거 = 본 트랙 수용기준) + detach 청소(사용자 육안 확인).
### 워크플로 / 교훈 (반복 회피)
- brainstorming → **cmux API 라이브 탐침**(set-status 발견) → ralplan 합의(Planner×2/Architect×3/Critic×2) → 청크 구현(executor) → **라이브 PTY 검증** → quad-review-loop.
- **Architect R2가 lterm 레포 안 읽고 "앵커 0 hit → UNSOUND" 오발** → 메인 에이전트가 직접 grep해 반증(앵커 전부 실재) 후 R3 재실행. **교차레포 리뷰 시 에이전트에 레포 절대경로 명시 + "신규 식별자는 작성 대상" 프레이밍 필수.**
- **quad-review-loop가 결정적 값**: Claude code-reviewer는 양쪽 APPROVE였으나 **Codex(gpt-5.5)가 lterm HIGH 3건**(① `run_cmux_command` 무한 대기→프리즈 ② pill key 미검증 ③ set-progress 전역 누수) 적발 → 전부 수정. **단일 리뷰 사각을 멀티모델이 메움.**
- **agy는 8KB+ 프롬프트 hang**(92KB diff라 SKIP), **forge는 `forge info`부터 flaky** → quad가 사실상 Claude+Codex 듀얼. 정상 폴백.
- ralplan/quad-review가 코드 사실 불일치를 잡음: "핵심 4 pill(cost·git)"이 codex 경로 구조적 None → model·ctx·cpu·mem로 재결정.
### ⏭ 다음 세션 이월 (전부 선택)
1. **understatus 릴리스**: v0.4.0 이후 cmux pills 누적분 미릴리스. §C 절차(3종 버전 범프→태그→`release.yml` 그린 대기→`cargo publish`→Homebrew tap→npm은 사용자 passkey).
2. **lterm 릴리스**: v1.0.22 이후 미릴리스.
3. **cmux pills 후속**: (a) cmux `rpc` 배치 set으로 `sink.apply` 동기 spawn을 비동기 worker로(현재 3s 타임아웃으로 프리즈만 차단, diff 게이트로 호출 드묾). (b) cost·git용 lterm payload 확장(현재 codex 경로 None). (c) NativeChrome(iTerm OSC1337)·DelegatedSurface(Tmux) 백엔드. (d) 동일 pane 동시 attach 시 짧은 pill 깜빡임(수용 한계, instance-id는 SIGKILL 재조정과 상충해 미도입).
### 검증 수치
- understatus main: clippy 클린, **310+13 테스트**, CI(ci) 그린.
- lterm main: **1.96** clippy 클린, unit **417** + cli_smoke 201, release `--locked`, CI 7체크 그린.
---
## §0B. 직전 세션 (2026-06-08) — 완료(배경)
> 이번 세션: ① understatus **ctx 소멸 버그 수정**(#9) + ② lterm **status 라우팅 인프라 배선**(#122) + ③ **진짜 ctx 소멸 원인 = `workspace.repo` 객체화 파싱 실패 수정**(#10) + ④ **understatus v0.4.0 4채널 배포 완료**. 직전 세션(06-07)은 §0C, 배경은 §A~E.
>
> **현재 상태: 열린 PR 0, understatus v0.4.0 라이브(crates.io·npm·Homebrew·GitHub Release), 화면 ctx 정상.** 다음 작업은 lterm 실렌더 트랙(아래 이월).
### ✅ 완료 (양쪽 main 머지됨)
1. **understatus ctx 소멸 버그 수정** — Claude Code statusline JSON의 `context_window.used_percentage`가 **간헐 누락**되면 understatus가 ctx 세그먼트를 생략하면서 동시에 체인된 omc HUD ctx도 strip(§0C-2)해 **ctx가 화면에서 완전히 사라지던** 버그(스크린샷 증상). 체인된 omc HUD의 자체 안정화는 매 refresh마다 새 프로세스로 떠 인메모리 상태가 초기화돼 86↔98로 튀던 게 strip의 원인. 수정:
- **토큰 fallback**: `context_window`의 `current_usage` 토큰합/`total_input_tokens` ÷ `context_window_size`(omc HUD `getContextPercent`와 동일 우선순위).
- **resolve_context_percent**: 양수 native > TTL(30s) 내 직전 native 유지(hold, 세션 캐시 `ctx_native`) > 토큰 fallback > 생략.
- **비대칭 하강 가드**: 상승 노이즈(86↔98)는 hold로 차단하되, fallback이 직전 native보다 12%p↓이면(`/compact` 등 실감소) hold 해제·즉시 반영. omc 대칭 tolerance가 86↔98 상승에도 튀던 회귀 회피.
- **held 캐시 신뢰경계**: `interpret_held_native_ctx`가 `0<v≤100` 유한값만 인정(변조 캐시 거부→fallback 저하). **lenient f64 역직렬화**: 토큰 필드 타입 드리프트가 statusline 전체를 무력화하지 않게 격리.
- → **understatus PR #9 머지**(main `a9368bf`, 커밋 4개). **quad-review-loop 2라운드**(Codex+Forge 2트랙 합의 MEDIUM=held 검증 반영). **297 테스트**.
- 핵심 파일: `src/claude.rs`(compute_context_fallback/percent_of/clamp_percent/resolve_context_percent/ContextResolution/deserialize_lenient_f64), `src/main.rs`(resolve_claude_context/interpret_held_native_ctx, `CONTEXT_HOLD_TTL_SECONDS=30`/`CONTEXT_HOLD_DROP_TOLERANCE=12`/`CONTEXT_NATIVE_CACHE`).
2. **lterm status 백엔드 라우팅 인프라 배선** — §0C 이월의 "라우팅 실제 배선" **1단계 완료(behavior-preserving)**. PoC `select_status_backend`(이전 `#[allow(dead_code)]`)를 attach 진입부에 실배선:
- `status_enabled = select_status_backend(policy, &gather()) != Disabled && requests_row()` — 기존 `status_bar_supported(requests_row())`와 **정확히 동치**(backend≠Disabled ⟺ !forced_off && terminal_capable). 미사용된 `status_bar_supported` 제거.
- `gather_status_env_snapshot` 신설(실 env→StatusEnvSnapshot).
- **지뢰 처리(이월 항목)**: `tmux_compat::inside_cmux` `pub(crate)` 승격, `detect_real_tmux`+순수 `is_self_provided_tmux`로 lterm self-TMUX(`server::fake_tmux_value`=`{lterm_socket},{pid},0` + `LTERM_SOCKET` export) 식별 → **real_tmux 오분류 방지**. `detect_is_iterm`. `#[allow(dead_code)]` 4개 제거.
- → **lterm PR #122 머지**(main `fbeade0`). code-reviewer APPROVE(동작 동치 검증). 미구현 백엔드(NativeChrome/DelegatedSurface/TitleCueDelegation)는 `status_enabled`(bool)로 환원돼 기존 DECSTBM 경로 그대로(동작 불변) → **라이브 검증 불필요**.
3. **understatus `workspace.repo` 타입 드리프트 수정 (진짜 ctx 소멸 원인)** — 사용자가 "여전히 ctx 안 보임" 보고 → **statusLine stdin 라이브 캡처**로 진단: Claude Code가 `workspace.repo`를 문자열→`{"host","owner","name"}` **객체**로 바꿨는데 understatus `RawWorkspace.repo: Option<String>`이 거부 → `RawClaudeInput` **전체 파싱 실패** → model/ctx/cost/git이 통째 사라지고 시스템 지표만 남음. (`used_percentage` 60%는 정상 전달됐고 파싱만 실패 — §0-1 ctx 수정과 무관한 별개 회귀.) 실제 payload에서 repo만 문자열로 바꾸면 ctx 즉시 복구로 확정.
- **수정**: `deserialize_lenient_string`(Value로 받아 문자열만 추출, 객체/숫자/배열/bool/null→None) 추가. `RawWorkspace`(4필드)·`RawModel`(2필드)·`RawClaudeInput` 최상위(session_id/cwd) String 필드에 적용 → 표시·캐시키 String 필드 **일반화 방어**(향후 다른 필드 객체화도 안전). git_worktree 우선 폴백 보존. **(별개)** hold TTL 30s→**600s** 상향(긴 used_percentage 누락 대비).
- → **understatus PR #10 머지**(main `930d6be`). code-reviewer APPROVE. **293 테스트**(repo 객체 드리프트 보존 등 +5). 라이브 화면 ctx 복귀 사용자 확인.
- **진단 교훈**: 증상을 추측(TTL)하지 말고 **statusLine stdin을 캡처**해 측정하라. 캡처 래퍼는 `tee`(부분쓰기 race) 대신 stdin 전체를 변수로 받아 원자적 append. 두 Claude 세션이 동시 활성이면 전역 캡처 파일에 섞이니 `session_id`/`cwd`로 구분.
### ⏭ 다음 세션 이월
1. **lterm status 실렌더 트랙**(가장 큰 가치, 미구현). 라우팅은 라이브지만 비-DECSTBM 백엔드는 아직 DECSTBM로 환원됨. 트랙별:
- **DelegatedSurface(Cmux)** — ⚠️ **선결 조사 필요**: cmux split은 surface **ref 문자열만** 주고(`open_cmux_split`/`send_cmux_attach`는 attach 명령 **1회** 주입), lterm은 그 surface에 status 바이트를 **주기적으로 쓸 write 핸들이 없음**. `cmux send --surface <ref> <raw SGR>`가 지원되는지 **cmux CLI 계약을 document-specialist로 조사**해야 실현 가능 판정(lterm 레포엔 cmux 구현 없음).
- **NativeChrome(iTerm OSC1337)** — from-scratch(코드 전무). `.poc/poc2-iterm-status.sh`가 검증법 제시(SetUserVar base64 plain text, truecolor/멀티라인 불가). base64 `protocol.rs:309`(pub 승격 필요), iTerm 식별 `detect_is_iterm` 이미 있음.
- 배선점: `attach_pty_rows`(client.rs ~3595)가 "본문 1행 양보 여부" 단일 결정점 — 비-DECSTBM 백엔드는 full `rows` 전달해야 함. 콘텐츠 계약(`LTERM_STATUS_COMMAND`→`command_line`)은 backend-무관 재사용 가능(소비점은 `build_draw_body` 1곳).
- 실렌더는 동작을 바꾸므로 **라이브 PTY attach 육안 검증 필수**(자동 테스트로 색·입력칸 회귀 못 잡음 — HANDOFF 반복 교훈).
2. **understatus 잔여 LOW**(알려진 한계): display=None 내는 극단 프레임(양수 native 부재 + 600s TTL 초과 + 토큰 fallback 부재 = 사실상 cold-start)엔 omc strip과 겹쳐 ctx 잠깐 빔. 빈도 낮고 cold-start는 빈 게 맞아 미수정.
3. **lterm 릴리스**(선택): lterm 라우팅 인프라 배선(#122)은 main에 있으나 v1.0.22 이후 **미릴리스**. 동작 불변(behavior-preserving)이라 급하지 않음. 실렌더 트랙 완료 시 함께 릴리스 권장.
### 검증 수치(이번 세션)
- understatus main(v0.4.0): clippy 클린, **293 테스트**, release `--locked` 빌드 클린, CI 그린.
- lterm main: **1.96** clippy `-D warnings` 클린, unit **377**, release 클린, CI 7체크 SUCCESS.
- ⚠️ **lterm CI는 stable 1.96**(2026-05-28~). 로컬 rustup stable이 1.94면 `manual_option_zip` 등 신규 lint를 못 잡음 → `rustup toolchain install 1.96.0` 후 `cargo +1.96.0 clippy`로 CI 일치 검증(이번 세션 그 lint로 CI 1차 실패→로컬 1.96으로 재현·수정).
- lterm cli_smoke `notify_*cmux*`는 병렬 `CMUX_*` env 경합 flaky → `--test-threads=1` 또는 단독 실행(본 변경 무관).
### PR 상태 (전부 머지, 열린 PR 0)
- understatus: **#9**(ctx fix) · **#10**(repo drift fix) · **#11**(v0.4.0 범프) · **#12**(homebrew 사본 동기화) 전부 merged.
- lterm: **#122**(라우팅 인프라 배선) merged.
### 릴리스 (understatus v0.4.0 — 4채널 라이브 ✅)
v0.3.0 이후 누적분(lterm statusline 통합·codex 심층판독·strip_chain_ctx·ctx fallback/hold·repo drift fix)을 minor bump로 배포 완료:
- **crates.io**: v0.4.0 published(sparse index 확정). **npm**: `understatus@0.4.0`. **GitHub Release**: v0.4.0(arm64+x64 tar.gz+sha256). **Homebrew**: tap `ictechgy/homebrew-understatus` Formula v0.4.0(소스 빌드, 소스 아카이브 sha256 `483672d2…`) + repo 사본 동기화.
- 절차 메모(§C 보강): 태그 push→`release.yml`(macos-14 arm64+x64)→`cargo publish --allow-dirty`(IRREVERSIBLE, credentials.toml 보유)→Homebrew tap 직접 push(별도 PR 불요, formula는 **소스 아카이브** sha256 사용)→npm은 **사용자가 passkey**로 `npm publish ./npm --access public`(에이전트 불가). npm postinstall E2E로 v0.4.0 release 바이너리 수신·ctx 표시 확인.
---
## §0C. 직전 세션 (2026-06-07) — 완료/배경
> 직전 세션의 활성 작업은 §A(Phase 1)가 아니라 아래였다. §A~E는 배경/참고로 보존. 상세 상태는 자동메모리 `lterm-status-default-on`에 누적.
### ✅ 완료 (전부 양쪽 main 머지됨)
1. **Codex 세션 심층판독 (Phase 2-1)** — understatus가 `~/.codex/sessions/**/rollout-*.jsonl` 파싱해 model/ctx%/rate-limit/plan/effort 표시(`--source lterm` + agent=codex). `src/codex.rs`, `[codex]` config(enabled/freshness_minutes/scan_days), `src/claude.rs` 세션/페인 라벨. → **understatus PR #6 머지** (§B-1 완료).
2. **omc ctx 튐 진단·수정** — statusLine(understatus)은 기존 statusLine(omc HUD)을 `[chain]`으로 자식 실행해 합성하는데, 그 **체인된 omc HUD**가 Claude payload `used_percentage` 누락 시 토큰비율로 ctx를 발명해 86↔98로 튐(understatus 자체는 순수통과=무죄, 통제 재현으로 증명). understatus가 체인 출력에서 omc의 ctx 표시만 외과 제거(`[chain] strip_chain_ctx`, 기본 on). `src/chain.rs::strip_chained_context`(ANSI-aware·UTF-8 안전·bar/색/경고줄 처리)+13테스트. → **understatus PR #8 머지**(원래 #7; 스택 머지 중 base 삭제로 auto-close되어 #8 재생성). code-review APPROVE.
3. **lterm status-row 안정화** — content-only 백스톱(`force_content_redraw`): 주기 백스톱이 reserve(DECSTBM)를 재방출→codex scroll-region 침범→입력칸 증식하던 회귀 제거. + self-heal/dedup/cursor-hide. → **lterm PR #121 머지**. **라이브 시각검증 PASS**(다른 cmux 창 갔다 와도 입력칸 깔끔 — 사용자 확인).
4. **cross-env status 백엔드 라우팅 PoC** (lterm #121, **미배선**) — `select_status_backend(policy, &StatusEnvSnapshot) -> StatusBackend`(Disabled/DecstbmOverlay/NativeChrome/DelegatedSurface(Cmux|Tmux)/TitleCueDelegation) 순수 결정함수 + 8 라우팅 테스트. `#[allow(dead_code)]`라 런타임 영향 0.
5. lterm 바이너리: `~/.local/bin/lterm`은 `target/release/lterm` **심볼릭 링크** → 새 빌드가 곧 설치본(새 `lterm a`부터 #121). 데몬 핫스왑 안 됨, 새 attach 필요. status는 **client(attach) 측 렌더**라 데몬 재시작 불필요.
**연구 결론(핵심)**: 일반 터미널 + 메인버퍼 에이전트(codex)에서 **분리형 status 한 줄의 무손상 공존은 원리적으로 불가능**(DECSTBM 단일 전역 자원, host가 에이전트 scroll-region 질의 불가, alt-screen 게이트는 메인버퍼라 무력). best-effort=~50ms 수렴. 안전은 host=터미널(tmux/cmux) 또는 셀 그리드 밖 네이티브(iTerm OSC1337/탭)일 때만 성립.
### ⏭ 다음 세션 이월 — 라우팅 **실제 배선** (PoC만 머지됨)
`select_status_backend`는 결정만, 렌더 배선 미구현. 단계:
- `client.rs` `status_enabled`(~3089) 직후 `select_status_backend` 호출로 분기. PTY rows-1 clamp/reserve는 `DecstbmOverlay`일 때만.
- `StatusBackend` trait(reserve/draw/teardown 3메서드) — 공통 콘텐츠 계약은 기존 `LTERM_STATUS_COMMAND`+stdin JSON(`build_status_payload` v1)+stdout SGR passthrough 재사용(테마/펄스/세션라벨 N분기 방지).
- cmux 배선: attach 경로에서 `open_cmux_split`/`send_cmux_attach`(현재 tmux-compat split 핸들러에서만 호출) 신규 호출.
- **배선 지뢰(반드시 처리)**: ① `real_tmux`는 lterm이 자식에 TMUX를 **스스로 export**하므로 순진한 `$TMUX` 판정 시 오분류 → lterm-injected TMUX 식별해 `real_tmux=false`. ② `tmux_compat::inside_cmux`는 **private** → `pub(crate)` 승격. ③ NativeChrome OSC1337 값은 **base64 인코딩 필수**(`.poc/poc2`처럼) — OSC 인젝션 차단. ④ 멀티라인은 DelegatedSurface(cmux/tmux)에서만, DECSTBM/NativeChrome은 단일라인 격하.
- 배선 후 `.poc/poc2-iterm-status.sh`(iTerm), `.poc/poc3-convergence.md`(수렴+입력칸) 라이브 검증.
### 검증 수치(이번 세션 최종)
- understatus main: 빌드 클린 + **258 테스트**(250+8) 통과.
- lterm main: **581 테스트**(373 unit + 201 cli_smoke + 7 lifecycle) 통과, release 무경고.
- lterm #121 **quad-review-loop**: 4렌즈(정확성/보안/적대적/테스트) + round-2 델타 재검토, **CRITICAL/HIGH/확정블로커 0**, critic ACCEPT.
### PR 상태 (전부 머지/정리됨, 열린 PR 0)
- understatus: **#6**(codex) merged · **#8**(strip, =구 #7) merged.
- lterm: **#121**(status-row 안정화 + 라우팅 PoC) merged · **#120**(self-heal, #121이 supersede) closed.
---
## §A. 배경(Phase 1, 완료) — lterm × understatus statusline 통합
### 목표
Codex CLI는 Claude Code식 **command-backed statusline**(스크립트가 stdin JSON 받고 포맷 텍스트 반환 → 하단 렌더)을 미지원(공식 FR `openai/codex#17827`). 그래서 사용자의 터미널 세션 데몬 **lterm**(tmux 유사, 화면을 소유, `lterm codex` 등 에이전트 래핑 내장)의 하단 status row를 **command-backed로 확장**해, lterm 안에서 도는 모든 에이전트(Codex·Gemini·Claude…)가 에이전트 자체 지원과 무관하게 understatus statusline을 얻게 한다.
**사용법 (양쪽 main에 머지 완료):**
```bash
LTERM_STATUS_COMMAND="understatus render --source lterm --oneline" lterm codex
```
### 현재 상태 = Phase 1 완료, 양쪽 레포 main 머지됨 ✅
- **understatus** (이 레포): **PR #5 머지** → main. `render --source lterm` + `--oneline` 추가.
- `src/claude.rs::parse_lterm_input`(lenient, git 비활성, cwd 표시용, session_key 합성), `src/main.rs` `render --source <claude|lterm>`/`--oneline` 파서 + `run_render_pipeline(source, oneline)`, `tests/oneline.rs`.
- 설계/합의 문서: `docs/superpowers/specs/2026-06-05-lterm-statusline-integration-design.md` (ralplan 합의 APPROVE본 — **Phase 2 백로그는 이 문서 §15**).
- **lterm** (`/Users/jinhongan/Desktop/light_terminal`, 제품=lterm): **PR #119 머지** → main (6커밋 `980c4b5..6a66a33`).
- `src/sanitize.rs`: `sanitize_status_command_line`(신뢰 불가 stdout → **SGR-only 화이트리스트**, C1 CSI 차단, OSC/DCS/미완결 ESC 폐기, 단일행 강제, param `[0-9;:]`만+길이64/개수16 상한) + `truncate_status_line_ansi`(SGR 원자 보존+grapheme/CJK 폭 절단+끝 `\x1b[0m`).
- `src/client.rs`: `StatusCommandConfig`(env), `agent_name_from_command`, `build_status_payload`(serde JSON, 필드 길이 cap), `run_status_command`(셸 미경유 argv spawn, stdin→EOF, **reader 스레드+deadline로 status 스레드 무블로킹**, kill/wait 좀비 회수, 64KB 상한, process_group(0)), `spawn_status_command_thread`/`apply_pending_status_command`(metadata 동형), `StatusBar.command_line`+`draw_at_size` 통합(ANSI=1이면 테마 bg off+understatus 색), `attach` 배선, interruptible sleep, alt-screen pause.
### env/flag (lterm)
| 키 | 기본 | 의미 |
|---|---|---|
| `LTERM_STATUS_COMMAND` | (없음) | 설정 시 status row를 이 명령 출력으로. 미설정 시 기존 동작(세션+페인) **바이트 동일**. |
| `LTERM_STATUS_INTERVAL` | `2` | 초, `1..=3600` 클램프 |
| `LTERM_STATUS_ANSI` | `1` | 색 통과(SGR-only). `0`=strip(plain, 테마 bg 유지). **사용자가 =1 확정**(understatus 색 위주). |
| `LTERM_STATUS_DEBUG` | `0` | `1`이면 명령 실패/타임아웃 stderr 1줄 |
### stdin JSON 계약 (lterm → understatus)
```json
{"source":"lterm","version":1,"session":"codex","pane":"%3",
"session_key":"codex/%3","agent":"codex","cwd":"...","cols":120,"rows":40}
```
- understatus는 lenient: 미상 필드 무시, 빈 `{}` 무패닉. `version`은 읽되 무시(forward-compat). ignored 필드(version/cols/rows/source)는 `serde_json::Value`로 관대 — 타입 드리프트가 전체 파싱을 안 깸.
- **Phase 1에서 git branch 비활성**: understatus git 도출은 `workspace.git_worktree|repo`(워크트리 루트)를 요구하는데 lterm `SessionInfo.cwd`는 세션 시작 dir라 보장 안 됨 → cwd→branch 안 함(`$PWD` 폴백 코드 없음). git은 Phase 2(walk-up).
### 검증 (이번 세션, 양쪽 독립 확인)
- understatus: clippy `-D warnings` 클린, fmt 클린, 테스트 **205**, E2E OK.
- lterm: clippy 클린, fmt 클린, 단위 **352**, release 빌드, **라이브 PTY E2E PASS**(3회 — 실제 attach 화면 status row에 understatus truecolor 출력 `· mem 48% · disk 77% …`).
- 양쪽 **quad-review-loop SUCCESS**(4모델 교차검증). lterm R1에서 **실제 subprocess HIGH blocker**(stdin write/stdout read_to_end 무한 블로킹)를 적발·수정한 게 핵심 성과.
---
## §B. Phase 2 (다음 세션 — 선택, 우선순위순)
spec `docs/superpowers/specs/2026-06-05-lterm-statusline-integration-design.md` §15 참조.
1. ~~**Codex 세션 심층판독**~~ ✅ **완료**(§0-1, understatus #6 머지). `src/codex.rs`로 `~/.codex/sessions/**/rollout-*.jsonl` 파싱→model/ctx%/rate-limit/plan/effort.
2. **git branch**: `--source lterm`에서 cwd→`.git` walk-up(워크트리 루트 도출) 또는 payload에 `git_worktree` 추가.
3. **`mode=pane`** (split, full truecolor 다행): **연구 완료**(§0 연구결론, 메모리 §A). cmux=ghostty 기반 GUI 멀티플렉서, 별도 surface=ghostty PTY라 scroll-region 충돌 **구조적 부재**, lterm 이미 cmux 통합(`open_cmux_split`/`send_cmux_attach`) 보유 → 라우팅 배선(§0 이월)의 `DelegatedSurface(Cmux)` 트랙으로 구현. "OMX HUD-watch 재사용"은 실체 없음(omx HUD엔 ctx 요소 자체 없음).
4. **TOML `[status]` config** + `lterm attach --status-command` CLI 플래그(현재 env-only). lterm에 config 로더·`toml` 의존 없음 → 신설 필요.
5. **다중 에이전트 세그먼트**(Gemini/OpenCode 등 전용 표시).
6. **lterm 잔여 LOW**(비차단, quad-review 문서화됨):
- `build_status_payload`가 daemon의 `info.agent_name`(protocol.rs/server.rs) 대신 `info.command` 재파싱 → daemon값 우선 사용.
- reader 스레드 detach가 자손-stdout-점유 시 leak 가능 → 완전 해결은 process **group-kill**(`kill(-pgid)`, libc/nix 의존 필요) = Phase 2.
- `split_sgr_and_text`는 살균 출력 전제(docstring 명시) — pub/재사용 시 주의.
- status row 테마 bg 옵션화(ANSI=1에서도 bg 유지 선택), spawn 실패 백오프.
---
## §C. 배경 — understatus v0.3.0 (이미 출시됨)
> 제품은 **v0.3.0가 4채널 모두 라이브**. 위 statusline 작업은 그 위에 얹은 미릴리스 기능(아직 새 버전 안 냄 — 릴리스하려면 §C 릴리스 절차).
- **GitHub(공개):** https://github.com/ictechgy/understatus (default `main`).
- **lterm GitHub:** https://github.com/ictechgy/light_terminal (default `main`). Homebrew: `brew install ictechgy/tap/lterm`.
- **understatus 채널(전부 v0.3.0 라이브):** crates.io(`cargo install understatus`), Homebrew(`ictechgy/understatus/understatus`), npm(`understatus`), GitHub Release.
- **언어/플랫폼:** Rust 2021, **macOS only**(arm64+Intel). understatus build.rs는 IOKit+CoreFoundation 링크.
### ⚠️ Auth (지난 세션에 물림)
- **`gh` 토큰 만료 가능**. `gh auth status`가 invalid여도 `git push`(osxkeychain)·일부 `gh` API는 동작할 수 있음. `gh` 실패 시 `gh auth refresh -h github.com`(브라우저 — 에이전트 불가, 사용자에게). **이번 세션엔 gh 정상**이었음(PR #5/#119 생성·머지 성공).
- **npm publish/deprecate는 브라우저 passkey(EOTP) 필요** — 에이전트 일반적으로 불가.
### understatus 릴리스 절차 (v0.3.x+, 새 버전 낼 때)
1. **3종 버전 범프**: `Cargo.toml`, `npm/package.json`, `npm/install.js`(`const VERSION`) + `cargo build`로 `Cargo.lock` 갱신. 브랜치→PR→**rebase-merge**.
2. `git tag -a vX.Y.Z && git push origin vX.Y.Z` → `release.yml`(macos-14, arm64+x64) 그린 **대기 후** `cargo publish --allow-dirty`(IRREVERSIBLE).
3. Homebrew tap `Formula/understatus.rb` url+sha256 갱신(`curl -L <archive> | shasum -a 256`), repo `homebrew/understatus.rb` 사본 동기화(별도 PR).
4. npm: 로컬 `npm install ./npm --prefix /tmp/test` E2E 후 **사용자**가 `npm publish ./npm --access public`.
---
## §D. 이번 세션에서 배운 것 (반복 회피)
- **워크플로**: brainstorming → ralplan(합의) → spec → 청크 단위 구현(executor) → quad-review-loop → 머지. 효과적이었음. ralplan/quad-review가 **코드 사실 불일치·실제 보안 blocker를 잡음**(예: understatus가 cwd로 git 도출 안 함; lterm subprocess 타임아웃이 전체를 못 막음).
- **agy(Antigravity)**: 리뷰형 프롬프트 **~8KB 초과 시 hang** → 큰 diff에선 매번 SKIP(정상). 가용 3트랙(Claude+Codex+Forge)으로 합의.
- **Forge(forgecode)**: 큰 프롬프트에서 **구조화 출력 없이 reasoning 스트림만** 내는 경우 많음 → verdict/JSONL 없으면 **폐기**(합의에서 제외). flaky.
- **executor 장시간 태스크**: 매우 긴 단일 태스크에서 **API 소켓 에러로 중단**된 사례 있음 → 큰 작업은 **청크로 분할**(lterm은 3청크: 게이트→플러밍→draw통합)하면 안정적. 중단 시 부분 변경 확인 후 직접 마무리 가능.
- **lterm status bar는 attach 클라이언트가 그리는 chrome** → `lterm logs`/`capture`(scrollback)엔 안 나옴. 관측하려면 **실제 PTY attach** 필요(python `pty.fork` 하니스로 캡처 → 출력에 `mem`/`disk`+`\x1b[38;2;` 있으면 렌더 성공).
- **lterm AGENTS.md/HANDOFF.md는 gitignored**(로컬). 검증 스위트: `cargo fmt -- --check`/`cargo clippy --all-targets -- -D warnings`/`cargo test`/`cargo build --release --locked`/`cargo audit`. **의존성 추가는 정당화 필요**(group-kill용 libc 등은 신중히).
- **quad-review-loop blocker 기준** = severity HIGH+ AND consensus(≥2 트랙). MEDIUM/LOW는 루프를 안 멈추지만, 사용자는 실제 MEDIUM도 고치는 걸 선호(이번에 다 반영).
---
## §E. 빠른 상태 확인
```bash
# understatus (이 레포)
cd /Users/jinhongan/Desktop/status_ticon/statusticon
export PATH="$HOME/.cargo/bin:$PATH"
git log --oneline -8 # main: cmux pills #13(rebase) + v0.4.0 범프(#11) ...
cargo test # 310+13 통과
grep '^version' Cargo.toml # 0.4.0 (cmux pills는 미릴리스 누적분 — 배포는 §C)
echo '{"source":"lterm","session":"codex","pane":"%3","cwd":"'$PWD'"}' \
| COLORTERM=truecolor ./target/release/understatus render --source lterm --oneline | cat -v
# lterm
cd /Users/jinhongan/Desktop/light_terminal
export PATH="$HOME/.cargo/bin:$PATH"
git log --oneline -5 # main: Merge #123(af59ab9, cmux pills 실렌더) + 라우팅 배선 #122
cargo test --bin lterm # 417 통과. cli_smoke는 cmux env 경합 flaky → --test-threads=1
# CI는 stable 1.96: 로컬은 `rustup toolchain install 1.96.0` 후 `cargo +1.96.0 clippy --all-targets -- -D warnings`로 일치 검증
# 라이브 E2E: LTERM_STATUS_COMMAND="<understatus 절대경로> render --source lterm --oneline" lterm codex
# 입력칸 fix 시각검증: ~/.local/bin/lterm(=target/release 심볼릭) 새 attach로 codex 띄우고 cmux 창 전환→복귀
```