> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alfiz.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# alfiz-verify.config.json: Configuration Reference

> alfiz-verify.config.json reference: catalog path, scan directories, additive gate names, visibility names, server patterns, and client-reach guards.

`alfiz-verify` reads its configuration from `alfiz-verify.config.json` in the current working directory, or from the path passed via `--config <path>`. The file is plain JSON, with no JavaScript and no comments.

## Config fields

<ParamField body="catalog" type="string" required>
  Path to the emitted catalog JSON file, the output of `catalog.toDocument()`. Resolved relative to the current working directory.

  ```json theme={null}
  { "catalog": "alfiz-catalog.json" }
  ```
</ParamField>

<ParamField body="include" type="string[]" default="[&#x22;src&#x22;]" optional>
  Directories (or individual files) to scan. Resolved relative to the current working directory. `alfiz-verify` walks each directory recursively and scans every `.ts`, `.tsx`, `.mts`, and `.cts` file it finds (`.d.ts` files are skipped).

  ```json theme={null}
  { "include": ["src", "app", "pages"] }
  ```
</ParamField>

<ParamField body="exclude" type="string[]" optional>
  Path substrings to skip. A file is excluded when its path contains any of these strings. The built-in excludes `["node_modules", "dist", ".next", ".git"]` are always applied; this field adds to them.

  ```json theme={null}
  { "exclude": ["__generated__", "vendor"] }
  ```
</ParamField>

<ParamField body="gateNames" type="string[]" optional>
  Additional function names to treat as concrete-permission gates, **added to** the built-in defaults (`can`, `fresh`, `require`, `requirePermission`, `gateAction`, `apiRequirePermission`). Gate calls are checked for typed key validity, mark the enclosing function as gated, and count toward coverage.

  ```json theme={null}
  { "gateNames": ["assertCanEditFile", "requireFilePermission"] }
  ```

  <Note>
    This field is **additive**, so it extends the defaults. You do not need to restate `can` or `require`. If you want full replacement of the defaults (dropping the built-ins), use the programmatic `verifyProject` API directly.
  </Note>
</ParamField>

<ParamField body="visibilityNames" type="string[]" optional>
  Additional function names to treat as visibility affordances, **added to** the built-in defaults (`canAny`, `requireAny`, `holds`). Visibility affordances count toward key coverage but produce an error when used as a gate in a server file.

  ```json theme={null}
  { "visibilityNames": ["showIfAny", "hiddenUnless"] }
  ```

  <Note>
    Like `gateNames`, this is additive. The built-in visibility names are always included.
  </Note>
</ParamField>

<ParamField body="serverFilePatterns" type="string[]" optional>
  Additional RegExp source strings matched against file paths to identify server enforcement points, **added to** the built-in patterns (`app/.*route.(t|j)sx?`, `pages/api/`). Files matching these patterns are treated as server files even without a `"use server"` directive, so exported async functions in them must contain a gate.

  ```json theme={null}
  { "serverFilePatterns": ["app/actions/", "server/handlers/"] }
  ```

  Each string is compiled into a `RegExp`. If any entry is not a valid regular expression, `alfiz-verify` exits with code `2`.

  <Note>
    This is additive. The built-in patterns (`app/.*route.(t|j)sx?` and `pages/api/`) are always applied.
  </Note>
</ParamField>

<ParamField body="forbidClientIdentifiers" type="string[]" optional>
  Identifiers that must not appear in any `"use client"` module. Use this to ensure service-key material (environment variable names, key shim imports) can never reach the browser. When a listed identifier is found in a client-reachable file, `alfiz-verify` reports an error with the `client-reachable-secret` rule.

  ```json theme={null}
  { "forbidClientIdentifiers": ["ALFIZ_SERVICE_KEYS", "serviceKeyShim"] }
  ```

  This is the build-time half of the service-principal security posture: `createServiceKeyShim` validates keys server-side; this guard ensures the key material can never be bundled into client JavaScript.
</ParamField>

<ParamField body="importManifest" type="string" optional>
  Path to the emitted import manifest, the output of `catalog.toImportManifest()`. **Required if your catalog declares [imports](/catalog/imports)**: a catalog document carries owned vocabulary only, so without the manifest the verifier treats every imported key as foreign.

  ```json theme={null}
  { "importManifest": "alfiz-imports.json" }
  ```
</ParamField>

<ParamField body="imports" type="Record<string, string>" optional>
  The namespace owners' published documents, keyed by namespace. Optional enrichment on top of `importManifest`: the manifest already names every imported key, so these only add display copy and sharpen did-you-mean suggestions.

  ```json theme={null}
  { "imports": { "zoom": "src/authz/zoom.catalog.json" } }
  ```
</ParamField>

<ParamField body="importSource" type="&#x22;registry&#x22; | &#x22;none&#x22;" optional>
  Declares that a registry or Alfiz Cloud dashboard is wired up, which makes `implicit-import` a warning rather than an error. Defaults to `"registry"` when your catalog already declares imports.

  This is **declared, never detected**. `alfiz-verify` is offline and deterministic by construction: no network call decides whether your build passes.

  ```json theme={null}
  { "importSource": "registry" }
  ```
</ParamField>

<ParamField body="implicitImports" type="&#x22;error&#x22; | &#x22;warn&#x22; | &#x22;off&#x22;" optional>
  Overrides the `implicit-import` severity outright. Use `"off"` when foreign keys are an accepted, reviewed part of this codebase.

  ```json theme={null}
  { "implicitImports": "off" }
  ```
</ParamField>

<ParamField body="implicitImportAllow" type="string[]" optional>
  Namespaces exempt from `implicit-import` entirely, which is narrower than turning the rule off.

  ```json theme={null}
  { "implicitImportAllow": ["stripe", "zoom"] }
  ```
</ParamField>

## Complete example

```json theme={null}
{
  "catalog": "alfiz-catalog.json",
  "include": ["src", "app"],
  "exclude": ["__generated__", "e2e"],
  "gateNames": ["assertCanEditFile", "requireFilePermission"],
  "visibilityNames": ["showIfCanAny"],
  "serverFilePatterns": ["app/actions/", "server/handlers/"],
  "forbidClientIdentifiers": ["ALFIZ_SERVICE_KEYS", "createServiceKeyShim"]
}
```

## Additive vs. replacement

The three name lists (`gateNames`, `visibilityNames`, `serverFilePatterns`) are always **additive** through the CLI. This is intentional: the CLI is the batteries-included path, and forgetting to restate `can` in `gateNames` should not silently un-gate your whole codebase.

If you need full replacement of the built-in defaults, for example a codebase that uses entirely custom gate wrappers and wants to treat the built-in names as errors, use the programmatic `verifyProject` API from `@alfiz/verify` directly:

```ts theme={null}
import { verifyProject } from "@alfiz/verify";

const report = verifyProject({
  catalog,
  files,
  // Replacement, not addition: only your wrappers count as gates.
  gateNames: ["assertCanEditFile", "requireFilePermission"],
  visibilityNames: ["showIfCanAny"],
});
```

`files` is a list of paths; the source text comes from `read`, which defaults to the filesystem. Pass your own to verify an in-memory tree. `verifyProject` is synchronous and performs no network I/O, by construction.

It returns a `VerifyReport`:

```ts theme={null}
interface VerifyReport {
  issues: VerifyIssue[];            // { severity, rule, file, line, message }
  referencedKeys: Set<string>;      // concrete keys reached by a call site or nav item
  referencedPatterns: Set<string>;  // patterns, verbatim
  skippedFiles: Array<{ file: string; reason: string }>;
  errorCount: number;
  warningCount: number;
}
```

<Note>
  `referencedPatterns` is kept separately from `referencedKeys` because an imported wildcard expands to no keys. Pattern-wise reach is the only way to tell a live import from a stale one.
</Note>
