Optimize Claude Code Token Usage

Cut Claude Code token usage by 40-60% with benchmarked optimizations.

Introduction

30 Second Summary

Every message you send to an AI coding assistant carries a hidden cost: tokens. If you're hitting your usage limit by lunchtime, there's a good chance your tool is re-reading thousands of lines of code it never needed in the first place.

In this project, you will build a Token Benchmark Lab to test which Claude Code optimizations save tokens without sacrificing output quality. You'll walk away with hard data and a setup that cuts your token usage by 40-60%.

What You'll Build

A fully optimized Claude Code environment built on top of a realistic Next.js project, with benchmark data proving exactly which token-saving techniques work for your workflow.

By the end of this project, you'll have:

  • A benchmark scorecard comparing token costs and output quality across four optimization layers.
  • A lean CLAUDE.md and .claudeignore configuration that cuts context reads by 30-40%.
  • A daily workflow cheat sheet for session management, model switching, and context hygiene.
  • A chance to install the Caveman plugin and a usage dashboard for long-term token tracking in the Secret Mission.

Are there any prerequisites?

You need a Claude Pro ($20/mo), Max 5x ($100/mo), or Max 20x ($200/mo) subscription. This project walks you through the full setup for everything else, including Node.js and the Claude Code CLI.

Before We Start

Before We Start...

Set Up Your Environment

Every message you send to Claude Code costs tokens. The more files Claude reads, the more tokens you burn.

Before you can benchmark and optimize that cost, you need the right tools installed. In this step, you will install Node.js and the Claude Code CLI, then set up your paid Claude account.

In this step, get ready to:
  • Install Node.js and the Claude Code CLI.
  • Create your Claude account and subscribe to a paid plan.
  • Authenticate Claude Code in your terminal.
Install Node.js and Claude Code CLI

Node.js is the JavaScript runtime that powers both the Claude Code CLI and the project scaffolding tool you will use in the next step.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal and press Enter to open it.
  • Check if Node.js is already installed by running this command:
node --version

I see a version number

You are all set. Make sure the version number is v18 or higher. If it is lower, follow the install instructions in the other tab to upgrade.

Command not found

No worries. You need to install Node.js first.

  • Open your browser and go to nodejs.org.
  • Click the LTS download button. This downloads the installer for your operating system.
  • Run the downloaded installer and follow the on-screen prompts.
  • Close your terminal completely and reopen it.
  • Confirm the installation by running this command:
node --version

You should now see a version number starting with v18 or higher.

Now you will install the Claude Code CLI. This is the tool that lets you interact with Claude directly from your terminal.

  • Install Claude Code by running the command for your operating system:

macOS

  • Install Claude Code using the native installer by running this command:
curl -fsSL https://claude.ai/install.sh | bash

Linux

  • Install Claude Code using the native installer by running this command:
curl -fsSL https://claude.ai/install.sh | bash

Windows

  • Install Claude Code using npm by running this command:
npm install -g @anthropic-ai/claude-code

You should see a confirmation message when the installation finishes.

Installation failed?

  • Make sure Node.js v18 or higher is installed. Both install methods require it.
  • On macOS or Linux, if the native installer fails, try the npm method instead:
npm install -g @anthropic-ai/claude-code
  • If you get a permissions error with npm, try prefixing the command with sudo (macOS/Linux) or run your terminal as Administrator (Windows).
  • Help me troubleshoot my Claude Code installation.
Create your Claude account and subscribe

Claude Code requires a paid Claude subscription to work. Without one, the CLI cannot authenticate.

  • Open your browser and go to claude.ai.
  • Click Sign Up to create a new account, or Log In if you already have one.
  • Click your profile icon in the bottom-left corner of the sidebar.
  • Select Settings.
  • Click Billing.
  • Choose a paid plan: Pro ($20/mo), Max 5x ($100/mo), or Max 20x ($200/mo).
  • Complete the payment flow to activate your subscription.

Which plan should I choose?

Pro ($20/mo) is enough to complete this project. The Max plans give you higher usage limits, which matter if you use Claude Code heavily every day.

You can always start with Pro and upgrade later if you hit usage limits frequently.

Authenticate Claude Code

The first time you run Claude Code, it opens a browser window for a one-time OAuth login. After that, your terminal stays authenticated.

  • Start the authentication flow by running this command in your terminal:
claude

A browser window opens automatically. If it does not, the terminal prints a URL you can copy and paste into your browser manually.

  • Complete the sign-in flow in your browser using the same account you subscribed with.
  • Return to your terminal after you see the authentication success message in the browser.

Your terminal now shows the Claude Code interactive session. Type /exit and press Enter to close it for now.

  • Verify your authentication works by running this command:
claude "hello"

You should see Claude respond with a short greeting in your terminal. This confirms that authentication is working.

  • Confirm your installed version by running this command:
claude --version

You should see a version number printed in your terminal.

Authentication not working?

  • Make sure you completed the sign-in flow in the browser. The terminal waits until the browser confirms authentication.
  • Check that you logged into the same account that has a paid subscription. Claude Code does not work on free accounts.
  • Try running claude again if the browser window closed before you could log in.
  • Help me troubleshoot Claude Code authentication.

Your tools are installed and authenticated. Next up, you will create the benchmark test bed project that gives Claude a real codebase to chew through.

Create Your Benchmark Test Bed

Your environment is ready, but a bare-bones starter project is not enough to test token optimizations. A project with only two or three files produces nearly identical token counts no matter what you do, because there is so little context for Claude Code to read.

In this step, you will scaffold a realistic Next.js project with ~20 source files: components, API routes, utilities, and a planted bug. This gives Claude enough codebase to make real decisions about what to read, and enough surface area for your optimizations to produce measurable differences.

In this step, get ready to:
  • Scaffold a Next.js project as your benchmark test bed.
  • Add ~20 source files including a planted bug for quality testing.
  • Create a benchmark scorecard to track your results across optimization rounds.
Scaffold a Next.js project

Next.js generates a realistic project structure with node_modules (200MB+), config files, and the App Router layout. This makes it a perfect test bed for measuring how much context Claude Code reads.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Scaffold your Next.js project by running:
npx create-next-app@latest token-lab

What prompts will I see?

The CLI will ask you a series of setup questions. You need to customize settings so that your code lives inside a src/ directory. Follow the prompts below.

  • When asked "Would you like to use the recommended Next.js defaults?", select No, customize settings.
  • Enter Yes for the TypeScript prompt.
  • Select ESLint for the linter prompt.
  • Enter No for the React Compiler prompt.
  • Enter Yes for the Tailwind CSS prompt.
  • Enter Yes for the src/ directory prompt.
  • Enter Yes for the App Router prompt.
  • Enter No for the import alias prompt.
  • Enter No for the AGENTS.md prompt.

Why skip AGENTS.md?

The recommended defaults auto-generate an AGENTS.md and a CLAUDE.md file. You want to skip this because you will craft your own lean CLAUDE.md in a later step as part of your optimization benchmarks.

The CLI installs dependencies and creates your project folder. This takes a minute or two.

  • Move into your new project by running:
cd token-lab
  • Confirm the project was created by running:
ls src/app

You should see files like page.tsx, layout.tsx, and globals.css listed in the output.

Command not found or install failed?

  • Make sure Node.js is installed by running node --version. You need version 18+.
  • If npx is not recognized, reinstall Node.js from nodejs.org.
  • If the install hangs, check your internet connection and try again.

Still stuck? Help me troubleshoot why create-next-app is not working.

Add source files to bulk up the project

A freshly scaffolded Next.js project only has a handful of source files. You need to add enough code for Claude's context decisions to matter. You will create utility files, components, API routes, and a dashboard page.

One of these files will contain a planted bug: a fetch call missing await. This bug is your consistent quality check across every benchmark round.

  • Create the directories for your new files by running:
mkdir -p src/lib src/components src/app/api/health src/app/api/users src/app/dashboard
  • Confirm the directories were created by running:
ls src/lib src/components src/app/api

You should see health and users listed under src/app/api, plus empty src/lib and src/components directories.

Now open the project in your editor so you can create the source files.

  • Open the token-lab folder in VS Code by running:
code .

code command not found?

Open VS Code manually. Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar, type VS Code, and press Enter. Then click File > Open Folder and select the token-lab folder on your Desktop.

  • In VS Code, create a new file at src/lib/utils.ts and paste the following code:
export function formatDate(date: Date): string {
  return date.toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric",
  });
}

export function slugify(text: string): string {
  return text
    .toLowerCase()
    .replace(/[^\w\s-]/g, "")
    .replace(/\s+/g, "-")
    .trim();
}

export function truncate(text: string, maxLength: number): string {
  if (text.length <= maxLength) return text;
  return text.slice(0, maxLength) + "...";
}

export function classNames(...classes: (string | undefined | false)[]): string {
  return classes.filter(Boolean).join(" ");
}

What does this file do?

This is a standard utility file with helper functions for formatting dates, creating URL slugs, truncating strings, and joining CSS class names. These are common patterns Claude will encounter in real projects.

  • Create a new file at src/lib/constants.ts and paste the following code:
export const APP_NAME = "Token Lab";
export const APP_DESCRIPTION = "A benchmark test bed for Claude Code token optimization";

export const NAV_LINKS = [
  { label: "Home", href: "/" },
  { label: "Dashboard", href: "/dashboard" },
] as const;

export const API_ENDPOINTS = {
  health: "/api/health",
  users: "/api/users",
} as const;

export const ITEMS_PER_PAGE = 10;
  • Create a new file at src/lib/api-client.ts and paste the following code:
const API_BASE_URL = "https://api.example.com";

export async function fetchUsers() {
  // BUG: missing await on fetch call
  const response = fetch(`${API_BASE_URL}/users`);
  return response.json();
}

export async function fetchUserById(id: string) {
  const response = await fetch(`${API_BASE_URL}/users/${id}`);
  if (!response.ok) {
    throw new Error(`Failed to fetch user ${id}`);
  }
  return response.json();
}

export async function createUser(data: { name: string; email: string }) {
  const response = await fetch(`${API_BASE_URL}/users`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  return response.json();
}

This file has a planted bug. Do not fix it.

The fetchUsers() function is missing await on the fetch call. This means response is a Promise, not a Response object, so .json() will fail at runtime. In every benchmark round, you will check whether Claude catches this bug.

  • Save all three files.
  • Create a new file at src/components/Header.tsx and paste the following code:
import Link from "next/link";
import { APP_NAME, NAV_LINKS } from "@/lib/constants";

export default function Header() {
  return (
    <header className="border-b border-gray-200 bg-white">
      <nav className="mx-auto flex max-w-7xl items-center justify-between p-6">
        <Link href="/" className="text-xl font-bold">
          {APP_NAME}
        </Link>
        <ul className="flex gap-6">
          {NAV_LINKS.map((link) => (
            <li key={link.href}>
              <Link
                href={link.href}
                className="text-gray-600 hover:text-gray-900"
              >
                {link.label}
              </Link>
            </li>
          ))}
        </ul>
      </nav>
    </header>
  );
}
  • Create a new file at src/components/Footer.tsx and paste the following code:
import { APP_NAME } from "@/lib/constants";

export default function Footer() {
  return (
    <footer className="border-t border-gray-200 bg-white py-8">
      <div className="mx-auto max-w-7xl px-6 text-center text-sm text-gray-500">
        <p>&copy; {new Date().getFullYear()} {APP_NAME}. Built for benchmarking.</p>
      </div>
    </footer>
  );
}
  • Create a new file at src/components/UserCard.tsx and paste the following code:
import { truncate } from "@/lib/utils";

interface UserCardProps {
  name: string;
  email: string;
  bio?: string;
}

export default function UserCard({ name, email, bio }: UserCardProps) {
  return (
    <div className="rounded-lg border border-gray-200 p-4 shadow-sm">
      <h3 className="text-lg font-semibold">{name}</h3>
      <p className="text-sm text-gray-500">{email}</p>
      {bio && (
        <p className="mt-2 text-sm text-gray-700">{truncate(bio, 100)}</p>
      )}
    </div>
  );
}

What do these components do?

  • Header.tsx renders a navigation bar with links pulled from your constants file.
  • Footer.tsx renders a simple copyright footer.
  • UserCard.tsx displays a user's name, email, and truncated bio. It imports from your utils.ts file, creating cross-file dependencies for Claude to discover.
  • Save all three component files.
  • Create a new file at src/app/api/users/route.ts and paste the following code:
import { NextResponse } from "next/server";

const users = [
  { id: "1", name: "Alice Johnson", email: "alice@example.com" },
  { id: "2", name: "Bob Smith", email: "bob@example.com" },
  { id: "3", name: "Carol Williams", email: "carol@example.com" },
];

export async function GET() {
  return NextResponse.json({ users });
}

export async function POST(request: Request) {
  const body = await request.json();
  const newUser = {
    id: String(users.length + 1),
    name: body.name,
    email: body.email,
  };
  users.push(newUser);
  return NextResponse.json({ user: newUser }, { status: 201 });
}
  • Create a new file at src/app/api/health/route.ts and paste the following code:
import { NextResponse } from "next/server";

export async function GET() {
  return NextResponse.json({
    status: "ok",
    timestamp: new Date().toISOString(),
  });
}
  • Create a new file at src/app/dashboard/page.tsx and paste the following code:
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import UserCard from "@/components/UserCard";

const SAMPLE_USERS = [
  { name: "Alice Johnson", email: "alice@example.com", bio: "Full-stack developer who loves TypeScript and clean architecture." },
  { name: "Bob Smith", email: "bob@example.com", bio: "DevOps engineer focused on CI/CD pipelines and infrastructure automation." },
  { name: "Carol Williams", email: "carol@example.com" },
];

export default function Dashboard() {
  return (
    <div className="flex min-h-screen flex-col">
      <Header />
      <main className="mx-auto w-full max-w-7xl flex-1 p-8">
        <h1 className="text-2xl font-bold">Dashboard</h1>
        <p className="mt-2 text-gray-600">Sample users for benchmarking.</p>
        <div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          {SAMPLE_USERS.map((user) => (
            <UserCard key={user.email} {...user} />
          ))}
        </div>
      </main>
      <Footer />
    </div>
  );
}
  • Save all three files.

Finally, replace the default home page with one that uses your new components.

  • Open src/app/page.tsx in VS Code.
  • Select all the existing content and replace it with the following code:
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import { APP_DESCRIPTION } from "@/lib/constants";

export default function Home() {
  return (
    <div className="flex min-h-screen flex-col">
      <Header />
      <main className="flex flex-1 flex-col items-center justify-center p-8">
        <h1 className="text-4xl font-bold">Token Lab</h1>
        <p className="mt-4 text-lg text-gray-600">{APP_DESCRIPTION}</p>
      </main>
      <Footer />
    </div>
  );
}

What does this page do?

This replaces the default Next.js starter page with a simple home page that imports your Header, Footer, and APP_DESCRIPTION constant. The cross-file imports are the point. They give Claude real dependency chains to follow when analyzing your project.

  • Save src/app/page.tsx.
  • Verify your file count by switching to your terminal and running:
find src -name '*.ts' -o -name '*.tsx' | wc -l

You should see a count of at least 10 TypeScript files. Combined with the config files and generated files, your project has ~20 files for Claude to work with.

Seeing fewer files than expected?

  • Double-check you created all the directories with the mkdir -p command earlier.
  • Make sure each file was saved in the correct path. Check the Explorer sidebar in VS Code to verify the folder structure.

Need help finding a missing file? Help me figure out which source files I am missing in my token-lab project.

Awesome, I've got everything!

Great. Double check you have saved every file before moving on.

I'd like to double check the full code

Here is every source file you should have at this point. Compare each one against your project.

export function formatDate(date: Date): string {
  return date.toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric",
  });
}

export function slugify(text: string): string {
  return text
    .toLowerCase()
    .replace(/[^\w\s-]/g, "")
    .replace(/\s+/g, "-")
    .trim();
}

export function truncate(text: string, maxLength: number): string {
  if (text.length <= maxLength) return text;
  return text.slice(0, maxLength) + "...";
}

export function classNames(...classes: (string | undefined | false)[]): string {
  return classes.filter(Boolean).join(" ");
}
export const APP_NAME = "Token Lab";
export const APP_DESCRIPTION = "A benchmark test bed for Claude Code token optimization";

export const NAV_LINKS = [
  { label: "Home", href: "/" },
  { label: "Dashboard", href: "/dashboard" },
] as const;

export const API_ENDPOINTS = {
  health: "/api/health",
  users: "/api/users",
} as const;

export const ITEMS_PER_PAGE = 10;
const API_BASE_URL = "https://api.example.com";

export async function fetchUsers() {
  // BUG: missing await on fetch call
  const response = fetch(`${API_BASE_URL}/users`);
  return response.json();
}

export async function fetchUserById(id: string) {
  const response = await fetch(`${API_BASE_URL}/users/${id}`);
  if (!response.ok) {
    throw new Error(`Failed to fetch user ${id}`);
  }
  return response.json();
}

export async function createUser(data: { name: string; email: string }) {
  const response = await fetch(`${API_BASE_URL}/users`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  return response.json();
}
import Link from "next/link";
import { APP_NAME, NAV_LINKS } from "@/lib/constants";

export default function Header() {
  return (
    <header className="border-b border-gray-200 bg-white">
      <nav className="mx-auto flex max-w-7xl items-center justify-between p-6">
        <Link href="/" className="text-xl font-bold">
          {APP_NAME}
        </Link>
        <ul className="flex gap-6">
          {NAV_LINKS.map((link) => (
            <li key={link.href}>
              <Link
                href={link.href}
                className="text-gray-600 hover:text-gray-900"
              >
                {link.label}
              </Link>
            </li>
          ))}
        </ul>
      </nav>
    </header>
  );
}
import { APP_NAME } from "@/lib/constants";

export default function Footer() {
  return (
    <footer className="border-t border-gray-200 bg-white py-8">
      <div className="mx-auto max-w-7xl px-6 text-center text-sm text-gray-500">
        <p>&copy; {new Date().getFullYear()} {APP_NAME}. Built for benchmarking.</p>
      </div>
    </footer>
  );
}
import { truncate } from "@/lib/utils";

interface UserCardProps {
  name: string;
  email: string;
  bio?: string;
}

export default function UserCard({ name, email, bio }: UserCardProps) {
  return (
    <div className="rounded-lg border border-gray-200 p-4 shadow-sm">
      <h3 className="text-lg font-semibold">{name}</h3>
      <p className="text-sm text-gray-500">{email}</p>
      {bio && (
        <p className="mt-2 text-sm text-gray-700">{truncate(bio, 100)}</p>
      )}
    </div>
  );
}
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import { APP_DESCRIPTION } from "@/lib/constants";

export default function Home() {
  return (
    <div className="flex min-h-screen flex-col">
      <Header />
      <main className="flex flex-1 flex-col items-center justify-center p-8">
        <h1 className="text-4xl font-bold">Token Lab</h1>
        <p className="mt-4 text-lg text-gray-600">{APP_DESCRIPTION}</p>
      </main>
      <Footer />
    </div>
  );
}
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import UserCard from "@/components/UserCard";

const SAMPLE_USERS = [
  { name: "Alice Johnson", email: "alice@example.com", bio: "Full-stack developer who loves TypeScript and clean architecture." },
  { name: "Bob Smith", email: "bob@example.com", bio: "DevOps engineer focused on CI/CD pipelines and infrastructure automation." },
  { name: "Carol Williams", email: "carol@example.com" },
];

export default function Dashboard() {
  return (
    <div className="flex min-h-screen flex-col">
      <Header />
      <main className="mx-auto w-full max-w-7xl flex-1 p-8">
        <h1 className="text-2xl font-bold">Dashboard</h1>
        <p className="mt-2 text-gray-600">Sample users for benchmarking.</p>
        <div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          {SAMPLE_USERS.map((user) => (
            <UserCard key={user.email} {...user} />
          ))}
        </div>
      </main>
      <Footer />
    </div>
  );
}
import { NextResponse } from "next/server";

const users = [
  { id: "1", name: "Alice Johnson", email: "alice@example.com" },
  { id: "2", name: "Bob Smith", email: "bob@example.com" },
  { id: "3", name: "Carol Williams", email: "carol@example.com" },
];

export async function GET() {
  return NextResponse.json({ users });
}

export async function POST(request: Request) {
  const body = await request.json();
  const newUser = {
    id: String(users.length + 1),
    name: body.name,
    email: body.email,
  };
  users.push(newUser);
  return NextResponse.json({ user: newUser }, { status: 201 });
}
import { NextResponse } from "next/server";

export async function GET() {
  return NextResponse.json({
    status: "ok",
    timestamp: new Date().toISOString(),
  });
}
Create your benchmark scorecard

You need a structured place to record your benchmark results across every optimization round. This scorecard tracks input tokens, output tokens, and quality scores so you can compare each technique with hard data.

  • Create a new file called benchmark-results.md at the root of your token-lab folder (not inside src/) and paste the following:
# Token Benchmark Scorecard

## Benchmark Prompts
- **Debug Task**: "Review the codebase for bugs, focusing on src/lib/ and src/app/. List each bug with the file path, line number, what is wrong, and how to fix it."
- **Edit Task**: "Add a new API route at src/app/api/health/route.ts that returns a JSON response with the current server timestamp and a status of ok."

## Results

### Round 1: Baseline (No Optimizations)

| Metric | Debug Task | Edit Task |
|--------|-----------|----------|
| Input Tokens | | |
| Output Tokens | | |
| Cache Read Tokens | | |
| Bug Found? (yes/no) | | n/a |
| Code Runs? (yes/no) | n/a | |
| Quality (1-5) | | |

### Round 2: After .claudeignore + CLAUDE.md

| Metric | Debug Task | Edit Task |
|--------|-----------|----------|
| Input Tokens | | |
| Output Tokens | | |
| Cache Read Tokens | | |
| Bug Found? (yes/no) | | n/a |
| Code Runs? (yes/no) | n/a | |
| Quality (1-5) | | |

### Round 3: Haiku Model

| Metric | Debug Task | Edit Task |
|--------|-----------|----------|
| Input Tokens | | |
| Output Tokens | | |
| Cache Read Tokens | | |
| Bug Found? (yes/no) | | n/a |
| Code Runs? (yes/no) | n/a | |
| Quality (1-5) | | |

### Round 4: Caveman Mode (Secret Mission)

| Metric | Debug Task | Edit Task |
|--------|-----------|----------|
| Input Tokens | | |
| Output Tokens | | |
| Cache Read Tokens | | |
| Bug Found? (yes/no) | | n/a |
| Code Runs? (yes/no) | n/a | |
| Quality (1-5) | | |

## Summary

### Token Reduction by Layer

| Optimization | Input Token Change | Output Token Change | Quality Impact |
|-------------|-------------------|--------------------:|----------------|
| Baseline | -- | -- | -- |
| .claudeignore + CLAUDE.md | % | % | |
| Haiku Model | % | % | |
| Caveman (Secret Mission) | % | % | |

### My Optimization Playbook

1.
2.
3.
4.
5.

What does the scorecard track?

  • Input Tokens measure how much Claude reads. This is where 99%+ of your token budget goes.
  • Output Tokens measure how much Claude writes back.
  • Cache Read Tokens show how much Claude reused from its prompt cache instead of reprocessing.
  • Quality scores tell you whether a token-saving technique actually hurts the output.
  • Save benchmark-results.md.

Why two benchmark prompts?

The debug task tests Claude's ability to analyze and comprehend existing code. The edit task tests Claude's ability to generate new, runnable code. Together they cover both quality dimensions, so you can see if an optimization helps one type of task but hurts another.

Your test bed is ready. Next up, you will run the baseline benchmark to capture your starting token costs before applying any optimizations.

Run the Baseline Benchmark

Your test bed is loaded with ~20 source files and a planted bug lurking in api-client.ts. Everything is in place to start measuring.

Without a baseline, there is no way to prove that future optimizations actually save tokens. In this step, you will run two standardized prompts against your project with zero optimizations and record both the token cost and the output quality.

In this step, get ready to:
  • Define two benchmark prompts that test different skills.
  • Run the baseline benchmark using one-shot mode.
  • Score each result for quality alongside token cost.
Define your two benchmark prompts

For your benchmarks to be meaningful, you need the same prompts across every round of testing. You also need each run to start with a clean slate so accumulated context does not muddy the results.

Claude Code offers a mode called one-shot mode (claude -p) that is perfect for this. Each run sends a single prompt with zero conversation history, then exits.

What is one-shot mode?

Running claude -p sends a single prompt to Claude Code and prints the response. There is no interactive session, no accumulated conversation history, and no prior context.

This makes every run independent and reproducible. If you ran benchmarks in an interactive session, leftover context from previous messages would change your token counts from run to run.

Here are the two prompts you will use across all benchmark rounds:

  • Prompt 1 (Debug task): "Review the codebase for bugs, focusing on src/lib/ and src/app/. List each bug with the file path, line number, what is wrong, and how to fix it."
  • Prompt 2 (Edit task): "Add a new API route at src/app/api/health/route.ts that returns a JSON response with the current server timestamp and a status of ok."

Why a debug task and an edit task?

The debug task tests whether Claude can comprehend your code and spot issues. The edit task tests whether Claude can generate working code from scratch.

Together they cover both quality dimensions. The planted bug in api-client.ts (a missing await) gives you a consistent quality signal across every round.

Run the baseline benchmark

You will add --output-format json to each command so Claude returns structured JSON with token usage data instead of plain text.

  • Navigate into your project by running this command:
cd ~/Desktop/token-lab
  • Run the debug task benchmark by running this command:
claude -p "Review the codebase for bugs, focusing on src/lib/ and src/app/. List each bug with the file path, line number, what is wrong, and how to fix it." --output-format json

What does this command do?

  • claude -p runs Claude Code in one-shot mode. One prompt in, one response out, no session.
  • The quoted string is your prompt, sent directly to Claude.
  • --output-format json returns structured JSON including fields like input_tokens, output_tokens, and cache_read_input_tokens. These are the numbers you need for your scorecard.

This command may take 30-60 seconds to complete. Claude will read your source files, analyze the code, and return its findings as JSON.

  • Run the edit task benchmark by running this command:
claude -p "Add a new API route at src/app/api/health/route.ts that returns a JSON response with the current server timestamp and a status of ok." --output-format json
  • Open benchmark-results.md in your text editor.
  • Find the Round 1: Baseline table.
  • Fill in the Input Tokens, Output Tokens, and Cache Read Tokens rows using the values from each run's JSON output.

Command not working?

  • Make sure you are inside the token-lab directory. Claude Code needs to be in the project root to read your source files.
  • If you see an authentication error, run claude interactively (without -p) and complete the OAuth flow again. Then retry the command.
  • If the command hangs for more than 2 minutes, press Ctrl+C to cancel and try again. Temporary network issues can cause timeouts.
  • My claude -p command is failing or returning unexpected output. Help me debug.
Score the quality of each result

Token counts only tell half the story. An optimization that saves tokens but produces wrong answers is useless.

For each benchmark run, you need a quality score alongside the cost data. Start with the debug task.

  • Review Claude's debug task output from the JSON response.
  • Check whether Claude found the missing await bug in src/lib/api-client.ts. Record "yes" or "no" in the Bug Found? row.
  • Rate the explanation quality on a scale of 1-5 in the Quality row. A 5 means Claude identified the exact line, explained why it is wrong, and provided the correct fix.

Now check the edit task. You need to verify that Claude's generated health route actually runs.

  • Check whether src/app/api/health/route.ts was created or modified by Claude. If Claude only described the code in its output without creating the file, create the file manually and paste in the code Claude generated.
  • Start the Next.js dev server by running this command:
npm run dev

What should I see?

You should see output indicating the dev server is running, typically on http://localhost:3000. Wait until you see a "Ready" message before continuing. The dev server will keep running in this terminal.

  • Open a new terminal tab by pressing Cmd+T (macOS) or Ctrl+Shift+T (Windows).
  • Test the health endpoint by running this command:
curl http://localhost:3000/api/health

You should see a JSON response containing a status of "ok" and a timestamp value with the current server time.

  • Record "yes" or "no" in the Code Runs? row based on whether you got a valid JSON response.
  • Rate the edit task quality on a scale of 1-5 in the Quality row. A 5 means the code ran without modification and returned the expected format.
  • Stop the dev server by pressing Ctrl+C in the terminal where it is running.
  • Save benchmark-results.md with all your Round 1 results filled in.

Curl returning an error?

  • Make sure the dev server is still running in your other terminal tab. If it crashed, run npm run dev again.
  • If the endpoint returns a 404, the health route file may not exist. Check whether src/app/api/health/route.ts exists in your project. If it does not, create the file manually and paste Claude's generated code into it.
  • If you see Connection refused, make sure you are curling localhost:3000 and not a different port. Check the dev server output for the correct URL.
  • My health endpoint is returning an error after Claude's edit task. Help me figure out what went wrong.

You now have a baseline showing exactly how many tokens Claude uses with zero optimizations. These are the numbers to beat. Next up, you will add a .claudeignore file and a CLAUDE.md to see how much you can cut.

Apply Environment Optimizations

You now have baseline benchmark numbers showing exactly how many tokens Claude Code consumes with zero optimizations in place. Those numbers are about to drop.

In this step, you will create two configuration files that control what Claude reads and how it behaves. These are the highest-impact optimizations available, and they take just minutes to set up.

In this step, get ready to:
  • Create a .claudeignore file to exclude generated files from Claude's context.
  • Craft a lean CLAUDE.md with project context and context-gathering rules.
  • Re-run your benchmark prompts and measure the token reduction.
Create a .claudeignore file

Claude Code reads every file it can access when it needs context about your project. Files like node_modules/, .next/, and package-lock.json add thousands of tokens without providing useful information.

A .claudeignore file works like .gitignore. Any path listed in it becomes completely invisible to Claude Code.

  • In VS Code, create a new file called .claudeignore in the root of your token-lab folder.
  • Paste the following contents into the file:
# Dependencies
node_modules/

# Build output
.next/
out/
dist/
build/

# Lock files
package-lock.json
yarn.lock
pnpm-lock.yaml

# Version control
.git/

# Test coverage
coverage/
.nyc_output/

# Cache
.cache/
.turbo/
.eslintcache

# Environment files
.env
.env.local
.env*.local

# IDE
.idea/
.vscode/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Generated types
*.generated.ts
*.generated.js

What does this file do?

  • node_modules/ contains hundreds of megabytes of dependency code that Claude never needs to reference.
  • .next/ holds build artifacts that change on every build. In a Next.js project, excluding .next/ alone typically cuts context size by 30-40%.
  • Lock files like package-lock.json can be thousands of lines long. Claude has no reason to read them.
  • Environment files like .env are excluded for security. This keeps sensitive values out of Claude's reach.
  • Save .claudeignore.
  • Confirm the file exists by running:
ls -a

You should see .claudeignore listed alongside your other project files like package.json and .gitignore.

Don't see .claudeignore in the list?

  • Files starting with a dot are hidden by default. Make sure you used the -a flag with ls.
  • Check that you saved the file in the root of token-lab, not inside src/ or another subdirectory.
  • Confirm the file name starts with a dot. It should be .claudeignore, not claudeignore.

Why isn't my .claudeignore file showing up?

Awesome, I've got everything!

Double check you have saved .claudeignore before moving on.

I'd like to double check the full code

Here is the complete .claudeignore file for comparison.

# Dependencies
node_modules/

# Build output
.next/
out/
dist/
build/

# Lock files
package-lock.json
yarn.lock
pnpm-lock.yaml

# Version control
.git/

# Test coverage
coverage/
.nyc_output/

# Cache
.cache/
.turbo/
.eslintcache

# Environment files
.env
.env.local
.env*.local

# IDE
.idea/
.vscode/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Generated types
*.generated.ts
*.generated.js
Craft a lean CLAUDE.md

CLAUDE.md is a special configuration file that Claude Code loads at the start of every session. It is also re-read on every single message you send.

This means every line in your CLAUDE.md adds to your token cost on every turn. The goal is to keep it lean (under 200 lines) while giving Claude the project context it needs.

  • Create a new file called CLAUDE.md in the root of your token-lab folder.
  • Paste the following contents into the file:
# Token Lab - Project Context

## Tech Stack
- Next.js 15 (App Router)
- TypeScript
- Tailwind CSS
- Node.js 18+

## Key Directories
- src/app/ - Pages and API routes (App Router)
- src/app/api/ - API route handlers
- src/components/ - Reusable UI components
- src/lib/ - Utilities, constants, and API client
- public/ - Static assets

## Context Rules
- Minimize tool calls. Do not re-read files already in this session.
- Do not read files for context unless explicitly asked.
- Work from what is already in the conversation.
- Batch all changes into as few operations as possible.
- When exploring code, read only the specific file mentioned.

## Coding Conventions
- Use TypeScript strict mode
- Prefer async/await over .then() chains
- Use named exports for API routes
- Components use default exports

Why is the Context Rules section so important?

99.4% of the tokens Claude Code uses are input tokens. Claude reads 166 times more than it writes. Reducing what Claude reads is the single biggest lever you have.

  • Without context rules, Claude tends to re-read files it already has in context and make extra tool calls "just in case."
  • The instruction to minimize tool calls and work from existing conversation context directly reduces file reads per response.
  • The rest of the file (Tech Stack, Key Directories, Coding Conventions) gives Claude the minimum context to navigate your project without exploring blindly.
  • Save CLAUDE.md.
  • Confirm the file exists by running:
ls CLAUDE.md

You should see CLAUDE.md printed in the output. If the file is not found, the command prints an error instead.

Seeing "No such file or directory"?

  • Make sure the file name is all uppercase: CLAUDE.md, not claude.md or Claude.md. The casing matters.
  • Check that your terminal is in the token-lab directory. Run pwd to confirm.
  • Confirm the file is in the root of token-lab, not inside src/.

Why isn't Claude Code picking up my CLAUDE.md file?

Awesome, I've got everything!

Double check you have saved CLAUDE.md before moving on.

I'd like to double check the full code

Here is the complete CLAUDE.md file for comparison.

# Token Lab - Project Context

## Tech Stack
- Next.js 15 (App Router)
- TypeScript
- Tailwind CSS
- Node.js 18+

## Key Directories
- src/app/ - Pages and API routes (App Router)
- src/app/api/ - API route handlers
- src/components/ - Reusable UI components
- src/lib/ - Utilities, constants, and API client
- public/ - Static assets

## Context Rules
- Minimize tool calls. Do not re-read files already in this session.
- Do not read files for context unless explicitly asked.
- Work from what is already in the conversation.
- Batch all changes into as few operations as possible.
- When exploring code, read only the specific file mentioned.

## Coding Conventions
- Use TypeScript strict mode
- Prefer async/await over .then() chains
- Use named exports for API routes
- Components use default exports

Why is .claudeignore a free win?

Some optimizations involve tradeoffs. You might save tokens but lose output quality. .claudeignore is different. Claude never needed to read node_modules/ or build artifacts in the first place. Excluding them costs you nothing in quality and saves significant tokens on every interaction.

Re-run the benchmark

With both configuration files in place, it is time to measure the impact. You will run the exact same benchmark prompts from Step 3 so you can compare the results directly.

  • Make sure your terminal is in the token-lab directory.
  • Run the debug task benchmark by running this command:
claude -p "Review the codebase for bugs, focusing on src/lib/ and src/app/. List each bug with the file path, line number, what is wrong, and how to fix it." --output-format json
  • Find the input_tokens, output_tokens, and cache_read_input_tokens values in the JSON output.
  • Record these numbers in benchmark-results.md under the Round 2 Debug Task row.
  • Run the edit task benchmark by running this command:
claude -p "Add a new API route at src/app/api/health/route.ts that returns a JSON response with the current server timestamp and a status of ok." --output-format json
  • Record the same token metrics under the Round 2 Edit Task row.
  • Score the quality for each task using the same criteria from your baseline. Did Claude find the missing await bug in api-client.ts? Would the health endpoint code actually run?
  • Compare your Round 2 numbers against your baseline numbers from Step 3.

What should I see?

  • Your input token count should be noticeably lower than baseline. The .claudeignore file prevents Claude from reading node_modules/, .next/, and other generated files.
  • The CLAUDE.md context rules may also reduce how many files Claude reads during the debug task.
  • Quality scores should be the same or very close to your baseline. These optimizations cut noise, not useful information.

Token counts look the same as baseline?

  • Double-check that .claudeignore is in the root of your token-lab folder, not inside src/ or another subdirectory.
  • Make sure the file is named exactly .claudeignore with a leading dot. Without the dot, Claude Code ignores it.
  • Verify that you ran the command from inside the token-lab directory. Claude Code reads the .claudeignore from whatever directory you run it in.

Why didn't my .claudeignore reduce my token usage?

You now have hard data showing the impact of environment-level optimizations. Next up, you will test whether switching to a cheaper model can save even more tokens without sacrificing quality.

Test Model Switching

Your .claudeignore and CLAUDE.md are now filtering out unnecessary files and guiding Claude to read less. But there is another lever you have not pulled yet: the model itself.

Haiku costs roughly 1/4 of Sonnet per token. In this step, you will benchmark Haiku against your Sonnet results to find out exactly where the quality tradeoff kicks in.

In this step, get ready to:
  • Run both benchmark prompts using the Haiku model.
  • Compare Haiku results against your optimized Sonnet baseline.
  • Record your model switching recommendations in the scorecard.
Run benchmarks with Haiku

The --model flag lets you override Claude Code's default model for any one-shot run. You will use it to swap in Haiku and measure the difference.

  • Make sure your terminal is in the token-lab folder (the Next.js project you created in Step 2).
  • Run the debug benchmark prompt with the Haiku model by running this command:
claude -p --model claude-haiku-4-5 "Review the codebase for bugs, focusing on src/lib/ and src/app/. List each bug with the file path, line number, what is wrong, and how to fix it." --output-format json

What does --model claude-haiku-4-5 do?

The --model flag overrides Claude Code's default model (Sonnet) for this single run. claude-haiku-4-5 is Claude's fastest and cheapest model. It processes tokens at roughly 1/4 the cost of Sonnet.

  • Find the input_tokens, output_tokens, and cache_read_input_tokens values in the JSON output.
  • Open benchmark-results.md and record these numbers under Round 3: Haiku Model in the Debug Task column.
  • Run the edit benchmark prompt with Haiku by running this command:
claude -p --model claude-haiku-4-5 "Add a new API route at src/app/api/health/route.ts that returns a JSON response with the current server timestamp and a status of ok." --output-format json
  • Record the token counts under Round 3: Haiku Model in the Edit Task column.

Now score the quality of each Haiku response, just like you did in your earlier benchmark rounds.

  • For the debug task, check whether Haiku found the missing await bug in src/lib/api-client.ts. Record yes or no in the Bug Found? row.
  • For the edit task, check whether the generated health endpoint code is complete and would run correctly. Record yes or no in the Code Runs? row.
  • Rate the overall quality of each response on a 1-5 scale and record it in the Quality row.
  • Save benchmark-results.md.

Not getting JSON output?

  • Make sure --output-format json is included at the end of your command.
  • Check that --model claude-haiku-4-5 uses hyphens, not underscores. Typos in the model name will cause an error.
  • If you see an authentication error, run claude in interactive mode to re-authenticate, then try the one-shot command again.
  • Help me troubleshoot my claude -p command with the --model flag.
Compare Haiku and Sonnet results

Your Round 2 results from Step 4 already captured Sonnet's performance with your environment optimizations in place. Now you can put the two models side by side.

  • Open benchmark-results.md and compare Round 2 (Sonnet with optimizations) against Round 3 (Haiku) for each metric.
  • For the debug task, check whether Haiku found the same bugs Sonnet found.
  • For the edit task, compare whether the generated code was equally complete and runnable.
  • Note whether any quality difference is genuinely worse or just different in style (for example, less verbose but still technically correct).

What should I look for?

  • Compare input token counts. Haiku and Sonnet may read different amounts of context for the same prompt.
  • Compare output token counts. Haiku responses are often shorter and more direct.
  • The quality column matters most. Did Haiku find the missing await bug? Was the health endpoint code complete?
  • A response that is shorter but still correct is not a quality loss. A response that misses the bug or produces broken code is.
Draw your model switching conclusions

Your benchmark data now tells you exactly when Haiku is good enough and when you need Sonnet. Time to turn those numbers into a decision framework you can use every day.

  • In benchmark-results.md, scroll down to the Token Reduction by Layer summary table.
  • Fill in the Haiku Model row with the percentage change in input tokens, output tokens, and your quality impact notes.
  • Add a Recommended Model column to the summary table.
  • For each task type (debug and edit), write which model you recommend based on your results.
  • Save benchmark-results.md.

How do I decide which model to recommend?

  • If Haiku scored 4-5 on quality for a task type, it is a strong fit for that kind of work. The token savings are a free win.
  • If Haiku scored 3 or below, Sonnet is worth the extra cost for that task type.
  • Simple edits, formatting, and straightforward generation tasks are typically Haiku-safe. Deep debugging and multi-file refactors often benefit from Sonnet's stronger reasoning.

You now have hard data on which model to reach for based on the task at hand. Next up, you will learn session management commands and build a daily workflow that keeps your token usage lean.

Master Session Management and Build Your Daily Workflow

You now know which models work best for different task types. The next piece of the puzzle is managing your sessions so tokens do not pile up silently while you work.

Every message you send in an interactive Claude Code session compounds the context. Claude re-reads the entire conversation history on each turn. Without deliberate session hygiene, a 20-message session can burn through tokens faster than five separate one-shot prompts doing the same work.

In this step, get ready to:
  • Practice the core session management commands in an interactive session.
  • Build session hygiene habits for compacting, clearing, and planning.
  • Create a daily workflow cheat sheet documenting your personal optimization playbook.
Learn the core commands

Claude Code has a set of slash commands that give you visibility into what is happening under the hood. These commands show you where your tokens are going, how much you have spent, and let you actively manage your context window.

  • Start an interactive Claude Code session by running this command from your token-lab directory:
claude

You should see the Claude Code interactive prompt appear, ready for input.

  • Check what is consuming your context by typing:
/context

What does /context show?

The /context command visualizes your context window usage. It shows you the breakdown of tokens consumed by the system prompt, MCP servers, your CLAUDE.md file, and conversation history. This is the single most important diagnostic command for understanding where your tokens go.

  • Check your session spend by typing:
/cost

What does /cost show?

The /cost command shows token usage statistics for the current session. It displays input tokens, output tokens, and the total cost. Get into the habit of checking this after every few messages.

  • Send a short message to Claude so you have some conversation history. Type a quick prompt like:
What files are in the src/lib directory?
  • Now compact your conversation to free up context by typing:
/compact

What does /compact do?

The /compact command summarizes your entire conversation history into a compressed form. A conversation that takes 20,000+ tokens can shrink to around 2,000-3,000 tokens. This frees up your context window so future messages cost less.

Be aware that compaction is lossy. Critical details can be lost during the summarization. If something important came up in the conversation, save it to CLAUDE.md before compacting.

  • Clear your session entirely by typing:
/clear

When to use /clear vs /compact

Use /compact when you are staying on the same task but your context is getting large. Use /clear when you are switching to a completely unrelated task. Clearing wipes all conversation history, giving you a truly fresh start with zero accumulated context.

  • Set up a status line to monitor your session at a glance. The /statusline command accepts a natural language description of what you want to see. Type:
/statusline show model name and context percentage

What does /statusline do?

The /statusline command generates a shell script and updates your settings automatically. It creates a persistent bar at the bottom of Claude Code that displays the information you requested. Now you can see your model and context usage at all times without running a command.

You should now see a status line at the bottom of your Claude Code window showing the current model name and your context percentage.

Status line not showing up?

The status line may not appear until your next interaction with Claude Code. Try sending any message to trigger a refresh. If it still does not appear, check that ~/.claude/settings.json contains a statusLine field.

Help me troubleshoot my Claude Code status line setup.

Practice session hygiene habits

Knowing the commands is one thing. Building habits around when to use them is what actually saves tokens over time. In this substep, you will practice three key habits.

  • Start a task by asking Claude to review a specific file. Type:
Review src/lib/api-client.ts for potential bugs.
  • Send 2-3 follow-up messages asking Claude about the bugs it found or requesting more details.
  • Run /context to see how your context has grown after those messages.
  • Now run /compact and observe how the context size drops.
  • Run /context again to compare the before and after.

Pro tip: the 60% rule

Auto-compact triggers at around 95% context capacity by default. By then, you have already been sending bloated messages for a while. Manually compact at 60% for better results and lower costs. You can also set the CLAUDE_AUTOCOMPACT_PCT_OVERRIDE environment variable to control the auto-compact threshold.

  • Now start an unrelated task. Run /clear first to wipe the previous conversation.
  • Try Plan mode by pressing Shift+Tab before typing your next prompt.

What is Plan mode?

Plan mode makes Claude output a plan before executing any changes. This prevents wasted tokens on wrong approaches. If Claude is about to take a wrong turn on a complex multi-file task, you can catch it at the planning stage instead of after it has already written incorrect code.

Toggle it with Shift+Tab. Use it before any task that touches 3 or more files.

  • With Plan mode on, type a complex prompt like:
Add a loading spinner component to the dashboard page.

Claude should output a plan for your review instead of immediately writing code. You can approve, modify, or reject the plan before any tokens are spent on execution.

  • Press Shift+Tab again to toggle Plan mode off when you are done practicing.

Pro tip: edit instead of correct

If you realize your prompt had a typo or missing detail, do not send a follow-up correction. Instead, press the up arrow to edit your original message. Follow-up corrections double the context cost because Claude re-reads the entire conversation including the wrong prompt.

Why does prompt caching matter here?

Claude Code uses prompt caching to avoid reprocessing unchanged conversation history. The cache has a 5-minute timeout. If you step away for more than 5 minutes, the next message reprocesses everything from scratch. This is invisible overhead that causes usage spikes after breaks.

Build your daily workflow cheat sheet

You have now practiced every core session management technique. It is time to capture everything you have learned into a reference document you can use every day.

  • Create a file called workflow-cheatsheet.md in the root of your token-lab folder.
  • Copy the following content into it:
# Claude Code Daily Workflow Cheat Sheet

## Session Start
- Start Claude Code from your project root: `claude`
- Check initial context load: `/context`
- Verify your model: look at the status line

## During a Task
- One task per session. Do not mix unrelated work.
- Use Plan mode (Shift+Tab) before complex tasks (3+ files).
- Reference specific files with @filename instead of letting Claude explore.
- Batch instructions into a single message when possible.
- Edit your original message instead of sending follow-up corrections.
- Watch Claude work. Stop it if it goes down the wrong path.

## Context Management
- Check context usage: `/context`
- Check cost: `/cost`
- Compact at 60% capacity: `/compact`
- Clear when switching tasks: `/clear`
- After 3-4 compacts in a row, get a session summary, /clear, paste summary, continue.

## Model Switching
- Default (most coding): Sonnet (`/model sonnet`)
- Simple tasks (formatting, quick edits): Haiku (`/model haiku`)
- Complex architecture decisions: Opus (`/model opus`) - use sparingly

## MCP Server Management
- Check what is loaded: `/context`
- Disconnect servers you are not actively using
- Prefer CLIs over MCP servers when available

## Timing Strategy
- Peak hours (higher usage drain): 8am-2pm ET weekdays
- Off-peak (normal/better rates): afternoons, evenings, weekends
- Rolling 5-hour window: messages sent at 9am stop counting by 2pm
- Spread work across 2-3 sessions per day
- If near your limit reset with time remaining, take a break
- If near a reset with budget remaining, go heavy

## Quick Commands Reference
- `/context` - See what is eating your tokens
- `/cost` - See session spend
- `/compact` - Summarize conversation, free context
- `/clear` - Wipe history, fresh start
- `/model [name]` - Switch models mid-session
- `claude -p "prompt"` - One-shot mode, zero context accumulation
- `Shift+Tab` - Toggle Plan mode

What does this cheat sheet cover?

  • Session Start tells you what to check every time you open Claude Code.
  • During a Task covers the habits that prevent token waste mid-session.
  • Context Management gives you the decision framework for when to compact vs clear.
  • Model Switching reminds you which model fits which task type, based on your Step 5 benchmarks.
  • Timing Strategy helps you plan your work around peak and off-peak usage windows.
  • Save workflow-cheatsheet.md.
  • Confirm the file exists by running:
ls workflow-cheatsheet.md

You should see workflow-cheatsheet.md listed in the output.

Pro tip: make it yours

This cheat sheet is a starting point. As you use Claude Code over the next few weeks, update it with your own observations. Add task types you frequently run, note which models you prefer for each, and adjust the 60% compaction rule if you find a different threshold works better for your workflow.

Awesome, I've got everything!

Great. Double check you have saved your file.

I'd like to double check the full code

# Claude Code Daily Workflow Cheat Sheet

## Session Start
- Start Claude Code from your project root: `claude`
- Check initial context load: `/context`
- Verify your model: look at the status line

## During a Task
- One task per session. Do not mix unrelated work.
- Use Plan mode (Shift+Tab) before complex tasks (3+ files).
- Reference specific files with @filename instead of letting Claude explore.
- Batch instructions into a single message when possible.
- Edit your original message instead of sending follow-up corrections.
- Watch Claude work. Stop it if it goes down the wrong path.

## Context Management
- Check context usage: `/context`
- Check cost: `/cost`
- Compact at 60% capacity: `/compact`
- Clear when switching tasks: `/clear`
- After 3-4 compacts in a row, get a session summary, /clear, paste summary, continue.

## Model Switching
- Default (most coding): Sonnet (`/model sonnet`)
- Simple tasks (formatting, quick edits): Haiku (`/model haiku`)
- Complex architecture decisions: Opus (`/model opus`) - use sparingly

## MCP Server Management
- Check what is loaded: `/context`
- Disconnect servers you are not actively using
- Prefer CLIs over MCP servers when available

## Timing Strategy
- Peak hours (higher usage drain): 8am-2pm ET weekdays
- Off-peak (normal/better rates): afternoons, evenings, weekends
- Rolling 5-hour window: messages sent at 9am stop counting by 2pm
- Spread work across 2-3 sessions per day
- If near your limit reset with time remaining, take a break
- If near a reset with budget remaining, go heavy

## Quick Commands Reference
- `/context` - See what is eating your tokens
- `/cost` - See session spend
- `/compact` - Summarize conversation, free context
- `/clear` - Wipe history, fresh start
- `/model [name]` - Switch models mid-session
- `claude -p "prompt"` - One-shot mode, zero context accumulation
- `Shift+Tab` - Toggle Plan mode

Your session management toolkit is locked in. Next up, you will bring all your benchmark results together and draw conclusions about which optimizations are free wins and which ones have tradeoffs.

Analyze Results and Draw Conclusions

You now have a session management toolkit, a daily workflow cheat sheet, and three full rounds of benchmark data sitting in your scorecard.

Raw numbers alone do not tell you what to do differently tomorrow. In this step, you will turn your benchmark data into a personal optimization playbook. You will calculate the real percentage savings from each technique, separate the free wins from the tradeoffs, and write down the specific habits you plan to keep.

In this step, get ready to:
  • Calculate percentage reductions in input and output tokens for each optimization layer.
  • Categorize each technique as a free win or a tradeoff based on your quality scores.
  • Write your personal optimization playbook with 3-5 concrete rules.
Complete your scorecard comparison

You have benchmark results from three rounds: the baseline (no optimizations), the environment-optimized round (.claudeignore + CLAUDE.md), and the Haiku model round. Now you need to compare them directly.

  • Open benchmark-results.md in your text editor.
  • Scroll down to the Summary section at the bottom of the file.
  • Find the Token Reduction by Layer table.

The table has columns for Input Token Change, Output Token Change, and Quality Impact. You will fill in the percentage changes now and handle quality in the next substep.

How do I calculate percentage reduction?

For each optimization layer, use this formula:

((baseline tokens - optimized tokens) / baseline tokens) x 100 = percentage reduction.

For example, if your baseline debug task used 50,000 input tokens and the .claudeignore round used 30,000, your reduction is ((50000 - 30000) / 50000) x 100 = 40%.

  • Pull the input token counts from each round's results table (Round 1, Round 2, and Round 3) for the debug task.
  • Calculate the percentage reduction for the .claudeignore + CLAUDE.md row by comparing Round 2 against your Round 1 baseline.
  • Calculate the percentage reduction for the Haiku row by comparing Round 3 against your Round 1 baseline.
  • Repeat both calculations for the output token counts.
  • Do the same for the edit task. You should now have percentage values for both tasks across both optimization layers.
  • Fill in the Input Token Change and Output Token Change columns with your calculated percentages.

Pro tip: average across tasks

If the debug task and edit task show different percentage reductions for the same layer, average them for the summary table. This gives you a single number that represents the overall impact of that optimization.

  • Save benchmark-results.md.

What should my numbers look like?

Results will vary based on your specific runs, but here is a rough guide from the research. Excluding .next/ alone typically cuts context size by 30-40% in Next.js projects. Haiku costs roughly 1/4 of Sonnet per token, so you should see a meaningful cost difference even if the raw token counts are similar.

If your numbers are wildly different from these ranges, double-check that you are comparing the right rounds and using the baseline as the denominator.

Identify free wins vs tradeoffs

A percentage reduction means nothing if the output quality tanked. The whole point of benchmarking quality alongside cost is to find which optimizations you can use without thinking and which ones require judgment.

  • Look at each round's results table and compare the Bug Found? and Quality (1-5) columns for the debug task.
  • Compare the Code Runs? and Quality (1-5) columns for the edit task.

Now categorize each optimization layer into one of two buckets.

What counts as a free win vs a tradeoff?

A free win is an optimization that reduced tokens with zero quality impact. The bug was still found. The code still ran. The quality score stayed the same or improved.

A tradeoff is an optimization where quality changed in exchange for cost savings. Maybe Haiku missed the bug. Maybe the code it generated had minor issues. The savings might still be worth it for certain tasks, but you need to be selective about when to use it.

  • For the .claudeignore + CLAUDE.md row, check whether both quality scores stayed the same as the baseline. If yes, write Free win in the Quality Impact column. If quality dropped, write Tradeoff and note what changed.
  • Do the same for the Haiku row.
  • Leave the Caveman row empty for now. That is part of the Secret Mission.

What the research says about these categories

Based on widely-reported benchmarks, .claudeignore is almost always a free win. Claude Code never needed to read node_modules/ or build artifacts to begin with.

Haiku handles simple, well-scoped tasks fine but may miss nuanced bugs that Sonnet catches. Your benchmark data tells you whether that held true for your specific prompts. Disconnecting unused MCP servers is another free win. A single MCP server can add around 18,000 tokens per message just from its tool definitions.

  • Save benchmark-results.md.
Write your personal optimization playbook

You have the data. You know what saves tokens and what costs quality. The last piece is committing to specific habits you will actually follow.

  • Scroll down to the My Optimization Playbook section at the very bottom of benchmark-results.md.

There are five numbered slots waiting for you. Fill each one with a concrete rule based on your data.

Pro tip: think in three buckets

Organize your playbook around three questions:

  • Which optimizations will I always use? (These are your free wins. They go on every project from day one.)
  • Which optimizations will I use situationally? (These are your tradeoffs. Define the specific conditions, like "use Haiku only for formatting and quick edits.")
  • Which optimizations will I skip? (If something did not help or hurt quality too much, name it and move on.)
  • Write 3-5 bullet points in the playbook section. Each bullet should name the technique, state when you will use it, and reference the data that supports your decision.

What does a good playbook bullet look like?

A strong playbook bullet is specific and actionable. Here are two examples:

  • "Always: Add a .claudeignore to every project on day one. Reduced input tokens by 38% with identical quality scores."
  • "Situational: Switch to Haiku for formatting tasks and simple refactors. Quality matched Sonnet on the edit task but missed the bug in the debug task."

Vague rules like "be more efficient" do not help. Tie every bullet to a number from your scorecard.

  • Save benchmark-results.md.
  • Review the completed file from top to bottom. Your scorecard now has filled-in results for each round, a summary table with percentage reductions and quality impact labels, and a personal playbook at the bottom.

Why does a personal playbook matter?

Generic optimization advice is everywhere online. The difference is that your playbook is backed by your own data, on your own project, with your own prompts. When a new optimization technique appears, you now have the benchmarking skills to test it yourself instead of trusting someone else's numbers.

Secret mission

Install Caveman and the Usage Dashboard

You have optimized your environment and benchmarked model switching. Now, push your output token savings even further with a plugin that makes Claude talk like a caveman. Then install a usage dashboard for long-term tracking and find out whether terse output is a free win or a quality tradeoff.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing cloud costs. Your Claude Pro or Max subscription is billed separately regardless of this project.

Resources you used:

  • token-lab Next.js project directory (local).
  • benchmark-results.md scorecard file (inside project).
  • workflow-cheatsheet.md daily workflow file (inside project).
  • .claudeignore and CLAUDE.md configuration files (inside project).
  • Claude Code CLI (globally installed via npm or native installer).
  • Caveman plugin and Huryn usage dashboard (Secret Mission only).

Keep everything running

No action needed. Choose this if you are still actively building or plan to use your optimized Claude Code setup as your daily driver.

  • Your token-lab project stays on disk as a reference for future benchmarks.
  • Your .claudeignore and CLAUDE.md files can be copied into any future project to apply the same optimizations.
  • Claude Code CLI stays installed globally for everyday use.

Pause - I'll come back to this later

There are no running processes or cloud resources to pause. Your project files sit on disk without consuming any resources while idle.

  • If you have a running Next.js dev server, stop it by pressing Ctrl+C in the terminal.
  • If you have an active Claude Code interactive session, type /clear to free up context, then exit with Ctrl+C.
  • Keep Claude Code CLI installed so you can pick up where you left off.
  • Your benchmark-results.md and workflow-cheatsheet.md files will be waiting for you in the project folder.

Delete - I don't want to use this again

Remove all project resources and start fresh. Before deleting, consider copying your .claudeignore and CLAUDE.md files somewhere safe. They are reusable across projects.

  • Delete the entire project directory by running rm -rf token-lab from the parent folder.
  • Uninstall Claude Code CLI globally by running npm uninstall -g @anthropic-ai/claude-code.
  • If you installed the Caveman plugin (Secret Mission), remove it by running claude plugin uninstall caveman.
  • If you cloned the Huryn usage dashboard (Secret Mission), delete it by running rm -rf claude-usage.
  • Your Claude Pro or Max subscription is unaffected. Manage it at claude.ai/settings if you want to change your plan.

Mission accomplished

That's a Wrap!

You did it! You went from blindly burning tokens to running a data-driven, optimized Claude Code setup with hard numbers proving exactly what works.

Here is what you accomplished:

  • Built a Token Benchmark Lab with ~20 source files and ran standardized benchmarks measuring both token cost and output quality across multiple optimization layers.
  • Configured .claudeignore and a lean CLAUDE.md with context-gathering rules that cut token usage by 30-40% with zero quality impact.
  • Created a personal optimization playbook and daily workflow cheat sheet backed by real benchmark data from model switching, session management, and quality comparisons.
  • Installed the Caveman plugin for terse output and the Huryn usage dashboard for long-term token tracking, then benchmarked whether terse mode is a free win or a tradeoff.

Ready to quiz yourself?