Configuration
This guide covers how to configure Naylence components. The SDK provides pre-built configuration objects that work out of the box while allowing customization through environment variables and configuration profiles.
Overview
Naylence uses a profile-based configuration system that simplifies setup while providing flexibility:
- Pre-built configs - The SDK exports ready-to-use configurations for sentinels, nodes (agents), and clients
- Configuration profiles - Each aspect of the system (security, storage, delivery, etc.) can be configured via named profiles
- Environment variable interpolation - All profiles support
${env:VAR_NAME:default}syntax for runtime customization
This approach means you can start with zero configuration and gradually customize as your requirements grow.
Pre-built Configurations
Both SDKs provide three configuration objects that you can use directly:
| Config | Use Case |
|---|---|
SENTINEL_CONFIG | For standalone sentinels that accept connections |
NODE_CONFIG | For agents that connect to a sentinel |
CLIENT_CONFIG | For clients that invoke agents |
import { SENTINEL_CONFIG, NODE_CONFIG, CLIENT_CONFIG } from '@naylence/agent-sdk';
// Start a sentinel with default configuration
const sentinel = new Sentinel(SENTINEL_CONFIG);
await sentinel.start();
// Create an agent using the node config
const agent = new MyAgent(NODE_CONFIG);
await agent.start();
// Create a client
const client = new Client(CLIENT_CONFIG);
await client.start();from naylence.agent import SENTINEL_CONFIG, NODE_CONFIG, CLIENT_CONFIG
from naylence.agent import Sentinel, BaseAgent, Client
# Start a sentinel with default configuration
sentinel = Sentinel(SENTINEL_CONFIG)
await sentinel.start()
# Create an agent using the node config
agent = MyAgent(NODE_CONFIG)
await agent.start()
# Create a client
client = Client(CLIENT_CONFIG)
await client.start()The pre-built configs include sensible defaults and support environment variable interpolation, so you can customize them at runtime without changing code.
Configuration Profiles
Naylence uses profiles to configure different aspects of the system. Each profile type has a default value that can be overridden via environment variables.
Profile Types
| Profile | Purpose | Default |
|---|---|---|
| Security | Message signing and encryption | open |
| Admission | Connection authentication | open (client/node), none (sentinel) |
| Storage | State and message persistence | memory |
| Delivery | Message delivery guarantees | at-most-once |
| Node Identity | Identity management (TypeScript only) | default |
How Profiles Work
Each configuration section uses a profile reference that looks like this:
security:
type: SecurityProfile
profile: "${env:FAME_SECURITY_PROFILE:open}"This means:
- Look for
FAME_SECURITY_PROFILEenvironment variable - If not set, use
openas the default - The runtime loads the corresponding profile implementation
Available Profile Values
Security Profiles
| Profile | Description |
|---|---|
open | No message signing, encryption, or authorization (development only) |
overlay | Message signing with OAuth2 JWT authorization |
overlay-callback | Overlay with HMAC-based reverse authorization (callback flow) |
strict-overlay | Full X.509 certificate chain signing with JWKS verification |
gated | OAuth2 authorization without message signing |
gated-callback | Gated with HMAC-based reverse authorization |
Admission Profiles
| Profile | Description |
|---|---|
open | Direct WebSocket connection without authentication |
none / noop | No outbound connections |
direct | OAuth2 client credentials over WebSocket |
direct-pkce | OAuth2 PKCE flow over WebSocket (browser-friendly) |
direct-http | OAuth2 client credentials over HTTP |
direct-inpage | In-page channel connection (same-origin browser) |
welcome | Welcome service with OAuth2 client credentials |
welcome-pkce | Welcome service with OAuth2 PKCE flow |
Storage Profiles
| Profile | Description |
|---|---|
memory | In-memory storage (data lost on restart) |
indexeddb | Browser IndexedDB storage (browser environments only) |
sqlite | SQLite file-based storage (Node.js only) |
encrypted-sqlite | SQLite with AES-256 encryption (Node.js only) |
Delivery Profiles
| Profile | Description |
|---|---|
at-most-once | Fire-and-forget, no retries |
at-least-once | Retry until acknowledged (with configurable backoff) |
Config Structure
The configuration is a JSON/dictionary object with a node section containing the component settings:
// Structure of SENTINEL_CONFIG
export const SENTINEL_CONFIG = {
plugins: ['@naylence/runtime', '@naylence/agent-sdk'],
node: {
type: 'Sentinel',
id: '${env:FAME_NODE_ID:}',
public_url: '${env:FAME_PUBLIC_URL:}',
listeners: [
{ type: 'HttpListener', port: 8000 },
{ type: 'WebSocketListener', port: 8000 },
],
requested_logicals: ['fame.fabric'],
security: {
type: 'SecurityProfile',
profile: '${env:FAME_SECURITY_PROFILE:open}',
},
admission: {
type: 'AdmissionProfile',
profile: '${env:FAME_ADMISSION_PROFILE:none}',
},
identity_policy: {
type: 'NodeIdentityPolicyProfile',
profile: '${env:FAME_NODE_IDENTITY_PROFILE:default}',
},
storage: {
type: 'StorageProfile',
profile: '${env:FAME_STORAGE_PROFILE:memory}',
},
delivery: {
type: 'DeliveryProfile',
profile: '${env:FAME_DELIVERY_PROFILE:at-most-once}',
},
},
};# Structure of SENTINEL_CONFIG
SENTINEL_CONFIG = {
"node": {
"type": "Sentinel",
"id": "${env:FAME_NODE_ID:}",
"public_url": "${env:FAME_PUBLIC_URL:}",
"listeners": [
{"type": "HttpListener", "port": 8000},
{"type": "WebSocketListener", "port": 8000},
],
"requested_logicals": ["fame.fabric"],
"security": {
"type": "SecurityProfile",
"profile": "${env:FAME_SECURITY_PROFILE:open}",
},
"admission": {
"type": "AdmissionProfile",
"profile": "${env:FAME_ADMISSION_PROFILE:none}",
},
"storage": {
"type": "StorageProfile",
"profile": "${env:FAME_STORAGE_PROFILE:memory}",
},
"delivery": {
"type": "DeliveryProfile",
"profile": "${env:FAME_DELIVERY_PROFILE:at-most-once}",
},
},
}Key Differences by Config Type
| Setting | SENTINEL_CONFIG | NODE_CONFIG | CLIENT_CONFIG |
|---|---|---|---|
type | Sentinel | Node | (implicit) |
listeners | HTTP + WebSocket on 8000 | None | None |
admission default | none | open | open |
id | Optional | Optional | N/A |
public_url | Optional | Optional | N/A |
Custom Configuration
You can extend or modify the pre-built configs for specific needs:
import { SENTINEL_CONFIG } from '@naylence/agent-sdk';
// Create a custom config based on SENTINEL_CONFIG
const customConfig = {
...SENTINEL_CONFIG,
node: {
...SENTINEL_CONFIG.node,
listeners: [
{ type: 'HttpListener', port: 9000 }, // Custom port
{ type: 'WebSocketListener', port: 9000 },
],
// Add telemetry configuration
telemetry: {
type: 'OpenTelemetryTraceEmitter',
service_name: 'my-service',
endpoint: '${env:OTEL_ENDPOINT:}',
},
},
};
const sentinel = new Sentinel(customConfig);from naylence.agent import SENTINEL_CONFIG
# Create a custom config based on SENTINEL_CONFIG
custom_config = {
**SENTINEL_CONFIG,
"node": {
**SENTINEL_CONFIG["node"],
"listeners": [
{"type": "HttpListener", "port": 9000}, # Custom port
{"type": "WebSocketListener", "port": 9000},
],
# Add telemetry configuration
"telemetry": {
"type": "OpenTelemetryTraceEmitter",
"service_name": "my-service",
"endpoint": "${env:OTEL_ENDPOINT:}",
},
},
}
sentinel = Sentinel(custom_config)YAML Configuration Files
For complex configurations, you can use YAML files instead of inline configs:
node:
type: Sentinel
id: "${env:FAME_NODE_ID:}"
public_url: "${env:FAME_PUBLIC_URL:}"
listeners:
- type: HttpListener
port: 8000
- type: WebSocketListener
port: 8000
requested_logicals:
- fame.fabric
security:
type: SecurityProfile
profile: "${env:FAME_SECURITY_PROFILE:open}"
admission:
type: AdmissionProfile
profile: "${env:FAME_ADMISSION_PROFILE:none}"
storage:
type: StorageProfile
profile: "${env:FAME_STORAGE_PROFILE:memory}"
delivery:
type: DeliveryProfile
profile: "${env:FAME_DELIVERY_PROFILE:at-most-once}"Environment Variable Reference
All environment variables use the FAME_ prefix. This section provides a comprehensive reference of supported variables.
Connection Variables
| Variable | Description | Example |
|---|---|---|
FAME_DIRECT_ADMISSION_URL | WebSocket URL to connect to a sentinel | ws://sentinel:8000/fame/v1/attach/ws/downstream |
FAME_PEER_WS_URL | WebSocket URL for sentinel peering | ws://peer:8000/fame/v1/attach/ws/peer |
FAME_PUBLIC_URL | Public URL for this node | wss://my-service.example.com |
Node Identity Variables
| Variable | Description | Default |
|---|---|---|
FAME_NODE_ID | Unique identifier for this node | Auto-generated |
FAME_NODE_IDENTITY_PROFILE | Node identity management profile (TS only) | default |
Profile Variables
| Variable | Description | Default | Values |
|---|---|---|---|
FAME_SECURITY_PROFILE | Security profile to use | open | open, overlay, overlay-callback, strict-overlay, gated, gated-callback |
FAME_ADMISSION_PROFILE | Admission profile to use | open/none | open, none, direct, direct-pkce, direct-http, direct-inpage, welcome, welcome-pkce |
FAME_STORAGE_PROFILE | Storage profile to use | memory | memory, indexeddb, sqlite, encrypted-sqlite |
FAME_DELIVERY_PROFILE | Delivery profile to use | at-most-once | at-most-once, at-least-once |
Storage Variables
| Variable | Description | Required For |
|---|---|---|
FAME_STORAGE_DB_DIRECTORY | Directory for SQLite database files | sqlite, encrypted-sqlite |
FAME_STORAGE_MASTER_KEY | 32-byte hex encryption key | encrypted-sqlite |
Security: The FAME_STORAGE_MASTER_KEY should be a secure 32-byte (64 hex character) key. Generate one using:
openssl rand -hex 32Never commit this key to version control.
Authentication Variables
Used with direct, direct-pkce, welcome, and welcome-pkce admission profiles:
| Variable | Description | Used With |
|---|---|---|
FAME_ADMISSION_TOKEN_URL | OAuth2 token endpoint URL | direct, direct-pkce, welcome, welcome-pkce |
FAME_ADMISSION_CLIENT_ID | OAuth2 client ID | All OAuth2 profiles |
FAME_ADMISSION_CLIENT_SECRET | OAuth2 client secret | direct, welcome (not PKCE) |
FAME_ADMISSION_AUTHORIZE_URL | OAuth2 authorization endpoint | direct-pkce, welcome-pkce |
FAME_ADMISSION_REDIRECT_URL | OAuth2 redirect URI | direct-pkce, welcome-pkce |
FAME_ADMISSION_SERVICE_URL | Welcome service URL | welcome, welcome-pkce |
FAME_JWT_AUDIENCE | JWT audience claim | All OAuth2 profiles |
FAME_ADMISSION_LOGIN_HINT_PARAM | Login hint parameter name | PKCE profiles (default: login_hint) |
FAME_ADMISSION_CODE_CHALLENGE_METHOD | PKCE code challenge method | PKCE profiles (default: S256) |
Security Variables
Used with security profiles for message signing and authorization:
| Variable | Description | Used With |
|---|---|---|
FAME_HMAC_SECRET | HMAC secret for JWT signing | overlay-callback, gated-callback |
FAME_JWT_TRUSTED_ISSUER | Trusted JWT issuer | overlay, gated, strict-overlay |
FAME_JWT_ALGORITHM | JWT signing algorithm | overlay, gated (default: RS256) |
FAME_JWKS_URL | JWKS endpoint for key verification | strict-overlay |
FAME_DEFAULT_ENCRYPTION_LEVEL | Default message encryption level | strict-overlay (default: channel) |
FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER | Issuer for reverse auth JWTs | overlay-callback, gated-callback |
FAME_JWT_REVERSE_AUTH_AUDIENCE | Audience for reverse auth JWTs | overlay-callback, gated-callback |
Debugging Variables
| Variable | Description | Values |
|---|---|---|
FAME_LOG_LEVEL | Logging verbosity | DEBUG, INFO, WARNING, ERROR |
FAME_SHOW_ENVELOPES | Log message envelopes | true, false |
Plugin Variables (TypeScript Only)
| Variable | Description | Default |
|---|---|---|
FAME_PLUGINS | Comma-separated list of plugins to load | @naylence/runtime |
The TypeScript SDK automatically adds @naylence/agent-sdk to FAME_PLUGINS when imported.
Telemetry Variables
Used when configuring OpenTelemetry:
| Variable | Description |
|---|---|
FAME_TELEMETRY_OTLP_ENDPOINT | OTLP collector endpoint |
FAME_TELEMETRY_TOKEN_URL | Token URL for telemetry auth |
FAME_TELEMETRY_CLIENT_ID | Client ID for telemetry auth |
FAME_TELEMETRY_CLIENT_SECRET | Client secret for telemetry auth |
FAME_TELEMETRY_JWT_AUDIENCE | JWT audience for telemetry |
Delivery Variables
Used with at-least-once delivery profile for retry configuration:
| Variable | Description | Default |
|---|---|---|
FAME_DELIVERY_MAX_RETRIES | Maximum retry attempts | 5 (sender), 6 (receiver) |
FAME_DELIVERY_BASE_DELAY_MS | Initial retry delay in milliseconds | 1000 (sender), 100 (receiver) |
FAME_DELIVERY_MAX_DELAY_MS | Maximum retry delay in milliseconds | 10000 (sender), 2000 (receiver) |
FAME_DELIVERY_JITTER_MS | Random jitter added to delays | 200 (sender), 50 (receiver) |
FAME_DELIVERY_BACKOFF_FACTOR | Exponential backoff multiplier | 2.0 (sender), 1.8 (receiver) |
Flow Control Variables
| Variable | Description | Default |
|---|---|---|
FAME_FLOW_CONTROL | Flow control buffer size (0 = disabled) | (varies) |
Configuration Patterns
Development Setup
Minimal configuration for local development:
# No env vars needed - defaults work out of the box
# Optionally enable debug logging:
export FAME_LOG_LEVEL=DEBUG
export FAME_SHOW_ENVELOPES=trueDistributed Setup
For agents connecting to a remote sentinel:
# Agent/Client connecting to sentinel
export FAME_DIRECT_ADMISSION_URL=ws://sentinel:8000/fame/v1/attach/ws/downstreamPersistent Storage Setup
For agents that need to persist state:
export FAME_STORAGE_PROFILE=encrypted-sqlite
export FAME_STORAGE_MASTER_KEY=$(openssl rand -hex 32)
export FAME_STORAGE_DB_DIRECTORY=./dataProduction Setup
Recommended configuration for production:
# Security
export FAME_SECURITY_PROFILE=overlay
export FAME_ADMISSION_PROFILE=direct
export FAME_ADMISSION_TOKEN_URL=https://auth.example.com/oauth/token
export FAME_ADMISSION_CLIENT_ID=your-client-id
export FAME_ADMISSION_CLIENT_SECRET=your-client-secret
# Storage
export FAME_STORAGE_PROFILE=encrypted-sqlite
export FAME_STORAGE_MASTER_KEY=<secure-32-byte-hex-key>
export FAME_STORAGE_DB_DIRECTORY=/var/data/naylence
# Delivery
export FAME_DELIVERY_PROFILE=at-least-once
# Connection (for agents/clients)
export FAME_DIRECT_ADMISSION_URL=wss://sentinel.example.com/fame/v1/attach/ws/downstreamDocker Compose Pattern
Using .env files with Docker Compose:
services:
sentinel:
image: naylence/agent-sdk-node:0.3.5
env_file:
- config/.env.sentinel
# ...
agent:
image: naylence/agent-sdk-node:0.3.5
env_file:
- config/.env.agent
# ...FAME_STORAGE_PROFILE=encrypted-sqlite
FAME_STORAGE_MASTER_KEY=${FAME_STORAGE_MASTER_KEY}
FAME_STORAGE_DB_DIRECTORY=/work/data/sentinelFAME_DIRECT_ADMISSION_URL=ws://sentinel:8000/fame/v1/attach/ws/downstream
FAME_STORAGE_PROFILE=encrypted-sqlite
FAME_STORAGE_MASTER_KEY=${FAME_STORAGE_MASTER_KEY}
FAME_STORAGE_DB_DIRECTORY=/work/data/agentBrowser Environment
For browser clients, set environment variables via a global object:
<script>
window.__ENV__ = {
FAME_DIRECT_ADMISSION_URL: "ws://localhost:8000/fame/v1/attach/ws/downstream",
FAME_LOG_LEVEL: "WARNING",
FAME_SHOW_ENVELOPES: "false"
};
</script>Or in a separate file:
window.__ENV__ = window.__ENV__ || {};
window.__ENV__.FAME_DIRECT_ADMISSION_URL = "ws://localhost:8000/fame/v1/attach/ws/downstream";
window.__ENV__.FAME_LOG_LEVEL = "WARNING";Best Practices
- Start with defaults - The pre-built configs work for most development scenarios
- Use environment variables - Never hardcode secrets or URLs in code
- Use
.env.examplefiles - Document required variables with placeholders - Separate configs per component - Each sentinel/agent/client should have its own env file
- Secure production secrets - Use secret management tools, never commit keys
- Enable
at-least-oncedelivery for reliability - Combined with persistent storage for crash recovery - Use
overlaysecurity in production - Provides message signing and encryption