Skip to content
mdlake

Ownership zones

Which files in a generated site belong to the kit, which are generated and which are yours. Covers provenance.json, npx mdlake ownership, adopt, check-ownership and what the tools refuse to overwrite.

On this page

A generated site is a starting point. You keep building on it, by hand or with Claude Code. For that to be safe, every tool that writes files must know which files are yours. Each file in a site is in one of three zones, and a manifest, provenance.json, records the files the tools wrote.

The rule behind it is that no skill or script may overwrite your work. A tool that is not allowed to write a file prints what it would have changed and stops, so you can decide.

The three zones

ZoneFilesWho writes themIf you edit one by hand
KitThe vendored packages in vendor/*.tgz, everything in .mdlake/ (such as ruleset.json, generate-jobs.json and hosting.json), lake.lock, builder.json, site-snapshot.jsonTools onlynpm run check fails with an error
Generatedlake.config.ts (its defineLake call), src/pages.config.ts, src/content/generated/*; the hosting files .github/workflows/deploy.yml, azure-pipelines.yml, infra/main.bicep and infra/modules/*.bicep; the typed API client src/api/generated/*plan-to-config, write-generated, regenerate, hosting init, api generatenpm run check warns
SiteEverything else: src/pages, your components, styles, site.config.ts, api/, infra/parameters/*.bicepparamYouNothing. refresh-content, regenerate and upgrade-ruleset never touch it

A few files are mixed. They are yours, but the tools edit them in declared places: package.json, package-lock.json, .gitignore, .env.example, CLAUDE.md, src/env.d.ts, src/styles/global.css, tsconfig.json and, in a site with a Node backend, api/package.json (the kit keeps its two kit-package entries current). A tool adds a dependency, an ignore line, the theme block of src/styles/global.css or the ruleset section of CLAUDE.md. It does not rewrite the rest.

For lake.config.ts only the defineLake({ ... }) call counts. The siteTypeSlots export next to it is edited by hand, and a change there is not drift.

Why kit files are locked

The kit is code that the tools keep consistent with each other: the version of the packages, the lock, the ruleset record. A hand edit would be lost in the next upgrade or, worse, would break the build in a way that nobody can trace. To change what the kit does, override a component in site.config.ts. See Custom components.

The plugin’s edit hook enforces this inside Claude Code. It blocks Edit and Write on kit files and on any file marked locked. The message points to the override in site.config.ts and to npx mdlake adopt.

provenance.json

provenance.json is the ownership manifest. The scripts write it and you never edit it by hand. It is committed.

JSON
{
  "version": 2,
  "files": {
    "lake.config.ts": {
      "zone": "generated",
      "hash": "71f8dd4a1df33b04bc19c8fd859d10492d91f10258c946315117aadc289455f2",
      "writer": "plan-to-config"
    },
    "src/pages.config.ts": {
      "zone": "site",
      "hash": "1598b4c2a843006a071a35594b6d29151451e13c87bd1a1942ab6cf51d7b15de",
      "adoptedFrom": "generated",
      "adoptedAt": "2026-10-20T08:12:44.000Z"
    }
  }
}
FieldMeaning
zonekit, generated or site.
hashA SHA-256 of what the tool last wrote. Text is hashed without a byte order mark and with line endings normalised, so Windows and Linux agree.
writerThe tool that wrote it last, such as plan-to-config, write-generated, regenerate, migrate or scaffold.
lockedtrue means no tool writes the file and the edit hook refuses edits to it, whatever its zone. You set this by hand.
adoptedFrom, adoptedAtSet when a generated file was adopted. An adopted file has zone site.

A file with no entry has the zone that its location gives it: kit and generated files as listed above, and site for anything else. Keys are sorted, so a Git diff shows only what changed. Older sites have a bare map, { "<path>": { "locked": true } }. It is still read, and its locked flags are kept.

See the zones: npx mdlake ownership

PowerShell
npx mdlake ownership

It lists the kit and generated files with their state, then the site files.

kit       12 files  (written by tools: never edit by hand)
  ok         builder.json
  ok         lake.lock
generated 4 files  (written by skills from plan.md and the lake: adopt to edit by hand)
  ok         lake.config.ts
  EDITED     src/pages.config.ts  adopt it: npx mdlake adopt src/pages.config.ts
site      9 files under src/, 1 adopted from the generated zone  (yours: the kit never writes there)
  adopted    src/content/generated/home-hero.md  (changed since it was adopted)
  (npx mdlake ownership --all lists them)
StateMeaning
okThe file is as the tool wrote it.
EDITEDIt differs from the recorded hash.
MISSINGIt is recorded but not on disk.
unrecordedThe tool may have written it, but the manifest does not say so.
adoptedYou adopted it.

A kit or generated file whose manifest entry has no hash is unrecorded, so it is never silently skipped. npx mdlake ownership lists it and check-ownership warns that it “is not recorded as written by the kit”. Adopt it, regenerate it or run npx mdlake migrate --trust-generated.

OptionMeaning
--allAlso list the site-owned files under src/.
--jsonMachine-readable output.

When provenance.json has no zones yet, the command says so and tells you to run npx mdlake migrate, which records them without overwriting anything.

Adopt a file: npx mdlake adopt

Adopting turns a generated file into a site file. After that, the kit never writes it again. Use it when you want to edit a generated file by hand and keep the edit.

PowerShell
npx mdlake adopt src/pages.config.ts
npx mdlake adopt lake.config.ts src/content/generated/home-hero.md
npx mdlake adopt --edited
FormMeaning
adopt <file>...Adopts the listed files.
adopt --editedAdopts every generated file that was edited by hand or is not recorded.

What happens:

  • The manifest entry becomes zone site, with adoptedFrom: generated, a time and a hash of the file as it is now.
  • Each file prints adopted <file>: it is site-owned now. regenerate, refresh-content and upgrade-ruleset will not write it; they print what they would have changed instead.
  • A kit file is refused: “is kit-owned and cannot be adopted. To change what the kit renders, register your own component in site.config.ts.”
  • A file that is a site file already is refused: “there is nothing to adopt.”
  • A file that does not exist is refused. The command exits with 1 when any file is refused.

Adopt does not move the file, and there is no command to undo it.

Important

Adopting src/pages.config.ts or lake.config.ts means plan.md no longer drives them. After that, keep plan.md in step by hand, or stop treating it as the source. Do not adopt a file for someone else without asking. Skills must not do it for you either.

Typical cases:

You want toDo this
Add a nav link or change a heading in src/pages.config.tsEdit plan.md and run plan-to-config.mjs. Or edit the file, run npx mdlake adopt src/pages.config.ts, and keep plan.md in step.
Bind a new document in lake.config.tsAdd it to the plan, or edit the file and adopt it.
Keep a hand-polished generated headlinenpx mdlake adopt src/content/generated/<key>.md.
Use a hand-adapted pipelineAdopt .github/workflows/deploy.yml or azure-pipelines.yml. hosting init then leaves it alone.
Change how a kit module looksDo not adopt. Override the component in site.config.ts.

What the checks say

npm run check includes check:ownership (mdlake check-ownership).

SituationResult
A kit file was editedError. The message says to revert it (git checkout <file>) and to use site.config.ts instead.
A kit file is missingError. Restore it or run the upgrade-ruleset skill.
A generated file was edited, not adoptedWarning. Adopt it to keep your version, or regenerate it.
A generated file is not recordedWarning. Same advice.
A file is adoptedA note: “is site-owned (adopted from generated).”
site-snapshot.json is missing or older than lake.lockWarning. Run npx mdlake snapshot after a build.
.mdlake/types/lake.d.ts is missingWarning. mdlake prepare writes it.

The last line is a summary such as Ownership: 14 files as the kit wrote them, 1 adopted, 0 errors, 1 warnings. It exits 1 when there is an error. The warnings do not fail the check, but do not leave them. A warning on a generated file is a decision waiting for you.

What the tools refuse

Every kit writer writes through one guarded function: scaffold-ruleset, vendor-packages, plan-to-config, write-generated, write-lake-lock, apply-design, commit-site, migrate, snapshot, hosting init and the others. It refuses to write a file when:

ReasonMeaning
adoptedYou adopted it.
lockedprovenance.json marks it locked.
siteIt is site-owned. The kit does not write there.
editedIt is generated, and it was edited by hand after the kit wrote it.
unrecordedIt exists, its content differs, and the manifest does not say the kit wrote it.
existsA tool that may only create a file found one.

A refusal prints the file, the reason and a summary of what would have changed, with the first lines of the difference. Scripts then exit with code 3. The migration prints the same as a refused note.

NOT WRITTEN src/pages.config.ts (edited): src/pages.config.ts was edited by hand after the kit wrote it. Adopt it to keep your version (npx mdlake adopt src/pages.config.ts), or overwrite it to regenerate.
  would change src/pages.config.ts: 3 lines added, 1 removed (first change at line 14)
    - { label: 'Cases', href: '/cases/' },
    + { label: 'Customers', href: '/customers/' },

When a skill sees exit code 3 it shows you that summary and stops. It does not decide for you. You can keep the file as it is, adopt it, or regenerate it.

To regenerate a file that was edited but not adopted, run the script again with --overwrite (plan-to-config.mjs, write-generated.mjs). --overwrite never overrides an adopted file. Your edits in the old file are lost, so look at the summary first.

A legacy provenance.json (from before 0.16, a plain map) is left alone by every plugin script that writes a file, such as vendor-packages.mjs and write-lake-lock.mjs. The script writes its file and leaves provenance.json byte for byte as it was. Only npx mdlake migrate converts it. Until then check-ownership warns “no ownership zones yet: run npx mdlake migrate”, the locked flags of the old file are still honoured, and npx mdlake adopt refuses to run on a legacy manifest.

What can go wrong

SymptomCause and fix
check-ownership error: “is kit-owned but was edited by hand”You or a tool changed a vendored package, lake.lock or a .mdlake file. Revert it with git checkout <file>.
Exit code 3 from a scriptA protected file. Read the summary. Keep, adopt or --overwrite.
adopt says the file is kit-ownedKit files cannot be adopted. Override the component in site.config.ts.
A skill did not change a file you expectedThe file is adopted or locked. The skill printed what it would have changed.
provenance.json has no ownership zones yetAn old site. Run npx mdlake migrate.

What’s next