OpenClaw 세션 관리 및 압축 가이드: 데이터 최적화 전략
신뢰의 원천: Gateway
섹션 제목: “신뢰의 원천: Gateway”OpenClaw는 세션 상태를 소유하는 단일 Gateway 프로세스를 중심으로 설계되었어요.
- UI(macOS 앱, 웹 Control UI, TUI)는 세션 목록이나 토큰 수를 확인할 때 Gateway에 쿼리해야 해요.
- 원격 모드에서는 세션 파일이 원격 호스트에 저장되기 때문에, “로컬 Mac 파일”을 확인해도 Gateway가 실제로 사용하는 데이터를 반영하지 못해요.
두 개의 영속성 레이어
섹션 제목: “두 개의 영속성 레이어”OpenClaw는 세션을 두 가지 레이어로 나누어 저장해요.
-
Session store (
sessions.json)sessionKey -> SessionEntry형태의 Key/value 맵이에요.- 크기가 작고 수정이 가능하며, 직접 편집하거나 항목을 삭제해도 안전해요.
- 현재 세션 ID, 마지막 활동, 토글, 토큰 카운터 같은 세션 메타데이터를 추적해요.
-
Transcript (
<sessionId>.jsonl)- 각 항목이
id와parentId를 가지는 트리 구조의 추가 전용(Append-only) Transcript 파일이에요. - 실제 대화 내용, tool calls, Compaction 요약본을 저장해요.
- 나중에 모델의 컨텍스트를 재구성할 때 사용해요.
- 각 항목이
디스크 저장 위치
섹션 제목: “디스크 저장 위치”Gateway 호스트의 에이전트별 저장 경로는 다음과 같아요.
- Store:
~/.openclaw/agents/<agentId>/sessions/sessions.json - Transcripts:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl- 텔레그램 토픽 세션:
.../<sessionId>-topic-<threadId>.jsonl
- 텔레그램 토픽 세션:
OpenClaw는 src/config/sessions.ts를 통해 이 경로들을 확인해요.
저장소 유지 관리 및 디스크 제어
섹션 제목: “저장소 유지 관리 및 디스크 제어”세션 영속성 관리를 위해 sessions.json과 Transcript 파일에 대한 자동 유지 관리 제어 기능(session.maintenance)을 제공해요.
mode:warn(기본값) 또는enforcepruneAfter: 오래된 항목의 삭제 기준 시간 (기본값30d)maxEntries:sessions.json에 저장될 최대 항목 수 제한 (기본값500)rotateBytes:sessions.json파일이 너무 커지면 로테이션 실행 (기본값10mb)resetArchiveRetention:*.reset.<timestamp>Transcript 아카이브 파일의 보관 기간 (기본값은pruneAfter와 동일하며,false로 설정하면 정리를 비활성화해요)maxDiskBytes: 선택 사항으로, 세션 디렉토리의 전체 용량 예산을 설정해요.highWaterBytes: 정리 후 목표로 하는 용량 (기본값은maxDiskBytes의80%)
mode: "enforce"일 때 디스크 용량 정리는 다음 순서로 진행돼요.
- 가장 오래된 아카이브 파일이나 고립된 Transcript 파일을 먼저 제거해요.
- 그래도 목표 용량보다 크다면, 가장 오래된 세션 항목과 해당 Transcript 파일을 삭제해요.
- 사용량이
highWaterBytes이하가 될 때까지 이 과정을 반복해요.
mode: "warn" 모드에서는 삭제될 가능성이 있는 항목을 보고만 하고, 실제 저장소나 파일을 수정하지는 않아요.
필요할 때 직접 유지 관리를 실행할 수도 있어요.
openclaw sessions cleanup --dry-runopenclaw sessions cleanup --enforceCron 세션 및 실행 로그
섹션 제목: “Cron 세션 및 실행 로그”격리된 Cron 실행도 세션 항목과 기록(transcripts)을 생성해요. 이를 관리하기 위한 전용 보관 설정이 마련되어 있어요.
cron.sessionRetention(기본값24h): 세션 저장소에서 오래된 격리된 Cron 실행 세션을 삭제해요.false로 설정하면 이 기능을 꺼둘 수 있어요.cron.runLog.maxBytes+cron.runLog.keepLines:~/.openclaw/cron/runs/<jobId>.jsonl파일의 크기를 제한해요. (기본값:2_000_000바이트 및2000라인)
세션 키 (sessionKey)
섹션 제목: “세션 키 (sessionKey)”sessionKey는 여러분이 현재 어떤 대화 버킷에 있는지를 식별해요. 이를 통해 라우팅과 격리가 이루어지죠.
자주 사용되는 패턴은 다음과 같아요:
- 메인/직접 채팅 (에이전트별):
agent:<agentId>:<mainKey>(기본값main) - 그룹:
agent:<agentId>:<channel>:group:<id> - 룸/채널 (Discord/Slack):
agent:<agentId>:<channel>:channel:<id>또는...:room:<id> - Cron:
cron:<job.id> - Webhook:
hook:<uuid>(재정의하지 않은 경우)
표준 규칙에 대한 자세한 내용은 /concepts/session 문서에 잘 정리되어 있어요.
세션 ID (sessionId)
섹션 제목: “세션 ID (sessionId)”각 sessionKey는 현재의 sessionId를 가리켜요. 이는 대화가 계속 이어지는 실제 트랜스크립트 파일을 의미해요.
기억해두면 좋은 규칙들이에요:
- 리셋 (
/new,/reset): 해당sessionKey에 대해 새로운sessionId를 생성해요. - 일일 리셋: 기본적으로 Gateway 호스트의 현지 시간 기준 오전 4시에 리셋돼요. 리셋 시간 이후 첫 메시지가 오면 새로운
sessionId가 만들어져요. - 유휴 만료 (
session.reset.idleMinutes또는 기존session.idleMinutes): 설정된 유휴 시간 이후에 메시지가 도착하면 새로운sessionId를 생성해요. 일일 리셋과 유휴 만료가 모두 설정된 경우, 먼저 조건이 충족되는 쪽이 적용돼요. - 스레드 부모 포크 가드 (
session.parentForkMaxTokens, 기본값100000): 부모 세션이 이미 너무 크면 부모 트랜스크립트 포크를 건너뛰고, 새 스레드를 깨끗하게 시작해요.0으로 설정하면 이 기능을 끌 수 있어요.
구현 세부 사항이 궁금하다면 src/auto-reply/reply/session.ts 파일의 initSessionState() 함수를 살펴보세요.
세션 저장소 스키마 (sessions.json)
섹션 제목: “세션 저장소 스키마 (sessions.json)”저장소의 값 타입은 src/config/sessions.ts에 정의된 SessionEntry를 사용해요.
주요 필드는 다음과 같아요 (전체 목록은 아니에요):
sessionId: 현재 트랜스크립트 ID (sessionFile이 설정되지 않았다면 이 값을 바탕으로 파일명이 결정돼요)updatedAt: 마지막 활동 타임스탬프sessionFile: 선택 사항으로, 트랜스크립트 경로를 직접 지정할 때 사용해요chatType:direct | group | room(UI 및 전송 정책 결정에 도움을 줘요)provider,subject,room,space,displayName: 그룹이나 채널 라벨링을 위한 메타데이터- 토글 설정:
thinkingLevel,verboseLevel,reasoningLevel,elevatedLevelsendPolicy(세션별 재정의)
- 모델 선택:
providerOverride,modelOverride,authProfileOverride
- 토큰 카운터 (최선을 다해 계산하지만 provider에 따라 다를 수 있어요):
inputTokens,outputTokens,totalTokens,contextTokens
compactionCount: 이 세션 키에 대해 자동 압축(auto-compaction)이 완료된 횟수memoryFlushAt: 마지막 사전 압축 메모리 플러시 타임스탬프memoryFlushCompactionCount: 마지막 플러시가 실행되었을 때의 압축 횟수
이 저장소는 직접 수정해도 안전하지만, Gateway가 최종 권한을 가져요. 세션이 실행됨에 따라 항목을 다시 쓰거나 데이터를 복구할 수 있다는 점을 참고하세요.
트랜스크립트 구조 (*.jsonl)
섹션 제목: “트랜스크립트 구조 (*.jsonl)”트랜스크립트는 @mariozechner/pi-coding-agent의 SessionManager에 의해 관리돼요.
파일은 JSONL 형식으로 구성되어 있어요:
- 첫 번째 줄: 세션 헤더 (
type: "session",id,cwd,timestamp, 선택 사항인parentSession포함) - 그 이후:
id와parentId를 가진 세션 엔트리들 (트리 구조)
주요 엔트리 타입은 다음과 같아요:
message: user/assistant/toolResult 메시지custom_message: 모델 context에 포함되는 extension 주입 메시지 (UI에서는 숨길 수 있어요)custom: 모델 context에 들어가지 않는 extension 상태compaction:firstKeptEntryId와tokensBefore가 포함된 저장된 압축 요약branch_summary: 트리 브랜치를 탐색할 때 저장되는 요약
OpenClaw는 의도적으로 트랜스크립트를 직접 “수정”하지 않아요. Gateway가 SessionManager를 사용해서 트랜스크립트를 읽고 쓸 뿐이죠.
Context window와 추적된 토큰의 차이
섹션 제목: “Context window와 추적된 토큰의 차이”여기서 두 가지 서로 다른 개념이 중요해요:
- Model context window: 모델당 하드 제한 (모델이 볼 수 있는 토큰 수)
- Session store counters:
sessions.json에 기록되는 누적 통계 (/status및 대시보드에 사용돼요)
제한 수치를 튜닝하고 있다면 다음 내용을 참고하세요:
- Context window는 모델 카탈로그에서 가져오며, config를 통해 덮어쓸 수 있어요.
- 저장소의
contextTokens는 런타임 추정치이자 보고용 값이에요. 이걸 엄격한 보증값으로 취급해서는 안 돼요.
더 자세한 내용은 /token-use에서 확인할 수 있어요.
Compaction이란 무엇인가요
섹션 제목: “Compaction이란 무엇인가요”Compaction은 오래된 대화 내용을 요약해서 transcript에 compaction 항목으로 저장하고, 최근 메시지들은 그대로 유지하는 기능이에요.
Compaction이 진행된 후, 이후의 대화(turns)에서는 다음 내용들을 보게 돼요:
- Compaction 요약본
firstKeptEntryId이후의 메시지들
Compaction은 session pruning과 달리 **영구적(persistent)**으로 유지되는 특징이 있어요. 자세한 내용은 /concepts/session-pruning을 참고해 보세요.
Auto-compaction이 발생하는 시점 (Pi runtime)
섹션 제목: “Auto-compaction이 발생하는 시점 (Pi runtime)”임베디드된 Pi agent에서는 다음 두 가지 상황에서 auto-compaction이 트리거돼요:
- Overflow recovery: 모델이 context overflow 에러를 반환하면, compact를 실행한 후 다시 시도해요.
- Threshold maintenance: 대화가 성공적으로 완료된 시점에 아래 조건을 만족하면 실행돼요:
contextTokens > contextWindow - reserveTokens
여기서 각 항목은 다음과 같아요:
contextWindow: 모델의 context window 크기reserveTokens: 프롬프트와 다음 모델 출력을 위해 확보해둔 여유 공간(headroom)
이것은 Pi runtime의 동작 로직이에요. OpenClaw는 발생하는 이벤트를 수신하지만, 실제 compact 시점은 Pi가 결정하게 돼요.
압축 설정 (reserveTokens, keepRecentTokens)
섹션 제목: “압축 설정 (reserveTokens, keepRecentTokens)”Pi의 압축(Compaction) 설정은 Pi settings에서 관리해요.
{ compaction: { enabled: true, reserveTokens: 16384, keepRecentTokens: 20000, },}OpenClaw는 embedded 실행 시 안전 하한선(safety floor)을 적용해요.
compaction.reserveTokens가reserveTokensFloor보다 작으면 OpenClaw가 이 값을 높여요.- 기본 하한선은
20000tokens예요. - 하한선을 비활성화하려면
agents.defaults.compaction.reserveTokensFloor: 0으로 설정하면 돼요. - 설정값이 이미 하한선보다 높다면 OpenClaw는 값을 수정하지 않아요.
이렇게 하는 이유는 압축이 꼭 필요한 상황이 오기 전에, 메모리 쓰기 같은 멀티턴 “housekeeping” 작업을 처리할 수 있는 충분한 여유 공간(headroom)을 확보하기 위해서예요.
구현 코드: src/agents/pi-settings.ts 파일의 ensurePiCompactionReserveTokens() 함수 (src/agents/pi-embedded-runner.ts에서 호출돼요).
사용자 확인 방법
섹션 제목: “사용자 확인 방법”압축 상태와 세션 상태는 다음 위치에서 확인할 수 있어요.
/status(모든 채팅 세션 내)openclaw status(CLI 명령)openclaw sessions또는sessions --json- Verbose 모드:
🧹 Auto-compaction complete메시지와 함께 압축 횟수가 표시돼요.
사일런트 하우스키핑 (NO_REPLY)
섹션 제목: “사일런트 하우스키핑 (NO_REPLY)”OpenClaw는 사용자가 중간 과정을 볼 필요 없는 백그라운드 작업을 위해 “사일런트(silent)” 턴을 지원해요.
사용 규칙은 다음과 같아요:
- 어시스턴트가 출력을 시작할 때
NO_REPLY를 넣으면 “사용자에게 응답을 전달하지 마세요”라는 신호로 인식해요. - OpenClaw는 전달 레이어에서 이 부분을 제거하거나 숨겨줘요.
2026.1.10 버전부터는 부분적인 청크가 NO_REPLY로 시작할 때 드래프트/타이핑 스트리밍도 함께 숨겨줘요. 덕분에 사일런트 작업 중에 중간 내용이 사용자에게 노출되지 않아요.
컴팩션 전 “메모리 플러시” (구현됨)
섹션 제목: “컴팩션 전 “메모리 플러시” (구현됨)”이 기능의 목표는 자동 컴팩션(auto-compaction)이 일어나기 전에, 중요한 컨텍스트가 유실되지 않도록 에이전트 워크스페이스의 디스크(예: memory/YYYY-MM-DD.md)에 상태를 기록하는 사일런트 에이전트 턴을 실행하는 것이에요.
OpenClaw는 임계값 전 플러시(pre-threshold flush) 방식을 사용해요:
- 세션의 컨텍스트 사용량을 실시간으로 모니터링해요.
- 사용량이 “소프트 임계값”(Pi의 컴팩션 임계값보다 낮은 지점)을 넘으면,
NO_REPLY를 사용해 사용자 몰래 “지금 메모리를 기록하세요”라는 사일런트 명령을 에이전트에게 내려요.
설정 항목 (agents.defaults.compaction.memoryFlush):
enabled(기본값:true)softThresholdTokens(기본값:4000)prompt(플러시 턴을 위해 전달할 사용자 메시지)systemPrompt(플러시 턴에 추가로 붙는 시스템 프롬프트)
참고 사항:
- 기본 프롬프트와 시스템 프롬프트에는 응답 노출을 막기 위한
NO_REPLY힌트가 포함되어 있어요. - 플러시는 컴팩션 주기당 한 번만 실행되며, 이는
sessions.json에서 추적해요. - 이 플러시 로직은 임베디드 Pi 세션에서만 작동하며, CLI 백엔드는 건너뛰어요.
- 세션 워크스페이스가 읽기 전용(
workspaceAccess: "ro"또는"none")인 경우 플러시를 실행하지 않아요. - 워크스페이스 파일 구조와 기록 패턴에 대해 더 알고 싶다면 Memory 문서를 참고해 보세요.
Pi는 확장 API에서 session_before_compact 훅을 제공하고 있지만, 현재 OpenClaw의 플러시 로직은 Gateway 쪽에서 관리되고 있어요.
문제 해결 체크리스트
섹션 제목: “문제 해결 체크리스트”- 세션 키가 잘못되었나요? /concepts/session 문서를 확인하고,
/statusAPI에서sessionKey가 일치하는지 확인해 보세요. - Store와 트랜스크립트 내용이 다른가요? Gateway 호스트 설정과
openclaw status명령어로 확인한 store 경로가 맞는지 체크해 보세요. - 컴팩션이 너무 자주 발생하나요? 다음 항목을 확인해 보세요:
- 모델의 컨텍스트 윈도우가 너무 작거나, 컴팩션 설정의
reserveTokens가 모델 윈도우 크기에 비해 너무 높게 잡혀 있는지 확인해 보세요. - 도구 결과(tool-result) 데이터가 너무 큰지 확인하고, 세션 프루닝(pruning) 기능을 활성화하거나 세부 설정을 조정해 보세요.
- 모델의 컨텍스트 윈도우가 너무 작거나, 컴팩션 설정의
- 사일런트 턴 내용이 사용자에게 노출되나요? 응답이 정확히
NO_REPLY토큰으로 시작하는지 확인하고, 스트리밍 억제 수정 사항이 포함된 최신 빌드를 사용 중인지 확인해 보세요.
OpenClaw Expert
아직 막혀 있나요?
이 문서에서 답을 못 찾았다면 OpenClaw Expert에게 바로 물어보세요.