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

# Doctor checks

> Run every check the Tap Store runs, on your machine, with a fix under each failure.

`doctor` runs the checks a publish runs — the ones on your own files and the ones Tappify answers
— so a failure lands on your machine rather than on a release.

```bash theme={null}
tappify extension doctor
```

It prints one line per check and closes with a count. A line marked `✗` is an error and the
command exits non-zero; a line marked `!` is a warning, which is printed and does not stop a
release.

| Flag           | Does                                                              |
| -------------- | ----------------------------------------------------------------- |
| `--fix`        | Applies the fixes that cannot change behaviour                    |
| `--skip-build` | Leaves out everything that runs your own scripts or reads `dist/` |
| `--offline`    | Runs only the checks that need no network                         |

`--fix` names each edit it made and makes only three kinds: it adds the scopes your contributions
require, rewrites `src/tappify.d.ts`, and adds the `$schema` line. It never edits a component, a
schema or your listing. A scope owners read a reason for is added with a placeholder
justification, and `scopes.justification_placeholder` then holds the release until you have
written the real sentence.

## What stops a release

| Check                              | Fires when                                                                                                                                                                                                                                                                    | Fix                                                               |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `manifest.schema`                  | The manifest breaks the schema: a malformed field, a slot that is not on its page, a series naming a metric the connector does not declare, a public extension with an incomplete listing, an assistant `input` schema over 16 KB or carrying prose longer than a description | Fix the field the message names in `tappify.extension.json`       |
| `manifest.scopes`                  | A contribution needs a scope you have not declared                                                                                                                                                                                                                            | `tappify extension doctor --fix`, or remove the contribution      |
| `scopes.justification_placeholder` | A scope still carries the placeholder justification `--fix` wrote                                                                                                                                                                                                             | Write the reason owners should read before they grant it          |
| `sdk.served`                       | Your `sdk` range names no major Tappify serves                                                                                                                                                                                                                                | `tappify extension set sdk ^2.0.0` and rebuild against that major |
| `entry.missing`                    | A contribution's `entry` file is not on disk                                                                                                                                                                                                                                  | Create the file, or remove the contribution                       |
| `entry.default_export`             | The entry file has no default export                                                                                                                                                                                                                                          | Export the component as the file's default export                 |
| `icon.missing`                     | The icon the manifest names is not there                                                                                                                                                                                                                                      | Add the icon file, at most 512 KB                                 |
| `icon.too_large`                   | The icon is over 512 KB                                                                                                                                                                                                                                                       | Export it again under 512 KB                                      |
| `icon.not_square`                  | The icon is not square                                                                                                                                                                                                                                                        | Export it square; the Tap Store crops anything else               |
| `icon.unreadable`                  | The icon is neither a png nor an svg                                                                                                                                                                                                                                          | Save it as a png or an svg                                        |
| `schema.missing`                   | A `$ref` points at a file that is not there                                                                                                                                                                                                                                   | Create the schema file the manifest points at                     |
| `schema.invalid`                   | A schema file is not valid JSON                                                                                                                                                                                                                                               | Fix the JSON in the schema file                                   |
| `schema.cycle`                     | Two schema files `$ref` their way back to each other                                                                                                                                                                                                                          | Inline one of the two so the chain ends                           |
| `listing.screenshot_missing`       | `visibility` is `public` and a screenshot the listing names is not there                                                                                                                                                                                                      | Add the screenshot, or take it out of `listing.screenshots`       |
| `listing.screenshot_size`          | A screenshot is not 1600 by 1000                                                                                                                                                                                                                                              | Export it at 1600 by 1000                                         |
| `types.stale`                      | `src/tappify.d.ts` no longer matches the manifest and its schemas                                                                                                                                                                                                             | `tappify extension types`                                         |
| `typescript`                       | Your typecheck script failed                                                                                                                                                                                                                                                  | Fix the type errors the script printed                            |
| `tests`                            | Your test script failed                                                                                                                                                                                                                                                       | Fix the failing tests                                             |
| `build`                            | Your build script failed, or the project declares none                                                                                                                                                                                                                        | Fix the build errors the script printed                           |
| `bundle.remote_entry`              | `dist/` or `dist/remoteEntry.js` is not there                                                                                                                                                                                                                                 | Run your build script                                             |
| `bundle.size`                      | The build unpacks to over 25 MB, or the zip is over the 5 MB Tappify accepts                                                                                                                                                                                                  | Trim it; large images and bundled fonts are the usual cause       |
| `exposes`                          | The build carries no expose for a contribution you declared                                                                                                                                                                                                                   | Rebuild after adding the contribution's entry                     |
| `bundle.icon`                      | The icon sits outside the extension folder, or is neither a png nor an svg                                                                                                                                                                                                    | Point `icon` at a png or an svg inside this extension             |
| `bundle.storage_schemas`           | A schema file the manifest names sits outside the extension folder                                                                                                                                                                                                            | Move it inside and point the `$ref` at it there                   |
| `bundle.listing_assets`            | A screenshot sits outside the extension folder                                                                                                                                                                                                                                | Move it inside and point `listing.screenshots` at it there        |
| `bundle.path`                      | Another file the manifest names sits outside the extension folder                                                                                                                                                                                                             | Move it inside the extension                                      |
| `bundle.third_party_script`        | Built code loads a script from another origin                                                                                                                                                                                                                                 | Bundle the script; the host content policy blocks another origin  |
| `bundle.external_font`             | Built code loads a font from another origin                                                                                                                                                                                                                                   | Use the host `--font-*` variables instead                         |
| `bundle.css_asset`                 | The build emitted a stylesheet as its own file, which never reaches your shadow root                                                                                                                                                                                          | Import it from the component so the build inlines it              |
| `bundle.assistant_text`            | Bundled markdown the assistant reads matches instruction-override patterns                                                                                                                                                                                                    | Rewrite those files so they describe your product                 |
| `a11y`                             | The accessibility pass found violations                                                                                                                                                                                                                                       | Fix the axe violations the run printed                            |

Generate and check types with the registry reachable: offline, the generator leaves the host
event payloads out, and `types.stale` compares the file byte for byte, so a correct file written
online reads as stale under `--offline` and `--fix` rewrites it without those payload types.

## What it warns about

| Check                    | Fires when                                                                                                         | Fix                                                            |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- |
| `manifest.schema_url`    | The `$schema` line is missing, so your editor cannot validate or complete the manifest                             | `tappify extension doctor --fix`                               |
| `procedures.write_kind`  | A procedure whose name reads like a write has no `kind: "write"`                                                   | Add `"kind": "write"` so Tappify never retries it              |
| `lint`                   | Your lint script failed                                                                                            | Fix what the lint script reported                              |
| `bundle.size`            | `dist/` and the files the manifest names come to over 5 MB before compression, and 5 MB is the zip limit           | Trim it, or check that it compresses under the limit           |
| `bundle.style_injection` | Built code writes styles into the document, which leaks into the host and every other extension                    | Import the stylesheet from the component instead               |
| `a11y.unavailable`       | `axe-core` is not installed, so the accessibility pass did not run                                                 | Add `axe-core` to your dev dependencies                        |
| `registry.offline`       | The event catalogue came from the SDK, which does not know which events are published or what scope each one needs | Run the command again with the network up                      |
| `checks.unreachable`     | Tappify could not be reached, so its checks did not run                                                            | Run it again online, or pass `--offline` to leave them out     |
| `checks.refused`         | Tappify would not run its checks for this extension                                                                | Run `tappify login`, or publish once to register the extension |

`--skip-build` leaves the accessibility pass out, and Tappify's own note that it cannot run the
pass without a browser comes back as an `a11y` warning in its place.

## The checks Tappify answers

`doctor` sends your manifest, along with the expose list your last build produced, and folds the
answers into the same checklist. A rule that runs in both places is reported once. What only
Tappify can answer is this, and every one of them stops a release except `storage.pii`, which is a
warning:

| Check                     | Fires when                                                                                               | Fix                                                                          |
| ------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `manifest.id.reserved`    | Your id collides with a Tappify route                                                                    | `tappify extension set id <new-id>`; the id is fixed after the first publish |
| `scopes.security_review`  | A scope you declared cannot go live until your vendor account passes a security review                   | Ask Tappify to run one, or drop the scope                                    |
| `assistant_text.override` | A tool, action, mention, skill or prompt description matches instruction-override patterns               | Rewrite the description so it describes your product                         |
| `storage.pii`             | A storage collection declares a personal field, and a reviewer reads that collection before it goes live | Take the field out of the schema, or keep it on your own server              |

Every one of them is on
[Review and what gets checked](/extensions/publish/review), with what a reviewer looks for
alongside.

`--offline` leaves that half out and reads the registry it last cached. `publish` runs `doctor`
itself before it uploads, without your build, lint, tests and accessibility pass — it has just run
your build — and `--skip-doctor` leaves even that out; the second line of the publish output says
which happened.

One check belongs to `publish` alone: it asks `<base url>/tappify/health` for a 200 within three
seconds, on every base url your manifest declares, and stops there if one does not answer. See
[Deploy your server](/extensions/build/deploy-your-server).
