Skip to content

Configuration

Place emendant.json in the root of the repository being scanned. Emendant works without configuration; add the file only for stable project-specific choices.

{
"ignore": ["legacy/**", "generated/**"],
"packages": ["openai", "ai"],
"severity": ["breaking", "deprecation"],
"adopted": false
}

Unknown keys and invalid values are errors. This is deliberate: a misspelled exclusion must not produce a scan that looks correctly narrowed.

Key Type Meaning
ignore string[] Repository-relative glob patterns excluded from the source walk.
packages string[] Registry package names to scan. Empty means every directly declared package with feed coverage.
severity string[] Any of breaking, deprecation, or behaviour. Empty uses the built-in default.
adopted boolean Include findings for releases the project has already adopted.
packageManager string npm, pnpm, yarn, uv, or poetry: which manager really installs this repository. Read only where two managers’ lockfiles sit in one directory.
testCommand string The test command emendant fix proves a patch with, overriding what it would otherwise find. Unused by scan.
typecheckCommand string The typecheck command, on the same terms. Unused by scan.
verifyTimeout integer Seconds a single verification command may run before it is stopped. Unused by scan.
maxPatchLines integer The largest patch emendant fix will offer for one finding. Unused by scan.
model object Which model provider writes the patches no transform can. Unused by scan.
feed object snapshot, autoUpdate, and offline: which feed a run in this repository uses.

emendant fix finds a typecheck and a test command rather than requiring one: a script the manifest declares, or a tool the repository installed. testCommand and typecheckCommand are overrides for a repository where the found command is the wrong one. A repository nothing can be found for still gets its patches, graded structurally checked and saying so.

A directory can hold two managers’ lockfiles at once: a committed pnpm-lock.yaml beside a package-lock.json somebody’s npm install left behind, or a yarn.lock from before a migration. They are two accounts of the same tree written at different moments, and they can disagree about the installed version.

Nothing in a repository proves which of them was written last. A packageManager field records what the project intends and is edited by a person rather than by an install; a .yarnrc.yml or pnpm-workspace.yaml outlives the install that wrote it. Believing either would place a package against a version it is not on. So both lockfiles are read, a disagreement is reported as the closed range between them, and the findings it touches are placed unknown rather than guessed either way.

packageManager is how you settle it, because you know which manager you run and the repository does not:

{
"packageManager": "npm"
}

--package-manager <name> is the same answer for one run, on scan, fix, detect, match, and prefilter. Where a directory holds one lockfile, neither changes anything.

A few breaking changes have no mechanical rewrite. emendant fix can ask a model to write those, and only a provider you name is ever called. Without one, those findings are reported unfixed and nothing is sent anywhere.

{
"model": {
"provider": "azure",
"auth": "entra",
"endpoint": "https://contoso.openai.azure.com",
"name": "my-gpt-5-deployment"
}
}
Key Type Meaning
provider string codex, claude, openai, anthropic or azure. Required.
auth string local (codex, claude), api, or entra (azure). Optional: claude defaults to local, and azure reads the environment when this is absent.
name string The model to use. For azure this is the deployment name you created, and it is required.
endpoint string The Azure AI Foundry resource to post to. For openai and anthropic it names a gateway that speaks the same wire format. codex and claude reject it.

claude runs the Claude Code CLI you installed, signed in the way it already is, with no tools and in an empty directory. Claude Code prefers an exported ANTHROPIC_API_KEY, an ANTHROPIC_AUTH_TOKEN or a cloud provider to your Claude subscription. So with auth: local a run that would use one of those is refused, and the message names it. Set auth: api to use that credential through Claude Code.

azure sends the excerpt to a resource in your own tenant rather than to a vendor, which is the route for a network that permits a fixed list of hosts. Its credential is AZURE_OPENAI_API_KEY or, for Microsoft Entra ID, a token you obtain yourself and export as AZURE_OPENAI_AUTH_TOKEN. Emendant never obtains a credential and stores no part of one.

The first interactive scan can record the same provider settings in the user-level configuration. Command-line flags override emendant.json, and emendant.json overrides the user-level choice. The user-level file also records whether automatic feed refresh is allowed, whether first-run setup is complete, whether a failed patch sends back what the release broke, and the random identifier those contributions carry once one has been sent. It never stores a key or token.

Patterns are matched against paths relative to the repository root:

{
"ignore": [
"legacy/**",
"apps/demo/src/generated/**"
]
}

A pattern ending in /** excludes the named directory and its complete subtree. This is separate from .gitignore: Emendant respects committed .gitignore files automatically, while ignore expresses a scanner-specific choice.

When --package is supplied, its repeated values replace the configured package list for that run. Likewise, --severity replaces the configured severity list. --adopted enables adopted findings even when the file leaves them disabled, and --package-manager replaces the configured manager.

Terminal window
npx emendant scan --package openai --severity breaking
Terminal window
npx emendant scan --config config/emendant.ci.json

A relative path is resolved from the directory being scanned. An explicitly named file that cannot be read is an error.