Build a huglet and ship it anywhere as a small, self-contained artifact on a runtime-free, sans-IO Rust core.
Huggr is a toolkit for building small, domain-specific huglets. A huglet is a small Rust crate: a huggr.toml manifest (model tiers, tool grants, limits), a SYSTEM.md system prompt, and optionally a typed Rust response contract. Huggr turns that folder into one standalone binary that answers questions over a JSON contract and serves MCP through --mcp-serve.
The idea is that a specialist with a focused prompt and five jailed tools is cheaper, faster, and safer than a generalist with fifty, and that an orchestrator (a human, a script, or a larger agent) should pay one tool call to use it.
cargo run -p huggr-toolkit --bin huggr -- new my-agent # scaffold an agent crate
export HF_TOKEN=hf_... # key for the default Hugging Face provider
cargo run -p huggr-toolkit --bin huggr -- run my-agent "question" # interpret it (dev loop)
cargo run -p huggr-toolkit --bin huggr -- build my-agent # ship it: one standalone binary
./my-agent/dist/my-agent-cli/target/debug/my-agent "question" # answers; --trace <id> resumes; --mcp-serve serves MCPEvery built binary self-describes: --describe (tools, privileges, tiers, pricing, context policy, limits), --config (effective identity, models, grants, skills, runtime args, limits, state paths, and response schema, with secrets omitted), --traces (stored lineage).
Agent state lives under ~/.huggr/<agent-name>/ by default: immutable traces in traces/, per-lineage scratch state in scratch/. Override with HUGGR_AGENT_HOME or HUGGR_HOME.
my-agent/
Cargo.toml # Rust crate metadata; typed contracts and hooks live here
huggr.toml # name, required model tier, tool grants + scopes, limits
SYSTEM.md # the system prompt
src/lib.rs # optional typed response / hooks / custom Rust wiring
[agent]
name = "policy-docs"
description = "Answers questions about the company travel policy."
[models]
default = "powerful"
[tools.fs_read]
root = "./policies" # read-only, jailed to this folderThe manifest chooses among four stable capability tiers: fast, balanced, powerful, and max. Concrete providers, model ids, and prices normally live once in ~/.huggr/models.toml; the CLI creates that file with usable defaults on first run. A build resolves and embeds the mappings, while a models.toml on the machine running the built artifact overrides the embedded snapshot. See Models, providers, and pricing.
The manifest defines the agent's blast radius and is the document to audit. Grant-driven tools that are not declared are not registered; the per-lineage scratchpad is part of every ask. Unknown keys are hard errors, so a typo cannot silently widen or narrow the grant.
The built-in library includes jailed filesystem reads and writes, restricted or full shell execution, allowlisted web fetch, Exa web search, memory, trace inspection, scratch state, and isolated self-delegation. High-privilege tools remain opt-in grants: restricted shell commands execute without shell syntax, while full shell and full-disk roots explicitly hand sandboxing to the operator. See the built-in capability reference.
- One invocation contract. The input is a question string. The output is a structured response with mandatory status, cost, duration, token, and trace-id metadata. Errors are answers (
status: "error", exit 0), so callers branch on data instead of exceptions. - Resumable and forkable traces. Every completed turn persists an immutable trace. Pass its
trace_idback to continue the conversation, or pass an older id to fork a sibling branch. Replay is bit-for-bit deterministic. - Sandboxing by construction. An agent registers only its manifest-granted tools plus the universal scratchpad, each jailed to its declared scope. Every agent also gets explicit blob exchange with the caller.
- Progressively disclosed skills. Add standard
SKILL.mdfolders toskills = [...]in the manifest or pass--skill <path>for one ask. The model sees the skill catalog and loads matching instructions or referenced files through a jailed reader only when needed. - Cost accounting. Every response carries cost (from per-tier pricing config), duration, and token counts, folded from the trace.
huggr statsaggregates them across runs. - Composition. A built Huggr agent is a tool: grant it with
[tools.agent.<name>] artifact = "..."and call it like any capability. Delegation never widens privileges, and the child's cost folds into the caller's metadata. - Isolated self-delegation. Grant
[tools.delegate]when an agent should call itself in a fresh context window. Recursion is depth-capped and child cost folds into the parent.
examples/huglet-docs answers questions about a documentation folder. It has no shell, write, or network tools; only the read-only, folder-jailed fs_* family.
export HF_TOKEN=hf_...
cargo run -p huggr-toolkit --bin huggr -- run examples/huglet-docs ./docs "What is the narrow-waist rule?" | jq{
"status": "success",
"response": {
"response": "The narrow-waist rule is ...",
"related_documents": [{ "path": "README.md", "url": "https://github.com/Wauplin/huggr/blob/main/docs/README.md" }]
},
"trace_id": "1e4f7d0a9b2c3d44",
"metadata": { "duration_ms": 1234, "tokens_in": 1000, "tokens_out": 200, "cost_micro_usd": 1300, "models": ["zai-org/GLM-5.2:together"], "model_calls": 2, "tool_calls": 3 }
}The docs folder is runtime config, not a compiled-in scope: the same agent crate runs against ./docs or any other folder, each invocation jailed to the folder it was given. Build it with huggr build examples/huglet-docs to get a standalone binary that any language can call as a subprocess or through --mcp-serve.
The same runtime is available without writing Rust:
- Consume a built agent from Python.
huggr build <agent> --surface pythonwraps the agent into a typed wheel:ask()in-process, dataclasses out. See Package an agent for Python. - Define an agent in Python. The
huggr-agentspackage embeds the runtime: tools are decorated callables, config is data,agent.ask(...)returns the standardAnswer. See Define an agent in Python. - Define an agent in TypeScript. The
huggr-agentsTS package drives the same brain compiled to WASM, in Node and the browser. See Define an agent in TypeScript.
Traces use the same huggr-replay format across surfaces. The Rust CLI can verify a trace when an agent crate resolves to its store; the TypeScript runtime also exposes agent.verify().
The runtime is built on huggr-core, a pure, sans-IO, single-threaded reducer over an append-only event log. The brain and host communicate through two enums and two methods:
loop {
for cmd in brain.poll() { // drain commands the brain wants performed
host.perform(cmd);
}
let event = host.next_event().await; // the only await; host-side only
brain.submit(Envelope::new(host.now(), event)); // pure, instant, no IO
}All nondeterminism (time, model output, tool results) is injected through time-stamped events, so any session replays bit-for-bit. A trace stores that replay input plus the consolidated durable log and emitted commands. Resume re-folds the log, a fork copies a prefix, and cost is computed from per-op metadata in it. This is what lets the same brain run natively, in Python, and in the browser.
- Not a general-purpose coding or browser agent. Huggr defines the callee side; generalists are usually the orchestrators that call Huggr agents.
- Not a hosted runtime or marketplace. Huggr ships artifacts; you choose where to run them (locally, CI, a container).
- Not an agent-to-agent wire protocol. MCP is the adapter for exposing an agent to orchestrators; A2A and others could be added at the edge but are not foundations.
- Not multimodal-first. Text in, text out, with blob attachments that a specific agent's tools may interpret.
- Not stable. This is a hobby prototype with no external users. Breaking changes land without deprecation shims or compatibility ceremony.
huggr/
├── crates/
│ ├── huggr-core/ # the sans-IO brain: log, projection, op table, reducer (no tokio, reqwest, or fs)
│ ├── huggr-host/ # native tokio host: driver loop, capability/model registries, MCP client
│ ├── huggr-providers/ # OpenAI-compatible streaming model adapter
│ ├── huggr-replay/ # trace format, content-addressed blob store, replay/verify/inspect
│ ├── huggr-agent/ # huglet runtime: Ask/Answer, resume/fork, scratchpad, blobs, limits, cost
│ ├── huggr-toolkit/ # manifests, the tool library, and the `huggr` CLI (new/run/build/traces/stats/replay/verify)
│ ├── huggr-wasm/ # WASM bindings around huggr-core for browser/JS hosts
│ └── huggr-python/ # PyO3 runtime embedding (built by maturin from bindings/python)
├── bindings/
│ ├── python/ # the `huggr-agents` Python package
│ └── typescript/ # the `huggr-agents` TypeScript package (Node + browser)
├── examples/
│ ├── huglet-docs/ # the reference docs-Q&A agent crate with a typed response contract
│ ├── huglet-weather/ # the beginner agent; source of the `huggr new --template weather` scaffold
│ ├── huglet-insights/ # offline self-improvement agent over traces and feedback
│ ├── huglet-datasmith/ # docs-QA dataset synthesizer with a typed QaDataset contract
│ ├── hf-librarian/ # Python pipeline: datasmith wheel, jailed Hub publisher, judge-graded eval
│ └── chrome-extension/ # a concrete browser host: chrome.* capabilities, side-panel UI, MV3
└── docs/ # tutorials, task guides, concepts, and reference
- Tutorials teach a surface end to end.
- Guides cover specific tasks.
- Concepts explain design and behavior.
- Reference specifies contracts, configuration, packages, and terminology.
cargo build --workspace
cargo test # unit + scripted/determinism + end-to-end tests
cargo clippy --all-targets
cargo fmt --all
cargo tree -p huggr-core # audit: must stay free of tokio/reqwest/fsNotable tests: huggr-core/tests (scripted sessions + deterministic replay), huggr-host/tests/end_to_end.rs (real engine, tools, MCP, record/replay/resume), and the ignored slow gates cargo test -p huggr-toolkit --test conformance -- --ignored / --test build_cli -- --ignored (compile a real agent binary and check the in-process crate, built CLI, and MCP surfaces agree; the generated Python, typed Node/browser, and Chrome surfaces are not yet in this gate).
Licensed under Apache-2.0.