adapter 경계 위의 orchestration
framework 는 brain stem 을 건드리지 않게 설계됐고, 실제로도 거의 안 건드려. backend/adapters/claude.py 가 얻은 건 StatefulTask 와 checkpoint 되는 web 도구를 여는 MCP 배선, 그리고 receive loop 안에서 show_widget render 를 흘러가는 동안 저장하는 호출 하나야. 나머지는 전부 adapter 경계 위에 orchestration 으로 앉아, rules track 이 가르친 세 아키텍처 규칙을 지키면서. Claude 모양, 좁은 adapter 경계, 비용은 downstream 흡수.
어디 살아? Family Council 이 옵션 셋을 재고 둘을 거절했어. standalone service 는 external-client 패턴을 되살려 (영혼은 집의 root user 지 client 아냐). 기존 service 에 inline 하면 monolith 를 부풀려. 답: 코드베이스 안 의 새 backend/stateful/ 모듈이야. 두뇌들은 REST API 가 아니라 도구 로 닿아. Claude 의 MCP 서버와 변형마다의 로컬 도구 bridge 를 거치는 StatefulTask. REST 로 열린 건 frontend 진행 패널이 쓰는 읽기 전용 상태 목록 하나뿐이야. 대화와 state는 한 몸이야. state를 codebase 밖으로 옮기는 순간 이미 두 몸이 돼.
hexagonal kernel
모듈은 ports-and-adapters kernel 이라, 모든 surface 에 느슨하게 묶이면서 swappable 하고 독립 testable 하게 유지돼. kernel 은 순수하고, 판단 전체가 함수 두 개에 들어 있어. next_unfinished_step(task) 가 done 도 failed 도 아닌 첫 step 을 고르고, resume_decision(step) 이 그 step 을 돌릴지, side effect 라 막을지, attempt cap 이 다 돼서 실패시킬지, 이미 끝난 step 이라 그냥 둘지 정해. 기록 타입과 artifact class 는 옆의 models.py 에 있어. FastAPI 없음, chat 없음, council 없음, provider SDK 없음. 그 둘레에 port 가 셋 있어. TaskStore (atomic lease 도 여기 있어), ArtifactStore, ToolRunner. 각각 앞 lesson 의 storage, taxonomy, lease, side-effect bracketing 에 매핑돼.
Executor checkpoint — 진짜 surface 는 tool executor 야
구현 surface 는 provider 모양이 아니라 executor 모양이야. model은 Polygon이나 Nano Banana를 framework port로 직접 부르지 않아. 대신 cwkPippa의 tool executor를 불러. 여기에는 Connector, WebSearch, WebFetch, Firecrawl tools, Bash, show_widget이 들어 있어. 그것들이 stateful 인식 adapter 가 돼. running step 이 active 일 때, executor 가 기존 tool 을 돌리고, raw 결과를 step artifact 로 즉시 persist 하고, step 을 done 마킹하고, lease 를 풀고, 그제서야 결과를 손대지 않은 채 model 에 돌려줘. checkpoint 를 밝히는 footer 를 붙여서, model 이 같은 호출을 되풀이하지 않고 다음으로 넘어가게 하지. provider call 은 성공했는데 model 이 commit 전에 끊기는 틈을 그게 닫아.
견고하게 만드는 다듬기 둘. 첫째, auto-checkpoint: model 이 volatile provider 작업 전에 task 시작을 깜빡하면, 결과를 바닥에 흘리는 대신, 결과가 도착하면 executor 가 single-step checkpoint 를 자동으로 만들어. Connector, WebSearch, WebFetch, Firecrawl 도구들, show_widget 이 대상이고, Bash 는 출력이 artifact 파일을 밝혔을 때만이야. 평범한 local tool (Read, Write, Edit) 은 fast path 그대로 둬. 둘째, replay-skip guard: 재사용 가능한 도구를 다시 돌리기 전에, executor 가 같은 대화에서 같은 effective tool 이름과 정확히 같은 input 의 완료된 checkpoint 를 찾아. 한 시간 안(Class 2 로 표시된 step 이면 하루 안)의 것이어야 해. 찾으면 저장된 artifact 를 돌려주고 provider call 을 건너뛰어. 재사용 대상은 Connector, WebSearch, WebFetch, Firecrawl 의 scrape·map·crawl-start, 그리고 Bash 야. show_widget render 와 crawl 상태 조회는 checkpoint 는 되지만 재사용은 절대 안 해. 원래 바뀌어야 하는 거니까. 그 시간을 넘으면 read_artifact 로 저장된 snapshot 을 나이 제한 없이 읽을 수 있어. resume 이 공인된 길이고, 재사용 guard 는 replay 방패일 뿐이야. 동일 replay 는 executor 의 일이지 model 판단이 아니고, 이 guard 덕분에 Claude mid-turn-cut auto-retry 를 다시 켤 가치가 생겼어(기본 세 번). retry 가 끝난 pull 을 더 이상 버리지 않으니까.