Skip to content

Sunset legacy storage surfaces (CLI / MCP / docs / sync tests) #120

@MajorTal

Description

@MajorTal

Sunset legacy storage surfaces (CLI / MCP / docs / sync tests)

Why now

The private gateway repo (kychee-com/run402-private) executed a big-bang sunset of the legacy storage shim today (2026-04-28) rather than waiting for the original 2026-06-01 deadline. The trigger was discovering that the shim's write path silently broke the new v1.33 CDN serving path: it wrote bytes to <project_id>/<key> only, never promoting them to _cas/<sha>, so any blob uploaded via the legacy shim returned 5xx/404 when fetched through the post-cutover /_blob/* CDN origin.

Pre-revenue stance from the project owner: no backwards-compat carrying cost. Forward-fix only.

What's gone on the gateway side (private repo main, today)

The following routes return 404 from the Express default handler as of the next deploy:

  • POST /storage/v1/object/{bucket}/{path} — upload
  • GET /storage/v1/object/{bucket}/{path} — download
  • DELETE /storage/v1/object/{bucket}/{path} — delete
  • POST /storage/v1/object/sign/{bucket}/{path} — presigned-GET shim
  • GET /storage/v1/object/list/{bucket} — list
  • GET /storage/v1/public/{project_id}/{bucket}/{path} — anonymous public read

Plus removed: deprecation middleware, BLOB_DUAL_WRITE_ENABLED flag, three v1.33 cutover scripts (backfill-public-blobs-to-legacy.ts, cleanup-legacy-blob-dual-write.ts, invalidate-cached-blob-404s.ts). The 6 orphaned <project_id>/<key> S3 keys + their internal.blobs rows have been deleted.

The new flow is the only flow:

POST /storage/v1/uploads          → { upload_id, parts: [{ url, ... }] }
PUT  <presigned S3 URL>           (direct to S3, no gateway in byte path)
POST /storage/v1/uploads/:id/complete
                                  → AssetRef { key, url, immutable_url,
                                               cdn_url, cdn_immutable_url,
                                               content_sha256, etag, sri,
                                               size, content_type }

Per-key reads/deletes/sign/list are served by /storage/v1/blob/{key}, /storage/v1/blobs, /storage/v1/blob/{key}/sign. Public blobs are served at https://pr-<public_id>.run402.com/_blob/<key> (auto-subdomain — always available) or any claimed subdomain / mapped custom domain.

Surfaces in this repo that need updates

1. MCP tools — delete the four legacy tools entirely

Currently registered in src/index.ts and described as "(deprecated)" — but they now point at routes that 404. Recommend delete, not just keep-deprecated:

The five blob_* MCP tools (blob_put, blob_get, blob_ls, blob_rm, blob_sign) already cover every use case and use the new routes.

2. CLI — delete the run402 storage subcommand

  • Delete cli/lib/storage.mjs entirely
  • Remove the storage dispatcher in cli/cli.mjs:121 (the deprecation banner)
  • Remove any references to run402 storage from cli/cli.mjs HELP block

The run402 blob put|get|ls|rm|sign subcommands cover every use case.

3. Docs — strip every reference

  • SKILL.md — remove the "(deprecated)" sections at lines 213, 228, 819, 833, 862; remove the "Supersedes <tool> (deprecated)" callouts at lines 139, 150, 162, 166 (just say what the tool does); replace upload_file / rest_query examples with their blob_put / blob_get equivalents
  • README.md — drop rows 65–68 from the tool table (upload_file, download_file, delete_file, list_files); update example at line 217 to use blob_put
  • README.zh-CN.md — same edits in the Chinese translation
  • openclaw/SKILL.md — same audit; this is the OpenClaw fork's skill file
  • cli/llms-cli.txt:474 — drop the run402 storage deprecation note (currently a one-liner pointing at the migration doc, which is also being removed)

4. Sync tests — re-pin against the simplified private-repo site/llms.txt

  • sync.test.ts — the legacy-storage table is gone from the private repo's site/llms.txt as of 2026-04-28; any assertion that grep'd for /storage/v1/object in the upstream needs to flip to "must NOT contain"
  • SKILL.test.ts — same audit; ensure no test pins legacy tool names

5. SDK — already clean

sdk/src/namespaces/blobs.ts already uses the new API (POST /storage/v1/uploads → S3 PUT → /complete). No legacy refs found in sdk/src/. Nothing to change here. ✓

6. OpenSpec — note the upstream change in active proposals

Suggested PR shape

Single PR titled something like chore: retire legacy storage shim surfaces (CLI/MCP/docs). Bundle the deletions together — the change is purely additive removal, no new functionality.

Recommended npm version bump for run402-mcp: minor (because tools are removed). Current is v0.2.0 per the README; bumping to v0.3.0 matches semver-for-MCP conventions.

Migration cheatsheet for downstream agents

If anyone consuming this MCP server (or CLI) was using the legacy tools, the 1:1 mapping is:

Legacy New Notes
upload_file(project, bucket, path, content) blob_put(project, key=bucket+"/"+path, content) bucket becomes the first path segment of the new flat keyspace
download_file(project, bucket, path) blob_get(project, key=bucket+"/"+path) same key shape
list_files(project, bucket) blob_ls(project, prefix=bucket+"/") prefix-based instead of bucket-scoped
delete_file(project, bucket, path) blob_rm(project, key=bucket+"/"+path) same key shape
run402 storage upload <id> <bucket> <path> --file <local> run402 blob put <id> <bucket>/<path> --file <local> optional --immutable for content-addressed URLs

The new tools return CDN-fronted URLs in the response (cdn_url / cdn_immutable_url) — agents generating HTML/CSS/JS should prefer cdn_immutable_url for read-after-write correctness without polling.

References

  • Private-repo commits (visible only to kychee-com org members):
    • 42c74fcf feat(gateway): delete BLOB_DUAL_WRITE_ENABLED safety net + cutover scripts
    • 9e2fe943 feat(gateway): big-bang sunset of legacy storage shim (Option B)
  • The migration doc at https://run402.com/docs/blob#migration was the planned destination for the legacy → new mapping; if it's still live, it can stay as a permanent reference.
  • The Sunset: Mon, 01 Jun 2026 00:00:00 GMT header is no longer being emitted (the middleware that emitted it was deleted with the shim).

Filed by the private-repo maintainer to keep the public surfaces in sync.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions