Volga
Home
Agent Skill
API Docs
GitHub
  • English
  • Русский
Home
Agent Skill
API Docs
GitHub
  • English
  • Русский
  • Home
  • Getting Started

    • Quick Start
    • Handlers
    • Route Parameters
    • Query Parameters
    • Route Groups
  • Requests & Responses

    • Headers
    • Handling JSON
    • Handling Form Data
    • Working with Files
    • Multipart Responses
    • Raw Request Body
    • Cookies
    • Validating Requests
  • Middleware & Infrastructure

    • Basic Middleware
    • Custom Middleware
    • Parameterized Middleware
    • Response Compression
    • Request Decompression
    • CORS (Cross-Origin Resource Sharing)
    • Static Files
    • Rate Limiting
    • Configuration Files
    • OpenAPI
  • Security & Access

    • Authentication and Authorization
    • OAuth 2.1 & OpenID Connect
    • OAuth 2.1 Client
    • Machine-to-Machine Grants
    • DPoP — Sender-Constrained Tokens
  • Reliability & Observability

    • Global Error Handling
    • Tracing & Logging
    • Request cancellation
    • Graceful Shutdown
  • Protocols & Realtime

    • HTTP Versions and Methods
    • HTTPS
    • WebSockets
    • Server-Sent Events (SSE)
  • Advanced Patterns

    • Dependency Injection
    • Custom Handling of HEAD, OPTIONS, and TRACE Methods
  • Agent Skill

Agent Skill

A packaged Agent Skill that teaches a coding assistant to write Volga correctly — the same material as this site, reorganised for a model rather than a reader.

Download volga-skill.zip~50 KiB · MIT · tracks volga 0.14.1

Source: skill/volga.

Why you might want it

Assistants are confidently wrong about Volga, and for a specific reason: the 0.9 line changed security defaults and removed a family of helper methods, 0.10.0 rebuilt how requests reach middleware and how route groups apply what they hold, 0.10.1 changed what a rejected token is answered with, and 0.11.0 added synchronous handlers, catch-all routes and a shutdown timeout, 0.11.1 gave a route group a fallback of its own, 0.12.0 turned a handler's Err into an error for map_err rather than a second response, 0.13.0 made every path parameter arrive percent-decoded, 0.13.1 let a route group or a route set its own request body limit, 0.13.2 let a resource server fetch an issuer's keys from a URL of its choosing, 0.13.3 made with_alg replace the default HS256 and checks the keys against it at startup, 0.14.0 made Dc<T> read-only and checks services and path parameters at startup, and 0.14.1 renamed cache_control, use_problem_details and ValidPath after one naming rule, while most Volga code a model has seen predates all of it. So the failure mode is not a forgotten method name. It is an assistant writing ok!("hi", [("x-key", "v")]) with a comma instead of a semicolon, returning Err("not found".to_string()) and getting a 500, decoding a path parameter that arrived decoded already, reaching for with_default_cors(), calling use_cors() on an app that never configured CORS, mapping static files with map_static_assets(), or shipping a bearer-auth setup that answers 400 to every request once it sits behind a TLS-terminating proxy.

The skill front-loads exactly those traps, then routes to detail on demand.

What is in it

FileCovers
SKILL.mdEstablishing the version and features, the non-negotiables, a minimal app, routing
references/routing.mdRoutes, groups, path/query params, path parameters of your own types, JSON, forms, files, multipart, body limits, headers, cookies
references/responses.mdResponse macros, IntoResponse, status codes, streaming, errors and IntoError, Problem Details
references/middleware.mdwith / wrap / attach / filter / tap_req / map_ok, CORS, compression, static files, rate limiting
references/di-config.mdDI lifetimes, Inject, factories, configuration files, hot reload
references/security.mdBasic auth, JWT, authorizers, OAuth 2.1 / OIDC, the client crate, TLS, HSTS
references/realtime.mdWebSockets, WebSocket-over-HTTP/2, Server-Sent Events
references/operations.mdFeature flags, graceful shutdown, cancellation, tracing, OpenAPI and hand-written schemas, TestServer
references/migration.mdSymptom → cause, and the 0.14.0 → 0.14.1, 0.13.x → 0.14.0, 0.13.2 → 0.13.3, 0.13.1 → 0.13.2, 0.13.0 → 0.13.1, 0.12.x → 0.13.0, 0.11.x → 0.12.0, 0.10.x → 0.11.0, 0.10.0 → 0.10.1, 0.9.x → 0.10.x and 0.8.x → 0.9.x upgrade paths

SKILL.md stays short on purpose: an entrypoint an agent always reads, and eight references it loads only when the task needs one.

Install

The SKILL.md format is a shared standard, so installation is the same everywhere: unzip and copy the volga/ directory into the tool's skills folder, keeping the folder name — it has to match the name in the frontmatter.

ToolPersonalPer project
Claude Code~/.claude/skills/volga/.claude/skills/volga/
opencode~/.config/opencode/skills/volga/.opencode/skills/volga/
Codex CLI~/.codex/skills/volga/.codex/skills/volga/
unzip volga-skill.zip
mkdir -p ~/.claude/skills && cp -r volga ~/.claude/skills/

Restart the assistant afterwards — skills are discovered at startup.

opencode also reads .claude/skills/ and .agents/skills/, so a single copy inside a project can serve more than one tool.

Anything else

Any assistant that can read a file will do. Point it at SKILL.md and let it follow the links, or add a line to the project's AGENTS.md:

For Rust web work with the `volga` crate, read
`.agents/skills/volga/SKILL.md` and the reference file it routes you to.

What it front-loads

The whole point of shipping a skill rather than a prose summary is the list of things a model gets wrong on its own. A sample of what SKILL.md puts before anything else:

  • Custom headers come after a semicolon. ok!("Hello"; [("x-key", "v")]). A comma matches the format! arm and fails to compile.
  • with_* consumes the App, map_* borrows it. Configuration is chained first; routing needs let mut app.
  • require_https and strip_token_from_request default to on for bearer authentication — the reason a working local setup returns 400 behind a reverse proxy.
  • with_aud makes aud a required claim unless without_strict_aud() says otherwise.
  • with_default_cors() and with_default_tracing() are gone, and the on/off builders (with_credentials, with_preload, …) no longer take a bool.
  • Path<T> is a tuple, NamedPath<T> is the named struct, and neither may be mixed with positional path parameters in one handler. A type of your own becomes a path parameter through FromPathArg since 0.13.0.
  • full is not everything — #[derive(Claims)], #[http_header], development certificates and TestServer each need a feature full does not include.
  • A rejected bearer token is 401, not 403 since 0.10.1 — 403 is left to a valid token that lacks the role or permission a route asks for.
  • An unresolvable DI graph stops the app at startup since 0.10.1, so a hand-written impl Inject should declare what it resolves.
  • A synchronous handler runs on the runtime worker — blocking work goes in blocking, not in a plain fn handler.
  • A catch-all value is not a safe file path: {*path} arrives unnormalized, .. included.
  • Endless responses end on the shutdown signal, via the ShutdownHandle extractor, instead of being closed at the shutdown timeout.
  • The SPA shell answers GET and HEAD alone since 0.11.1, and an API sharing the server gives its group a map_fallback of its own.
  • A handler's Err is an error since 0.12.0: it reaches map_err, a bare string answers 500, and an error type implements IntoError — never From<T> for Error.
  • Path parameters arrive decoded since 0.13.0: a handler never decodes one again, and a literal segment written with %XX panics at mapping.
  • A body limit belongs where the body is read since 0.13.1: a route group or a route raises or lowers it for itself, the most specific limit wins, and a body over it answers 413.
  • with_issuer is the iss tokens carry — when the server cannot reach it (a container, an ingress host), 0.13.2 fetches the keys from with_jwks_uri instead of pointing the issuer at an internal URL.
  • with_alg names the whole list since 0.13.3: the first call replaces HS256, encode signs with the first, a static RSA, EC or Ed25519 key comes with with_alg of its family or the app does not start, and with_iss makes iss a required claim.
  • Dc<T> is read-only since 0.14.0: changing state lives behind a Mutex, an RwLock or an atomic inside the service, and a handler or middleware taking a service nobody registered stops the app at startup.
  • A handler reads only the path parameters its route declares since 0.14.0: map_get("/sum", |x: i32, y: i32| ..) panics where it is mapped, instead of answering 500 on every request.

The code in it compiles

The Rust in the skill is compiled against the published volga crates in this repository's CI, on the same job that checks the snippets on this site — so what an assistant copies out of it builds. Blocks that show a shape rather than a program (a signature, a trait impl with elided bodies) opt out explicitly.

Run the same check yourself after editing:

python3 ci/check-snippets.py --docs-dir skill --default-mode compile-fragment --default-features "full auth-full macros dev-cert test"

Version

The skill tracks volga 0.14.1 on MSRV 1.90. The frontmatter records both, so an assistant can tell whether the skill matches the crate in front of it:

metadata:
  volga-version: "0.14.1"
  msrv: "1.90"
Last Updated: 10/21/26, 4:26 PM