jsakamoto/blazingstory/storage-adapter
Claude Code and agent skill by jsakamoto/blazingstory
- community
Checking that the SKILL.md file is still in the repository.
Implement scripts/snapshot-storage.ts so a storage service (Dropbox, MinIO, WebDAV, any S3-compatible, …) can hold the VRT baseline screenshots. Use when the user asks to implement, set up, or switch the snapshot storage backend of this VRT project.
Install
npx vskill@latest install jsakamoto/blazingstory/storage-adapterSKILL.md
Implementing a storage adapter
This project shares its VRT baseline screenshots (tests/vrt.spec.ts-snapshots/) through a storage service instead of committing them to git. Which service that is depends entirely on one file, scripts/snapshot-storage.ts, which ships here as an empty template exporting a single storageAdapter: StorageAdapter. Implement its members and any service can hold the baselines. Everything else (the CLIs, diff planning, globalSetup, --prune, prompts) is provider-agnostic and must not be touched.
Read before writing code:
scripts/snapshot-storage.ts: the empty template, one comment per memberscripts/snapshot-sync.ts: theStorageAdapterinterface (the contract) plus the
helpers the adapter uses, runPool (parallel per-file transfers) and snapshotsDir (the local baseline directory)
How the pieces fit
scripts/global-setup.ts(Playwright'sglobalSetup) downloads the baselines missing
locally before every test run: current platform only, never overwrites or deletes. VRT_SKIP_CLOUD=1 skips it, and any other failure aborts the run with errorHint().
npm run snapshots:pull/npm run snapshots:pushare the explicit syncs. They
default to a diff sync by content MD5, print the plan, and ask for confirmation on an interactive terminal. Options: --force, --missing, --filter <glob>, --all-platforms (pull only), --prune, --dry-run, --yes.
- Baseline file names carry a platform suffix (
<story-id>-<platform>.png), so one
remote store holds the linux / win32 / darwin sets side by side. The common code does that filtering; the adapter only ever deals with plain flat file names.
Ask the user first
- Which service, and which SDK (prefer an official npm SDK; note its package name)
- The auth model. Prefer a CLI login or ambient credentials. Secrets must NOT go into
vrt.config.ts (it is committed); read them from env vars instead. vrt.config.ts loads a .env file from the project root if one exists, and .gitignore already excludes it, so .env is where a password or access key belongs. A variable set in the shell wins over .env.
Contract invariants (what the common code relies on)
listRemote()returns name → content MD5 in base64, orundefinedwhen unknown.
undefined makes the diff sync treat that file as always changed: acceptable as a fallback, wrong as the normal case. Skip any name that is not a flat *.png.
upload()must ensure a laterlistRemote()can return the uploaded file's MD5.
Pick whichever mechanism the service offers:
- it computes and returns a content hash itself (Google Cloud Storage does this with
md5Hash): nothing to do
- it has a content-MD5 header or property settable on upload (Azure Blob Storage's
Content-MD5): set it explicitly, otherwise every later sync sees the file as changed
- it returns an entity tag that equals the MD5 only under conditions (an S3 ETag does,
for single-part uploads on non-KMS buckets): normalize it (quoted hex to base64) and map every value you cannot trust to undefined, then document the caveat in the file's header comment
- none of the above: store the MD5 yourself as user-defined metadata next to the file
and read it back in listRemote()
download()writes tojoin(snapshotsDir, name); the directory already exists.- Wrap per-file transfers in
runPool(exported bysnapshot-sync.tstogether with
snapshotsDir).
errorHint(error)maps each likely failure (no credentials, permission denied,
bucket or container not found) to ONE actionable line, and falls back to a generic "check vrt.config.ts and your network connection" line carrying the message.
- Module-level client construction is fine, but it must not perform network I/O at
import time.
- Erasable TypeScript only (no
enum, nonamespace: Node runs these files through
type stripping) and explicit .ts extensions on local imports.
File conventions
- Start the file with a terse header comment: the SDK package, the auth prerequisites,
the exact vrt.config.ts fields the adapter reads, and any caveat such as the ETag one above.
- Connection values live in
vrt.config.tsand only the adapter reads them. Follow the
pattern the existing baseURL field already shows, env override first: storageBucket: process.env.VRT_STORAGE_BUCKET ?? "<bucket name>". For a secret, drop the literal fallback and let the value be undefined when unset, so a missing credential fails loudly instead of silently trying a placeholder. Leave baseURL itself alone; it belongs to the test run, not the storage.
- Comments in English and short. Never use em dashes or en dashes anywhere in this
project, comments and strings alike; it is the project owner's style preference. Restructure the sentence with a colon, parentheses, or a full stop instead.
Wiring it up
npm i -D <sdk package>- Add the connection fields to
vrt.config.ts npx tsc --noEmit(scripts/snapshot-storage.tsis part of the type check)
Verification
npm run snapshots:push -- --dry-run: the plan lists the local baselinesnpm run snapshots:push, then push again: expect0 to upload, N up to date. This
proves the MD5 round-trip; if the files stay "changed", the MD5s returned by listRemote() are wrong.
- Delete one local PNG, then
npm run snapshots:pullrestores exactly that file.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingProjectTemplate/Content/BlazingStoryVRT/.agents/skills/storage-adapter/SKILL.md
Popularity
- Repository stars
- 471
- Repository forks
- 41
- 7-day trend score
- 31
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/jsakamoto/blazingstory/storage-adapter)