Skip to main content
skill CX Codex

flash — Claude Code skill for Runpod Serverless

A skill that writes and deploys Runpod Serverless with runpod-flash: @Endpoint decorators, local iteration, and shipping endpoints.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add runpod/runpod-plugins-official --skill flash -a claude-code
Open on GitHub

What flash does

The skill teaches your agent to work with runpod-flash, a library where a serverless endpoint is described in code. One function behind @Endpoint becomes an endpoint with its own workers, several HTTP routes can share a single worker pool, and a pre-built Docker image plugs in as an external service. What the agent gets is not a command reference but the mental model and the gotchas that flash --help does not carry.

Development splits into two phases. flash dev starts a local server on :8888 and runs your decorated functions on remote GPU or CPU workers, with hot reload and the worker's logs streaming live to the terminal. flash deploy builds an artifact and ships a stable endpoint — slow, so it belongs after the code works under flash dev. One detail matters: flash dev sends only the function body to the worker, so a NameError on a module-level name shows up right away, while flash deploy imports the whole module and can hide that bug.

Before the first run you need a Runpod account: flash login or the RUNPOD_API_KEY environment variable. The library installs with uv tool install runpod-flash. Releases follow their own cadence, so the skill tells you to check flash --help and pip show runpod-flash before deciding a flag is unavailable. For projects with an explicit Dockerfile or template, the author points to the separate runpod-build-template skill — swapping in the code-first flow there is the wrong move.

What it helps with

  • define a Runpod serverless endpoint in plain Python
  • run a function on a remote GPU with hot reload
  • catch a NameError before deploy instead of after
  • wire up a pre-built Docker image and call it over HTTP
  • put several routes on one shared worker pool

Example prompts for the agent

  • start flash dev in the background and show me the worker logs
  • create an @Endpoint on GpuGroup.AMPERE_80 with five workers
  • deploy the endpoint once it works under flash dev

How to install flash

1Skills CLI (Vercel)

npx skills add runpod/runpod-plugins-official --skill flash -a claude-code

2Manually: put the files in place

~/.claude/skills/flash/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/flash/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about flash

How do I install flash in Claude?

Run npx skills add runpod/runpod-plugins-official --skill flash -a claude-code. The skill lands at ~/.claude/skills/flash/SKILL.md.

What does flash do?

It helps the agent write and deploy Runpod Serverless with runpod-flash: @Endpoint decorators, endpoint modes, resources, and debugging. It also covers the flash dev and flash deploy loop.

What do I need before using it?

A Runpod account and auth: flash login or the RUNPOD_API_KEY environment variable. The library itself installs with uv tool install runpod-flash.

Source text

SKILL.md · Apache-2.0
---
name: flash
description: >-
  Write and deploy code-first Runpod Serverless with runpod-flash: @Endpoint/@remote,
  flash dev, resource configuration, and debugging. Use runpod-build-template for
  explicit Dockerfile/template project authoring, and runpodctl/runpod-mcp for
  infrastructure management.
user-invocable: true
metadata:
  author: runpod
  version: "1.8.0" # x-release-please-version
  concepts: [flash, serverless-endpoint, serverless-handler, worker, volume-cache]
license: Apache-2.0
---

# Runpod Flash

For an explicit Dockerfile/template project request, use
[runpod-build-template](../runpod-build-template/SKILL.md). Do not replace that
deliverable with Flash unless the user chooses its code-first workflow.

Write code locally, iterate with `flash dev` — it runs your functions on remote Runpod GPUs/CPUs with hot-reload and live worker logs — then `flash deploy` to ship. `Endpoint` handles provisioning.

`runpod-flash` releases on its own cadence, so **`flash --help` and `flash <command> --help`
are authoritative for the command surface** — this skill is the mental model, the decision
rules, and the gotchas that help output does not carry. Confirm the installed version with
`pip show runpod-flash` before concluding a subcommand or flag is unavailable.

**Worked examples first for anything multi-step.** Flash appears in verified end-to-end
paths — [03 variant B (whisper endpoint via flash)](../runpod/golden-paths/03-whisper-endpoint/variant-b-flash.md)
and [08 (fine-tune → serve)](../runpod/golden-paths/08-finetune-to-serverless.md); the full
index is [runpod/golden-paths/README.md](../runpod/golden-paths/README.md). Open the matching
path before planning a deploy — it carries the ordering and the cost cleanup this skill only
summarizes.

**Load on demand — this skill keeps the mental model + gotchas inline; details live in [`reference/`](reference/):**

| Need | Read |
|------|------|
| Install, auth, `flash init`, and the full `flash` command list | [reference/setup-and-cli.md](reference/setup-and-cli.md) |
| `Endpoint(...)` constructor params, `NetworkVolume`/`PodTemplate`/`EndpointJob`, GPU & CPU enum tables | [reference/api.md](reference/api.md) |
| Worked patterns — choosing a model, warm-worker model loading, CPU→GPU pipeline, parallel calls | [reference/patterns.md](reference/patterns.md) |

Quick start: `uv tool install runpod-flash` → `flash login` (or `export RUNPOD_API_KEY=...`) → `flash init my-project` → `flash dev`. Details in [reference/setup-and-cli.md](reference/setup-and-cli.md).

## Dev vs Deploy

- `flash dev` — **iterate.** Local server at `:8888`, but your decorated functions
  execute on **remote GPU/CPU workers**. Hot-reloads on save and **streams the worker's
  logs live** to the terminal. No build/upload/deploy wait — use this the whole time you
  develop.
- `flash deploy` — **ship.** Builds an artifact and deploys a stable endpoint. Slow
  (build + upload + provision); only do this once the code works under `flash dev`.

`flash dev` ships **only the function body** to the worker, so a `NameError` for a
module-level name surfaces immediately here. `flash deploy` imports the whole module and
can mask that bug (see Gotcha #1). Develop against `flash dev` and you catch it first.

## Autonomous Dev Loop

`flash dev` is a long-running server. Three rules:
- **Run it in the background** — don't block on it.
- **Capture its output** to a log file.
- **Drive it over HTTP.**

The captured log is the remote worker's live stream (cold start, model load, `print`s,
tracebacks) — read it to debug.

```bash
flash dev > /tmp/flash-dev.log 2>&1 &                          # background; never run it blocking
for i in $(seq 1 60); do grep -q "flash dev  localhost:" /tmp/flash-dev.log && break; sleep 2; done  # bounded ~2min; if it never appears, check the log for errors
URL=$(grep -o "localhost:[0-9]*" /tmp/flash-dev.log | head -1)               # actual port (8888 bumps if taken)
curl -s "$URL/main/predict" -d '{"data": {...}}'               # dispatches to the remote worker
```

- **Read the real URL from the log** — flash auto-bumps the port if 8888 is in use, and
  prints `✓ flash dev  localhost:<port>` plus the route table.
- **Routes are namespaced by file**: `main.py`'s `/predict` is served at `/main/predict`.
- **Two route shapes, two body shapes** (mismatch → `422` naming the missing field in `loc`):
  - **Load-balanced** (`@api.post("/predict")`) → `POST /main/predict`, body is the arg
    at top level: a handler `def predict(data: dict)` wants `{"data": {...}}` (not the bare object).
  - **Queue-based** (bare `@Endpoint` decorator) → `POST /main/runsync` (the local dev
    server only generates `/runsync`; production also exposes `/run`),
    body is **double-wrapped** in `input`: a handler `def synthesize(data: dict)` wants
    `{"input": {"data": {...}}}`. The outer `input` is the queue envelope; the inner key is
    the handler's param name.
- Edit a handler and save — hot-reload re-syncs the body; just re-send the request, no
  redeploy. Add `--auto-provision` to skip the first-call cold start. `kill %1` when done.

## Endpoint: Three Modes

Full constructor params and the GPU/CPU enum tables are in [reference/api.md](reference/api.md).

### Mode 1: Your Code (Queue-Based Decorator)

One function = one endpoint with its own workers.

```python
from runpod_flash import Endpoint, GpuGroup

@Endpoint(name="my-worker", gpu=GpuGroup.AMPERE_80, workers=5, dependencies=["torch"])
async def compute(data):
    import torch  # MUST import inside function (cloudpickle)
    return {"sum": torch.tensor(data, device="cuda").sum().item()}

result = await compute([1, 2, 3])
```

### Mode 2: Your Code (Load-Balanced Routes)

Multiple HTTP routes share one pool of workers.

```python
from runpod_flash import Endpoint, GpuGroup

api = Endpoint(name="my-api", gpu=GpuGroup.ADA_24, workers=(1, 5), dependencies=["torch"])

@api.post("/predict")
async def predict(data: list[float]):
    import torch
    return {"result": torch.tensor(data, device="cuda").sum().item()}

@api.get("/health")
async def health():
    return {"status": "ok"}
```

### Mode 3: External Image (Client)

Deploy a pre-built Docker image and call it via HTTP.

```python
from runpod_flash import Endpoint, GpuGroup, PodTemplate

server = Endpoint(
    name="my-server",
    image="my-org/my-image:latest",
    gpu=GpuGroup.AMPERE_80,
    workers=1,
    env={"HF_TOKEN": "xxx"},
    template=PodTemplate(containerDiskInGb=100),
)

# LB-style
result = await server.post("/v1/completions", {"prompt": "hello"})
models = await server.get("/v1/models")

# QB-style
job = await server.run({"prompt": "hello"})        # optional: webhook="https://..." for completion callback
await job.wait()
print(job.output)
```

Connect to an existing endpoint by ID (no provisioning):

```python
ep = Endpoint(id="abc123")
job = await ep.runsync({"prompt": "hello"})  # runsync wraps this as {"input": {"prompt": "hello"}}
print(job.output)
```

## How Mode Is Determined

| Parameters | Mode |
|-----------|------|
| `name=` only | Decorator (your code) |
| `image=` set | Client (deploys image, then HTTP calls) |
| `id=` set | Client (connects to existing, no provisioning) |

The table above is *how* the mode is picked from params. *When* to reach for `image=`:

### When to use `image=` (custom container) vs your own code

Default to writing Python (decorator / routes) — it runs arbitrary code with
`dependencies=[...]`/`system_dependencies=[...]` and needs no Dockerfile. Even large
HuggingFace models stay in decorator mode (weights stream at runtime — see
[reference/patterns.md → Loading ML models](reference/patterns.md#loading-ml-models-warm-workers)).
Reach for `image=` **only** when you need:

- **a pre-built inference server** — vLLM, TensorRT-LLM (`image="vllm/vllm-openai:latest"`, or `runpod/worker-vllm`, `runpod/worker-comfy`)
- **system-level deps not pip-installable** — a specific CUDA/cuDNN, OS libraries
- **models baked into the image** — to skip the runtime download entirely
- **an existing Runpod Serverless worker** — you already have a working image

Trade-off: `image=` mode **can't run arbitrary Python** (the image owns all logic) and the
image must implement a Runpod Serverless handler. Full list + examples:
https://docs.runpod.io/flash/custom-docker-images

## Gotchas

1. **Only the function body ships to the worker** -- most common error. Put imports *and* any module-level constants/helpers the function uses *inside* the decorated body. `flash deploy` imports the whole module so module globals happen to work; `flash dev` ships just the body, so a module-level name raises `NameError`. A handler that works deployed can break under dev — fix it by moving everything inside.
2. **Forgetting await** -- all decorated functions and client methods need `await`.
3. **Missing dependencies** -- must list in `dependencies=[]`.
4. **gpu/cpu are exclusive** -- pick one per Endpoint.
5. **idle_timeout is seconds** -- default 60s, not minutes.
6. **10MB payload limit** -- pass URLs, not large objects. Return binary (audio/images/files) as base64 in the JSON (`{"audio_b64": ...}`) and decode client-side; for larger outputs write to a NetworkVolume or upload to storage and return a URL.
7. **Client vs decorator** -- `image=`/`id=` = client. Otherwise = decorator.
8. **Auto GPU switching requires workers >= 5** -- pass a list of GPU types (e.g. `gpu=[GpuGroup.ADA_24, GpuGroup.AMPERE_80]`) and set `workers=5` or higher. The platform only auto-switches GPU types based on supply when max workers is at least 5.
9. **`runsync` timeout is 60s** -- cold starts can exceed 60s. Use `ep.runsync(data, timeout=120)` for first requests or use `ep.run()` + `job.wait()` instead.
10. **Request body shape (raw/external HTTP callers only)** -- match the request shape to the endpoint type:
    - **LB routes** (`@api.post(...)`): send the handler arg at the top level — `{"data": {...}}`.
    - **QB endpoints** (bare `@Endpoint`, hit via `.../run` or `.../runsync`): the worker calls
      **`handler(**job_input)`**, so the request's `input` keys must match the handler's parameter
      names — `def transcribe(input_data: dict)` wants `{"input": {"input_data": {...}}}`, and
      `def read(input: dict)` wants `{"input": {"input": {...}}}`. A mismatch fails with
      `got an unexpected keyword argument …`. Use `**kwargs` if the handler ignores the payload.
    - **Never send an empty `input`.** A QB request with `{"input": {}}` is rejected by the
      worker SDK as `Job has missing field(s): id or input` — always include at least one key.
    - *Context:* the flash client (`ep.runsync(x)`, `api.post(...)`) hides the spreading, so this
      only bites raw HTTP/external callers (mismatch behavior verified 2026-07-10 via worker logs).
      See *Autonomous Dev Loop*.
11. **Load a model once per worker (not per call)** -- for real inference use a class `@Endpoint` whose `__init__` loads the model once per worker (see [reference/patterns.md → Loading ML models](reference/patterns.md#loading-ml-models-warm-workers)). In function-form, reconcile with #1 by caching in a module global *inside* the body so it works under both `flash dev` and `deploy`:
    ```python
    global _MODEL
    try: _MODEL
    except NameError: _MODEL = load_model()   # runs once per worker, reused across calls
    ```
12. **Native CUDA libs go in `dependencies=[]` too** -- e.g. CTranslate2/faster-whisper needs `nvidia-cublas-cu12` + `nvidia-cudnn-cu12` or it silently falls back to CPU. Add them alongside the Python package.
13. **Silent 401 auth failure** -- a set `RUNPOD_API_KEY` env var overrides the `flash login` token, so a bad/expired key wins. The failure is quiet: provisioning logs `GraphQL request failed: 401`, but `flash dev` still prints its normal ready line ("failed endpoints deploy on-demand"), so it *looks* healthy. When endpoints fail to provision:
    1. Check the provisioning log for `GraphQL request failed: 401`.
    2. Verify the current key independently: `curl -s -o /dev/null -w '%{http_code}' https://api.runpod.io/v2/serverless -H "Authorization: Bearer $RUNPOD_API_KEY"` (200 = good, 401 = bad).
    3. Fix it: `unset RUNPOD_API_KEY` to fall back to the `flash login` token, or `export` a valid key.
14. **`system_dependencies=` adds to cold start** -- apt packages (e.g. `["ffmpeg", "espeak-ng"]`) install on the worker before first use, so the initial call is slower (on top of any model download); warm calls are unaffected.
15. **Teardown a deployed app with `flash app delete <app>`** -- `flash undeploy list` may show "no endpoints" for an app that is deployed and serving; `flash app delete` (or `runpodctl serverless delete <id>`) reliably removes it.

## Resources

- Setup & CLI: [reference/setup-and-cli.md](reference/setup-and-cli.md) · API & compute enums: [reference/api.md](reference/api.md) · Patterns: [reference/patterns.md](reference/patterns.md)
- Flash source: https://github.com/runpod/flash
- Runnable examples: https://github.com/runpod/flash-examples — clone and adapt the closest one
- Package (PyPI): https://pypi.org/project/runpod-flash/
- Docs: https://docs.runpod.io/flash/overview
  - Custom Docker images (when + how): https://docs.runpod.io/flash/custom-docker-images
  - Storage / network volumes: https://docs.runpod.io/flash/configuration/storage

© runpod · Apache-2.0 · runpod/runpod-plugins-official

Similar skills

Everything for DevOps and infrastructure →

From the same set11

runpod-mcp Connects the Runpod MCP server and routes agent tasks for managing pods and serverless endpoints on Runpod. Useful for orchestrating GPU cloud resources directly in the coding agent. CX Codex +1 12,500installs runpod-usage Explains how Runpod works: Pods versus Serverless, GPU and VRAM choices, image builds, storage and networking. Useful when you need to decide what to run before running anything. CX Codex +1 12,500installs runpod-migrate Migrates Runpod GraphQL API and REST v1 code to REST v2, locating call sites and breaking changes. Use it before an API upgrade or to identify the API generation in a repository. CX Codex +1 10,800installs runpod-templates A skill that finds official Runpod Pod templates, explains their ports and autostart, and repairs model metadata in ComfyUI workflows. CX Codex +1 10,100installs serverless-deploy Turns a model or worker source into a working Runpod Serverless endpoint through MCP tools: picks the engine, sizes the GPU, provisions and proves it with one real job. CX Codex +1 2,700installs pod-doctor Diagnoses unreachable, GPU-blind, or stuck Runpod Pods using Runpod MCP tools. It stays read-only until you approve a specific recovery step. CX Codex +1 2,600installs endpoint-ops A skill for an existing Runpod Serverless endpoint: finds why jobs queue up or workers die, and changes a setting only when you authorize it. CX Codex +1 2,700installs discovery The skill checks GPU availability, stock levels, and prices across Runpod catalogs without launching resources. It also estimates VRAM needs for model inference. CX Codex +1 2,600installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor