hotaru 0.8.3

Small, sweet, easy framework with a protocol-neutral, no_std-ready core
Documentation

The Hotaru 0.8 era starts from 23/May/2026.

Hotaru Web Framework

Latest Version Crates.io MIT License

Small, sweet, easy framework with a protocol-neutral, no_std-ready core

Overview

The name 'Hotaru' comes from the Japanese Character '蛍(ほたる)' represents the firefly.

Official Website | Example Project

MSRV: 1.86

Stability in 0.8.x

The tokio + HTTP stack (default features trans, http, tokio) is the tested, supported path and is safe for production use today.

Everything else is experimental and will stabilize by 0.8.7:

  • RuntimeSpec trait surface (currently only hotaru_rt_tokio implements it; other runtime backends are planned, not shipped)
  • no_std builds of hotaru_core (Cortex-M / RISC-V bare-metal, CI-verified but not yet exercised by a real embedded backend)
  • IO adapter crates: hotaru_io_futures ships as a standalone crate (limited real-world use). hotaru_io_embedded is not published in 0.8.3 — it stays in-repo until embedded stabilizes (targeted 0.8.5+). The hotaru umbrella is std-only; once the embedded backend ships, bare-metal projects will depend on hotaru_core + hotaru_io_embedded directly.
  • Embassy runtime backend (planned)

If you are shipping something now, stick with the tokio default and revisit the experimental paths as they land.

Key Features

  • Multi-Protocol: HTTP/1.1 and HTTPS (TLS) ship out of the box. The Protocol trait is an open extension point for custom TCP-based protocols (WebSocket, MQTT, and other frames), though no non-HTTP protocol ships in this workspace today
  • Server + Client: Endpoints for inbound traffic, outpoints for outbound. Same protocol trait, same routing, same middleware
  • Runtime-Neutral Core: hotaru_core speaks to any async runtime through the RuntimeSpec trait. Tokio ships today via hotaru_rt_tokio (the only runtime backend so far); other runtimes can plug in via the same sibling-crate pattern. IO adapters are further along, with hotaru_io_tokio, hotaru_io_futures, and hotaru_io_embedded already shipping
  • no_std-Ready Core: hotaru_core builds bare-metal on Cortex-M4/M7 and RISC-V (with atomics) under alloc. CI verified on thumbv7em-none-eabihf and riscv32imac-unknown-none-elf
  • Sync main: fn main() { run_server!(APP); }. No async fn main, no #[tokio::main]
  • Ergonomic Macros: endpoint! / outpoint! / middleware! DSL in three flavors (trans, semi-trans, attr)
  • Full-Stack: Akari template rendering, form/URL-encoded body parsing, session cookies, HTTP body compression (gzip / deflate / brotli / zstd) all built in
  • Flexible Routing: Regex, literal, and pattern segments (<int:id>, <uuid:token>, <**path>) with a tree walker

Quick Start

use hotaru::prelude::*;
use hotaru::http::*;

LServer!(
    APP = Server::new()
        .binding("127.0.0.1:3003")
        .single_protocol(ProtocolBuilder::new(HTTP::server(HttpSafety::default())))
        .build()
);

fn main() {
    run_server!(APP);
}

endpoint! {
    APP.url("/"),
    pub index<HTTP> {
        text_response("Hello, Hotaru!")
    }
}

run_server!(APP) builds a tokio runtime, blocks the current thread, and shuts down on Ctrl+C. No async fn main, no #[tokio::main]. See Core Concepts for the sibling macros (run_server_until!, run_server_no_block!, run_server_no_block_until!) when you need a custom stop source or multi-server orchestration.

Installation

Using the CLI Tool (Recommended)

Install the Hotaru CLI tool:

cargo install hotaru

Create a new project:

hotaru new my_app
cd my_app
cargo run

Manual Installation

Add to your Cargo.toml:

[dependencies]
hotaru = "0.8.3"
tokio = { version = "1", features = ["full"] }

Optional Features

Default features: trans, http, tokio. Cargo's additive feature unification means sub-features pull in their prerequisites automatically — you never have to enable a base feature by hand.

Protocol stack

  • http (default-on): HTTP/1.1 stack (hotaru_http + ahttpm). Opt out with default-features = false for protocol-only builds (e.g. gRPC-only deployments) — hotaru::http::*, HTTP, HttpContext, HttpRequest, HttpResponse, etc. then disappear from the crate surface.
  • tokio (default-on): Tokio runtime + TCP/IO defaults for the umbrella crate (Server, Client, Url, S* aliases, TcpTransport, TokioRuntime). If you disable default features but still use those defaults, re-enable tokio.
  • https: TLS/HTTPS support — surfaces HTTPS, TlsTransport, TlsOutboundTarget, TlsClientConfig. Implies http.
  • http_compression: HTTP body codecs for Content-Encoding (gzip / deflate / brotli / zstd). Off by default because brotli + zstd together add ~7 s to a clean build. Implies http. Without this feature, ContentCoding::decode_compressed / encode_compressed return io::ErrorKind::Unsupported for compressed bodies.

Endpoint macro flavor — pick one (see Core Concepts):

  • trans (default) — bang macro with hotaru-blocks body
  • semi-trans — stacked attributes above an fn
  • attr — single attribute with args

Misc

  • debug: Enable debug logging for development and troubleshooting.
  • external-ctor: Use the external ctor crate instead of Hotaru's built-in constructor implementation. When enabling, you must also add ctor to your dependencies:
    [dependencies]
    hotaru = { version = "0.8.3", features = ["external-ctor"] }
    ctor = "0.4.0"
    tokio = { version = "1", features = ["full"] }
    

Example — HTTPS server with body compression:

[dependencies]
hotaru = { version = "0.8.3", features = ["https", "http_compression"] }
tokio = { version = "1", features = ["full"] }

Example — gRPC-only (no HTTP):

[dependencies]
hotaru = { version = "0.8.3", default-features = false, features = ["trans", "tokio"] }
hotaru_grpc = "..."
tokio = { version = "1", features = ["full"] }

Binary Commands

Use the CLI to scaffold projects — it generates build.rs for asset copying and src/resource.rs for runtime template/static lookup, which are non-trivial to wire up by hand.

cargo install hotaru                   # install the CLI (see Installation above)
hotaru new my_app                      # scaffold a new project
hotaru init                            # or scaffold into the current Cargo crate
cd my_app && cargo run                 # serves http://127.0.0.1:3003

Project Structure

my_app/
├── Cargo.toml              # Dependencies and project metadata
├── build.rs                # Asset copying build script
├── src/
│   ├── main.rs            # Application entry point with LServer! + endpoint!
│   └── resource.rs        # Resource locator helpers
├── templates/             # Akari HTML templates
└── programfiles/          # Static assets (CSS, JS, images)

The build script copies templates/ and programfiles/ to the target directory at compile time so they're accessible at runtime.

Core Concepts

Endpoints

Three macro flavors, enabled by the trans / semi-trans / attr cargo features. Pick one per project; trans is the default. All three register the same route at startup; they only differ in syntax.

trans (default) — bang macro with hotaru-blocks body:

endpoint! {
    APP.url("/users/<int:id>"),
    pub get_user<HTTP> {
        let user_id = req.param("id").unwrap_or_default();
        akari_json!({ id: user_id })
    }
}

semi-trans — stacked attributes above an fn:

#[endpoint]
#[url("/users/<int:id>")]
pub fn get_user<HTTP>() {
    let user_id = req.param("id").unwrap_or_default();
    akari_json!({ id: user_id })
}

attr — single attribute with args:

#[endpoint("/users/<int:id>")]
pub fn get_user<HTTP>() {
    let user_id = req.param("id").unwrap_or_default();
    akari_json!({ id: user_id })
}

akari_json! is the JSON-response macro re-exported via hotaru::prelude; it already wraps json_response(...) so callers don't compose the two. Keys are bare idents (not "..."). req.param(...) returns Option<String>.

Macro Notes

  • Endpoints and middleware auto-register at startup — no manual router.register().
  • trans form: brace syntax {} with doc comments inside the block; angle-bracket body defaults to req. Optional fn-style pub fn name(req: HTTP) { ... } is also accepted.
  • Remaining readme examples use trans. To switch, set default-features = false on the hotaru dependency and turn on the flavor you want, e.g. hotaru = { version = "0.8.3", default-features = false, features = ["semi-trans", "http", "tokio"] }. Cargo feature unification would otherwise keep trans on alongside it; remember to re-add http and tokio since default-features = false also drops the default HTTP stack and Tokio facade defaults.
  • See macro_ra.md for syntax details. Analyzer support is planned.

Middleware

Attach a middleware to a protocol via the ProtocolBuilder. Add htmstd = "0.8" to your Cargo.toml for the bundled middleware library:

use htmstd::CookieSession;

LServer!(
    APP = Server::new()
        .binding("127.0.0.1:3003")
        .single_protocol(
            ProtocolBuilder::new(HTTP::server(HttpSafety::default()))
                .append_middleware::<CookieSession>(),
        )
        .build()
);

CookieSession writes encrypted session cookies. By default, those cookies are production-safe (Secure, HttpOnly, SameSite=Lax, Path=/). If you are running a plain-HTTP development environment, configure the cookie safety policy explicitly through the app config:

use htmstd::{CookieSecurity, CookieSession, CookieSessionSettings};

LServer!(
    APP = Server::new()
        .binding("127.0.0.1:3003")
        .mode(RunMode::Development)
        .set_config(CookieSessionSettings::new().security(CookieSecurity::Auto))
        .single_protocol(
            ProtocolBuilder::new(HTTP::server(HttpSafety::default()))
                .append_middleware::<CookieSession>(),
        )
        .build()
);

CookieSecurity::Auto follows RunMode: Production/Beta keep Secure cookies, while Development/Build allow plain HTTP cookies. For production, also configure a stable SessionSecret so sessions survive process restarts.

Middleware can also be attached per-endpoint via middleware = [...] inside the endpoint! block — see example_hotaru for the pattern.

Templates

Render HTML with Akari via akari_render! — the macro looks up the template file and substitutes the named bindings:

endpoint! {
    APP.url("/profile"),
    pub profile<HTTP> {
        akari_render!("profile.html", name = "Alice")
    }
}

HTTP Safety Configuration

Configure request validation per endpoint:

endpoint! {
    APP.url("/upload"),
    config = [HttpSafety::new()
        .with_max_body_size(50 * 1024 * 1024)  // 50MB
        .with_allowed_methods(vec![HttpMethod::POST])
    ],
    pub upload<HTTP> {
        // Handle file upload
    }
}

Examples

Check out the example repository for:

  • Basic routing and handlers
  • Form processing and file uploads
  • Session management with cookies
  • CORS configuration
  • Multi-protocol applications

Crate Ecosystem

Hotaru is built on a modular architecture:

  • hotaru - Main framework with convenient API
  • hotaru_core - Core protocol and routing engine
  • hotaru_trans - Procedural macros for endpoint! and middleware!
  • hotaru_http - HTTP implementation for Hotaru
  • hotaru_tls - TLS/HTTPS implementation for Hotaru
  • hotaru_rt_tokio - Tokio runtime backend (TokioRuntime)
  • hotaru_io_tokio - Tokio TCP/IO backend (TcpTransport, TokioIo)
  • hotaru_io_futures - futures-io adapter backend (FuturesIo, experimental)
  • hotaru_io_embedded - embedded-io-async adapter backend (EmbeddedIo) — experimental; not published in 0.8.3, planned for 0.8.5+
  • hotaru_lib - Utility functions (compression, encoding, etc.)
  • htmstd - Standard middleware library (CORS, sessions)

Changelog

0.8.3 (Current)

  • Core/backend split: hotaru_core is now backend-neutral at the public type layer. Concrete Tokio runtime and TCP/IO implementations moved into sibling crates (hotaru_rt_tokio, hotaru_io_tokio), while the umbrella hotaru crate keeps the familiar Tokio defaults.
  • IO adapter crates: futures-io and embedded-io-async adapters moved out of core into hotaru_io_futures and hotaru_io_embedded. Each backend uses local wrapper types (TokioIo<T>, FuturesIo<T>, EmbeddedIo<T>) so adapter impls stay additive and avoid trait-coherence conflicts.
  • Simpler hotaru_core features: core no longer owns io_*, rt_*, tokio, or embassy feature flags. It now keeps only the platform axis (std / embedded) and task-mobility axis (spawn_send / spawn_local); runtime and IO backends are selected through backend crates, or through the std-only hotaru umbrella (Tokio and futures backends only — the embedded backend is consumed directly).
  • hotaru umbrella is std-only: the umbrella no longer re-exports hotaru_io_embedded or exposes embedded / io_embedded features (its prelude pulls std-only items such as std::thread::sleep and once_cell::sync::Lazy). hotaru_io_embedded is not published in 0.8.3 (targeted 0.8.5+); once it ships, no_std / bare-metal projects will depend on hotaru_core + hotaru_io_embedded directly.
  • Runtime abstraction cleanup: RuntimeSpec is the backend-neutral runtime trait, with Tokio implemented externally by hotaru_rt_tokio::TokioRuntime. Framework types (Server, Client, builders, and URL/protocol-entry types) now carry explicit transport/runtime parameters in core, while hotaru restores ergonomic defaults.
  • MaybeSend task-mobility model: async framework surfaces use MaybeSend so spawn_send builds keep real Send bounds and spawn_local builds can support local !Send futures. hotaru_io_embedded gates its actual embedded-io-async trait impls on spawn_local, not on the embedded platform flag.
  • Framework-owned async IO traits: HotaruRead, HotaruWrite, HotaruBufRead, HotaruBufWrite, HotaruIOError, HotaruBufReader, and HotaruBufWriter provide the common IO trait surface used by transports and protocols without hardcoding Tokio types in core.
  • Native async trait surfaces: core transport/protocol traits use return-position impl Future instead of async-trait, reducing proc-macro dependency surface and avoiding unnecessary boxed futures at trait boundaries.
  • Protocol-agnostic endpoint outcomes: EndpointOutcome<C> lets generated endpoints apply return values to any request context. HTTP keeps the existing HttpResponse endpoint style, while non-HTTP/inbound-only protocols can use () outcomes without placeholder responses.
  • Per-protocol URL parsing hooks: Protocol can customize URL tokenization/literal parsing, and URL parser internals such as RawToken, TypeKind, tokenize, and tokens_to_patterns are re-exported for protocol-specific routing work.
  • Preferred-language middleware: htmstd adds PreferredLanguageMiddleware, PreferredLanguage, settings, and request-extension helpers for parsing and negotiating the Accept-Language header.
  • no_std preparation: core continues moving toward no_std readiness with alloc usage, core imports, Akari lite/no_std alignment, generic IO errors, and backend-neutral abstractions. Real Embassy wiring remains deferred; embedded support is still experimental.
  • Sync-main entry macros: run_server! / run_server_until! (blocking) and run_server_no_block! / run_server_no_block_until! (fire-and-forget) let users run a server from an ordinary fn main() — no #[tokio::main], no async fn main. Backed by a new BlockingRuntimeCap capability trait implemented by TokioRuntime.

0.8.2

  • http and http_compression moved to optional features (compression default-off)
  • HTTP re-exports relocated to hotaru::http
  • Clean builds ~35% faster (dropped tracing, gated heavy codecs)
  • regex bumped 1.5.6 -> 1.12
  • AccessPointTable switched to PRwLock (no more poisoning)
  • hotaru_trans .. middleware inheritance now honors the URL's app ident
  • hotaru_trans anonymous-fn _ form fixed
  • Client / outpoint runtime paired with Client<TS>, the outpoint! macro, and run! / call! invocation sugar
  • Protocol trait reshape: channel-based open_channel / handle / send; new Channel trait + ProtocolFlow
  • RequestContext rework: Default supertrait, type Channel anchor, inject_request / into_response; new EmptyError
  • Result-typed execution chain — no boxing at chain boundaries
  • Named access points with a single canonical registration funnel
  • Instance-based transports: TransportSpec::Inbound / Outbound replace Accepter / Connector
  • HTTPS feature: HTTPS = Http1Protocol<TlsStream, TlsTransport>
  • New LServer! / LClient! / LUrl! / LPattern! macros replace LApp!

0.7.x

  • Multi-protocol support (HTTP, WebSocket, custom TCP)
  • Enhanced security controls with HttpSafety
  • Improved middleware system with protocol inheritance
  • Performance optimizations in URL routing
  • Comprehensive security testing
  • .worker() method now properly configures dedicated worker threads per Server instance
  • Fixed hotaru new and hotaru init to generate correct endpoint! macro syntax
  • Built-in constructor implementation (no external ctor dependency required)
  • Fn-style blocks: New syntax pub fn name(req: HTTP) { ... } for endpoint! and middleware! macros (original hotaru blocks syntax preserved)
  • Bug fix for URL routing

0.6.x

  • Protocol abstraction layer
  • Request context improvements
  • Standard middleware library (htmstd)
  • Cookie-based session management

0.4.x and earlier

  • Async/await support with Tokio
  • Akari templating integration
  • Cookie manipulation APIs
  • File upload handling
  • Form data processing improvements

Learn More

Video Resources URL
Quick Tutorial Youtube: https://www.youtube.com/watch?v=8pV-o04GuKk&t=6s Bilibili: https://www.bilibili.com/video/BV1BamFB7E8n/

AI Declaration of each Mod

We believe in transparency about AI-assisted development. The framework is governed jointly by two maintainer groups using a shared four-tier system that prioritizes understanding over line counts.

Maintained by: PMINE/Research

Name Tier Comments
hotaru_core/app Author-Owned
hotaru_core/connection Author-Owned
hotaru_core/executable Author-Owned
hotaru_core/url Author-Owned
hotaru_core/protocol Author-Owned
hotaru_http/trails Co-Authored
hotaru_http/* Human-Led
hotaru_mqtt/broker Co-Authored
hotaru_mqtt/traits Co-Authored
hotaru_mqtt/* Human-Led
hotaru_lib Human-Led Basic API Access
h2per Co-Authored Integration of Hyper - Not stable yet
htmstd/cors Human-Led
htmstd/session Human-Led

Maintained by: Project-StarFall

Name Tier Comments
hotaru_trans/endpoint Author-Owned Proof and language design must be fully understood by humans
hotaru_trans/outpoint Author-Owned Proof and language design must be fully understood by humans
hotaru_trans/middleware Author-Owned Proof and language design must be fully understood by humans
hotaru_trans/cors Co-Authored Trivial user-level abstraction
ahttpm Co-Authored Imports akari_macro plus improvements
SFX Co-Authored Trivial user-level abstraction
akari External https://crates.io/crates/akari
akari_lang External (TBD)
akari_macro External https://crates.io/crates/akari

Shared term meanings

Term Meaning
Forbidden The intelligence work in this module — design decisions, proof obligations, language semantics, novel logic — is authored by humans. AI is not used for this content (the mechanical/test/doc carve-out in operating rule 2 still applies). Reserved for modules where the work is the thinking, not the typing.
Author-Owned AI may assist with drafts and completion, but the committed code reads as the author's own throughout. A reviewer should not be able to tell where AI helped. The module signals "a human owns the design and the prose."
Human-Led The human authored the structure and the load-bearing pieces; AI filled in helpers, repetitive sections, or boilerplate. Some sections may visibly bear AI's hand, but the design choices and non-trivial logic are clearly human. The author can defend every part without re-consulting AI.
Co-Authored AI participated substantively in both design exploration and implementation. The human author has internalized the result and can defend, modify, and debug without re-prompting. Appropriate for well-understood patterns and third-party integrations.

The understanding requirement is uniform across Author-Owned, Human-Led, and Co-Authored: the author can explain any line, modify surrounding code without AI help, and walk a reviewer through the code on request. The tiers differ only in where AI's voice is allowed to show through, not in what the author owes the team.

Operating rules

  1. No quantification. Tiers describe the kind of collaboration, not the amount of AI-authored code. Counting lines is brittle and incentivizes the wrong behavior.
  2. Tests, documentation, and mechanical typing are permitted in every tier — including Forbidden. AI assistance is allowed across all modules for: unit tests; doc comments and inline prose; and mechanical typing where the design decision has already been made by a human and AI is only writing it out (e.g., applying a settled pattern across similar cases, expanding hand-authored pseudocode, regenerating a table from a spec). The defining criterion is that no intelligence work is delegated to AI — design, proof, and semantics decisions remain with the human. The author remains responsible for understanding what was generated.
  3. Reviewer-driven understanding check. Any reviewer may flag a PR with "this doesn't feel author-owned" — regardless of the module's tier. The author clears the flag by demonstrating understanding in PR comments or a short walkthrough. Flags are requests for evidence, not accusations.
  4. Smell-test threshold scales with tier. Author-Owned code is flagged if any section visibly reads as AI-generated. Human-Led is flagged if the structural code reads as AI-generated or AI's hand pervades rather than appearing locally. Co-Authored is flagged only if the author cannot defend the code in review.
  5. Tier reflects the work, not preferences. Maintainers set tiers based on the nature of the module. If the character of a module changes, the tier is re-set rather than stretched.
  6. External code is outside this policy. AI-authored code arriving through a third-party crate is governed by that crate's own conventions, transparently linked.

📄 License

MIT License — see LICENSE.txt.

Copyright (c) 2024-2026 @ Field of Dreams Studio (FDS) & Project-StarFall & PMINE-FDS