Skip to content
mdlake

Working with AI

How Claude Code builds on a generated site. Covers the ruleset in CLAUDE.md, the skills and when to use each, where they stop for your approval, the edit hook and AI usage reporting.

On this page

The builder is a plugin for Claude Code. It gives Claude the rules for your site and a set of skills for the jobs you repeat: planning, scaffolding, refreshing content, adding a page. This page explains how that works after the site exists, so that you know what Claude will and will not do on its own, and where it stops to ask you.

The principle is simple. Claude proposes and you approve. A skill never overwrites your work, never moves the content pin by itself and never commits a risky change without your answer.

The ruleset: CLAUDE.md

scaffold-site runs scaffold-ruleset.mjs, which writes the plugin’s ruleset into the site’s CLAUDE.md. If the site already has a CLAUDE.md, the script keeps your text and adds the ruleset at the end, once. It does not mark the ruleset with delimiters. It recognises it by the first line of the ruleset, and does not add it again to a file that has that line. The upgrade-ruleset skill replaces the ruleset section with the current one when you upgrade and keeps your own rules. Claude Code reads that file at the start of every session in the site folder, so the rules apply to every change, whether you use a skill or just ask.

The ruleset covers:

TopicWhat it says
StackAstro, React with TypeScript, Tailwind, react-aria-components. Static output by default.
ContentContent comes from the lake only. Never paste lake text into code. Bind documents by ID and lists by collection. Treat every optional field as possibly missing.
Content kindsRendered, shaped and generated, and when to use which. Generated copy has provenance and is never edited by hand.
plan.mdThe format of the plan and what the scripts parse.
Brief and designThe brief is the plan’s contract. design.md settles tone and tokens.
ComponentsReuse first. Tokens, no hard-coded colours or font sizes. Lucide icons only.
Required on every siteSEO, images, accessibility to WCAG 2.1 AA.
Never by defaultNo analytics, cookies or tracking unless the client asks. Forms only through the forms module.
Modes and lake.lockSnapshot and live, and how the lock moves.
Continuing developmentOwnership zones, adopt, typed access, the route snapshot, and the skills for your own work.
Hosting and server codeThe three tiers and where server code may live.
ProcessNever edit provenance.json by hand. Run npm run check before saying anything is done.

You can add your own rules to CLAUDE.md. The upgrade-ruleset skill replaces the ruleset section and keeps the site’s own rules. See Upgrade and migrate.

Ask in plain words, or call a skill

You can describe a job and Claude picks the skill, or you can call it by name. Skills of the plugin are called with the plugin name in front, for example /mdlake-builder:refresh-content.

/mdlake-builder:add-page

The skills and when to use them

SkillUse it toWhere it stops for you
check-lakeFind which lake content can fill a site type’s slots, before any planning. Use it first on a new site and when bindings change.It confirms the lake’s address with you.
plan-siteInterview you and write plan.md and design.md.It asks you to approve the plan and the design before it finishes.
scaffold-siteCreate the site from an approved plan and design.It refuses to start without an approved design.md.
regenerateChange one module, one page or one generated copy of a composed site.It stops when a file is adopted or locked, and shows what it would have changed.
refresh-contentMove a snapshot site to newer lake content.Before it moves lake.lock, and before it applies any fix.
generate-copyWrite copy from several documents, with provenance.At the sources and at the result.
add-pageAdd a hand-written route.Before it commits, when the ruleset asks for it.
add-componentAdd a site component or override a kit module.Before it commits, when the ruleset asks for it.
add-formAdd a contact form with the forms module.Before it commits. It switches the site to the server tier.
add-api-routeAdd a server route.Before the tier changes, and before it commits.
add-backendAdd a separate backend (Node or .NET).Before it moves routes, before it writes files, and before it commits.
setup-hostingWrite the pipelines and Bicep for the hosting tier.Before it commits.
upgrade-rulesetMove the site to a newer plugin version.Before it changes a locked file.
publishRun npm run check, commit and push to main, which deploys.It stops when no pipeline exists (it points to setup-hosting), when the check fails, and before the push, because a push to main deploys to production. There are no pull request previews.

Where the skills are described in detail:

Approval stops

A stop is a point where the skill shows you what it found or changed and waits. It does not go on until you answer. The main ones:

  • Plan and design. Nothing is scaffolded before you approve the plan and design.md.
  • Generated copy. You confirm the sources before any text is written. Then you review the result in npm run dev.
  • Content refresh. You see the content report, the route comparison and the check results, and you look at the site. Only then does the lock move.
  • Ownership. A skill that meets an adopted, locked or hand-edited file prints what it would have changed and exits with code 3. It does not decide for you, and it never runs adopt for you. See Ownership zones.
  • Hosting. Moving to the server tier, or to a split site, changes the cost and the hosting. The skill says so and waits.
  • Commits. A skill commits through commit-site.mjs with an explicit list of paths, and only after approval.

Claude Code has its own permission prompts for commands and file writes on top of these. The stops above are part of the skills.

What Claude may not do

The ruleset and the tools hold some lines whatever you ask:

  • Edit kit files. The edit hook below enforces it.
  • Edit provenance.json or lake.lock by hand. The scripts write them.
  • Edit the lake. Planning skills may read it, and nothing writes to it.
  • Hand-edit a generated copy file.
  • Paste lake text into code.
  • Add analytics, cookies or tracking scripts, unless the client asks.
  • Print or store your token.

The edit hook

The plugin installs a hook that runs before every Edit or Write in the site. It looks at provenance.json.

FileResult
Marked locked: trueBlocked. The message says to propose the change as a diff.
A kit file that you did not adoptBlocked. The message says to use an override in site.config.ts, or to adopt the file to keep a changed copy.
Anything elseAllowed.

A site with no provenance.json has nothing locked, and an unreadable manifest is reported by npm run check and does not block you. The hook only runs inside Claude Code. It does not stop you from editing a file in your own editor, but npm run check then reports a kit file that was edited by hand as an error.

Other hooks run at the start of a session. The ruleset check prints a one-line notice when the site is behind the plugin. See Upgrade and migrate. The usage reporter runs at session start, at the end of each turn and at the end of the session.

The lake in Claude’s reach

The plugin declares an MCP server called lake. With MDLAKE_API_URL and a token in .env, Claude can search and read documents as the CMS has them now. Planning skills use it to find content.

The MCP server is for looking. A build, the plan commit, the provenance of generated copy and lake.lock come from the lake clone only. A document ID that only the MCP shows is not bound until refresh-content brings it into the clone.

Use a token with the access Published content for this. A token with drafts is for previews. See Workspace tokens.

AI usage reporting

The workspace can count the AI work that happens in its sites. A hook reports the token counts of Claude Code sessions in the site folder to the CMS. It reports counts only: never prompts, answers, file names or paths. The numbers come from Claude Code’s own session record, so they are what the API billed, and the model is never asked to report anything.

Turn it on

  1. In the CMS, create a token with the checkbox Can report AI usage. See Workspace tokens.
  2. Put these in the site’s .env:
MDLAKE_API_URL=https://cms.example.com/api/lake/acme
MDLAKE_TOKEN=mdl_...

The hook then reports at session start, at the end of each turn and at the end of the session. It runs only in a site (a folder with .mdlake/ruleset.json) whose .env has both values.

Turn it off

Set MDLAKE_USAGE_REPORT=0 in the environment or in .env.

See the state

PowerShell
npx mdlake usage

It shows where it reports to, what was reported, what is queued, and whether the token is blocked. To send the queue now:

PowerShell
npx mdlake usage --flush

How it behaves

  • Exactly once. Each record has a stable ID, and the CMS ignores one it already knows. Repeated hook runs, retries and resumed sessions cannot count anything twice.
  • Never in the way. A request times out after a short wait and the hook always lets Claude Code go on. When the CMS cannot be reached, the records wait in .mdlake/usage-queue.jsonl and go out with the next run.
  • A token without permission. The CMS answers 403. The hook stops trying and prints one line: “This token can’t report AI usage; create one with ‘Can report AI usage’ in the CMS.” The records are kept and sent once you replace the token.
  • Plain http is refused, except to localhost.
  • The token is never printed or stored by the hook.
  • State files are in .mdlake/: usage-state.json, usage-queue.jsonl and usage.lock. They are ignored by Git. Do not read or edit them, and do not ask Claude to.

Limits

  • A session that is killed before its last turn ends (a crash, a closed terminal) loses the usage after the last report.
  • Usage outside the site folder is not seen. Neither is the Claude app’s own use or the work of other plugins’ agents.

What can go wrong

SymptomCause and fix
Claude says a file is a kit file and will not edit itIt is. Ask for an override in site.config.ts, or adopt the file if it is a generated one.
A skill printed “NOT WRITTEN” and stoppedThe file is adopted, locked or hand-edited. Read the summary and decide. See Ownership zones.
No skills appearThe plugin is not installed or not reloaded. See Install the builder.
A notice says the site is behind the pluginRun upgrade-ruleset.
npx mdlake usage says reporting is offMDLAKE_API_URL or MDLAKE_TOKEN is missing, or MDLAKE_USAGE_REPORT=0.
The usage line says the token can’t reportCreate a token with Can report AI usage and put it in .env.
Usage looks too lowSessions outside the site folder and killed sessions are not counted.

What’s next

  • Skills for the reference list.
  • Workspace tokens for creating the tokens that the hook and the MCP server use.