Skip to content
For the complete documentation index optimized for AI agents, see llms.txt or llms-full.txt. A markdown version of this page is available by appending .md to the URL or sending Accept: text/markdown.

Configuration Reference

For AI agents: the documentation index is at llms.txt (full corpus: llms-full.txt). A markdown source for this page is /a4-server/reference.md.

This page documents the principal configuration options available in a4-server. The server consumes generated Rust spec() values, not deployment URLs or hosted release manifests.

The server is configured using a fluent builder pattern:

use a4_server::Server;
Server::builder()
.spec(my_spec()) // Generated live or program-only specification
.websocket() // Enable WebSocket server
.bind("[::]:8877".parse()?)
.yellowstone(config) // Optional: manual Yellowstone config
.health_monitoring() // Enable health monitoring
.http_health() // Configure the shared HTTP listener
.reconnection() // Enable auto-reconnection
.start()
.await?;

The generated spec carries exact ProgramSpec identities and local account readers. For OSS code-first use, release fingerprints are derived automatically from each ProgramSpec and the generated decoder-engine contract. Hosted Program Releases, deployments, and endpoint bindings are separate control-plane concepts and are not required here.

Live, Program Read, chain-read, and transaction surfaces are independent. The fluent helpers update a RuntimePlan:

Builder methodCapabilities enabled
.websocket()WebSocket transport and live projection runtime
.program_reads()Health plus typed, release-checked program HTTP reads
.chain_reads()Generic Solana chain-read HTTP routes
.stack_queries()Stack-scoped query HTTP routes
.transactions_config(config)Fixed transaction routes when config.enabled is true
.http()Convenience set: health, program reads, chain reads, and stack queries

Transaction routes are never enabled by .http(). To enforce an exact capability set after configuring listeners, replace the inferred plan:

use a4_server::RuntimePlan;
let plan = RuntimePlan {
health: true,
chain_reads: false,
program_reads: true,
stack_queries: false,
transactions: false,
websocket: false,
live_runtime: false,
};
Server::builder()
.spec(my_program::spec())
.http_bind("0.0.0.0:8081".parse()?)
.runtime_plan(plan)
.start()
.await?;

This program-only configuration does not require Yellowstone. A composed client may point each LiveSpec alias and each Program Read binding at different services, then supply independent chain and transaction transports.

These environment variables are read by the generated runtime and server code:

VariableRequiredDefaultDescription
YELLOWSTONE_ENDPOINTFor live runtimeYellowstone gRPC endpoint URL
YELLOWSTONE_X_TOKENProvider-specificAuthentication token for the endpoint
ARETE_READ_RPC_URLFor RPC-backed readsUpstream used by Program Read and chain-read routes
ARETE_TRANSACTION_RPC_URLFor transaction routesIndependent transaction inspect/send upstream
ARETE_TRANSACTIONS_ENABLEDNofalseExplicitly enables fixed transaction routes
ARETE_SNAPSHOT_ENABLEDNofalseEnables state snapshots for restart recovery
ARETE_SNAPSHOT_URLFor snapshotsSnapshot store location (file://... or local path)
RUST_LOGNoinfoLog level filter (e.g., debug, info,a4_server=debug)

The full set of ARETE_SNAPSHOT_* variables is documented in State Snapshots & Restore.

// Enable with defaults (binds to [::]:8877)
Server::builder()
.websocket()
.start()
.await?;
// Or specify a custom bind address
Server::builder()
.websocket()
.bind("[::]:9000".parse()?)
.start()
.await?;

For full control, use websocket_config():

use a4_server::WebSocketConfig;
let ws_config = WebSocketConfig {
bind_address: "[::]:8877".parse()?,
};
Server::builder()
.websocket_config(ws_config)
.start()
.await?;
FieldTypeDefaultDescription
bind_addressSocketAddr[::]:8877Address and port for the WebSocket server

The Yellowstone gRPC connection is typically configured via environment variables. However, you can also configure it programmatically:

use a4_server::YellowstoneConfig;
let yellowstone = YellowstoneConfig::new("https://your-endpoint.com")
.with_token("your-secret-token");
Server::builder()
.yellowstone(yellowstone)
.start()
.await?;
FieldTypeDefaultDescription
endpointStringYellowstone gRPC endpoint URL
x_tokenOption<String>NoneAuthentication token
MethodDescription
YellowstoneConfig::new(endpoint)Create with endpoint
.with_token(token)Set authentication token

Health monitoring tracks stream connectivity and detects issues like stale connections.

// Enable with defaults
Server::builder()
.health_monitoring()
.start()
.await?;
use a4_server::HealthConfig;
use std::time::Duration;
let health = HealthConfig::new()
.with_heartbeat_interval(Duration::from_secs(30))
.with_health_check_timeout(Duration::from_secs(10));
Server::builder()
.health_config(health)
.start()
.await?;
FieldTypeDefaultDescription
heartbeat_intervalDuration30sHow often to check stream health
health_check_timeoutDuration10sTimeout for health check operations
MethodDescription
HealthConfig::new()Create with defaults
.with_heartbeat_interval(duration)Set heartbeat interval
.with_health_check_timeout(duration)Set health check timeout

The shared HTTP listener exposes health routes and whichever read/transaction capabilities are selected in RuntimePlan. For compatibility, http_health()/http_health_config() are aliases for http()/http_config(); by themselves they infer health, Program Read, chain-read, and stack-query capabilities.

// Configure the listener with the full HTTP convenience capability set.
// It binds to [::]:8081.
Server::builder()
.http_health()
.start()
.await?;
// Or specify a custom bind address
Server::builder()
.http_health()
.health_bind("0.0.0.0:8081".parse()?)
.start()
.await?;

For health-only HTTP alongside a live WebSocket, replace the inferred plan after configuring the listener:

use a4_server::RuntimePlan;
Server::builder()
.spec(spec)
.websocket()
.http_health()
.health_bind("0.0.0.0:8081".parse()?)
.runtime_plan(RuntimePlan {
health: true,
websocket: true,
live_runtime: true,
..RuntimePlan::default()
})
.start()
.await?;
use a4_server::HttpHealthConfig;
let http_health = HttpHealthConfig::new("0.0.0.0:9090".parse()?);
Server::builder()
.http_health_config(http_health)
.start()
.await?;
FieldTypeDefaultDescription
bind_addressSocketAddr[::]:8081Address and port for the HTTP health server
EndpointMethodDescription
/health or /healthzGETLiveness check — returns 200 OK if server is running
/ready or /readinessGETReadiness check — returns 200 OK if stream is healthy, 503 otherwise
/statusGETDetailed JSON status with health state and error count
{
"healthy": true,
"status": "Connected",
"error_count": 0
}

Controls automatic reconnection behavior when the Yellowstone gRPC connection drops.

// Enable with defaults
Server::builder()
.reconnection()
.start()
.await?;
use a4_server::ReconnectionConfig;
use std::time::Duration;
let reconnect = ReconnectionConfig::new()
.with_initial_delay(Duration::from_millis(100))
.with_max_delay(Duration::from_secs(60))
.with_max_attempts(10)
.with_backoff_multiplier(2.0)
.with_http2_keep_alive_interval(Duration::from_secs(30));
Server::builder()
.reconnection_config(reconnect)
.start()
.await?;
FieldTypeDefaultDescription
initial_delayDuration100msDelay before first reconnection attempt
max_delayDuration60sMaximum delay between attempts (caps exponential backoff)
max_attemptsOption<u32>None (infinite)Maximum reconnection attempts before giving up
backoff_multiplierf642.0Multiplier for exponential backoff
http2_keep_alive_intervalOption<Duration>30sHTTP/2 keep-alive to prevent silent disconnects
MethodDescription
ReconnectionConfig::new()Create with defaults
.with_initial_delay(duration)Set initial reconnection delay
.with_max_delay(duration)Set maximum backoff delay
.with_max_attempts(n)Limit reconnection attempts
.with_backoff_multiplier(m)Set exponential backoff multiplier
.with_http2_keep_alive_interval(duration)Set HTTP/2 keep-alive interval

Enable optional features in your Cargo.toml:

[dependencies]
a4-server = { version = "0.20.1", features = ["otel"] }
FeatureDefaultDescription
otelNoOpenTelemetry integration for metrics and distributed tracing

When the otel feature is enabled:

use a4_server::Metrics;
let metrics = Metrics::new();
Server::builder()
.metrics(metrics)
.start()
.await?;

Here’s a production-ready configuration combining all options:

use a4_server::{
Server, HealthConfig, HttpHealthConfig, ReconnectionConfig
};
use std::time::Duration;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// TLS provider for gRPC
rustls::crypto::ring::default_provider()
.install_default()
.expect("Failed to install rustls crypto provider");
// Load environment variables
dotenvy::dotenv().ok();
// Initialize logging
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "info,a4_server=debug".into()),
)
.init();
let spec = my_stack::spec();
Server::builder()
.spec(spec)
// WebSocket on port 8877
.websocket()
.bind("[::]:8877".parse()?)
// Health monitoring with custom intervals
.health_config(
HealthConfig::new()
.with_heartbeat_interval(Duration::from_secs(15))
)
// Shared HTTP listener on port 8081. The convenience helper enables
// health, Program Read, chain-read, and stack-query routes.
.http_health()
.health_bind("0.0.0.0:8081".parse()?)
// Reconnection with limited attempts
.reconnection_config(
ReconnectionConfig::new()
.with_max_attempts(100)
.with_max_delay(Duration::from_secs(30))
)
.start()
.await?;
Ok(())
}

Portable ProgramSpec, LiveSpec, and StackManifest hashes do not include runtime hostnames. Building or starting a4-server also does not publish generated SDK packages. Operators are responsible for reviewed npm/crates.io publication and for mapping the resulting endpoint bindings through any DNS/CDN provider they choose.