<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title id="root">The lock file: vibe.lock</title>
  <status stage="doc" state="work" audience="user"/>
  <p p="1">`vibe.lock` is the file vibe writes and you commit: the exact versions the project got. This page explains every field so you can read a diff of it in a pull request and know what changed.</p>
  <section id="where" title="Where it lives and who writes it">
    <p p="2">There is one `vibe.lock` per workspace, at the absolute root, beside the root [manifest](../glossary/index.xml#manifest); members never have their own. `vibe install` and `vibe update` write it; `vibe clean` keeps it; nothing edits it by hand. It is the recorded decision; the dependency tree on disk is only its consequence and can always be rebuilt from it.</p>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-007#NESTING-PRINCIPLE" p="3"/>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-053#CLEAN-KEEPS-THE-LOCK" p="4"/>
  </section>
  <section id="meta" title="[meta]">
    <table p="5">
      <tr>
        <td>Field</td>
        <td>Meaning</td>
      </tr>
      <tr>
        <td>`generated_by`, `generated_at`</td>
        <td>the vibe version and the time of the last write; informational</td>
      </tr>
      <tr>
        <td>`schema_version`</td>
        <td>the lock schema; an older vibe refuses a newer schema rather than misreading it</td>
      </tr>
      <tr>
        <td>`solver`</td>
        <td>the resolver that produced the graph</td>
      </tr>
      <tr>
        <td>`root_dependencies`</td>
        <td>the coordinates the manifests asked for directly; the baseline of the freshness check</td>
      </tr>
      <tr>
        <td>`language_chain`</td>
        <td>the resolved language preference and its fallbacks, so a re-install on another machine materialises the same files</td>
      </tr>
    </table>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-011#NO-NEW-FIELD" p="6"/>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-resolver/PROP-003#LF-META-LANGUAGE" p="7"/>
    <p p="8">`root_dependencies` copies the manifest's `[requires.packages]`, so the [lock file](../glossary/index.xml#lock-file) is a self-contained snapshot that needs no manifest to read. Removing a root with `vibe uninstall` drops it from both files; removing a package that is only a transitive dependency is refused with an explanation.</p>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#LOCKFILE-V2" p="9"/>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#LF-ROOT-DEPENDENCIES" p="10"/>
  </section>
  <section id="package-entries" title="[[package]]">
    <table p="11">
      <tr>
        <td>Field</td>
        <td>Meaning</td>
      </tr>
      <tr>
        <td>`group`, `name`, `version`</td>
        <td>the coordinate that was resolved</td>
      </tr>
      <tr>
        <td>`kind`</td>
        <td>the package's kind, for placement and filters</td>
      </tr>
      <tr>
        <td>`content_hash`</td>
        <td>the fingerprint of the package's shippable tree; the identity; verified on every fetch</td>
      </tr>
      <tr>
        <td>`registry`</td>
        <td>the name of the registry that answered, from the manifest's list</td>
      </tr>
      <tr>
        <td>`source_url`, `source_ref`, `resolved_commit`</td>
        <td>where and at what git ref the bytes were fetched this time; informational, always the canonical address even when a mirror served</td>
      </tr>
      <tr>
        <td>`source_kind`</td>
        <td>`registry`, `git`, `override` or `path`: which resolution path produced the entry; for `path` the URL field holds the member's folder relative to the root</td>
      </tr>
      <tr>
        <td>`dependencies`</td>
        <td>the resolved dependencies of this package, as exact coordinates</td>
      </tr>
      <tr>
        <td>`overridden`</td>
        <td>true when an `[[override]]` supplied the package</td>
      </tr>
      <tr>
        <td>`features`, `subskills`</td>
        <td>the active features and subskills recorded for the package</td>
      </tr>
      <tr>
        <td>`files_written`</td>
        <td>the project files this package's install wrote outside its own folder, so that uninstall can remove exactly them</td>
      </tr>
      <tr>
        <td>`via_redirect`</td>
        <td>the address of the registry stub that delegated the package elsewhere, when one was followed; absent otherwise</td>
      </tr>
    </table>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#IDENTITY-TUPLE" p="12"/>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#SOURCE-KIND-VALUES" p="13"/>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#MIR-CANONICAL-IN-LOCKFILE" p="14"/>
  </section>
  <section id="reading-a-diff" title="Reading a diff">
    <p p="15">A changed `version` with a changed `content_hash` is an update. A changed `content_hash` with the same version is impossible in a healthy world: vibe refuses it at fetch time, so if you see it in a diff someone edited the file. A changed `source_url` alone is a [mirror](../glossary/index.xml#mirror) or a host migration and means nothing for the project. A new entry with `source_kind = "override"` is a patch someone applied on purpose and should carry a reason in the commit message.</p>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#EFF-LOCKFILE-STABLE" p="16"/>
  </section>
  <section id="edge-cases" title="Edge cases and rules">
    <p p="17">An unchanged manifest against an unchanged [lock file](../glossary/index.xml#lock-file) makes `vibe install` skip the resolver entirely: the lock is the answer.</p>
    <rule ref="spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-011#LOCKFILE-RESPECTING" p="18"/>
    <p p="19">The lock file records no [registry](../glossary/index.xml#registry) [index](../glossary/index.xml#index-registry) and no mirror: reproducing it needs only the [coordinates](../glossary/index.xml#coordinate), the [fingerprints](../glossary/index.xml#fingerprint) and a source that can serve them.</p>
    <p p="20">`vibe why &lt;coordinate&gt;` explains from the lock file and the manifests why a package is in the project, or what blocked it.</p>
    <p p="21">The file is read strictly: a field vibe does not know is an error, not a warning, so a hand edit or a field from a newer vibe is caught at once.</p>
  </section>
</spec>
