Skip to main content

Crate keel

Crate keel 

Source
Expand description

Keel as a Rust front end.

Rust has no import hook to hang a zero-code-change promise off of (that’s a dynamic-language trick python/keel/node/keel use), so the Rust front end keeps the “one optional attribute” ceiling (dx-spec.md invariant 1) instead: call init once from your own main, then mark the calls you want policy-driven resilience on.

Two seams:

  • wrap (re-exported from keel-macros) — #[keel::wrap(target = "...")] on a free async fn routes its body through the engine’s cache → rate → breaker → timeout → retry chain. See the macro’s own docs (crates/keel-macros/src/lib.rs) for the exact v1 scope (explicit target only, Clone parameters, no generics/methods).
  • KeelMiddleware — a reqwest_middleware::Middleware for HTTP clients built on reqwest. See its module docs for the exact v1 scope (exact-host targets, no glob/llm: mapping, no body-hash caching).

Both share one process-wide keel_core::Engine, configured from <cwd>/keel.toml (or Level 0 defaults if absent) — mirrors python/keel’s install_keel/node/keel’s installKeel, minus the import-hook and adapter-detection machinery neither seam needs here.

Deferred (see the session gap brief’s explicit descoping): no cargo-keel subcommand, no syn-based static scanner (crates/keel-cli/src/scan/rust.rs), no keel init --rust wiring. A Rust project adds this crate itself and calls init; keel doctor/keel init do not yet know Rust projects exist. This is real, tracked architectural debt, not an oversight — flagged for prioritization rather than assumed to be next.

Published name vs. import name. This crate is published to crates.io as keelrun (plain keel is taken — see docs/naming-decision.md), but every #[keel::wrap]/::keel::… path generated by the macro is hardcoded to the identifier keel, matching the product’s one-attribute promise (dx-spec.md invariant 1). Add the dependency with an explicit rename so the two agree:

[dependencies]
keel = { package = "keelrun", version = "0.1" }

(equivalently, cargo add keelrun --rename keel). This mirrors how this workspace’s own crates already depend on keelrun-core as keel-core — not a workaround, the intended way to add this crate.

Structs§

KeelMiddleware
A Middleware that wraps every request in the keel-core Engine chain. Owns a cloned reqwest::Client to send attempts itself (module docs explain why: Next/Extensions cannot cross into keel_core::Engine::execute’s effect closure under #[async_trait]’s Send-boxing requirement).

Enums§

Error
The error a #[keel::wrap]-wrapped function or crate::KeelMiddleware surfaces.

Functions§

init
Initialize Keel from <current_dir>/keel.toml (or Level 0 defaults if absent). Idempotent — a second call is a no-op (mirrors python/keel’s/node/keel’s idempotent install_keel/installKeel).
init_from
As init, loading keel.toml from dir instead of the current directory (multi-root setups; tests).
is_initialized
True once an Engine has been installed, whether by an explicit init/init_from call or lazily by the first wrapped call/ middleware invocation.
report
Deterministic per-target metrics/discovery report (JSON), forwarded from the underlying keel_core::Engine::report.

Attribute Macros§

wrap
#[keel::wrap(target = "...", idempotent = true)].