# ai-register

> Keep a register of the AI tools your project uses, their data, legal basis and transfers, and let a soft check warn about any AI integration found in the repository that the register misses.

Canonical: https://bmad-plus.rochetta.fr/docs/reference/cli-ai-register/
Language: en
BMAD+ version: 0.23.1
Documentation reviewed: 2026-10-19
Author: Laurent Rochetta
License: MIT

BMAD+ documentation › [Reference](https://bmad-plus.rochetta.fr/docs/reference/) › ai-register

Coding assistants, agent command lines, model APIs called by your product and MCP servers all process data, sometimes personal data. `ai-register` keeps one file, `_bmad/ai-processing-register.yaml`, that says for each tool who provides it, for what purpose, which data it sees, on which legal basis, for how long and where the data goes outside the EEA. Its `check` action looks for AI integrations in the repository and warns about any the register does not cover. It belongs to the Shield pack’s toolkit and is useful to anyone who has to prepare a record of processing, a DPIA that involves AI tooling or a supplier review.

> **Note · A soft gate, by design** A missing entry is a warning and never fails a build; only a register that cannot be read exits non-zero. The register records processing, it does not make it lawful. The legal basis, the transfer mechanism and the agreements are decisions for the controller and its data protection officer, and the check sees configuration inside the repository only: a tool installed on a developer’s machine without project files is found by asking, not by the check.

<a id="synopsis"></a>
## Synopsis

**In your project terminal**

```sh
npx bmad-plus ai-register init [-d <path>] [--json]
npx bmad-plus ai-register check [-d <path>] [--json]
```

**Actions and options of ai-register**

| Flag or action | Argument | Default | What it does |
| --- | --- | --- | --- |
| `init` | - | - | Copies the Shield template to `_bmad/ai-processing-register.yaml`. Never overwrites an existing register. The template entries are examples, so `check` keeps warning until you replace them. |
| `check` | - | - | Detects the AI integrations of the project, compares them with the register and prints the result. |
| `-d, --directory` | `<path>` | current folder | Project folder. |
| `--json` | - | off | Machine-readable output (`schemaVersion: 1`). |

<a id="register-file"></a>
## The register file

**Shape of an entry (from the Shield template)**

```yaml
schema: bmad-plus/ai-processing-register/1
controller: Example Ltd, 1 Example Street, Example City
reviewed: 2026-09-29
tools:
  - id: coding-assistant
    name: Claude Code
    provider: Anthropic PBC
    integrations: [claude-code]
    purpose: Assist developers in reading, writing and reviewing the code of this repository.
    data:
      - Source code and commit history of this repository
    personalData: true
    legalBasis: legitimate-interests
    retention: The period set by the provider’s terms, written here in days.
    transfers:
      - to: United States
        mechanism: standard-contractual-clauses
    agreement: Data processing addendum attached to the commercial terms.
```

**Rules the check enforces**

| Field | Rule |
| --- | --- |
| `schema` | Must be `bmad-plus/ai-processing-register/1`. Unknown top-level keys are refused (allowed: `schema`, `controller`, `reviewed`, `tools`). |
| `controller` | Required text: who is responsible for the processing. |
| `reviewed` | Required date written `YYYY-MM-DD`. The check warns when it is more than 365 days old. |
| `tools[].id` | Unique, lowercase letters, digits and dashes. |
| `tools[].name`, `provider`, `purpose`, `retention` | Required text of up to 2000 characters. |
| `tools[].integrations` | Non-empty list of the integration ids the entry covers: an adapter tool id (`claude-code`, `gemini-cli`, `antigravity`, `cursor`, `codex-cli`, `opencode`, `aider`), another tool such as `github-copilot`, `windsurf` or `continue`, or `mcp:<server name as declared>`. An id can be covered by one entry only. |
| `tools[].data` | Non-empty list of the categories of data the tool sees. |
| `tools[].personalData` | Required `true` or `false`. |
| `tools[].legalBasis` | Required when `personalData` is `true`, forbidden otherwise. One of `consent`, `contract`, `legal-obligation`, `vital-interests`, `public-task`, `legitimate-interests` (GDPR Art. 6(1)). |
| `tools[].transfers` | Required list, `[]` for nowhere. Each item is `{ to, mechanism }` with a mechanism among `adequacy-decision`, `standard-contractual-clauses`, `binding-corporate-rules`, `derogation`. |
| `tools[].agreement` | Optional text: the processing agreement in place. |

<a id="reads-writes"></a>
## What it reads and writes

- `init` writes one file, `_bmad/ai-processing-register.yaml`, creating `_bmad` if needed. It refuses when `_bmad` is not a folder (a link would write outside the project).
- `check` writes nothing. It reads the register (up to 256 KB) and looks for AI integrations in four places: the adapter files BMAD+ installs (`CLAUDE.md`, `GEMINI.md`, `.cursor/rules/bmad-plus.mdc`, `.codex/AGENTS.md`, `.opencode/AGENTS.md`, `CONVENTIONS.md`), the tools’ own markers (`.claude`, `.cursor`, `.cursorrules`, `.gemini`, `.codex`, `.opencode`, `opencode.json`, `.aider.conf.yml`, `.github/copilot-instructions.md`, `.windsurf`, `.windsurfrules`, `.continue`), and the MCP servers declared in `.mcp.json`, `.cursor/mcp.json`, `.gemini/settings.json` and `.vscode/mcp.json` (comments and trailing commas are accepted).
- Nothing is sent anywhere and no program is started. Symbolic links are not followed.

<a id="exit-codes"></a>
## Exit codes

**Exit codes by action**

| Action | Code | Meaning |
| --- | --- | --- |
| `init` | 0 | Register written. |
| `check` | 0 | The register was read or is absent. Warnings do not change this. |
| `check` | 1 | The register exists but cannot be used: unreadable, not valid YAML, or it breaks a rule above. The reason is printed as `error`. |
| `init`, other | 3 | Unknown action (`ai-register: unknown action "x" (init, check)`) or `init` failed (for example the register already exists). |

<a id="real-output"></a>
## What the output looks like

The transcripts are composed from the message templates in the source, on an imagined project that uses Claude Code and a GitHub MCP server and later adds Cursor. They are marked simulated.

**Start the register, then check it**

```text
$ npx bmad-plus ai-register init
_bmad/ai-processing-register.yaml: started from the Shield template. Replace the example entries, then run bmad-plus ai-register check.
$ npx bmad-plus ai-register check
_bmad/ai-processing-register.yaml: reviewed 2026-09-29 — 2/2 AI integration(s) registered
  registered claude-code → coding-assistant
  registered mcp:github → issue-tracker-connector
# The 2/2 assumes that the project’s .mcp.json declares a github server. Without it the count is 1/1 and a line says that mcp:github is “not found here (may be used outside the repository)”.
```

Output captured from a real run. Source: Replayed with the 0.23.0 package (Core and Shield packs, Claude Code) in a throwaway project whose .mcp.json declares a github server

**A tool the register misses**

```text
$ npx bmad-plus ai-register check
_bmad/ai-processing-register.yaml: reviewed 2026-09-29 — 2/3 AI integration(s) registered
  registered claude-code → coding-assistant
  registered mcp:github → issue-tracker-connector
  warning   cursor is set up (.cursor/rules/bmad-plus.mdc, .cursor) but not in the AI processing register
  Add each tool with its purpose, data, legal basis, retention and transfers; see the Shield template shared/ai-processing-register-template.yaml.
# Exit code 0: a warning never fails the command.
```

Output captured from a real run. Source: Replayed with the 0.23.0 package in the same throwaway project after adding the Cursor adapter

Other lines you may see: `<file>: absent — 0/N AI integration(s) registered` with the warning `no AI processing register at _bmad/ai-processing-register.yaml` when integrations exist but no register does; `warning   the register was last reviewed on <date>, <n> days ago`; `not found here (may be used outside the repository): <ids>` for entries that match nothing in the repository (normal for a model API called only by your product); and `error` lines on the error stream when the register is invalid. With `--json`, the result has `status` (`ok`, `warning` or `error`), `integrations` (each with `ids`, `sources`, `coveredBy`), `unmatched`, `warnings` and `errors`.

<a id="doctor"></a>
## The same check inside doctor

When the Shield pack is installed, `bmad-plus doctor` runs the same comparison as the check `shield.ai-register`. It is a `pass` (“AI processing register covers the N AI integration(s) found.”) or a `warning` that lists the problems and points you to `bmad-plus ai-register check`. Doctor never turns this into an error, so an incomplete register does not make an installation fail its health check.

<a id="errors"></a>
## Errors and what to do

**Messages of ai-register**

| Message | Cause | What to do |
| --- | --- | --- |
| `ai-register: _bmad/ai-processing-register.yaml already exists` | `init` never overwrites. | Edit the existing file, or move it away first. |
| `ai-register: _bmad is not a folder` | Something other than a folder sits at `_bmad`. | Remove or rename it, then run `init` again. |
| `ai-register: unknown action "x" (init, check)` | The action is not `init` or `check`. | Use one of the two actions. |
| `error     _bmad/ai-processing-register.yaml: tool X: legalBasis must be one of ...` | `personalData` is true and the legal basis is missing or unknown. | Pick one of the six legal bases, or set `personalData: false` and remove `legalBasis`. |
| `error     ... tool X: transfers must list where data goes outside the EEA ([] for nowhere)` | The `transfers` list is missing. | Add `transfers: []`, or the destinations with their mechanism. |
| `error     ... tool X: <id> is already covered by Y` | Two entries claim the same integration id. | Keep the id in one entry only. |
| `error     ... register: schema must be "bmad-plus/ai-processing-register/1"` / `unknown key(s) ...` | Wrong schema line or an unrecognised key. | Fix the `schema` line, and remove or rename the unknown key. |
| `error     ... register: reviewed: expected a date written YYYY-MM-DD` | The review date is not a real calendar date in that form. | Write it as `2026-09-29`. |
| `warning   <file> cannot be read (...); its MCP servers are not checked` | An MCP declaration file is not valid JSON (comments and trailing commas are fine). | Fix the file; until then its servers are not compared. |
| `warning   <file> declares the MCP server "<name>", whose name cannot be registered; it is not checked` | The server name has characters a register id cannot hold. | Rename the server in the MCP file, or keep a note about it outside the register. |

<a id="examples"></a>
## Examples

<a id="example-cli-ai-register-inventory"></a>
### Inventory the AI tools and fill the register

Your team uses a coding assistant and two MCP servers, and nobody wrote down what they see.

**In your AI assistant**

```text
Shield, which AI tools touch this project’s data? Run the register check, create the register if there is none, and fill one entry per tool. Ask me for anything you cannot read in the repository instead of guessing it.
```

**What you should get** Shield runs `bmad-plus ai-register check`, lists the integrations found (adapter files, tool folders, MCP servers) and any it should ask about because they leave no trace in the repository, such as a model API called by your product. It runs `ai-register init`, replaces the template examples with one entry per tool, filling provider, purpose, data, retention and transfers from the provider’s terms and what the tool can read, and says so plainly when a fact is unknown. For entries with personal data it proposes a legal basis for you to decide. It finishes by running `check` again and reporting which integrations are registered, and any warning left.

<a id="example-cli-ai-register-before-dpia"></a>
### Check the register before a DPIA

You are about to run a data protection impact assessment on a feature that uses AI tooling.

**In your AI assistant**

```text
Shield, before we start the DPIA, check that the AI processing register is complete and reviewed. List any tool whose entry is missing, any entry without a legal basis, and anything last reviewed more than a year ago.
```

**What you should get** Shield runs `bmad-plus ai-register check` (read-only). It reports each `warning` line (tools set up but not registered, a review older than 365 days) and, if the register is invalid, each `error` line, which also means exit code 1. It then reads the register file for entries that would still need a decision, and points out that detection only sees what is configured in the repository. It does not fill in a legal basis for you; for a large-scale or novel processing it recommends carrying on with the DPIA workflow.

**See also**

- [CLI overview](https://bmad-plus.rochetta.fr/docs/reference/cli-overview/)
- [doctor: reports the same check as a warning](https://bmad-plus.rochetta.fr/docs/reference/cli-doctor/)
- [assurance: the other Shield evidence file](https://bmad-plus.rochetta.fr/docs/reference/cli-assurance/)
- [Adapters: the files the check looks for](https://bmad-plus.rochetta.fr/docs/reference/adapters/)

[BMAD+ documentation](https://bmad-plus.rochetta.fr/docs/) · [Reference](https://bmad-plus.rochetta.fr/docs/reference/)

[Source on GitHub](https://github.com/lrochetta/BMAD-PLUS)
