Claude Code의 SessionStart hook을 이용해 이전 작업 메모와 git 상태를 세션 시작 시 자동 주입하는 구현 절차
요약
Claude Code의 SessionStart hook을 활용하여 이전 작업 메모와 git 상태를 자동으로 컨텍스트에 주입하는 구현 절차를 설명합니다. 이 기능을 통해 사용자는 매번 세션 시작 시 상황 설명을 반복할 필요 없이, 프로젝트의 연속성을 유지하며 작업을 이어갈 수 있습니다.
핵심 포인트
- SessionStart hook은 스크립트 출력을 Claude 컨텍스트에 자동 주입한다.
- 환경변수는 `CLAUDE_ENV_FILE`을 통해 추가해야 세션 전체에 상속된다.
- hook 내부에서 파일 쓰기 시에는 반드시 '추가(append)' 모드('a')를 사용해야 한다.
Claude Code를 매일 사용하다 보면, 세션을 열 때마다 '지난번에 어디까지 했더라', '지금 어느 브랜치였지' 같은 설명을 다시 하는 것이 꽤 번거로워진다. CLAUDE.md에 적을 만큼 영구적인 정보는 아니고, 그날/그 순간의 상태를 매번 전달하고 싶다.
이것을 자동화하는 것이 바로 SessionStart hook이다. 세션 시작 시 스크립트를 실행하여 그 출력을 Claude의 컨텍스트에 주입할 수 있다.
본 글은 SessionStart hook으로 '이전 작업 메모'와 'git 상태'를 자동으로 주입하는 구현 절차와, 필자가 직접 겪었던 세 가지 난관을 정리한 것이다.
예상 독자
- Claude Code를 일상적으로 사용하며 hooks를 한 번쯤 만져본 사람
- 장시간/다중 세션에 걸친 작업에서 매번 상황 설명을 생략하고 싶은 사람
환경
- Claude Code v2.1 계열 (2026년 10월 기준)
- macOS 15 / Python 3.13
- hooks 설정은
.claude/settings.json에 작성한다.
(프로젝트 단위)
- SessionStart hook은 exit 0으로 stdout에 출력한 내용이 그대로 컨텍스트로 들어간다. JSON의
additionalContext에 주입된다. - 전달할 수 있는 matcher는
startup,/resume,/clear,/compact네 종류가 있다.startup만 사용하면/compact나/clear후에 정보가 사라진다. hook 내부에서export한 환경변수는 Bash 툴로 상속되지 않는다. 환경변수는CLAUDE_ENV_FILE에 추가해야 한다.
.claude/settings.json에 아래와 같이 작성한다.
{
"hooks": {
"SessionStart": [
...
}
$CLAUDE_PROJECT_DIR은 프로젝트의 루트를 가리킨다. 상대 경로로 작성할 경우, 서브 디렉토리에서 실행했을 때 스크립트를 찾지 못하고 조용히 실패하므로, 절대 경로로 해결해 두는 것이 좋다.
.claude/hooks/session_start.py:
#!/usr/bin/env python3
import json
import os
...
stdin에는 session_id, cwd, hook_event_name, source 등이 포함된 JSON이 전달된다. source를 보면 신규 시작인지 /compact 후인지를 구분할 수 있다.
chmod +x .claude/hooks/session_start.py
echo '{"source":"startup"}' | CLAUDE_PROJECT_DIR=$PWD python3 .claude/hooks/session_start.py
JSON이 한 줄로 출력되면 OK다. 이어서 claude를 실행하고, 처음에
회피책: SessionStart hook에만 전달되는 CLAUDE_ENV_FILE
해당 경로에 export 문을 **추가(append)**한다. 여기에 작성된 내용은 이후 Bash 툴 실행 시 로드된다.
env_file = os.environ.get("CLAUDE_ENV_FILE")
if env_file:
with open(env_file, "a", encoding="utf-8") as f:
...
만약 덮어쓰기("w")를 사용하면 다른 hook이 작성한 줄을 지워버리므로 반드시 "a"로 해야 한다. 민감 정보는 여기에 직접 기재하지 않고, 기존의 셸 설정이나 시크릿 관리 시스템에서 읽어오는 형태로 유지한다.
증상: "main 브랜치에서 직접 작업했을 때 경고하고 중단시키고 싶다"고 생각하여 PreToolUse와 같은 방식으로 exit 2를 반환했다. 그러나 세션은 아무 일 없이 시작되었고, Claude는 경고를 알지 못했다.
원인: SessionStart는 **블록할 수 없는 이벤트(non-blockable event)**이다. exit 2의 stderr는 사용자 화면에 표시될 뿐 Claude에게 전달되지 않는다. 게다가 JSON 출력은 exit 0일 때만 해석되므로, exit 2로 설정하는 순간 additionalContext도 버려진다.
회피책: 중단시키는 것은 포기하고, exit 0 상태를 유지하면서 주의 문구를 주입한다.
if git("branch", "--show-current") in ("main", "master"):
parts.insert(0, "**경고: 기본 브랜치에 있습니다. 작업 전에 반드시 브랜치를 분리하세요.**")
정말로 작업을 멈추게 하고 싶다면, 블록 기능은 PreToolUse hook이 담당하도록 해야 한다.
나는 무인으로 장시간 구동되는 자율 시스템(완전 자율 구현 시스템)을 운영하고 있으며, 에이전트가 작업 종료 시 handoff.md 파일에 "수행한 내용 / 다음 할 일 / 미해결 문제"를 작성하는 운영 방식을 사용한다. 다음 세션은 이를 SessionStart에서 받기 때문에, 인간의 개입 없이도 작업이 끊김 없이 진행된다.
주의할 점은 양이다. git log나 diff 전체를 흘려보내면 매 세션 수천 토큰을 소비하게 된다. 나는 "최근 5개 커밋 + 간략한 상태 요약 + 메모 3000자까지"로 범위를 좁히고 있다. 또한 hook이 느리면 세션 시작 자체가 지연되므로, git 명령어에도 개별적인 타임아웃을 설정했다.
SessionStarthook은exit 0과 stdout(또는additionalContext)를 통해 컨텍스트를 주입할 수 있다.- matcher는
compact/clear등을 포함하지 않으면, 압축 후 인계 정보가 사라진다. - 환경 변수는
export가 아니라CLAUDE_ENV_FILE에 추가한다. SessionStart는 블록 불가하므로,exit 2를 사용하지 않고 주의 문구 주입으로 대응한다.- 주입량과 스크립트 실행 시간은 의식적으로 제한해야 한다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기