Imported from tq02ksu/hugrs (
AGENTS.md). Install upstream withnpx skills add tq02ksu/hugrs. Copyright stays with the author.
AGENTS.md
Project Overview
HugRS is a transparent caching proxy for HuggingFace and ModelScope model files. Files are split into 4MB chunks, each keyed by SHA256. The project now provides:
hugrs: daemon process with config file, environment variable, and CLI override supporthugrsctl: management client for service, repo, and file operations- control-plane admin API under
/_hugrs/...
Core Design Principles
- Transparent cache: upstream responses are forwarded as-is. Do NOT modify content-type, headers, or response body.
- Proxy follows redirects: upstream HuggingFace uses 302→xet-bridge redirect chains. The proxy MUST follow redirects internally and return the final response to clients. Clients should never see 30x from upstream.
- Redirect transparency: 302 responses are followed internally. Headers from the 302 (X-Repo-Commit, X-Linked-Size, X-Linked-ETag) and final 200 (Content-Length, ETag, Content-Type) are merged. The client always receives 200 with the combined metadata.
- Metadata first: HEAD requests cache file metadata (size, etag, x-repo-commit) in the
filestable without downloading content. Subsequent GET/POST uses cached metadata for Range/Content-Length. - No guessing: never invent content-type, filenames, or other response metadata. Take it from upstream or don't include it. There is no fallback default for content-type like
application/octet-stream— every byte of response metadata must trace back to an upstream source. - Partial downloads resume: interrupted GET downloads restart from the last completed chunk.
file_chunkstracks which chunks are cached. - Immutable chunks: chunk data is keyed by SHA256 and never modified. Same chunk (same hash) is reused across multiple files.
Tech Stack
- Language: Rust (stable)
- Runtime: tokio (async)
- HTTP Framework: axum
- SQLite: rusqlite (bundled, WAL mode)
- S3: aws-sdk-s3
- CLI: clap (derive)
- HTTP Client: reqwest
- Error Handling: anyhow + thiserror
Build & Run Commands
# Build
cargo build
# Run daemon
cargo run
# Run management client
cargo run --bin hugrsctl -- service
# CLI help
cargo run --bin hugrsctl -- --help
# Tests
cargo test
# Lint
cargo clippy --all-features
# Format
cargo fmt
# Release build
cargo build --release
Code Conventions
- Use
anyhow::Result<T>for application-level errors,thiserrorfor library errors - Async functions return
Result<T>from anyhow - SQLite accessed via
rusqlite::Connectionwith WAL pragma enabled at startup - Storage backends implement the
StorageBackendtrait - CLI uses clap derive macros
- Clippy lint levels are centralized in
Cargo.tomlunder[lints.clippy] - Keep CI lint execution thin: it should run Cargo/Clippy, not redefine lint policy in workflow flags
- Prefer curated project lints over crate-level
#![forbid(...)]attributes unless a rule truly must not be overridden - Follow standard Rust naming conventions (snake_case, CamelCase)
- Keep modules focused: one module = one responsibility
- No comments unless code is genuinely non-obvious
Documentation
- Bilingual docs must stay in sync:
README.md↔README_zh.mddocs/CONFIG.md↔docs/CONFIG_zh.mddocs/CLI.md↔docs/CLI_zh.mdWhen modifying either file in a pair, sync the same change to its counterpart.
- Protocol and interface design reference:
- When designing or reviewing upstream-facing APIs, file routes, metadata behavior, redirects, auth/header forwarding, or client compatibility logic, consult
docs/protocol/first. - Treat the provider notes in
docs/protocol/huggingface.mdanddocs/protocol/modelscope.mdas the protocol baseline unless the code, trace evidence, or changelog proves they need to be updated. - If a feature change modifies upstream protocol behavior, external interfaces, or client usage modes, update the relevant file under
docs/protocol/as needed and keep the document content consistent with the implementation. - Do not land an implementation that conflicts with the documented client-visible behavior in
docs/protocol/huggingface.mdordocs/protocol/modelscope.mdunless the same change also updates those documents.
- When designing or reviewing upstream-facing APIs, file routes, metadata behavior, redirects, auth/header forwarding, or client compatibility logic, consult
- Config responsibility split:
clapparses daemon and management CLI arguments.dotenvyloads.envinto the process environment.figmentmerges defaults, config file values, environment variables, and CLI overrides intoConfig. Keep this separation explicit in code and docs. Do not describeclapordotenvyas config merge solutions.
Commit Checklist
- Before creating any commit, run the relevant verification commands for the change and confirm they pass.
- For Rust code changes, the default pre-commit quality gates are:
cargo fmtcargo clippy --all-features --testscargo test
- During iteration, targeted tests are acceptable for faster feedback, but do not commit until the full required checks for the touched area have passed.
- Do not commit code that is known to fail formatting, clippy (including test code), or tests.
- Test lint policy:
unwrap_usedandexpect_usedare denied for production code (lib,bin) but allowed in test targets via#![allow(clippy::unwrap_used, clippy::expect_used)]at the top of each test file. This follows the community convention that.unwrap()in tests is idiomatic — tests should panic on unexpected failures. Other clippy lints (e.g.uninlined_format_args,useless_vec) apply to tests as well and should be fixed, not suppressed. - Commit discipline: keep different types of changes in separate commits. Bug fixes, new features, and release version bumps (Cargo.toml, CHANGELOG, README tags) must be in distinct commits with appropriate prefixes (
fix:,feat:,release:). Do not mix bugfix code with version bump metadata in the same commit.
Release Checklist
- Release tags use the
v*pattern. Pushing a tag likev0.4.0triggers.github/workflows/release.yml. - Release artifacts and Docker image must include both
hugrsandhugrsctl. - Before cutting a release, follow this order:
- Summarize the changes since the previous version and write them into
CHANGELOG.md. - Re-review the implementation against the changelog and fix any incomplete design or release details first.
- If nothing else is missing, run the quality gates:
cargo fmtcargo clippy --all-featurescargo test
- Only after the checks pass, bump the version in
Cargo.toml. - Update
Cargo.lock, Docker image tags inREADME.md/README_zh.md, and any user-facing docs that mention the current release version. - Commit the release changes, create the git tag, and push both commit and tag.
- Update Homebrew tap formula — the tap repo
homebrew-tap/Formula/hugrs.rbneeds version and SHA256 updated for all 4 platform binaries (aarch64/x86_64 × macOS/Linux). The tap repo lives at../homebrew-tap/(same level as this repo). Alternatively, usegh repo clone tq02ksu/homebrew-taporgit cloneto access it. After updating, commit and push the tap repo as well.
- Summarize the changes since the previous version and write them into
Project Structure
src/
├── main.rs # `hugrs` daemon entry point
├── bin/hugrsctl.rs # `hugrsctl` binary entry point
├── hugrsctl_cli.rs # Management CLI command definitions and formatting
├── admin_client.rs # Client for the control-plane admin API
├── control.rs # Control-plane request/response types
├── config.rs # Configuration
├── server.rs # HTTP server (axum)
├── service.rs # Business logic
├── session.rs # Download session and prefetch coordination
├── chunker.rs # File split/assemble
├── metadata.rs # SQLite operations
├── git.rs # Git/LFS proxy support
├── storage/
│ ├── mod.rs # StorageBackend trait
│ ├── local.rs # Local FS backend
│ └── s3.rs # S3 backend
├── migrations/ # SQL migrations
└── hf.rs # HuggingFace Hub integration