Releases: frankbesch/memvet
Release list
v0.12.0
Changelog
- 1279734 action: empty-array-safe expansion in the check step (bash 3.2 under set -u)
- 3f984b7 rename: memlint becomes memvet (v0.12.0; D-### at wrap, ruled 2026-09-17)
Install with go install github.com/frankbesch/memvet@v0.12.0, or
download a binary above and verify it against checksums.txt.
v0.11.1
Changelog
- 4bbaf60 docs: pin the Action and pre-commit snippets to v0.11.1
- b3e56cc docs: retire the [secrets] entropy detector from the roadmap (D-### at wrap, 2026-09-11)
- 7eca25b init: infer a flat memory folder from MEMORY.md alone (v0.11.1)
Install with go install github.com/frankbesch/memlint@v0.11.1, or
download a binary above and verify it against checksums.txt.
v0.11.0
What's new
This release is about the first five minutes: memlint now does something useful before you have written a config, checks the memory folder Claude Code keeps outside your repo, and runs as a GitHub Action or a pre-commit hook.
check runs without a config, and says so. With no .memlint.toml at the target, check runs the config init would have written and reports that first:
config YELLOW .memlint.toml not found; ran the inferred config (pointers); memlint init to keep it [config/inferred]
an inferred run checks only what the tree shows; declare the invariants you rely on
pointers RED MEMORY.md:3 dead reference: memory/gone.md does not exist [pointers/dead-ref]
memlint: 1 red, 1 yellow (tree eec04fc40977)
Nothing is written. The YELLOW fails the run under --strict, so a CI job that forgot its config is loud rather than clean. An invalid config is still exit 2; only absence infers. Try it on any repo without installing anything:
go run github.com/frankbesch/memlint@latest check .
Flat memory folders. Claude Code's auto-memory is MEMORY.md beside its notes, indexed as [Title](note.md), with no folder to name as a root. The new [pointers] root "." checks slash-less link destinations against the file's own folder. Only link destinations count; a.md in prose is a word, not a claim. init infers it when MEMORY.md sits beside two or more notes and no markdown folder exists, which means this now works with no config at all:
memlint check ~/.claude/projects/<project-slug>/memory
Wider discovery. init and inference enable pointers on whichever of GEMINI.md, COPILOT.md, .github/copilot-instructions.md, .cursorrules, and CONVENTIONS.md exist, alongside MEMORY.md, CLAUDE.md, and AGENTS.md. The mirrors suggestion list is unchanged and still closed.
GitHub Action. Fetches the released binary, verifies it against checksums.txt, and runs check --format github:
- uses: frankbesch/memlint@v0.11.0
with:
strict: true
base: ${{ github.event.pull_request.base.sha }}pre-commit hook. Builds memlint at the pinned release with go install and runs check --changed on what you are about to commit:
- repo: https://github.com/frankbesch/memlint
rev: v0.11.0
hooks:
- id: memlintCompatibility
memlint checkon a directory with no.memlint.tomlused to exit 2 with a one-line refusal. It now runs and exits 0 or 1 like any other run, with theconfig/inferredYELLOW as its first line. Scripts that relied on the refusal (none known) should pass--strict, which turns the YELLOW into exit 1.roots = ["."]used to be a config error. It now enables the sibling pass. No existing valid config changes meaning.- One new finding code,
config/inferred. No code was renamed or removed, and the JSONschema_versionstays 1. - Fixture counts, examples, the tree receipt, and all other output are byte-for-byte unchanged.
Install
brew upgrade memlint
go install github.com/frankbesch/memlint@v0.11.0
Binaries for macOS and Linux are attached; verify against checksums.txt.
Engineering notes
Commit b7733b0. SPEC.md v0.11 addendum parts 1–5 with gates; the post-push CI run 34639081021 is green on ubuntu, macos, and the new action job, which runs this repo's action.yml against examples/broken and asserts it fails. The addendum header records a competitor read of agents-lint, ctxlint, and claude-healthcheck, cross-checked the same day; the parts here close the first-run gaps only, and check still has no fix mode.
v0.10.0
What's new
This release changes how memlint feels, not what it checks. No rule, finding code, or exit code changed.
Flags work before or after the path.
memlint check . --strict # now works
memlint check --strict . # still works
An unknown flag anywhere, a flag without its value, or a second path is still a usage error (exit 2), printed with that command's help. Nothing is ignored silently.
Each command has its own help. memlint --help is one screen: the three commands and where to go next. memlint check --help, memlint init --help, and memlint fingerprint --help each carry only what that command needs. memlint help <command> does the same.
init tells you what it inferred. It reports three tiers:
Enabled
pointers MEMORY.md, CLAUDE.md -> roots memory, docs
junk .DS_Store seen in the tree
Suggested (written as commented sections; uncomment to enable)
append_only memory/decisions.md exists
mirrors CLAUDE.md and AGENTS.md both present
Not inferred (needs a decision only you can make)
human_brief authorship is a policy choice
tokens a budget is a choice
...
The generated .memlint.toml is now short: a four-line header, the enabled sections, and commented sections only for the suggested rules. The full rule reference lives in docs/rules.md, not in every generated file. The suggestion list is closed: a decisions.md by name suggests append_only, two of CLAUDE.md, AGENTS.md, GEMINI.md at the root suggest mirrors, and nothing else is ever guessed.
init --dry-run prints the config it would write to stdout and the report to stderr, and writes nothing. It works when a .memlint.toml already exists, so you can rerun discovery on a configured repo. init still never overwrites, and there is no --force.
Also in this release
The README is now a landing page, with the reference material under docs/. docs/recipes.md gives copy-and-paste configs for a basic memory repo, a decision log, and shared instructions; each is a directory under examples/ that CI runs on every commit, and a test keeps the README's quoted output identical to the real run. A complete pull-request workflow is at .github/examples/memlint.yml.
Compatibility
memlint check <path> --flagused to exit 2. It now runs. Scripts that relied on the refusal (none known) would see a real result instead.initno longer printsN rules enabled. Scripts that grepped for it should read theEnabledtier.- The generated config no longer carries commented examples for every rule. Existing configs are untouched.
- Everything else, including JSON output, GitHub annotations, and the tree receipt, is byte-for-byte unchanged.
Install
brew upgrade memlint
go install github.com/frankbesch/memlint@v0.10.0
Binaries for macOS and Linux are attached; verify against checksums.txt.
Engineering notes
Commit c3d3314. SPEC.md v0.10 addendum parts 1–4 with gates G1–G6 (G6 is the post-push CI run, 34635112173, green on ubuntu and macos). Ruling D-143. No new rule ships until the next minor; new invariants face the admission bar in CONTRIBUTING.md.
v0.9.1
What's new
Anchored markdown references are now validated.
Before v0.9.1, memory/setup.md#install passed as long as memory/setup.md existed. Now the anchor must resolve too: #install has to match a heading slug, a {#custom-id} attribute, or an <a id>/<a name> tag in the target file. A miss is RED pointers/dead-anchor, and the finding lists the anchors the file does expose so the fix is a copy-and-paste.
Why it matters
A renamed heading used to leave agent memory pointing at a section that no longer exists, and nothing failed. It fails now.
Compatibility
Repositories with [pointers] enabled may report new pointers/dead-anchor findings on the first run. Each one is a real broken link. No config change is needed; anchored references were already extracted, only the anchor half was unchecked.
Install
brew upgrade memlint
go install github.com/frankbesch/memlint@v0.9.1
Binaries for macOS and Linux are attached; verify against checksums.txt.
Engineering notes
Commit 4bb6135. SPEC.md v0.9 addendum part 2, gates G1–G5. The planted-defect fixture is now 10 red, 4 yellow.
v0.9.0
Changelog
- 8a9af9c docs: v0.9 futures — pointers/dead-anchor, secrets entropy
- b816eaf v0.9: tree fingerprint — memlint fingerprint, tree receipt in every check summary and summary.tree, --expect-tree turns a moved tree into RED tree/moved (Frank ruled 2026-09-08; gates G1–G5 in SPEC.md)
Install with go install github.com/frankbesch/memlint@v0.9.0, or
download a binary above and verify it against checksums.txt.
v0.8.0
Changelog
- 4bd9197 check --changed: findings narrowed to files changed since HEAD (modified, staged, untracked); config-level findings survive; git-per-file rules skip the rest; exit 2 without git
- 594cbe4 docs: v0.8 roadmap state
- 8b0dc1c globs: recursive ** as a whole-segment wildcard in every glob-taking key (junk, tokens, pointers, ids); one translator for matching and validation
- 9c5a887 ids: cited_in (dead citations are RED ids/dead-cite) and ordered = true (mid-log paste is RED ids/out-of-order)
- 8e60827 v0.8: [blocks] mirror=true content mirroring; [append_only] per-file headers; [human_brief] follow_renames
- 8a09cc2 v0.8: [stamps] last-verified dates vs the file's last change; [secrets] credential-shaped text (value never echoed)
Install with go install github.com/frankbesch/memlint@v0.8.0, or
download a binary above and verify it against checksums.txt.
v0.7.0
Changelog
- 4a00ae6 Add PreToolUse output-filter hook: noisy commands (go test/build/vet, make, npm/pip install) return only failures + summary + log path; fails open, unlisted commands untouched
- 2151a8f append_only: rotation allowance — a cut span found verbatim in a new listed file is INFO append_only/rotated, not RED; header_lines marks the only mutable span
- 4682712 docs: two-register findings entries — plain-English lead, expert detail after
- df26d84 ids: known = [...] — reconciled collisions report as INFO ids/known-duplicate; a known id that never collides is YELLOW ids/known-unused
- 5ad2a4c ids: new [ids] rule — every id opening a line must be unique across the listed files; duplicate = RED ids/duplicate citing the first occurrence
- 4ca76b9 ids: the delimiter form "^(D-\d{3}) |" is the default pattern (Frank ruled 2026-09-05)
- 2d2ef9f tokens: optional two-tier budget — limit=M adds a RED tokens/over-limit tier
Install with go install github.com/frankbesch/memlint@v0.7.0, or
download a binary above and verify it against checksums.txt.