[{"data":1,"prerenderedAt":3362},["ShallowReactive",2],{"docs:\u002Fworkshops":3},{"id":4,"title":5,"accent":6,"body":7,"description":3328,"estReadTime":3329,"extension":3330,"eyebrow":3331,"icon":3332,"intro":3333,"lastUpdated":3334,"meta":3335,"navigation":390,"next":3336,"path":3339,"prev":3340,"review":3333,"seo":3343,"stem":6,"tocItems":3356,"__hash__":3361},"docs\u002Fworkshops.md","Workshops","workshops",{"type":8,"value":9,"toc":3316},"minimark",[10,19,152,279,651,807,1175,1453,1630,2098,2604,2695,2754,2828,2881,3034,3156,3312],[11,12,13,14,18],"p",{},"Reading about Claude Code gets you nowhere on its own. The people who actually get fast at it are the ones who sit down, open a terminal, and ",[15,16,17],"em",{},"do the thing"," — with a clear goal, a deadline, and something to show at the end. This page is that. Seven build-alongs, five challenges, a few suggested tracks. Every workshop has a start state, a target artifact, and a stop condition. Pick one, give yourself the stated time, and ship.",[20,21,24,27,68,71,74,149],"docs-section",{"id":22,"title":23},"how-to-use","How to use this page",[11,25,26],{},"Every workshop follows the same shape so you can jump in without reading the whole chapter first.",[28,29,30,38,44,50,56,62],"ul",{},[31,32,33,37],"li",{},[34,35,36],"strong",{},"Time"," — a budget, not a target. If you're done in half the time, the goal was too small.",[31,39,40,43],{},[34,41,42],{},"You'll need"," — the setup required before you start. Don't skip this; it's the difference between a workshop and a debugging session.",[31,45,46,49],{},[34,47,48],{},"The goal"," — one sentence describing the artifact you should have at the end.",[31,51,52,55],{},[34,53,54],{},"Steps"," — the happy path. Paste, prompt, observe. Deviate when you have a reason.",[31,57,58,61],{},[34,59,60],{},"Stop when"," — the definition of done. Close Claude, commit, move on.",[31,63,64,67],{},[34,65,66],{},"Stretch"," — one or two optional extensions if you want to push further.",[11,69,70],{},"The build-alongs teach one concept each. They're safe, scripted, and designed so nothing in your repo breaks if you follow them literally. Do these first.",[11,72,73],{},"The challenges give you a constraint and a target — no scripted steps. They're harder on purpose. Do them after the build-alongs, or when you want to prove a concept has stuck.",[75,76,79,82,146],"docs-callout",{"title":77,"variant":78},"Work on a real repo, but protect it","tip",[11,80,81],{},"Run workshops inside a scratch worktree or a branch you can throw away:",[83,84,89],"pre",{"className":85,"code":86,"language":87,"meta":88,"style":88},"language-bash shiki shiki-themes github-light","git worktree add ..\u002Fworkshops -b workshops\u002F$(date +%Y-%m-%d)\ncd ..\u002Fworkshops\nclaude\n","bash","",[90,91,92,131,140],"code",{"__ignoreMap":88},[93,94,97,101,105,108,111,115,118,122,125,128],"span",{"class":95,"line":96},"line",1,[93,98,100],{"class":99},"s7eDp","git",[93,102,104],{"class":103},"sYBdl"," worktree",[93,106,107],{"class":103}," add",[93,109,110],{"class":103}," ..\u002Fworkshops",[93,112,114],{"class":113},"sYu0t"," -b",[93,116,117],{"class":103}," workshops\u002F",[93,119,121],{"class":120},"sgsFI","$(",[93,123,124],{"class":99},"date",[93,126,127],{"class":103}," +%Y-%m-%d",[93,129,130],{"class":120},")\n",[93,132,134,137],{"class":95,"line":133},2,[93,135,136],{"class":113},"cd",[93,138,139],{"class":103}," ..\u002Fworkshops\n",[93,141,143],{"class":95,"line":142},3,[93,144,145],{"class":99},"claude\n",[11,147,148],{},"That way every exercise lives in isolation. Finish, review the diff, cherry-pick what's worth keeping, delete the worktree.",[11,150,151],{},"Pair where you can. Two engineers running the same build-along and comparing outputs is worth roughly four engineers reading the docs solo.",[20,153,156,159],{"id":154,"title":155},"build-alongs","Build-alongs",[11,157,158],{},"Seven guided practicals, one for each skill that separates a hobbyist from someone who ships with Claude Code every day. Do them in order if you're new; cherry-pick if you've already got the basics.",[160,161,162,180],"table",{},[163,164,165],"thead",{},[166,167,168,172,175,178],"tr",{},[169,170,171],"th",{},"#",[169,173,174],{},"Build",[169,176,177],{},"You'll practice",[169,179,36],{},[181,182,183,198,211,225,239,252,266],"tbody",{},[166,184,185,189,192,195],{},[186,187,188],"td",{},"1",[186,190,191],{},"CLAUDE.md from scratch",[186,193,194],{},"Context architecture",[186,196,197],{},"45 min",[166,199,200,203,206,209],{},[186,201,202],{},"2",[186,204,205],{},"Your first Plan Mode feature",[186,207,208],{},"Plan → execute discipline",[186,210,197],{},[166,212,213,216,219,222],{},[186,214,215],{},"3",[186,217,218],{},"Your first hook",[186,220,221],{},"Deterministic guardrails",[186,223,224],{},"40 min",[166,226,227,230,233,236],{},[186,228,229],{},"4",[186,231,232],{},"A custom slash command",[186,234,235],{},"Prompt reuse",[186,237,238],{},"30 min",[166,240,241,244,247,250],{},[186,242,243],{},"5",[186,245,246],{},"Wire up an MCP server",[186,248,249],{},"External context",[186,251,197],{},[166,253,254,257,260,263],{},[186,255,256],{},"6",[186,258,259],{},"A 3-agent team",[186,261,262],{},"Orchestration mechanics",[186,264,265],{},"60 min",[166,267,268,271,274,277],{},[186,269,270],{},"7",[186,272,273],{},"An eval suite",[186,275,276],{},"Regression safety",[186,278,265],{},[20,280,283,301,306,331,340,344,350,359,365,373,598,607,614,619,627,632],{"id":281,"title":282},"ba-claude-md","Build 1 — CLAUDE.md from scratch",[11,284,285,288,289,292,293,296,297,300],{},[34,286,287],{},"Time:"," 45 minutes · ",[34,290,291],{},"Level:"," Beginner · ",[34,294,295],{},"Artifact:"," a tested ",[90,298,299],{},"CLAUDE.md"," committed to your repo.",[11,302,303],{},[34,304,305],{},"You'll need:",[28,307,308,315,321],{},[31,309,310,311,314],{},"A repo you know well (or a fresh worktree off ",[90,312,313],{},"main",").",[31,316,317,318,314],{},"Claude Code installed and authenticated (",[90,319,320],{},"claude --version",[31,322,323,324,326,327,330],{},"No existing ",[90,325,299],{}," in the repo root. If one exists, rename it to ",[90,328,329],{},"CLAUDE.md.bak"," for this exercise.",[11,332,333,336,337,339],{},[34,334,335],{},"The goal."," Write a ",[90,338,299],{}," that a teammate (or a cold Claude session) could use to onboard in ten minutes. You'll validate it with Claude itself.",[341,342,54],"h3",{"id":343},"steps",[345,346,347],"ol",{},[31,348,349],{},"Open Claude in the repo root. Start with the cold test — no context yet:",[83,351,357],{"className":352,"code":354,"filename":355,"language":356,"meta":88},[353],"language-text","Do not look at any config files yet. Read only the top-level directory\nand pick the three files you think are most central to what this project does.\n\nThen answer:\n1. What does this project do, in one sentence?\n2. What stack is it built on?\n3. What command runs the tests?\n4. What's one rule about this codebase you can't guess from the files?\n\nMark each answer \"certain \u002F guessing \u002F unknown\".\n","prompt — cold read","text",[90,358,354],{"__ignoreMap":88},[11,360,361,362,364],{},"Save that output. Anything marked \"guessing\" or \"unknown\" is what ",[90,363,299],{}," exists to cover.",[345,366,367],{"start":133},[31,368,369,370,372],{},"Draft ",[90,371,299],{}," from that list. Keep it under 100 lines. Use this skeleton:",[83,374,378],{"className":375,"code":376,"filename":299,"language":377,"meta":88,"style":88},"language-markdown shiki shiki-themes github-light","# [Project name]\n\n## What this is\n[One sentence. Who uses it, what it does.]\n\n## Stack\n- Language: [e.g. TypeScript 5.x]\n- Framework: [e.g. Nuxt 4]\n- Database: [e.g. Postgres 16 via Prisma]\n- Package manager: [npm \u002F pnpm \u002F bun]\n\n## Commands\n- `npm run dev` — local server at :3000\n- `npm test` — vitest, watch mode off\n- `npm run lint` — eslint + typecheck\n- `npm run build` — production build\n\n## Repo layout\n- `app\u002F` — source. See sub-READMEs for component rules.\n- `content\u002F` — markdown pages consumed by the app.\n- `scripts\u002F` — one-off utilities, not part of the runtime.\n\n## Hard rules\n- [e.g. \"All errors throw — never return. See docs\u002Ferrors.md\"]\n- [e.g. \"Never import from internal\u002F; use the public index.\"]\n\n## Before touching [sensitive area]\nRead [docs\u002Fx.md] first.\n","markdown",[90,379,380,386,392,397,403,408,414,424,432,440,448,453,459,470,481,492,503,508,514,525,536,547,552,558,566,574,579,585],{"__ignoreMap":88},[93,381,382],{"class":95,"line":96},[93,383,385],{"class":384},"surfw","# [Project name]\n",[93,387,388],{"class":95,"line":133},[93,389,391],{"emptyLinePlaceholder":390},true,"\n",[93,393,394],{"class":95,"line":142},[93,395,396],{"class":384},"## What this is\n",[93,398,400],{"class":95,"line":399},4,[93,401,402],{"class":120},"[One sentence. Who uses it, what it does.]\n",[93,404,406],{"class":95,"line":405},5,[93,407,391],{"emptyLinePlaceholder":390},[93,409,411],{"class":95,"line":410},6,[93,412,413],{"class":384},"## Stack\n",[93,415,417,421],{"class":95,"line":416},7,[93,418,420],{"class":419},"sqxcx","-",[93,422,423],{"class":120}," Language: [e.g. TypeScript 5.x]\n",[93,425,427,429],{"class":95,"line":426},8,[93,428,420],{"class":419},[93,430,431],{"class":120}," Framework: [e.g. Nuxt 4]\n",[93,433,435,437],{"class":95,"line":434},9,[93,436,420],{"class":419},[93,438,439],{"class":120}," Database: [e.g. Postgres 16 via Prisma]\n",[93,441,443,445],{"class":95,"line":442},10,[93,444,420],{"class":419},[93,446,447],{"class":120}," Package manager: [npm \u002F pnpm \u002F bun]\n",[93,449,451],{"class":95,"line":450},11,[93,452,391],{"emptyLinePlaceholder":390},[93,454,456],{"class":95,"line":455},12,[93,457,458],{"class":384},"## Commands\n",[93,460,462,464,467],{"class":95,"line":461},13,[93,463,420],{"class":419},[93,465,466],{"class":113}," `npm run dev`",[93,468,469],{"class":120}," — local server at :3000\n",[93,471,473,475,478],{"class":95,"line":472},14,[93,474,420],{"class":419},[93,476,477],{"class":113}," `npm test`",[93,479,480],{"class":120}," — vitest, watch mode off\n",[93,482,484,486,489],{"class":95,"line":483},15,[93,485,420],{"class":419},[93,487,488],{"class":113}," `npm run lint`",[93,490,491],{"class":120}," — eslint + typecheck\n",[93,493,495,497,500],{"class":95,"line":494},16,[93,496,420],{"class":419},[93,498,499],{"class":113}," `npm run build`",[93,501,502],{"class":120}," — production build\n",[93,504,506],{"class":95,"line":505},17,[93,507,391],{"emptyLinePlaceholder":390},[93,509,511],{"class":95,"line":510},18,[93,512,513],{"class":384},"## Repo layout\n",[93,515,517,519,522],{"class":95,"line":516},19,[93,518,420],{"class":419},[93,520,521],{"class":113}," `app\u002F`",[93,523,524],{"class":120}," — source. See sub-READMEs for component rules.\n",[93,526,528,530,533],{"class":95,"line":527},20,[93,529,420],{"class":419},[93,531,532],{"class":113}," `content\u002F`",[93,534,535],{"class":120}," — markdown pages consumed by the app.\n",[93,537,539,541,544],{"class":95,"line":538},21,[93,540,420],{"class":419},[93,542,543],{"class":113}," `scripts\u002F`",[93,545,546],{"class":120}," — one-off utilities, not part of the runtime.\n",[93,548,550],{"class":95,"line":549},22,[93,551,391],{"emptyLinePlaceholder":390},[93,553,555],{"class":95,"line":554},23,[93,556,557],{"class":384},"## Hard rules\n",[93,559,561,563],{"class":95,"line":560},24,[93,562,420],{"class":419},[93,564,565],{"class":120}," [e.g. \"All errors throw — never return. See docs\u002Ferrors.md\"]\n",[93,567,569,571],{"class":95,"line":568},25,[93,570,420],{"class":419},[93,572,573],{"class":120}," [e.g. \"Never import from internal\u002F; use the public index.\"]\n",[93,575,577],{"class":95,"line":576},26,[93,578,391],{"emptyLinePlaceholder":390},[93,580,582],{"class":95,"line":581},27,[93,583,584],{"class":384},"## Before touching [sensitive area]\n",[93,586,588,591,595],{"class":95,"line":587},28,[93,589,590],{"class":120},"Read [",[93,592,594],{"class":593},"sEuWB","docs\u002Fx.md",[93,596,597],{"class":120},"] first.\n",[345,599,600],{"start":142},[31,601,602,603,606],{},"Validate with a cold session. Run ",[90,604,605],{},"\u002Fclear",", then:",[83,608,612],{"className":609,"code":610,"filename":611,"language":356,"meta":88},[353],"Read CLAUDE.md. Then read the actual top-level directory.\n\nTell me:\n1. Anything CLAUDE.md claims that the repo doesn't reflect.\n2. Anything you still have to guess at.\n3. One rule that belongs in CLAUDE.md that isn't there yet.\n\nDo not edit anything.\n","prompt — validation",[90,613,610],{"__ignoreMap":88},[345,615,616],{"start":399},[31,617,618],{},"Fix what Claude caught. Commit.",[11,620,621,623,624,626],{},[34,622,60],{}," you can hand ",[90,625,299],{}," to a teammate and say \"read this and the code will make sense\" — and they can, within 10 minutes, answer the four questions from step 1 correctly.",[11,628,629],{},[34,630,631],{},"Stretch.",[28,633,634,641],{},[31,635,636,637,640],{},"Add a \"Before touching ",[93,638,639],{},"sensitive area","\" pointer for your most dangerous subsystem.",[31,642,643,644,647,648,650],{},"Run ",[90,645,646],{},"\u002Fcontext"," and verify ",[90,649,299],{}," is under 3,000 tokens. If it isn't, cut it.",[20,652,655,668,672,683,692,695,711,718,741,748,753,760,765,772,780,789,793],{"id":653,"title":654},"ba-plan-mode","Build 2 — Your first Plan Mode feature",[11,656,657,288,659,292,661,663,664,667],{},[34,658,287],{},[34,660,291],{},[34,662,295],{}," one feature shipped start-to-finish through Plan Mode, with the plan committed as a ",[90,665,666],{},".claude\u002Fplan.md"," artifact.",[11,669,670],{},[34,671,305],{},[28,673,674,677],{},[31,675,676],{},"A small, real feature request (rename a field, add a log, expose a new flag — something you could do yourself in 20 minutes).",[31,678,679,680,682],{},"A ",[90,681,299],{}," in the repo root (use Build 1 if you haven't got one).",[11,684,685,687,688,691],{},[34,686,335],{}," Experience the full plan → review → execute → verify loop ",[15,689,690],{},"deliberately",", with the plan as a reviewable artifact. Most people skip to execute. You won't.",[341,693,54],{"id":694},"steps-1",[345,696,697,708],{},[31,698,699,700,703,704,707],{},"Open Claude at the repo root. Activate Plan Mode: press ",[34,701,702],{},"Shift+Tab"," twice. The StatusLine indicator will flip to ",[90,705,706],{},"plan mode",".",[31,709,710],{},"State the task. Be specific about scope:",[83,712,716],{"className":713,"code":714,"filename":715,"language":356,"meta":88},[353],"Feature: [one sentence — exactly what changes].\n\nProduce a plan:\n1. Files you'll touch (path + why)\n2. Functions you'll add, change, or delete\n3. Tests to add or update\n4. Any ambiguity that needs my decision before you start\n5. Rollback strategy if this goes wrong\n\nDo not write any code. When done, save the plan to .claude\u002Fplan.md\nas a markdown document I can diff later.\n","prompt — plan phase",[90,717,714],{"__ignoreMap":88},[345,719,720,738],{"start":142},[31,721,722,723,726,727],{},"Read the plan. Not skim — ",[15,724,725],{},"read",". Look for:",[28,728,729,732,735],{},[31,730,731],{},"Files you didn't expect to see touched.",[31,733,734],{},"Missing tests.",[31,736,737],{},"Any step that uses the word \"probably\" or \"should\".",[31,739,740],{},"Send it back for revision if anything is off:",[83,742,746],{"className":743,"code":744,"filename":745,"language":356,"meta":88},[353],"Revisions:\n- [specific thing to fix in the plan]\n- [another thing]\n\nUpdate .claude\u002Fplan.md and re-report only what changed.\n","prompt — plan revision",[90,747,744],{"__ignoreMap":88},[345,749,750],{"start":405},[31,751,752],{},"Exit Plan Mode (Shift+Tab once more). Kick off execution with the plan pinned:",[83,754,758],{"className":755,"code":756,"filename":757,"language":356,"meta":88},[353],"Execute the plan in .claude\u002Fplan.md exactly. One logical change at a time.\nAfter each step, run the lint\u002Ftypecheck command and show me the output\nbefore moving to the next step. If anything diverges from the plan,\nstop and ask.\n","prompt — execute phase",[90,759,756],{"__ignoreMap":88},[345,761,762],{"start":410},[31,763,764],{},"When execution is done, verify:",[83,766,770],{"className":767,"code":768,"filename":769,"language":356,"meta":88},[353],"Run the full test suite and lint. Report pass\u002Ffail counts and any\ndiagnostic that looks new since the feature started. Then run git diff\nand tell me: does the final diff match the plan? List any divergence.\n","prompt — verify phase",[90,771,768],{"__ignoreMap":88},[345,773,774],{"start":416},[31,775,776,777,779],{},"Commit. Include ",[90,778,666],{}," in the commit so the reviewer can read the plan alongside the diff.",[11,781,782,784,785,788],{},[34,783,60],{}," the feature is merged ",[15,786,787],{},"and"," you can show the plan file next to the diff.",[11,790,791],{},[34,792,631],{},[28,794,795,801],{},[31,796,797,798,707],{},"Redo the same feature without Plan Mode on a different worktree. Compare: lines of diff, number of prompt iterations, total ",[90,799,800],{},"\u002Fcost",[31,802,803,804,806],{},"Add ",[90,805,666],{}," to your team's PR template so every non-trivial change ships with a plan.",[20,808,811,830,834,850,855,858,866,977,984,997,1004,1009,1015,1018,1023,1125,1134,1143,1147],{"id":809,"title":810},"ba-hook","Build 3 — Your first hook",[11,812,813,815,816,818,819,821,822,825,826,829],{},[34,814,287],{}," 40 minutes · ",[34,817,291],{}," Intermediate · ",[34,820,295],{}," a working ",[90,823,824],{},"PostToolUse"," lint hook committed to ",[90,827,828],{},".claude\u002Fsettings.json",", plus one audit hook in your personal config.",[11,831,832],{},[34,833,305],{},[28,835,836,847],{},[31,837,838,839,842,843,846],{},"A project with a linter command (",[90,840,841],{},"npm run lint",", ",[90,844,845],{},"ruff",", whatever).",[31,848,849],{},"A terminal open next to Claude so you can tail logs.",[11,851,852,854],{},[34,853,335],{}," Wire up a deterministic guardrail that runs after Claude edits a file, then see what breaks when you push on it.",[341,856,54],{"id":857},"steps-2",[345,859,860],{},[31,861,862,863,865],{},"Add the hook to your project's ",[90,864,828],{},". Create the file if it doesn't exist:",[83,867,871],{"className":868,"code":869,"filename":828,"language":870,"meta":88,"style":88},"language-json shiki shiki-themes github-light","{\n  \"hooks\": {\n    \"PostToolUse\": [\n      {\n        \"matcher\": \"Edit|Write\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"npm run lint -- --fix $CLAUDE_FILE_PATHS 2>&1 | tail -20\"\n          }\n        ]\n      }\n    ]\n  }\n}\n","json",[90,872,873,878,886,894,899,913,920,925,937,947,952,957,962,967,972],{"__ignoreMap":88},[93,874,875],{"class":95,"line":96},[93,876,877],{"class":120},"{\n",[93,879,880,883],{"class":95,"line":133},[93,881,882],{"class":113},"  \"hooks\"",[93,884,885],{"class":120},": {\n",[93,887,888,891],{"class":95,"line":142},[93,889,890],{"class":113},"    \"PostToolUse\"",[93,892,893],{"class":120},": [\n",[93,895,896],{"class":95,"line":399},[93,897,898],{"class":120},"      {\n",[93,900,901,904,907,910],{"class":95,"line":405},[93,902,903],{"class":113},"        \"matcher\"",[93,905,906],{"class":120},": ",[93,908,909],{"class":103},"\"Edit|Write\"",[93,911,912],{"class":120},",\n",[93,914,915,918],{"class":95,"line":410},[93,916,917],{"class":113},"        \"hooks\"",[93,919,893],{"class":120},[93,921,922],{"class":95,"line":416},[93,923,924],{"class":120},"          {\n",[93,926,927,930,932,935],{"class":95,"line":426},[93,928,929],{"class":113},"            \"type\"",[93,931,906],{"class":120},[93,933,934],{"class":103},"\"command\"",[93,936,912],{"class":120},[93,938,939,942,944],{"class":95,"line":434},[93,940,941],{"class":113},"            \"command\"",[93,943,906],{"class":120},[93,945,946],{"class":103},"\"npm run lint -- --fix $CLAUDE_FILE_PATHS 2>&1 | tail -20\"\n",[93,948,949],{"class":95,"line":442},[93,950,951],{"class":120},"          }\n",[93,953,954],{"class":95,"line":450},[93,955,956],{"class":120},"        ]\n",[93,958,959],{"class":95,"line":455},[93,960,961],{"class":120},"      }\n",[93,963,964],{"class":95,"line":461},[93,965,966],{"class":120},"    ]\n",[93,968,969],{"class":95,"line":472},[93,970,971],{"class":120},"  }\n",[93,973,974],{"class":95,"line":483},[93,975,976],{"class":120},"}\n",[11,978,979,980,983],{},"Adapt the command for your linter. The ",[90,981,982],{},"2>&1 | tail -20"," keeps Claude's context from filling up with lint output on big changes.",[345,985,986],{"start":133},[31,987,988,989,992,993,996],{},"Restart your Claude session so the hook loads (",[90,990,991],{},"\u002Fexit",", then ",[90,994,995],{},"claude"," again). Confirm it's registered:",[83,998,1002],{"className":999,"code":1000,"filename":1001,"language":356,"meta":88},[353],"Run \u002Fhooks and list every hook currently active, with matcher and command.\n","prompt",[90,1003,1000],{"__ignoreMap":88},[345,1005,1006],{"start":142},[31,1007,1008],{},"Make a deliberate lint violation. Pick a file that already exists and ask Claude to add one bad line:",[83,1010,1013],{"className":1011,"code":1012,"filename":1001,"language":356,"meta":88},[353],"Add a single unused import at the top of src\u002Ffoo.ts.\nDo not fix the lint error — just add the import.\n",[90,1014,1012],{"__ignoreMap":88},[11,1016,1017],{},"Watch the hook fire in the terminal output. Expect one of three outcomes: the lint auto-fixes it, the lint reports the error and Claude responds to the report, or the hook fails silently. All three teach you something.",[345,1019,1020],{"start":399},[31,1021,1022],{},"Add an audit hook in your personal config (so it follows you across repos):",[83,1024,1027],{"className":868,"code":1025,"filename":1026,"language":870,"meta":88,"style":88},"{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"echo \\\"$(date -u +%Y-%m-%dT%H:%M:%SZ) | $CLAUDE_TOOL_INPUT\\\" >> ~\u002F.claude\u002Fbash-audit.log\"\n          }\n        ]\n      }\n    ]\n  }\n}\n","~\u002F.claude\u002Fsettings.json",[90,1028,1029,1033,1039,1046,1050,1061,1067,1071,1081,1101,1105,1109,1113,1117,1121],{"__ignoreMap":88},[93,1030,1031],{"class":95,"line":96},[93,1032,877],{"class":120},[93,1034,1035,1037],{"class":95,"line":133},[93,1036,882],{"class":113},[93,1038,885],{"class":120},[93,1040,1041,1044],{"class":95,"line":142},[93,1042,1043],{"class":113},"    \"PreToolUse\"",[93,1045,893],{"class":120},[93,1047,1048],{"class":95,"line":399},[93,1049,898],{"class":120},[93,1051,1052,1054,1056,1059],{"class":95,"line":405},[93,1053,903],{"class":113},[93,1055,906],{"class":120},[93,1057,1058],{"class":103},"\"Bash\"",[93,1060,912],{"class":120},[93,1062,1063,1065],{"class":95,"line":410},[93,1064,917],{"class":113},[93,1066,893],{"class":120},[93,1068,1069],{"class":95,"line":416},[93,1070,924],{"class":120},[93,1072,1073,1075,1077,1079],{"class":95,"line":426},[93,1074,929],{"class":113},[93,1076,906],{"class":120},[93,1078,934],{"class":103},[93,1080,912],{"class":120},[93,1082,1083,1085,1087,1090,1093,1096,1098],{"class":95,"line":434},[93,1084,941],{"class":113},[93,1086,906],{"class":120},[93,1088,1089],{"class":103},"\"echo ",[93,1091,1092],{"class":113},"\\\"",[93,1094,1095],{"class":103},"$(date -u +%Y-%m-%dT%H:%M:%SZ) | $CLAUDE_TOOL_INPUT",[93,1097,1092],{"class":113},[93,1099,1100],{"class":103}," >> ~\u002F.claude\u002Fbash-audit.log\"\n",[93,1102,1103],{"class":95,"line":442},[93,1104,951],{"class":120},[93,1106,1107],{"class":95,"line":450},[93,1108,956],{"class":120},[93,1110,1111],{"class":95,"line":455},[93,1112,961],{"class":120},[93,1114,1115],{"class":95,"line":461},[93,1116,966],{"class":120},[93,1118,1119],{"class":95,"line":472},[93,1120,971],{"class":120},[93,1122,1123],{"class":95,"line":483},[93,1124,976],{"class":120},[345,1126,1127],{"start":405},[31,1128,1129,1130,1133],{},"Run any task that involves shell commands. Then ",[90,1131,1132],{},"tail ~\u002F.claude\u002Fbash-audit.log"," in another terminal. You should see every Bash call logged with a timestamp. This is the foundation of team-wide observability.",[11,1135,1136,1138,1139,1142],{},[34,1137,60],{}," both hooks run automatically, and you can point to a line in ",[90,1140,1141],{},"bash-audit.log"," that corresponds to a command Claude ran a minute ago.",[11,1144,1145],{},[34,1146,631],{},[28,1148,1149,1164],{},[31,1150,1151,1152,1155,1156,1159,1160,1163],{},"Add a ",[90,1153,1154],{},"PreToolUse"," hook with matcher ",[90,1157,1158],{},"Edit|Write"," that blocks edits to any path matching ",[90,1161,1162],{},"**\u002F*.env*"," (exit code 2 to deny).",[31,1165,1166,1167,1170,1171,1174],{},"Write a ",[90,1168,1169],{},"SessionStart"," hook that prints ",[90,1172,1173],{},"git log --oneline -5"," into context so Claude always knows the last five commits.",[20,1176,1179,1196,1200,1207,1212,1215,1220,1386,1391,1397,1402,1408,1411,1417,1422,1430,1434],{"id":1177,"title":1178},"ba-command","Build 4 — A custom slash command",[11,1180,1181,1183,1184,292,1186,1188,1189,1192,1193,707],{},[34,1182,287],{}," 30 minutes · ",[34,1185,291],{},[34,1187,295],{}," a reusable ",[90,1190,1191],{},"\u002Freview-diff"," slash command committed to ",[90,1194,1195],{},".claude\u002Fcommands\u002F",[11,1197,1198],{},[34,1199,305],{},[28,1201,1202],{},[31,1203,1204,1205,314],{},"A repo with some in-flight changes to review (uncommitted diff, or a branch diff vs ",[90,1206,313],{},[11,1208,1209,1211],{},[34,1210,335],{}," Turn a prompt you find yourself retyping into a one-word command that does the right thing every time.",[341,1213,54],{"id":1214},"steps-3",[345,1216,1217],{},[31,1218,1219],{},"Create the command file:",[83,1221,1224],{"className":375,"code":1222,"filename":1223,"language":377,"meta":88,"style":88},"---\ndescription: Review the current diff as a skeptical senior engineer\n---\n\n# Review diff\n\nRun `git diff $ARG` (default: `main`) and review the output as a\nskeptical senior engineer.\n\nFlag:\n- Logic errors or edge cases not covered by the tests\n- Divergence from CLAUDE.md conventions\n- Missing error handling\n- Anything that would make a reviewer pause\n\nDo not flag:\n- Pure style issues the linter handles\n- Whitespace\n- Personal preference\n\nOutput:\n- Top 3 concerns, each with a file:line reference\n- Top 3 things that look right\n- One question for the author\n\n$ARGUMENTS\n",".claude\u002Fcommands\u002Freview-diff.md",[90,1225,1226,1231,1242,1246,1250,1255,1259,1275,1280,1284,1289,1296,1303,1310,1317,1321,1326,1333,1340,1347,1351,1356,1363,1370,1377,1381],{"__ignoreMap":88},[93,1227,1228],{"class":95,"line":96},[93,1229,1230],{"class":120},"---\n",[93,1232,1233,1237,1239],{"class":95,"line":133},[93,1234,1236],{"class":1235},"shJU0","description",[93,1238,906],{"class":120},[93,1240,1241],{"class":103},"Review the current diff as a skeptical senior engineer\n",[93,1243,1244],{"class":95,"line":142},[93,1245,1230],{"class":120},[93,1247,1248],{"class":95,"line":399},[93,1249,391],{"emptyLinePlaceholder":390},[93,1251,1252],{"class":95,"line":405},[93,1253,1254],{"class":384},"# Review diff\n",[93,1256,1257],{"class":95,"line":410},[93,1258,391],{"emptyLinePlaceholder":390},[93,1260,1261,1263,1266,1269,1272],{"class":95,"line":416},[93,1262,643],{"class":120},[93,1264,1265],{"class":113},"`git diff $ARG`",[93,1267,1268],{"class":120}," (default: ",[93,1270,1271],{"class":113},"`main`",[93,1273,1274],{"class":120},") and review the output as a\n",[93,1276,1277],{"class":95,"line":426},[93,1278,1279],{"class":120},"skeptical senior engineer.\n",[93,1281,1282],{"class":95,"line":434},[93,1283,391],{"emptyLinePlaceholder":390},[93,1285,1286],{"class":95,"line":442},[93,1287,1288],{"class":120},"Flag:\n",[93,1290,1291,1293],{"class":95,"line":450},[93,1292,420],{"class":419},[93,1294,1295],{"class":120}," Logic errors or edge cases not covered by the tests\n",[93,1297,1298,1300],{"class":95,"line":455},[93,1299,420],{"class":419},[93,1301,1302],{"class":120}," Divergence from CLAUDE.md conventions\n",[93,1304,1305,1307],{"class":95,"line":461},[93,1306,420],{"class":419},[93,1308,1309],{"class":120}," Missing error handling\n",[93,1311,1312,1314],{"class":95,"line":472},[93,1313,420],{"class":419},[93,1315,1316],{"class":120}," Anything that would make a reviewer pause\n",[93,1318,1319],{"class":95,"line":483},[93,1320,391],{"emptyLinePlaceholder":390},[93,1322,1323],{"class":95,"line":494},[93,1324,1325],{"class":120},"Do not flag:\n",[93,1327,1328,1330],{"class":95,"line":505},[93,1329,420],{"class":419},[93,1331,1332],{"class":120}," Pure style issues the linter handles\n",[93,1334,1335,1337],{"class":95,"line":510},[93,1336,420],{"class":419},[93,1338,1339],{"class":120}," Whitespace\n",[93,1341,1342,1344],{"class":95,"line":516},[93,1343,420],{"class":419},[93,1345,1346],{"class":120}," Personal preference\n",[93,1348,1349],{"class":95,"line":527},[93,1350,391],{"emptyLinePlaceholder":390},[93,1352,1353],{"class":95,"line":538},[93,1354,1355],{"class":120},"Output:\n",[93,1357,1358,1360],{"class":95,"line":549},[93,1359,420],{"class":419},[93,1361,1362],{"class":120}," Top 3 concerns, each with a file:line reference\n",[93,1364,1365,1367],{"class":95,"line":554},[93,1366,420],{"class":419},[93,1368,1369],{"class":120}," Top 3 things that look right\n",[93,1371,1372,1374],{"class":95,"line":560},[93,1373,420],{"class":419},[93,1375,1376],{"class":120}," One question for the author\n",[93,1378,1379],{"class":95,"line":568},[93,1380,391],{"emptyLinePlaceholder":390},[93,1382,1383],{"class":95,"line":576},[93,1384,1385],{"class":120},"$ARGUMENTS\n",[345,1387,1388],{"start":133},[31,1389,1390],{},"Restart Claude. List commands to confirm it loaded:",[83,1392,1395],{"className":1393,"code":1394,"filename":1001,"language":356,"meta":88},[353],"Run \u002Fhelp and list all available slash commands that came from this repo.\n",[90,1396,1394],{"__ignoreMap":88},[345,1398,1399],{"start":142},[31,1400,1401],{},"Try it on the current working tree:",[83,1403,1406],{"className":1404,"code":1405,"language":356,"meta":88},[353],"\u002Freview-diff\n",[90,1407,1405],{"__ignoreMap":88},[11,1409,1410],{},"Then try it against a specific ref:",[83,1412,1415],{"className":1413,"code":1414,"language":356,"meta":88},[353],"\u002Freview-diff main~3\n",[90,1416,1414],{"__ignoreMap":88},[345,1418,1419],{"start":399},[31,1420,1421],{},"Iterate on the command based on what comes back. If Claude flagged ten things you don't care about, tighten the \"do not flag\" list. If it missed a class of issues, add it to the flag list. The command file is a prompt you can refine — edit, save, re-run.",[11,1423,1424,1426,1427,1429],{},[34,1425,60],{}," ",[90,1428,1191],{}," gives you output you'd actually use in a PR review, without reshaping it.",[11,1431,1432],{},[34,1433,631],{},[28,1435,1436,1443],{},[31,1437,1438,1439,1442],{},"Build ",[90,1440,1441],{},"\u002Fship"," that runs lint, typecheck, tests, and writes a PR description in one shot.",[31,1444,1151,1445,1448,1449,1452],{},[90,1446,1447],{},"\u002Fhandoff [name]"," command that writes a structured handoff note to ",[90,1450,1451],{},".claude\u002Fhandoffs\u002F[name].md"," for picking up later.",[20,1454,1457,1469,1473,1489,1494,1497,1502,1534,1537,1542,1548,1555,1560,1566,1577,1585,1607,1615,1619],{"id":1455,"title":1456},"ba-mcp","Build 5 — Wire up an MCP server",[11,1458,1459,288,1461,818,1463,1465,1466,1468],{},[34,1460,287],{},[34,1462,291],{},[34,1464,295],{}," one MCP server connected and used in a real task, plus a note in ",[90,1467,299],{}," documenting when to reach for it.",[11,1470,1471],{},[34,1472,305],{},[28,1474,1475,1486],{},[31,1476,1477,1478,1485],{},"An MCP server to connect. Start with the official ",[1479,1480,1484],"a",{"href":1481,"rel":1482},"https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Fservers",[1483],"nofollow","filesystem server"," if you don't have one in mind — it works everywhere and has no credentials.",[31,1487,1488],{},"20 minutes of patience for the first-time setup; it gets fast after.",[11,1490,1491,1493],{},[34,1492,335],{}," Experience the shift from \"Claude knows what's in the repo\" to \"Claude can query a live system.\" You only have to feel it once.",[341,1495,54],{"id":1496},"steps-4",[345,1498,1499],{},[31,1500,1501],{},"Register the server. For the filesystem server:",[83,1503,1505],{"className":85,"code":1504,"language":87,"meta":88,"style":88},"claude mcp add filesystem -- npx -y @modelcontextprotocol\u002Fserver-filesystem \u002FUsers\u002Fyou\u002Fprojects\n",[90,1506,1507],{"__ignoreMap":88},[93,1508,1509,1511,1514,1516,1519,1522,1525,1528,1531],{"class":95,"line":96},[93,1510,995],{"class":99},[93,1512,1513],{"class":103}," mcp",[93,1515,107],{"class":103},[93,1517,1518],{"class":103}," filesystem",[93,1520,1521],{"class":113}," --",[93,1523,1524],{"class":103}," npx",[93,1526,1527],{"class":113}," -y",[93,1529,1530],{"class":103}," @modelcontextprotocol\u002Fserver-filesystem",[93,1532,1533],{"class":103}," \u002FUsers\u002Fyou\u002Fprojects\n",[11,1535,1536],{},"Adjust the directory to one you actually want Claude to browse.",[345,1538,1539],{"start":133},[31,1540,1541],{},"Verify it connected:",[83,1543,1546],{"className":1544,"code":1545,"filename":1001,"language":356,"meta":88},[353],"Run \u002Fmcp. List every connected MCP server, its status, and what tools\neach one exposes.\n",[90,1547,1545],{"__ignoreMap":88},[11,1549,1550,1551,1554],{},"If the server is red or missing, check ",[90,1552,1553],{},"claude mcp list"," in the shell and re-register. First-time connection errors are almost always a bad path or a missing dependency.",[345,1556,1557],{"start":142},[31,1558,1559],{},"Use it for something real. Example for the filesystem server:",[83,1561,1564],{"className":1562,"code":1563,"filename":1001,"language":356,"meta":88},[353],"Using the filesystem MCP tools (not your built-in Read), find every\npackage.json under ~\u002Fprojects, and tell me which ones depend on Nuxt\nand at what version.\n",[90,1565,1563],{"__ignoreMap":88},[11,1567,1568,1569,1572,1573,1576],{},"Watch which tools Claude calls. This is the actual mental model shift: built-in tools read the ",[15,1570,1571],{},"current"," repo, MCP tools read ",[15,1574,1575],{},"outside"," it.",[345,1578,1579],{"start":399},[31,1580,1581,1582,1584],{},"Document it in ",[90,1583,299],{},":",[83,1586,1588],{"className":375,"code":1587,"language":377,"meta":88,"style":88},"## MCP servers wired up\n- filesystem (~\u002Fprojects) — for cross-repo queries. Use when the task\n  spans more than this repo.\n",[90,1589,1590,1595,1602],{"__ignoreMap":88},[93,1591,1592],{"class":95,"line":96},[93,1593,1594],{"class":384},"## MCP servers wired up\n",[93,1596,1597,1599],{"class":95,"line":133},[93,1598,420],{"class":419},[93,1600,1601],{"class":120}," filesystem (~\u002Fprojects) — for cross-repo queries. Use when the task\n",[93,1603,1604],{"class":95,"line":142},[93,1605,1606],{"class":120},"  spans more than this repo.\n",[11,1608,1609,1611,1612,1614],{},[34,1610,60],{}," Claude has answered a question using MCP that it couldn't have answered without it, and ",[90,1613,299],{}," tells the next session when to reach for it.",[11,1616,1617],{},[34,1618,631],{},[28,1620,1621,1624],{},[31,1622,1623],{},"Connect a second MCP server from something you actually use day-to-day — Linear, Sentry, Datadog, Postman, Figma, whatever. The wiring is the same shape; the value jumps dramatically once it's tied to your real work.",[31,1625,1166,1626,1629],{},[90,1627,1628],{},"\u002Fwhats-on-fire"," command that asks Claude to check Sentry (or your monitoring MCP) and summarize anything new in the last 24h.",[20,1631,1634,1649,1653,1664,1669,1672,1680,1976,1981,2009,2014,2021,2032,2039,2046,2053,2058,2077,2081],{"id":1632,"title":1633},"ba-agents","Build 6 — A 3-agent team",[11,1635,1636,1638,1639,1641,1642,1644,1645,1648],{},[34,1637,287],{}," 60 minutes · ",[34,1640,291],{}," Advanced · ",[34,1643,295],{}," an ",[90,1646,1647],{},"AGENTS.md"," describing a Planner → Implementer → Reviewer team, plus one real feature shipped through it in conductor mode.",[11,1650,1651],{},[34,1652,305],{},[28,1654,1655,1661],{},[31,1656,1657,1658,1660],{},"A working ",[90,1659,299],{}," (Build 1) and at least one hook (Build 3) — this exercise assumes the basics are already in place.",[31,1662,1663],{},"A small, well-scoped feature task.",[11,1665,1666,1668],{},[34,1667,335],{}," Ship something with three coordinated Claude roles. Not for the efficiency — for the reps. Multi-agent workflows are unforgiving to teams that skip this practical.",[341,1670,54],{"id":1671},"steps-5",[345,1673,1674],{},[31,1675,1676,1677,1679],{},"Create ",[90,1678,1647],{}," in the repo root. Start with this template and edit the bracketed parts:",[83,1681,1683],{"className":375,"code":1682,"filename":1647,"language":377,"meta":88,"style":88},"# Agent team charter\n\n## Roles\n\n### Planner\nModel: opus\nWorkdir: repo root (read-only)\nTools: Read, Glob, Grep, WebFetch\n\nResponsibilities:\n- Explore the relevant code for the task\n- Produce a plan: files touched, functions changed, tests, risks\n- Save plan to .claude\u002Fplan.md\n\nRules:\n- Never edit code\n- Ambiguity → list it, stop, do not guess\n\n### Implementer\nModel: sonnet\nWorkdir: feature worktree\nTools: Read, Edit, Write, Bash(npm test*), Bash(npm run lint*)\n\nResponsibilities:\n- Read .claude\u002Fplan.md first\n- Implement exactly the plan — do not expand scope\n- Save completion note to .claude\u002Fimpl-done.md\n\nRules:\n- No test edits (Reviewer owns those)\n- Ambiguity → note in impl-done.md, best-effort, keep going\n\n### Reviewer\nModel: sonnet\nWorkdir: feature worktree (read-only)\nTools: Read, Glob, Grep, Bash(npm test*), Bash(git diff*)\n\nResponsibilities:\n- Read plan.md, read impl-done.md, run git diff main\n- Report: what's right, what's wrong, what's missing\n- Save to .claude\u002Freview.md\n\nRules:\n- Report findings only — do not propose fixes\n- If tests fail, list which; do not try to fix\n\n## Ordering\nPlanner → Implementer → Reviewer → human\n\n## Shared state\nAll handoffs live in .claude\u002F (gitignored). No state through conversation.\n",[90,1684,1685,1690,1694,1699,1703,1708,1713,1718,1723,1727,1732,1739,1746,1753,1757,1762,1769,1776,1780,1785,1790,1795,1800,1804,1808,1815,1822,1829,1833,1838,1846,1854,1859,1865,1870,1876,1882,1887,1892,1900,1908,1916,1921,1926,1934,1942,1947,1953,1959,1964,1970],{"__ignoreMap":88},[93,1686,1687],{"class":95,"line":96},[93,1688,1689],{"class":384},"# Agent team charter\n",[93,1691,1692],{"class":95,"line":133},[93,1693,391],{"emptyLinePlaceholder":390},[93,1695,1696],{"class":95,"line":142},[93,1697,1698],{"class":384},"## Roles\n",[93,1700,1701],{"class":95,"line":399},[93,1702,391],{"emptyLinePlaceholder":390},[93,1704,1705],{"class":95,"line":405},[93,1706,1707],{"class":384},"### Planner\n",[93,1709,1710],{"class":95,"line":410},[93,1711,1712],{"class":120},"Model: opus\n",[93,1714,1715],{"class":95,"line":416},[93,1716,1717],{"class":120},"Workdir: repo root (read-only)\n",[93,1719,1720],{"class":95,"line":426},[93,1721,1722],{"class":120},"Tools: Read, Glob, Grep, WebFetch\n",[93,1724,1725],{"class":95,"line":434},[93,1726,391],{"emptyLinePlaceholder":390},[93,1728,1729],{"class":95,"line":442},[93,1730,1731],{"class":120},"Responsibilities:\n",[93,1733,1734,1736],{"class":95,"line":450},[93,1735,420],{"class":419},[93,1737,1738],{"class":120}," Explore the relevant code for the task\n",[93,1740,1741,1743],{"class":95,"line":455},[93,1742,420],{"class":419},[93,1744,1745],{"class":120}," Produce a plan: files touched, functions changed, tests, risks\n",[93,1747,1748,1750],{"class":95,"line":461},[93,1749,420],{"class":419},[93,1751,1752],{"class":120}," Save plan to .claude\u002Fplan.md\n",[93,1754,1755],{"class":95,"line":472},[93,1756,391],{"emptyLinePlaceholder":390},[93,1758,1759],{"class":95,"line":483},[93,1760,1761],{"class":120},"Rules:\n",[93,1763,1764,1766],{"class":95,"line":494},[93,1765,420],{"class":419},[93,1767,1768],{"class":120}," Never edit code\n",[93,1770,1771,1773],{"class":95,"line":505},[93,1772,420],{"class":419},[93,1774,1775],{"class":120}," Ambiguity → list it, stop, do not guess\n",[93,1777,1778],{"class":95,"line":510},[93,1779,391],{"emptyLinePlaceholder":390},[93,1781,1782],{"class":95,"line":516},[93,1783,1784],{"class":384},"### Implementer\n",[93,1786,1787],{"class":95,"line":527},[93,1788,1789],{"class":120},"Model: sonnet\n",[93,1791,1792],{"class":95,"line":538},[93,1793,1794],{"class":120},"Workdir: feature worktree\n",[93,1796,1797],{"class":95,"line":549},[93,1798,1799],{"class":120},"Tools: Read, Edit, Write, Bash(npm test*), Bash(npm run lint*)\n",[93,1801,1802],{"class":95,"line":554},[93,1803,391],{"emptyLinePlaceholder":390},[93,1805,1806],{"class":95,"line":560},[93,1807,1731],{"class":120},[93,1809,1810,1812],{"class":95,"line":568},[93,1811,420],{"class":419},[93,1813,1814],{"class":120}," Read .claude\u002Fplan.md first\n",[93,1816,1817,1819],{"class":95,"line":576},[93,1818,420],{"class":419},[93,1820,1821],{"class":120}," Implement exactly the plan — do not expand scope\n",[93,1823,1824,1826],{"class":95,"line":581},[93,1825,420],{"class":419},[93,1827,1828],{"class":120}," Save completion note to .claude\u002Fimpl-done.md\n",[93,1830,1831],{"class":95,"line":587},[93,1832,391],{"emptyLinePlaceholder":390},[93,1834,1836],{"class":95,"line":1835},29,[93,1837,1761],{"class":120},[93,1839,1841,1843],{"class":95,"line":1840},30,[93,1842,420],{"class":419},[93,1844,1845],{"class":120}," No test edits (Reviewer owns those)\n",[93,1847,1849,1851],{"class":95,"line":1848},31,[93,1850,420],{"class":419},[93,1852,1853],{"class":120}," Ambiguity → note in impl-done.md, best-effort, keep going\n",[93,1855,1857],{"class":95,"line":1856},32,[93,1858,391],{"emptyLinePlaceholder":390},[93,1860,1862],{"class":95,"line":1861},33,[93,1863,1864],{"class":384},"### Reviewer\n",[93,1866,1868],{"class":95,"line":1867},34,[93,1869,1789],{"class":120},[93,1871,1873],{"class":95,"line":1872},35,[93,1874,1875],{"class":120},"Workdir: feature worktree (read-only)\n",[93,1877,1879],{"class":95,"line":1878},36,[93,1880,1881],{"class":120},"Tools: Read, Glob, Grep, Bash(npm test*), Bash(git diff*)\n",[93,1883,1885],{"class":95,"line":1884},37,[93,1886,391],{"emptyLinePlaceholder":390},[93,1888,1890],{"class":95,"line":1889},38,[93,1891,1731],{"class":120},[93,1893,1895,1897],{"class":95,"line":1894},39,[93,1896,420],{"class":419},[93,1898,1899],{"class":120}," Read plan.md, read impl-done.md, run git diff main\n",[93,1901,1903,1905],{"class":95,"line":1902},40,[93,1904,420],{"class":419},[93,1906,1907],{"class":120}," Report: what's right, what's wrong, what's missing\n",[93,1909,1911,1913],{"class":95,"line":1910},41,[93,1912,420],{"class":419},[93,1914,1915],{"class":120}," Save to .claude\u002Freview.md\n",[93,1917,1919],{"class":95,"line":1918},42,[93,1920,391],{"emptyLinePlaceholder":390},[93,1922,1924],{"class":95,"line":1923},43,[93,1925,1761],{"class":120},[93,1927,1929,1931],{"class":95,"line":1928},44,[93,1930,420],{"class":419},[93,1932,1933],{"class":120}," Report findings only — do not propose fixes\n",[93,1935,1937,1939],{"class":95,"line":1936},45,[93,1938,420],{"class":419},[93,1940,1941],{"class":120}," If tests fail, list which; do not try to fix\n",[93,1943,1945],{"class":95,"line":1944},46,[93,1946,391],{"emptyLinePlaceholder":390},[93,1948,1950],{"class":95,"line":1949},47,[93,1951,1952],{"class":384},"## Ordering\n",[93,1954,1956],{"class":95,"line":1955},48,[93,1957,1958],{"class":120},"Planner → Implementer → Reviewer → human\n",[93,1960,1962],{"class":95,"line":1961},49,[93,1963,391],{"emptyLinePlaceholder":390},[93,1965,1967],{"class":95,"line":1966},50,[93,1968,1969],{"class":384},"## Shared state\n",[93,1971,1973],{"class":95,"line":1972},51,[93,1974,1975],{"class":120},"All handoffs live in .claude\u002F (gitignored). No state through conversation.\n",[345,1977,1978],{"start":133},[31,1979,1980],{},"Create a feature worktree:",[83,1982,1984],{"className":85,"code":1983,"language":87,"meta":88,"style":88},"git worktree add ..\u002Fworkshop-agents -b workshop\u002Fagents\ncd ..\u002Fworkshop-agents\n",[90,1985,1986,2002],{"__ignoreMap":88},[93,1987,1988,1990,1992,1994,1997,1999],{"class":95,"line":96},[93,1989,100],{"class":99},[93,1991,104],{"class":103},[93,1993,107],{"class":103},[93,1995,1996],{"class":103}," ..\u002Fworkshop-agents",[93,1998,114],{"class":113},[93,2000,2001],{"class":103}," workshop\u002Fagents\n",[93,2003,2004,2006],{"class":95,"line":133},[93,2005,136],{"class":113},[93,2007,2008],{"class":103}," ..\u002Fworkshop-agents\n",[345,2010,2011],{"start":142},[31,2012,2013],{},"Run in conductor mode — you drive each role manually. Start the Planner:",[83,2015,2019],{"className":2016,"code":2017,"filename":2018,"language":356,"meta":88},[353],"You are the Planner role from AGENTS.md. Read AGENTS.md first, then:\n\nTask: [your small feature].\n\nProduce the plan exactly as the role specifies. Save to .claude\u002Fplan.md.\nStop when done — do not implement.\n","prompt — planner session",[90,2020,2017],{"__ignoreMap":88},[345,2022,2023],{"start":399},[31,2024,2025,2026,2028,2029,2031],{},"Read ",[90,2027,666],{},". If it's bad, send it back. If it's good, ",[90,2030,605],{}," and start the Implementer:",[83,2033,2037],{"className":2034,"code":2035,"filename":2036,"language":356,"meta":88},[353],"You are the Implementer role from AGENTS.md. Read AGENTS.md, then\nread .claude\u002Fplan.md, then execute.\n\nSave your completion note to .claude\u002Fimpl-done.md when finished.\n","prompt — implementer session",[90,2038,2035],{"__ignoreMap":88},[345,2040,2041],{"start":405},[31,2042,2043,2045],{},[90,2044,605],{}," and start the Reviewer:",[83,2047,2051],{"className":2048,"code":2049,"filename":2050,"language":356,"meta":88},[353],"You are the Reviewer role from AGENTS.md. Read AGENTS.md, then\n.claude\u002Fplan.md, then .claude\u002Fimpl-done.md, then run git diff main.\n\nWrite your review to .claude\u002Freview.md.\n","prompt — reviewer session",[90,2052,2049],{"__ignoreMap":88},[345,2054,2055],{"start":410},[31,2056,2057],{},"Read the review. Fix, retry, or ship. Commit.",[11,2059,2060,2062,2063,2066,2067,842,2070,842,2073,2076],{},[34,2061,60],{}," you have three files in ",[90,2064,2065],{},".claude\u002F"," (",[90,2068,2069],{},"plan.md",[90,2071,2072],{},"impl-done.md",[90,2074,2075],{},"review.md",") and the feature is shipped.",[11,2078,2079],{},[34,2080,631],{},[28,2082,2083,2089],{},[31,2084,2085,2086,2088],{},"Add a fourth role: Documenter. Reads the diff, updates ",[90,2087,299],{}," if any convention shifted.",[31,2090,2091,2092,2094,2095,2097],{},"Convert conductor mode to orchestrator mode: one main Claude reads ",[90,2093,1647],{}," and spawns all three roles as subagents without you in between. Only try this after you've done conductor mode twice — the ",[90,2096,1647],{}," needs to be battle-tested first.",[20,2099,2102,2111,2115,2123,2128,2131,2136,2158,2249,2254,2420,2425,2438,2441,2446,2572,2585,2592,2596],{"id":2100,"title":2101},"ba-evals","Build 7 — An eval suite",[11,2103,2104,1638,2106,1641,2108,2110],{},[34,2105,287],{},[34,2107,291],{},[34,2109,295],{}," a minimal eval suite with 5 golden examples and one LLM-as-judge check, runnable locally.",[11,2112,2113],{},[34,2114,305],{},[28,2116,2117,2120],{},[31,2118,2119],{},"A part of your system where Claude is producing user-facing output (a slash command, a subagent that writes summaries, an MCP-assisted Q&A flow — anything with a repeatable \"input → Claude-generated output\" shape).",[31,2121,2122],{},"Node installed.",[11,2124,2125,2127],{},[34,2126,335],{}," Build a tiny regression suite. Five examples, one scorer. From scratch. Once you've done it once, you'll never ship unscored LLM features again.",[341,2129,54],{"id":2130},"steps-6",[345,2132,2133],{},[31,2134,2135],{},"Make a directory and capture five examples. Pick five real inputs to your flow, run them, and save the outputs you consider \"correct enough\":",[83,2137,2139],{"className":85,"code":2138,"language":87,"meta":88,"style":88},"mkdir -p evals\ncd evals\n",[90,2140,2141,2152],{"__ignoreMap":88},[93,2142,2143,2146,2149],{"class":95,"line":96},[93,2144,2145],{"class":99},"mkdir",[93,2147,2148],{"class":113}," -p",[93,2150,2151],{"class":103}," evals\n",[93,2153,2154,2156],{"class":95,"line":133},[93,2155,136],{"class":113},[93,2157,2151],{"class":103},[83,2159,2162],{"className":868,"code":2160,"filename":2161,"language":870,"meta":88,"style":88},"[\n  {\n    \"id\": \"ex-1\",\n    \"input\": \"[real input #1]\",\n    \"expected_contains\": [\"[key phrase Claude must produce]\"],\n    \"expected_not_contains\": [\"[phrase that would mean it hallucinated]\"],\n    \"notes\": \"[why this example matters]\"\n  }\n  \u002F* 4 more *\u002F\n]\n","evals\u002Fgoldens.json",[90,2163,2164,2169,2174,2186,2198,2212,2224,2234,2238,2244],{"__ignoreMap":88},[93,2165,2166],{"class":95,"line":96},[93,2167,2168],{"class":120},"[\n",[93,2170,2171],{"class":95,"line":133},[93,2172,2173],{"class":120},"  {\n",[93,2175,2176,2179,2181,2184],{"class":95,"line":142},[93,2177,2178],{"class":113},"    \"id\"",[93,2180,906],{"class":120},[93,2182,2183],{"class":103},"\"ex-1\"",[93,2185,912],{"class":120},[93,2187,2188,2191,2193,2196],{"class":95,"line":399},[93,2189,2190],{"class":113},"    \"input\"",[93,2192,906],{"class":120},[93,2194,2195],{"class":103},"\"[real input #1]\"",[93,2197,912],{"class":120},[93,2199,2200,2203,2206,2209],{"class":95,"line":405},[93,2201,2202],{"class":113},"    \"expected_contains\"",[93,2204,2205],{"class":120},": [",[93,2207,2208],{"class":103},"\"[key phrase Claude must produce]\"",[93,2210,2211],{"class":120},"],\n",[93,2213,2214,2217,2219,2222],{"class":95,"line":410},[93,2215,2216],{"class":113},"    \"expected_not_contains\"",[93,2218,2205],{"class":120},[93,2220,2221],{"class":103},"\"[phrase that would mean it hallucinated]\"",[93,2223,2211],{"class":120},[93,2225,2226,2229,2231],{"class":95,"line":416},[93,2227,2228],{"class":113},"    \"notes\"",[93,2230,906],{"class":120},[93,2232,2233],{"class":103},"\"[why this example matters]\"\n",[93,2235,2236],{"class":95,"line":426},[93,2237,971],{"class":120},[93,2239,2240],{"class":95,"line":434},[93,2241,2243],{"class":2242},"sAwPA","  \u002F* 4 more *\u002F\n",[93,2245,2246],{"class":95,"line":442},[93,2247,2248],{"class":120},"]\n",[345,2250,2251],{"start":133},[31,2252,2253],{},"Write the runner. Keep it under 60 lines:",[83,2255,2260],{"className":2256,"code":2257,"filename":2258,"language":2259,"meta":88,"style":88},"language-js shiki shiki-themes github-light","import fs from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\n\nconst goldens = JSON.parse(fs.readFileSync(\".\u002Fgoldens.json\", \"utf8\"));\n\nfunction run(input) {\n  \u002F\u002F Adapt this: call your slash command \u002F subagent \u002F MCP flow.\n  \u002F\u002F The simplest version: shell out to claude with the input as a\n  \u002F\u002F one-shot prompt.\n  const res = spawnSync(\n    \"claude\",\n    [\"-p\", input, \"--output-format\", \"text\"],\n    { encoding: \"utf8\" }\n  );\n  return res.stdout ?? \"\";\n}\n\nlet pass = 0;\nlet fail = 0;\nfor (const g of goldens) {\n  const out = run(g.input);\n  const hits = (g.expected_contains ?? []).every((p) => out.includes(p));\n  const misses = (g.expected_not_contains ?? []).every(\n    (p) => !out.includes(p),\n  );\n  const ok = hits && misses;\n  console.log(`${ok ? \"PASS\" : \"FAIL\"}  ${g.id}`);\n  if (!ok) console.log(\"  output:\", out.slice(0, 400));\n  ok ? pass++ : fail++;\n}\n\nconsole.log(`\\n${pass}\u002F${pass + fail} passed`);\nprocess.exit(fail ? 1 : 0);\n","evals\u002Frun.js","js",[90,2261,2262,2267,2272,2276,2281,2285,2290,2295,2300,2305,2310,2315,2320,2325,2330,2335,2339,2343,2348,2353,2358,2363,2368,2373,2378,2382,2387,2392,2397,2402,2406,2410,2415],{"__ignoreMap":88},[93,2263,2264],{"class":95,"line":96},[93,2265,2266],{},"import fs from \"node:fs\";\n",[93,2268,2269],{"class":95,"line":133},[93,2270,2271],{},"import { spawnSync } from \"node:child_process\";\n",[93,2273,2274],{"class":95,"line":142},[93,2275,391],{"emptyLinePlaceholder":390},[93,2277,2278],{"class":95,"line":399},[93,2279,2280],{},"const goldens = JSON.parse(fs.readFileSync(\".\u002Fgoldens.json\", \"utf8\"));\n",[93,2282,2283],{"class":95,"line":405},[93,2284,391],{"emptyLinePlaceholder":390},[93,2286,2287],{"class":95,"line":410},[93,2288,2289],{},"function run(input) {\n",[93,2291,2292],{"class":95,"line":416},[93,2293,2294],{},"  \u002F\u002F Adapt this: call your slash command \u002F subagent \u002F MCP flow.\n",[93,2296,2297],{"class":95,"line":426},[93,2298,2299],{},"  \u002F\u002F The simplest version: shell out to claude with the input as a\n",[93,2301,2302],{"class":95,"line":434},[93,2303,2304],{},"  \u002F\u002F one-shot prompt.\n",[93,2306,2307],{"class":95,"line":442},[93,2308,2309],{},"  const res = spawnSync(\n",[93,2311,2312],{"class":95,"line":450},[93,2313,2314],{},"    \"claude\",\n",[93,2316,2317],{"class":95,"line":455},[93,2318,2319],{},"    [\"-p\", input, \"--output-format\", \"text\"],\n",[93,2321,2322],{"class":95,"line":461},[93,2323,2324],{},"    { encoding: \"utf8\" }\n",[93,2326,2327],{"class":95,"line":472},[93,2328,2329],{},"  );\n",[93,2331,2332],{"class":95,"line":483},[93,2333,2334],{},"  return res.stdout ?? \"\";\n",[93,2336,2337],{"class":95,"line":494},[93,2338,976],{},[93,2340,2341],{"class":95,"line":505},[93,2342,391],{"emptyLinePlaceholder":390},[93,2344,2345],{"class":95,"line":510},[93,2346,2347],{},"let pass = 0;\n",[93,2349,2350],{"class":95,"line":516},[93,2351,2352],{},"let fail = 0;\n",[93,2354,2355],{"class":95,"line":527},[93,2356,2357],{},"for (const g of goldens) {\n",[93,2359,2360],{"class":95,"line":538},[93,2361,2362],{},"  const out = run(g.input);\n",[93,2364,2365],{"class":95,"line":549},[93,2366,2367],{},"  const hits = (g.expected_contains ?? []).every((p) => out.includes(p));\n",[93,2369,2370],{"class":95,"line":554},[93,2371,2372],{},"  const misses = (g.expected_not_contains ?? []).every(\n",[93,2374,2375],{"class":95,"line":560},[93,2376,2377],{},"    (p) => !out.includes(p),\n",[93,2379,2380],{"class":95,"line":568},[93,2381,2329],{},[93,2383,2384],{"class":95,"line":576},[93,2385,2386],{},"  const ok = hits && misses;\n",[93,2388,2389],{"class":95,"line":581},[93,2390,2391],{},"  console.log(`${ok ? \"PASS\" : \"FAIL\"}  ${g.id}`);\n",[93,2393,2394],{"class":95,"line":587},[93,2395,2396],{},"  if (!ok) console.log(\"  output:\", out.slice(0, 400));\n",[93,2398,2399],{"class":95,"line":1835},[93,2400,2401],{},"  ok ? pass++ : fail++;\n",[93,2403,2404],{"class":95,"line":1840},[93,2405,976],{},[93,2407,2408],{"class":95,"line":1848},[93,2409,391],{"emptyLinePlaceholder":390},[93,2411,2412],{"class":95,"line":1856},[93,2413,2414],{},"console.log(`\\n${pass}\u002F${pass + fail} passed`);\n",[93,2416,2417],{"class":95,"line":1861},[93,2418,2419],{},"process.exit(fail ? 1 : 0);\n",[345,2421,2422],{"start":142},[31,2423,2424],{},"Run it:",[83,2426,2428],{"className":85,"code":2427,"language":87,"meta":88,"style":88},"node run.js\n",[90,2429,2430],{"__ignoreMap":88},[93,2431,2432,2435],{"class":95,"line":96},[93,2433,2434],{"class":99},"node",[93,2436,2437],{"class":103}," run.js\n",[11,2439,2440],{},"Expect 4\u002F5 or 5\u002F5 on first run — you picked these examples. The suite starts catching things when you refactor and something quietly regresses.",[345,2442,2443],{"start":399},[31,2444,2445],{},"Add a judge. For each example, have a separate Claude session grade it against a rubric:",[83,2447,2450],{"className":2256,"code":2448,"filename":2449,"language":2259,"meta":88,"style":88},"import fs from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\n\nconst goldens = JSON.parse(fs.readFileSync(\".\u002Fgoldens.json\", \"utf8\"));\n\nconst rubric = `\nGrade from 1-5:\n- 5: answers the question fully, no extra info, no hallucination\n- 4: correct but slightly verbose or tangential\n- 3: partial answer, or minor factual drift\n- 2: misses the point, or introduces a wrong claim\n- 1: wrong \u002F unsafe \u002F empty\n\nOutput only a single digit.\n`;\n\nfor (const g of goldens) {\n  const out = spawnSync(\"claude\", [\"-p\", g.input, \"--output-format\", \"text\"], {\n    encoding: \"utf8\",\n  }).stdout;\n  const prompt = `Input:\\n${g.input}\\n\\nOutput:\\n${out}\\n\\nRubric:${rubric}`;\n  const grade = spawnSync(\"claude\", [\"-p\", prompt, \"--output-format\", \"text\"], {\n    encoding: \"utf8\",\n  }).stdout.trim();\n  console.log(`${g.id} → ${grade}`);\n}\n","evals\u002Fjudge.js",[90,2451,2452,2456,2460,2464,2468,2472,2477,2482,2487,2492,2497,2502,2507,2511,2516,2521,2525,2529,2534,2539,2544,2549,2554,2558,2563,2568],{"__ignoreMap":88},[93,2453,2454],{"class":95,"line":96},[93,2455,2266],{},[93,2457,2458],{"class":95,"line":133},[93,2459,2271],{},[93,2461,2462],{"class":95,"line":142},[93,2463,391],{"emptyLinePlaceholder":390},[93,2465,2466],{"class":95,"line":399},[93,2467,2280],{},[93,2469,2470],{"class":95,"line":405},[93,2471,391],{"emptyLinePlaceholder":390},[93,2473,2474],{"class":95,"line":410},[93,2475,2476],{},"const rubric = `\n",[93,2478,2479],{"class":95,"line":416},[93,2480,2481],{},"Grade from 1-5:\n",[93,2483,2484],{"class":95,"line":426},[93,2485,2486],{},"- 5: answers the question fully, no extra info, no hallucination\n",[93,2488,2489],{"class":95,"line":434},[93,2490,2491],{},"- 4: correct but slightly verbose or tangential\n",[93,2493,2494],{"class":95,"line":442},[93,2495,2496],{},"- 3: partial answer, or minor factual drift\n",[93,2498,2499],{"class":95,"line":450},[93,2500,2501],{},"- 2: misses the point, or introduces a wrong claim\n",[93,2503,2504],{"class":95,"line":455},[93,2505,2506],{},"- 1: wrong \u002F unsafe \u002F empty\n",[93,2508,2509],{"class":95,"line":461},[93,2510,391],{"emptyLinePlaceholder":390},[93,2512,2513],{"class":95,"line":472},[93,2514,2515],{},"Output only a single digit.\n",[93,2517,2518],{"class":95,"line":483},[93,2519,2520],{},"`;\n",[93,2522,2523],{"class":95,"line":494},[93,2524,391],{"emptyLinePlaceholder":390},[93,2526,2527],{"class":95,"line":505},[93,2528,2357],{},[93,2530,2531],{"class":95,"line":510},[93,2532,2533],{},"  const out = spawnSync(\"claude\", [\"-p\", g.input, \"--output-format\", \"text\"], {\n",[93,2535,2536],{"class":95,"line":516},[93,2537,2538],{},"    encoding: \"utf8\",\n",[93,2540,2541],{"class":95,"line":527},[93,2542,2543],{},"  }).stdout;\n",[93,2545,2546],{"class":95,"line":538},[93,2547,2548],{},"  const prompt = `Input:\\n${g.input}\\n\\nOutput:\\n${out}\\n\\nRubric:${rubric}`;\n",[93,2550,2551],{"class":95,"line":549},[93,2552,2553],{},"  const grade = spawnSync(\"claude\", [\"-p\", prompt, \"--output-format\", \"text\"], {\n",[93,2555,2556],{"class":95,"line":554},[93,2557,2538],{},[93,2559,2560],{"class":95,"line":560},[93,2561,2562],{},"  }).stdout.trim();\n",[93,2564,2565],{"class":95,"line":568},[93,2566,2567],{},"  console.log(`${g.id} → ${grade}`);\n",[93,2569,2570],{"class":95,"line":576},[93,2571,976],{},[345,2573,2574],{"start":405},[31,2575,2576,2577,2580,2581,2584],{},"Commit ",[90,2578,2579],{},"evals\u002F"," into your repo. Add a CI step (GitHub Action, pre-push hook, whatever you've got) that runs ",[90,2582,2583],{},"node run.js"," on main. When it fails, something drifted.",[11,2586,2587,1426,2589,2591],{},[34,2588,60],{},[90,2590,2583],{}," exits 0 against your current system, and you've deliberately broken one of the underlying prompts to watch a test go red.",[11,2593,2594],{},[34,2595,631],{},[28,2597,2598,2601],{},[31,2599,2600],{},"Cache outputs by input so you're not re-running Claude for every CI run.",[31,2602,2603],{},"Add a third dimension: latency. Fail the suite if median response time exceeds N seconds.",[20,2605,2608,2611,2614],{"id":2606,"title":2607},"challenges","Challenges",[11,2609,2610],{},"Build-alongs teach a concept. Challenges test whether it stuck. Each one has a target and a time limit — no scripted steps. You figure out the path.",[11,2612,2613],{},"These are meant to feel slightly uncomfortable. If you're sailing through, pick a harder version.",[160,2615,2616,2630],{},[163,2617,2618],{},[166,2619,2620,2622,2625,2628],{},[169,2621,171],{},[169,2623,2624],{},"Challenge",[169,2626,2627],{},"Goal",[169,2629,36],{},[181,2631,2632,2647,2659,2671,2683],{},[166,2633,2634,2636,2639,2645],{},[186,2635,188],{},[186,2637,2638],{},"Cost-cut 50%",[186,2640,2641,2642,2644],{},"Halve ",[90,2643,800],{}," on a repeatable task",[186,2646,265],{},[166,2648,2649,2651,2654,2657],{},[186,2650,202],{},[186,2652,2653],{},"CLAUDE.md diet",[186,2655,2656],{},"30% fewer tokens, same behavior",[186,2658,197],{},[166,2660,2661,2663,2666,2669],{},[186,2662,215],{},[186,2664,2665],{},"Prompt precision",[186,2667,2668],{},"Kill 5 prompt iterations",[186,2670,197],{},[166,2672,2673,2675,2678,2681],{},[186,2674,229],{},[186,2676,2677],{},"Debug a broken hook",[186,2679,2680],{},"Silent hook → firing hook",[186,2682,238],{},[166,2684,2685,2687,2690,2693],{},[186,2686,243],{},[186,2688,2689],{},"Model routing",[186,2691,2692],{},"Stop defaulting to Opus",[186,2694,238],{},[20,2696,2699,2706,2712,2721,2726,2737,2746],{"id":2697,"title":2698},"ch-cost","Challenge 1 — Cost-cut 50%",[11,2700,2701,1638,2703,2705],{},[34,2702,287],{},[34,2704,291],{}," Intermediate.",[11,2707,2708,2711],{},[34,2709,2710],{},"The setup."," Pick a task you've done multiple times with Claude — a weekly triage, a report generation, a refactor template, a review pass. Something you could run five times a week and the shape is the same.",[11,2713,2714,2717,2718,2720],{},[34,2715,2716],{},"The target."," Run it once, baseline the cost with ",[90,2719,800],{},". Then get that number down by at least 50% without degrading the output.",[11,2722,2723],{},[34,2724,2725],{},"Constraints.",[28,2727,2728,2731,2734],{},[31,2729,2730],{},"The output must still pass the smell test — a colleague reading the two results shouldn't prefer the expensive one.",[31,2732,2733],{},"You can change anything: CLAUDE.md, the prompt, the model, Plan Mode on\u002Foff, the ordering, adding a hook to strip output, caching context, using a subagent for the retrieval phase.",[31,2735,2736],{},"You cannot skip the work. If the baseline task produced a diff, the cheap version produces an equivalent diff.",[11,2738,2739,2742,2743,2745],{},[34,2740,2741],{},"What you're actually learning."," Where the tokens were going. Most people discover one of four culprits: bloated ",[90,2744,299],{},", Opus where Sonnet was enough, unnecessary file re-reads, or chatty \"explain yourself\" behavior that could be hook-trimmed.",[11,2747,2748,2750,2751,2753],{},[34,2749,60],{}," the two ",[90,2752,800],{}," readings differ by 50% or more and you can explain why in one sentence.",[20,2755,2758,2764,2772,2793,2798,2802,2813,2820],{"id":2756,"title":2757},"ch-diet","Challenge 2 — CLAUDE.md diet",[11,2759,2760,288,2762,2705],{},[34,2761,287],{},[34,2763,291],{},[11,2765,2766,2768,2769,2771],{},[34,2767,2710],{}," Your existing ",[90,2770,299],{},". Measure it first:",[83,2773,2775],{"className":85,"code":2774,"language":87,"meta":88,"style":88},"# Roughly — wc -w is a decent proxy for tokens; 1 token ≈ 0.75 words\nwc -w CLAUDE.md\n",[90,2776,2777,2782],{"__ignoreMap":88},[93,2778,2779],{"class":95,"line":96},[93,2780,2781],{"class":2242},"# Roughly — wc -w is a decent proxy for tokens; 1 token ≈ 0.75 words\n",[93,2783,2784,2787,2790],{"class":95,"line":133},[93,2785,2786],{"class":99},"wc",[93,2788,2789],{"class":113}," -w",[93,2791,2792],{"class":103}," CLAUDE.md\n",[11,2794,2795,2797],{},[34,2796,2716],{}," Get it 30% smaller, same or better task outcomes.",[11,2799,2800],{},[34,2801,2725],{},[28,2803,2804,2807,2810],{},[31,2805,2806],{},"Remove only. Don't rewrite wholesale; delete what's dead.",[31,2808,2809],{},"For every section you cut, be able to answer: \"what would break without this?\" If nothing would, it was cargo cult.",[31,2811,2812],{},"After the cut, run a known task and confirm the output didn't regress.",[11,2814,2815,1426,2817,2819],{},[34,2816,2741],{},[90,2818,299],{}," rots. Rules get added because someone got burned once, then live forever. A 30% cut is almost always available because much of what's there is answering a question that never gets asked.",[11,2821,2822,2824,2825,2827],{},[34,2823,60],{}," the file is 30% lighter ",[15,2826,787],{}," a known task still produces the same output.",[20,2829,2832,2839,2848,2853,2857,2871,2876],{"id":2830,"title":2831},"ch-prompt","Challenge 3 — Prompt precision",[11,2833,2834,288,2836,2838],{},[34,2835,287],{},[34,2837,291],{}," Beginner.",[11,2840,2841,2843,2844,2847],{},[34,2842,2710],{}," Pick a task you've fumbled recently — a change Claude got wrong twice before getting right. Replay the exchange mentally (or look at ",[90,2845,2846],{},"\u002Fstatus"," \u002F session history).",[11,2849,2850,2852],{},[34,2851,2716],{}," Produce one single prompt that would have gotten the same correct final result on the first try. One prompt — no follow-ups.",[11,2854,2855],{},[34,2856,2725],{},[28,2858,2859,2862,2865],{},[31,2860,2861],{},"The prompt can be long. Multi-paragraph is fine.",[31,2863,2864],{},"You can reference files Claude should read, constraints it should respect, output format it should produce.",[31,2866,2867,2868,2870],{},"When you have it, start a fresh session (",[90,2869,605],{},") and run it. If you need a second prompt, you haven't solved the challenge. Rewrite and try again.",[11,2872,2873,2875],{},[34,2874,2741],{}," The gap between \"what I meant\" and \"what I said.\" Every extra turn in the original exchange is a piece of context you failed to include up-front. The precision-prompt exercise is the fastest way to internalize what up-front context is worth.",[11,2877,2878,2880],{},[34,2879,60],{}," a cold session produces the right final result on prompt #1.",[20,2882,2885,2891,2898,2986,2992,2997,3001,3022,3027],{"id":2883,"title":2884},"ch-hook","Challenge 4 — Debug a broken hook",[11,2886,2887,1183,2889,2705],{},[34,2888,287],{},[34,2890,291],{},[11,2892,2893,2895,2896,1584],{},[34,2894,2710],{}," Add this to your ",[90,2897,1026],{},[83,2899,2901],{"className":868,"code":2900,"language":870,"meta":88,"style":88},"{\n  \"hooks\": {\n    \"PostToolUse\": [\n      {\n        \"matcher\": \"Edit|Write\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"grep -r 'TODO' $CLAUDE_FILE_PATHS > \u002Ftmp\u002Fclaude-todos.log 2>&1\"\n          }\n        ]\n      }\n    ]\n  }\n}\n",[90,2902,2903,2907,2913,2919,2923,2933,2939,2943,2953,2962,2966,2970,2974,2978,2982],{"__ignoreMap":88},[93,2904,2905],{"class":95,"line":96},[93,2906,877],{"class":120},[93,2908,2909,2911],{"class":95,"line":133},[93,2910,882],{"class":113},[93,2912,885],{"class":120},[93,2914,2915,2917],{"class":95,"line":142},[93,2916,890],{"class":113},[93,2918,893],{"class":120},[93,2920,2921],{"class":95,"line":399},[93,2922,898],{"class":120},[93,2924,2925,2927,2929,2931],{"class":95,"line":405},[93,2926,903],{"class":113},[93,2928,906],{"class":120},[93,2930,909],{"class":103},[93,2932,912],{"class":120},[93,2934,2935,2937],{"class":95,"line":410},[93,2936,917],{"class":113},[93,2938,893],{"class":120},[93,2940,2941],{"class":95,"line":416},[93,2942,924],{"class":120},[93,2944,2945,2947,2949,2951],{"class":95,"line":426},[93,2946,929],{"class":113},[93,2948,906],{"class":120},[93,2950,934],{"class":103},[93,2952,912],{"class":120},[93,2954,2955,2957,2959],{"class":95,"line":434},[93,2956,941],{"class":113},[93,2958,906],{"class":120},[93,2960,2961],{"class":103},"\"grep -r 'TODO' $CLAUDE_FILE_PATHS > \u002Ftmp\u002Fclaude-todos.log 2>&1\"\n",[93,2963,2964],{"class":95,"line":442},[93,2965,951],{"class":120},[93,2967,2968],{"class":95,"line":450},[93,2969,956],{"class":120},[93,2971,2972],{"class":95,"line":455},[93,2973,961],{"class":120},[93,2975,2976],{"class":95,"line":461},[93,2977,966],{"class":120},[93,2979,2980],{"class":95,"line":472},[93,2981,971],{"class":120},[93,2983,2984],{"class":95,"line":483},[93,2985,976],{"class":120},[11,2987,2988,2989,707],{},"Intended behavior: every time Claude edits or writes a file, log any TODOs in it to ",[90,2990,2991],{},"\u002Ftmp\u002Fclaude-todos.log",[11,2993,2994,2996],{},[34,2995,2716],{}," Make Claude edit a file containing a TODO. Verify the hook fired. If it didn't, figure out why, and fix it without looking at documentation.",[11,2998,2999],{},[34,3000,2725],{},[28,3002,3003,3016,3019],{},[31,3004,3005,3006,842,3009,842,3012,3015],{},"Only tools: ",[90,3007,3008],{},"\u002Fhooks",[90,3010,3011],{},"cat \u002Ftmp\u002Fclaude-todos.log",[90,3013,3014],{},"echo $CLAUDE_FILE_PATHS"," style debugging, the Claude session itself.",[31,3017,3018],{},"No Googling, no asking another Claude, no reading the hooks docs page.",[31,3020,3021],{},"When the hook works reliably for three edits in a row, you win.",[11,3023,3024,3026],{},[34,3025,2741],{}," Hooks fail silently by design. Debugging them is a recurring tax if you can't hold the mental model — what variables the hook sees, what shell it runs in, what the matcher actually matches. Fix one broken hook from scratch and that tax drops by half.",[11,3028,3029,3031,3032,707],{},[34,3030,60],{}," three consecutive edits each append a line to ",[90,3033,2991],{},[20,3035,3038,3044,3052,3057,3061,3076,3081,3146,3151],{"id":3036,"title":3037},"ch-routing","Challenge 5 — Model routing",[11,3039,3040,1183,3042,2705],{},[34,3041,287],{},[34,3043,291],{},[11,3045,3046,3048,3049,3051],{},[34,3047,2710],{}," Your current default model is probably Sonnet or Opus across the board. It shouldn't be. Different tasks want different models; picking per-task is the single easiest cost lever after ",[90,3050,299],{}," weight.",[11,3053,3054,3056],{},[34,3055,2716],{}," Establish a working routing policy for your next week — concrete rules for when you use Opus, when Sonnet, when Haiku — and commit it somewhere the whole team can see.",[11,3058,3059],{},[34,3060,2725],{},[28,3062,3063,3070,3073],{},[31,3064,3065,3066,3069],{},"The policy must be specific. \"Use Opus for hard things\" is not a policy. \"Use Opus for multi-file refactors across 5+ files ",[15,3067,3068],{},"or"," novel architecture decisions; Sonnet otherwise\" is.",[31,3071,3072],{},"It must fit on a sticky note.",[31,3074,3075],{},"You must be able to point to three past tasks and categorize each one under the policy unambiguously.",[11,3077,3078],{},[34,3079,3080],{},"A starting template — edit, don't adopt:",[83,3082,3084],{"className":375,"code":3083,"language":377,"meta":88,"style":88},"## Model routing\n\n- **Haiku** — classification, simple transforms, generating commit messages,\n  grepping through logs, any task where I know the answer shape in advance.\n- **Sonnet** — default. Feature work, code review, single-file edits,\n  most prompts.\n- **Opus** — architecture planning, debugging something I genuinely don't\n  understand, writing AGENTS.md \u002F multi-agent choreography, the\n  irreducibly-hard 5% of work.\n",[90,3085,3086,3091,3095,3106,3111,3121,3126,3136,3141],{"__ignoreMap":88},[93,3087,3088],{"class":95,"line":96},[93,3089,3090],{"class":384},"## Model routing\n",[93,3092,3093],{"class":95,"line":133},[93,3094,391],{"emptyLinePlaceholder":390},[93,3096,3097,3099,3103],{"class":95,"line":142},[93,3098,420],{"class":419},[93,3100,3102],{"class":3101},"sbYKK"," **Haiku**",[93,3104,3105],{"class":120}," — classification, simple transforms, generating commit messages,\n",[93,3107,3108],{"class":95,"line":399},[93,3109,3110],{"class":120},"  grepping through logs, any task where I know the answer shape in advance.\n",[93,3112,3113,3115,3118],{"class":95,"line":405},[93,3114,420],{"class":419},[93,3116,3117],{"class":3101}," **Sonnet**",[93,3119,3120],{"class":120}," — default. Feature work, code review, single-file edits,\n",[93,3122,3123],{"class":95,"line":410},[93,3124,3125],{"class":120},"  most prompts.\n",[93,3127,3128,3130,3133],{"class":95,"line":416},[93,3129,420],{"class":419},[93,3131,3132],{"class":3101}," **Opus**",[93,3134,3135],{"class":120}," — architecture planning, debugging something I genuinely don't\n",[93,3137,3138],{"class":95,"line":426},[93,3139,3140],{"class":120},"  understand, writing AGENTS.md \u002F multi-agent choreography, the\n",[93,3142,3143],{"class":95,"line":434},[93,3144,3145],{"class":120},"  irreducibly-hard 5% of work.\n",[11,3147,3148,3150],{},[34,3149,2741],{}," Model selection is a skill. The wrong model is either lighting money on fire (Opus on rote work) or burning time on rework (Sonnet on a task it can't plan). Getting this right compounds across every future session.",[11,3152,3153,3155],{},[34,3154,60],{}," your policy is written down, shared, and you can route three sample tasks through it without hesitation.",[20,3157,3160,3163,3167,3170,3192,3198,3202,3205,3235,3246,3250,3253,3258,3275,3280,3297,3305],{"id":3158,"title":3159},"tracks","Workshop tracks",[11,3161,3162],{},"The build-alongs and challenges can combine into longer programs when you want a structured day (or weekend) of work. Three tracks worth running.",[341,3164,3166],{"id":3165},"track-1-the-solo-up-skill-afternoon-34-hrs","Track 1 — The \"solo up-skill\" afternoon (3–4 hrs)",[11,3168,3169],{},"For the individual engineer who's been using Claude Code casually and wants to get serious without committing a whole week.",[345,3171,3172,3177,3182,3187],{},[31,3173,3174,3176],{},[34,3175,282],{}," (45 min) — the foundation everything else sits on.",[31,3178,3179,3181],{},[34,3180,654],{}," (45 min) — the workflow discipline.",[31,3183,3184,3186],{},[34,3185,810],{}," (40 min) — the guardrail layer.",[31,3188,3189,3191],{},[34,3190,2831],{}," (45 min) — the self-correction drill.",[11,3193,3194,3197],{},[34,3195,3196],{},"Outcome."," A repo that's been tuned, a workflow you've used deliberately, and one hard prompt you rewrote. You'll ship faster the next day.",[341,3199,3201],{"id":3200},"track-2-the-team-kickoff-day-67-hrs","Track 2 — The \"team kickoff\" day (6–7 hrs)",[11,3203,3204],{},"For a team rolling out Claude Code together. Pairs, whole-group debrief at the end of each block.",[345,3206,3207,3213,3223,3229],{},[31,3208,3209,3212],{},[34,3210,3211],{},"Morning (group)"," — Build 1 on the shared repo. One CLAUDE.md, co-authored. Review and merge before lunch.",[31,3214,3215,3218,3219,3222],{},[34,3216,3217],{},"Early afternoon (pairs)"," — Build 2. Everyone plans the ",[15,3220,3221],{},"same"," feature in parallel, then pairs compare plans. The differences are your CLAUDE.md's next draft.",[31,3224,3225,3228],{},[34,3226,3227],{},"Mid-afternoon (group)"," — Build 3. One hook for the team, one personal audit hook each.",[31,3230,3231,3234],{},[34,3232,3233],{},"End of day (group)"," — Challenge 1. Pick a task the whole team does weekly; run the cost-cut as a group exercise. The discussion is the value — who noticed what, what worked.",[11,3236,3237,3239,3240,3242,3243,3245],{},[34,3238,3196],{}," A shared ",[90,3241,299],{},", a committed ",[90,3244,828],{}," with hooks, and a team-wide cost baseline you'll measure against next month.",[341,3247,3249],{"id":3248},"track-3-the-advanced-retreat-weekend-1215-hrs","Track 3 — The \"advanced retreat\" weekend (12–15 hrs)",[11,3251,3252],{},"For engineers who've done the basics and want multi-agent, evals, and cost discipline in their bones. Two days.",[11,3254,3255],{},[34,3256,3257],{},"Day 1 — extensions and orchestration.",[345,3259,3260,3263,3266,3269,3272],{},[31,3261,3262],{},"Build 4 — Custom slash command (30 min).",[31,3264,3265],{},"Build 5 — MCP server (45 min).",[31,3267,3268],{},"Build 6 — 3-agent team (60 min).",[31,3270,3271],{},"Challenge 4 — Debug a broken hook (30 min).",[31,3273,3274],{},"Free time to extend the 3-agent team into an orchestrator-mode run.",[11,3276,3277],{},[34,3278,3279],{},"Day 2 — measurement and discipline.",[345,3281,3282,3285,3288,3291,3294],{},[31,3283,3284],{},"Build 7 — Eval suite (60 min).",[31,3286,3287],{},"Challenge 1 — Cost-cut 50% (60 min).",[31,3289,3290],{},"Challenge 2 — CLAUDE.md diet (45 min).",[31,3292,3293],{},"Challenge 5 — Model routing policy (30 min).",[31,3295,3296],{},"Retro: what changed, what's now your default, what's your next CLAUDE.md edit.",[11,3298,3299,3301,3302,3304],{},[34,3300,3196],{}," An ",[90,3303,1647],{}," you've actually run features through, an eval suite wired into CI, a routing policy, and roughly 40% lower token spend on repeat tasks. Two days well spent.",[75,3306,3309],{"title":3307,"variant":3308},"Tell us how the workshops go","info",[11,3310,3311],{},"These workshops evolve. If a build-along was too vague, a challenge was trivially easy, or a track didn't survive contact with real teams, that's the feedback loop this page lives on. File an issue on the repo, or rewrite the section yourself — pull requests are welcome.",[3313,3314,3315],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .surfw, html code.shiki .surfw{--shiki-default:#005CC5;--shiki-default-font-weight:bold}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html pre.shiki code .sEuWB, html code.shiki .sEuWB{--shiki-default:#032F62;--shiki-default-text-decoration:underline}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sbYKK, html code.shiki .sbYKK{--shiki-default:#24292E;--shiki-default-font-weight:bold}",{"title":88,"searchDepth":133,"depth":133,"links":3317},[3318,3319,3320,3321,3322,3323,3324,3325,3326,3327],{"id":343,"depth":142,"text":54},{"id":694,"depth":142,"text":54},{"id":857,"depth":142,"text":54},{"id":1214,"depth":142,"text":54},{"id":1496,"depth":142,"text":54},{"id":1671,"depth":142,"text":54},{"id":2130,"depth":142,"text":54},{"id":3165,"depth":142,"text":3166},{"id":3200,"depth":142,"text":3201},{"id":3248,"depth":142,"text":3249},"Hands-on practicals — guided build-alongs for every major Claude Code concept, plus timed challenges to sharpen your instincts.","Pick one, ~45 min each","md","Learn by doing","LucideGraduationCap",null,"2026-04-24",{},{"title":3337,"path":3338},"Cheatsheet","\u002Fcheatsheet","\u002Fworkshops",{"title":3341,"path":3342},"Resources","\u002Fresources",{"title":3344,"description":3345,"keywords":3346,"proficiencyLevel":3354,"timeRequired":3355},"Workshops — Hands-On Claude Code Practicals","Hands-on Claude Code workshops: seven guided build-alongs (CLAUDE.md, Plan Mode, hooks, commands, MCP, agent teams, evals) and five timed challenges. Learn by shipping, not by reading.",[3347,3348,3349,3350,3351,3352,3353],"claude code workshop","claude code exercises","claude code practicals","hands-on claude code","claude code build along","claude code challenges","claude code tutorial","Intermediate","PT45M",[3357,3358,3359,3360],{"id":22,"title":23,"level":133},{"id":154,"title":155,"level":133},{"id":2606,"title":2607,"level":133},{"id":3158,"title":3159,"level":133},"VpavkDAiYk2fMLo2XaATxWKx7dk1CZOxYFV84NhE5h0",1777109529374]