AI & IT toolsAI Workflow

Keeping a multi-week Claude Code project on track: RESUME files, handoffs and context limits

A long Claude Code chat gets summarized or cut as it grows, so for work that runs for weeks we split it into sessions with a short 'current summary' in a RESUME file, a /handoff command, and a status line and hook that report context usage. We follow the real records of our working folder and an example we ran ourselves.

AZTechnology17 min read

한국어English

Based on: the Claude Code docs (Status line, Hooks reference, Commands, Context window) and Node.js 24 on Windows 11 with Git Bash installed. Checked on November 5, 2026. Figure 1 is a chart drawn from our working folder's git history. Figure 2 shows the real output of this guide's example scripts, laid out as a terminal window.

For a job that ends in a day or two, one Claude Code chat is enough. Work that runs for weeks is different. As a chat grows, Claude Code summarizes the earlier part to make room, and any decision lost in that summary has to be explained again the next day. Open a new chat and you start from zero.

This guide shares the method we use in a working folder where Blender video work has run on Claude Code for weeks. Keep the memory in files, not in the chat. Any chat can end at any time, and a new chat reads a few files and picks up right away.

By the end of this guide you can:

  1. Tell what happens when the context window fills up.
  2. Set up the three kinds of files a new session reads first (CLAUDE.md, RESUME, handoff notes).
  3. Make a /handoff command to run at the end of a day.
  4. Show context usage in the status line and add a hook that tells Claude at 60% and 70%.
  5. Decide how much a new session reads before it starts.

Before you start: Claude Code must be installed. Setup is in Getting started with Claude Code. The examples in section 4 use Node.js. If node -v prints a version in a command prompt, you are ready. On Windows, also install Git for Windows (Git Bash). The status line and hook in section 4 are written to run in Git Bash.

1. What happens when the context window fills up

The context window is how much text Claude can see at once in one chat. Think of it as the size of a desk. The chat, the files Claude reads, and command output all pile up on it. When the desk is full, the oldest papers have to be cleared. The idea is explained in What tokens and context windows mean.

Claude Code has three commands for the desk.

CommandWhat it doesWhat stays
/compactSummarizes the chat so far to free space. Also runs on its own as the window fillsThe summary, the CLAUDE.md at the project root (reloaded from disk), and up to five files read or edited most recently
/clearStarts a new chat with empty contextProject memory (CLAUDE.md and so on). The old chat can be reopened with /resume
/contextShows what fills the context right now as a colored gridNothing changes

The point of the table: you do not choose what survives a summary. You can add focus notes after /compact, but weeks of decisions rarely fit in one summary. CLAUDE.md, on the other hand, is reloaded from disk even after compaction. So anything that must last goes in a file, not in the chat.

2. The three kinds of files a new session reads

Here, files are kept in three layers. A new session reads from the top only as far as it needs.

FileWhat it holdsLengthComparison
CLAUDE.mdRules that do not change, and "what to read when a session starts"Short (ours is 60 lines)The notice on the office wall
The "current summary" in RESUME.mdWhere work stopped, files to look at, the next step, what a person must decide30 lines or fewerA sticky note on the desk
Handoff notes reports/<date>_handoff_<area>.mdEverything done that day, output paths, blockersCan be longThe work diary

The reason for three layers is to cut how much a new session reads. A new session reads the wall notice and the sticky note and starts working. It opens the diary only when it needs the details.

2-1. Add a "session start" section to CLAUDE.md

Starting point: open the project folder you want to continue. If there is no CLAUDE.md at the top of the folder, create one.

Follow along:

  1. Open CLAUDE.md at the top of the project folder in Notepad.
  2. Paste this section at the top and save.
## Session start
1. Read only the "Current summary" section at the top of RESUME.md. Open the history below it only when needed.
2. Start from "Files to look at" and "Next step" in the summary.
3. Do not read large files (over 2,000 lines) in full. Search for the part you need, or ask a subagent for a summary.

## Context rules
- From 60% context usage, start no new work and only finish the current step.
- At 70%, write the handoff with /handoff and continue in a new session.

Keep CLAUDE.md short. Ours once grew to 13 KB (121 lines) with tables and background. On October 11 we moved the detailed tables to other documents and cut it to 5 KB (60 lines). A file that loads every time takes desk space before any work begins.

2-2. Make a "current summary" in RESUME.md

Follow along:

  1. Create RESUME.md at the top of the project folder.
  2. Paste the template below and fill it in with the current state.
# <project name> resume

## Current summary (<date> handoff)

**One line:** <one sentence on how far you got and where you stopped>

| Item | Content |
|---|---|
| Files to look at | <path to the output or comparison image> |
| Next step | <the one thing the new session does first> |
| Needs a decision | <what is waiting for a person> |
| Lesson | <one line that prevents the same mistake> |
| Handoff | reports/<date>_handoff_<area>.md |

## History: <date> <what was done>
- (move old summaries down here)

There are two rules. First, the current summary stays at 30 lines or fewer. When it goes over, move the oldest parts down to the history section. Second, you rewrite the summary instead of adding to it. If you only add, the summary turns back into a diary.

2-3. What happens if you keep adding

Bar chart. The status board grew from 65 lines on October 3 to 114 on the 9th, 131 on the 10th and 143 on the 11th, then stayed at 80 to 83 lines from October 12 to November 4

Figure 1. Line count of the one-page status board that tracks progress by area. Only days with commits, peak count for each day (chart, from the working folder's git history)

Our folder has a one-page status board with the current state of each area. At first we added a line whenever there was news. As Figure 1 shows, it went from 65 to 143 lines in about a week, and new sessions could no longer read all of it. On October 11 we changed the rule: one line per area, and you rewrite that line. Older progress goes to the handoff notes and the RESUME files. Since then the board has stayed around 80 lines for nearly a month.

The RESUME current summary works the same way. That is why it has a 30-line limit.

3. A /handoff command to end the day

Writing a handoff by hand every time means some fields get skipped. Turn the steps into one command. Claude Code uses a file at .claude/commands/<name>.md as the command /<name>. The docs suggest skills (.claude/skills/<name>/SKILL.md) for new commands, but command files still work. Here we use a command file because it is a single file.

Follow along:

  1. Create a .claude\commands folder inside the project folder.
  2. Create handoff.md in it, paste the following and save.
---
description: Write today's handoff
---
Sum up what this session did today so the next session can continue right away.

1. Rewrite the "Current summary" section at the top of RESUME.md (30 lines or fewer) to match the current state.
   - Fields: one line, files to look at, next step, needs a decision, lesson, handoff note path
   - Rewrite, do not append. If it goes over 30 lines, move the oldest parts to the "History" section below.
2. Write today's work in detail in reports/<today's date>_handoff_<area>.md.
   - What was done, output file paths, what is left, blockers and why, questions for me
3. Report results only if they are in files. Do not write numbers or results that exist only in memory.
4. Finally, report to me in three lines: what got done today, what I should check, what comes next.
  1. Open Claude Code again and type / in the input box. If /handoff is in the list, it worked.

Rule 3 ("only if they are in files") is there on purpose. At the end of a long chat, the summarized memory and the real files can disagree. If a wrong number gets into the handoff, the next session takes it as fact.

Our folder collected 80 handoff notes from September 30 to November 5. A new session opens only yesterday's one, and only when it needs to.

4. A status line and a hook for 60% and 70%

The hard part of a handoff is knowing when. When you are deep in work, you forget how full the context is. So we add two things.

  • Status line: a line that always shows at the bottom of Claude Code. Like the fuel gauge in a car, it shows context usage.
  • UserPromptSubmit hook: a script Claude Code runs every time you send a message. Like a low-fuel warning light, it attaches a short note for Claude when usage passes a line.

A file links the two. The status line script writes the context % to ~/.claude/ctx/<session ID>.json, and the hook reads that file. The hook's input does not include context usage, but the status line's input does.

60% and 70% are lines our folder chose. They are not official recommendations. We set 70% so that there is still room to write and check the handoff after it starts. Change them to fit your work.

4-1. Make the status line script

Starting point: continue in the project folder you set up through section 2.

Follow along:

  1. Type %USERPROFILE%\.claude in the File Explorer address bar and press Enter. Your Claude Code user settings folder opens.
  2. Create statusline.mjs in it, paste the code below as is, and save.
// Status line: show the model and context usage, and save the context % per session to a file.
import fs from "node:fs";
import path from "node:path";
import os from "node:os";

let input = "";
process.stdin.on("data", (chunk) => (input += chunk));
process.stdin.on("end", () => {
  let data = {};
  try { data = JSON.parse(input.replace(/^\uFEFF/, "")); } catch {}
  const model = data.model?.display_name ?? "Claude";
  const pct = data.context_window?.used_percentage;

  // save one file per session so another script (the hook) can read it
  if (data.session_id && typeof pct === "number") {
    try {
      const dir = path.join(os.homedir(), ".claude", "ctx");
      fs.mkdirSync(dir, { recursive: true });
      fs.writeFileSync(path.join(dir, `${data.session_id}.json`), JSON.stringify({ ctx: pct, t: Date.now() }));
    } catch {}
  }

  const shown = typeof pct === "number" ? `${Math.round(pct)}%` : "?";
  console.log(`[${model}] context ${shown}`);
});
  1. Open settings.json in the same folder, or create it. Add the statusLine field below and save. Replace <your user name> with your Windows user folder name.
{
  "statusLine": {
    "type": "command",
    "command": "node \"C:/Users/<your user name>/.claude/statusline.mjs\""
  }
}

If settings.json already has other fields, add only "statusLine": {…} inside the outer { }, separated by a comma. Write the path with forward slashes (/), not backslashes (\). On Windows, Claude Code runs this command through Git Bash when Git Bash is installed, and Git Bash strips backslashes, which breaks the path.

The status line redraws when a session opens, each time Claude replies, and when /compact finishes. At the very start of a session there is no usage value yet, so it may show context ?. Usage counts input-side tokens only (the chat, files read, and cache).

4-2. Make the context watch hook

Follow along:

  1. Create a .claude\hooks folder inside the project folder.
  2. Create ctx_watch.mjs in it, paste the code below as is, and save.
// UserPromptSubmit hook: on every prompt, read this session's context % and tell Claude when it passes a line.
import fs from "node:fs";
import path from "node:path";
import os from "node:os";

const WARN = 60;     // stop starting new work
const HANDOFF = 70;  // hand off and move to a new session

let input = "";
process.stdin.on("data", (chunk) => (input += chunk));
process.stdin.on("end", () => {
  try {
    const data = JSON.parse(input.replace(/^\uFEFF/, "") || "{}");
    const sid = String(data.session_id || "");
    if (!sid || /[\\/.]/.test(sid)) return;
    const file = path.join(os.homedir(), ".claude", "ctx", `${sid}.json`);
    if (!fs.existsSync(file)) return;
    const pct = JSON.parse(fs.readFileSync(file, "utf8")).ctx;
    if (typeof pct !== "number" || pct < WARN) return;

    const text = pct >= HANDOFF
      ? `Context usage in this session is ${Math.round(pct)}%. In this project, from ${HANDOFF}% no new work starts: the current step is finished, then /handoff writes the handoff notes and work continues in a new session.`
      : `Context usage in this session is ${Math.round(pct)}%. In this project, from ${WARN}% no new work starts and only the current step is finished.`;
    process.stdout.write(JSON.stringify({
      hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext: text },
    }));
  } catch {
    // if anything fails, do nothing (never block the prompt)
  }
});
  1. Open .claude\settings.json in the project folder, or create it. Add the following and save.
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/ctx_watch.mjs\"",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

Three things in the hook script are worth a look.

  • The note states facts, not orders. The docs recommend writing hook text as plain facts, like "The deployment target is production". Text that looks like a system command can make Claude treat it as an injected instruction and ask you about it. So the note says "In this project, from 70% …" instead of "Stop now".
  • If it cannot read something, it stays quiet. This hook runs on every message, and Claude waits until it finishes. An error must not block the chat, so every failure is swallowed in catch. The timeout is also short at 5 seconds (the default for this hook is 30 seconds).
  • The hook only reports. It cannot end a session or start a new one. You run /clear and start the new session yourself.

4-3. Test first

Before you attach them to Claude Code, run the scripts on their own. Feed a fake input JSON and check the output.

Follow along:

  1. Open Git Bash and cd to the user settings folder that holds statusline.mjs (~/.claude).
  2. Run these two lines in turn. Repeat with 65 in the first line changed to 42 and then 74.
echo '{"session_id":"demo-session","model":{"display_name":"Opus"},"context_window":{"used_percentage":65}}' | node statusline.mjs
echo '{"session_id":"demo-session","prompt":"hi"}' | node "/c/<project folder>/.claude/hooks/ctx_watch.mjs"

A dark terminal. At 42% only the status line prints and the hook prints nothing. At 65% a hookSpecificOutput JSON with the 60% rule note prints, and at 74% one with the 70% rule and the /handoff note

Figure 2. The status line script and the hook run at 42%, 65% and 74%. The figure shortens the first command's input JSON and splits the hook's JSON output over lines for reading; the real output is one line (run output of the English scripts above, Git Bash)

You should see three things, as in Figure 2. At 42% only the status line text appears and the hook prints nothing. At 65% you get the 60% note, and at 74% the /handoff note. When the test is done, you can delete ~/.claude/ctx/demo-session.json.

If the test looks right, open Claude Code. When [model name] context N% shows at the bottom, the status line is working.

5. How to continue in a new session

When the hook reports 70%, move over in this order.

Follow along:

  1. Finish only the current step (editing one file, running one test).
  2. Run /handoff. Claude rewrites the RESUME current summary and the handoff notes, then reports in three lines.
  3. Open RESUME.md yourself and check that "Next step" holds a single thing.
  4. Run /clear. The old chat is not deleted; it stays in the /resume list.
  5. In the new chat, send "Continue from the RESUME current summary." Thanks to the "session start" section in CLAUDE.md, Claude reads only the summary and starts.

Here we go one step further. Work is split into "lanes" by area, and each lane has one card (what to read, the flow, what it hands over). A new session starts with /lane <lane name> and reads only that card and that lane's RESUME summary. With several areas, this stops a new session from filling its desk with other areas' records.

6. Other habits for long work

HabitWhy
Agents report "full text in a file, a 10-line summary in the chat"Long subagent reports pasted into the chat fill the context fast
Files over 2,000 lines are not read directly; a subagent summarizes themA subagent reads in its own context window and returns only the summary
One agent does not get endless roundsIn our character work, after one agent ran more than six rounds in a row, the amount done per round dropped; it came back when we switched to a new agent that read the how-to doc and the score file (one record, October 11)
Status boards and summaries are rewritten, not appendedThe 143-line status board in section 2-3

How to split work among subagents is in Subagents and multi-agent systems.

Exercises

  1. Pick one of your projects and write its RESUME current summary in 15 lines or fewer. Check that "Next step" holds a single thing.
  2. Run /context and write down the largest block in your current context.
  3. Change WARN in ctx_watch.mjs to 50 and run the test in section 4-3 again. See how the output changes at 42% and 65%.
  4. Run /handoff at the end of a day, and the next day note whether a new session could continue from the RESUME alone.

Common mistakes and fixes

SymptomCauseFix
The status line does not showA comma or quote error in settings.json, or a path with backslashesCheck the JSON syntax and write the path with slashes, like C:/Users/…
The status line keeps showing context ?No value yet at the start of a sessionLook again after Claude replies once
Nothing happens past 70%The status line is off, so no context file is writtenCheck that a session ID file appears in ~/.claude/ctx/
Testing in PowerShell prints only context ?PowerShell adds a BOM (an invisible marker character) to the start of the text it pipesStrip it before parsing with replace(/^\uFEFF/, ""), as in the example
A new session does not know yesterday's workRESUME was not rewritten, or CLAUDE.md has no "session start" sectionRecheck sections 2-1 and 3
The summary grew long againOnly appendingMove the oldest parts to history past 30 lines

Summary

Memory in files (CLAUDE.md → RESUME current summary → handoff notes), context on a gauge (status line), and a warning light for when to move (stop at 60%, hand off at 70%). The first guide below explains why a long chat loses track of earlier parts.

References

KEEP EXPLORING

Read next

Claude Code Docs page. In the left menu, Automate actions with hooks is selected under Automation. The centre shows the same title and a description starting with Hooks are user-defined shell commandsAI & IT tools
AI Workflow16 min read

Claude Code hooks: blocking risky agent commands with a PreToolUse guard

Build a small Python script that Claude Code runs just before an AI agent uses a tool, and use it to block five things: deleting lock files, wrapping Blender in timeout, factory-startup installs, running Blender without the lock script, and reading secret files. Real test output included.

A Claude Code terminal answering a question about the Higgsfield MCP connection, with a table showing the connection is working and a second table showing both the Blender MCP and the Higgsfield MCP are connectedAI & IT tools
AI Workflow13 min read

Using Higgsfield from Claude Code: connect over MCP, get a quote first, submit one job at a time, and keep a log

Compare the MCP and CLI ways of connecting Higgsfield to Claude Code, then follow the real order we used for one scene of a sponsored video: checking the connection, uploading files, making a style frame, getting a quote, submitting the video, waiting for the result, and keeping a credit ledger.

Four frames from the first version of the air defense game. Launchers in a low-poly desert at sunset, the score, base health 100, and a green bar at the top left, time left 0:30, 0:17, 0:07, and 0:00 at the top right, and in the last frame the Korean text for Defense succeeded! Score 1500, R: restart (Godot run screenshot)AI & IT tools
AI Workflow13 min read

Setting the scope of your first game: a size a solo developer can finish, and how to schedule it

To take a first solo game all the way to the end, you need to cut it down to the right size. This guide covers what to write on a one-page plan and how to split the schedule into steps, with real times, snags, and scope changes from making three small games in Godot.

Air defense game screen in a low-poly desert at sunset. Box 1 is the on-screen text at the top left, box 2 is missile smoke and an explosion, box 3 is a launcher truck at the bottom left (Godot run screenshot)AI & IT tools
AI Workflow18 min read

Splitting solo game dev work with AI: what to hand off, what to check, terms, and Steam and itch.io AI disclosure

When you make a game alone, how much of the code, 3D assets, art, sound, and text can you hand to AI, and where must a person check the result? This guide covers the commercial-use terms of each kind of tool, the AI disclosure rules on Steam and itch.io, and what AI actually did in a Godot game test.

A low-poly desert at sunset with four launchers. A missile rises from the left launcher, a three-ring aim circle with a yellow 90% sits among red diamond markers in the sky, and the top left shows remaining launchers 4/4 and remaining missiles 31 (Godot run screenshot)AI & IT tools
AI Workflow13 min read

A map of solo game development: what Blender, AI, and a game engine each do, and the steps to your first game

When you make a game alone, Blender, an AI assistant, and a game engine each take a different part of the work. This guide sorts out who does what, lays out seven steps to a first finished game, and shows notes from making small games in Godot. It is the starting page of a five-part series on solo development.

The Script screen of the Godot editor. Under func _steer at line 102 of missile.gd are var to_t := target.position - position, var dist := to_t.length(), var want := (lead - position).normalized(), and var ang := dir.angle_to(want), with a list of functions on the leftAI & IT tools
AI Workflow16 min read

What helps to know before solo game development: what you need without a degree and what AI fills in

When you make a game alone, which parts of programming, math (vectors and coordinates), art, sound, and game design do you really need, and which can AI and tools fill in? This guide answers with real game code and notes, including what AI cannot fill in, and points to the official learning material for each engine.