@evlog/cli runs separately from your application. Use it locally or in CI to inspect your source, configure evlog, and work with telemetry.
Start with evlog map to check supported entry points for evlog logging patterns and get a static observability score with suggested fixes. It writes evlog.map.json unless you pass --no-write. The score describes recognized source patterns, not the logs your handlers produce in production.
evlog init adds evlog configuration to the app. evlog agents writes logging conventions for the AI agents working in the repository.
evlog map has adapters for Nuxt, Nitro, Next.js App Router, TanStack Start, and Hono. Each adapter recognizes specific entry-point shapes. Check the detected framework and entry-point count before interpreting the score. Rules can change between releases, so pin the version when you gate CI on the number.pnpm dlx @evlog/cli map
bunx @evlog/cli map
npx @evlog/cli map
Add it as a dev dependency once you gate CI on the score, so every run uses the same version:
pnpm add -D @evlog/cli
bun add -d @evlog/cli
npm install --save-dev @evlog/cli
evlog binary.Commands
Global flags
Every command accepts these:
| Flag | What it does |
|---|---|
--json | Machine-readable JSON on stdout instead of the report |
--debug | Print a debug summary of the run, and emit it as a wide event |
--noHeader | Skip the branded header |
--cwd <dir> | Run against another directory instead of the current one |
--help | Usage for the command |
--version | Print the CLI version and exit |
Human output goes to stderr
The report you read is written to stderr. Stdout is reserved for --json, so a run can be piped into jq without the report getting in the way:
evlog map --json | jq '.map.score'
Without --json, nothing is written to stdout at all. Colour is dropped when stdout is not a TTY or when NO_COLOR is set, and the report lays itself out for the width it is given, so set COLUMNS to render at a fixed width.
Exit codes
| Code | Meaning |
|---|---|
0 | The command ran and nothing failed |
1 | A check failed, or --min-score was not met |
2 | Usage error — an unknown flag or an invalid value |
$? with the exit code of the last command in it, so evlog map --min-score 90 \| head always looks successful. Use set -o pipefail when you pipe a gated run.When a check is wrong
Every verdict can be turned off from the code it is about, so a false positive never becomes a reason to stop running the tool:
// evlog-map-disable-next-line wide-event, context -- liveness probe, deliberately silent
export default defineEventHandler(() => ({ ok: true }))
The check becomes n/a with your reason attached, at no score cost and with no failed gate, and the report counts how many checks the project disabled, so the number stays honest. Full syntax.
Monorepos
init, map and doctor all resolve the nearest package.json above the working directory, then treat that package as the project. In a pnpm or npm workspace, running from apps/web scans apps/web, not the repo root.
evlog map scans one app at a time. Running it from a bare workspace root, where there is no framework to detect, is an error rather than an empty report:
cd apps/web && evlog map
# or
evlog map --cwd apps/web
Debugging a run
--debug prints what the command did: the steps it went through, the directory it resolved, and any findings, and emits the same information as an evlog wide event:
evlog map --debug
── debug ────────────────────────────────
command map
env development
cwd /Users/you/apps/web
steps resolveProject → detectFramework → resolveEvlog → scan → writeMapFile → done
──────────────────────────────────────────
full event → --json --debug (stderr)
Add --json to get the whole event instead of the summary. EVLOG_CLI_DEBUG=1 does the same as the flag, which is useful in a CI job you cannot easily edit.
Next
evlog init: wire evlog into an app that does not have it yetevlog map: what it scans and how to read the report- Rules: every check, what satisfies it, and how to fix it
- Scoring: how the number is calculated
- CI: gate a pull request on the score