> ## 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.

# Storage limits and rate limits

> Every size and rate an extension is held to, and what happens at each ceiling.

This is the reference for the ceilings the host and the manifest schema enforce. Limits are per
install unless a row says otherwise. Crossing one returns an error with a code you can act on,
never a silent truncation.

## Hosted storage

| Limit                                  | Value  | At the ceiling                |
| -------------------------------------- | ------ | ----------------------------- |
| One document                           | 256 KB | `STORAGE_DOCUMENT_TOO_LARGE`  |
| Documents per collection per scope key | 1,000  | `STORAGE_COLLECTION_FULL`     |
| Total per install                      | 50 MB  | `STORAGE_QUOTA_EXCEEDED`      |
| Collections per manifest               | 10     | The manifest fails validation |

The scope key is the user id for a `user` collection, the literal `install` for an `install`
one, and the organization id for an `organization` one, so three owners of the same install each
get their own thousand documents in a `user` collection. Overwriting a document frees the bytes
it replaces before the 50 MB is measured.

## Procedures

| Limit                   | Value      | At the ceiling                |
| ----------------------- | ---------- | ----------------------------- |
| Time to answer          | 30 seconds | `PROCEDURE_TIMEOUT`           |
| Request body            | 1 MB       | `PROCEDURE_PAYLOAD_TOO_LARGE` |
| Response body           | 1 MB       | `PROCEDURE_PAYLOAD_TOO_LARGE` |
| Procedures per manifest | 30         | The manifest fails validation |

`kind: "read"` is retried twice when the connection fails. `kind: "write"` is never retried, and
neither kind is retried after a timeout or an oversized answer — the window is already spent and
the answer would be oversized again.

## Rates

Counted in a fixed window, per install unless the row says otherwise:

| Surface                  | Limit          | Counted per |
| ------------------------ | -------------- | ----------- |
| Data API queries         | 120 per minute | install     |
| Storage reads and writes | 300 per minute | install     |
| Procedure calls          | 120 per minute | install     |
| Telemetry events         | 60 per minute  | install     |
| Install token mints      | 30 per minute  | user        |
| Publishes                | 30 per day     | extension   |
| Inbound webhooks         | 60 per minute  | install     |
| Alerts                   | 3 per day      | project     |
| Action runs              | 200 per day    | project     |

Over a rate, the call returns `RATE_LIMIT_EXCEEDED` with the surface and the window in the
message. The data hooks cache and dedupe across mounts, so two widgets asking for the same
series in the same range spend one query.

An organization-scoped install has no project, so the workspace stands in for one on the two
project rows. The alert ceiling refuses differently from the others: a fourth alert in a day is
stored and marked rate-limited rather than answered with an error, and the owner is not told. An
action run is counted when the run is created, so a run the owner rejects spends one.

## The manifest

| Field                                | Limit                                                                                                               |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `id`                                 | 3 to 40 characters, lowercase letters, digits and dashes, starting with a letter. Immutable after the first publish |
| `name`                               | 2 to 40 characters                                                                                                  |
| `description`                        | 10 to 200 characters                                                                                                |
| `icon`                               | A path inside the extension, at most 200 characters                                                                 |
| `listing.longDescription`            | 5,000 characters                                                                                                    |
| `listing.screenshots`                | 1 to 6 paths                                                                                                        |
| Scope justification                  | 20 to 500 characters                                                                                                |
| UI contributions, all kinds together | 20                                                                                                                  |
| Each contribution list on its own    | 20                                                                                                                  |
| Contribution ids                     | 2 to 40 characters, lowercase letters, digits and dashes, starting with a letter                                    |
| Titles and labels                    | 60 characters                                                                                                       |
| Storage collections                  | 10                                                                                                                  |
| Procedures                           | 30, names at most 60 characters                                                                                     |
| Tools                                | 15                                                                                                                  |
| Mentions                             | 10                                                                                                                  |
| Actions                              | 10                                                                                                                  |
| Knowledge files                      | 20                                                                                                                  |
| Skills                               | 5, each naming at most 15 tools                                                                                     |
| Prompt templates                     | 20, each template 2,000 characters                                                                                  |
| Context providers                    | 3                                                                                                                   |
| Connector metrics                    | 50, each with at most 10 dimensions                                                                                 |
| Connector credential fields          | 20                                                                                                                  |
| Telemetry names                      | 20, `snake_case`, each at most 60 characters                                                                        |
| Marker glyph                         | 2 characters                                                                                                        |
| `backfillDays`                       | 90                                                                                                                  |

Every one of these is a schema rule, so breaking one fails the `manifest.schema` check in
`tappify extension doctor` and again at publish.

## The files the manifest points at

The manifest holds the path; the file itself is measured, so these report their own check ids
rather than `manifest.schema`.

| File                             | Limit               | Check                                                                 |
| -------------------------------- | ------------------- | --------------------------------------------------------------------- |
| `icon`                           | 512 KB              | `icon.too_large` locally, `bundle.icon` at publish                    |
| `icon`                           | Square              | `icon.not_square` locally, `bundle.icon` at publish                   |
| `icon`                           | A png or an svg     | `icon.unreadable` locally, `bundle.icon` at publish                   |
| Each `listing.screenshots` entry | A png, 1600 by 1000 | `listing.screenshot_size` locally, `bundle.listing_assets` at publish |

The screenshots are measured only while `visibility` is `public`, by `doctor` and at publish
alike, so a private extension learns about a wrong size on the publish that makes it public.

Release notes are capped at 1,000 characters too, and that one is neither a schema rule nor a
check: `tappify extension publish` refuses a longer `--notes` before it sends anything.

## The bundle and the runtime

| Limit                           | Value                                                                                        |
| ------------------------------- | -------------------------------------------------------------------------------------------- |
| Bundle zip                      | 5 MB                                                                                         |
| Bundle unpacked                 | Capped; the failure message names the size and the limit                                     |
| Remote entry load               | 8 seconds, then the failure card                                                             |
| Remote loads in flight per page | 3                                                                                            |
| Install token lifetime          | 5 minutes, refreshed by the host every 4                                                     |
| Health check response           | 200 within 3 seconds, on `server.baseUrl` and on `server.sandboxBaseUrl` when you declare it |
| Event poll                      | Every 15 seconds, at most 100 events a page                                                  |
| Documents kept after retirement | 30 days                                                                                      |
| Health check sweep              | Every 15 minutes, per live release that declares a server                                    |
| Connector sync retries          | 3, backing off 30 seconds, 2 minutes, 10 minutes                                             |
| Event delivery retries          | 3, on the same backoff, for a 5xx or an unreachable server                                   |
| A metric with no sync           | Stale after 24 hours                                                                         |

A redirect from a health check counts as a failure. An event subscription starts from the moment
your mount subscribes, so a widget never receives the backlog of a quiet week. All four attempts of
a sync are one run, and a stale metric keeps its stored points — its line is drawn dashed with the
time of the last sync.

## Limits on the assistant surfaces

How many tools, mentions, actions, skills, prompts and context providers you may declare is in
the manifest table above. These are the ceilings on what each one may spend, and on how much of
your text the assistant reads.

| Limit                                                   | Value                                             | At the ceiling                                                                   |
| ------------------------------------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------- |
| Tool calls                                              | 600 per hour per project                          | `RATE_LIMIT_EXCEEDED`                                                            |
| Time to answer a tool call                              | 30 seconds, and it is never retried               | `PROCEDURE_TIMEOUT`                                                              |
| Tool response body                                      | 1 MB                                              | `PROCEDURE_PAYLOAD_TOO_LARGE`                                                    |
| Tool `cache`, and context provider `cache`              | `1m`, `5m` or `1h`                                | The manifest fails validation                                                    |
| Tool description, as the assistant reads it             | 400 characters                                    | Cut, with an ellipsis                                                            |
| Tool answer, as the assistant reads it                  | 8,192 characters                                  | Cut, with an ellipsis; the card the host draws keeps the whole answer            |
| Tool or action `input` schema                           | 16 KB serialised                                  | The manifest fails validation, in `doctor` and again at publish                  |
| A `title` or `description` inside an `input` schema     | 500 characters, and 400 as the assistant reads it | The manifest fails validation; what the assistant reads is cut, with an ellipsis |
| Mention items per answer                                | 20, each label 80 characters                      | The rest are dropped                                                             |
| Context provider block                                  | 2 KB once rendered                                | `data` dropped, then the prose trimmed                                           |
| Context provider description on the block's label line  | 300 characters                                    | Cut, with an ellipsis                                                            |
| Time a context provider has to answer                   | 3 seconds                                         | The block is dropped, and the provider is skipped for a minute                   |
| Skill file                                              | 4,000 words                                       | The publish fails with `bundle.skill_size`                                       |
| Skill name and description, as the assistant reads them | 60 and 200 characters                             | Cut, with an ellipsis                                                            |
| Knowledge chunks retrieved per turn                     | 3, each 1,000 characters                          | The rest are not retrieved                                                       |
| Knowledge title, as the assistant reads it              | 120 characters                                    | Cut, with an ellipsis                                                            |
| The message a knowledge search is run on                | 1,000 characters, and words over 64 are dropped   | The rest is not searched on                                                      |
| A prompt chip's resolved question                       | 500 characters                                    | Cut, with an ellipsis                                                            |
| Vendor prompt chips per suggestion row                  | 2                                                 | The rest are not offered                                                         |
| Vendor text in one turn, across every extension         | 8 KB                                              | Whole blocks are dropped, never half of one                                      |

The 8 KB is shared: blocks are added in the order Tappify built them, and the first one that would
cross the budget is dropped along with every block after it. That is why a knowledge file with a
long heading, or a context provider that returns everything it has, costs another extension its
place in the turn.

<Card title="Errors" icon="triangle-exclamation" href="/extensions/reference/errors">
  Every code a ceiling returns, and what to do about it.
</Card>
