Skip to content
Mini workshop · Start here · Free

The first five walls of Claude Code.

Learning to work with AI turns out to be a lot like learning the fundamentals of data engineering. You can read the guidance and it does not stick. You learn the concept the first time you feel the pain of not knowing it, and from then on you navigate by the memory of not wanting to feel that again. Nobody internalises why a query is expensive from a style guide. They internalise it the morning it locks up the warehouse.

Claude Code works the same way. There are five walls almost everybody runs into, in roughly the same order, and each one has to be felt before the fix makes sense. That is not you learning it wrong. That is how the concept gets in.

So this mini workshop does the one thing that can actually be handed over in advance: it shows you what the five walls are. You will still hit them. You will just already know what you are looking at, and get to the way around it a lot faster than the people who had to work it out from scratch.

Written for people who have used Claude or Cowork, keep hearing that Claude Code is a different thing, and may not be technical. Every wall says whether you can already deal with it in the app you have, shows a before and after so the value is visible rather than claimed, and ships a starter file you can download and use the same day.

First five is deliberate. Every wall here is one person hitting the limits of their own setup, on the way from "it worked once" to "it works every time." The moment a second person shares that setup, a different set of walls starts, and those are a separate workshop.

What Claude Code is, next to the Claude app Home tab and Cowork, and which surface suits which job. Then the thesis for the hour: five walls almost everybody hits, in roughly the same order, each one only making sense once you have felt it.

Take the whole kit

Six files, no installation, nothing to sign up for. Every one is also shown in full on this page with a plain-English note on where it goes. The only ones that need a terminal are the two hooks, and each comes with a single line you can paste to prove it works before you trust it.

Download the starter kit CLAUDE.md · SKILL.md · HANDOFF.md · protect-secrets.sh · no-select-star.sh · settings-snippet.json

Every wall has a video. Watch it first, then use the files here to run the same thing against your own data.

Level 1 of 5

Raw prompting

Describe what you want. It builds it. No setup at all.

You are already here

This is what using Claude or Cowork feels like, except Claude Code is looking at the real files on your computer instead of things you upload. Nothing to configure.

Raw prompting is Claude Code with nothing set up at all: open a folder, describe what you want, and it goes. What the video makes visible is the real cost of that first answer, several minutes of trust gates, connection questions and auth choices before a single number appears. The wall is that none of that setup survives the session, so the next question starts the whole configuration over again.

For a small, self-contained job this is not a beginner mode you are meant to outgrow. It is the right level, and building machinery you do not need yet is its own kind of mistake.

The first session

You ask for something real and it works. Getting there took a stack of decisions first: trust this folder, use this tool, authenticate this way, the credentials live here. You answer them all, it runs, and the answer is right. This is the session that makes people say Claude Code is incredible, and they are not wrong.

The next session

Same folder, same warehouse, same question shape. It knows none of it. The trust prompt, the tool, the authentication, where things live: all of it again, from zero, because a session begins knowing nothing about you.

This is the first ceiling, and notice it is not a quality problem. Nothing was wrong with the answer. What went wrong is that the expensive part, the setup, was thrown away the moment the session ended, so you pay for it again every time.

What it costs you Nothing. There is nothing to build.
You have outgrown it when You are re-explaining your setup at the start of every session.
Try it yourself After watching, run this click path in a clean folder to feel the wall.

Same shape as the video: a brand-new folder, one real question, and everything it has to establish before it can answer.

  1. Do: Make an empty folder, start Claude Code in it, and ask a question that needs real data: "Pull our sales numbers for 2025 and 2026 out of the warehouse." See: Before any answer, it asks. Do you trust this folder. Can it read and write here. Which tool should it use, how should it authenticate. Every one of those is a decision you make, on the spot.
  2. Do: Answer them and let it work all the way to a number. See: It gets there, and it is genuinely impressive. Note the clock: most of that was not the question, it was the setup around it.
  3. Do: Now open a fresh session tomorrow and ask a second question of the same data. See: It knows none of it. Same folder, same warehouse, same conventions, and you are answering the same setup questions again.

The way around it: Wall one is not that the answer was wrong, it is that none of the setup survived the session. The way through is to write it down once, in a file the next session reads on its own. That file is wall two.

Try it in your environment The prompts from the video, which ran against our demo warehouse. Reword them for your own data: the shape of the question is the part to copy.

One question in an empty folder. What matters is not the answer, it is everything it has to ask you first.

Try a prompt like this
Pull our sales numbers for 2025 and 2026 out of the warehouse, and break them out by year.

Try a question like this in a folder with nothing set up, pointed at wherever your data actually lives. Count the questions it has to ask before it can start: trust the workspace, which client, which authentication, where the credentials live. Keep the permission prompts on rather than skipping them, because watching what it wants to do is the whole value at this level. Then note how long the setup took versus the answer, and remember you get to do it all again next session. That is wall one.

Level 2 of 5

A CLAUDE.md file

Write down the things you keep re-typing. It reads them before you say a word.

You have a version of this already

If you have used custom instructions on a Project in the Claude app, you know the idea. The difference is that this one is a file that lives inside the project, next to the actual work, so it travels with the folder and anyone else who opens it gets the same instructions.

CLAUDE.md is the working memory of a project folder, read at the start of every session before you say a word. The video builds one without ever opening an editor, by stating the rule in plain language and asking Claude to write the file, then proves it by opening a brand-new chat that already knows the conventions. It also makes the organising argument: keep separate files per project so unrelated work does not bleed together.

The file holds exactly what you were re-typing: what the project is, what your words mean, how you want things done, where things go. For most people it is the single biggest jump in reliability they will ever get.

Without the file

Every session opens with the same three paragraphs of context, pasted by you, every time. Skip the paste and you get generic output that has to be corrected. Over a week the ratio quietly flips: you spend more time steering than you save.

With the file

Your first message is the actual request. The context is already there, the same way every time, including for whoever else opens this folder next week.

The catch arrives later and it is counterintuitive. These files grow, because every line in them is something a real person genuinely wanted the model to know. Anthropic’s documentation is direct about the consequence: longer files reduce adherence, and instructions are context, not enforced configuration, so nothing guarantees strict compliance. The failure is silent: rules just get followed less consistently, and nothing tells you which ones.

The length rule, and the test that keeps you under it. Anthropic’s documentation does give a number: target under 200 lines per CLAUDE.md file, because longer files consume more context and reduce adherence. Treat the number as a target, not a cliff, and pair it with a sharper test we apply to every line: would removing this line cause Claude to make a mistake? If not, cut it. The test is ours rather than Anthropic’s, but it is how you get under the target without losing the lines that matter.

What it costs you An afternoon, once. Then ten minutes whenever something goes wrong.
You have outgrown it when The file is over a page, and rules you definitely wrote down are getting broken anyway.
Try it yourself After watching, run this click path in a clean folder to feel the wall.

Pick up in the same folder as wall one, once the setup finally works. You will never open the file by hand.

  1. Do: Do not write the file. Say it out loud in plain language and end with "add that to the CLAUDE.md file for this project" (exact wording in the copy block below). See: Claude writes CLAUDE.md for you, and it captures more than you dictated: the connection, how to authenticate, where the data lives. You maintained the file by talking, not editing.
  2. Do: Open the file and read it once, so you know what it actually recorded on your behalf. See: This is the step people skip. It is a plain text file you can read in a minute, and it is about to load into every session you start.
  3. Do: Start a completely new chat and ask a fresh question of the same data. See: No setup interview this time. It already knows where to go and how to get in, and answers straight away. That is wall one solved, in one file.

The way around it: Keep one CLAUDE.md per project rather than one big one, so unrelated work does not bleed together. The trap comes later: these files grow, and the documentation is clear that longer files reduce adherence. Prune against the removal test, then move whole procedures out into skills, which is wall three.

Try it in your environment The prompts from the video, which ran against our demo warehouse. Reword them for your own data: the shape of the question is the part to copy.

Same folder, same data. This time you teach it once instead of answering setup questions forever.

Try prompts like these, one at a time
Moving forward, whenever I ask about running a SQL query, I want you to run it against the demo database in the warehouse. Add that to the CLAUDE.md file for this project.
Now start a new chat in this folder and ask: break down 2025 sales by region.
Roughly what Claude writes for you (paste this instead if you would rather not dictate it)
# CLAUDE.md

## SQL queries, run against the demo database
Whenever the user asks about running a SQL query, or asks a data question a query
would answer, run it against the demo database. Do not just print the SQL, execute
it and report the results.

## How to connect
- Use the CLI already installed on this machine, with the "demo" connection profile.
- Auth is key-pair. The private key path is in the profile, never in this file.
- Never paste credentials into chat.

## The dataset
- Opportunities: one row per deal. Key columns include amount, close date, stage,
  is-won, fiscal year, region, owner.
- "Sales" means closed-won revenue, counted by close date.

Try the first prompt, reworded for your own setup, and Claude writes the file for you. Notice what it records without being asked: the connection profile, the auth method, a pointer to where the key lives rather than the key itself. Then open a brand-new chat and ask the second question. No setup interview, straight to the answer. You taught it once by talking.

Take this with you

Copy it from the page or download the file. Each one says where it goes.

CLAUDE.md A fill-in-the-blanks starter. Replace the bracketed parts, delete the rest.
Where it goes: Save it as CLAUDE.md in the top folder of your project. That is the entire installation.
# CLAUDE.md starter

Save this as `CLAUDE.md` in the top folder of your project. Claude Code reads it
at the start of every session, before your first message.

Replace everything in square brackets. Delete every line you do not need. A
short file that gets followed beats a thorough one that gets skipped.

Anthropic's guidance is to target under 200 lines, because longer files reduce
adherence. The sharper test for every single line below: **would removing this
line cause Claude to make a mistake?** If not, cut it. (The test is ours; the
200-line target is Anthropic's.)

---

## What this project is

[One or two sentences. What the work is, who it is for, what "done" looks like.]

## How I want you to work

- [Ask before X. For example: ask before creating a new file rather than editing
  an existing one.]
- [Show me Y before doing it. For example: show me the plan before you start
  changing things.]
- [Never Z without checking with me. For example: never send anything to anyone.]

## Words that mean something specific here

- **[Your term]**: [what it means in this project, and what it is NOT]
- **[Your term]**: [what it means in this project, and what it is NOT]

Ambiguous vocabulary is the single most common reason a capable model gives a
confidently wrong answer. If two words in your world could be confused, define
both here.

## Where things live

- [folder or file]: [what belongs there]
- [folder or file]: [what belongs there]

## How I want things written

- [Tone, format, or style rules. For example: plain language, no jargon.]
- [Formatting rules. For example: dates as YYYY-MM-DD.]

## Things that have gone wrong before

- [The mistake, and the rule that prevents it.]

Only keep entries here that have actually happened. This section is where these
files get bloated, and a bloated file is one Claude follows less reliably.

---

## Maintaining this file

Treat it like anything else you own: review it when something goes wrong, prune
it regularly, and check whether a change actually shifted the behaviour.

Two symptoms and what they usually mean:

- **A rule keeps getting broken.** The file is probably too long and that rule is
  getting lost. Cut other things.
- **Claude asks you something this file already answers.** The wording is
  probably ambiguous. Rewrite that line, do not add a second one.

If a rule must hold every single time, with no exceptions, this file is the
wrong home for it. This file is a request. A hook is enforcement.
Download CLAUDE.md
Level 3 of 5

Skills

A procedure you would otherwise explain out loud every time, written down once.

Claude and Cowork have these too

Same concept, and the file format is the same. What changes in Claude Code is what a skill is allowed to do: it can run a script that checks the work, rather than only describing how the work should be done.

A skill is a procedure written down once, so asking for the same thing twice stops producing two different answers. The video builds a monthly sales digest end to end, turns it into a skill you can call by name, and then tours what actually landed on disk: a SKILL.md sitting next to the script it runs. The idea worth keeping is the dial inside every skill, where more script means more deterministic, more rigid and cheaper in tokens, and more prose means more flexible and more variable run to run.

Honest sourcing: this level is documented by Anthropic and the mechanism is solid, but when we ran a separate pass over what practitioners report going wrong in the wild, complaints about skills not firing did not show up. Treat it as recommended practice, not as a widely reported problem.

A short document that teaches one procedure and stays out of the way until it is needed. Two things make it work. It costs almost nothing when unused, because only its name and one-line description load up front. And that description is not documentation, it is the entire basis on which the skill gets chosen, since Claude decides having read none of the rest.

Without a skill

Every Friday you explain the weekly update format again: what counts as a win, what a risk needs attached to it, how long it should be. It comes out slightly different every week, because your explanation was slightly different every week.

With a skill

You say "write the weekly update". The same procedure runs, in the same order, with the same rules about what gets left out. When the format needs to change you edit one file rather than remembering to say something different next Friday.

Which buys you consistency, and then stops. The procedure gets followed, but nobody is checking the result except you. A skill is still something the model reads and interprets, so you remain the only quality gate in the system, every single time.

Deterministic versus probabilistic, the dial inside every skill. A skill is a spectrum, and this is the most useful idea on this page. The more of it you write as an exact script, the more deterministic it is: the same result every single run, but rigid, and it breaks the moment the situation is a little different. The more you write as prose and prompt, the more probabilistic it is: you are leaning on the model to work out the specifics, which is flexible around the edges but more variable run to run. Neither end is correct. A database connection wants the deterministic end. Drafting a summary wants the flexible end. Choosing the mix per task IS the skill.

What it costs you An hour per procedure. Write it the next time you would have explained it anyway.
You have outgrown it when You have caught the same kind of mistake in the output three weeks running.
Try it yourself After watching, run this click path in a clean folder to feel the wall.

Best felt with something you will genuinely be asked for again, like a recurring summary for stakeholders.

  1. Do: Ask for a real deliverable, not a query. Something like a monthly digest of the numbers your stakeholders care about, and let it build the whole thing. See: You end up steering: what goes in, what format, how it looks. It gets there, and the result is good.
  2. Do: Here is the move. Once you are happy with it, say: "create a skill I can call any time to run this same report." See: It writes the skill for you, and asks whether it should be available everywhere or only in this project. Scope it to the project unless you really want it firing everywhere.
  3. Do: Go and look at what it created, under .claude/skills. On a Mac press Command Shift Period in Finder to see the dot folder. See: A SKILL.md holding the procedure, sitting next to the script it runs. That pairing is the whole idea: prose for the parts that need judgement, a script for the parts that must not vary.

The way around it: Next month you say "run the monthly digest" and get the same thing, in the same shape. Without the skill you would be re-steering all those choices from scratch and getting something slightly different, which is the actual pain that sends people here.

Try it in your environment The prompts from the video, which ran against our demo warehouse. Reword them for your own data: the shape of the question is the part to copy.

Build the thing once, then turn it into something you can call by name. That second prompt is the whole level.

Try prompts like these, one at a time
Give me a monthly digest of insights on our sales data for my executive stakeholders. Cover how we are doing on closed-won deals and the largest lost deals. Build it as an HTML digest.
Now create a skill I can call any time to run this same report. Only make it available in this project folder.
Roughly what lands at .claude/skills/monthly-sales-digest/SKILL.md
---
name: monthly-sales-digest
description: Builds the monthly sales digest for executive stakeholders as an HTML report, covering closed-won performance and the largest lost deals. Use when the user asks for the monthly digest, the sales summary, or the stakeholder report. SKIP for one-off ad-hoc questions that are not the recurring digest.
---

# Monthly sales digest

## The shape, every time
- Headline numbers first: closed-won revenue, deal count, win rate.
- Then the story for the month, two or three sentences, no filler.
- Then largest closed-won deals, then largest lost deals.
- State the source table and the date range at the bottom, so it can be audited.

## How to build it
- Run the query through the connection already recorded in CLAUDE.md.
- Render as a self-contained HTML file. Keep the house colours and fonts.
- Show the SQL before running it, and keep it with the output so the numbers
  can be traced back.

Try the first prompt against your own data and steer it until the digest is right, which will take a few rounds. Then the second, and that work stops being a one-off. Note what it asks you: whether the skill should be available everywhere or only here. Scope it to the project unless you want it firing on unrelated work. Look at what it wrote under .claude/skills, a SKILL.md next to the script it runs. Next month the whole thing is four words.

Team wall ahead

One more thing to plant here: sharing a skill, and the database access behind it, across a team is a whole other set of walls. Who owns the credential, whose conventions win when two people edit the same skill, how a fix reaches everyone. That is not on this page. It is the separate mini workshop on scaling across a team.

Take this with you

Copy it from the page or download the file. Each one says where it goes.

SKILL.md A working example: the weekly update skill, with notes on why the description is written the way it is.
Where it goes: Save it as .claude/skills/weekly-update/SKILL.md inside your project. Create those folders if they do not exist. Then just ask for a weekly update in plain language.
---
name: weekly-update
description: Writes the weekly status update from this week's notes, following the house format of wins, risks, and asks. Use when the user says "write the weekly update", "draft my status note", "what do I send the team this week", or asks for a summary of the week's progress. SKIP for a one-off summary of a single document, and for anything that gets sent without the user reading it first.
---

# Weekly update

## Before you start

Read `CLAUDE.md` for the vocabulary. If the notes folder is empty or covers a
different week than the user asked for, say so and stop. Do not invent progress.

## Steps

1. Gather every note file changed in the last seven days.
2. Sort what you find into three buckets, and only these three:
   - **Wins**: things that finished. Not things that progressed.
   - **Risks**: things that could stop a win from happening. Each one needs a
     named owner or it is not a risk, it is a worry.
   - **Asks**: decisions or approvals needed from someone else, each with the
     name of the person and the date it is needed by.
3. Anything that fits none of the three buckets gets left out. A weekly update is
   not a diary.
4. Write it in the format below. Six bullets maximum in total. If there are more
   than six, the extra ones were not important enough for this update.
5. Show it to the user. Never send anything.

## Format

```
Week of [date]

Wins
- [what finished, and why it mattered]

Risks
- [what could go wrong] (owner: [name])

Asks
- [what you need] from [name], by [date]
```

## Rules

- Plain language. If a sentence needs a glossary, rewrite the sentence.
- Every claim traces to a note. If you cannot point at the note, cut the line.
- No filler. "Continued work on X" is not a win and does not go in.
- If a week genuinely had no wins, say that. A short honest update is worth more
  than a padded one, and padding is what teaches people to stop reading these.

---

## How to adapt this

Three things make a skill fire at the right moment and stay useful:

1. **The description at the top is the whole selection mechanism.** Claude reads
   only the name and description when deciding whether to use this. It has not
   read a word of the body. Write the description in third person, say what the
   skill does AND when to use it, and include the actual phrases you would type.
2. **The SKIP line matters as much as the trigger.** It is how you stop three
   similar skills from all looking equally plausible.
3. **Keep the body short and the steps specific.** This is a procedure, not an
   essay. The more exact the sequence, the more consistent the result.
Download SKILL.md
Level 4 of 5

Hooks

The first thing on this ladder that does not ask the model to cooperate.

This one you cannot do in the app

This is the rung where Claude Code stops being a nicer version of what you already have. Nothing in the chat apps can refuse an action before it happens, because nothing in them is running on your machine at the moment the action is taken.

A hook is a small script that fires automatically at a set moment, before a file changes, after an edit, or before a session is allowed to finish, and it can refuse. The framing the video lands is the one to keep: a rule written into CLAUDE.md is usually followed, and usually is not the same thing as always. Hooks are where you stop asking the model to behave and start enforcing it, which is what makes shipping faster safe rather than reckless.

It runs whether or not the model agrees, and it can say no. Anthropic’s documentation draws the same line: CLAUDE.md is context, not enforced configuration, and blocking an action regardless of what Claude decides is exactly what hooks are for.

The rule as a sentence

"Never touch the .env file" is written in CLAUDE.md. It gets respected almost every time, which is the problem: almost every time is indistinguishable from every time until the day it is not, and nothing announces the exception.

The rule as a hook

The edit is stopped before it happens, every time, and the reason travels back so the model can do the right thing instead: tell you what needs changing and let you change it yourself.

Note what the refusal actually says. It is written as an instruction, not as an error, because the model reads it. A good hook is not just a wall, it is a wall that explains itself.

The same hook, nine different file paths, tested
.env                               -> deny
/repo/.env                         -> deny
./.env                             -> deny
config/.env.production             -> deny
/Users/x/app/secrets.yml           -> deny
src/credentials.json               -> deny
notes/todo.md                      -> allow
README.md                          -> allow
src/app.py                         -> allow

That list is the actual test run, not an illustration. It matters that all three shapes of the same path are checked (bare, absolute, and ./-prefixed), because the most common way a guard like this fails is that it looks installed, passes a quick test, and quietly never fires on the path shape you actually use.

Where enforcement leaks, reported by practitioners. Blocking a tool by name does not remove the underlying ability. Practitioners report that when writing files is blocked but running commands is allowed, the model reaches the same result another way, and that Anthropic closed this as not planned. They report the same gap for a few other contexts where a refusal does not carry through. Treat that as reported experience rather than confirmed behaviour, and take the practical lesson: a hook guarantees that a check runs. For anything that absolutely must hold, put the check at the point where work gets saved for good, because every route has to pass through there.

What it costs you An hour for the first one, because the concept is new. Ten minutes for the next.
You have outgrown it when You trust what comes out now, and the thing holding everything up is you.
Try it yourself After watching, run this click path in a clean folder to feel the wall.

Two hooks worth having on day one. Both patterns are in the starter kit at the top of this page.

  1. Do: Add a style hook that blocks a character you never want. The classic is the em-dash. Then ask for text that would normally contain one. See: It gets caught and rewritten every time, without you asking. This is enforcement, not a polite request.
  2. Do: Add an "ask first" gate: anything that writes to the production database or deploys to production stops and asks you. Then try a command that looks like a prod write. See: It pauses for your yes instead of just running. The seatbelt is on.
  3. Do: Point the secrets guard from the kit at your real database credentials file. See: Claude can still read it to run the query skill, but any attempt to edit or move it is denied with a reason.

The way around it: The fix is the hook, because it does not depend on the model cooperating. Just remember the edges leak, so the checks that truly must hold belong at the commit or deploy step, where every path is forced through one gate.

Try it in your environment The prompts from the video, which ran against our demo warehouse. Reword them for your own data: the shape of the question is the part to copy.

The classic first hook, and the one in the video: banning a character you never want. Ask for it in plain language and let Claude write the hook.

Try prompts like these, one at a time
Add a hook that strips em dashes from anything you write, anywhere, in any output. I never want one to reach a file.
Now write me two paragraphs of marketing copy about our Q4 results.
Roughly what it writes, as .claude/hooks/no-em-dash.sh (then chmod +x it and wire it in settings.json)
#!/bin/bash
# PostToolUse hook. Fires after a file is written and fails if an em dash or en
# dash survived, so the rule holds whether or not the model was paying attention.
#
# Test it, expecting exit 2:
#   printf 'a \xe2\x80\x94 b' > /tmp/t.md
#   echo '{"tool_input":{"file_path":"/tmp/t.md"}}' | ./no-em-dash.sh; echo "exit $?"
set -uo pipefail

file=$(jq -r '.tool_input.file_path // empty')
if [ -z "$file" ] || [ ! -f "$file" ]; then
  exit 0
fi

# Matched as raw UTF-8 bytes rather than a regex class, because BSD grep on
# macOS has no -P and would silently never match.
em=$(printf '\xe2\x80\x94')
en=$(printf '\xe2\x80\x93')

if grep -q -e "$em" -e "$en" "$file"; then
  # Exit 2 sends this text back to the model as an instruction rather than an
  # error, which is what lets it fix its own output without you saying anything.
  echo "Em or en dash found in $file. Rewrite those lines using commas, periods, colons or parentheses." >&2
  exit 2
fi
exit 0

You do not have to write this by hand. Ask for it the way the first prompt does and Claude builds the hook, drops it in .claude/hooks, and wires it up. Then try the second prompt: marketing copy is exactly the kind of writing where a model reaches for an em dash. It gets caught and rewritten every time, without you asking. That is the difference between a request and enforcement. The same pattern is what stops a write to production or an edit to your secrets file, and both of those are in the kit below.

Take this with you

Copy it from the page or download the file. Each one says where it goes.

no-select-star.sh The hook from the demo. Refuses to write a .sql file that uses SELECT *, so the skill's "list columns" rule holds even when the model slips.
Where it goes: Save it as .claude/hooks/no-select-star.sh, then chmod +x it. It has a one-line test in its header you can paste to prove it works. Only .sql writes are inspected; everything else passes.
#!/usr/bin/env bash
# PreToolUse hook: refuse to write a SQL file that uses SELECT *.
#
# WHY THIS EXISTS
# A skill can say "never SELECT *" and the model still slips. A skill is a
# request. This hook is enforcement: it reads what is about to be written and
# says no if the query uses SELECT *, so the rule holds whether or not the model
# remembered it.
#
# INSTALL
#   1. Save as .claude/hooks/no-select-star.sh, then: chmod +x .claude/hooks/no-select-star.sh
#   2. Add it to .claude/settings.json under hooks.PreToolUse with matcher "Write|Edit".
#
# TEST WITHOUT CLAUDE
#   echo '{"tool_input":{"file_path":"qry_signups.sql","content":"select * from t"}}' | .claude/hooks/no-select-star.sh
#   -> a JSON line with "permissionDecision":"deny"

set -uo pipefail

if ! command -v python3 >/dev/null 2>&1; then
  printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"no-select-star: python3 not found, so the check could not run. Failing closed on purpose."}}\n'
  exit 0
fi

cat | python3 -c '
import json, re, sys

try:
    event = json.load(sys.stdin)
except Exception:
    print(json.dumps({"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}}))
    sys.exit(0)

ti = event.get("tool_input", {}) or {}
path = ti.get("file_path", "") or ""

# Only inspect SQL files. Everything else passes.
if not path.endswith(".sql"):
    print(json.dumps({"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}}))
    sys.exit(0)

# Gather the text this write would put on disk, across Write, Edit, and MultiEdit.
chunks = [ti.get("content", ""), ti.get("new_string", "")]
for e in ti.get("edits", []) or []:
    chunks.append(e.get("new_string", ""))
text = "\n".join(c for c in chunks if c)

# SELECT * (optionally SELECT DISTINCT * or SELECT table.*), case-insensitive,
# any whitespace. count(*) does not match: the * must follow SELECT directly.
if re.search(r"select\s+(distinct\s+)?(\w+\s*\.\s*)?\*", text, re.IGNORECASE):
    reason = ("no-select-star: this query uses SELECT *, which our conventions forbid. "
              "List the columns explicitly, then write it again.")
    print(json.dumps({"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": reason}}))
else:
    print(json.dumps({"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}}))
'
Download no-select-star.sh
protect-secrets.sh Refuses edits to .env, key, and credentials files, including the key your connection profile points at. Tested against all nine paths shown.
Where it goes: Save it as .claude/hooks/protect-secrets.sh, then run chmod +x .claude/hooks/protect-secrets.sh once to make it runnable. The file itself has a one-line test you can paste into a terminal to prove it works before you trust it.
#!/usr/bin/env bash
# PreToolUse hook: refuse to let Claude Code write to a secrets file.
#
# WHY THIS EXISTS
# "Never touch my .env file" written in CLAUDE.md is a request. The model reads
# it, usually respects it, and one day does not. This script is enforcement: it
# runs on every Write and Edit, before the file is touched, whatever the model
# intended.
#
# INSTALL (two steps, no coding required)
#   1. Save this file as .claude/hooks/protect-secrets.sh in your project, then
#      make it runnable:  chmod +x .claude/hooks/protect-secrets.sh
#   2. Copy the block in settings-snippet.json into .claude/settings.json.
#
# TEST IT WITHOUT CLAUDE (paste this whole line into your terminal)
#   echo '{"tool_name":"Write","tool_input":{"file_path":".env"}}' | .claude/hooks/protect-secrets.sh
#   You should see a JSON line containing "permissionDecision":"deny".
#
# HOW IT DECIDES
# Claude Code hands this script a JSON description of what it is about to do, on
# standard input. The script prints a JSON decision back. "deny" stops the edit
# and sends the reason to the model, which is why the reason is written as an
# instruction rather than an error.

set -uo pipefail

# Add or remove patterns here. One per line, shell glob syntax.
PROTECTED=(
  "*.env"
  ".env"
  ".env.*"
  "*.pem"
  "*.key"
  "*credentials*"
  "*secrets*"
)

# The hook needs python3 only to read one field out of the incoming JSON. If it
# is missing we FAIL CLOSED: a guard that cannot check must not wave things
# through, because a broken guard that returns "allow" is worse than no guard
# at all. You would never know it stopped working.
if ! command -v python3 >/dev/null 2>&1; then
  printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"protect-secrets: python3 not found, so the secrets check could not run. Failing closed on purpose. Install python3 or remove this hook deliberately."}}\n'
  exit 0
fi

EVENT=$(cat)
FILE_PATH=$(printf '%s' "$EVENT" | python3 -c '
import json, sys
try:
    event = json.load(sys.stdin)
except Exception:
    print("")
    sys.exit(0)
print(event.get("tool_input", {}).get("file_path", "") or "")
')

# No file path means this event is not a file write we care about. Allow.
if [ -z "$FILE_PATH" ]; then
  printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\n'
  exit 0
fi

BASENAME=$(basename "$FILE_PATH")

# The matched name gets interpolated into the JSON decision below. Escape it
# first, so a path containing a quote or backslash cannot break the JSON and
# turn a deny into a hook error.
json_escape() { printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'; }
SAFE_BASENAME=$(json_escape "$BASENAME")
SAFE_FILE_PATH=$(json_escape "$FILE_PATH")

for PATTERN in "${PROTECTED[@]}"; do
  # Match the bare filename AND the full path, because Claude may pass either an
  # absolute path, a repo-relative path, or a ./-prefixed path. Checking only one
  # shape is the most common reason a guard like this looks installed and never
  # actually fires.
  # shellcheck disable=SC2254
  case "$BASENAME" in
    $PATTERN)
      printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"protect-secrets: %s is a protected file and must be edited by a human, not by Claude. If this change is genuinely needed, tell the user exactly what to change and let them make the edit themselves."}}\n' "$SAFE_BASENAME"
      exit 0
      ;;
  esac
  # shellcheck disable=SC2254
  case "$FILE_PATH" in
    $PATTERN|*/$PATTERN)
      printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"protect-secrets: %s is a protected file and must be edited by a human, not by Claude. If this change is genuinely needed, tell the user exactly what to change and let them make the edit themselves."}}\n' "$SAFE_FILE_PATH"
      exit 0
      ;;
  esac
done

printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\n'
exit 0
Download protect-secrets.sh
settings-snippet.json Wires both hooks to Claude Code. Without this, the scripts above are just files sitting there.
Where it goes: Paste the hooks block into .claude/settings.json in your project.
{
  "_comment": "Paste the hooks block below into .claude/settings.json in your project. If that file does not exist yet, this whole file works as a starting one: delete this _comment line first, since real JSON has no comments. Both hooks run on every Write and Edit.",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/protect-secrets.sh"
          },
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/no-select-star.sh"
          }
        ]
      }
    ]
  }
}
Download settings-snippet.json
Level 5 of 5

Running sessions in parallel

Several context windows open at once, each holding a different question.

You can open several chats already, but not like this

Having five conversations open in the Claude app is not the same thing. These sessions are each doing work in your actual files, and you watch them side by side, so the question stops being how fast the model is and starts being how many things you can hold in your head at once.

Once your context file, your skills and your hooks are in place, you start trusting the output enough to stop babysitting it, and the bottleneck moves to you feeding it one question at a time. The video fires off one question, opens a second session, splits the view, and keeps going, so several windows are working at once instead of queuing. The honest catch it names: the model is no longer the rate limiter, your own short-term memory is.

The prerequisites are the point. This only works after the lower walls are built: a context file doing its job, skills for the things you repeat, and hooks you trust. Without those you are not running five sessions, you are reviewing five sessions.

One window

A question goes in and you wait, watching it work. The next stakeholder request sits behind it doing nothing. You are as fast as the slowest single answer, and most of that time you are just reading.

Several windows

You fire the first question, open a new session, and ask the second. Split the view and both run at once. Two stakeholders get answers in the time one used to take, because the waiting now happens in parallel instead of in sequence.

The honest catch, and the video is blunt about it: a human still does one thing at a time. Past a few windows the limit is not the tool, it is your own short-term memory, how many open threads you can actually keep straight. That is why an external monitor helps more than a faster machine, and why this wall has no obvious next rung.

Why this one comes last, and not by accident. This level multiplies whatever your setup already does, in both directions. Running five windows on top of solid skills and hooks gets you five times the work. Running five windows with nothing checking the output gets you five times the cleanup, and you find out at the end. That is the real argument for building the lower walls first: not tidiness, but that each one is what makes this one survivable. And a note on vocabulary, some people call these agents. That is a generous word for what is really several chat windows doing your work at the same time.

What it costs you No setup at all. What it costs is attention, and a second monitor helps more than you would think.
You have outgrown it when You have lost track of which window is doing what, and you are the bottleneck.
Try it yourself After watching, run this click path in a clean folder to feel the wall.

This one needs nothing installed. It is a working habit, and you can try it in the next ten minutes.

  1. Do: Ask a question that takes a while, something that has to go and look at real data rather than answer from memory. See: It starts working, and you sit there reading. That waiting is the thing you are about to stop doing.
  2. Do: Without waiting for it to finish, open a new session and ask something unrelated, ideally for a different stakeholder. Then split the view so you can see both. See: Both run at once. The second answer no longer costs you the first answer's waiting time.
  3. Do: Keep splitting until you notice you have lost the thread of one of them. See: That number is your actual limit, and it is a fact about you rather than about the tool. Most people find it is smaller than they expected.

The way around it: There is no next wall on this page, because the next one is not yours alone. The moment you want this work reviewed, shipped, and shared with other people, a different set of problems starts, and those are a separate workshop.

Try it in your environment The prompts from the video, which ran against our demo warehouse. Reword them for your own data: the shape of the question is the part to copy.

Two unrelated questions, run side by side. Any two will do, the point is that neither waits for the other.

Try prompts like these, one at a time
How many opportunities are set to close in 2025 and 2026? Break it out by year.
Separately: which accounts have had no activity in the last 90 days? Start a new session for this one.

Ask the first, and while it is still working, open a new session and ask the second. Split the view and watch both run. That is the whole technique, there is nothing to install. The thing to pay attention to is not the speed, it is the point where you stop being able to follow both, because that is the real ceiling.

Take this with you

Copy it from the page or download the file. Each one says where it goes.

HANDOFF.md For when one of those parallel threads outlives its session. Written for a stranger, because that stranger is Claude in twenty minutes.
Where it goes: Save it in your project as HANDOFF.md and keep it current during long work. After any reset, say: "Read HANDOFF.md and continue from the next step."
# HANDOFF.md starter

Save this in your project and keep it current during any long piece of work.

**Why this file exists.** A long Claude Code session eventually runs out of room
and compacts itself: it summarises the conversation so far and carries on from
the summary. That happens on a size threshold, not at a sensible stopping point,
so it can land in the middle of something. What practitioners report losing is
the specific stuff: error details, exact file names, the middle steps of a long
piece of debugging, and the reasoning behind decisions already made.

This file is the fix, and it is deliberately low-tech. Anything written here is
on disk, so it survives. Anything living only in the conversation does not.

Write it for a stranger. In practice that stranger is Claude in twenty minutes,
with no memory of the last two hours.

---

## Goal

[What we are trying to achieve, in one or two sentences. Not the task list, the
outcome.]

## Where things stand

[What is genuinely finished. Include one hard fact per item that proves it is
finished, for example a count, a filename, or a check that passed. "Mostly done"
is not a status.]

## What is in flight right now

[The thing being worked on this moment, and how far in.]

## Decisions already made, and why

- **[Decision]**: [why, and what the alternative was]

The "why" is the part that gets lost. Without it, the next session relitigates a
question you already settled.

## Open questions

- **[Question]**: [what would resolve it, and who decides]

## Gotchas already hit, do not rediscover

- [What went wrong, what it looked like, and what fixed it.]

This section is worth more than the rest of the file combined. Every entry is
time somebody already spent.

## Next steps, in order

1. [Next concrete action]
2. [The one after that]

---

## How to use it

- Update it before any long run, and after anything surprising.
- After a reset, a new session, or when answers start feeling vague, say:
  **"Read HANDOFF.md and continue from the next step."**
- If you find yourself re-explaining something you already explained today, that
  belongs in here.
Download HANDOFF.md

Which level are you on?

Read down until one of these describes your week. That is your level, and the move beside it is the only thing worth building next.

Level 1

Only ever used the chat apps, and not sure this is worth the switch?

Open a folder, ask for something real, and let it work. That is all of level one, and a lot of good work correctly stays here.

Level 2

You are re-explaining your setup at the start of every session?

Write a CLAUDE.md, without opening an editor. Tell Claude the rule in plain language and ask it to add that to the file.

Level 3

The file is over a page, and rules you definitely wrote down are getting broken anyway?

Move whole procedures out of CLAUDE.md and into skills, so the file that loads every time stays short enough to actually get read.

Level 4

You have caught the same kind of mistake in the output three weeks running?

Stop catching it by hand. Turn that check into a hook, which fires whether or not the model feels like cooperating.

Level 5

You trust what comes out now, and the thing holding everything up is you?

Stop feeding it one question at a time. Fire one off, open a second session, and split the view.

Past these five

You have lost track of which window is doing what, and you are the bottleneck?

You have run out of walls that are yours alone. Everything after this one starts the moment a second person shares your setup, and that is a separate workshop.

The ladder is not a maturity contest. It is a diagnostic: find the thing that keeps breaking, and build exactly one level of infrastructure above it.

One thing to be clear about: this is not the pattern everybody follows, and it is not a ranking. These are simply the walls I have run into myself, and the ones I keep hearing other people describe. Your order may differ, and some of these you may never hit at all.

The reason for writing them down is to take some of that pain off the table. Every one of these cost me time to work out from scratch, and none of them had to. If knowing the shape of a wall in advance gets you past it faster, this page has done its job.

Worth saying plainly: none of this scales past a single environment. Everything here is one person, on their own machine, getting their own setup to hold. The moment a team shares that setup, it is a different problem with a different set of answers, and that is what the next workshop covers.

Where these five stop

Every wall on this page is one person hitting the limits of their own setup, which is why they are the first five. That covers the whole of the adoption journey most people actually hit: the pitfalls, the ceilings, and the fixes, from the first session to a setup that holds.

The moment a second person shares that setup, the walls change shape rather than just getting taller. Whose conventions win when two people disagree. How a working environment gets distributed to people who did not build it, and updated afterwards without breaking their work. What to standardise across a whole organisation versus what to leave to each team. How to tell whether any of it is actually being used. And how to keep the whole thing from rotting as it grows, which is the failure mode nobody plans for.

None of that is on this page, and none of it is a harder version of what is. It is a separate workshop, currently in development. If you are already there and want to compare notes, the address below reaches us directly.

Looking to accelerate your team's Claude capability?

Everything on this page is one person getting their own setup to hold. Taking that across a team, so conventions are shared, environments are reproducible, and the whole thing does not rot as it grows, is a different problem. It is also one of the things Spicy Data does. If that is where you are headed, get in touch.