This guide covers two approaches to building Sentinel agents:
- SDK (Recommended) - High-level, ergonomic API with less boilerplate
- Low-level Protocol - Direct protocol access for maximum control
Using the SDK (Recommended)
The Sentinel Agent SDK provides a high-level API that handles protocol details, connection management, CLI parsing, and logging automatically.
Add Dependency
[]
= { = "https://github.com/raskell-io/sentinel-agent-sdk" }
Implement Your Agent
use *;
;
async
SDK Features
| Type | Methods |
|---|---|
Request | method(), path(), query("key"), header("name"), client_ip(), body_json::<T>() |
Response | status_code(), is_success(), is_html(), header("name"), body_json::<T>() |
Decision | allow(), block(status), deny(), redirect(url), add_request_header(), with_tag() |
AgentRunner | with_name(), with_socket(), with_json_logs(), run() |
Handling Configuration
Receive configuration from the proxy’s KDL config block:
Using cargo-generate (Low-level)
For more control, use the low-level protocol directly. The fastest way to start is using cargo-generate:
# Install cargo-generate
# Generate from template
# Follow prompts for project name and description
Manual Setup
1. Create Project
2. Add Dependencies
# Cargo.toml
[]
= "my-agent"
= "0.1.0"
= "2021"
[]
# Sentinel agent protocol
= "0.1"
# Async runtime
= { = "1", = ["full"] }
= "0.1"
# CLI and configuration
= { = "4", = ["derive", "env"] }
= "1"
# Logging
= "0.1"
= { = "0.3", = ["json", "env-filter"] }
# Serialization (for custom config)
= { = "1", = ["derive"] }
= "1"
3. Implement AgentHandler
The core of every agent is the AgentHandler trait:
use async_trait;
use ;
4. Create Main Entry Point
use PathBuf;
use ;
use Parser;
use info;
use ;
use MyAgent;
async
Echo Agent Deep Dive
The Echo Agent is a complete reference implementation. Let’s examine its key components.
Agent Structure
Handling Request Headers
Blocking Requests
To block a request, return a block decision:
async
Redirecting Requests
async
Handling Configuration
Implement on_configure() to receive configuration from the proxy’s KDL config:
use RwLock;
use ;
// Define your config struct with kebab-case for KDL compatibility
The corresponding KDL configuration:
agent "my-agent" type="custom" {
unix-socket "/tmp/my-agent.sock"
events "request_headers"
config {
enabled #true
threshold 100
allowed-paths "/health" "/metrics" "/api/public"
}
}
Key points:
- Use
#[serde(rename_all = "kebab-case")]to match KDL naming conventions - Use
#[serde(default)]for optional fields with defaults - Wrap mutable config in
RwLockfor thread-safe updates - Return a block decision to reject invalid configurations
- CLI args can serve as fallback when no config block is present
Running the Agent
Unix Socket Mode
# Build
# Run
gRPC Mode
Docker Deployment
FROM rust:1.75-slim AS builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/my-agent /usr/local/bin/
USER nobody
ENTRYPOINT ["my-agent"]
CMD ["--grpc", "0.0.0.0:50051"]
Systemd Service
[Unit]
My Sentinel Agent
network.target
[Service]
simple
sentinel
/usr/local/bin/my-agent --socket /var/run/sentinel/my-agent.sock
always
5
[Install]
multi-user.target
Proxy Configuration
Configure Sentinel to use your agent:
agents {
agent "my-agent" type="custom" {
unix-socket "/var/run/sentinel/my-agent.sock"
// Or for gRPC:
// grpc "http://localhost:50051"
events "request_headers"
timeout-ms 100
failure-mode "open"
}
}
routes {
route "api" {
matches { path-prefix "/api/" }
upstream "backend"
agents "my-agent"
}
}
Testing Your Agent
Unit Tests
Integration Testing
Test with the actual protocol using grpcurl:
# Start your agent
&
# Test with grpcurl
Best Practices
Performance
- Keep handlers fast - Agents add latency to every request
- Use async I/O - Never block the event loop
- Pre-compile patterns - Compile regexes at startup
- Limit body inspection - Only inspect when necessary
Reliability
- Handle errors gracefully - Return allow/block, don’t panic
- Configure timeouts - The proxy will timeout slow agents
- Use structured logging - Include correlation IDs
- Export metrics - Prometheus metrics for observability
Security
- Validate all input - Don’t trust data from the proxy
- Minimize dependencies - Fewer deps = smaller attack surface
- Keep secrets secure - Use environment variables
- Audit regularly - Run
cargo auditin CI
Building Agents in Other Languages
With gRPC support, you can build agents in any language. See the Protocol Specification for the protobuf definitions.
Python Example
=
# Your logic here
return
return
=
Go Example
package main
import (
"context"
"net"
pb "github.com/your-org/sentinel-proto"
"google.golang.org/grpc"
)
type myAgent struct
func (ctx context.Context, req *pb.AgentRequest) (*pb.AgentResponse, error)
func main()