RTK Rust Design Patterns
rtk-ai/rtk
Describes seven Rust design patterns for the RTK CLI filter modules, with when to use each, RTK examples, and notes on when a pattern is overkill.
Axum (0.8+) web framework patterns: type-safe extractors, Tower middleware, route routing, and graceful shutdown.
$ npx skills add irahardianto/awesome-agv --skill axum-idioms -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install irahardianto/awesome-agv axum-idioms --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/axum-idioms .claude/skills/axum-idioms && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "axum-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/axum-idioms into .claude/skills/axum-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "axum-idioms", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/axum-idiomsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add irahardianto/awesome-agv --skill axum-idioms -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install irahardianto/awesome-agv axum-idioms --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/axum-idioms .agents/skills/axum-idioms && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "axum-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/axum-idioms into .agents/skills/axum-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "axum-idioms", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add irahardianto/awesome-agv --skill axum-idioms -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install irahardianto/awesome-agv axum-idioms --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/axum-idioms .cursor/skills/axum-idioms && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "axum-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/axum-idioms into .cursor/skills/axum-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "axum-idioms", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/irahardianto/awesome-agv.git --path .agents/skills/axum-idioms--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add irahardianto/awesome-agv --skill axum-idioms -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install irahardianto/awesome-agv axum-idioms --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/axum-idioms .gemini/skills/axum-idioms && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "axum-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/axum-idioms into .gemini/skills/axum-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "axum-idioms", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install irahardianto/awesome-agv axum-idiomsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add irahardianto/awesome-agv --skill axum-idioms -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/axum-idioms .github/skills/axum-idioms && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "axum-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/axum-idioms into .github/skills/axum-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "axum-idioms", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add irahardianto/awesome-agv --skill axum-idioms -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install irahardianto/awesome-agv axum-idioms --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/irahardianto/awesome-agv.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/axum-idioms .opencode/skills/axum-idioms && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "axum-idioms" agent skill from https://github.com/irahardianto/awesome-agv/tree/main/.agents/skills/axum-idioms into .opencode/skills/axum-idioms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "axum-idioms", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
axum-idiomsAxum (0.8+) web framework patterns: type-safe extractors, Tower middleware, route routing, and graceful shutdown.
Axum Idioms is an agent skill from irahardianto/awesome-agv. Axum (0.8+) web framework patterns: type-safe extractors, Tower middleware, route routing, and graceful shutdown. Use when implementing HTTP APIs or web services in Rust. Pair with rust-idioms.
Its SKILL.md is about 4.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering Type safety and REST APIs. It works with Rust. The repository describes itself as: Comprehensive sets of standards and practices designed to elevate the capabilities of AI coding agents. The licence is MIT.
2 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 9e997ba. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are rust).
From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
github.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Axum Idioms loads about 4.8k tokens when it runs. Until then it costs about 51 tokens; SKILL.md has 721 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from irahardianto/awesome-agv at commit 9e997ba, republished under its MIT licence (© irahardianto). 721 words, ~4,758 tokens.
.claude/skills/axum-idioms/SKILL.md (or your agent's skills folder).Axum (0.8+) rewards composability via Tower, type-safe extractors, and zero-cost abstractions. Idiomatic Axum = thin handlers, tower middleware, typed errors.
Version note: This skill targets Axum 0.8+ (released 2025). Key changes from 0.7: path parameter syntax changed from
:nameto{name},Stateextractor is now inaxum::extract, andaxum::servereplacesaxum::Server. If you encounter an existing codebase on 0.7, check the Axum 0.8 changelog before applying these patterns.
Scope: Axum-specific patterns. For Rust fundamentals: @.agents/skills/rust-idioms/SKILL.md. For project structure: @.agents/skills/rust-idioms/references/project-structure.md.
Build routers with Router::new() and method routing:
// ✅ Group by resource, nest for versioning
fn task_routes() -> Router<AppState> {
Router::new()
.route("/tasks", get(list_tasks).post(create_task))
.route("/tasks/{id}", get(get_task).put(update_task).delete(delete_task))
}
fn app(state: Arc<AppState>) -> Router {
let api = Router::new()
.merge(task_routes()) // .merge() combines peer routers
.merge(user_routes());
Router::new()
.nest("/api/v1", api) // .nest() adds prefix to sub-router
.fallback(handle_404) // typed error, not Axum's default plain-text 404
.with_state(state)
}Path parameters use {name} syntax (not :name).
Built-in extractors — Path, Query, Json, State, HeaderMap:
// ✅ Typed and validated at compile time
async fn get_task(
State(state): State<Arc<AppState>>,
Path(id): Path<Uuid>,
) -> Result<Json<TaskResponse>, AppError> {
let task = state.task_service.find(id).await?;
Ok(Json(task.into()))
}Extractor ordering — body-consuming extractors MUST be last:
// ✅ Path before Json (Json consumes the body)
async fn update_task(
State(state): State<Arc<AppState>>,
Path(id): Path<Uuid>,
Json(body): Json<UpdateTaskRequest>,
) -> Result<Json<TaskResponse>, AppError> { ... }
// ❌ Json before Path — won't compile or will fail at runtime
async fn update_task(Json(body): Json<UpdateTaskRequest>, Path(id): Path<Uuid>) { ... }Custom extractors via FromRequestParts (non-body) or FromRequest (body):
// ✅ Custom extractor for authenticated user
impl<S: Send + Sync> FromRequestParts<S> for AuthUser {
type Rejection = AppError;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
let token = parts.headers.get(AUTHORIZATION)
.and_then(|v| v.to_str().ok())
.and_then(|v| v.strip_prefix("Bearer "))
.ok_or(AppError::Unauthorized)?;
decode_jwt(token).map_err(|_| AppError::Unauthorized)
}
}Handle rejections with custom types — never let Axum's default messages leak to clients.
Wrap in Arc, pass via State:
pub struct AppState {
pub db: sqlx::PgPool,
pub task_service: TaskService,
pub config: AppConfig,
}
let state = Arc::new(AppState { db: pool, task_service, config });
let app = Router::new().route("/tasks", get(list_tasks)).with_state(state);Compose state for feature isolation — each feature defines its own state struct, combined at app level.
Never clone AppState directly — wrap in Arc, clone the Arc.
ServiceBuilder for layer composition:
// ✅ Full middleware stack — order matters (outermost runs first)
let app = Router::new()
.nest("/api/v1", api_routes())
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(CompressionLayer::new())
.layer(CorsLayer::permissive()) // development ONLY — see below
.layer(TimeoutLayer::new(Duration::from_secs(30)))
)
.with_state(state);Never ship
CorsLayer::permissive()to production. It allows any origin, any method, any header, and sends noAccess-Control-Allow-Credentials. Use an explicit, allow-listed layer instead. Load allowed origins from config, not literals:
use tower_http::cors::CorsLayer;
use http::HeaderValue;
// ✅ Production-safe — explicit allow-list
fn cors_layer(allowed_origins: &[String]) -> CorsLayer {
let origins: Vec<HeaderValue> = allowed_origins
.iter()
.filter_map(|o| HeaderValue::try_from(o).ok())
.collect();
CorsLayer::new()
.allow_origin(origins) // explicit list, NEVER Any in prod
.allow_methods([ // methods you actually serve
axum::http::Method::GET,
axum::http::Method::POST,
axum::http::Method::PUT,
axum::http::Method::DELETE,
])
.allow_headers([
axum::http::header::AUTHORIZATION,
axum::http::header::CONTENT_TYPE,
axum::http::header::ACCEPT,
])
.allow_credentials(true) // required for cookies / auth
.max_age(Duration::from_secs(3600)) // cache preflight 1h
}
// .layer(cors_layer(&config.cors.allowed_origins))Rule:
allow_credentials(true)is incompatible withallow_origin(Any)— browsers reject it. If you need credentials, you MUST enumerate origins. Seesecurity-principles.md§CORS.
Custom middleware with from_fn:
async fn auth_middleware(
State(state): State<Arc<AppState>>,
request: Request,
next: Next,
) -> Result<Response, AppError> {
let token = request.headers().get(AUTHORIZATION)
.and_then(|v| v.to_str().ok())
.and_then(|v| v.strip_prefix("Bearer "))
.ok_or(AppError::Unauthorized)?;
state.auth_service.validate(token).await?;
Ok(next.run(request).await)
}
// Apply to specific routes with route_layer
let protected = Router::new()
.route("/tasks", get(list_tasks))
.route_layer(middleware::from_fn_with_state(state.clone(), auth_middleware));Layer ordering: ServiceBuilder applies bottom-to-top — last .layer() wraps closest to handler.
Propagate correlation IDs with TraceLayer:
use tower_http::trace::TraceLayer;
use tracing::Span;
// ✅ Inject x-request-id into every span for log correlation
let trace_layer = TraceLayer::new_for_http()
.make_span_with(|request: &Request<_>| {
let request_id = request
.headers()
.get("x-request-id")
.and_then(|v| v.to_str().ok())
.map(String::from)
.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
tracing::info_span!(
"request",
method = %request.method(),
uri = %request.uri(),
request_id = %request_id,
)
});
let app = Router::new()
.nest("/api/v1", api_routes())
.layer(trace_layer)
.with_state(state);All
tracing::info!,warn!,error!calls inside a handler will automatically inherit the span fields above (method, uri, request_id). This satisfies thecorrelationIdrequirement from the Logging Mandate. Seelogging-implementation/SKILL.md§Rust for the fullinit_tracing()setup.
Request body size limits — prevent denial-of-service via large payloads:
use axum::extract::DefaultBodyLimit;
let app = Router::new()
.nest("/api/v1", api_routes())
.layer(DefaultBodyLimit::max(1024 * 1024)) // 1 MB global limit
.with_state(state);
// Per-route override for file uploads:
let upload_routes = Router::new()
.route("/upload", post(upload_file))
.layer(DefaultBodyLimit::max(50 * 1024 * 1024)); // 50 MB for uploadsUnified AppError enum with IntoResponse:
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("not found: {0}")] NotFound(String),
#[error("validation failed: {0}")] Validation(String),
#[error("unauthorized")] Unauthorized,
#[error("forbidden")] Forbidden,
#[error(transparent)] Internal(#[from] anyhow::Error),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, msg) = match &self {
Self::NotFound(m) => (StatusCode::NOT_FOUND, m.clone()),
Self::Validation(m) => (StatusCode::UNPROCESSABLE_ENTITY, m.clone()),
Self::Unauthorized => (StatusCode::UNAUTHORIZED, "unauthorized".into()),
Self::Forbidden => (StatusCode::FORBIDDEN, "forbidden".into()),
Self::Internal(e) => {
tracing::error!(error = %e, "internal server error");
(StatusCode::INTERNAL_SERVER_ERROR, "internal server error".into())
}
};
(status, Json(serde_json::json!({ "error": msg }))).into_response()
}
}Handler return type: always Result<impl IntoResponse, AppError>.
Convert rejections into AppError for consistent JSON error shape.
Json<T> for standard responses, (StatusCode, Json<T>) tuple for non-200:async fn list_tasks(...) -> Result<Json<Vec<TaskResponse>>, AppError> { ... }
async fn create_task(...) -> Result<(StatusCode, Json<TaskResponse>), AppError> {
Ok((StatusCode::CREATED, Json(task.into())))
}Response builder for headers, streaming, or non-JSON (CSV, files).validator crate with #[derive(Validate)]:
#[derive(Debug, Deserialize, Validate)]
pub struct CreateTaskRequest {
#[validate(length(min = 1, max = 255))]
pub title: String,
#[validate(range(min = 1, max = 5))]
pub priority: u8,
}Custom ValidatedJson<T> extractor — implement FromRequest<S> that deserializes via Json<T> then calls value.validate(), converting failures to AppError::Validation:
use axum::extract::{FromRequest, Request};
use axum::Json;
use serde::de::DeserializeOwned;
use validator::Validate;
pub struct ValidatedJson<T>(pub T);
impl<S, T> FromRequest<S> for ValidatedJson<T>
where
S: Send + Sync,
T: DeserializeOwned + Validate,
{
type Rejection = AppError;
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
let Json(value) = Json::<T>::from_request(req, state)
.await
.map_err(|e| AppError::Validation(e.to_string()))?;
value.validate().map_err(|e| AppError::Validation(e.to_string()))?;
Ok(ValidatedJson(value))
}
}
// Usage — replaces bare Json<T> in handler signatures
async fn create_task(
State(state): State<Arc<AppState>>,
ValidatedJson(body): ValidatedJson<CreateTaskRequest>,
) -> Result<(StatusCode, Json<TaskResponse>), AppError> {
let task = state.task_service.create(body).await?;
Ok((StatusCode::CREATED, Json(task.into())))
}Separate request and response types — never expose domain models directly to the API:
// --- Request type (deserialize + validate) ---
#[derive(Debug, Deserialize, Validate)]
#[serde(rename_all = "camelCase")]
pub struct CreateTaskRequest {
#[validate(length(min = 1, max = 255))]
pub title: String,
#[serde(default)]
pub description: Option<String>,
#[validate(range(min = 1, max = 5))]
#[serde(default = "default_priority")]
pub priority: u8,
}
fn default_priority() -> u8 { 3 }
// --- Response type (serialize) ---
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskResponse {
pub id: Uuid,
pub title: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub priority: u8,
pub created_at: DateTime<Utc>,
}
// --- Domain → Response conversion ---
impl From<Task> for TaskResponse {
fn from(task: Task) -> Self {
Self {
id: task.id,
title: task.title,
description: task.description,
priority: task.priority,
created_at: task.created_at,
}
}
}Use .into() in handlers for clean conversion:
async fn get_task(
State(state): State<Arc<AppState>>,
Path(id): Path<Uuid>,
) -> Result<Json<TaskResponse>, AppError> {
let task = state.task_service.find(id).await?;
Ok(Json(task.into())) // From<Task> for TaskResponse
}For serde attribute patterns (rename_all, deny_unknown_fields, skip_serializing_if), see rust-idioms/references/serde-patterns.md.
For universal testing principles, see
.agents/rules/testing-strategy.md. Below: Axum-specific patterns only.
tower::ServiceExt::oneshot — test handlers without spawning a server:
#[tokio::test]
async fn test_create_task_returns_201() {
let app = app(Arc::new(test_app_state().await));
let response = app.oneshot(
Request::builder().method("POST").uri("/api/v1/tasks")
.header("content-type", "application/json")
.body(Body::from(r#"{"title":"Test","priority":3}"#)).unwrap(),
).await.unwrap();
assert_eq!(response.status(), StatusCode::CREATED);
}Mock state helpers — inject trait-based test doubles for isolation:
/// Build test AppState with mock services (no real DB needed)
fn test_app_state() -> Arc<AppState> {
let mock_task_service = MockTaskService::new(); // implements TaskService trait
Arc::new(AppState {
task_service: Box::new(mock_task_service),
config: test_config(),
})
}This follows the trait-based DI pattern from
@.agents/rules/architectural-pattern.md— swap real I/O implementations for test doubles at theAppStatelevel.
tower dev-dependency required — add tower = { version = "0.5", features = ["util"] } to [dev-dependencies] to use ServiceExt::oneshot.
Integration tests use a real database via sqlx::test or Testcontainers.
Container orchestrators (Kubernetes, Docker stop) send SIGTERM, not SIGINT — handle BOTH. Use tokio_util::sync::CancellationToken (the recommended cancellation primitive per @.agents/skills/rust-idioms/SKILL.md §Async and Concurrency) so in-flight handlers and background tasks can observe the shutdown and unwind cooperatively. Axum's with_graceful_shutdown then drains active connections before exiting.
use tokio::signal;
use tokio_util::sync::CancellationToken;
// Wire the token into AppState so background tokio tasks can observe shutdown.
let shutdown = CancellationToken::new();
let state = Arc::new(AppState { /* ... */ shutdown: shutdown.clone() });
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal(shutdown.clone()))
.await?;/// ✅ Unified signal handler — fires on SIGINT (ctrl-c) OR SIGTERM (container stop).
async fn shutdown_signal(token: CancellationToken) {
let ctrl_c = async { signal::ctrl_c().await.expect("install ctrl-c handler") };
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("install SIGTERM handler")
.recv().await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => tracing::info!("SIGINT received, shutting down"),
_ = terminate => tracing::info!("SIGTERM received, shutting down"),
}
token.cancel(); // notify background tasks + long-lived handlers to unwind
}Why: Axum stops accepting new connections and drains in-flight requests before exiting. The shared
CancellationTokenlets your background workers (queue consumers, scheduled jobs, long-poll handlers) observe the same shutdown and exit cooperatively instead of being killed mid-write. Addtokio-util(with thertfeature) to your dependencies. Seerust-idioms§Async and Concurrency for the cancellation-safety policy.
Extension instead of State — Extension is untyped and pre-0.6; use State<T> alwaysArc, clone the Arctokio::task::spawn_blocking for CPU-bound or blocking I/OJson, Form) must be the last parameterAppError with IntoResponse for consistent error shapetracing::error!, return generic message to clientSame tooling as Rust. See @.agents/skills/rust-idioms/SKILL.md#clippy-and-formatting.
© irahardianto, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/axum-idioms of irahardianto/awesome-agv.
Open the folder on GitHubat commit 9e997ba
Axum Idioms next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Axum Idioms this skillirahardianto/awesome-agv | 156 | — | ~4.8k | Automated safety check: Pass | MIT | |
| RTK Rust Design Patternsrtk-ai/rtk | 83k | — | ~1.9k | Automated safety check: Pass | Apache-2.0 | |
| Rust Path Typesopeninterpreter/openinterpreter | 69k | 2 repos | ~605 | Automated safety check: Pass | Apache-2.0 | |
| Rust Ffiariebovenberg/whenever | 2.4k | — | ~2.5k | Automated safety check: Pass | MIT | |
| Strict Programming Practicescode-yeongyu/oh-my-openagent | 70k | — | ~9.5k | Automated safety check: Pass | Custom licence | |
| API Changesoftware-mansion/smelter | 734 | — | ~450 | Automated safety check: Notes | Custom licence |
rtk-ai/rtk
Describes seven Rust design patterns for the RTK CLI filter modules, with when to use each, RTK examples, and notes on when a pattern is overkill.
openinterpreter/openinterpreter
Rules for choosing Rust types for filesystem paths in new Codex code, covering protocol types, internal use and model tool arguments.
ariebovenberg/whenever
Instructions for using whenever's internal Rust FFI abstractions
code-yeongyu/oh-my-openagent
Applies strict, type-first coding rules for Python, Rust, TypeScript and Go, loading the matching language reference before the agent writes or edits any code.
software-mansion/smelter
Run the full API change workflow after modifying types in smelter-api.
utensils/nxv
Find any version of any Nix package across nixpkgs git history using the nxv CLI or HTTP API.
irahardianto/awesome-agv
Commits to one bold aesthetic direction, sets up a CSS token system for it, then builds the interface in Vue or plain HTML using those tokens.
irahardianto/awesome-agv
Profile-driven performance optimization protocol. An agent skill from irahardianto/awesome-agv.
irahardianto/awesome-agv
Coding conventions for Angular 19 and later: standalone components, signals, OnPush change detection, lazy routes and where RxJS still belongs.
irahardianto/awesome-agv
Rules for designing CI/CD pipelines in layers: universal lint, test and scan stages, container builds with SBOM attestation, and GitOps for orchestrated deployments.
irahardianto/awesome-agv
Hono lightweight web framework patterns: type-safe route handlers, middleware composition, Zod validation, and RPC clients for Cloudflare Workers, Node, or Bun.
irahardianto/awesome-agv
Mobile E2E testing patterns — Flutter integrationtest, Patrol, Maestro, golden testing, device matrix, and test data management.
Works with
Categories
Axum (0.8+) web framework patterns: type-safe extractors, Tower middleware, route routing, and graceful shutdown. Axum Idioms is an agent skill from irahardianto/awesome-agv.8+) web framework patterns: type-safe extractors, Tower middleware, route routing, and graceful shutdown.
Axum Idioms fits situations like: implementing HTTP APIs; web services in Rust.
Run `npx skills add irahardianto/awesome-agv --skill axum-idioms -a claude-code`. Or copy the skill folder (.agents/skills/axum-idioms in irahardianto/awesome-agv) into .claude/skills/axum-idioms in your project. Claude Code loads it when a task matches its description.
Run `npx skills add irahardianto/awesome-agv --skill axum-idioms -a codex`. Or copy the skill folder (.agents/skills/axum-idioms in irahardianto/awesome-agv) into .agents/skills/axum-idioms in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add irahardianto/awesome-agv --skill axum-idioms -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/axum-idioms, .gemini/skills/axum-idioms, .github/skills/axum-idioms and .opencode/skills/axum-idioms in your project.
SKILL.md names no scripts, command-line tools or credentials: Axum Idioms is instructions for the agent only.
SKILL.md names 1 domain. As links in the text: github.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Axum Idioms is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.8k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Axum Idioms: RTK Rust Design Patterns (rtk-ai/rtk, 83k stars), Rust Path Types (openinterpreter/openinterpreter, 69k stars), Rust Ffi (ariebovenberg/whenever, 2.4k stars) and Strict Programming Practices (code-yeongyu/oh-my-openagent, 70k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
irahardianto (a GitHub user) maintains it in irahardianto/awesome-agv, which has 156 GitHub stars. The repository holds 34 skills in this directory. The repository was last updated on October 5, 2026.
Source: irahardianto/awesome-agv on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.