From a68c156890f2e6ec5414b1dae3d4d0861ba84dcf Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Sun, 11 Oct 2026 15:38:30 +0100 Subject: [PATCH 01/21] Label LPM CLI's byte sizes in binary units LPM CLI prints sizes counted in 1024s as KiB, MiB and GiB (lpm-dev/rust-client: label byte sizes in binary units). Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/store.mdx | 2 +- content/docs/reference/exit-codes.mdx | 2 +- content/docs/reference/terminal-output.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/docs/infra/store.mdx b/content/docs/infra/store.mdx index 5861aff3..8b7de497 100644 --- a/content/docs/infra/store.mdx +++ b/content/docs/infra/store.mdx @@ -289,7 +289,7 @@ lpm store clean --json { "success": true, "removed_bytes": 1048576, - "removed": "1.0 MB", + "removed": "1.0 MiB", "path": "/Users/you/.lpm/store/v1", "v1_path": "/Users/you/.lpm/store/v1", "v2_path": "/Users/you/.lpm/store/v2", diff --git a/content/docs/reference/exit-codes.mdx b/content/docs/reference/exit-codes.mdx index 06d2d667..78521838 100644 --- a/content/docs/reference/exit-codes.mdx +++ b/content/docs/reference/exit-codes.mdx @@ -105,7 +105,7 @@ A failed operation does not always emit the shared error envelope: | [lpm exec](/docs/dev/exec), [lpm dlx](/docs/dev/dlx), and direct source-file execution | Child I/O passes through. `--json` does not add a CLI result envelope. | | [lpm audit](/docs/packages/audit), [lpm tidy](/docs/packages/tidy), and [lpm doctor](/docs/infra/doctor) | Command report plus a status that reflects the selected failure conditions. | -Tool results omit successful child logs and truncate included failed streams at 10 MB each. +Tool results omit successful child logs and truncate included failed streams at 10 MiB each. An `exit_code: null` with an `error` means the member could not start or prepare its tool. A command can complete its checks but report findings. For example, doctor can return a completed report with `success: true` and exit `1`. diff --git a/content/docs/reference/terminal-output.mdx b/content/docs/reference/terminal-output.mdx index b07a62a8..30384cb2 100644 --- a/content/docs/reference/terminal-output.mdx +++ b/content/docs/reference/terminal-output.mdx @@ -62,7 +62,7 @@ JSON serialization preserves the semantic values of included strings. It escapes It does not remove terminal commands from those strings. This does not guarantee a complete copy of child output. A command can omit successful logs or truncate captured failures. -For example, workspace tool results include failed output with a 10 MB limit per stream. +For example, workspace tool results include failed output with a 10 MiB limit per stream. Parse JSON before you use its fields. If your program later displays a parsed string in a terminal, sanitize that string at display time. From 677b3803b4429430dc847a2a16b9ad0ca1bf8b64 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Sun, 11 Oct 2026 15:38:30 +0100 Subject: [PATCH 02/21] Refresh CLI output documentation dates Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/generated/content-dates.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 8ed26fec..78005758 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -233,7 +233,7 @@ }, "infra/store.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-09-20T03:12:34+01:00" + "modified": "2026-10-11T15:38:30+01:00" }, "infra/token-rotate.mdx": { "published": "2026-06-16T23:33:51+01:00", @@ -461,7 +461,7 @@ }, "reference/exit-codes.mdx": { "published": "2026-04-20T23:50:31+01:00", - "modified": "2026-09-20T19:20:28+01:00" + "modified": "2026-10-11T15:38:30+01:00" }, "reference/glossary.mdx": { "published": "2026-04-20T23:50:31+01:00", @@ -501,7 +501,7 @@ }, "reference/terminal-output.mdx": { "published": "2026-07-22T19:51:43+01:00", - "modified": "2026-09-20T19:20:27+01:00" + "modified": "2026-10-11T15:38:30+01:00" }, "registries.mdx": { "published": "2026-05-01T13:51:26+01:00", From f443aa48787a3f07e22cce74bffa39deefe30596 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Mon, 12 Oct 2026 13:47:31 +0100 Subject: [PATCH 03/21] Show an exact size as a whole number in the store clean example Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/store.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/infra/store.mdx b/content/docs/infra/store.mdx index 8b7de497..05c9a496 100644 --- a/content/docs/infra/store.mdx +++ b/content/docs/infra/store.mdx @@ -289,7 +289,7 @@ lpm store clean --json { "success": true, "removed_bytes": 1048576, - "removed": "1.0 MiB", + "removed": "1 MiB", "path": "/Users/you/.lpm/store/v1", "v1_path": "/Users/you/.lpm/store/v1", "v2_path": "/Users/you/.lpm/store/v2", From bd9833e9996c361ba389127595b757a502087787 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Mon, 12 Oct 2026 13:47:31 +0100 Subject: [PATCH 04/21] chore: update content dates Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/generated/content-dates.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 78005758..4bcdd945 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -233,7 +233,7 @@ }, "infra/store.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-11T15:38:30+01:00" + "modified": "2026-10-12T13:47:31+01:00" }, "infra/token-rotate.mdx": { "published": "2026-06-16T23:33:51+01:00", From 82850b1cabdb1702b861c7dbc3b5d34f1c444b0e Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Mon, 12 Oct 2026 19:38:45 +0100 Subject: [PATCH 05/21] docs: whoami's storage overage states, and the lpm.dev tarball check Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 8 ++++++++ content/docs/packages/publish.mdx | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index 1dc8fe0f..5e603e71 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -193,6 +193,14 @@ lpm whoami --json The command checks the selected LPM-compatible registry account. Output includes plan, MFA, Pool access, usage, scopes, credential sources, expiry warnings, and storage health. +Usage past a limit reads as past it, rounded up. Past the storage limit, the output says what publishing does, as the registry reports it: + +- **Billed:** storage past the included size is billed per GiB a month, rounded up. +- **Paused:** billing is past due, so publishing past the limit is refused until the payment succeeds. +- **Blocked:** the plan doesn't bill storage overage, as on Hobby, so publishing is restricted until you upgrade. + +A registry that doesn't report it gets no claim either way: the output says only that the storage is past the included size. JSON reports it as `storage_overage`. + Human output masks the email address. JSON includes the full address. The third-party registry list reports credential availability; it does not test each credential with its provider. diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index bd4169dc..e4dd592a 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -243,7 +243,7 @@ Run [`lpm install`](/docs/packages/install) before publication. Missing bundles, | Encoded archive path | 32 KiB | | Path components, including `package/` | 256 | -The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts uploads up to 100 MiB. Other registries can impose smaller limits. +The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, so a publish that includes it refuses a larger one before any target is published. Other registries can impose smaller limits. ## Credentials and OTP From 43e4cde023c4eadeb44bf08e799448135ac193e2 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Mon, 12 Oct 2026 19:38:45 +0100 Subject: [PATCH 06/21] chore: update content dates --- lib/generated/content-dates.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 4bcdd945..e2c1ee42 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-09-20T00:17:59+01:00" + "modified": "2026-10-12T19:38:45+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-09-18T23:56:31+01:00" + "modified": "2026-10-12T19:38:45+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", From 31aad0ca1de5063649b6de414fb059cf6b3decc4 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Mon, 12 Oct 2026 22:47:48 +0100 Subject: [PATCH 07/21] docs: whoami's storage states as the registry decides them, and lpm.dev's request limit before any target publishes Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 6 +++--- content/docs/packages/publish.mdx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index 5e603e71..fc7134ee 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -196,10 +196,10 @@ The command checks the selected LPM-compatible registry account. Output includes Usage past a limit reads as past it, rounded up. Past the storage limit, the output says what publishing does, as the registry reports it: - **Billed:** storage past the included size is billed per GiB a month, rounded up. -- **Paused:** billing is past due, so publishing past the limit is refused until the payment succeeds. -- **Blocked:** the plan doesn't bill storage overage, as on Hobby, so publishing is restricted until you upgrade. +- **Paused:** billing isn't active, so publishing past the limit is refused until it is again. +- **Blocked:** nothing bills storage past the limit. On Hobby, publishing is restricted until you upgrade; on Pro without a subscription, until you subscribe. -A registry that doesn't report it gets no claim either way: the output says only that the storage is past the included size. JSON reports it as `storage_overage`. +A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does; for other plans the output says only that the storage is past the limit. JSON reports what the registry sent as `storage_overage`. Human output masks the email address. JSON includes the full address. diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index e4dd592a..6b575328 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -243,7 +243,7 @@ Run [`lpm install`](/docs/packages/install) before publication. Missing bundles, | Encoded archive path | 32 KiB | | Path components, including `package/` | 256 | -The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, so a publish that includes it refuses a larger one before any target is published. Other registries can impose smaller limits. +The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds a bundle of a few kilobytes as LPM.dev publishes, which that check doesn't count. Other registries can impose smaller limits. ## Credentials and OTP From 8b97992ecfc1f28b99852321fe7696076a8ab45e Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Mon, 12 Oct 2026 22:47:49 +0100 Subject: [PATCH 08/21] chore: update content dates Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/generated/content-dates.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index e2c1ee42..4b7614ea 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-10-12T19:38:45+01:00" + "modified": "2026-10-12T22:47:48+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-12T19:38:45+01:00" + "modified": "2026-10-12T22:47:48+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", From 27402dd36d1df22a9aa06f232863c761f6c37d29 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 02:44:28 +0100 Subject: [PATCH 09/21] docs: whoami's exempt storage and refusals, the provenance reserve, the multi-target storage check, and release's member-by-member checks Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 6 ++++-- content/docs/packages/publish.mdx | 2 +- content/docs/packages/release.mdx | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index fc7134ee..4123badb 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -193,11 +193,13 @@ lpm whoami --json The command checks the selected LPM-compatible registry account. Output includes plan, MFA, Pool access, usage, scopes, credential sources, expiry warnings, and storage health. -Usage past a limit reads as past it, rounded up. Past the storage limit, the output says what publishing does, as the registry reports it: +Usage past a limit reads as past it, rounded up. On Hobby, storage in packages whose sales exempt them doesn't count toward the limit; the output shows the storage the limit counts, and the exempt storage on a line of its own. Past the storage limit, the output says what publishing does, as the registry reports it: - **Billed:** storage past the included size is billed per GiB a month, rounded up. - **Paused:** billing isn't active, so publishing past the limit is refused until it is again. -- **Blocked:** nothing bills storage past the limit. On Hobby, publishing is restricted until you upgrade; on Pro without a subscription, until you subscribe. +- **Blocked:** nothing bills storage past the limit, so publishing to your personal scope past it is refused: on Hobby until you upgrade, and on a Pro plan without a subscription, as staff grant one, for as long as the storage stays past it. + +Past the private-package limit, the output says new private packages in your personal scope are refused. A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does; for other plans the output says only that the storage is past the limit. JSON reports what the registry sent as `storage_overage`. diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index 6b575328..3d595709 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -243,7 +243,7 @@ Run [`lpm install`](/docs/packages/install) before publication. Missing bundles, | Encoded archive path | 32 KiB | | Path components, including `package/` | 256 | -The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds a bundle of a few kilobytes as LPM.dev publishes, which that check doesn't count. Other registries can impose smaller limits. +The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice as LPM.dev publishes, about 10 KB each, so that check keeps 1 MiB of the limit free for it. Other registries can impose smaller limits. A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent, and stops before any target publishes when it refuses the account's storage; any other refusal, as for a version it already has, is left to its own upload. ## Credentials and OTP diff --git a/content/docs/packages/release.mdx b/content/docs/packages/release.mdx index 4d196220..60b08298 100644 --- a/content/docs/packages/release.mdx +++ b/content/docs/packages/release.mdx @@ -189,6 +189,8 @@ lpm release publish --all --lpm --otp 123456 --yes For LPM.dev Registry, `--otp` supplies the same six-digit authenticator code to each package. Use a fresh code before it expires. +Members publish one at a time, each prepared and checked as the release reaches it. A member refused before its upload, as for its size or a secret its files hold, stops the release after the members already published. Run with `--dry-run` first to prepare and check every member without uploading. + ### Lifecycle scripts Publishing can run these scripts from each selected member: From b74cba67e33e4aa867ad0216d6c03acacf255f4a Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 02:44:28 +0100 Subject: [PATCH 10/21] chore: update content dates Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/generated/content-dates.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 4b7614ea..2baac1fb 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-10-12T22:47:48+01:00" + "modified": "2026-10-13T02:44:28+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-12T22:47:48+01:00" + "modified": "2026-10-13T02:44:28+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", @@ -369,7 +369,7 @@ }, "packages/release.mdx": { "published": "2026-07-03T10:46:26+01:00", - "modified": "2026-09-17T21:19:46+01:00" + "modified": "2026-10-13T02:44:28+01:00" }, "packages/remove.mdx": { "published": "2026-05-01T09:47:04+01:00", From 4a7041e4b7b94132325475da3fc7ee07f710d6ab Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 04:54:32 +0100 Subject: [PATCH 11/21] docs: lpm.dev stops every target on any refusal it keeps, release dry runs don't check storage, and whoami at the limit Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 6 +++--- content/docs/packages/publish.mdx | 2 +- content/docs/packages/release.mdx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index 4123badb..84909dd1 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -193,15 +193,15 @@ lpm whoami --json The command checks the selected LPM-compatible registry account. Output includes plan, MFA, Pool access, usage, scopes, credential sources, expiry warnings, and storage health. -Usage past a limit reads as past it, rounded up. On Hobby, storage in packages whose sales exempt them doesn't count toward the limit; the output shows the storage the limit counts, and the exempt storage on a line of its own. Past the storage limit, the output says what publishing does, as the registry reports it: +Usage past a limit reads as past it, rounded up. On Hobby, the tarballs of packages whose sales exempt them don't count toward the limit, though their READMEs, docs and Swift source archives do; the output shows the storage the limit counts, and the exempt tarballs on a line of their own. Past the storage limit, the output says what publishing does, as the registry reports it: - **Billed:** storage past the included size is billed per GiB a month, rounded up. - **Paused:** billing isn't active, so publishing past the limit is refused until it is again. - **Blocked:** nothing bills storage past the limit, so publishing to your personal scope past it is refused: on Hobby until you upgrade, and on a Pro plan without a subscription, as staff grant one, for as long as the storage stays past it. -Past the private-package limit, the output says new private packages in your personal scope are refused. +At the storage limit, where any publish goes past it, the output says so where publishing is refused. At or past the private-package limit, it says new private packages in your personal scope are refused. -A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does; for other plans the output says only that the storage is past the limit. JSON reports what the registry sent as `storage_overage`. +A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does; for other plans the output says only that the storage is past the limit. A registry that doesn't report the storage the limit counts has its whole storage compared, exempt tarballs included. JSON reports what the registry sent as `storage_overage`, and the storage the limit counts as `usage.counted_storage_bytes`. Human output masks the email address. JSON includes the full address. diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index 3d595709..c4d2ae4b 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -243,7 +243,7 @@ Run [`lpm install`](/docs/packages/install) before publication. Missing bundles, | Encoded archive path | 32 KiB | | Path components, including `package/` | 256 | -The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice as LPM.dev publishes, about 10 KB each, so that check keeps 1 MiB of the limit free for it. Other registries can impose smaller limits. A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent, and stops before any target publishes when it refuses the account's storage; any other refusal, as for a version it already has, is left to its own upload. +The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice as LPM.dev publishes, about 10 KB each, so that check keeps 1 MiB of the limit free for it. Other registries can impose smaller limits. A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent, and stops before any target publishes when it refuses the publish for good: for the account's storage, private-package limit or billing, a second factor it requires, the tarball's size, or the token's permission. A version it already has, as after a partial publish, a rate limit or a server error is left to each target's own upload; a rate limit, a timeout or a server error is retried first. The question counts the tarball, while LPM.dev Registry also stores the README and docs it derives from it, and a Swift package's source archive, so a publish within that much of the limit can still be refused at its upload. `--dry-run` asks the same question and fails on any refusal. ## Credentials and OTP diff --git a/content/docs/packages/release.mdx b/content/docs/packages/release.mdx index 60b08298..185233e5 100644 --- a/content/docs/packages/release.mdx +++ b/content/docs/packages/release.mdx @@ -189,7 +189,7 @@ lpm release publish --all --lpm --otp 123456 --yes For LPM.dev Registry, `--otp` supplies the same six-digit authenticator code to each package. Use a fresh code before it expires. -Members publish one at a time, each prepared and checked as the release reaches it. A member refused before its upload, as for its size or a secret its files hold, stops the release after the members already published. Run with `--dry-run` first to prepare and check every member without uploading. +Members publish one at a time, each prepared and checked as the release reaches it. A member refused, before its upload or by it, as for its size, a secret its files hold, or LPM.dev Registry's storage, stops the release after the members already published. `--dry-run` prepares every member and checks each target's version without uploading, but doesn't ask LPM.dev Registry about storage, which each member's upload adds to, so a release a dry run passes can still stop part way. ### Lifecycle scripts From b48df97c73f33e58ed77bc26bf74c141f935c583 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 04:54:33 +0100 Subject: [PATCH 12/21] chore: update content dates Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/generated/content-dates.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 2baac1fb..7f6223cb 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-10-13T02:44:28+01:00" + "modified": "2026-10-13T04:54:32+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-13T02:44:28+01:00" + "modified": "2026-10-13T04:54:32+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", @@ -369,7 +369,7 @@ }, "packages/release.mdx": { "published": "2026-07-03T10:46:26+01:00", - "modified": "2026-10-13T02:44:28+01:00" + "modified": "2026-10-13T04:54:32+01:00" }, "packages/remove.mdx": { "published": "2026-05-01T09:47:04+01:00", From 4e3383dfce99dafbde3c8f1a28348a2fd9151b73 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 08:45:49 +0100 Subject: [PATCH 13/21] docs: what stops every target, the second factor settled first, release refusals' error codes, and whoami's billed storage Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 8 ++++---- content/docs/packages/publish.mdx | 2 +- content/docs/packages/release.mdx | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index 84909dd1..03da4691 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -195,13 +195,13 @@ The command checks the selected LPM-compatible registry account. Output includes Usage past a limit reads as past it, rounded up. On Hobby, the tarballs of packages whose sales exempt them don't count toward the limit, though their READMEs, docs and Swift source archives do; the output shows the storage the limit counts, and the exempt tarballs on a line of their own. Past the storage limit, the output says what publishing does, as the registry reports it: -- **Billed:** storage past the included size is billed per GiB a month, rounded up. -- **Paused:** billing isn't active, so publishing past the limit is refused until it is again. -- **Blocked:** nothing bills storage past the limit, so publishing to your personal scope past it is refused: on Hobby until you upgrade, and on a Pro plan without a subscription, as staff grant one, for as long as the storage stays past it. +- **Billed:** storage past the included size is billed per GiB a month, rounded up. The output says so at the limit too, where the next publish starts it. +- **Paused:** billing isn't active, so publishing past the limit is refused until it is again. Storage already past it is still billed while a failed payment is retried, and isn't while the subscription is paused or has ended; past the limit, the output says which, where the registry reports it. +- **Blocked:** nothing bills storage past the limit, so publishing to your personal scope past it is refused: on Hobby until you upgrade or delete enough to bring it under the limit, and on a Pro plan without a subscription, as staff grant one, for as long as the storage stays past it. At the storage limit, where any publish goes past it, the output says so where publishing is refused. At or past the private-package limit, it says new private packages in your personal scope are refused. -A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does; for other plans the output says only that the storage is past the limit. A registry that doesn't report the storage the limit counts has its whole storage compared, exempt tarballs included. JSON reports what the registry sent as `storage_overage`, and the storage the limit counts as `usage.counted_storage_bytes`. +A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does; for other plans the output says only that the storage is past the limit. A registry that doesn't report the storage the limit counts has its whole storage compared, exempt tarballs included. JSON reports what the registry sent: what publishing does past the limit as `storage_overage`, whether storage already past it is billed meanwhile as `storage_excess_billed`, and the storage the limit counts as `usage.counted_storage_bytes`. Each is `null` where the registry doesn't send it. Human output masks the email address. JSON includes the full address. diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index c4d2ae4b..426013ea 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -243,7 +243,7 @@ Run [`lpm install`](/docs/packages/install) before publication. Missing bundles, | Encoded archive path | 32 KiB | | Path components, including `package/` | 256 | -The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice as LPM.dev publishes, about 10 KB each, so that check keeps 1 MiB of the limit free for it. Other registries can impose smaller limits. A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent, and stops before any target publishes when it refuses the publish for good: for the account's storage, private-package limit or billing, a second factor it requires, the tarball's size, or the token's permission. A version it already has, as after a partial publish, a rate limit or a server error is left to each target's own upload; a rate limit, a timeout or a server error is retried first. The question counts the tarball, while LPM.dev Registry also stores the README and docs it derives from it, and a Swift package's source archive, so a publish within that much of the limit can still be refused at its upload. `--dry-run` asks the same question and fails on any refusal. +The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice as LPM.dev publishes, about 10 KB each, so that check keeps 1 MiB of the limit free for it. Other registries can impose smaller limits. A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent, and stops before any target publishes when it refuses the publish for good, as it does for permission, payment or size (HTTP 402, 403 or 413): for the account's storage, private-package limit or billing, an organization's 2FA rule or IP allowlist, a scope the account doesn't own, the tarball's size, or the token's permission. A version it already has, as after a partial publish, whether it says so by its `VERSION_EXISTS` code or, as an older LPM.dev Registry does, by its message alone, is left to each target's own upload, as are a request it can't read, an unknown package, a rate limit, a server error, and an answer that can't be read; a rate limit, a timeout or a server error is retried first. The same publish then settles LPM.dev Registry's second factor before any target publishes: with 2FA on, it asks for the code, and under `--json` without `--otp` it publishes none. A token LPM.dev Registry no longer accepts stops it there too. The question counts the tarball, while LPM.dev Registry also stores the README and docs it derives from it, and a Swift package's source archive, so a publish within that much of the limit can still be refused at its upload. `--dry-run` asks the same question and fails on any refusal. ## Credentials and OTP diff --git a/content/docs/packages/release.mdx b/content/docs/packages/release.mdx index 185233e5..958f97dd 100644 --- a/content/docs/packages/release.mdx +++ b/content/docs/packages/release.mdx @@ -189,7 +189,7 @@ lpm release publish --all --lpm --otp 123456 --yes For LPM.dev Registry, `--otp` supplies the same six-digit authenticator code to each package. Use a fresh code before it expires. -Members publish one at a time, each prepared and checked as the release reaches it. A member refused, before its upload or by it, as for its size, a secret its files hold, or LPM.dev Registry's storage, stops the release after the members already published. `--dry-run` prepares every member and checks each target's version without uploading, but doesn't ask LPM.dev Registry about storage, which each member's upload adds to, so a release a dry run passes can still stop part way. +Members publish one at a time, each prepared and checked as the release reaches it. A member refused, before its upload or by it, as for its size, a secret its files hold, or LPM.dev Registry's storage, stops the release after the members already published. A member LPM.dev Registry refuses in its preflight stops the release with the error its answer's status is, as for any failed request: `error_code` `auth_required`, `forbidden`, `not_found`, `rate_limited` or `http` in `--json` output, with LPM.dev Registry's message. A version it already has, by its `VERSION_EXISTS` code or, from an older LPM.dev Registry, by its message, is skipped. `--dry-run` prepares every member and checks each target's version without uploading, but doesn't ask LPM.dev Registry about storage or the private-package limit, which each member's upload adds to, so a release a dry run passes can still stop part way. ### Lifecycle scripts From d1f46a96eb786192bcfbf1adafc374c1fa9da286 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 08:45:49 +0100 Subject: [PATCH 14/21] chore: update content dates --- lib/generated/content-dates.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 7f6223cb..464bed3c 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-10-13T04:54:32+01:00" + "modified": "2026-10-13T08:45:49+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-13T04:54:32+01:00" + "modified": "2026-10-13T08:45:49+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", @@ -369,7 +369,7 @@ }, "packages/release.mdx": { "published": "2026-07-03T10:46:26+01:00", - "modified": "2026-10-13T04:54:32+01:00" + "modified": "2026-10-13T08:45:49+01:00" }, "packages/remove.mdx": { "published": "2026-05-01T09:47:04+01:00", From 744375a905ce5d9b1005a553cdcd5273b9eac1d0 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 12:36:26 +0100 Subject: [PATCH 15/21] docs: split the publish, release and login paragraphs on LPM.dev Registry's answers Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 8 +++++++- content/docs/packages/publish.mdx | 23 ++++++++++++++++++++++- content/docs/packages/release.mdx | 6 +++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index 03da4691..bcfdf62d 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -201,7 +201,13 @@ Usage past a limit reads as past it, rounded up. On Hobby, the tarballs of packa At the storage limit, where any publish goes past it, the output says so where publishing is refused. At or past the private-package limit, it says new private packages in your personal scope are refused. -A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does; for other plans the output says only that the storage is past the limit. A registry that doesn't report the storage the limit counts has its whole storage compared, exempt tarballs included. JSON reports what the registry sent: what publishing does past the limit as `storage_overage`, whether storage already past it is billed meanwhile as `storage_excess_billed`, and the storage the limit counts as `usage.counted_storage_bytes`. Each is `null` where the registry doesn't send it. +A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does. For other plans, the output then says only that the storage is past the limit. A registry that doesn't report the storage the limit counts has its whole storage compared, exempt tarballs included. + +JSON reports what the registry sent. Each field is `null` where the registry doesn't send it: + +- `storage_overage`: what publishing does past the limit +- `storage_excess_billed`: whether storage already past the limit is billed meanwhile +- `usage.counted_storage_bytes`: the storage the limit counts Human output masks the email address. JSON includes the full address. diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index 426013ea..ea1263da 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -243,7 +243,28 @@ Run [`lpm install`](/docs/packages/install) before publication. Missing bundles, | Encoded archive path | 32 KiB | | Path components, including `package/` | 256 | -The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB, the tarball in base64 with the package's metadata, so a publish that includes it refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice as LPM.dev publishes, about 10 KB each, so that check keeps 1 MiB of the limit free for it. Other registries can impose smaller limits. A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent, and stops before any target publishes when it refuses the publish for good, as it does for permission, payment or size (HTTP 402, 403 or 413): for the account's storage, private-package limit or billing, an organization's 2FA rule or IP allowlist, a scope the account doesn't own, the tarball's size, or the token's permission. A version it already has, as after a partial publish, whether it says so by its `VERSION_EXISTS` code or, as an older LPM.dev Registry does, by its message alone, is left to each target's own upload, as are a request it can't read, an unknown package, a rate limit, a server error, and an answer that can't be read; a rate limit, a timeout or a server error is retried first. The same publish then settles LPM.dev Registry's second factor before any target publishes: with 2FA on, it asks for the code, and under `--json` without `--otp` it publishes none. A token LPM.dev Registry no longer accepts stops it there too. The question counts the tarball, while LPM.dev Registry also stores the README and docs it derives from it, and a Swift package's source archive, so a publish within that much of the limit can still be refused at its upload. `--dry-run` asks the same question and fails on any refusal. +The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. Other registries can impose smaller limits. + +LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB: the tarball in base64 with the package's metadata. A publish that includes LPM.dev Registry refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice, about 10 KB each, so that check keeps 1 MiB of the limit free for it. + +## When LPM.dev Registry refuses a publish + +A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent. It stops before any target publishes when LPM.dev Registry refuses the publish for good, for permission, payment or size (HTTP 402, 403 or 413): + +- the account's storage, private-package limit or billing +- an organization's 2FA rule or IP allowlist +- a scope the account doesn't own +- the tarball's size +- the token's permission + +Other answers are left to each target's own upload: + +- A version LPM.dev Registry already has, as after a partial publish. It says so by its `VERSION_EXISTS` code, or an older LPM.dev Registry by its message alone. +- A request it can't read, an unknown package, a rate limit, a server error, or an answer that can't be read. A rate limit, a timeout or a server error is retried first. + +The same publish then settles LPM.dev Registry's second factor before any target publishes. With 2FA on, it asks for the code. Under `--json` without `--otp`, it publishes none. A token LPM.dev Registry no longer accepts stops it there too. + +The question counts the tarball. LPM.dev Registry also stores the README and docs it derives from the tarball, and a Swift package's source archive, so a publish within that much of the limit can still be refused at its upload. `--dry-run` asks the same question and fails on any refusal. ## Credentials and OTP diff --git a/content/docs/packages/release.mdx b/content/docs/packages/release.mdx index 958f97dd..75518a10 100644 --- a/content/docs/packages/release.mdx +++ b/content/docs/packages/release.mdx @@ -189,7 +189,11 @@ lpm release publish --all --lpm --otp 123456 --yes For LPM.dev Registry, `--otp` supplies the same six-digit authenticator code to each package. Use a fresh code before it expires. -Members publish one at a time, each prepared and checked as the release reaches it. A member refused, before its upload or by it, as for its size, a secret its files hold, or LPM.dev Registry's storage, stops the release after the members already published. A member LPM.dev Registry refuses in its preflight stops the release with the error its answer's status is, as for any failed request: `error_code` `auth_required`, `forbidden`, `not_found`, `rate_limited` or `http` in `--json` output, with LPM.dev Registry's message. A version it already has, by its `VERSION_EXISTS` code or, from an older LPM.dev Registry, by its message, is skipped. `--dry-run` prepares every member and checks each target's version without uploading, but doesn't ask LPM.dev Registry about storage or the private-package limit, which each member's upload adds to, so a release a dry run passes can still stop part way. +Members publish one at a time, each prepared and checked as the release reaches it. A member refused before its upload or by it stops the release after the members already published. That covers its size, a secret its files hold, and LPM.dev Registry's storage. + +A member LPM.dev Registry refuses in its preflight stops the release with the error its answer's status is, as for any failed request. In `--json` output, its `error_code` is `auth_required`, `forbidden`, `not_found`, `rate_limited` or `http`, with LPM.dev Registry's message. A version LPM.dev Registry already has is skipped, whether it says so by its `VERSION_EXISTS` code or, as an older LPM.dev Registry does, by its message. + +`--dry-run` prepares every member and checks each target's version without uploading. It doesn't ask LPM.dev Registry about storage or the private-package limit, which each member's upload adds to, so a release a dry run passes can still stop part way. ### Lifecycle scripts From 36574d95a3a227205eb7af7dd53b52a7ef08ea7f Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 12:36:26 +0100 Subject: [PATCH 16/21] chore: update content dates Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/generated/content-dates.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 464bed3c..f4406ddb 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-10-13T08:45:49+01:00" + "modified": "2026-10-13T12:36:26+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-13T08:45:49+01:00" + "modified": "2026-10-13T12:36:26+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", @@ -369,7 +369,7 @@ }, "packages/release.mdx": { "published": "2026-07-03T10:46:26+01:00", - "modified": "2026-10-13T08:45:49+01:00" + "modified": "2026-10-13T12:36:26+01:00" }, "packages/remove.mdx": { "published": "2026-05-01T09:47:04+01:00", From 597fd6f155a996097a5063d6496c2559e5e480e3 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 16:05:13 +0100 Subject: [PATCH 17/21] docs(publish): name every derived artifact storage counts, and the second factor's and whoami's answers when the Registry can't say Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 11 +++++++++-- content/docs/packages/publish.mdx | 8 +++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index bcfdf62d..97a39639 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -193,7 +193,11 @@ lpm whoami --json The command checks the selected LPM-compatible registry account. Output includes plan, MFA, Pool access, usage, scopes, credential sources, expiry warnings, and storage health. -Usage past a limit reads as past it, rounded up. On Hobby, the tarballs of packages whose sales exempt them don't count toward the limit, though their READMEs, docs and Swift source archives do; the output shows the storage the limit counts, and the exempt tarballs on a line of their own. Past the storage limit, the output says what publishing does, as the registry reports it: +Usage past a limit reads as past it, rounded up. + +On Hobby, the tarballs of packages whose sales exempt them don't count toward the limit. What the registry derives from those packages still counts: READMEs, API docs, LLM context and skill content, and for a Swift package its source archive, raw `Package.swift` and manifest bundle. The output shows the storage the limit counts, and the exempt tarballs on a line of their own. + +Past the storage limit, the output says what publishing does, as the registry reports it: - **Billed:** storage past the included size is billed per GiB a month, rounded up. The output says so at the limit too, where the next publish starts it. - **Paused:** billing isn't active, so publishing past the limit is refused until it is again. Storage already past it is still billed while a failed payment is retried, and isn't while the subscription is paused or has ended; past the limit, the output says which, where the registry reports it. @@ -201,7 +205,10 @@ Usage past a limit reads as past it, rounded up. On Hobby, the tarballs of packa At the storage limit, where any publish goes past it, the output says so where publishing is refused. At or past the private-package limit, it says new private packages in your personal scope are refused. -A registry that doesn't report it is taken to block Hobby storage past its limit, as every LPM.dev Registry does. For other plans, the output then says only that the storage is past the limit. A registry that doesn't report the storage the limit counts has its whole storage compared, exempt tarballs included. +Some registries don't report what publishing does past the limit, or the storage the limit counts. The output then compares the whole storage, exempt tarballs included: + +- On Hobby, at or past the limit, it says publishing to your personal scope is refused there, apart from packages whose sales exempt them. Every LPM.dev Registry refuses Hobby storage past its limit. +- For other plans, it says only that the storage is past the limit. JSON reports what the registry sent. Each field is `null` where the registry doesn't send it: diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index ea1263da..05f1ffd2 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -259,12 +259,14 @@ A publish to LPM.dev Registry and another target asks LPM.dev Registry first, wi Other answers are left to each target's own upload: -- A version LPM.dev Registry already has, as after a partial publish. It says so by its `VERSION_EXISTS` code, or an older LPM.dev Registry by its message alone. +- A version LPM.dev Registry already has, as after a partial publish. It says so by its `VERSION_EXISTS` code, or an older LPM.dev Registry by its message alone. The LPM.dev target then reports that answer without uploading, and the other targets publish. - A request it can't read, an unknown package, a rate limit, a server error, or an answer that can't be read. A rate limit, a timeout or a server error is retried first. -The same publish then settles LPM.dev Registry's second factor before any target publishes. With 2FA on, it asks for the code. Under `--json` without `--otp`, it publishes none. A token LPM.dev Registry no longer accepts stops it there too. +The same publish then settles LPM.dev Registry's second factor before any target publishes, unless LPM.dev Registry already has the version. With 2FA on, it asks for the code. Under `--json` without `--otp`, it publishes none. A malformed `--otp`, or a token LPM.dev Registry refuses, stops it there too. -The question counts the tarball. LPM.dev Registry also stores the README and docs it derives from the tarball, and a Swift package's source archive, so a publish within that much of the limit can still be refused at its upload. `--dry-run` asks the same question and fails on any refusal. +When the account can't be read, as while LPM.dev Registry is unavailable, the other targets still publish. The LPM.dev target tries again and reports its own result. + +The question counts the tarball. At the upload, LPM.dev Registry also counts what it derives from the tarball: the README and skill content, and for a Swift package its source archive, raw `Package.swift` and manifest bundle. So a publish within that much of the limit can still be refused at its upload. API docs and LLM context, which it derives later, count toward storage too. `--dry-run` asks the same question and fails on any refusal. ## Credentials and OTP From c8af4f30659e1647d8fd0d9a905ee367cfbdf786 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 16:05:13 +0100 Subject: [PATCH 18/21] chore: update content dates --- lib/generated/content-dates.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index f4406ddb..a1a0691b 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-10-13T12:36:26+01:00" + "modified": "2026-10-13T16:05:13+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-13T12:36:26+01:00" + "modified": "2026-10-13T16:05:13+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", From d91f2443d4363bbf19a63ff9b4cf78e692c6c23f Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 21:58:31 +0100 Subject: [PATCH 19/21] docs: rewrite the storage, publish and release passages in plain English Shorter sentences, no contractions or semicolons, the storage reports as a table instead of bold lead-ins, and the refused answers as lists. No fact changes. Co-Authored-By: Claude Opus 5.5 (1M context) --- content/docs/infra/login.mdx | 21 ++++++++++---------- content/docs/packages/publish.mdx | 33 +++++++++++++++++++------------ content/docs/packages/release.mdx | 6 +++--- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/content/docs/infra/login.mdx b/content/docs/infra/login.mdx index 97a39639..a7927cb9 100644 --- a/content/docs/infra/login.mdx +++ b/content/docs/infra/login.mdx @@ -193,24 +193,23 @@ lpm whoami --json The command checks the selected LPM-compatible registry account. Output includes plan, MFA, Pool access, usage, scopes, credential sources, expiry warnings, and storage health. -Usage past a limit reads as past it, rounded up. +The output rounds usage past a limit up, so that it shows as past the limit. -On Hobby, the tarballs of packages whose sales exempt them don't count toward the limit. What the registry derives from those packages still counts: READMEs, API docs, LLM context and skill content, and for a Swift package its source archive, raw `Package.swift` and manifest bundle. The output shows the storage the limit counts, and the exempt tarballs on a line of their own. +On Hobby, the tarballs of packages whose sales exempt them do not count toward the limit. The content that the registry derives from those packages still counts: READMEs, API docs, LLM context, skill content, and for a Swift package, its source archive, raw `Package.swift`, and manifest bundle. The output shows the storage that the limit counts, and shows the exempt tarballs on a separate line. Past the storage limit, the output says what publishing does, as the registry reports it: -- **Billed:** storage past the included size is billed per GiB a month, rounded up. The output says so at the limit too, where the next publish starts it. -- **Paused:** billing isn't active, so publishing past the limit is refused until it is again. Storage already past it is still billed while a failed payment is retried, and isn't while the subscription is paused or has ended; past the limit, the output says which, where the registry reports it. -- **Blocked:** nothing bills storage past the limit, so publishing to your personal scope past it is refused: on Hobby until you upgrade or delete enough to bring it under the limit, and on a Pro plan without a subscription, as staff grant one, for as long as the storage stays past it. - -At the storage limit, where any publish goes past it, the output says so where publishing is refused. At or past the private-package limit, it says new private packages in your personal scope are refused. +| Report | What publishing does | +| --- | --- | +| Billed | LPM.dev bills storage past the included size per GiB a month, rounded up. The output also says this at the limit, where the next publish starts the billing. | +| Paused | Billing is not active, so the registry refuses publishes past the limit until billing is active again. While Stripe tries a failed payment again, storage that is already past the limit is still billed. It is not billed while the subscription is paused or after it ended. Past the limit, the output says which of these applies, if the registry reports it. | +| Blocked | Nothing bills storage past the limit, so the registry refuses publishes to your personal scope past it. On Hobby, this continues until you upgrade, or delete enough storage to go below the limit. On a Pro plan without a subscription, which staff can grant, this continues while the storage stays past the limit. | -Some registries don't report what publishing does past the limit, or the storage the limit counts. The output then compares the whole storage, exempt tarballs included: +At the storage limit, any publish goes past it. The output says so where the registry refuses publishes. At or past the private-package limit, the output says that the registry refuses new private packages in your personal scope. -- On Hobby, at or past the limit, it says publishing to your personal scope is refused there, apart from packages whose sales exempt them. Every LPM.dev Registry refuses Hobby storage past its limit. -- For other plans, it says only that the storage is past the limit. +Some registries do not report what publishing does past the limit, or the storage that the limit counts. The output then compares the whole storage, exempt tarballs included. On Hobby, at or past the limit, the output says that this registry refuses publishes to your personal scope. Packages whose sales exempt them are the exception. Every LPM.dev Registry refuses Hobby storage past its limit. For other plans, the output says only that the storage is past the limit. -JSON reports what the registry sent. Each field is `null` where the registry doesn't send it: +JSON output reports what the registry sent. A field is `null` if the registry does not send it: - `storage_overage`: what publishing does past the limit - `storage_excess_billed`: whether storage already past the limit is billed meanwhile diff --git a/content/docs/packages/publish.mdx b/content/docs/packages/publish.mdx index 05f1ffd2..4df37a48 100644 --- a/content/docs/packages/publish.mdx +++ b/content/docs/packages/publish.mdx @@ -245,28 +245,35 @@ Run [`lpm install`](/docs/packages/install) before publication. Missing bundles, The `package/` prefix leaves 255 components for a project-relative path. Target-specific rewrites and bundled dependencies use the same limits. Other registries can impose smaller limits. -LPM.dev Registry accepts compressed tarballs up to 100 MiB, and publish requests up to 150 MiB: the tarball in base64 with the package's metadata. A publish that includes LPM.dev Registry refuses a larger one before any target is published. A `--provenance` publish adds its Sigstore bundle to the request twice, about 10 KB each, so that check keeps 1 MiB of the limit free for it. +LPM.dev Registry accepts compressed tarballs up to 100 MiB. It accepts publish requests up to 150 MiB, which hold the tarball in base64 with the metadata of the package. If a publish includes LPM.dev Registry, LPM CLI refuses a larger tarball before it publishes to any target. A `--provenance` publish adds its Sigstore bundle to the request two times, about 10 KB each. As a result, LPM CLI keeps 1 MiB of the limit free for it. ## When LPM.dev Registry refuses a publish -A publish to LPM.dev Registry and another target asks LPM.dev Registry first, with the size of the tarball it's sent. It stops before any target publishes when LPM.dev Registry refuses the publish for good, for permission, payment or size (HTTP 402, 403 or 413): +A publish to LPM.dev Registry and another target first asks LPM.dev Registry, and sends the size of the tarball. If LPM.dev Registry refuses the publish for good, for permission, payment, or size (HTTP 402, 403, or 413), the publish stops before any target publishes. These refusals are for: -- the account's storage, private-package limit or billing -- an organization's 2FA rule or IP allowlist -- a scope the account doesn't own -- the tarball's size -- the token's permission +- The storage, private-package limit, or billing of the account +- The 2FA rule or IP allowlist of an organization +- A scope that the account does not own +- The size of the tarball +- The permission of the token -Other answers are left to each target's own upload: +Each target handles other answers at its own upload. One of these answers is a version that LPM.dev Registry already has, for example after a partial publish. LPM.dev Registry gives the `VERSION_EXISTS` code, or an older LPM.dev Registry gives only its message. The LPM.dev target then reports that answer and does not upload. The other targets publish. -- A version LPM.dev Registry already has, as after a partial publish. It says so by its `VERSION_EXISTS` code, or an older LPM.dev Registry by its message alone. The LPM.dev target then reports that answer without uploading, and the other targets publish. -- A request it can't read, an unknown package, a rate limit, a server error, or an answer that can't be read. A rate limit, a timeout or a server error is retried first. +Each target also handles these answers at its own upload: -The same publish then settles LPM.dev Registry's second factor before any target publishes, unless LPM.dev Registry already has the version. With 2FA on, it asks for the code. Under `--json` without `--otp`, it publishes none. A malformed `--otp`, or a token LPM.dev Registry refuses, stops it there too. +- A request that LPM.dev Registry cannot read +- An unknown package +- A rate limit +- A server error +- An answer that LPM CLI cannot read -When the account can't be read, as while LPM.dev Registry is unavailable, the other targets still publish. The LPM.dev target tries again and reports its own result. +After a rate limit, a timeout, or a server error, LPM CLI tries the request again first. -The question counts the tarball. At the upload, LPM.dev Registry also counts what it derives from the tarball: the README and skill content, and for a Swift package its source archive, raw `Package.swift` and manifest bundle. So a publish within that much of the limit can still be refused at its upload. API docs and LLM context, which it derives later, count toward storage too. `--dry-run` asks the same question and fails on any refusal. +Before any target publishes, the same publish then completes the second factor of LPM.dev Registry, unless LPM.dev Registry already has the version. If 2FA is on, it asks for the code. With `--json` and no `--otp`, it publishes to no target. A malformed `--otp`, or a token that LPM.dev Registry refuses, also stops it at this point. + +If LPM CLI cannot read the account, for example while LPM.dev Registry is unavailable, the other targets still publish. The LPM.dev target tries again and reports its own result. + +This first question counts the tarball. At the upload, LPM.dev Registry also counts the content that it derives from the tarball: the README, skill content, and for a Swift package, its source archive, raw `Package.swift`, and manifest bundle. As a result, LPM.dev Registry can still refuse a publish at its upload if the publish is within that much of the limit. API docs and LLM context, which it derives later, also count toward storage. `--dry-run` asks the same question and fails on any refusal. ## Credentials and OTP diff --git a/content/docs/packages/release.mdx b/content/docs/packages/release.mdx index 75518a10..1d73bdaa 100644 --- a/content/docs/packages/release.mdx +++ b/content/docs/packages/release.mdx @@ -189,11 +189,11 @@ lpm release publish --all --lpm --otp 123456 --yes For LPM.dev Registry, `--otp` supplies the same six-digit authenticator code to each package. Use a fresh code before it expires. -Members publish one at a time, each prepared and checked as the release reaches it. A member refused before its upload or by it stops the release after the members already published. That covers its size, a secret its files hold, and LPM.dev Registry's storage. +Members publish one at a time. The release prepares and examines each member when it reaches that member. If a member is refused before or at its upload, the release stops after the members that already published. This applies to the size of the member, a secret that its files hold, and the storage of LPM.dev Registry. -A member LPM.dev Registry refuses in its preflight stops the release with the error its answer's status is, as for any failed request. In `--json` output, its `error_code` is `auth_required`, `forbidden`, `not_found`, `rate_limited` or `http`, with LPM.dev Registry's message. A version LPM.dev Registry already has is skipped, whether it says so by its `VERSION_EXISTS` code or, as an older LPM.dev Registry does, by its message. +If LPM.dev Registry refuses a member in its preflight, the release stops. The error follows the status of the answer, as for any failed request. In `--json` output, its `error_code` is `auth_required`, `forbidden`, `not_found`, `rate_limited`, or `http`, with the message from LPM.dev Registry. The release skips a version that LPM.dev Registry already has. LPM.dev Registry says so with the `VERSION_EXISTS` code, or an older LPM.dev Registry says so with its message. -`--dry-run` prepares every member and checks each target's version without uploading. It doesn't ask LPM.dev Registry about storage or the private-package limit, which each member's upload adds to, so a release a dry run passes can still stop part way. +`--dry-run` prepares every member and examines the version on each target. It does not upload. It does not ask LPM.dev Registry about storage or the private-package limit, which the upload of each member adds to. As a result, a release that passes a dry run can still stop before it is complete. ### Lifecycle scripts From 3601875efc4aa8dd7bdb1b0b46ba9eb050a62cd1 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Tue, 13 Oct 2026 21:58:31 +0100 Subject: [PATCH 20/21] chore: update content dates Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/generated/content-dates.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index a1a0691b..992b8aca 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -189,7 +189,7 @@ }, "infra/login.mdx": { "published": "2026-06-16T23:33:51+01:00", - "modified": "2026-10-13T16:05:13+01:00" + "modified": "2026-10-13T21:58:31+01:00" }, "infra/policy.mdx": { "published": "2026-06-28T15:54:59+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-10-13T16:05:13+01:00" + "modified": "2026-10-13T21:58:31+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", @@ -369,7 +369,7 @@ }, "packages/release.mdx": { "published": "2026-07-03T10:46:26+01:00", - "modified": "2026-10-13T12:36:26+01:00" + "modified": "2026-10-13T21:58:31+01:00" }, "packages/remove.mdx": { "published": "2026-05-01T09:47:04+01:00", From 20febfd3b0d7dbe8332809cba9950dd6863d04c0 Mon Sep 17 00:00:00 2001 From: Tolga Ergin Date: Fri, 16 Oct 2026 14:55:39 +0100 Subject: [PATCH 21/21] chore: update content dates --- lib/generated/content-dates.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/generated/content-dates.json b/lib/generated/content-dates.json index 88beb5d8..9811a1ab 100644 --- a/lib/generated/content-dates.json +++ b/lib/generated/content-dates.json @@ -233,7 +233,7 @@ }, "infra/store.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-09-20T03:12:34+01:00" + "modified": "2026-10-12T13:47:31+01:00" }, "infra/token-rotate.mdx": { "published": "2026-06-16T23:33:51+01:00", @@ -353,7 +353,7 @@ }, "packages/publish.mdx": { "published": "2026-05-01T09:47:04+01:00", - "modified": "2026-09-18T23:56:31+01:00" + "modified": "2026-10-13T21:58:31+01:00" }, "packages/quality.mdx": { "published": "2026-05-01T09:47:04+01:00", @@ -369,7 +369,7 @@ }, "packages/release.mdx": { "published": "2026-07-03T10:46:26+01:00", - "modified": "2026-09-17T21:19:46+01:00" + "modified": "2026-10-13T21:58:31+01:00" }, "packages/remove.mdx": { "published": "2026-05-01T09:47:04+01:00", @@ -501,7 +501,7 @@ }, "reference/terminal-output.mdx": { "published": "2026-07-22T19:51:43+01:00", - "modified": "2026-09-20T19:20:27+01:00" + "modified": "2026-10-11T15:38:30+01:00" }, "registries.mdx": { "published": "2026-05-01T13:51:26+01:00",