> hyle

Code assistant in a single Rust binary

cargo install, set an OpenRouter key, start working. 7 tools the LLM calls directly (read, write, edit, grep, glob, bash, patch). 30+ slash commands with zero latency. Multi-model. Session persistence. Event-sourced.

~/project
Tool use loop

Affordance cascade

Each layer builds on the previous. j/k to navigate, enter to expand.

$ cargo install --git https://github.com/uprootiny/hyle
$ export OPENROUTER_API_KEY=sk-or-...
$ hyle doctor
 API key configured
 OpenRouter reachable
 State directory ready
cargo install set API key hyle doctor ready

Type a prompt, get a streaming response. Switch models with /model. Resume sessions across restarts. Free models via OpenRouter.

> explain the borrow checker error on line 47
The value `connection` is moved into the async block...

> /model deepseek/deepseek-chat-v3-0324:free
Switched to deepseek-chat-v3 (free)

The LLM emits tool calls, hyle executes them. Atomic writes with backup rotation. Recursive grep across directories. Compilation verification.

[read]  src/routes/upload.rs (247 lines)
[grep]  "rate_limit" in src/ (3 matches)
[edit]  src/routes/upload.rs: +4 -1 lines
[bash]  cargo check
 compiles
read grep edit bash verify

Multi-step execution with 16-message context cap and summarization. Intent detection prevents idle narration. Works best on bounded tasks; complex runs still need supervision.

$ hyle --task "add error handling to parse()"
iter 1: [read] src/lib.rs
iter 2: [edit] src/lib.rs (+12 -3)
iter 3: [bash] cargo test
 3 iterations, all tests pass
plan execute verify iterate

Every agent run emits structured events to JSONL. UX metrics track responsiveness, smoothness, and autonomy. Token usage and cost tracked per session.

> /cost
Session: a3f7c2d
  Tokens in:  47,832  ($0.024)
  Tokens out: 12,441  ($0.037)

$ cat ~/.local/share/hyle/run_a3f7c2d.jsonl
{"event":"tool_call","tool":"read",...}

13-tier recentering system detects agent drift (over-architecting, hallucinating APIs, ignoring tests) and injects corrective nudges. Automatic symptom classifier picks the tier.

$ hyle smoke
 recenter-list   4 prompts loaded
 recenter-auto   classifier: tier 3

> /recenter auto
[tier 3: Test-First Nudge]
Run the existing tests before changing more code.

Define scenario files with phased prompt injection. Triggers fire on iteration count, elapsed time, or output patterns. The runner nudges the agent through workflows without manual intervention.

scenario.json
{ "phases": [
  { "trigger": "Immediate",
    "prompt": "Read the codebase structure first" },
  { "trigger": { "AfterIterations": 3 },
    "prompt": "Now run the test suite" },
  { "trigger": { "OnPattern": "test.*fail" },
    "prompt": "Fix failing tests before proceeding" }
]}
scenario.json triggers inject adapt
j/k navigate · enter expand · esc close

What actually works

Honest inventory. Green = solid. Yellow = works but has rough edges.

7 tools, executed directly

read, write, edit, grep, glob, bash, patch. The LLM emits tool calls, hyle runs them. Atomic writes with backup rotation. Recursive grep. Compilation verification.

[read] src/lib.rs (312 lines) [grep] "parse_token" in src/ (7 matches) [edit] src/lib.rs: replace line 47 [bash] cargo check compiles, backup at .bak.1

30+ slash commands

Run locally, zero latency, no API call. /build /test /diff /commit /status /cost /grep /doctor /recenter and more.

> /status Modified: src/lib.rs, src/parser.rs > /diff src/lib.rs - let result = parse(input)?; + let result = parse(input) + .map_err(|e| anyhow!("Parse: {}", e))?; > /commit "fix parse error handling" [a3f7c2d] fix parse error handling

Multi-model via OpenRouter

35+ free models. Switch mid-session with /model. DeepSeek, Qwen, Llama, Claude, GPT-4. Fuzzy search picker.

$ hyle --free [Using deepseek/deepseek-chat-v3-0324:free] > /model qwen Switched: qwen/qwen-2.5-coder-32b-instruct:free

Safety guardrails

Destructive command blocking. Permission system (deny/ask/auto per tool category). Atomic writes never corrupt files.

[BLOCKED] rm -rf / matches dangerous pattern [ASK] bash: cargo clean (destructive, confirm?) [AUTO] read: src/lib.rs (safe, proceed)

Agentic loop (experimental)

Multi-step autonomous execution. Context window capped at 16 messages with summarization. Intent detection prevents idle narration. Best on bounded tasks.

$ hyle --task "add error handling to parse()" iter 1: [read] src/lib.rs iter 2: [edit] src/lib.rs (+12 -3) iter 3: [bash] cargo test 3 iterations, all tests pass

Self-correction

13-tier recentering prompt system. Detects when the agent drifts and injects corrective nudges. From gentle taps to hard resets. /recenter auto.

$ hyle smoke recenter-list 4 prompts loaded recenter-auto classifier: tier 3 > /recenter auto [tier 3: Test-First Nudge]

Real-world examples

Click to expand and see the actual prompts

📝
Stripe webhook types from JSON
Paste API response, get serde structs
painless

You're integrating with Stripe's API and need to deserialize webhook payloads. Instead of manually transcribing JSON into Rust structs, paste a sample response and get types with proper serde attributes, Option<T> for nullable fields, and chrono DateTime handling.

~/code/payment-service
> generate rust types from this stripe webhook: {"id":"evt_1abc","type":"payment_intent.succeeded", "data":{"object":{"id":"pi_xyz","amount":2000, "currency":"usd","customer":"cus_123"}}} [write] src/stripe/types.rs (89 lines) [bash] cargo check Compiles successfully
🔧
Fix async lifetime errors
Compiler error in, working code out
painless

Rust's async lifetime errors are cryptic. "Lifetime may not live long enough" pointing at trait bounds you didn't write. Paste the error, hyle reads the file, understands ownership flow, and applies the fix.

~/code/realtime-sync
> fix this: error[E0597]: `connection` does not live long enough --> src/ws/handler.rs:47:23 [read] src/ws/handler.rs The spawn requires 'static. Clone the Arc. [patch] src/ws/handler.rs cargo check: ok
🧪
Generate tests from implementation
Comprehensive coverage, edge cases included
painless

You've written the parser, now you need tests. Point hyle at the module and it analyzes the public API, identifies edge cases, and generates a test file that exercises the paths that matter.

~/code/markdown-compiler
> write tests for src/parser/inline.rs [read] src/parser/inline.rs (312 lines) [write] tests/parser_inline_tests.rs (247 lines) Generated for: parse_emphasis - 6 tests (nested, unmatched) parse_link - 8 tests (inline, reference) parse_code_span - 4 tests [bash] cargo test parser_inline 23 tests passed
🔒
Add JWT auth to all routes
Middleware, extractors, error handling
painless

Security boilerplate is tedious. hyle reads your route handlers, creates JWT validation middleware with proper error responses, adds extractor types, and wires everything together.

~/code/inventory-api
> add JWT auth to src/routes/*, return 401 for invalid [read] src/routes/*.rs (4 files) [write] src/middleware/auth.rs (78 lines) [write] src/auth/claims.rs (34 lines) [patch] src/routes/mod.rs (+12 lines) [patch] Cargo.toml (jsonwebtoken = "9") [bash] cargo test 47 tests passed
🎨
Description to Leptos component
Reactive state, event handlers, CSS
creative

You know what you want the UI to look like. Describe it in words and hyle generates a complete Leptos component with signals, derived state, event handlers, and CSS.

~/code/file-manager
> create file browser component: - tree view left (collapsible folders) - file preview right - breadcrumb nav top - keyboard nav (j/k, enter to open) [write] src/components/file_browser.rs [write] src/components/file_browser.css Created with: - RwSignal<Vec<TreeNode>> for tree - create_effect for keyboard - Accessible ARIA attributes [bash] trunk serve http://localhost:8080
🔄
Port Python to Rust
Idiomatic translation, not transliteration
creative

That Python prototype is now a bottleneck. hyle understands Python idioms and maps them to Rust: dict comprehensions become iterators, context managers become RAII, exceptions become Result.

~/code/image-processor
> port to rust with tokio: async def process_batch(paths): async with aiofiles.open("log.txt", "a") as log: for path in paths: try: img = Image.open(path) results[path.stem] = analyze(img) except Exception as e: await log.write(f"Failed: {e}\n") [write] src/processor.rs (67 lines) [bash] cargo clippy No warnings
🚀
Entity to full CRUD stack
Migrations, handlers, tests, OpenAPI
impressive

Describe an entity's fields and hyle generates the complete vertical slice: SQLx migrations, model structs with validation, CRUD handlers, integration tests, and OpenAPI documentation. All following your existing patterns.

~/code/saas-platform
> create entity: Subscription - id: UUID - user_id: UUID (foreign key) - plan: enum (free, pro, enterprise) - status: enum (active, cancelled, past_due) - current_period_end: DateTime - stripe_subscription_id: Option<String> [write] migrations/20260110_subscriptions.sql [write] src/models/subscription.rs [write] src/handlers/subscriptions.rs [write] tests/subscriptions_test.rs [bash] sqlx migrate run && cargo test 12 tests passed. 5 files, 847 lines.
🔄
Split 2000-line monolith
Modules, imports, Cargo.toml updates
impressive

The file that started as "temporary" is now 2000 lines. hyle analyzes the dependency graph, identifies natural module boundaries, extracts code into proper structure, fixes imports, and verifies compilation.

~/code/event-sourcing
> src/event_store.rs is 2000 lines, split into modules [read] src/event_store.rs (2,147 lines) Found 6 clusters: Storage (412) - Projection (387) - Snapshot (234) Subscription (298) - Aggregate (456) - Types (360) [mkdir] src/event_store/ [write] src/event_store/mod.rs [write] src/event_store/{storage,projection,...}.rs [delete] src/event_store.rs [bash] cargo test All 89 tests pass
🐛
Debug production panic
Stack trace to root cause to fix
impressive

Your monitoring alerts on a panic. Paste the stack trace, hyle correlates with source, identifies the failing unwrap, explains why, fixes error handling, and adds a regression test.

~/code/trading-engine
> sentry shows this, fix it: panicked at 'called `Option::unwrap()` on `None`', src/orderbook/matching.rs:142:35 [read] src/orderbook/matching.rs Line 142: let price = self.best_bid.unwrap(); Panics when orderbook empty (no bids). [patch] src/orderbook/matching.rs - let price = self.best_bid.unwrap(); + let Some(price) = self.best_bid else { + return Err(MatchError::NoLiquidity); + }; [write] tests/orderbook_edge_cases.rs (+1 test) 34 tests passed
📑
Spec to implementation
Step-by-step with tests after each
impressive

Paste a design doc and hyle implements incrementally - writing code, running tests after each step, proceeding only when they pass. Great for well-specified features.

~/code/rate-limiter
> implement, test after each step: ## Token Bucket Rate Limiter - Configurable capacity and refill rate - Thread-safe (Arc<RateLimiter>) - Returns remaining tokens on check - Multiple named buckets - Async-compatible Step 1/5: Core TokenBucket [write] src/bucket.rs 4 tests passed Step 2/5: Atomic refill [patch] src/bucket.rs 6 tests passed ...steps 3-5... All 34 tests pass. Docs generated.
View on GitHub cargo install --git https://github.com/uprootiny/hyle
~
Default Composable Velocity Reliable Depth Playful Observable Community Independent Learning Control Secure Flow