@keboola/agent-precheck
v0.2.6
Published
Portable pre-push enforcement CLI for Keboola UI platform consumers — runs formatting and lint checks consistently across any repo.
Readme
@keboola/agent-precheck
A portable pre-push enforcement CLI for the Keboola UI platform. Runs the same formatting and lint gates everywhere — keboola/ui, other Keboola repos, AI-agent-generated apps — so a single command verifies that a working tree is push-ready.
Why this exists
PR template checklists and "remember to run lint" agent instructions are descriptive but unverified. Agents (and humans) push PRs that fail CI on oxfmt or oxlint despite ticking every box. This package replaces the checklist with a single command that mechanically applies fixes and reports a hard pass/fail.
The CLI is platform-distributed — published to npm so any consumer of @keboola/design or @keboola/api-client can run the same gate without copying scripts around.
Install
Inside keboola/ui, use pnpm lint instead: this CLI can't find the oxfmt/oxlint each workspace pins (see How binaries are resolved). Elsewhere:
pnpm add -D @keboola/agent-precheckOr run ad-hoc without installing:
npx @keboola/agent-precheckUsage
# Default: fix mode on files changed vs origin/main + working tree
pnpm exec agent-precheck
# CI mode: no fixes, exit non-zero on any issue
pnpm exec agent-precheck --check
# Only files currently staged
pnpm exec agent-precheck --staged
# Every tracked file (slow; for first-run cleanups)
pnpm exec agent-precheck --all
# Suppress per-tool stdout
pnpm exec agent-precheck --quiet
# Skip the workspace-wide checks individually
pnpm exec agent-precheck --no-deps-check
pnpm exec agent-precheck --no-knipWhat it runs (in order, fail-fast)
oxfmt— apply formatting.oxlint --fix— apply lint auto-fix.oxfmt --check— verify formatting is clean.oxlint— verify lint is clean.syncpack lint— verify dependency versions are consistent (only when at least onepackage.jsonis in the changed-file set; only ifsyncpackis installed).knip— verify no unused exports / deps / files (only ifknipis installed).
Any auto-fixed file is re-git added so git push ships the fixes.
Agent verify loop + foot-guns
The contract for an agent finishing a logical edit, before git commit / git push:
| Goal | Command | Behavior |
| ---------------------------- | ----------------------------------- | ------------------------------------------------------------------------------ |
| Verify before push (default) | pnpm exec agent-precheck | Fix + re-check files changed vs origin/main + working tree. Re-stages fixes. |
| CI parity, no fixes | pnpm exec agent-precheck --check | Verify only; non-zero exit on any issue. |
| Pre-commit subset | pnpm exec agent-precheck --staged | Only currently-staged files. |
| First-run cleanup | pnpm exec agent-precheck --all | Every tracked file. Slow. |
Non-zero exit ⇒ do not push around it. Fix the reported issues and re-run.
Order is fixed and fail-fast: oxfmt (fix) → oxlint --fix → oxfmt --check → oxlint → syncpack lint (only when a package.json changed, if installed) → knip (if installed).
Foot-gun: lint src, not dist — gitignore dist FIRST
oxlint must never see the built bundle. If dist/ is committed (or untracked and un-ignored), lint scans minified output and emits thousands of phantom errors. This CLI hard-filters dist/ (plus build/, out/, node_modules/, .next/, .turbo/, coverage/, storybook-static/) from its own file set regardless of .gitignore — but only inside agent-precheck. A raw pnpm lint / oxlint in the repo still trips on a missing ignore.
So in any new app the first commit must add a .gitignore with dist (and .env*) — see apps/boilerplate/.gitignore, the canonical reference. Scaffold the ignore before generating or building code.
Always-ignored paths
The following directories are filtered from the discovered file set regardless of .gitignore state — universal JS-project artifacts that no project meaningfully lints:
node_modules/ dist/ build/ out/ .next/
.turbo/ coverage/ storybook-static/The match is both leading-prefix (node_modules/foo) and any internal segment (packages/foo/node_modules/bar) so monorepo workspace node_modules are also skipped. Belt-and-suspenders against the common "fresh git init + npm install without .gitignore" footgun where git ls-files --others --exclude-standard would otherwise return every file under node_modules/**.
How binaries are resolved
- Walk up
node_modules/.bin/fromcwd(handles monorepo + worktree cases). Misses tools installed only in a workspace leaf package. - For
oxfmtandoxlint: fall back tonpx --yes --package <name>if not found locally. Slower on first run; cached afterward. - For
syncpackandknip: skip gracefully (with a one-line(skipped: not installed)note) if not found locally. No npx fallback — auto-installing heavier deps in repos that deliberately opt out is a footgun. Use--no-deps-check/--no-knipto suppress the "skipped" line.
This means the CLI works in:
- This monorepo (all four binaries live in root
node_modules). - Other repos that
pnpm add -Dwhichever subset they use. - Bare working trees with only Node and network access (oxfmt/oxlint via npx fallback; syncpack/knip skipped with a
(skipped: not installed)note, suppressible via--quietor--no-deps-check/--no-knip).
Out of scope (for now)
brand-auditintegration — added when the audit CLI is stable.- Pre-push git hook installation — the CLI is the contract; whoever wires it into a hook gets the gate.
- CI integration to run
--checkearly in the workflow — separate follow-up.
Failure mode
Exit code 1 with an explicit message:
❌ agent-precheck failed: format issues remain, lint issues remain.
Fix the issues above and re-run. Do not push around them.Reference
Part of the Keboola UI platform (@keboola/*). For platform overview see
docs/architecture.md in this repository.
