This document provides comprehensive architectural guidance for the @nexical/agent package. It outlines the system's core design, runtime behavior, and patterns for development. This serves as the authoritative guide for contributing to and understanding the Nexus Agent.
The Nexus Agent is an Orchestrator Worker. It acts as the execution arm of the Nexus Ecosystem. It is designed to connect to the centralized Orchestrator API, receive tasks, and process them locally or act as a supervisor for long-running processes.
The agent operates in two primary modalities via a single entrypoint (src/main.ts):
- Supervisor Mode (Default): Runs the
JobPoller(which fetches and executes discrete jobs) and acts as a process manager (Supervisor) spawning child processes for long-running persistent agents. - Processor Mode (
--processor [name]): Runs as a dedicated spawned child process executing a singlePersistentAgentcontinuously.
The core abstractions are located in src/core/.
Defines a worker that handles discrete, queue-based jobs.
- Trigger: Activated by the
JobPollerwhen the Orchestrator API assigns a job. - Validation: Enforces strongly-typed payloads using
z.ZodSchema. TheJobExecutorautomatically validates the payload before handing it to theprocess()method. - Contract: Must implement
jobType(string),schema(Zod), andprocess(job, context)logic.
Defines a worker that runs continuously in a loop (tick-based).
- Trigger: Started by the
AgentSupervisorand runs in its own isolated OS process. - Loop: Executes the
tick()method on a definedintervalMs. - Contract: Must implement
name(string) and thetick()method. State is maintained within the class instance.
The runtime details are orchestrated inside src/runtime/.
When the main process boots, the AgentSupervisor reads all registered PersistentAgent classes from the registry and spawns them.
- Isolation: Each persistent agent runs in a child process (via
forkin production orspawnwithtsxin development). - Resilience: The supervisor listens for exit signals from children and automatically restarts them after a 5-second backoff.
- Graceful Shutdown: Intercepts
SIGINT/SIGTERMto safely terminate all child processes before exiting the main process. - Environment Awareness: The supervisor MUST detect the entrypoint type and use the appropriate engine (
tsxfor development,nodefork for production).
While persistent agents run as children, the main process runs the JobPoller.
- JobPoller: Continuously long-polls the Orchestrator API (via
AgentClient.poll) advertising its "capabilities" (the list of registeredJobProcessortypes). - JobExecutor: When a job is received, the Executor validates the payload against the processor's Zod schema. It injects an
AgentContext(providing API access and remote logging) into the processor. - Completion/Failure: The Poller guarantees that the outcome (
completeorfail) is reported back to the Orchestrator.
Network interactions are managed in src/networking/.
A specialized wrapper around the @nexical/sdk NexicalClient. It is responsible for orchestrator-specific operations:
- Registration: Calls
registerAgentproviding its hostname and capabilities. - Polling & Updates: Handles
pollJobs,completeJob,failJob, andupdateProgress. - Job Creation: Allows agents to spawn child jobs via
createJob.
Security relies on a shared secret token mechanism.
- The
AgentAuthStrategyapplies the token (fromAGENT_API_TOKEN) as a Bearer token. - Both the main Poller and the Persistent Agent child processes utilize this token.
When adding new capabilities to the agent, adhere strictly to these patterns:
- Create a class extending
JobProcessor<T>inapps/backend/modules/{module}/src/agent/{ClassName}.ts. - Define your payload schema using
zod. - Implement the
processmethod. Usecontext.loggerfor remote observability, avoiding standardconsole.logfor job-specific execution flows. - DO NOT manually edit
src/registry.ts. The discovery script handles registration automatically. - Trigger registration by running
npm run generatein thepackages/agentdirectory.
// Example Implementation (apps/backend/modules/orchestrator-api/src/agent/EchoProcessor.ts)
import { z } from 'zod';
import { JobProcessor, type AgentJob, type AgentContext } from '@nexical/agent';
export const MyJobSchema = z.object({ targetPath: z.string() });
export type MyJobPayload = z.infer<typeof MyJobSchema>;
export class MyJobProcessor extends JobProcessor<MyJobPayload> {
public jobType = 'my-job-type';
public schema = MyJobSchema;
public async process(job: AgentJob<MyJobPayload>, ctx: AgentContext) {
ctx.logger.info(`Processing ${job.payload.targetPath}`);
// implementation
return { success: true };
}
}- Create a class extending
PersistentAgentinapps/backend/modules/{module}/src/agent/{ClassName}.ts. - Define the
nameand (optionally) overrideintervalMs. - Implement the
tick()method. - Trigger registration by running
npm run generatein thepackages/agentdirectory.
The Nexus Agent utilizes a centralized registry for background agents and job processors discovered across backend modules.
- Discovery Root: The system scans
apps/backend/modules/*/src/agent/*.tsfor valid classes. - Registry Key Convention: Keys MUST follow the format
{module-name}.{ClassName}(e.g.,orchestrator-api.EchoProcessor). - Trigger: The file
packages/agent/src/registry.tsis machine-generated and MUST NOT be edited manually. Runnpm run generateto refresh the registry.
- Strict Naming: Agent implementation classes MUST use PascalCase and include a functional suffix:
Processorfor queue-based jobs (JobProcessor) orAgentfor continuous tasks (PersistentAgent). - Strict Typing: The
anytype is strictly forbidden. Use Zod schemas to derive TypeScript types automatically. - Isolation: Processors must not maintain shared memory state, as they may be executed concurrently or across different agent nodes.
- API Access: Always utilize the
this.api(Nexical SDK client) or thecontext.apiinjected into job processors. Do not construct rawfetchcalls to the orchestrator. - ESM Module Imports: Local file imports in TypeScript MUST include the
.jsextension to ensure compatibility with the ESM runtime (e.g.,import { MyService } from './my-service.js').
- Boot:
node dist/main.jsis executed. - Env Validation: Ensures
AGENT_API_TOKENexists. - Supervisor Init:
AgentSupervisorspawns child processes for eachPersistentAgent. - Registration: Main process calls the Orchestrator to register its capabilities (
jobProcessors). - Poller Loop: Main process polls for jobs.
- On Job ->
JobExecutor-> Validate -> Execute -> Complete/Fail.
- On Job ->
- Child Loops: Child processes run
PersistentAgent.tick()independently.
- ESM Import Compliance: All relative imports MUST include the
.jsextension even when writing in TypeScript (e.g.,import { MyService } from './my-service.js'). - Named Exports Only: Core classes, interfaces, and constants MUST be exported using named exports. Default exports are strictly forbidden.
- Constructor-Based Dependency Injection: All classes MUST receive their dependencies (clients, loggers, config) via the constructor. Do NOT pull directly from
process.envin the constructor. - Persistent Lifecycle Management: Persistent agents MUST use a controlled
while(this.running)loop with atry/catchwrapper for thetick()method to isolate individual failure events. - Environment-First Configuration: Agent configuration (API URLs, Tokens, Intervals) MUST prioritize
AGENT_*environment variables. - Standardized SDK Client: Agents MUST use
NexicalClientwith the appropriateAgentAuthStrategyfor all API interactions.