GEODE는 두 프로세스로 삽니다. 사용자가 만지는 thin CLI와 모든 런타임을 소유한 serve 데몬입니다. 데몬이 부트되는 순서, 호스팅하는 것, 내려가는 순서를 코드 기준으로 따라갑니다.
부트: thin CLI에서 데몬까지
geode (thin CLI) │ 1. 소켓 probe: ~/.geode/cli.sock 살아 있나 │ 2. 없으면 cli.startup.lock flock 잡고 │ "geode serve"를 detached로 spawn (최대 30초 대기) │ 3. client_capability 핸드셰이크 (TTY 여부, 터미널 폭) ▼ geode serve (데몬) ← 하나의 GeodeRuntime이 전부 소유
자동 시작은 start_serve_if_needed(core/cli/ipc_client.py)가 담당합니다. pidfile flock으로 동시 실행된 thin CLI 여러 개가 데몬을 중복으로 띄우지 않게 막습니다. 데몬은 시작 직후 상속받은 환경에서 모델 선택류 behavior 키를 떨어뜨립니다 (core/cli/bootstrap.py의 load_daemon_env). 그래서 /model의 toml 쓰기가 데몬 수명 내내 이깁니다.
주입 순서
데몬 안에서 GeodeRuntime(core/runtime.py)이 인프라 싱글톤을 만들고, 구현은 core/wiring/으로 위임됩니다. 무거운 모듈 트리는 해당 컴포넌트가 실제로 쓰일 때 lazy하게 로드됩니다.
| 단계 | 만드는 것 | 코드 |
|---|---|---|
| 1 | HookSystem + SQLite event sink. 모든 프로덕션 훅과 teardown이 여기서 등록됩니다. | core/wiring/bootstrap.py |
| 2 | PolicyChain, ToolRegistry, LaneQueue, 인증 스토어 | core/wiring/container.py |
| 3 | TriggerManager + SchedulerService | core/wiring/scheduling.py |
| 4 | MCP, 알림, 캘린더, 게이트웨이 어댑터 | core/wiring/adapters.py |
세션 생성은 SharedServices.create_session(mode)(core/server/supervised/services.py) 한 곳으로 수렴합니다. REPL, IPC, DAEMON, SCHEDULER 네 모드가 같은 배선의(ToolExecutor, AgenticLoop) 쌍을 받고, 모드는 HITL 레벨과 time budget 같은 기본값만 바꿉니다.
배선 불변식 하나가 이 단계 전체를 지배합니다. 핸들러가 존재한다고 발화하지 않습니다. 훅 핸들러는 bootstrap에 등록되어야 하고, get_*() ContextVar 액세서는 대응하는 set_*()가 있어야 합니다. poller 데몬 스레드는 boot.propagate_to_thread()로 ContextVar를 다시 주입받습니다(core/cli/bootstrap.py).
데몬이 호스팅하는 것
- CLI IPC 서버 (
core/server/ipc_server/poller.py). thin CLI의 자유 텍스트와 슬래시 명령 처리. - 메신저 poller와 게이트웨이 (
core/server/supervised/,core/messaging/binding.py). - SchedulerService. 부팅 시 저장 작업 로드와 놓친 발화 복구, serve 루프에서 drain.
- 옵션 webhook HTTP 엔드포인트 (
settings.webhook_enabled).
종료 순서
순서가 곧 안전입니다. 새 요청을 먼저 끊고, 하던 일을 마치게 하고, 상태를 저장한 뒤 연결을 닫습니다 (core/cli/typer_serve.py).
1. HookEvent.SHUTDOWN_STARTED 발화 2. IPC 소켓 닫기 (신규 클라이언트 차단) 3. 활성 세션 drain (최대 30초) 4. 스케줄러 save + stop 5. MCP 종료 6. 게이트웨이 정지
실패 모드
| 증상 | 원인 | 해법 |
|---|---|---|
| 업데이트했는데 옛 동작이 계속됨 | 오래된 데몬이 살아남아 소켓을 점유 | pkill -f "geode serve" 후 재진입합니다. geode update는 이 재시작을 대신 해줍니다. |
geode serve 시작 거부 | gateway_enabled 꺼짐 | 헤드리스 데몬이 필요할 때만 GEODE_GATEWAY_ENABLED=true를 켭니다. |
| 기능이 조용히 동작하지 않음 | 핸들러 미등록 또는 ContextVar 미주입 | bootstrap 등록 여부를 먼저 봅니다. core/wiring/bootstrap.py의 get_plugin_status()가 플러그인별 등록 상태를 보고합니다. |
다음
- 데몬으로 실행. 운영 관점의 시작과 정지.
- Serve와 게이트웨이. 데몬이 호스팅하는 메신저 경로.
- 훅 등록. bootstrap 등록이 필수인 이유.