메인과 자식은 연결되어 있지만, 각각의 종료 시점은 다릅니다.
가재코드,
안에서 무슨 일이
일어날까?
하나의 대화 뒤에는 메인 실행, 하위 에이전트, 질문, 백그라운드 작업이 있습니다. 이들의 상태를 구분해야 키보드의 불빛도 정확해집니다.
어떤 단위가 끝났는지부터 확인해야 합니다.
현재 스냅샷과 시간 순서의 사건은 서로 보완합니다.
먼저 01의 노드를 눌러 보고, 03에서 ‘부모 응답 종료’를 재현해 보세요. 코드 기준: 2026-09-06 조사 · f50b17a
GJC의 중심은 AgentSession입니다
사용자 요청을 실행하고, 발생한 이벤트를 여러 소비자에게 전달합니다. 아래 지도는 주요 상태 전달 경로입니다. 화살표는 관계를 나타내며 모든 내부 호출을 그린 것은 아닙니다.
AgentSession
한 대화 세션의 실행을 조정합니다. 로컬 이벤트 전달과 상태 파일 쓰기를 분리하므로 파일 쓰기가 늦거나 실패해도 대화형 실행이 반드시 멈추는 것은 아닙니다.
키크론의 관점: 현재 실행을 가장 가까이에서 관찰할 수 있는 지점입니다.
코드 근거 열기 ↗‘기능 수정하고 테스트해줘’를 따라가 볼까요?
다음 단계를 눌러 이벤트를 한 개씩 진행하세요. 중요한 차이는 turn_end와 agent_end입니다.
아직 실행 전
사용자 입력 대기터미널과 세션은 살아 있습니다. 에이전트가 일을 하지 않는 것과 프로세스가 종료된 것은 다릅니다.
turn.completed와 Agent runtime의 turn_end는 다릅니다. 전자는 관리하는 요청의 완료이고, 후자는 모델 응답 한 번과 도구 결과의 끝입니다.agent_end도 성공이 아닐 수 있나요?
네. 종료 사유는 completed, paused, cancelled, maintenance 등으로 나뉩니다. 실패 진단과 유지보수 결과도 확인해야 합니다. 이벤트 이름 하나만 보고 초록색으로 바꾸면 취소와 일시정지도 성공처럼 보일 수 있습니다.
완료된 응답은 목표 달성의 증거인가요?
응답 종료는 실행 경계입니다. 테스트 통과, 목표 달성, 보고 가능한 결과 수령은 별도 의미입니다. 키크론 초록색을 ‘응답 완료’로 정할 수도 있지만 ‘모든 작업 완료’와 같은 뜻으로 설명하면 안 됩니다.
SDK 종료 분류 ↗한 키 안의 여러 에이전트, 직접 바꿔 보세요
여기서는 ‘한 키 = 최상위 세션과 그 자식들’로 묶습니다. 초록색은 메인 정상 종료와 소유 작업의 정리가 모두 확인된 예시입니다. 실제 제품의 최종 표시 정책은 별도 결정 사항입니다.
메인과 두 자식이 실행 중
코드 조사와 구현을 나눠 실행하고, 테스트도 백그라운드에서 돌리고 있습니다.
선은 소유 관계입니다. 원·기호·문구로 상태를 함께 구분합니다. 자식에게 독립 터미널이 있다는 뜻은 아닙니다.
- 메인
- 실행 중
- 조사 자식
- 실행 중
- 구현 자식
- 실행 중
- 백그라운드 작업
- 실행 중
이번 사건과 집계 근거 보기
아래 JSON은 설명용 정규화 모델입니다. 현재 GJC의 실제 wire 형식을 그대로 복사한 것이 아닙니다.
‘자식 완료’는 누구의 완료일까요?
조사 담당이 끝나도 메인이 코드를 쓰고 있을 수 있습니다. 부모 응답이 끝나도 백그라운드 테스트는 계속될 수 있습니다. 따라서 실행 상태, 미해결 질문, 자식·job 상태를 별도 보관합니다.
task:subagent:* 채널 정의 ↗키를 누르면 어디로 가나요?
기본적으로 그 작업을 소유한 메인 세션의 터미널로 이동합니다. 자식은 hasUI:false로 생성될 수 있으므로 ‘자식 하나 = 터미널 하나’가 아닙니다.
어디에 연결해야 상태를 받을 수 있을까요?
‘스트림이 존재한다’와 ‘외부 관찰자가 필요한 모든 상태를 받을 수 있다’는 다른 조건입니다. 수신 경로를 선택해 차이를 확인하세요.
파일 감시는 현재 상태를 다시 읽는 방식입니다
OS 파일 변경 알림을 받아 상태를 읽을 수 있습니다. 다만 파일은 마지막 상태를 담으므로, 읽기 전에 여러 번 바뀐 중간 전이는 사라질 수 있습니다.
마지막으로 저장된 실행 상태와 일부 도구 활동.
전체 사건 순서, 자식 계층, 모든 질문·승인, 정확한 프로세스 생존.
Herdr는 내부 이벤트를 듣습니다
installHerdrReporter( listener => session.subscribe(listener) )
메인 시작·종료와 ask 도구 대기를 외부 앱에 보고합니다. GJC 안에 관찰 어댑터를 두는 구조가 이미 존재합니다.
모든 자식·백그라운드 작업·승인을 처리하는 완성형 어댑터는 아닙니다.
Herdr reporter ↗상태 관찰과 HID 출력을 분리합니다
공개 확장으로 부족한 관찰 지점은 GJC 쪽 추가 구현이 필요할 수 있습니다. 여기서는 네트워크 연결을 실행하지 않습니다.
더 깊이 이해하고 싶을 때
한 번에 다 읽지 않아도 됩니다. 파일의 의미, 식별자, 실패 복구, 현재 키크론의 변경 지점을 필요할 때 펼쳐 보세요.
① .gjc 안에는 무엇이 저장되나요?
조사한 커밋에서 런타임 상태와 SDK 연결 정보는 다른 위치를 사용합니다. 명시적 환경 설정과 실행 모드에 따라 경로가 달라질 수 있습니다. SDK 연결 정보의 직접 소비는 공식 외부 통합 경로로 안내되지 않습니다.
| 필드 | 뜻 | 오해하면 안 되는 것 |
|---|---|---|
state | 마지막으로 기록한 런타임 상태 | 모든 작업을 합친 전역 상태 아님 |
live | 기본 작성 경로는 state === running | 프로세스가 살아 있다는 별도 증거 아님 |
updated_at | 생명주기 상태 기록 시각 | 매초 갱신되는 생존 신호 아님 |
active_tool_count | in-flight 도구 호출 수 | 에이전트 수 아님 |
activity.seq | 도구 활동 변경 순번 | 모든 상태 이벤트의 전역 순번 아님 |
공개 도구 목록은 최대 8개로 제한되지만 개수는 별도로 유지합니다. 파일의 수정 시간이 오래됐다는 이유만으로 세션을 종료 처리하면 긴 도구 실행을 오판할 수 있습니다.
중복 쓰기 제한과 상태 작성 ↗② sessionId, agentId, PID, 터미널 ID가 왜 모두 필요한가요?
각 식별자는 다른 질문에 답합니다. 프로젝트 이름 하나나 PID 하나로 합치면 다른 실행을 같은 작업으로 오인할 수 있습니다.
어디의 코드를 다루는가? 같은 프로젝트에 독립 세션이 여러 개 있을 수 있습니다.
어느 대화 세션인가? 전환·재개·분기와 물리 터미널의 수명은 다릅니다.
어떤 자식이며 누가 소유하는가? 부모의 이벤트 버스 문맥도 함께 유지합니다.
어느 실행의 몇 번째 사건인가? 이전 실행의 늦은 종료가 새 실행을 덮지 않게 합니다.
키를 누르면 어느 화면을 여는가? GJC sessionId만으로 모든 앱의 화면을 찾을 수는 없습니다.
PID는 재사용될 수 있으므로 SDK는 프로세스 incarnation과 endpoint generation 등을 고려합니다. 설명용 시뮬레이터의 runId는 개념 표현이며 실제 SDK 필드명을 통일한 것이 아닙니다.
③ 질문 하나에 답했는데 왜 아직 대기 중일 수 있나요?
질문이 여러 개일 수 있기 때문입니다. 대기 상태는 boolean 하나보다 미해결 질문·승인 ID의 집합으로 보는 편이 정확합니다. 부모와 자식, 로컬 UI와 원격 응답 경로가 서로 다른 대기 상태를 가질 수 있습니다.
AskTool은 실제 TUI가 있으면 로컬 UI를 우선합니다. 원격 answer source가 있으면 로컬·원격 응답을 경합시킵니다. headless에서는 workflow gate 같은 경로를 사용합니다. 답변·취소·시간 초과를 같은 질문에 결속해야 잔여 대기가 남지 않습니다.
ask 도구 시작·종료 추적은 좋은 출발점입니다. 하지만 권한 확인, 확장 UI, 워크플로 승인 전체를 포괄한다고 보장할 수는 없습니다.④ 연결이 끊기면 마지막 상태를 계속 보여주면 되나요?
마지막 상태를 참고 정보로 남길 수는 있지만 ‘현재 확인된 상태’로 보여주면 안 됩니다. 관찰 신뢰도와 작업 상태를 분리해야 합니다.
연결됨 → 사건 수신 → 연결 끊김
↓
현재 상태 확인 불가
↓ 재연결
현재 스냅샷 취득
↓
이후 사건을 순서대로 적용SDK event ring의 기본 보관 크기는 256개입니다. 순번에 gap이 생기면 현재 상태를 다시 맞춰야 합니다. SDK의 (revision, generation, seq)와 Coordinator의 namespace별 seq는 서로 다른 순서 체계입니다.
주기적인 연결 heartbeat와 업무 상태를 반복 조회하는 폴링은 목적이 다릅니다. ‘상태는 이벤트로 받고 연결은 heartbeat로 확인’하는 설계는 가능합니다.
이벤트 보관 및 gap ↗⑤ 같은 프로젝트를 한 키로 묶으면 무엇이 달라지나요?
세션 가족별 배정은 A와 B에 별도 키를 줍니다. 프로젝트 그룹은 A와 B를 한 키 아래에 합칩니다. 후자는 키를 아낄 수 있지만 어떤 세션의 상태인지 한눈에 구분하기 어렵고, 키 입력 시 이동 우선순위와 순환 규칙이 필요합니다.
03의 체크박스를 켜면 세션 A가 끝나도 같은 프로젝트의 B가 실행 중이라 초록색이 되지 않습니다. 그룹의 ‘완료’를 어떻게 정의하느냐에 따른 차이입니다.
작업공간의 개발 티켓은 최상위 GJC 세션별 키 배정과 Orca 터미널 이동을 기술합니다. 이 HTML의 프로젝트 그룹은 비교 학습용이며 확정된 추가 기능이 아닙니다.
⑥ 현재 키크론 코드에서 무엇을 재사용하나요?
| 영역 | 현재 코드 | GJC 적용 시 |
|---|---|---|
| 장치 제어 | keychron_hid.py | LED 출력과 조명 원복 재사용 후보 |
| 상태 수집 | orca_status.py | GJC 상태 스트림 어댑터 추가 |
| 실행 루프 | indicator.py | 수신 큐와 렌더 주기를 분리 |
| 그룹 집계 | worktree_tracker.py | 워크트리 대신 세션·자식 계층 추적 |
| 키 입력·이동 | digit_hold.py / orca_navigation.py | 세션을 정확한 Orca pane에 연결 |
현재 키크론은 작업 중=노랑, 응답 대기=주황, 오류=빨강, 완료=초록, 혼합=자홍, 유휴=하늘색을 사용합니다. 현재 집계는 done + working을 done으로 표시합니다. 03의 소유 작업 전체 집계는 새로운 정책 제안입니다.
현재 macOS 입력 조건은 Orca가 앞에 있을 때의 Option+숫자입니다. 단순히 GJC 데이터 소스만 바꾸면 입력과 화면 이동의 연결까지 자동으로 바뀌지 않습니다.
메인이 끝났고 테스트 자식이 실행 중입니다.
‘소유 작업 전체 완료’를 알리는 초록색은 언제 켜야 할까요?
선택하면 이유를 확인할 수 있습니다.
이 HTML에서 확실히 구분한 것
코드 근거를 직접 열어 보기
모든 링크는 조사한 커밋으로 고정했습니다. 본문은 관련 실행 경로를 교차 조사한 해설이며 저장소 전체 파일의 전수 검증은 아닙니다.
메인과 상태 전달
로컬 전달, 확장 이벤트, 비동기 sidecar 쓰기의 경계.
session/agent-session.ts ↗런타임 스냅샷
상태 변환, active tools, updated_at 의미.
gjc-runtime/session-state-sidecar.ts ↗하위 에이전트
부모 eventBus로 lifecycle과 progress를 전달.
task/executor.ts ↗소유 작업의 생명주기
running, queued, paused와 terminal 상태 구별.
async/job-manager.ts ↗SDK streaming 범위
해당 실행의 소유 연결로 콘텐츠 이벤트를 전달.
sdk/host/session-runtime.ts ↗Coordinator 전송 계약
롱폴링, Webhook, 순번·중복·재시도.
docs/hermes-mcp-bridge.md ↗