SpecLock is a local-first CLI that checks whether code still follows rules your project already decided.
AI coding tools (and people in a hurry) can quietly change things a project already decided should not change — a renamed key, a banned import, a debug print left in. SpecLock lets you write those decisions down as small markdown guard files, then reports exactly where code violates them — by file and line.
- Scans a target directory you point it at.
- Reads markdown guard files.
- Supports scoped file globs (e.g.
src/**), so a guard only looks where you tell it. - Matches forbidden literal code tokens (exact strings).
- Reports file/line matches.
- Strips comments before matching for
.js,.jsx,.ts,.tsx, and.sql, so a token inside a comment doesn't false-fire. - Has a few implemented SQL required-pattern checks (e.g. a
SECURITY DEFINERfunction missingSET search_path) where those patterns are present — literal guards are the main path, not these.
- It is not a semantic policy engine.
- It does not understand project intent automatically.
- It does not replace human review.
- It does not upload your code anywhere (everything runs locally).
- It does not provide a dashboard or SaaS.
- It does not currently strip Python
#comments or"""docstrings"""(a token inside one can false-fire). - It does not automatically verify README/Docker/build consistency.
npm installNode is the only requirement; there are no runtime dependencies.
A guard is a markdown file. Copy this, change the title and tokens, and you have your own:
# APP-G01 - No console.log left in source
## Tier
1
## Applies to
```
src/**
```
## Forbidden CODE tokens
```
console.log(
```
## Severity
Failnode bin/speclock.js check APP_GUARDS.md ./myapp(APP_GUARDS.md is the guard file above; ./myapp is the project directory to scan.)
speclock check — Tier-A literal matcher (guards: APP_GUARDS.md, target: /abs/path/myapp)
G01 FIRES 1 No console.log left in source [src/app.js:2]
FIRES n means the forbidden token was found n times, each with its file:line. A clean guard prints no fire. (The display uses the short ID G01 from your APP-G01.)
Each ## section is required:
- Header —
# <ID> - <title>. The ID is<PREFIX>-G<number>(the prefix can be anything:APP,LIB, …). The separator may be a hyphen-, en dash–, or em dash—. If the header is malformed, SpecLock warns that no guards were parsed. ## Tier—1for a hard rule.## Applies to— one glob per line inside a fenced ``` block; which files to scan (src/**= everything under `src/`).## Forbidden CODE tokens— one literal string per line; the guard fires if any appears in scope.## Severity—FailorWarn.
- Literal matching is the strongest path today.
- Python comment/docstring stripping is not supported yet — a token inside a
#comment or"""docstring"""can false-fire. - Required-pattern-absence checks are early and specific, not general.
- SpecLock reports possible drift; it does not decide true vs. false positive for you — it fires and locates, you judge.
npm run harnessThe harness should pass before changes are committed.
Early local CLI. Useful for dogfooding and private developer testing.