The limits below are constants in the code, not configurable values. Local and resolution limits end execution with code 1; the device API can also reject requests with its own errors, such as limit or rate-limit errors.
#Complete limits table
| Limit | Value | Where |
|---|---|---|
| GitHub HTTP response | 10 MiB (10485760 bytes) | cli/src/runtime.ts |
| Aggregate size per skill | 5 MiB (5242880 bytes) | cli/src/runtime.ts |
| Resolved GitHub files per skill | 200 | cli/src/runtime.ts |
| Inline files per skill | 1–200 | packages/core/src/maleta.ts |
| Timeout per request | 10 s (10000 ms) | cli/src/runtime.ts |
| Device API request timeout | 15 s (15000 ms) | cli/src/deviceApi.ts |
| Minimum interval between polls | 10 s (10000 ms) | cli/src/deviceApi.ts and site/lib/device.ts |
| Server-provided polling cadence | 30 s (30000 ms) | cli/src/deviceApi.ts and site/lib/device.ts |
| Device API backoff ceiling | 5 min (300000 ms) | cli/src/deviceApi.ts |
| Authorization code lifetime | 10 min (600000 ms) | cli/src/deviceApi.ts and site/lib/device.ts |
| Devices per user | 20 | site/lib/device.ts |
| Cloud Maletas per user | 3 | site/lib/cloudMaleta.ts |
| Locally saved Maletas (browser) | 50 (aggregate 2 MiB) | site/lib/maletaStorage.ts |
| Cloud Maleta request envelope | 1049600 bytes (1 MiB + 1024 bytes) | site/lib/cloudMaleta.ts |
| Cloud Maleta client timeout | 15 s (15000 ms) | site/lib/cloudMaletaClient.ts |
| Authorization requests per IP and window | 10 in 10 min | site/lib/device.ts |
| Device API request body | 8 KiB (8192 UTF-8 bytes) | site/lib/device.ts |
| Binding status detail | 300 characters | site/lib/device.ts |
maleta.json as string input | 1 MiB (1048576 UTF-8 bytes) | packages/core/src/maleta.ts |
skills[] | 500 entries | packages/core/src/maleta.ts |
plugins[] | 200 entries | packages/core/src/maleta.ts |
name | 80 characters | packages/core/src/maleta.ts |
slug | 96 characters | packages/core/src/maleta.ts |
description | 600 characters | packages/core/src/maleta.ts |
source.path | 240 characters | packages/core/src/maleta.ts |
source.ref | 160 characters | packages/core/src/maleta.ts |
Inline files have no separate byte limit. Their content, paths, and JSON escaping all consume the complete maleta.json limit of 1 MiB (1048576 UTF-8 bytes), so that document cap is the inline content budget.
The HTTP response limit is applied twice: first using content-length, then using the actual size of the body read. Exceeding it results in download exceeded maximum size (10485760 bytes). The aggregate per-skill limit is checked file by file as the tree is traversed and results in skill exceeded maximum size (5242880 bytes).
#How each limit fails
| Condition | Message |
|---|---|
| Response body over 10 MiB | download exceeded maximum size (10485760 bytes) |
| More than 200 files in the resolved tree | skill exceeded maximum file count (200) |
Inline files is not an array or has fewer than 1 or more than 200 entries | Invalid files for skill "<name>" |
| Combined file size over 5 MiB | skill exceeded maximum size (5242880 bytes) |
| Individual file over 5 MiB | skill file exceeded maximum size (5242880 bytes) (or skill file exceeded maximum size: <path> when the listing already reports the size) |
| Directory listing at the GitHub API cap | directory listing reached the GitHub API limit (1000 entries): <dir>; split the skill into a smaller directory |
No uppercase SKILL.md at the resolved root | skill path not found: <path> (uppercase SKILL.md is required at the skill root) |
GitHub 401 (bad or missing token) | GitHub authentication failed; check GITHUB_TOKEN |
GitHub 403 with x-ratelimit-remaining: 0 | GitHub rate limit exceeded; retry after <reset>; set GITHUB_TOKEN to increase the limit |
GitHub 403 without a rate-limit exhaustion | GitHub access denied; check repository access and GITHUB_TOKEN |
GitHub 404 (diagnosed repository, ref, or path) | GitHub repository not found: <repo>; if this is a private repo, set GITHUB_TOKEN, GitHub ref not found: <ref> or GitHub skill path not found: <path> |
| Request stopped by the 10 s timeout | network timeout |
maleta.json over 1 MiB | Maleta file is too large |
skills[] over 500 entries | Invalid skill list |
plugins[] over 200 entries | Invalid plugin list |
| More than 3 Cloud Maletas on account | You reached the limit of 3 Maletas on the account |
| Cloud Maleta document over 1 MiB | Maleta too large. The limit is 1 MB |
#GitHub resolution: no retries and no automatic waiting
GitHub skill resolution never retries or waits: each request has a 10-second timeout and, if it fails, the error propagates immediately. The rate-limit headers are read to name the situation, not to sleep and retry. For a 404, the CLI makes separate diagnostic requests — described below — and never retries the same request. The device flow is different: it honors the server cadence and caps backoff at 5 minutes.
- Failures are named distinctively:
401printsGitHub authentication failed; check GITHUB_TOKEN;403withx-ratelimit-remaining: 0prints the reset time andset GITHUB_TOKEN to increase the limit; any other403printsGitHub access denied; check repository access and GITHUB_TOKEN; a404on a private repository printsif this is a private repo, set GITHUB_TOKEN. - The CLI reads those headers but never waits before another attempt.
- A
404is not retried: the CLI makes diagnostic requests to distinguish a missing repository, ref, or skill path, and reports the most specific one. - Other statuses outside
2xxbecomeGitHub request failed (HTTP <status>). A transport failure keeps the real cause (for exampleGitHub request failed: fetch failed: DNS lookup failed), with any token-looking value replaced by[redacted]. - The only way to work around a rate limit is to set
GITHUB_TOKENand run the command again manually.