Capability-aware workflow system for distributed workers with dynamic tool availability checking.
- Capability Registration: Workers declare what they can do
- Tool Availability: Dynamic checking of tool availability
- Builder Pattern: Ergonomic API for defining capabilities
- Alternative Tools: Specify fallback tools
- Serializable: JSON support for capability exchange
- Type-Safe: Strongly typed capability definitions
- Zero Dependencies: Only serde for serialization
[dependencies]
worker-capabilities = "0.1"use worker_capabilities::Capabilities;
// Define capabilities for a Rust worker
let rust_worker = Capabilities::new("rust-analyzer")
.with_static_analysis("clippy", true) // Required
.with_security_tool("cargo-audit", false) // Optional
.with_fuzzing_tool("cargo-fuzz", false)
.with_flag("ast_support")
.with_flag("llm_support");
// Check if worker can perform static analysis
let tool_checker = |tool: &str| {
// Your logic to check if tool is installed
matches!(tool, "clippy" | "cargo-audit")
};
if rust_worker.has_capability("static_analysis", &tool_checker) {
println!("Worker can perform static analysis!");
}
// Check all required tools are available
if rust_worker.has_all_required_tools(&tool_checker) {
println!("Worker is fully operational");
}Assign tasks to workers based on their capabilities:
use worker_capabilities::{Capabilities, CapabilityRegistry};
let mut registry = CapabilityRegistry::new();
// Register workers with different capabilities
registry.register(
Capabilities::new("rust-worker")
.with_static_analysis("clippy", true)
.with_security_tool("cargo-audit", true)
);
registry.register(
Capabilities::new("solidity-worker")
.with_static_analysis("slither", true)
.with_security_tool("mythril", false)
);
// Find workers that can do security scanning
let tool_checker = |tool: &str| tool == "cargo-audit" || tool == "slither";
let security_workers = registry.find_with_capability("security_scanning", &tool_checker);
for worker in security_workers {
println!("Worker {} can perform security scanning", worker.id);
}Specify alternative tools for flexibility:
let caps = Capabilities::new("formatter")
.with_alternative(
"rustfmt",
vec!["rustfmt", "cargo-fmt", "rustfmt-nightly"]
);
// Will accept any of the alternatives
let satisfied = caps.has_capability("static_analysis", &|tool| {
tool == "cargo-fmt" // Using alternative
});Workers and coordinators can negotiate capabilities:
let worker_caps = Capabilities::new("worker1")
.with_static_analysis("tool-a", true)
.with_dynamic_tool("tool-b", false);
// Coordinator checks if worker meets requirements
let required_checker = |tool: &str| tool == "tool-a";
if worker_caps.has_all_required_tools(&required_checker) {
// Assign task to worker
println!("Worker meets requirements");
}Store additional information about capabilities:
let caps = Capabilities::new("worker")
.with_tool("clippy", true)
.with_metadata("version", "0.1.0")
.with_metadata("platform", "linux")
.with_metadata("max_concurrent", "4");
if let Some(platform) = caps.get_metadata("platform") {
println!("Worker runs on: {}", platform);
}Main capability definition.
Constructor:
new(id)- Create new capability set
Builder Methods:
with_static_analysis(tool, required)- Add static analysis toolwith_security_tool(tool, required)- Add security toolwith_dynamic_tool(tool, required)- Add dynamic analysis toolwith_fuzzing_tool(tool, required)- Add fuzzing toolwith_test_framework(tool, required)- Add test frameworkwith_tool(tool, required)- Add generic toolwith_alternative(tool, alternatives)- Add tool with fallbackswith_flag(flag)- Add capability flagwith_metadata(key, value)- Add metadata
Query Methods:
has_capability(type, checker)- Check if capability is availablehas_all_required_tools(checker)- Verify all required toolsall_tools()- List all tools (including alternatives)has_flag(flag)- Check if flag is setget_metadata(key)- Get metadata value
Registry for managing multiple capability sets.
Methods:
new()- Create empty registryregister(caps)- Register capability setget(id)- Get capabilities by IDlist_ids()- List all registered IDsfind_with_capability(type, checker)- Find workers with capability
Individual tool capability.
Fields:
tool_name- Primary tool namerequired- Whether tool is requiredalternatives- Alternative tool names
Methods:
new(name, required)- Create tool capabilitywith_alternatives(alts)- Add alternative toolsis_satisfied(checker)- Check if tool is available
// Define capabilities for different build agents
let linux_agent = Capabilities::new("linux-agent")
.with_tool("docker", true)
.with_tool("cargo", true)
.with_metadata("os", "linux")
.with_metadata("arch", "x86_64");
let macos_agent = Capabilities::new("macos-agent")
.with_tool("xcodebuild", true)
.with_tool("cargo", true)
.with_metadata("os", "macos")
.with_metadata("arch", "aarch64");
// Assign tasks based on capabilities and metadata// Workers register their capabilities
let worker = Capabilities::new("worker-1")
.with_static_analysis("analyzer", true)
.with_security_tool("scanner", false)
.with_metadata("max_jobs", "5")
.with_metadata("priority", "high");
// Job queue matches tasks to capable workers
if worker.has_capability("static_analysis", &tool_checker) {
// Assign static analysis job
}# Run tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_capabilities_builderExtracted from Red Asgard, a security platform where it manages capability negotiation between distributed security analysis workers.
Licensed under MIT License. See LICENSE-MIT for details.
Contributions welcome! Areas of interest:
- Additional capability types
- Performance optimizations
- Documentation improvements
- Real-world examples
- Author: Red Asgard
- Email: hello@redasgard.com
- GitHub: https://github.com/redasgard