agent-first-data
Agent-First Data (AFD) — Suffix-driven output formatting and protocol templates for AI agents.
The field name is the schema. Agents read latency_ms and know milliseconds, api_key_secret and know to redact, no external schema needed.
Installation
API Reference
Total: 9 public APIs + optional AFD tracing (4 protocol builders + 3 output functions + 1 internal + 1 utility)
Protocol Builders (returns JSON Value)
Build AFD protocol structures. Return serde_json::Value objects for API responses.
// Startup (configuration)
build_json_startup // Success (result)
build_json_ok // Error (simple message)
build_json_error // Generic (any code + fields)
build_json
Use case: API responses (frameworks like axum automatically serialize)
Example:
use *;
use json;
// Startup
let startup = build_json_startup;
// Success (always include trace)
let response = build_json_ok;
// Error
let error = build_json_error;
// Specific error code
let not_found = build_json;
CLI/Log Output (returns String)
Format values for CLI output and logs. All formats redact _secret fields. YAML and Plain also strip suffixes from keys and format values for human readability.
output_json // Single-line JSON, original keys, for programs/logs
output_yaml // Multi-line YAML, keys stripped, values formatted
output_plain // Single-line logfmt, keys stripped, values formatted
Example:
use *;
use json;
let data = json!;
// JSON (secrets redacted, original keys, raw values)
println!;
// {"api_key_secret":"***","created_at_epoch_ms":1738886400000,"file_size_bytes":5242880,"user_id":123}
// YAML (keys stripped, values formatted, secrets redacted)
println!;
// ---
// api_key: "***"
// created_at: "2025-02-07T00:00:00.000Z"
// file_size: "5.0MB"
// user_id: 123
// Plain logfmt (keys stripped, values formatted, secrets redacted)
println!;
// api_key=*** created_at=2025-02-07T00:00:00.000Z file_size=5.0MB user_id=123
Internal Tools
internal_redact_secrets // Manually redact secrets in-place
Most users don't need this. Output functions automatically protect secrets.
Utility Functions
parse_size // Parse "10M" → bytes
Example:
use *;
assert_eq!;
assert_eq!;
assert_eq!;
Usage Examples
Example 1: REST API
use *;
use ;
use json;
async
Example 2: CLI Tool (Complete Lifecycle)
use *;
use json;
Example 3: JSONL Output
use *;
use json;
Complete Suffix Example
use *;
use json;
let data = json!;
// YAML output (keys stripped, values formatted, secrets redacted)
println!;
// ---
// api_key: "***"
// cache_ttl: "3600s"
// count: 42
// created_at: "2025-02-07T00:00:00.000Z"
// file_size: "5.0MB"
// payment: "50000000msats"
// price: "$99.99"
// request_timeout: "5.0s"
// success_rate: "95.5%"
// user_name: "alice"
// Plain logfmt output (same transformations, single line)
println!;
// api_key=*** cache_ttl=3600s count=42 created_at=2025-02-07T00:00:00.000Z file_size=5.0MB payment=50000000msats price=$99.99 request_timeout=5.0s success_rate=95.5% user_name=alice
AFD Tracing (optional feature)
AFD-compliant structured logging via the tracing ecosystem. Enable with:
Every log line is formatted using the library's own output_json/output_plain/output_yaml functions. Span fields are automatically flattened into each event line, solving the concurrent-request log interleaving problem.
API
use afd_tracing;
use EnvFilter;
// Convenience initializers — set up the default tracing subscriber with AFD output
init_json // Single-line JSONL (secrets redacted, original keys)
init_plain // Single-line logfmt (keys stripped, values formatted)
init_yaml // Multi-line YAML (keys stripped, values formatted)
// Low-level — create a tracing Layer for custom subscriber stacks
AfdLayer // implements tracing_subscriber::Layer
Json | Plain | Yaml
Setup
use afd_tracing;
use EnvFilter;
// JSON output for production (one JSONL line per event, secrets redacted)
init_json;
// Plain logfmt for development (keys stripped, values formatted)
init_plain;
// YAML for detailed inspection (multi-line, keys stripped, values formatted)
init_yaml;
Log Output
Standard tracing macros work unchanged. Output format depends on the init function used.
use ;
info!;
// JSON: {"timestamp_epoch_ms":1739000000000,"message":"Server started","target":"myapp","code":"info"}
// Plain: code=info message="Server started" target=myapp timestamp_epoch_ms=1739000000000
// YAML: ---
// code: "info"
// message: "Server started"
// target: "myapp"
// timestamp_epoch_ms: 1739000000000
warn!;
// JSON: {"timestamp_epoch_ms":...,"message":"DNS lookup failed","target":"myapp","domain":"example.com","latency_ms":1280,"code":"warn"}
// Plain: code=warn domain=example.com latency=1.28s message="DNS lookup failed" target=myapp ...
Span Support
Span fields are flattened into every event inside the span. Child spans override parent fields on collision.
let span = info_span!;
let _guard = span.enter;
info!;
// {"timestamp_epoch_ms":...,"message":"Processing","target":"myapp","request_id":"abc-123","code":"info"}
warn!;
// {"timestamp_epoch_ms":...,"message":"Failed","target":"myapp","request_id":"abc-123","error":"not found","code":"warn"}
Custom Code Override
The code field defaults to the log level (trace/debug/info/warn/error). Override with an explicit code field:
info!;
// {"timestamp_epoch_ms":...,"message":"Server ready","target":"myapp","code":"startup"}
Output Fields
Every log line contains:
| Field | Type | Description |
|---|---|---|
timestamp_epoch_ms |
number | Unix milliseconds |
message |
string | Log message |
target |
string | Source module path |
code |
string | Level (trace/debug/info/warn/error) or explicit override |
| span fields | any | Flattened from root span to leaf span |
| event fields | any | Structured fields from the log macro |
Log Output Formats
All three formats use the library's own output functions, so AFD suffix processing applies to log fields too:
| Format | Function | Keys | Values | Use case |
|---|---|---|---|---|
| JSON | init_json |
original (with suffix) | raw | production, log aggregation |
| Plain | init_plain |
stripped | formatted | development, compact scanning |
| YAML | init_yaml |
stripped | formatted | debugging, detailed inspection |
All formats automatically redact _secret fields in log output.
Output Formats
Three output formats for different use cases:
| Format | Structure | Keys | Values | Use case |
|---|---|---|---|---|
| JSON | single-line | original (with suffix) | raw | programs, logs |
| YAML | multi-line | stripped | formatted | human inspection |
| Plain | single-line logfmt | stripped | formatted | compact scanning |
All formats automatically redact _secret fields.
Supported Suffixes
- Duration:
_ms,_s,_ns,_us,_minutes,_hours,_days - Timestamps:
_epoch_ms,_epoch_s,_epoch_ns,_rfc3339 - Size:
_bytes(auto-scales to KB/MB/GB/TB),_size(config input, pass through) - Currency:
_msats,_sats,_btc,_usd_cents,_eur_cents,_jpy,_{code}_cents - Other:
_percent,_secret(auto-redacted in all formats)
License
MIT