The Claude Code setup that actually works for weekend builds
We run Claude Code inside a Linux sandbox for thousands of weekend builds. Every config we shipped that was clever got rolled back. The boring config that survived is six lines of settings.json, two CLAUDE.md files, three MCP servers, and a list of four files Claude is told never to touch. Here it is verbatim. Steal it.
The setup that works on Saturday afternoon, when you have four hours and you do not want to babysit a permission dialog: settings.json with defaultMode: "acceptEdits", a project CLAUDE.md that names the load-bearing files Claude must not modify, and a single Playwright MCP so Claude verifies the DOM before reporting done. The whole thing fits in this article.
Verified by reading mk0r's sandbox config at src/core/vm-claude-md.ts (lines 21, 321 to 331, 340 to 381, 1142 to 1244) and src/core/e2b.ts (lines 170 to 213).
The whole config, on one tree
Before the long version, here is the file layout. Two CLAUDE.md files. One settings.json. Three skill folders. That is the entire surface. If your current Claude Code setup has more files than this, the extra files are probably hurting you, not helping you.
The settings.json that does the heavy lifting
The full settings.json is six lines. The only field that matters is permissions.defaultMode set to acceptEdits. That single line is the difference between Claude Code feeling like a partner on a weekend build and feeling like a paranoid intern who interrupts you every 90 seconds for written approval.
What it does. File edits land without a permission dialog. Bash commands still prompt when they could touch outside the working tree (rm, curl piped to a shell, anything that writes to /etc), so the dangerous category still gets human approval. The shape of the prompt cadence flips: instead of one approval per write, you only see prompts when Claude wants to do something that could affect the host.
Why we tried richer settings and rolled them back. We shipped a version with custom allow rules per command. We shipped a version with file-path scope rules. We shipped a version that auto-denied anything outside /app. Every one of those got rolled back because the cost of being right (a few avoided shell prompts) was lower than the cost of being wrong (Claude getting blocked on an obvious-in-hindsight edit and the user wondering why their feature stopped working halfway through prompt three). The minimal config wins because the model is already good at picking which moves matter.
If you are not in a sandbox, this exact same field still works on a laptop. You are the sandbox. The blast radius of a bad edit is your working tree, which lives in git. git stash is a perfectly fine recovery primitive.
“Lines in the settings.json. Every clever permission rule we tried to add got reverted within a week.”
src/core/vm-claude-md.ts:323-331
The project CLAUDE.md (the one Claude reads at the start of every session)
The project CLAUDE.md is the file most weekend setups skip. It is also the file that pays off the fastest. The job of this file is to tell Claude what is load-bearing and what is open for editing. Get this right and the model stops trying to be helpful in places it should leave alone.
The full file is around 100 lines. The four lines that pay rent are the "do not modify" list. vite.config.ts, src/main.tsx, src/_mk0rBridge.ts, src/index.css. Without this list, Claude will eventually get clever and reorganize one of them on a turn that was supposed to be about a button.
The second high-value piece is the mount rule: every new component must be imported in src/App.tsx. Without that rule written down, you get the most confusing failure mode in a weekend build, a feature where Claude wrote a beautiful component, the file is on disk, the dev server compiles cleanly, and nothing changes on the page. The component never got mounted. One sentence in CLAUDE.md prevents that for the rest of the session.
The third piece is styling rules: Tailwind v4 (which uses @import "tailwindcss", not v3's @tailwind base), three-color palette, no decorative icons. These exist because models will, in the absence of a specific style guide, default toward 2022-era purple gradients on Inter. CLAUDE.md is where you head that off once and never deal with it again.
The system prompt is three sentences. On purpose.
Most setup guides treat the system prompt as the place to write your "voice and tone" novella. That is the wrong file. System prompts are sticky, they live in code, they require a redeploy to change. CLAUDE.md is plain text in the working tree. It re-reads on every session start. It is the right place for everything substantive.
The system prompt covers exactly four things: role identity, working directory, dev server URL, what tools are available. Then it says "read your CLAUDE.md files" and gets out of the way. If you are tempted to write a long system prompt because you do not have CLAUDE.md yet, write CLAUDE.md instead. You will be glad you did the first time you want to change a coding rule mid-session without restarting Claude.
The MCP servers (Playwright is the one that pays off the fastest)
Three MCP servers run alongside the agent. Only one of them is essential for a weekend build, and that is Playwright. The other two are workflow extensions, useful but droppable.
Playwright MCP is what closes the loop on whether a change actually worked. After Claude writes a component, it runs browser_navigateagainst the dev server, takes a snapshot, and reads the DOM. If the form is not on the page, Claude knows it. If a console error fired, Claude reads it. The accuracy gain over "the file compiled, ship it" is the single biggest reason Claude Code feels good on a weekend build instead of feeling like you are debugging the agent.
Scheduler MCP is for the projects that need recurring work: a daily digest email, a periodic scrape, a Sunday-night data refresh. Standard 5-field cron, runs inside the same sandbox the agent edits in. You can drop this on a laptop setup; replace it with a launchd plist or systemd timer when you actually need scheduling.
mk0r-provisioning MCP is the lazy backend. When the user asks for email or persistence, the agent calls provision_email_audience() or provision_database(), which writes the env vars into /app/.env. On a laptop you would replace this with a personal Resend key and a local Postgres. The pattern (provision on demand, write to .env, restart the dev server, integrate) is the part worth stealing even if you swap out the implementation.
What happens on one prompt
Prompt arrives
User types: "add a contact form"
CLAUDE.md loads
Global + project rules pinned to context
Skill activates
backend-services matches "email" trigger
MCP provisions
Resend audience + API key written to /app/.env
Edits land
acceptEdits = no permission prompt per file
Playwright verifies
Real Chromium hits localhost:5173, asserts DOM
What it actually looks like when a turn runs
Concrete trace of what a single "add a contact form" turn looks like with this config. The agent is reading CLAUDE.md, picking the matching skill, calling the matching MCP, editing files, then running Playwright to verify, all without prompting the user.
This is the specific experience the six-line settings.json buys you. Without acceptEdits, the agent stops after step one and asks "may I edit src/components/ContactForm.tsx?" You answer yes, it stops again to ask about src/App.tsx, you answer yes, and so on. The turn balloons from a few seconds of focused work into a multi-minute approval drill. On a weekend build, that is the difference between shipping by Sunday and not shipping.
Three skills, all global
The three SKILL.md files in /root/.claude/skills/ are how Claude Code picks the right tool for the right phrase. Each skill has frontmatter with a description; Claude scans the descriptions on session start and matches them against incoming prompts. Concretely:
- frontend-designactivates when the user asks to build a component, page, or UI. It forces a step before code, "commit to an aesthetic direction", that pushes the model away from the default purple-gradient look. This is also the skill that bans Inter and Roboto in favor of distinctive Google Fonts pairings.
- copywritingactivates on any "write copy for" or "rewrite this" request. It enforces the obvious-but-easily-missed rules: clarity over cleverness, benefits over features, customer language over company language. On a weekend build, this is the skill that prevents the "Empower your workflow" landing page from happening.
- backend-servicesactivates on database, email, analytics, or auth requests. It is what wires the user's ask for "a contact form that emails me" to the actual provisioning call, then to the integration code that reads the freshly-written env vars.
Three is enough. We tried more. The hit rate per skill goes down sharply past the third, because the model is already good at the broader cases without a skill. Skills earn their keep when there is a specific failure mode worth pinning down: generic AI aesthetics, vague marketing copy, "but where do these env vars come from" provisioning confusion.
Drop-in for a laptop weekend build
If you want this exact setup on a laptop on Saturday morning, here is the short version, no sandbox required:
- Create
~/.claude/settings.jsonwith the six lines above. That is the whole file. - Create
~/.claude/CLAUDE.mdwith your global rules: how you want memory used, how you want corrections handled, your design defaults. Roughly 50 to 200 lines depending on how opinionated you are. - In the project root, create
CLAUDE.mdwith the do-not-modify list, the mount rule, and the styling rules for that project. 30 to 80 lines. - Add Playwright MCP to your Claude Code config. Point it at your local Chrome. Drop the scheduler and provisioning MCPs unless you need them; you do not.
- Optional: drop
frontend-design,copywriting, orbackend-servicesSKILL.md files into~/.claude/skills/. Or write your own. The pattern is name + frontmatter description + body. - Run
claudein the project. The first turn will tell you whether the config is doing what you wanted: edits should land without prompting, the agent should know the file rules, Playwright should fire after the change.
If you skip the project CLAUDE.md, you will hit the "component on disk but never mounted" failure mode within an hour. If you skip Playwright, you will be the one verifying every change. If you skip acceptEdits, you will give up by 3pm Saturday. The other pieces are nice. These three are load-bearing.
The honest counterpoint
defaultMode: "acceptEdits" is the right default in a sandbox. It is the wrong default if you are running Claude Code against a production codebase you ship to paying customers without a CI gate. In that environment, the cost of a bad edit is real, the recovery is more than git stash, and the time you save by skipping prompts is dwarfed by the time you spend untangling a regression.
The right framing is: this is the weekend-build config. Disposable working tree, fast feedback, low cost of a mistake. If you are using Claude Code to ship a real release on Monday morning, dial the permissions back up, add a pre-commit hook that runs the typechecker and tests, and treat the agent more like a colleague than a demo.
The setup in this article is for the four-hour Saturday window where you have an idea and you want it running. Use the right tool for the right context.
Want to see this exact Claude Code setup running on your weekend project?
Bring an idea you have been sitting on. We'll walk through the working setup live, settings.json to Playwright verification, on whatever shape your project is.
Frequently asked questions
What is the single most important line in this entire setup?
permissions.defaultMode = "acceptEdits" in settings.json. That one field changes Claude Code from a tool that asks permission for every edit (which makes a weekend build feel like filling out a tax form) into a tool that edits files and only stops for genuinely scary commands like rm -rf or curl piped to bash. The whole config is six lines because that one line is doing the work. We tried richer settings, more permission rules, allow lists, deny lists. They all got reverted. The behavior we wanted from Claude Code on weekend builds is: trust the model, sandbox the blast radius, let it edit. acceptEdits gives you that, with the kernel sandbox doing the safety lifting.
Why are the project CLAUDE.md and the global CLAUDE.md two separate files?
Because they answer two different questions. The global file (/root/.claude/CLAUDE.md) is about Claude itself: how to use memory, how to handle corrections, how to think about design. It is identical across every weekend project we ship and gets reused. The project file (/app/CLAUDE.md) is about this specific working tree: which files are load-bearing infra (vite.config.ts, src/main.tsx, src/_mk0rBridge.ts, src/index.css), where new components mount (src/App.tsx), and which Tailwind version is installed (v4, which uses @import "tailwindcss" not v3's @tailwind base). Putting project specifics in the global file is how you end up with Claude trying to edit vite.config.ts on a fresh weekend repo because some prior project had a comment about it.
Do you really need all three MCP servers, or is Playwright enough?
Playwright is the one that pays off the fastest and the one we would never ship without. It is what makes Claude Code stop guessing whether the change worked. It opens the dev server in a real Chromium, takes a snapshot, asserts the DOM. That is the single biggest accuracy win on this setup. The scheduler and mk0r-provisioning MCPs are for slightly later in a build's life: scheduling a recurring job, or lazily provisioning Resend or a Neon Postgres database when the user asks for email or persistence. If you are running this on your laptop for a single weekend project, you can drop both. The settings.json + CLAUDE.md + Playwright MCP combo is the minimum viable working setup.
Why do skills go inside ~/.claude/skills/ and not in the project?
Discovery. Claude Code scans /root/.claude/skills/ on startup, parses the description field in each SKILL.md frontmatter, and matches against incoming user prompts. A skill in the global location is available across every project. A skill scoped to one project rarely earns its keep, because by the time you have written one, you have probably noticed the same pattern in two more projects. Our three skills (frontend-design, copywriting, backend-services) all live globally for that reason. The project CLAUDE.md exists to describe the project. The skills exist to describe Claude's reflexes.
What does the system prompt do, given that the CLAUDE.md files exist?
Almost nothing, on purpose. The system prompt is three sentences in src/core/e2b.ts (line 170): role identity, working directory, available tools. Everything substantive (workflow, code quality, styling rules, file-path knowledge) lives in the two CLAUDE.md files. We learned to keep the system prompt minimal because system prompts are sticky, version-controlled with the code, and a pain to edit at runtime. CLAUDE.md is text in a regular file. It is read fresh at the start of every session, you can change it without redeploying, and a contributor can read it without grepping the source. If you have ever debugged a weird AI behavior by chasing a stale string in a Python file three packages deep, you know why this matters.
Will this work outside the mk0r sandbox, on a normal laptop?
Yes, with two adjustments. First, the MCPs that point at /opt/scheduler-mcp.js and /opt/provisioning-mcp.js are mk0r-internal, drop them. Keep the Playwright MCP and point it at whatever Chrome you have installed (the env var PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH is what to change). Second, the project CLAUDE.md mentions src/_mk0rBridge.ts which only matters if your build runs inside our HMR proxy. If you are on plain Vite locally, delete those lines. Everything else, the settings.json, the global CLAUDE.md content, the three skills, the four-files-do-not-modify pattern, ports cleanly to a laptop weekend build.
More on running Claude Code without it running you
Keep going
The Claude Weekly Cap Workflow: A 5-Step Playbook for Pro and Max
Five steps that fit inside a 7-day window: route, batch, OAuth, read the resetsAt epoch, buy extra only when it actually matters.
Build an Anthropic Claude App Without Code (Real-Browser Finish Line)
Inside an E2B sandbox, Claude drives a real Chromium via Playwright MCP and verifies the DOM before reporting done.
The Weekend Project Single-File HTML Playbook (Ship by Sunday)
One self-contained HTML file is the only weekend-project shape that actually ships. Eight ideas for the 48-hour clock.