Axor
Axor is a zero-overhead, modular backend framework based on agents.
It helps you structure your backend logic into isolated, injectable components — called agents — that expose typed operations and can be invoked either directly or dynamically via RPC.
“Give me six hours to chop down a tree and I will spend the first four sharpening the axe.”
— Abraham Lincoln
Axor is your sharpened axe: focus on business logic, not boilerplate.
✅ Clean design
🧪 No ceremony
🚀 Zero runtime cost when calling directly
🌐 RPC-style invocation when needed
🔌 Inject and share any service, with no trait or macro required
Agents are exposed to the runtime. Services, in contrast, can be injected and shared without being registered as public operations — keeping your context clean and focused.
✨ Features
- ✅ Strongly-typed agents with auto-injection
- 🔌 Service/Agent DI via
Inject<T> - ⚙️ Operations with
#[operation], exposed automatically - 🧪 Business logic is testable directly (no runtime required)
- 🚀 Zero overhead in direct mode, thanks to static dispatch
- 🌐 Optional RPC-style interface via
Payload
Use
axor::prelude::*for a complete, developer-friendly import.
📦 Installation
[]
= "0.1"
= "0.1" # Required for attribute macros
⚠️ You must declare
axor-macrosin yourCargo.toml, but you don't need to import it in your source code — just use the prelude:
use *;
🛠️ Basic usage
1. Define a service and an agent
use Arc;
use *;
;
2. Register and run
let mut context = new;
context.register;
context.;
context.init;
// Direct call (zero overhead)
let agent = context.;
assert_eq!;
// RPC-style used by web, cli and tauri runtimes
let payload = new;
let result = context.invoke;
assert!;
📜 Manifest support
Introspect all registered agents and operations:
let manifest = context.manifest;
println!;
⚠️ Limitations
❌ No reflection
Rust doesn’t provide reflection. You must:
- Add
#[agent]to your struct - Add
#[agent_impl]to your impl block - Use
#[operation]to expose methods
🎯 Operation constraints
Each operation may take zero or one input, which must:
- Be
DeserializeOwned - Not be a reference (e.g., use
String, not&str)
Return values must be Serialize, but they are optional.
🔄 Runtime cost only when using Payload
In direct mode, everything is statically dispatched and compiled away.
RPC-style invocation uses serde_json::Value, which involves serialization overhead — by design.
🧭 Roadmap
- Core agent system and macros
- Dependency injection with
Inject<T> - Operation exposure
- Manifest generation
- Type metadata for operations
-
axor-web(RPC over HTTP) -
axor-cli(invoke agents from CLI) -
axor-tauri(bindings for desktop apps) - TypeScript client generator
-
axor-docfor endpoint documentation
🔗 License
MIT © 2025 — Made with ❤️ in Rust