Skip to content

FleetManager API Reference

The FleetManager class is the primary entry point for using herdctl programmatically. It provides a simple, high-level API to initialize and run a fleet of agents with minimal configuration.

Terminal window
npm install @herdctl/core
# or
pnpm add @herdctl/core
import { FleetManager } from '@herdctl/core';
const manager = new FleetManager({
configPath: './herdctl.yaml',
stateDir: './.herdctl',
});
await manager.initialize();
await manager.start();
// Subscribe to events
manager.on('job:created', (payload) => {
console.log(`Job ${payload.job.id} created for ${payload.agentName}`);
});
// Graceful shutdown
process.on('SIGINT', async () => {
await manager.stop();
process.exit(0);
});

Creates a new FleetManager instance.

const manager = new FleetManager(options: FleetManagerOptions);
ParameterTypeRequiredDefaultDescription
options.stateDirstringYesPath to the state directory (e.g., .herdctl). Created if it doesn’t exist. Stores job artifacts, session state, and logs.
options.configPathstringNoAuto-discoverPath to herdctl.yaml. Can be absolute, relative, or a directory path. If not provided, searches up from cwd.
options.loggerFleetManagerLoggerNoConsole loggerCustom logger with debug, info, warn, error methods.
options.checkIntervalnumberNo1000Interval in milliseconds between scheduler checks.
import { FleetManager } from '@herdctl/core';
// Minimal configuration
const manager = new FleetManager({
stateDir: './.herdctl',
});
// Full configuration
const manager = new FleetManager({
configPath: './config/herdctl.yaml',
stateDir: './.herdctl',
checkInterval: 5000, // 5 seconds
logger: {
debug: (msg) => console.debug(`[DEBUG] ${msg}`),
info: (msg) => console.info(`[INFO] ${msg}`),
warn: (msg) => console.warn(`[WARN] ${msg}`),
error: (msg) => console.error(`[ERROR] ${msg}`),
},
});

Initializes the fleet manager by loading configuration and preparing the state directory.

await manager.initialize(): Promise<void>

This method:

  1. Loads and validates the configuration file
  2. Initializes the state directory structure
  3. Prepares the scheduler (but does not start it)

After initialization, the fleet manager is ready to start.

ErrorCondition
FleetManagerStateErrorAlready initialized or running
FleetManagerConfigErrorConfiguration is invalid or not found
FleetManagerStateDirErrorState directory cannot be created
const manager = new FleetManager({
configPath: './herdctl.yaml',
stateDir: './.herdctl',
});
try {
await manager.initialize();
console.log(`Loaded ${manager.state.agentCount} agents`);
} catch (error) {
if (error instanceof FleetManagerConfigError) {
console.error('Configuration error:', error.message);
}
}

Starts the fleet manager scheduler, which begins processing agent schedules.

await manager.start(): Promise<void>

This begins the scheduler, which will:

  1. Check agent schedules at the configured interval
  2. Trigger agents when their schedules are due
  3. Track schedule state in the state directory
ErrorCondition
FleetManagerStateErrorNot initialized
await manager.initialize();
await manager.start();
// The manager is now running and processing schedules
manager.on('schedule:triggered', (payload) => {
console.log(`Triggered ${payload.agentName}/${payload.scheduleName}`);
});

Gracefully stops the fleet manager.

await manager.stop(options?: FleetManagerStopOptions): Promise<void>
ParameterTypeRequiredDefaultDescription
options.waitForJobsbooleanNotrueWait for running jobs to complete before stopping
options.timeoutnumberNo30000Maximum time in ms to wait for jobs to complete
options.cancelOnTimeoutbooleanNofalseCancel jobs that don’t complete within timeout
options.cancelTimeoutnumberNo10000Time in ms for each job to respond to SIGTERM before SIGKILL

This will:

  1. Signal the scheduler to stop accepting new triggers
  2. Wait for running jobs to complete (with timeout)
  3. If timeout is reached and cancelOnTimeout is true, cancel remaining jobs
  4. Persist all state before shutdown completes
  5. Emit 'stopped' event when complete
ErrorCondition
FleetManagerShutdownErrorShutdown times out and cancelOnTimeout is false
// Normal shutdown - wait for jobs with default 30s timeout
await manager.stop();
// Shutdown with custom timeout
await manager.stop({ timeout: 60000 });
// Shutdown without waiting for jobs (not recommended)
await manager.stop({ waitForJobs: false });
// Cancel jobs if they don't complete in time
await manager.stop({
timeout: 30000,
cancelOnTimeout: true,
cancelTimeout: 10000,
});

Hot-reloads configuration without restarting the fleet.

await manager.reload(): Promise<ConfigReloadedPayload>
interface ConfigReloadedPayload {
agentCount: number; // Number of agents in new config
agentNames: string[]; // Names of agents in new config
configPath: string; // Path to reloaded config file
changes: ConfigChange[]; // List of detected changes
timestamp: string; // ISO timestamp of reload
}
interface ConfigChange {
type: 'added' | 'removed' | 'modified';
category: 'agent' | 'schedule' | 'defaults';
name: string; // Agent name or "agent/schedule"
details?: string; // What changed (for modifications)
}

This method provides hot configuration reload capability:

  1. Loads and validates the new configuration
  2. If validation fails, keeps the old configuration (fails gracefully)
  3. Running jobs continue with their original configuration
  4. New jobs will use the new configuration
  5. Updates the scheduler with new agent definitions
  6. Emits a 'config:reloaded' event with change details
ErrorCondition
InvalidStateErrorFleet manager is not initialized
FleetManagerConfigErrorNew configuration is invalid
// Reload configuration
const result = await manager.reload();
console.log(`Reloaded with ${result.changes.length} changes`);
for (const change of result.changes) {
console.log(` ${change.type} ${change.category}: ${change.name}`);
}
// Subscribe to reload events
manager.on('config:reloaded', (payload) => {
console.log(`Config reloaded: ${payload.agentCount} agents`);
});

Returns a comprehensive snapshot of fleet state.

await manager.getFleetStatus(): Promise<FleetStatus>
interface FleetStatus {
state: FleetManagerStatus; // Current state
uptimeSeconds: number | null; // Time since started
initializedAt: string | null; // ISO timestamp
startedAt: string | null; // ISO timestamp
stoppedAt: string | null; // ISO timestamp
counts: FleetCounts; // Summary counts
scheduler: {
status: 'stopped' | 'running' | 'stopping';
checkCount: number; // Total checks performed
triggerCount: number; // Total triggers fired
lastCheckAt: string | null; // ISO timestamp
checkIntervalMs: number;
};
lastError: string | null;
}
interface FleetCounts {
totalAgents: number;
idleAgents: number;
runningAgents: number;
errorAgents: number;
totalSchedules: number;
runningSchedules: number;
runningJobs: number;
}
const status = await manager.getFleetStatus();
console.log(`Fleet: ${status.state}`);
console.log(`Uptime: ${status.uptimeSeconds}s`);
console.log(`Agents: ${status.counts.totalAgents} total, ${status.counts.runningAgents} running`);
console.log(`Jobs: ${status.counts.runningJobs} running`);

Returns information about all configured agents.

await manager.getAgentInfo(): Promise<AgentInfo[]>
interface AgentInfo {
name: string; // Agent local name
qualifiedName: string; // Dot-separated qualified name (e.g., "myfleet.agent-name")
fleetPath: string[]; // Fleet hierarchy path (empty for root agents)
description?: string; // From configuration
status: 'idle' | 'running' | 'error';
currentJobId: string | null; // Currently running job
lastJobId: string | null; // Last completed job
maxConcurrent: number; // Max concurrent instances
runningCount: number; // Currently running instances
errorMessage: string | null; // Error if status is 'error'
scheduleCount: number; // Number of schedules
schedules: ScheduleInfo[]; // Schedule details
model?: string; // Model from config
working_directory?: string; // Working directory path
chat?: Record<string, AgentChatStatus>; // Chat connector statuses by platform
}
interface AgentChatStatus {
configured: boolean;
connectionStatus?: 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'disconnecting' | 'error';
botUsername?: string;
lastError?: string;
}
const agents = await manager.getAgentInfo();
for (const agent of agents) {
console.log(`${agent.name}: ${agent.status}`);
console.log(` Running: ${agent.runningCount}/${agent.maxConcurrent}`);
console.log(` Schedules: ${agent.scheduleCount}`);
}

Returns information about a specific agent.

await manager.getAgentInfoByName(name: string): Promise<AgentInfo>
ParameterTypeRequiredDescription
namestringYesThe agent name to look up
ErrorCondition
AgentNotFoundErrorNo agent with that name exists
try {
const agent = await manager.getAgentInfoByName('my-agent');
console.log(`Status: ${agent.status}`);
console.log(`Running: ${agent.runningCount}/${agent.maxConcurrent}`);
} catch (error) {
if (error instanceof AgentNotFoundError) {
console.log(`Agent "${error.agentName}" not found`);
console.log(`Available: ${error.availableAgents?.join(', ')}`);
}
}

Returns all schedules across all agents.

await manager.getSchedules(): Promise<ScheduleInfo[]>
interface ScheduleInfo {
name: string; // Schedule name
agentName: string; // Owning agent
type: string; // 'interval', 'cron', etc.
interval?: string; // e.g., "5m", "1h"
expression?: string; // Cron expression
status: 'idle' | 'running' | 'disabled';
lastRunAt: string | null; // ISO timestamp
nextRunAt: string | null; // ISO timestamp
lastError: string | null;
}
const schedules = await manager.getSchedules();
for (const schedule of schedules) {
console.log(`${schedule.agentName}/${schedule.name}: ${schedule.status}`);
console.log(` Next run: ${schedule.nextRunAt}`);
}

Returns a specific schedule by agent and schedule name.

await manager.getSchedule(agentName: string, scheduleName: string): Promise<ScheduleInfo>
ErrorCondition
AgentNotFoundErrorAgent doesn’t exist
ScheduleNotFoundErrorSchedule doesn’t exist for agent
const schedule = await manager.getSchedule('my-agent', 'hourly');
console.log(`Status: ${schedule.status}`);
console.log(`Last run: ${schedule.lastRunAt}`);
console.log(`Next run: ${schedule.nextRunAt}`);

Enables a previously disabled schedule.

await manager.enableSchedule(agentName: string, scheduleName: string): Promise<ScheduleInfo>

Enables a schedule that was previously disabled, allowing it to trigger again on its configured interval. The enabled state is persisted and survives restarts.

const schedule = await manager.enableSchedule('my-agent', 'hourly');
console.log(`Schedule status: ${schedule.status}`); // 'idle'

Disables a schedule temporarily.

await manager.disableSchedule(agentName: string, scheduleName: string): Promise<ScheduleInfo>

Disables a schedule, preventing it from triggering on its configured interval. The schedule remains in the configuration but won’t run until re-enabled. The disabled state is persisted and survives restarts.

// Disable a schedule temporarily
const schedule = await manager.disableSchedule('my-agent', 'hourly');
console.log(`Schedule status: ${schedule.status}`); // 'disabled'
// Later, re-enable it
await manager.enableSchedule('my-agent', 'hourly');

trigger(agentName, scheduleName?, options?)

Section titled “trigger(agentName, scheduleName?, options?)”

Manually triggers an agent outside its normal schedule.

await manager.trigger(
agentName: string,
scheduleName?: string,
options?: TriggerOptions
): Promise<TriggerResult>
ParameterTypeRequiredDescription
agentNamestringYesName of the agent to trigger
scheduleNamestringNoSchedule to use for configuration (prompt, work source)
options.promptstringNoOverride the prompt for this trigger
options.workItemsWorkItem[]NoCustom work items instead of fetching from work source
options.bypassConcurrencyLimitbooleanNoForce trigger even if agent is at capacity (default: false)
interface TriggerResult {
jobId: string; // Unique job identifier
agentName: string;
scheduleName: string | null;
startedAt: string; // ISO timestamp
prompt?: string; // Prompt used for trigger
}
ErrorCondition
InvalidStateErrorFleet manager not initialized
AgentNotFoundErrorAgent doesn’t exist
ScheduleNotFoundErrorSpecified schedule doesn’t exist
ConcurrencyLimitErrorAgent at capacity and bypass not enabled
// Trigger with agent defaults
const job = await manager.trigger('my-agent');
console.log(`Created job: ${job.jobId}`);
// Trigger a specific schedule
const job = await manager.trigger('my-agent', 'hourly');
// Trigger with custom prompt
const job = await manager.trigger('my-agent', undefined, {
prompt: 'Review the latest security updates',
});
// Force trigger even at capacity
const job = await manager.trigger('my-agent', undefined, {
bypassConcurrencyLimit: true,
});

Cancels a running job gracefully.

await manager.cancelJob(
jobId: string,
options?: { timeout?: number }
): Promise<CancelJobResult>
ParameterTypeRequiredDefaultDescription
jobIdstringYesID of the job to cancel
options.timeoutnumberNo10000Time in ms to wait for graceful shutdown before SIGKILL
interface CancelJobResult {
jobId: string;
success: boolean;
terminationType: 'graceful' | 'forced' | 'already_stopped';
canceledAt: string; // ISO timestamp
}

Cancels a running job by first sending SIGTERM to allow graceful shutdown. If the job doesn’t terminate within the timeout, it will be forcefully killed with SIGKILL.

ErrorCondition
InvalidStateErrorFleet manager not initialized
JobNotFoundErrorJob doesn’t exist
// Cancel with default timeout (10s)
const result = await manager.cancelJob('job-2024-01-15-abc123');
console.log(`Cancelled: ${result.terminationType}`);
// Cancel with custom timeout
const result = await manager.cancelJob('job-2024-01-15-abc123', {
timeout: 30000, // 30 seconds
});

Creates a new job based on an existing job’s configuration.

await manager.forkJob(
jobId: string,
modifications?: JobModifications
): Promise<ForkJobResult>
ParameterTypeRequiredDescription
jobIdstringYesID of the job to fork
modifications.promptstringNoOverride the prompt
modifications.schedulestringNoOverride the schedule name
modifications.workItemsWorkItem[]NoReplace work items
interface ForkJobResult {
jobId: string; // New job ID
forkedFromJobId: string; // Original job ID
agentName: string;
startedAt: string; // ISO timestamp
prompt?: string;
}

Creates a new job based on an existing job’s configuration. The new job will have the same agent and can optionally have modifications applied. If the original job has a session ID, the new job will fork from that session, preserving conversation context.

ErrorCondition
InvalidStateErrorFleet manager not initialized
JobNotFoundErrorOriginal job doesn’t exist
JobForkErrorJob cannot be forked
// Fork with same configuration
const result = await manager.forkJob('job-2024-01-15-abc123');
console.log(`Forked to: ${result.jobId}`);
// Fork with modified prompt
const result = await manager.forkJob('job-2024-01-15-abc123', {
prompt: 'Continue the previous task but focus on testing',
});
// Fork with different schedule
const result = await manager.forkJob('job-2024-01-15-abc123', {
schedule: 'nightly',
});

Streams all fleet logs as an async iterable.

manager.streamLogs(options?: LogStreamOptions): AsyncIterable<LogEntry>
ParameterTypeRequiredDefaultDescription
options.levelLogLevelNo'info'Minimum log level ('debug', 'info', 'warn', 'error')
options.agentNamestringNoFilter to specific agent
options.jobIdstringNoFilter to specific job
options.includeHistorybooleanNotrueReplay history before streaming
options.historyLimitnumberNo1000Max historical entries
interface LogEntry {
timestamp: string; // ISO timestamp
level: 'debug' | 'info' | 'warn' | 'error';
source: 'fleet' | 'agent' | 'job' | 'scheduler';
agentName?: string;
jobId?: string;
scheduleName?: string;
message: string;
data?: Record<string, unknown>;
}
// Stream all info+ logs
for await (const log of manager.streamLogs()) {
console.log(`[${log.level}] ${log.message}`);
}
// Stream only errors for a specific agent
for await (const log of manager.streamLogs({
level: 'error',
agentName: 'my-agent',
})) {
console.error(log.message);
}

Streams output from a specific job.

manager.streamJobOutput(jobId: string): AsyncIterable<LogEntry>

For completed jobs, this will replay the job’s history and then complete. For running jobs, it will continue streaming until the job completes.

ErrorCondition
JobNotFoundErrorJob doesn’t exist
for await (const log of manager.streamJobOutput('job-2024-01-15-abc123')) {
console.log(`[${log.level}] ${log.message}`);
}

Streams logs for a specific agent.

manager.streamAgentLogs(agentName: string): AsyncIterable<LogEntry>
ErrorCondition
AgentNotFoundErrorAgent doesn’t exist
for await (const log of manager.streamAgentLogs('my-agent')) {
console.log(`[${log.jobId}] ${log.message}`);
}

Returns the final output of a completed job as a string.

await manager.getJobFinalOutput(jobId: string): Promise<string>
ParameterTypeRequiredDescription
jobIdstringYesID of the job to get output from

Returns a Promise<string> containing the job’s final output. Throws JobNotFoundError if the job doesn’t exist.

const output = await manager.getJobFinalOutput('job-2024-01-15-abc123');
console.log(output);
// "I checked the prices for office chairs..."

Returns the current fleet manager state (read-only property).

manager.state: FleetManagerState
interface FleetManagerState {
status: FleetManagerStatus;
initializedAt: string | null;
startedAt: string | null;
stoppedAt: string | null;
agentCount: number;
lastError: string | null;
}
type FleetManagerStatus =
| 'uninitialized' // Initial state
| 'initialized' // After initialize()
| 'starting' // During start()
| 'running' // Scheduler active
| 'stopping' // During stop()
| 'stopped' // After stop()
| 'error'; // Error occurred
console.log(`Status: ${manager.state.status}`);
console.log(`Agents: ${manager.state.agentCount}`);
console.log(`Started at: ${manager.state.startedAt}`);

Returns the loaded configuration.

manager.getConfig(): ResolvedConfig | null

Returns null if not initialized.


Returns the loaded agents array.

manager.getAgents(): ResolvedAgent[]

Returns empty array if not initialized.


The FleetManager extends EventEmitter and provides strongly-typed events.

interface FleetManagerEventMap {
// Lifecycle
'initialized': [];
'started': [];
'stopped': [];
'error': [error: Error];
'config:reloaded': [payload: ConfigReloadedPayload];
// Agent events
'agent:started': [payload: AgentStartedPayload];
'agent:stopped': [payload: AgentStoppedPayload];
// Schedule events
'schedule:triggered': [payload: ScheduleTriggeredPayload];
'schedule:skipped': [payload: ScheduleSkippedPayload];
// Job events
'job:created': [payload: JobCreatedPayload];
'job:output': [payload: JobOutputPayload];
'job:completed': [payload: JobCompletedPayload];
'job:failed': [payload: JobFailedPayload];
'job:cancelled': [payload: JobCancelledPayload];
'job:forked': [payload: JobForkedPayload];
}
interface JobCreatedPayload {
job: JobMetadata;
agentName: string;
scheduleName?: string;
timestamp: string;
}
interface JobOutputPayload {
jobId: string;
agentName: string;
output: string;
outputType: 'stdout' | 'stderr' | 'assistant' | 'tool' | 'system';
timestamp: string;
}
interface JobCompletedPayload {
job: JobMetadata;
agentName: string;
exitReason: ExitReason;
durationSeconds: number;
timestamp: string;
}
interface JobFailedPayload {
job: JobMetadata;
agentName: string;
error: Error;
exitReason: ExitReason;
durationSeconds?: number;
timestamp: string;
}
interface JobCancelledPayload {
job: JobMetadata;
agentName: string;
terminationType: 'graceful' | 'forced' | 'already_stopped';
durationSeconds?: number;
timestamp: string;
}
interface JobForkedPayload {
job: JobMetadata;
originalJob: JobMetadata;
agentName: string;
timestamp: string;
}
const manager = new FleetManager({ stateDir: './.herdctl' });
// Lifecycle events
manager.on('initialized', () => {
console.log('Fleet initialized');
});
manager.on('started', () => {
console.log('Fleet started');
});
manager.on('stopped', () => {
console.log('Fleet stopped');
});
manager.on('error', (error) => {
console.error('Fleet error:', error.message);
});
// Job events
manager.on('job:created', (payload) => {
console.log(`Job ${payload.job.id} created for ${payload.agentName}`);
});
manager.on('job:output', (payload) => {
process.stdout.write(payload.output);
});
manager.on('job:completed', (payload) => {
console.log(`Job completed in ${payload.durationSeconds}s`);
});
manager.on('job:failed', (payload) => {
console.error(`Job failed: ${payload.error.message}`);
});
// Schedule events
manager.on('schedule:triggered', (payload) => {
console.log(`${payload.agentName}/${payload.scheduleName} triggered`);
});
manager.on('schedule:skipped', (payload) => {
console.log(`${payload.agentName}/${payload.scheduleName} skipped: ${payload.reason}`);
});
// Config reload
manager.on('config:reloaded', (payload) => {
console.log(`Config reloaded with ${payload.changes.length} changes`);
});

All errors extend FleetManagerError and include error codes for programmatic handling.

FleetManagerError (base)
├── ConfigurationError // Config invalid/not found
├── AgentNotFoundError // Agent not in config
├── JobNotFoundError // Job doesn't exist
├── ScheduleNotFoundError // Schedule not configured
├── InvalidStateError // Operation invalid for state
├── ConcurrencyLimitError // Agent at max capacity
├── JobCancelError // Job cancellation failed
├── JobForkError // Job fork failed
├── FleetManagerConfigError // Legacy config error
├── FleetManagerStateError // Legacy state error
├── FleetManagerStateDirError // State directory init failed
└── FleetManagerShutdownError // Shutdown failed
const FleetManagerErrorCode = {
FLEET_MANAGER_ERROR: 'FLEET_MANAGER_ERROR',
CONFIGURATION_ERROR: 'CONFIGURATION_ERROR',
CONFIG_LOAD_ERROR: 'CONFIG_LOAD_ERROR',
AGENT_NOT_FOUND: 'AGENT_NOT_FOUND',
JOB_NOT_FOUND: 'JOB_NOT_FOUND',
SCHEDULE_NOT_FOUND: 'SCHEDULE_NOT_FOUND',
INVALID_STATE: 'INVALID_STATE',
STATE_DIR_ERROR: 'STATE_DIR_ERROR',
CONCURRENCY_LIMIT: 'CONCURRENCY_LIMIT',
SHUTDOWN_ERROR: 'SHUTDOWN_ERROR',
JOB_CANCEL_ERROR: 'JOB_CANCEL_ERROR',
JOB_FORK_ERROR: 'JOB_FORK_ERROR',
};
import {
isFleetManagerError,
isConfigurationError,
isAgentNotFoundError,
isJobNotFoundError,
isScheduleNotFoundError,
isInvalidStateError,
isConcurrencyLimitError,
isJobCancelError,
isJobForkError,
} from '@herdctl/core';
try {
await manager.trigger('unknown-agent');
} catch (error) {
if (isAgentNotFoundError(error)) {
console.log(`Agent "${error.agentName}" not found`);
console.log(`Available: ${error.availableAgents?.join(', ')}`);
} else if (isConcurrencyLimitError(error)) {
console.log(`At capacity: ${error.currentJobs}/${error.limit}`);
}
}
class AgentNotFoundError extends FleetManagerError {
agentName: string; // The agent that wasn't found
availableAgents?: string[]; // List of valid agents
}

Here’s a complete example showing typical usage patterns:

import { FleetManager, isAgentNotFoundError } from '@herdctl/core';
async function main() {
const manager = new FleetManager({
configPath: './herdctl.yaml',
stateDir: './.herdctl',
checkInterval: 5000,
});
// Set up event handlers
manager.on('initialized', () => console.log('Fleet initialized'));
manager.on('started', () => console.log('Fleet started'));
manager.on('stopped', () => console.log('Fleet stopped'));
manager.on('job:created', (payload) => {
console.log(`Job ${payload.job.id} created for ${payload.agentName}`);
});
manager.on('job:output', (payload) => {
process.stdout.write(payload.output);
});
manager.on('job:completed', (payload) => {
console.log(`Job ${payload.job.id} completed in ${payload.durationSeconds}s`);
});
manager.on('job:failed', (payload) => {
console.error(`Job ${payload.job.id} failed: ${payload.error.message}`);
});
// Initialize and start
await manager.initialize();
await manager.start();
// Get fleet status
const status = await manager.getFleetStatus();
console.log(`Running ${status.counts.totalAgents} agents`);
// List all agents
const agents = await manager.getAgentInfo();
for (const agent of agents) {
console.log(`${agent.name}: ${agent.status}`);
}
// Manually trigger an agent
try {
const result = await manager.trigger('my-agent', 'check-issues', {
prompt: 'Check for urgent issues only',
});
console.log(`Triggered job: ${result.jobId}`);
} catch (error) {
if (isAgentNotFoundError(error)) {
console.error(`Agent not found: ${error.agentName}`);
}
}
// Handle shutdown
process.on('SIGINT', async () => {
console.log('Shutting down...');
await manager.stop({
timeout: 30000,
cancelOnTimeout: true,
});
process.exit(0);
});
}
main().catch(console.error);

The @herdctl/core package is written in TypeScript and provides full type definitions. All types are exported from the main package:

import type {
// Options and configuration
FleetManagerOptions,
FleetManagerLogger,
// State types
FleetManagerState,
FleetManagerStatus,
// Query result types
FleetStatus,
FleetCounts,
AgentInfo,
ScheduleInfo,
// Action types
TriggerOptions,
TriggerResult,
JobModifications,
CancelJobResult,
ForkJobResult,
// Stop options
FleetManagerStopOptions,
// Log streaming types
LogLevel,
LogSource,
LogEntry,
LogStreamOptions,
// Event types
FleetManagerEventMap,
FleetManagerEventName,
ConfigReloadedPayload,
ConfigChange,
JobCreatedPayload,
JobOutputPayload,
JobCompletedPayload,
JobFailedPayload,
JobCancelledPayload,
JobForkedPayload,
ScheduleTriggeredPayload,
ScheduleSkippedPayload,
} from '@herdctl/core';