Skip to content
reaatechREAATECH

@reaatech/agent-mesh-registry

npm v1.0.0

Manages a thread-safe registry of validated YAML agent configurations, providing atomic-swap updates and SIGHUP-triggered hot-reloading. It exposes a singleton state object for lookups and includes Zod-based validation with built-in SSRF protection for agent URLs.

@reaatech/agent-mesh-registry

npm version License: MIT CI

Status: Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.

Agent registry loader with atomic-swap semantics and SIGHUP hot-reload. Parses YAML agent configurations, validates them against Zod schemas with SSRF protection, and manages a thread-safe registry singleton with debounced signal-based updates.

Installation

terminal
npm install @reaatech/agent-mesh-registry
# or
pnpm add @reaatech/agent-mesh-registry

Feature Overview

  • YAML agent configuration — load agent definitions from a directory of YAML files with ${ENV_VAR} expansion
  • SSRF-safe URL validation — rejects localhost, private IPs (10.x, 172.16.x, 192.168.x), link-local addresses, and IPv6 loopbacks
  • Atomic-swap semantics — readers always get a consistent snapshot; failed reloads leave the old registry intact
  • SIGHUP hot-reload — debounced signal handler (5s default) with coalescing for rapid signals
  • Cross-agent invariant enforcement — exactly one default agent, unique IDs, default threshold must be 0
  • File size limits — YAML files exceeding 1MB are skipped with errors

Quick Start

typescript
import { initRegistry, registryState } from "@reaatech/agent-mesh-registry";
 
// Load the registry at startup
await initRegistry();
 
// Access the loaded registry
console.log(`${registryState.getAgentIds().length} agents loaded`);
console.log(`Default agent: ${registryState.defaultAgent?.agent_id}`);
 
// Look up a specific agent
const agent = registryState.getAgent("serval");

API Reference

Registry State

registryState (singleton)

The global RegistryState instance with atomic-swap semantics.

Property / MethodDescription
registryThe current agent registry array (or null if not loaded)
defaultAgentThe agent with is_default: true (or null)
isLoadedtrue if the registry has been successfully loaded
loadErrorThe last load error (or null)
lastLoadTimeTimestamp of the last successful load
getAgent(agentId)Look up an agent by ID
getAgentIds()Return all registered agent IDs

Loading

initRegistry(): Promise<void>

Loads the registry at startup. Throws on failure — fail-fast behavior.

loadRegistry(): Promise<AgentRegistry>

Loads and validates all YAML files from the configured directory. Returns a validated array of AgentConfig objects.

reloadRegistry(): Promise<RegistryLoadResult>

Loads and atomically swaps the registry. Returns a result object with success status, agent count, and errors. On failure, the old registry remains active — no downtime.

SIGHUP Handler

setupSighupHandler(debounceMs?): void

Registers a debounced SIGHUP handler that calls reloadRegistry(). Multiple signals within the debounce window (default 5s) coalesce into a single reload.

typescript
import { setupSighupHandler } from "@reaatech/agent-mesh-registry";
 
setupSighupHandler(); // Default 5s debounce
// or
setupSighupHandler(10000); // Custom 10s debounce

triggerReload(): Promise<void>

Triggers an immediate reload, bypassing the debounce. Useful for programmatic reloads or testing.

isReloadPending(): boolean

Returns true if a SIGHUP-triggered reload is pending (waiting for debounce).

cleanupSighupHandler(): void

Removes the SIGHUP listener and cancels any pending reloads.

Agent Configuration Schema

AgentConfigSchema (Zod)

FieldTypeDescription
agent_idstringUnique lowercase identifier with hyphens
display_namestringHuman-readable name
descriptionstringInjected into the classifier prompt
endpointstring (SSRF-safe URL)MCP server endpoint
typemcpAlways mcp
is_defaultbooleanExactly one agent must be true
confidence_thresholdnumber (0–1)Default must be 0
clarification_requiredbooleanWhether to ask clarifying questions
clarification_contextstring?Shown when clarification is needed
examplesstring[]Few-shot examples for the classifier

Agent YAML Format

Create files in the registry directory (default ./agents/):

yaml
agent_id: "my-agent"
display_name: "My Agent"
description: "Handles specific domain tasks"
endpoint: "${MY_AGENT_ENDPOINT:-http://localhost:8081}"
type: mcp
is_default: false
confidence_threshold: 0.7
clarification_required: false
examples:
  - "Example query 1"
  - "Example query 2"

Environment variables in ${VAR} and ${VAR:-default} syntax are expanded at load time.

Usage Patterns

At Startup

typescript
import { initRegistry, setupSighupHandler } from "@reaatech/agent-mesh-registry";
 
// Fail-fast: exit if registry can't load
await initRegistry();
 
// Register hot-reload handler
setupSighupHandler();

In Request Handlers

typescript
import { registryState } from "@reaatech/agent-mesh-registry";
 
function routeRequest(classification: ClassifierOutput) {
  const agent = registryState.getAgent(classification.agent_id);
  if (!agent) {
    // Fall back to default
    return registryState.defaultAgent;
  }
  return agent;
}

Programmatic Reload

typescript
import { triggerReload } from "@reaatech/agent-mesh-registry";
 
// Admin endpoint to reload agents
app.post("/admin/reload-registry", async (req, res) => {
  await triggerReload();
  res.json({ success: true, agents: registryState.getAgentIds() });
});

License

MIT