
Claude Code의 작동 원리 — 하네스(Harness)의 동작과 Claude API
요약
Claude Code의 동작 원리를 3층 구조(Claude API, 하네스, 세션 로그)로 분석합니다. Claude API의 스테이트리스 특성과 하네스의 컨텍스트 관리 방식, 그리고 프롬프트 캐시를 통한 효율적인 비용 관리 메커니즘을 설명합니다.
핵심 포인트
- Claude Code는 API, 하네스, 세션 로그의 3층 구조로 동작함
- Claude API는 상태를 유지하지 않는 스테이트리스(Stateless) 방식임
- 하네스가 매번 과거 로그를 재구축하여 전체 페이로드를 전송함
- 프롬프트 캐시를 통해 반복되는 컨텍스트 전송 비용을 최적화함
본 기사는 Claude Code가 동작하는 원리에 대해 정리한 것입니다.
과거에 단편적으로 조사하여 기사로 작성해 왔던 내용들입니다.
- Claude Code의 문서를 읽고 궁금했던 점을 검증해 보았다
- Claude Code가 LLM에 전달하는 컨텍스트(Context)의 내용을 조사한다
- Claude Code의 세션, 컨텍스트 크기와 토큰 소비량의 관계성
이번에는 그것들을 하나로 모아 가능한 한 체계적으로 작성했습니다. 긴 글이 되겠지만, 괜찮으시다면 함께해 주시기 바랍니다.
먼저, 본 기사 전체를 관통하는 멘탈 모델(Mental Model)을 제시합니다. Claude Code는 다음의 3층 구조로 동작합니다.
각 층의 역할은 명확하게 나누어져 있습니다.
| 층 | 실체 | 역할 |
|---|---|---|
| Claude API | Anthropic의 서버 | 모델에 의한 추론(사고·응답 생성·도구 사용 판단)만을 수행. 상태는 일절 가지지 않음 |
| 하네스 (Harness) | 로컬에서 동작하는 Claude Code 본체 | 도구 실행, 컨텍스트 구성, 권한 관리, 세션의 영속화. 모든 상태 관리를 담당 |
| 세션 로그 | JSONL 파일 | 대화의 영속화 계층. 하네스가 API 요청을 구성할 때, 대화 이력을 여기서 매번 읽어옴 |
'하네스(Harness)'는 공식 명칭입니다. 문서는 Claude Code를 "agentic harness" (에이전트용 마구·골격)라고 부르고 있습니다 2.
Claude Code serves as the
agentic harness around Claude: it provides the tools, context management, and execution environment that turn a language model into a capable coding agent.
이 3층 구조를 이해하는 데 있어 가장 중요한 원칙은, Claude API (Messages API)는 스테이트리스(Stateless)이다라는 사실입니다 3.
- API 서버는 대화 이력을 일절 보유하지 않습니다.
- 하네스는 API를 호출할 때마다 시스템 프롬프트(System Prompt)·과거의 모든 메시지·이번 입력을 전부 포함하여 전송합니다.
- "컨텍스트(Context)"란, 이 매번 전송되는 페이로드(Payload) 전체를 의미합니다.
요청 페이로드는 다음 형식입니다 3. 포인트는 messages 배열이며, 2턴째의 요청에는 1턴째의 user / assistant 메시지가 통째로 포함됩니다.
POST /v1/messages
{
"model": "claude-...",
...
즉 "대화가 이어지고 있는" 것처럼 보이는 이유는, 하네스가 매번 과거 로그를 재구축하여 다시 보내고 있기 때문입니다. 이 "재구축의 원천"이 세션 로그(JSONL)이며, "재구축 시 무엇이 추가되는가"가 제4장의 컨텍스트 주입(Context Injection) 이야기입니다.
"매번 전량 전송"을 계산 비용 측면에서 성립시키는 것이 서버 사이드의 **프롬프트 캐시(Prompt Cache)**입니다 4.
모델은 응답을 쓰기 시작하기 전에 페이로드 전체를 처음부터 읽습니다. 서버는 이 "읽은 결과"를 일시적으로 저장해 두었다가, 다음 요청의 시작 부분이 이전과 같다면 그 부분은 다시 읽지 않고 저장된 결과를 사용합니다. Claude Code의 에이전트 루프(2장에서 상세 기술) 요청은 "이전 페이로드의 끝에 몇 개의 블록을 추가한 것" 형태이므로, 거의 전체를 다시 읽을 필요가 없게 됩니다.
주의할 점은 두 가지입니다.
- 대화를 기억하고 있는 것이 아닙니다. 서버가 저장하는 것은 "읽은 결과"뿐이므로, 하네스는 매번 페이로드 전체를 보낼 필요가 있습니다. 스테이트리스 원칙은 깨지지 않았습니다.
- 일치 판정은 처음부터의 완전 일치입니다. 페이로드의 중간이 단 1바이트라도 이전과 달라지면, 그 이후의 캐시는 모두 사용할 수 없게 됩니다.
캐시를 사용할지 여부는 서버가 임의로 결정하는 것이 아니라, 하네스가 페이로드 내에서 지시합니다. 캐시하고 싶은 범위의 끝 블록에 cache_control이라는 표식을 붙입니다.
{
"tools": [ /* 도구 정의 */ ],
"system": [
...
- 페이로드는
tools→system→messages순서입니다.
순서로 연결되며, 표시(marker)를 지정한 블록까지의 범위가 캐시됩니다. 이 예시의 표시는 2개로, "tools + system까지의 안정적인 부분"과 "대화 전체"가 각각 캐시 대상입니다. 표시는 1개 요청당 최대 4개까지 둘 수 있습니다. 다음 요청에서는 길어진 대화의 새로운 끝부분에 표시를 다시 지정합니다. 과거 위치의 캐시도 유효하게 남기 때문에, 대화가 길어질수록 히트(hit) 범위가 쌓이게 됩니다.
- 캐시 유지 기간(TTL)은 5분(기본값) 또는 1시간 중에서 선택합니다. 캐시에서 읽은 부분은 통상 입력 비용의 약 0.1배이며, 새로 쓰는 부분은 약 1.25배(5분) ~ 2배(1시간)입니다. Claude Code는 1시간을 지정하고 있습니다 (실측).
대화가 진행될 때마다 payload의 끝에 메시지가 쌓이며, "캐시 히트 / 신규"의 경계와 표시의 위치가 아래로 이동합니다.
Claude Code는 자율적으로 도구를 사용하며 태스크를 진행합니다. 이 자율성은 성격이 다른 두 가지 계층으로 구성됩니다. 행동을 반복하는 루프 (loop) (하네스 측)와, 1회 응답 내부에서의 추론 (reasoning) (서버 측)입니다. 루프는 외부에 하나만 존재합니다.
사용자가 1회 발언(= 1턴)하면, 내부적으로는 여러 번의 API 호출이 실행됩니다.
포인트는 4가지입니다.
루프를 돌리는 주체는 하네스입니다. 모델은 "다음에 무엇을 해야 할지"를 판단하여 tool_use 블록을 반환할 뿐이며, 실제로 파일을 읽거나 명령을 실행하는 것은 로컬의 하네스입니다.
도구의 실행 결과는 tool_result 블록을 포함하는 user 역할 (role)의 메시지로 API에 반송됩니다.
루프의 지속 조건은 모델이 tool_use를 반환하는 것입니다. API 응답에는 생성을 멈춘 이유(stop_reason)가 붙어 있으며, 그것이 tool_use인 동안에는 하네스가 도구 실행과 재호출을 반복하고, tool_use를 포함하지 않는 응답(end_turn)이 반환되면 턴이 종료됩니다.
따라서 1턴 ≠ 1 API 호출입니다. 복잡한 태스크에서는 1턴의 이면에 수십 번의 API 호출이 실행되기도 합니다.
그림의 ①~③에 대응하는 실제 사례를 본 기사의 집필 세션 로그에서 발췌합니다 (내용은 일부 생략). tool_use와 tool_result는 id로 대응됩니다.
① 모델 → 하네스: API 응답. Bash 도구 실행을 요청하고, stop_reason: "tool_use"로 생성을 멈춤
{
"role": "assistant",
"content": [{
...
② 하네스 → 모델: 하네스가 로컬에서 ls를 실행하고, 그 결과를 user 메시지로 messages 끝에 추가하여 재호출
{
"role": "user",
"content": [{
...
③ 모델 → 하네스: 도구 결과를 바탕으로 한 응답. text로 완결되며, stop_reason: "end_turn"으로 턴이 종료됨
{
"role": "assistant",
"content": [{
...
공식 문서에서는 이 루프를 "gather context (정보 수집) → take action (행동) → verify results (검증)의 3단계 반복"이라고 설명합니다.
한편, 1회 API 호출의 내부에서도 모델은 추론을 수행합니다. 이것이 thinking입니다. Claude Code의 터미널에 회색으로 흐르는 사고 텍스트의 실체는 API 응답에 포함된 thinking 블록입니다.
그림과 같이, thinking은 1회의 연속된 텍스트 생성 중 전반부입니다. 모델은 thinking 토큰을 다 쓰면 그대로 이어서 출력 토큰을 생성합니다. 서버 내에 2.1과 같은 루프는 없습니다. thinking으로 인해 응답이 느려지는 이유는 답변 전에 수백~수만 토큰의 추론 텍스트를 생성하기 때문이며, 이 부분도 output 토큰으로서 과금됩니다.
활성화 — thinking을 활성화하는 것은 하네스이며, 요청 payload의 thinking 파라미터로 지정합니다.
extended thinking (Claude 4.5 세대 이전) — 하네스(Harness)가 사고 토큰(thinking tokens)의 예산을 명시합니다.
{
"model": "claude-sonnet-4-5",
"thinking": {"type": "enabled", "budget_tokens": 10000},
...
adaptive thinking (Claude 4.6 세대 이후) — 사고 여부는 모델이 판단하며, 깊이는 effort로 제어합니다.
{
"model": "claude-opus-4-6",
"thinking": {"type": "adaptive"},
...
응답에서의 나타남 — content의 선두에 thinking 블록이 삽입됩니다. thinking 비활성화 시와의 차이점은 이 블록의 유무뿐입니다 (본문은 예시 이미지).
{
"role": "assistant",
"content": [
...
interleaved thinking (교차 사고)에서는, 1회의 assistant 턴 내에서 도구 호출(tool call) 사이사이에도 thinking 블록이 나타납니다. 도구 결과(tool result)를 보고 "다음에는 무엇을 할 것인가"를 생각한 뒤 다음 tool_use를 내보내는 동작으로, adaptive thinking에서는 자동으로 수행됩니다.
하네스의 책임 — 활성화 외에 하네스가 담당하는 것은, 전달받은 블록의 렌더링과 세션 로그(session log)에 대한 기록(3.1절), 그리고 도구 사용 루프 중의 반환입니다. 도구 결과를 반환할 때는 직전 응답에 포함되어 있던 thinking 블록을 수정 없이 그대로 포함하는 것이 API 사양상의 의무이며, 누락되거나 변형될 경우 400 에러로 거부됩니다 5.
요약하자면, thinking은 루프가 아니라 1회의 API 응답 내에서 완결되는 추론입니다. 도구를 실행하여 결과를 얻고 다음을 결정하는 루프를 돌리는 것은 항상 하네스 측입니다.
| 외부 루프 | 내부 추론 |
|---|---|
| 주체 | 하네스 (로컬) |
| ... |
제2장의 루프는 로컬 세션 로그에 그대로 흔적으로 남습니다. 이 기사의 집필에 사용 중인 세션 자체의 JSONL을 소재로 확인하겠습니다.
세션 로그는 1행 = 1엔트리 (entry) 형태의 JSONL 파일로서 다음 위치에 저장되어 있습니다 1 (기본 30일 후 자동 삭제).
~/.claude/projects/<프로젝트 경로의 슬러그>/<세션 ID>.jsonl
<프로젝트 경로의 슬러그>는 작업 디렉토리 경로의 비영문자를 -로 치환한 것입니다 (예: /Users/foo/myapp → -Users-foo-myapp).
파일의 내용은 1행 1객체(object)의 나열이며, 끝에 행을 추가하며 늘어납니다. 각 행(= 엔트리)은 parentUuid 필드로 이전 엔트리를 가리키고 있으며, 세션 로그의 실체는 추가를 통해 늘어나는 연결 리스트 (linked list)입니다. 이 한 행이 후술할 표의 한 행에 대응합니다.
{"type": "user", "uuid": "e1", "parentUuid": "...", "message": { ... }}
{"type": "attachment", "uuid": "e2", "parentUuid": "e1", ... }
{"type": "assistant", "uuid": "e3", "parentUuid": "e2", "message": { ... }}
1개 엔트리를 전개한 구조입니다 (실물에서 발췌, 일부 생략).
{
"type": "assistant", // 엔트리의 종류 (user / assistant / system 등)
"uuid": "0794013f-...", // 이 엔트리의 ID
...
대화형 엔트리는 API와 주고받은 메시지를 message 필드에 거의 그대로 유지합니다. content는 배열이며, 그 요소가 content 블록 (객체)입니다. 2장에서 등장한 tool_use나 thinking, 일반적인 응답 텍스트의 text는 모두 이 블록의 type
종류입니다. 이후 표의 「블록 (block)」 열은 이 type을 가리킵니다.
이러한 전제를 바탕으로, 하나의 턴(사용자 발언 → 도구 실행 1회 → 응답)이 로그에 어떻게 쌓이는지 보여줍니다. 엔트리의 구조, 순서, 체인(chain)은 실제 측정값과 동일하며, 내용과 uuid는 설명을 위한 예시입니다.
| # | type | 블록 (block) | 내용 (예시) | uuid | parentUuid |
|---|---|---|---|---|---|
| 1 | user | — | 「빌드가 실패하는 원인을 조사해줘」 | e1 | -- |
| 2 | attachment | — | task_reminder (메타데이터 계열) | e2 | e1 |
| 3 | assistant | thinking | 「먼저 빌드를 실행하여 에러를 확인하자.」 | e3 | e2 |
| 4 | assistant | text | 「빌드를 실행하여 원인을 확인하겠습니다.」 | e4 | e3 |
| 5 | assistant | tool_use | Bash {"command": "npm run build"} | e5 | e4 |
| 6 | user | tool_result | Error TS2345: Argument of type 'string' ... | e6 | e5 |
| 7 | attachment | — | hook_success (메타데이터 계열) | e7 | e6 |
| 8 | assistant | text | 「원인은 login()에 전달하는 인자의 타입 불일치입니다. …」 | e8 | e7 |
attachment는 하네스(Harness)가 관리 정보를 기록하는 메타데이터 계열 엔트리입니다 (종류는 3.2절). parentUuid의 체인은 대화 계열 엔트리뿐만 아니라 메타데이터 계열 엔트리도 경유하여 하나로 연결되어 있습니다.
이 로그에는 2장의 루프(loop) 메커니즘이 그대로 나타나 있습니다. 읽어내야 할 사양은 세 가지입니다.
① 도구 실행 결과는 user 엔트리로 기록된다
엔트리 6은 user 타입이지만, 사용자의 발언이 아니라 하네스가 도구 실행 결과(tool_result)를 user 역할(role)로서 API에 반송한 기록입니다. 2.1의 포인트 2가 로그에 그대로 나타나 있습니다.
② 1회의 API 응답은 content 블록마다 여러 엔트리로 분할된다
엔트리 3~5는 세 줄로 나뉘어 있지만, 사실은 동일한 API 응답입니다. JSONL에는 API 호출을 나타내는 계층 구조가 없으며, 모든 엔트리가 동일한 계층에 나열됩니다. 어떤 엔트리가 동일한 응답에서 유래했는지는 message.id의 일치 여부로 표현됩니다.
| 엔트리 | 블록 (block) | message.id |
|---|---|---|
| 3 | thinking | msg_abc123 |
| 4 | text | msg_abc123 (= 동일한 API 응답) |
| 5 | tool_use | msg_abc123 (= 동일한 API 응답) |
Claude Code는 API 응답의 content 블록 1개당 JSONL 1엔트리로 기록합니다. 즉, 1회의 API 응답은 thinking + text만 있어도 2개의 엔트리로, 도구를 사용하면 더욱 많은 엔트리로 나뉘어 기록됩니다.
③ usage는 엔트리 단위가 아닌 API 호출 단위의 값이다
assistant 엔트리에는 usage 필드가 붙지만, 이 값은 '해당 엔트리 단독'이 아니라 '해당 API 호출 전체'의 토큰 수입니다. 이 세션의 실제 측정값입니다.
{
"input_tokens": 2,
"cache_creation_input_tokens": 379,
...
입력 측 3개 항목의 합계(input_tokens + cache_creation + cache_read)가 이 1회의 API 호출로 전송된 컨텍스트의 전체 양이며, 약 5.1만 토큰입니다. 그중 5만 토큰 초과는 캐시에서 읽혔고, 새로 처리된 것은 381 토큰뿐입니다. 1장에서 언급한 "매번 전체를 전송하되, 대부분은 캐시로 처리를 생략한다"가 이 수치에 그대로 나타나 있습니다.
엔트리의 type
은 대화 계열뿐만이 아닙니다. v2.1.220의 실제 세션에서 관측된 타입을 분류하면 다음과 같습니다:
| 분류 | type | 내용 |
|---|---|---|
| 대화 계열 (API payload 재구축에 사용됨) | user | 사용자 발언 또는 tool_result |
assistant | thinking / text / tool_use (1블록 1엔트리) | |
| 메타데이터 계열 (로컬 관리용. API에는 전송되지 않음) | system | compact 경계, 턴 소요 시간 등의 이벤트 기록 |
attachment | hook 실행 결과, 스킬 목록의 차분 등 | |
file-history-snapshot | 체크포인트 (→ 5.3 /rewind) | |
ai-title, last-prompt, mode, permission-mode 외 | 세션 이름, 입력 이력, 모드 상태 등 |
이와 같이, JSONL의 모든 엔트리가 API로 전송되는 것은 아닙니다 (대응 관계는 3.4에서 도해합니다).
3.1에서 본 연결 리스트는 정확하게는 **분기 가능한 트리 (Tree)**입니다. 단순한 리스트가 아니라 트리 구조인 이유는 대화의 되감기(rewind)와 분기를 지원하기 위해서입니다 (구체적인 가지치기는 5.3의 /rewind에서 확인합니다). '현재 대화'로서 payload로 재구축되는 것은, 최신 엔트리로부터 parentUuid를 거슬러 올라가며 추적할 수 있는 **단 하나의 경로 (Path)**뿐입니다.
세션 로그는 기본적으로 **추가 전용 (append-only)**이며, 과거의 행을 다시 쓰지 않습니다. 후술할 /compact조차 이력의 삭제가 아니라 '경계 엔트리와 요약의 추가'를 통해 실현됩니다 (5.2절). 이 추가 전용 설계와 트리 구조의 조합이 되감기, 분기, 복구의 모든 것을 뒷받침합니다.
지금까지의 내용을 바탕으로, 3층 구조의 '대응 관계'를 도해합니다. 하네스(Harness)는 API를 호출할 때마다 JSONL에서 대화 계열 엔트리를 읽어 들여, 그 외의 요소들을 조합하여 payload를 구성합니다.
그렇다면 구성된 payload 안에는 무엇이 어떻게 들어있을까요? 1장에서 본 system / tools / messages의 3개 구역에 각각 다음 요소들이 배치됩니다 6.
이 중 대화가 진행됨에 따라 단조 증가하는 것은 messages 배열(대화 본체)뿐이며, 이것이 컨텍스트 팽창(Context Bloat)의 주된 원인입니다. 자신의 세션 내역은 /context 명령으로 언제든 확인할 수 있으며, 카테고리별 토큰 소비량이 표시됩니다.
시스템 프롬프트(System Prompt)나 CLAUDE.md는 세션 로그에 저장되지 않습니다. 이것들은 API를 호출할 때마다 하네스가 디스크(disk)에서 다시 읽어 생성합니다. 그렇기 때문에 세션을 다음 날 재개하더라도 최신 CLAUDE.md가 반영되는 것입니다.
3.4의 그림에서 '하네스가 매번 생성·주입'이라고 적은 부분을 심층적으로 살펴보겠습니다. 하네스는 JSONL의 대화를 단순히 messages 배열로 변환할 뿐만 아니라, 모델의 사고를 제어하기 위한 정보를 곳곳에 주입하고 있습니다.
개별 주입에 대한 실측 데이터는 과거 게시글 ②로 미루고, 여기서는 체계만을 정리합니다.
| 채널 | 실체 |
|---|---|
| system 파라メータ | payload 최상위 레벨의 시스템 프롬프트. 페르소나·도구 사용 원칙·응답 형식의 핵심 지시 (1장의 payload 예시 참조) |
<system-reminder> 태그 | user 메시지 내에 삽입되는 만능 주입 태그. 모드 상태 통지, 스킬 목록, hook으로부터의 추가 컨텍스트 등 |
| 합성 이력 (Synthetic History) | '모델이 도구를 호출한 것으로 만든' 가짜 이력 |
| 도구 결과 래핑 (Tool Result Wrapping) | tool_result의 정형화 및 격리 |
<system-reminder>의 실례 (실측) — 빈 CLAUDE.md를 Read 했을 때의 도구 결과입니다. 파일 내용 대신 하네스가 이 주석을 주입하고 있었습니다.
{
"type": "tool_result",
"tool_use_id": "toolu_01...",
...
합성 이력의 실례 (구조는 실측과 동일, 내용은 예시) — 사용자가 @README.md
사용자가 @README.md를 멘션하면, 모델이 Read 툴을 호출한 것과 같은 tool_use / tool_result 쌍이 payload에 합성됩니다.
{"role": "assistant", "content": [
{"type": "tool_use", "id": "toolu_x1", "name": "Read", "input": {"file_path": "README.md"}}
]},
...
툴 결과 래핑(Wrap)의 실례 (실측) — WebFetch의 출력이 너무 컸을 때, tool_result의 내용이 퇴피(evacuated) 파일에 대한 참조와 도입부 프리뷰로 대체되어 있었습니다.
<persisted-output>
Output too large (71.1KB). Full output saved to:
~/.claude/projects/<프로젝트>/<세션ID>/tool-results/toolu_01NC....txt
...
하네스(Harness)는 "모델이 필요할 법한 정보"를 모두 주입(push)하는 것이 아닙니다. TodoList의 상태나 Plan 파일의 본체는 messages에 통째로 싣지 않고, 모델이 필요할 때 툴 호출을 통해 가져오도록 (pull) 설계되어 있습니다.
TodoList를 예로 들면 (내용은 예시):
push형이라면 — 매 요청의 payload에 리스트 전문이 계속 포함됨
<system-reminder>현재 태스크: 1. 빌드 수정 (진행 중) 2. 테스트 추가 3. ... (전문)</system-reminder>
pull형 (실제 설계) — 작은 알림만 주입하고, 내용은 모델이 직접 가져감
<system-reminder>태스크 리스트가 업데이트되었습니다. TaskList 툴로 확인할 수 있습니다.</system-reminder>
모델이 필요하다고 판단했을 때만, TaskList의 tool_use를 통해 전문을 가져옵니다.
이는 컨텍스트 소비를 억제하기 위한 설계적 판단으로 보입니다.
3장에서 살펴본 "JSONL ⇄ payload"의 대응 관계를 고려하면, 주입에는 중요한 비대칭성이 존재합니다. 주입되는 컨텍스트에는 JSONL에 영속화되는 것과, 전송 시에만 생성되어 기록에 남지 않는 것이 있습니다.
| 분류 | 예 | 동작 |
|---|---|---|
| 영속적 주입 | @멘션의 합성 이력, hook의 추가 컨텍스트 | JSONL에 기록되며, 이후의 모든 API 호출 시 재전송됨 |
| 휘발성 주입 | 모드 상태 알림 (Auto mode 등), 일부 리마인더 | 턴(turn) 전송 시 그 자리에서 생성. JSONL에는 남지 않으며, 다음 턴에서는 최신 상태가 다시 생성됨 |
휘발성 주입은 "항상 최신 상태만을 모델에게 보여주고 싶은 정보" (현재 모드, 현재 시각 등)에 사용됩니다. 즉, 세션 로그는 "대화의 기록"이지 "payload의 완전한 기록"은 아닙니다.
3장(JSONL)과 4장(payload 구성)의 지식이 합쳐지면, 세션을 조작하는 명령어군을 "JSONL에 무엇을 하는가" × "다음 API payload가 어떻게 되는가"라는 두 축으로 통합하여 설명할 수 있습니다.
먼저 전체를 일람합니다.
| 명령어 | JSONL (로컬 기록) | 다음 API payload (컨텍스트) | 세션 ID |
|---|---|---|---|
/clear | 새로운 파일 생성. 기존 파일은 그대로 남음 | 빈 대화부터 재시작 | 신규 발행 |
/compact | 동일 파일에 compact_boundary와 요약 엔트리 추가 | 과거의 messages가 요약 1개로 대체됨 | 변하지 않음 |
/rewind (대화 복원) | 과거의 엔트리를 부모로 하는 새로운 가지(branch) 생성 | 선택 시점까지의 이력으로 되돌아감 | 변하지 않음 |
/btw | 아무것도 기록되지 않음 | 현재 컨텍스트 + 질문 (1회성·일회용) | 변하지 않음 |
--continue / --resume | 기존 파일에 추가를 재개 | 저장된 이력으로부터 재구축 | 변하지 않음 |
/branch / --fork-session | 이력을 새 파일로 복사하여 이후 그곳에 추가 | 복사 시점까지의 이력을 계승 | 신규 발행 |
이하, 각 명령어별 내부 동작을 설명합니다.
/clear
는 "현재 세션 로그를 삭제하는" 명령어가 아닙니다. 실제로는 다음과 같이 동작합니다:
- 새로운 세션 ID를 발행하고, 새로운 JSONL 파일에 기록을 시작합니다.
- 이전 세션의 파일은 손상되지 않은 채로 남으며,
/resume을 통해 언제든 복귀할 수 있습니다. - 페이로드 (payload) 측면에서는
messages배열이 비워지므로, 컨텍스트 (context)는 초기 상태 (시스템 프롬프트 (system prompt) + CLAUDE.md 등)로 돌아갑니다.
/compact
(및 컨텍스트 압박 시의 자동 compaction)는 /clear와 대조적으로, 동일한 세션 및 동일한 파일 내에서 messages만을 압축합니다. 실제 JSONL에는 다음 두 가지 엔트리 (entry)가 추가됩니다.
① compact_boundary (system 엔트리) — 실제 데이터 발췌:
{
"type": "system",
"subtype": "compact_boundary",
...
이 엔트리에서 읽을 수 있는 사양은 세 가지입니다.
parentUuid: null— 여기서parentUuid체인이 물리적으로 단절됩니다. 페이로드를 재구성할 때, 이 이전의 엔트리는 추적되지 않습니다.logicalParentUuid
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기