Skip to content
oleks crane
Open-source libraryIn use

Pin your docs to the truth so they can’t drift.

Yakir — Ukrainian for anchor — is a drift-prevention framework: it tracks every place the same fact lives across code, docs and generated files, and reconciles them when one changes. It’s for anyone maintaining a repository, or a monorepo, where the same version, API name or measured number is quoted in more than one place.

  • 53

    tests passing

  • 0

    runtime dependencies

  • 2/5

    roadmap milestones shipped

{  "id": "package-version",  "tier": "token",  "policy": { "severity": "block", "mode": "auto" },  "sites": [    { "artifact": "package.json", "locator": { "kind": "json-pointer", "path": "/version" }, "write": "manual" },    { "artifact": "README.md",    "locator": { "kind": "region", "name": "version" },         "write": "managed" }  ]}

At a glance

Type
My own open-source library
Scope
Everything: the tether/site/fingerprint engine, the check/fix/accept/init/discover CLI, and the test suite — dogfooded against StitchAPI, another of my projects.
Status
In use — in StitchAPI’s repo, not released publicly · as of 24 Sep 2026
Timeline

Started Jun 2026 · not released yet

Platforms
Node.js 18+
Try it
Not on npm yet — the CLI runs from a clone of the repo.
Stack
TypeScriptNode.jsesbuildVitestpnpm

The challenge

The same fact often lives in more than one artefact — a version number, an API option name, a generated file — with no live binding between the copies. Each one is edited or regenerated on its own, so they drift apart quietly. Worse, you can’t continuously prove that two prose artefacts still agree; the best you can do is notice the moment one of them changes.

  • A release moves the version in package.json; nothing forces the README badge to move with it.
  • An API option gets renamed in the source; three doc pages and a blog post keep the old name.
  • A generated file like llms.txt quietly falls behind the source it was generated from.
  • You can’t continuously prove that two prose artefacts still agree — only notice the moment one of them changes.
  • Two sites can each drift to a different new value, and nothing says which one is now true.

The constraints

A few limits here are deliberate, not accidental: yakir never runs code it wasn’t told to, never writes into a site that hasn’t earned that trust, and — in v1 — watches one repository at a time.

  • Zero runtime dependencies — the engine has to stay small and embeddable.
  • A command site runs arbitrary shell, so it’s declared-only: discover never proposes or runs one.
  • Every site defaults to manual (read-only); it only becomes managed — auto-writable — once trusted.
  • A measured value, a set, or a generated file is detect-and-report only — never rewritten in place.
  • v1 watches one repository at a time, in-repo files only; cross-repo and repo-to-world watching is a later layer.

The solution

I modelled every fact as a tether over co-equal sites, with no single site called “the source” — each one carries a fingerprint, and comparing fingerprints to the last baseline is what tells yakir which site actually moved. Facts are guarded at the cheapest tier that fits: a literal token, a value measured by running a command, or eventually a diff-aware judgement. Reconciliation only ever writes into a site that has earned that trust.

  • No site is “the source” — a tether binds co-equal sites.

    A single source of truth doesn’t exist across artefacts you can’t import between; per-site fingerprints reveal which site actually moved, which is what makes “the newest value is the truth” computable without ever naming one site as canonical.

  • Guard each fact at the cheapest tier that fits.

    Most drift is a literal value that only needs comparing. A few facts need something to actually run — a bundle measured, a fence type-checked — and only what’s left over needs a real judgement call.

  • Auto-write is a capability a site earns, not a property of a tether.

    Defaulting every site to read-only and promoting it only once the binding is trusted means a typo in a generated badge can never corrupt package.json. It’s the same “earn auto-fix” ratchet used for counted lint suppressions.

  • A command site is declared-only.

    A command site runs arbitrary shell, so letting a scanner invent and execute one automatically would be a real security hole. A human has to write it into the manifest first.

  • Measured facts and generated files are detect-and-report, never rewritten in place.

    A measurement, a set of quotes, or a generated file has no single “winning” literal to copy in. yakir surfaces the mismatch and lets a human, or the real generator, make the fix.

Architecture

yakir.json manifest

Declares tethers — id, tier, sites, policy

Locators

json-pointer, region, pattern, file, command

Extract & fingerprint

Reads and hashes each site’s current value

Expand globs

One site per matching file, across a monorepo

Reconcile

Compares to the baseline — fresh, suspect or drifted

check / fix / accept / init

The CI gate — read-only, or apply the fix

discover

Proposes candidate tethers; never auto-fixes

yakir.lock

Committed baseline + per-site fingerprints

yakir.json declares tethers over sites; the engine extracts, fingerprints and reconciles them against the last baseline; the CLI turns that into a CI gate and writes the result back to yakir.lock.

I build — you own

Built to hand over

Yakir’s repository is public, so I can point at a handover instead of describing one — every item below is a real link into it, not a summary of it.

  • Source and licence

    Apache-2.0-licensed — 11 source files in src/, all one author.

    View (opens in a new tab)
  • Design docs

    docs/DESIGN.md, docs/manifest-sketch.md and docs/examples.md — the tether/site/fingerprint model and the file format, worked through in full.

    View (opens in a new tab)
  • Test suite

    7 Vitest files, 53 tests green, covering the engine, discovery, reconciliation, expansion and locators.

    View (opens in a new tab)
  • Dogfood manifests

    Two real yakir manifests running against StitchAPI, another of my projects, whose own repo now runs them directly — they catch an actual version lag and a stale bundle-size quote across five files.

    View (opens in a new tab)

Results

Milestones 1 and 2 are shipped: the engine, the full check / fix / accept / init / discover CLI, and both the token and executable tiers — 53 tests green, zero runtime dependencies. It’s dogfooded on StitchAPI, another of my projects, where it already catches a real version lag and a stale bundle-size quote across five files.

  • Apache-2.0

    open-source licence

What’s next

Next is the semantic tier — a diff-aware judge that only runs when a source actually changes — plus type-checking twoslash fences and link resolution as new executable-tier runners. CI-gate hardening and a repo-to-world watching layer follow after that.

Have a similar project in mind?

I’ll build it and hand it over: the code, the docs and the accounts are yours.

Discuss a project