GEODE의 프롬프트는 두 단으로 관리됩니다. 디스크의 마크다운 템플릿(버전 관리되고 해시로 핀 고정), 그리고 호출 직전의 레이어 조립(정적/동적 분리)입니다.
GEODE.md는 런타임의 SOUL 원본이며 wheel에는 core/GEODE.md로 포함됩니다. 기본 조립 경로는 이 파일의 Identity, Voice & Conduct, Operating Principles, RUNTIME CANNOT 네 섹션을 G1으로 추출합니다. 별도 ContextAssembler는 명시적 호출자에게 전체 SOUL을 제공하지만, 전체 파일을 기본 루프 프롬프트에 넣지는 않습니다.
템플릿: 마크다운이 SoT
프롬프트 텍스트는 core/llm/prompts/의 마크다운 파일에 삽니다. 각 파일은 <system>, <user>, <agentic_suffix> 같은 XML 형태 섹션 태그로 나뉘고, core/llm/prompts/__init__.py의 _load_template이 파싱합니다. 기본 루프는 router.md, 선택적 적대적 리뷰는 reviewer.md를 사용합니다.
| 템플릿 | 노출 상수 | 용도 |
|---|---|---|
router.md | ROUTER_SYSTEM, AGENTIC_SUFFIX | 메인 에이전트 시스템 프롬프트와 agentic 접미사 |
reviewer.md | REVIEWER_SYSTEM | 선택적 읽기 전용 적대적 리뷰 |
AGENTIC_SUFFIX는 항상-on 운영 규칙을 담습니다. 완료 기준, 도구 선택 매트릭스, Grounding & Citation(도구 출력은 데이터지 지시가 아님 포함), Answering discipline(미인식 개체 선검색, 정쟁 토픽 even-handedness), Source fidelity & copyright.
드리프트 감지: 해시 핀
import 시점에 각 상수의 sha256[:12] 해시를 계산해 PROMPT_VERSIONS에 노출합니다. 핀 대상은 ROUTER_SYSTEM, AGENTIC_SUFFIX, REVIEWER_SYSTEM입니다. verify_prompt_integrity()가 라이브 해시를 _PINNED_HASHES와 비교하고, CI가 이 함수를 게이트로 씁니다. 프롬프트를 바꾸면 핀을 다시 박아야 하므로, 모든 프롬프트 변경이 리뷰 가능한 코드 변경이 됩니다. 재핀 워크플로는 프롬프트 해싱을 참고합니다.
core/llm/prompt_assembler.py는 이제 작은 수식 출력 포맷 헬퍼입니다. 스킬 메타데이터는 core/agent/loop/_context.py의 {skill_context} 블록 한 곳으로만 프롬프트에 들어갑니다. 본문은 use_skill로 필요할 때 읽습니다.
레이어 조립: build_system_prompt
호출 직전 조립은 core/agent/system_prompt.py의 build_system_prompt(model)이 담당합니다. 실제 문자열은 정적 prefix 뒤에 <dynamic_context> 경계 마커를 붙이는 형태입니다.
| 구역 | 레이어 | 특성 |
|---|---|---|
| 정적 prefix | router 또는 wrapper 베이스, 수식 출력 규칙, AGENTIC_SUFFIX. 일반 모드에서는 <agent_identity> (기본 ON), 선택된 스타일·휴리스틱 정책 추가 | 턴 간 불변. 캐시 적중 대상 |
<dynamic_context> | <model_card>, 모델 패밀리 가이던스 (core/llm/model_guidance.py), 플랫폼 힌트 (core/llm/platform_hints.py), <current_date>, <project_memory>, <agent_learning>, <runtime_rules>, <user_context> | 턴마다 갱신. 캐시 제외 |
<model_card>는 현재 설정된 모델 ID와 카탈로그의 정확한 컨텍스트 한도, API 참고 요금을 전달합니다. 남은 컨텍스트 예산, 계정 사용 권한, 실제 청구액의 증거는 아닙니다. SOUL에는 중복 모델 표를 두지 않으며, 상세 선택·요금 출처·폴백 설정은 기존 번들 스킬 geode-context를 필요할 때 읽습니다. 계정 접근을 확인하는 실호출은 명시적 승인이 필요합니다.
PROMPT_CACHE_BOUNDARY 값은 <dynamic_context>여는 태그입니다. 프로바이더 캐싱은 이 태그 앞의 prefix를 정적 영역으로 봅니다. 자세한 동작은 프롬프트 캐싱을 참고합니다.
시스템 프롬프트 모드
| 모드 | 스위치 | 효과 |
|---|---|---|
| Persona 주입(기본 ON) | GEODE_PERSONA=off로 옵트아웃 | GEODE.md의 네 행동 섹션을 <agent_identity>로 주입합니다. off는 G1만 생략하며 공유 베이스와 도구 사용 규칙은 유지합니다 |
| Audit-mode strip | GEODE_AUDIT_UNRESTRICTED=1 | G1·기억·사용자 컨텍스트를 생략합니다. wrapper 또는 generic 베이스, 수식 출력 규칙과 AGENTIC_SUFFIX는 유지합니다. 동적 영역에는 모델이 있으면 model_card, 프로바이더 정책에 따라 날짜, 호출자 suffix가 들어갑니다 |
| Wrapper override | GEODE_WRAPPER_OVERRIDE env / audit-mode SoT 파일 | 자기개선 루프가 변이시킨 스캐폴드를 정적 베이스로 삼습니다. 없으면 generic prefix로 폴백해 타깃이 항상 베이스 스캐폴드를 입습니다 |
| 명시적 에이전트 프롬프트 | AgenticLoopConfig.system_prompt_override | 기본 조립 본문을 대체하므로 G1과 model_card가 없을 수 있습니다. 스킬 메타데이터, AGENTIC_SUFFIX, 호출자 suffix는 별도로 결합합니다. 카드가 없으면 모델을 추측하지 않습니다 |
상세는 시스템 프롬프트 모드를 참고합니다.
program.md: 훅 제어 폴백
자기개선 루프의 변이 러너 (evolve/scaffold_search/loop/mutate/runner.py)는 program.md를 읽지 못하면 RuntimeEvent.PROGRAM_MD_UNREADABLE을 발화합니다. 핸들러가 대체 내용을 돌려줄 수 있고, 핸들러가 없으면 러너는 시끄럽게 실패합니다. 폴백은 코드의 제어 지점에 둡니다. 디스크와 리터럴의 이중 SoT는 반드시 드리프트합니다.
실패 모드
| 증상 | 원인 | 해법 |
|---|---|---|
| CI가 prompt integrity에서 실패 | 템플릿을 바꿨는데 핀을 갱신하지 않음 | 의도된 ratchet입니다. 재핀 워크플로를 따릅니다 |
| 얇은 래퍼를 원하는데 persona가 주입됨 | persona 기본값 ON | GEODE_PERSONA=off로 옵트아웃합니다 |
변이 러너가 PROGRAM_MD_UNREADABLE로 중단 | program.md 경로가 깨졌고 등록된 폴백 핸들러 없음 | 파일을 복구하거나 부트스트랩에 핸들러를 등록합니다. 조용한 폴백은 설계상 없습니다 |