에이전트 감지
MadoHub이 실행 중인 AI 에이전트를 식별하고 상태를 추적하는 방법입니다.
MadoHub은 터미널 출력을 실시간으로 모니터링하여 어떤 AI 에이전트가 실행 중인지, 그리고 현재 상태가 어떤지를 감지합니다. 이 정보는 타일 제목 표시줄의 시각적 표시와 라우팅 연결 트리거에 사용됩니다.
지원하는 에이전트
Claude Code
터미널 출력에 있는 유니코드 마커로 감지합니다:
| 마커 | 의미 |
|---|---|
| ❯ (U+2770) | Claude Code 프롬프트 |
| ✽ (U+273D) | 생각 중 / 스피너 |
| ⏺ (U+23FA) | 도구 사용 표시 |
출력에 있는 문자열 "Claude Code"도 함께 매칭합니다.
OpenAI Codex CLI
다음 패턴으로 감지합니다:
OpenAI Codex— 브랜딩 라인codex>— TUI 프롬프트openai/codex— 패키지 참조codex v[0-9]— 버전 문자열> _ OpenAI Codex— 시작 배너codex --dangerously— 샌드박스 우회 플래그 (대소문자 구분 없음)codex...fast— 고속 모델 호출 (대소문자 구분 없음)gpt-[0-9.]+ x?high— 모델 정보
Amp와 OpenCode
Amp와 OpenCode 역시 에이전트 종류로 인식되지만, 위의 프런트엔드 터미널 텍스트 스니퍼로 인식되는 것은 아닙니다. 이 스니퍼는 Claude Code, Codex, 일반 셸만 분류합니다. Amp와 OpenCode 세션은 별도로, 백엔드의 프로세스 트리 스캔을 통해 식별됩니다. 이 스캔은 터미널의 자식 프로세스들을 순회하며 해당 실행 파일을 찾습니다.
일반 셸
에이전트 마커가 감지되지 않으면 터미널은 일반 셸 세션으로 처리됩니다.
에이전트 상태
MadoHub은 각 터미널에 대해 일곱 가지 상태를 추적합니다:
| 상태 | 감지 기준 | 시각적 표시 |
|---|---|---|
| 작업 중 | 상태 표시줄의 "esc to interrupt", 또는 ✽/⏺와 말줄임표 | 초록색 펄스 테두리 |
| 유휴 | 상태 표시줄의 "? for shortcuts" | 표시 없음 |
| 대기 중 | "Allow once" / "Allow always" / "Deny" / "Do you want to proceed?" / "(y/n)" / "requires approval" 대화상자 | 주황색 테두리 |
| 중지됨 | 터미널 스크레이핑으로 완료 키워드 감지 (모호함 — 작업이 성공적으로 끝났는지 아닌지는 알 수 없음) | 빨간색 표시 |
| 완료됨 | 확정된 성공 종료. 에이전트 자체의 JSONL/DB 세션 로그에서 파싱함 (예: Codex의 task_complete) | 초록색 표시 |
| 실패함 | 확정된 실패. 에이전트 자체의 JSONL/DB 세션 로그에서 파싱함 (예: Codex의 turn_aborted / error) | 빨간색 표시 |
| 종료됨 | 하부 PTY 프로세스가 더 이상 존재하지 않음 (종료 상태) | 회색/흐린 표시 |
각 상태에는 pty-scrape 또는 jsonl-watcher 중 하나의 stateSource 태그가 붙어, UI(및 라우팅 로직)가 "터미널 실시간 스크레이핑으로 추측한 것"과 "에이전트 자체 세션 기록을 읽어 확정한 판정"을 구분할 수 있게 합니다. "중지됨"은 항상 pty-scrape이며 본질적으로 모호합니다. 반면 "완료됨"과 "실패함"은 jsonl-watcher에서 나온 것으로, 확정적인 것으로 취급됩니다.
완료 감지
MadoHub은 고정된 단어 목록이 아니라 형태(shape) 일치로 에이전트의 작업 완료를 감지합니다: 줄 시작의 스피너 기호 뒤에 대문자로 시작하는 과거형 동사가 오고, 그 뒤에 " for "와 지속 시간이 오는 형태입니다.
정규식 패턴:
/(?:^\s*[✶✽✳✢·∗*]\s*([A-Z][a-zé]+(?:ed|t))|\b(Saut[ée]*d|Cogitated))\s+for\s+(?:\d+\s*[hm]\s*)*\d+\s*[hms]\b/Claude Code는 릴리스마다 동사를 바꿔가며 사용합니다 (Worked, Churned, Sautéed, Cogitated 등). 그래서 동사 자체는 의도적으로 열거 가능한 목록으로 만들지 않았으며, 대신 형태를 기준으로 매칭합니다. 실제로 일치하는 예시는 다음과 같습니다:
✽ Worked for 2m 30s줄 시작의 기호 앵커(✶✽✳✢·∗* 중 하나)가 바로 "Retried for 3s"와 같은 일반 문장을 잘못 감지하지 않게 막아주는 핵심입니다. Sautéed와 Cogitated가 이 패턴에 남아 있는 것은, 기호 앵커 방식 이전의 구형 CLI 출력을 위한, 기호 없는 레거시 폴백으로서일 뿐입니다.
완료가 감지되면 에이전트 상태가 "중지됨"으로 바뀌고, 연결된 라우팅 트리거가 실행될 수 있습니다.