@kernova/core
@kernova/core
The runtime kernel that powers every Kernova application. Like V8 is to Node.js, @kernova/core is to Kernova — it receives Intents and orchestrates their fulfillment through agents, tools, memory, and workflows.
Installation
npm install @kernova/coreQuick Start
import { KernovaKernel, defineAgent } from '@kernova/core';
const kernel = new KernovaKernel({ environment: 'development', dataDir: './kernova-data', models: { default: { provider: 'openai', model: 'gpt-4o' } },});
await kernel.start();
const result = await kernel.submit({ goal: 'Summarize the latest sales report', intentType: 'query',});
console.log(result.result?.summary);await kernel.stop();KernovaKernel
The central orchestrator. Every other module is accessible through kernel accessor properties.
Constructor
const kernel = new KernovaKernel(config: KernelConfig);KernelConfig
| Option | Type | Default | Description |
|---|---|---|---|
instanceId | string | auto-generated | Unique identifier for this kernel instance |
environment | 'development' | 'staging' | 'production' | — | Required. Runtime environment |
debug | boolean | false | Print kernel and agent log() messages to the console |
models | ModelRoutingConfig | auto-detected | Model routing: default provider + purpose overrides. Auto-detection uses the first available provider and its own default model |
providers | ModelProvider[] | [] | Additional model providers. They replace auto-detected providers with the same ID |
dataDir | string | './kernova-data' | Directory for SQLite persistence |
ephemeral | boolean | false | Keep everything in memory; nothing is written to disk |
builtInTools | BuiltInToolConfig | safe tools only | Built-in tools. shell-exec, code-eval, file-read, file-write, database-query are off unless listed in enabled |
toolPolicy | ToolPolicy | — | Kernel-wide allow/deny lists of tool IDs (globs supported) |
gateway | GatewayConfig | — | Settings for kernel.gateway |
rateLimits | RateLimiterConfig | 100 requests/min per owner | Per-owner rate limits. The internal system owner is only limited by an explicit rule |
eventRetentionDays | number | 30 | Delete persisted events older than this, at start and daily. 0 keeps them forever |
reflection | object | { enabled: false } | Global self-reflection settings. Each reflection adds at least one model call per answer |
threadHistory | boolean | true | Give agents the earlier turns of an intent’s metadata.threadId and record each exchange. Turn off when your app keeps its own history |
planning | Partial<AgentPlannerConfig> | — | kernel.planner settings: maxSteps, strategy, adaptiveReplanning, maxReplanAttempts |
rag | Partial<RAGPipelineConfig> | — | kernel.rag settings: chunkSize, chunkOverlap, topK, scoreThreshold, chunkStrategy |
identity | { sessionTtlSeconds? } | 24 hours | kernel.identity settings |
interface KernelConfig { instanceId?: string; environment: 'development' | 'staging' | 'production'; debug?: boolean; models?: ModelRoutingConfig; providers?: ModelProvider[]; dataDir?: string; ephemeral?: boolean; builtInTools?: BuiltInToolConfig; toolPolicy?: ToolPolicy; // { allow?: string[]; deny?: string[] } gateway?: GatewayConfig; rateLimits?: RateLimiterConfig; eventRetentionDays?: number; // default: 30 (0 = keep forever) shutdownTimeoutMs?: number; // default: 10000 reflection?: { enabled: boolean; // default: false threshold?: number; // default: 0.7 maxAttempts?: number; // default: 2 }; threadHistory?: boolean; // default: true planning?: Partial<AgentPlannerConfig>; rag?: Partial<RAGPipelineConfig>; identity?: { sessionTtlSeconds?: number };}Lifecycle
| Method | Signature | Description |
|---|---|---|
start() | () => Promise<void> | Initialize all modules, open DB connections, begin event processing |
stop() | () => Promise<void> | Graceful shutdown — refuses new intents, waits up to shutdownTimeoutMs for active ones, closes connections |
submit() | (intent) => Promise<Intent> | Submit an intent for agent execution (primary entry point) |
getStatus() | () => KernelStatus | Returns running state, active intents, providers, usage |
submit()
The primary entry point. Accepts a partial intent with at minimum a goal string.
const result = await kernel.submit({ goal: 'Draft an email to the team about the release', intentType: 'action', // 'query' | 'action' | 'observation' priority: 'high', // 'critical' | 'high' | 'medium' | 'low' owner: 'user-123', // scopes memory, budget and rate limits metadata: { tag: 'comms', threadId: 'conversation-42' }, // threadId: include earlier turns});
if (result.result?.success) { console.log(result.result.summary);}ownercan be any string, such as your app’s user ID. It scopes memory recall, budgets and rate limits. Owners registered withkernel.identitymust also have theintent:submitpermission. Without an owner, the intent runs assystem.metadata.threadIdgroups intents into a conversation: the agent sees earlier successful turns of the same thread (older turns are summarized). Without it, each intent is independent.- Retrieved documents from
kernel.ragare added to the agent’s context automatically.
Accessor Properties
| Property | Type | Description |
|---|---|---|
kernel.events | EventBus | Event pub/sub + persistence |
kernel.memoryEngine | MemoryEngine | Five-layer memory system |
kernel.agentRegistry | AgentRegistry | Agent management |
kernel.models | ModelRouter | Model routing & completions |
kernel.plugins | PluginRegistry | Plugin & tool management |
kernel.workflows | WorkflowEngine | Multi-step workflow execution |
kernel.identity | IdentityManager | Auth, users, permissions |
kernel.budget | BudgetManager | Token budgets & cost caps |
kernel.scheduler | Scheduler | Cron & one-shot jobs |
kernel.loops | BackgroundLoopModule | Polling monitors |
kernel.taskQueue | TaskQueue | Priority task queue |
kernel.triggers | ProactiveTriggerEngine | Event-driven rules |
kernel.channels | ConnectorRegistry | Channel adapters |
kernel.planner | AgentPlanner | Plan-and-execute |
kernel.reflection | SelfReflection | Quality evaluation |
kernel.conversation | ConversationManager | Thread management |
kernel.rag | RAGPipeline | Document retrieval |
kernel.mcp | MCPBridge | Model Context Protocol |
kernel.gateway | AgentGateway | HTTP API server |
kernel.metrics | MetricsCollector | Runtime metrics |
kernel.health | HealthMonitor | Health checks |
kernel.sandbox | SandboxManager | Isolated execution |
kernel.builtInTools | BuiltInToolRegistry | Built-in tool access |
EventBus
The nervous system of the runtime. Every state change, action, and decision flows through the EventBus as a structured event. Supports wildcard pattern matching, persistent storage via SQLite, timeline queries, and retention policies.
Key Exports
import { EventBus } from '@kernova/core';import type { EventBusConfig, EventQuery, EventStoreStats } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
publish(event) | (event: KernovaEvent) => void | Emit an event to all matching subscribers + persist |
subscribe(patterns, handler) | (patterns: string[], handler) => string | Subscribe to events; returns subscription ID |
unsubscribe(id) | (id: string) => void | Remove a subscription |
query(params) | (params: EventQuery) => KernovaEvent[] | Rich filtering (type, category, actor, time range) |
getTimeline(subjectId) | (subjectId: string, limit?: number) => KernovaEvent[] | All events for a specific entity |
getCorrelated(correlationId) | (correlationId: string, limit?: number) => KernovaEvent[] | Trace a full request flow |
count(params?) | (params?) => number | Count matching events |
applyRetention(days) | (retentionDays: number) => number | Delete events older than N days |
flush() | () => void | Force pending writes to disk |
Pattern Matching
Wildcards work at each dot-separated segment:
| Pattern | Matches |
|---|---|
"intent.*" | intent.created, intent.completed, intent.failed |
"*.created" | intent.created, agent.created, workflow.created |
"*" | Everything |
"kernel.started" | Exact match only |
Example
// Subscribe to all intent lifecycle eventsconst subId = kernel.events.subscribe(['intent.*'], (event) => { console.log(`[${event.eventType}] ${event.data.intentId}`);});
// Subscribe to everythingkernel.events.subscribe(['*'], (event) => { metrics.track(event.eventType);});
// Query recent errorsconst errors = kernel.events.query({ category: 'intent', severity: 'error', limit: 20, order: 'desc',});
// Get the full timeline of a specific intentconst timeline = kernel.events.getTimeline('intent-abc123');
// Clean up old eventsconst deleted = kernel.events.applyRetention(30); // keep 30 days
// Unsubscribe when donekernel.events.unsubscribe(subId);When to Use
- Reacting to system events in real-time (webhooks, notifications, logging)
- Auditing and compliance (full event history)
- Debugging with correlation tracing
- Building event-driven architectures on top of Kernova
MemoryEngine
A five-layer memory architecture inspired by human cognition. Combines SQLite FTS5 full-text search with vector embeddings for semantic retrieval.
Memory Layers
| Layer | Purpose | TTL |
|---|---|---|
working | Current task scratchpad | Minutes |
session | Current conversation context | Hours (default 3600s) |
longterm | Persistent user/agent knowledge | Months/Years |
organizational | Shared team knowledge | Indefinite |
global | System-wide facts | Indefinite |
Key Exports
import { MemoryEngine } from '@kernova/core';import type { MemoryEngineConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
store(entry) | (entry: MemoryEntry) => string | Store a memory; returns ID |
query(query) | (query: MemoryQuery) => MemoryEntry[] | Search by text, tags, layer, time range |
get(id) | (id: string) => MemoryEntry | null | Retrieve a specific memory by ID |
delete(id) | (id: string) => boolean | Remove a memory |
decay(options?) | (options?) => number | Run decay — expire working/session memories past TTL |
Example
// Store a long-term memoryconst memId = kernel.memoryEngine.store({ content: 'User prefers concise responses under 200 words', layer: 'longterm', tags: ['preference', 'style'], owner: 'user-123',});
// Semantic search across all layersconst results = kernel.memoryEngine.query({ text: 'communication preferences', layer: 'longterm', owner: 'user-123', limit: 5,});
// Store working memory (auto-expires)kernel.memoryEngine.store({ content: 'Currently drafting Q4 report', layer: 'working', tags: ['task-context'],});
// Manual decay pass (usually automatic)const expired = kernel.memoryEngine.decay({ maxAge: 3600 });When to Use
- Giving agents context about past interactions
- Storing user preferences and learned behaviors
- Building organizational knowledge bases
- Providing relevant context without exceeding token budgets
ModelRouter
Routes completion requests to the right model provider based on configurable rules. Supports purpose-based overrides, a fallback provider, streaming, embeddings, model listing, and 26 cataloged providers (see Model Providers).
Key Exports
import { ModelRouter, createProvider, detectAvailableProviders } from '@kernova/core';import { AzureOpenAIProvider, BedrockProvider, VertexAIProvider } from '@kernova/core';import type { ModelRouterConfig, ModelProvider } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
complete(request, purpose?) | (req, purpose?) => Promise<CompletionResponse> | Single completion |
stream(request, purpose?) | (req, purpose?) => AsyncGenerator<StreamChunk> | Streaming tokens |
embed(text) | (text: string) => Promise<number[]> | Generate embedding vector |
embedMany(texts) | (texts: string[]) => Promise<number[][]> | Embed several texts, batched where the provider allows |
listModels(provider?) | (provider?: string) => Promise<ModelInfo[]> | Models a provider offers (all available providers without one) |
getAvailableProviders() | () => string[] | IDs of the available providers |
getUsageStats() | () => { usage: TokenUsage; requestCount: number } | Token counts (including cached and reasoning tokens) and costs |
measureUsage(fn) | (fn) => Promise<{ result, usage }> | Tokens used by the model calls fn makes |
Routing Configuration
const kernel = new KernovaKernel({ environment: 'production', models: { default: { provider: 'anthropic', model: 'claude-sonnet-5-5' }, // Per-purpose models: reasoning, generation, classification, extraction, conversation, vision, code, ... overrides: { code: { provider: 'anthropic', model: 'claude-sonnet-5-5' }, classification: { provider: 'openai', model: 'gpt-4o-mini' }, }, // Tried once when the default provider fails fallback: { provider: 'openai', model: 'gpt-4o' }, },});Providers
Auto-detected from environment variables. The full list, with each provider’s variable and default model, is in Model Providers.
| Class | API | Used for |
|---|---|---|
OpenAIProvider | OpenAI | openai |
AzureOpenAIProvider | Azure OpenAI v1 API (API key or Microsoft Entra ID) | azure |
AnthropicProvider | Anthropic Messages API | anthropic |
GeminiProvider | Gemini API | gemini |
VertexAIProvider | Vertex AI (service account, gcloud ADC, metadata server, or express-mode key) | vertex |
BedrockProvider | Bedrock Converse API (Bedrock API key or SigV4-signed AWS credentials) | bedrock |
OllamaProvider | Ollama | ollama |
OpenAICompatibleProvider | Any /chat/completions API | DeepSeek, Groq, Mistral, xAI, Qwen, Moonshot, Z.ai, Together, OpenRouter, Hugging Face, NVIDIA, Fireworks, and your own |
GoogleAuth, AwsCredentialChain, and signAwsRequest() are exported for your own Google Cloud and AWS calls.
Creating Providers Manually
import { createProvider, OpenAICompatibleProvider } from '@kernova/core';
// From presetsconst deepseek = createProvider('deepseek');const ollama = createProvider('ollama', { defaultModel: 'mistral' });
// Custom OpenAI-compatible endpointconst custom = new OpenAICompatibleProvider({ id: 'my-provider', name: 'My LLM', baseUrl: 'https://api.example.com/v1', apiKey: process.env.MY_API_KEY!, defaultModel: 'my-model',});
// Cloud platformsconst bedrock = new BedrockProvider({ region: 'us-east-1' });const vertex = new VertexAIProvider({ project: 'my-project' });const azure = new AzureOpenAIProvider({ endpoint: 'https://my-resource.openai.azure.com' });Request Options
Beyond messages, model, temperature, maxTokens, stopSequences, and tools, every provider takes:
| Field | Type | Description |
|---|---|---|
responseFormat | ResponseFormat: { type: 'json' } or { type: 'json_schema', schema, name?, strict? } | JSON output; the parsed value comes back in response.parsed |
reasoning | { effort?, budgetTokens?, includeThoughts? } | Reasoning controls; the reasoning comes back in response.reasoning |
cache | boolean | Prompt caching (Claude and Bedrock need it; others cache automatically) |
parts (on a message) | ContentPart[] | Text, images, audio, and files ({ type: 'file', url, filename? }) |
providerData (on a message) | Record<string, unknown> | Copy of response.providerData for the assistant turn, sent back during tool use |
Example
// Direct completionconst response = await kernel.models.complete({ messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain quantum computing briefly.' }, ],});
// Streamingfor await (const chunk of kernel.models.stream({ messages: [{ role: 'user', content: 'Write a poem about code' }],}, 'creative')) { process.stdout.write(chunk.content || '');}
// Embeddings for semantic searchconst vector = await kernel.models.embed('machine learning concepts');const vectors = await kernel.models.embedMany(['first', 'second']);
// Structured output and reasoningconst { parsed } = await kernel.models.complete({ messages: [{ role: 'user', content: 'List three primes as JSON: { "primes": number[] }' }], responseFormat: { type: 'json' }, reasoning: { effort: 'low' },});
// What a provider offersconst models = await kernel.models.listModels('anthropic');AgentRegistry
Manages agent definitions, selection, and execution. Handles the tool-calling loop, inter-agent delegation, and provides the AgentTools interface to agent executors.
Key Exports
import { AgentRegistry } from '@kernova/core';import type { AgentExecutor, AgentTools } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
register(definition, executor) | (def, exec) => void | Register an agent |
unregister(id) | (id: string) => void | Remove an agent |
selectAgent(intent, context) | (intent, ctx) => AgentInstance | null | Find best agent for an intent |
execute(instance, intent, context) | (agent, intent, ctx) => Promise<IntentResult> | Run the agent |
list() | () => AgentDefinition[] | All registered agents |
count() | () => number | Number of registered agents |
AgentTools Interface
Every agent executor receives a tools object with these capabilities:
| Method | Description |
|---|---|
tools.complete(prompt) | Plain LLM completion |
tools.stream(prompt) | Streaming LLM completion |
tools.streamToString(prompt) | Stream and collect full response |
tools.completeWithTools(prompt) | LLM completion with automatic tool-calling loop |
tools.useTool(name, params) | Invoke a specific tool directly |
tools.listTools() | List available tools for this agent |
tools.delegate(agentId, goal) | Delegate a sub-task to another agent |
tools.ask(agentId, question) | Ask another agent a question |
tools.broadcast(goal) | Send a goal to all agents |
tools.remember(content, layer?, tags?) | Store a memory |
tools.recall(query, options?) | Search memories |
tools.emit(eventType, data) | Publish an event |
tools.log(message) | Structured logging |
Example
import { defineAgent } from '@kernova/core';
const assistant = defineAgent({ name: 'research-assistant', description: 'Researches topics and provides summaries', capabilities: [ { id: 'research', name: 'Research', description: 'Web research', confidence: 0.9 }, ], tools: [{ toolId: 'web-search', name: 'web-search', purpose: 'Search the web', required: true }], instructions: 'You are a research assistant. Search the web and provide concise summaries.',});
kernel.agentRegistry.register(assistant.definition, assistant.executor);defineAgent()
The developer-facing API for creating agents. Returns a { definition, executor } pair ready for registration. If no custom execute function is provided, uses a default LLM executor with automatic tool-calling.
Key Exports
import { defineAgent } from '@kernova/core';import type { AgentSpec, DefinedAgent } from '@kernova/core';AgentSpec Interface
interface AgentSpec { name: string; // Agent name description: string; // What the agent does capabilities: Capability[]; // What it can handle tools: ToolReference[]; // Tools it can use instructions: string; // System prompt execute?: (intent, context, tools: AgentTools) => Promise<IntentResult>; // Custom logic reflection?: { enabled: boolean; threshold?: number; // Override global (default 0.7) maxAttempts?: number; // Override global (default 2) }; toolPolicy?: ToolPolicy; // Which tools this agent may call (on top of the kernel's) model?: { provider?: string; model?: string }; // This agent's model (default: kernel routing) temperature?: number; // Sent with this agent's model calls maxTokens?: number; // Sent with this agent's model calls reasoning?: ReasoningOptions; // { effort?, budgetTokens?, includeThoughts? } responseFormat?: ResponseFormat; // JSON, optionally matching a schema promptCache?: boolean; // Prompt caching for this agent's calls}model routes every call the agent makes: give a provider ID (its default model), a model ID (sent to the default provider), or both. The provider must be registered (auto-detected from its API key, or passed in providers).
Default LLM Executor Behavior
When no execute function is provided, the agent:
- Assembles instructions + context memories + intent goal into a prompt
- If tools are available → uses
completeWithTools()(LLM decides which tools to call) - If no tools → uses plain
complete() - Returns the response with confidence scoring
Example — Custom Executor
const codeReviewer = defineAgent({ name: 'code-reviewer', description: 'Reviews code for bugs and style issues', capabilities: [ { id: 'review', name: 'Code Review', description: 'Analyzes code quality', confidence: 0.95 }, ], tools: [{ toolId: 'file-read', name: 'file-read', purpose: 'Read source files', required: true }], instructions: 'You review code for correctness, performance, and style.',
async execute(intent, context, tools) { const startTime = Date.now();
// Read the file to review const file = await tools.useTool('file-read', { path: intent.goal });
// Get LLM analysis const review = await tools.complete( `Review this code:\n\n${file}\n\nProvide specific feedback.` );
// Remember findings for future context await tools.remember(`Reviewed code: ${intent.goal}`, 'session', ['review']);
return { success: true, summary: review, data: review, evidence: { sources: [{ type: 'memory', ref: 'llm-response', label: 'Code review', consultedAt: new Date().toISOString() }], confidence: 0.9, reasoning: 'Automated code review completed', }, durationMs: Date.now() - startTime, }; },});
kernel.agentRegistry.register(codeReviewer.definition, codeReviewer.executor);PluginRegistry
Manages tools, middleware hooks, and plugin lifecycle. Plugins can provide tools (callable functions), middleware (request/response interceptors), or both.
Key Exports
import { PluginRegistry } from '@kernova/core';import type { KernovaPlugin, ToolDefinition, MiddlewareHook } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
register(plugin) | (plugin: KernovaPlugin) => Promise<void> | Register a plugin |
unregister(id) | (id: string) => void | Remove a plugin |
listTools() | () => ToolDefinition[] | All available tools |
executeTool(id, params) | (id, params) => Promise<unknown> | Execute a tool by ID |
list() | () => KernovaPlugin[] | All registered plugins |
Plugin Structure
interface KernovaPlugin { id: string; name: string; version: string; type: 'tool' | 'middleware' | 'integration'; tools?: ToolDefinition[]; middleware?: MiddlewareHook[]; onLoad?: (context: PluginContext) => Promise<void>; onUnload?: () => Promise<void>;}
interface ToolDefinition { id: string; name: string; description: string; parameters: JSONSchema; // JSON Schema for input validation execute: (params: Record<string, unknown>) => Promise<unknown>;}Example
await kernel.plugins.register({ id: 'my-tools', name: 'My Custom Tools', version: '1.0.0', type: 'tool', tools: [ { id: 'calculate', name: 'Calculator', description: 'Perform math calculations', parameters: { type: 'object', properties: { expression: { type: 'string', description: 'Math expression to evaluate' }, }, required: ['expression'], }, execute: async (params) => { const result = Function(`"use strict"; return (${params.expression})`)(); return { result }; }, }, ],});WorkflowEngine
Executes multi-step workflows with support for parallel steps, conditional branching, approval gates, and compensation (rollback on failure).
Key Exports
import { WorkflowEngine } from '@kernova/core';import type { WorkflowEngineConfig, ApprovalHandler } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
define(definition) | (def: WorkflowDefinition) => void | Register a workflow |
execute(definitionId, input?) | (id: string, input?: object) => Promise<WorkflowInstance> | Run a workflow and wait for it to finish |
getInstance(instanceId) | (id: string) => WorkflowInstance | undefined | A run’s status and step results |
listDefinitions() | () => WorkflowDefinition[] | All registered workflows |
listRunning() | () => WorkflowInstance[] | Runs in progress |
onApproval(handler) | (handler: ApprovalHandler) => void | Decide approval steps in code |
resolveApproval(workflowId, stepId, approved, reason?) | (...) => void | Approve or reject a waiting step |
getPendingApprovals() | () => Array<{ workflowId, stepId, stepName }> | Steps waiting for approval |
Example
Each step names its type and a config. Agent steps send config.input.goal (or the step name) to the agent named in config.agentId; steps don’t pass their output to the next step.
import { generateId, now } from '@kernova/core';
kernel.workflows.define({ id: 'content-pipeline', type: 'workflow_definition', version: '1.0.0', owner: 'system', status: 'active', createdAt: now(), updatedAt: now(), metadata: {}, name: 'Content Pipeline', description: 'Research, then approve, then publish', steps: [ { id: 'research', name: 'Research the topic', type: 'agent', config: { agentId: 'research-assistant', input: { goal: 'Research AI in healthcare' } }, onFailure: 'stop', }, { id: 'review', name: 'Editorial review', type: 'approval', config: { approvers: ['editor'] }, onFailure: 'stop', }, { id: 'publish', name: 'Publish to CMS', type: 'tool', config: { toolId: 'cms:publish' }, onFailure: 'compensate', compensation: { toolId: 'cms:unpublish' }, }, ],});
const instance = await kernel.workflows.execute('content-pipeline', { topic: 'AI in Healthcare' });console.log(instance.workflowStatus, instance.stepResults);With @kernova/sdk, the workflow(name, steps) helper fills in the boilerplate fields.
When to Use
- Multi-step processes that require coordination between agents
- Processes that need human approval at certain stages
- Operations that need rollback/compensation on failure
- Parallel task execution with dependency management
Scheduler
Runs jobs on cron schedules or after a one-shot delay. Persists schedules to survive restarts and detects missed executions.
Key Exports
import { Scheduler } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
register(input) | (input: ScheduledJobInput) => string | Register a job; returns ID |
remove(id) | (id: string) => void | Remove a scheduled job |
list() | () => ScheduledJob[] | All registered jobs |
get(id) | (id: string) => ScheduledJob | undefined | Get a specific job |
ScheduledJobInput
interface ScheduledJobInput { name: string; cronExpression?: string; // e.g. '0 9 * * *' (daily at 9am) delayMs?: number; // one-shot delay in milliseconds oneShot?: boolean; // auto-disable after first fire target: { type: 'agent' | 'intent' | 'event'; id?: string; goal?: string; };}Example
// Daily standup summary at 9amkernel.scheduler.register({ name: 'daily-standup', cronExpression: '0 9 * * 1-5', // Mon-Fri at 9:00 target: { type: 'agent', id: 'standup-agent', goal: 'Generate daily standup summary from yesterday\'s activity', },});
// One-shot reminder in 2 hourskernel.scheduler.register({ name: 'follow-up-reminder', delayMs: 2 * 60 * 60 * 1000, oneShot: true, target: { type: 'intent', goal: 'Remind user to follow up on the proposal', },});
// List all jobsconst jobs = kernel.scheduler.list();console.log(`${jobs.length} scheduled jobs`);When to Use
- Recurring agent tasks (daily reports, weekly cleanups)
- Delayed actions (reminders, follow-ups)
- Periodic data synchronization
- Any time-based automation
TaskQueue
A priority queue with concurrency control, exponential backoff retries, and dead-letter handling for failed tasks.
Key Exports
import { TaskQueue } from '@kernova/core';import type { TaskQueueConfig, TaskHandler } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
registerHandler(name, handler) | (name, handler: TaskHandler) => void | Register a task handler |
enqueue(input) | (input: TaskInput) => string | Add a task; returns task ID |
stats() | () => QueueStats | Queue statistics |
deadLetters(filter?) | (filter?) => DeadLetter[] | Get failed tasks |
replay(id) | (id: string) => void | Retry a dead-lettered task |
Priority Levels
Tasks are processed in priority order:
| Priority | Value | Use Case |
|---|---|---|
critical | 0 | System health, security alerts |
high | 1 | User-facing requests |
medium | 2 | Background processing (default) |
low | 3 | Maintenance, analytics |
Configuration
interface TaskQueueConfig { concurrency?: number; // 1-50, default: 5 maxRetries?: number; // default: 3 backoffMs?: number; // initial backoff, default: 1000 maxBackoffMs?: number; // cap, default: 30000 deadLetterLimit?: number; // max dead letters kept}Example
// Register a handlerkernel.taskQueue.registerHandler('send-email', async (task) => { const { to, subject, body } = task.payload; await emailService.send(to, subject, body); return { sent: true };});
// Enqueue tasks with prioritykernel.taskQueue.enqueue({ handler: 'send-email', payload: { to: 'team@company.com', subject: 'Alert', body: '...' }, priority: 'high',});
kernel.taskQueue.enqueue({ handler: 'send-email', payload: { to: 'analytics@company.com', subject: 'Weekly digest', body: '...' }, priority: 'low',});
// Check statsconst stats = kernel.taskQueue.stats();console.log(`Pending: ${stats.pending}, Active: ${stats.active}, Failed: ${stats.failed}`);
// Replay a failed taskconst deadLetters = kernel.taskQueue.deadLetters();if (deadLetters.length > 0) { kernel.taskQueue.replay(deadLetters[0].id);}When to Use
- Background job processing with guaranteed delivery
- Rate-limiting expensive operations (API calls, file processing)
- Prioritizing work when resources are limited
- Reliable task execution with retry semantics
ProactiveTriggerEngine
Event-driven rules that fire actions when specific events occur. Supports cooldown periods and conditional execution.
Key Exports
import { ProactiveTriggerEngine } from '@kernova/core';import type { TriggerEngineConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
register(input) | (input: TriggerRuleInput) => string | Register a trigger rule |
remove(id) | (id: string) => void | Remove a trigger |
enable(id) | (id: string) => void | Enable a disabled trigger |
disable(id) | (id: string) => void | Temporarily disable |
list() | () => TriggerRule[] | All registered triggers |
TriggerRuleInput
interface TriggerRuleInput { name: string; eventPattern: string; // Wildcard pattern: "intent.failed", "*.created" action: { goal: string; // What to execute when triggered priority?: string; }; cooldownMs?: number; // Minimum time between firings (min: 100ms) condition?: (event) => boolean; // Programmatic condition conditionDescription?: string; // Human-readable description}Example
// Auto-retry failed intentskernel.triggers.register({ name: 'auto-retry-failures', eventPattern: 'intent.failed', action: { goal: 'Analyze why intent {{event.data.intentId}} failed and suggest fixes', priority: 'medium', }, cooldownMs: 5000, // Don't fire more than once per 5 seconds});
// Welcome new userskernel.triggers.register({ name: 'welcome-new-user', eventPattern: 'identity.created', action: { goal: 'Send a welcome message to the new user', }, cooldownMs: 1000, conditionDescription: 'Only for human users, not service accounts',});
// Disable a trigger temporarilykernel.triggers.disable('trigger-abc123');When to Use
- Automated responses to system events
- Self-healing behaviors (retry on failure)
- Notification triggers
- Proactive agent behaviors based on system state changes
BackgroundLoopModule
Polling monitors that run at configurable intervals. Support pause/resume for graceful resource management.
Key Exports
import { BackgroundLoopModule } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
register(loop) | (loop: LoopDefinition) => string | Register a background loop |
remove(id) | (id: string) => void | Remove a loop |
pause(id) | (id: string) => void | Pause a running loop |
resume(id) | (id: string) => void | Resume a paused loop |
list() | () => LoopInfo[] | All registered loops |
Example
// Monitor system health every 30 secondskernel.loops.register({ name: 'health-check', intervalMs: 30000, handler: async () => { const status = kernel.getStatus(); if (status.activeIntents > 100) { kernel.events.publish({ eventType: 'system.overloaded', // ... }); } },});
// Check for new emails every 5 minuteskernel.loops.register({ name: 'email-poll', intervalMs: 5 * 60 * 1000, handler: async () => { const newEmails = await emailClient.checkInbox(); for (const email of newEmails) { await kernel.submit({ goal: `Process email: ${email.subject}` }); } },});When to Use
- Polling external services for changes
- Periodic health checks and monitoring
- Resource cleanup loops
- Any recurring background task that doesn’t fit a cron schedule
ConnectorRegistry
kernel.channels manages connections to messaging platforms. You register a connector with its platform config; the registry creates the adapter, connects it (reconnecting with backoff when a connection drops), and emits channel.* events. See the Channels guide for each platform’s config.
Supported Channels
| Channel | channelType | Adapter class |
|---|---|---|
| Slack | slack | SlackAdapter |
| Discord | discord | DiscordAdapter |
whatsapp | WhatsAppAdapter | |
| Telegram | telegram | TelegramAdapter |
email | EmailAdapter | |
| Microsoft Teams | teams | TeamsAdapter |
| SMS (Twilio) | sms | SmsAdapter |
| Signal | signal | SignalAdapter |
| Matrix | matrix | MatrixAdapter |
| IRC | irc | IrcAdapter |
| Voice (Twilio) | voice | VoiceAdapter |
| Push (FCM/APNs) | push | PushAdapter |
| RSS/Atom | rss | RssAdapter |
WebhookChannelAdapter and WebSocketChannelAdapter aren’t managed by the registry: use them directly (await adapter.connect()) or through the SDK’s app.channel().
Key Exports
import { ConnectorRegistry, SlackAdapter, WebhookChannelAdapter, WebSocketChannelAdapter } from '@kernova/core';import type { ConnectorRegistryConfig, ChannelAdapter } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
register(input) | ({ channelType, name, config }) => ConnectorDef | Add a connector; its config is validated |
connect(connectorId) | (id: string) => Promise<void> | Start the adapter |
disconnect(connectorId) | (id: string) => Promise<void> | Stop the adapter |
send(request) | ({ connectorId, recipient?, message }) => Promise<OutboundMessageResult> | Send a message through a connector, to recipient (an inbound message’s replyTo) |
onMessage(handler) | (handler: (msg: InboundMessage) => Promise<void> | void) => () => void | Handle inbound messages from every connector; returns an unsubscribe function |
reply(message, content) | (msg: InboundMessage, content: string | OutboundMessage) => Promise<OutboundMessageResult> | Answer a message on its connector, to its replyTo |
status() | () => ConnectorStatus[] | Connection state of every connector |
Example
const slack = kernel.channels.register({ channelType: 'slack', name: 'support-slack', config: { type: 'slack', botToken: process.env.SLACK_BOT_TOKEN!, signingSecret: process.env.SLACK_SIGNING_SECRET!, },});await kernel.channels.connect(slack.id);
// Answer every message in the conversation it came fromkernel.channels.onMessage(async (msg) => { const intent = await kernel.submit({ goal: msg.content, owner: msg.sender, metadata: { threadId: `${msg.connectorId}:${msg.replyTo}` } }); await kernel.channels.reply(msg, intent.result?.summary ?? '');});
// Or send proactivelyawait kernel.channels.send({ connectorId: slack.id, recipient: 'C024BE91L', // a Slack channel ID message: { content: 'Deploy finished' },});
console.log(kernel.channels.status()); // [{ name: 'support-slack', state: 'connected', ... }]When to Use
- Building multi-channel AI assistants
- Receiving messages from Slack, Discord, or other platforms
- Real-time communication via WebSocket
- Webhook integrations with third-party services
DaemonRunner
Persistent execution mode for Kernova. Wraps the kernel with signal handling (SIGINT/SIGTERM), periodic heartbeat emission, graceful shutdown, config file loading, and hot-reload.
Key Exports
import { DaemonRunner } from '@kernova/core';import type { DaemonConfig } from '@kernova/core';DaemonConfig
| Option | Type | Default | Description |
|---|---|---|---|
configPath | string | — | Path to agent config file or directory |
watch | boolean | false | Enable hot-reload of config files |
port | number | — | Port for webhook/gateway listeners |
dataDir | string | — | Data directory override |
shutdownTimeoutMs | number | 30000 | Max wait for active intents on shutdown |
heartbeatIntervalMs | number | 60000 | Heartbeat event interval |
Methods
| Method | Signature | Description |
|---|---|---|
start() | () => Promise<void> | Start daemon (resolves when stopped) |
stop() | () => Promise<void> | Graceful shutdown |
isRunning() | () => boolean | Check if running |
getLoadedConfigs() | () => Map<string, AgentConfigFile> | Get loaded agent configs |
Example
import { KernovaKernel, DaemonRunner } from '@kernova/core';
const kernel = new KernovaKernel({ environment: 'production', dataDir: '/var/lib/kernova',});
await kernel.start();
const daemon = new DaemonRunner(kernel, { configPath: './agents/', watch: true, shutdownTimeoutMs: 15000, heartbeatIntervalMs: 30000,});
// This blocks until SIGINT/SIGTERM is receivedawait daemon.start();// Graceful shutdown has completed hereWhen to Use
- Running Kernova as a long-lived background service
- Production deployments that need signal handling
- Loading agents from YAML/JSON config files with hot-reload
- Server processes that need heartbeat monitoring
AgentPlanner
Implements the Plan-and-Execute pattern: decompose a complex goal into steps, execute them sequentially, and adaptively replan on failure.
Key Exports
import { AgentPlanner } from '@kernova/core';import type { AgentPlannerConfig, StepExecutor } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
plan(goal, context?) | (goal, ctx?) => Promise<Plan> | Generate a multi-step plan |
execute(plan, executor) | (plan, exec) => Promise<PlanResult> | Execute all steps |
cancel(planId) | (planId: string) => void | Cancel a running plan |
Configuration
maxSteps: Maximum steps per plan (default: 10)- Adaptive replanning: If a step fails, the planner can revise remaining steps
Example
// Plan a complex taskconst plan = await kernel.planner.plan( 'Migrate the users database from PostgreSQL to MongoDB', { constraints: ['zero downtime', 'data validation required'] });
console.log(`Plan has ${plan.steps.length} steps`);plan.steps.forEach((step, i) => { console.log(` ${i + 1}. ${step.description}`);});
// Execute with a custom step executorconst result = await kernel.planner.execute(plan, async (step) => { return kernel.submit({ goal: step.description, priority: 'high' });});
if (result.success) { console.log('Migration completed successfully');}When to Use
- Complex multi-step tasks that need decomposition
- Tasks where later steps depend on earlier results
- Scenarios requiring adaptive replanning on failure
- When you want the LLM to reason about approach before acting
SelfReflection
Quality evaluation and regeneration loop. After an agent produces output, SelfReflection scores it against the original goal and optionally regenerates if below the confidence threshold.
Key Exports
import { SelfReflection, clampConfidence, resolveReflectionConfig } from '@kernova/core';import type { SelfReflectionConfig, ReflectionToggleConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
reflect(output, goal, context?, agentId?) | (...) => Promise<ReflectionResult> | Evaluate + optionally regenerate |
evaluate(output, goal, context?) | (...) => Promise<EvaluationResult> | Score without regeneration |
Configuration
| Option | Default | Description |
|---|---|---|
enabled | true | Enable/disable globally |
threshold | 0.7 | Minimum confidence to accept output |
maxAttempts | 2 | Max regeneration attempts |
Utility Functions
clampConfidence(score)— Clamp a confidence score to [0, 1]resolveReflectionConfig(global, agent?)— Merge global + per-agent reflection settings
Example
// Evaluate an agent's outputconst evaluation = await kernel.reflection.evaluate( agentOutput, 'Write a professional email to decline the meeting', { tone: 'polite but firm' });
console.log(`Confidence: ${evaluation.confidence}`);console.log(`Feedback: ${evaluation.feedback}`);
// Full reflect loop (evaluate + regenerate if needed)const result = await kernel.reflection.reflect( agentOutput, 'Write a professional email to decline the meeting', { tone: 'polite but firm' }, 'email-agent');
if (result.regenerated) { console.log('Output was regenerated for higher quality'); console.log(result.finalOutput);}When to Use
- Ensuring output quality for user-facing responses
- Building self-improving agents that learn from feedback
- Quality gates before publishing content
- Confidence scoring for decision-making pipelines
ConversationManager
Manages named conversation threads with sliding window context, automatic summarization when the window is exceeded, and thread archival.
Key Exports
import { ConversationManager } from '@kernova/core';import type { ConversationManagerConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
create(threadId) | (id: string) => Thread | Create a new thread |
retrieve(threadId) | (id: string) => Thread | null | Get an existing thread |
archive(threadId) | (id: string) => void | Archive a thread |
addMessageToThread(threadId, role, content) | (...) => void | Add a message |
getThreadContext(threadId) | (id) => Message[] | Get windowed messages |
addMessage(role, content) | (role, content) => Promise<void> | Add to default thread |
Configuration
| Option | Default | Description |
|---|---|---|
windowSize | 50 | Maximum messages in the sliding window |
autoSummarize | true | Summarize older messages when window is exceeded |
Example
// Create a named conversation threadkernel.conversation.create('support-ticket-456');
// Add messageskernel.conversation.addMessageToThread('support-ticket-456', 'user', 'My deployment is failing with exit code 137');kernel.conversation.addMessageToThread('support-ticket-456', 'assistant', 'Exit code 137 indicates an OOM kill. Let me check your memory limits...');
// Get windowed context (respects sliding window + summarization)const context = kernel.conversation.getThreadContext('support-ticket-456');
// Archive when donekernel.conversation.archive('support-ticket-456');When to Use
- Multi-turn conversations with context management
- Keeping conversation history within token budgets
- Support ticket / thread-based interactions
- Any long-running conversation that needs summarization
RAGPipeline
Retrieval-Augmented Generation pipeline. Ingest documents, chunk them with configurable strategies, and retrieve relevant context for agent prompts.
Key Exports
import { RAGPipeline } from '@kernova/core';import type { RAGPipelineConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
ingest(content, source, metadata?) | (...) => Promise<string> | Ingest a document; returns doc ID |
retrieve(query, options?) | (query, opts?) => Promise<Chunk[]> | Retrieve relevant chunks |
getContext(query, options?) | (query, opts?) => Promise<string> | Get pre-formatted context string |
remove(docId) | (id: string) => Promise<void> | Remove an ingested document |
stats() | () => RAGStats | Document/chunk counts |
Chunking Strategies
| Strategy | Description |
|---|---|
fixed | Fixed character-length chunks |
recursive | Recursive splitting on separators (paragraphs → sentences → words) |
sentence | Split on sentence boundaries |
paragraph | Split on paragraph boundaries |
Example
// Ingest documentationawait kernel.rag.ingest( fs.readFileSync('./docs/architecture.md', 'utf-8'), 'architecture.md', { category: 'docs', version: '2.0' });
await kernel.rag.ingest( fs.readFileSync('./docs/api-reference.md', 'utf-8'), 'api-reference.md', { category: 'docs', version: '2.0' });
// Retrieve relevant context for a queryconst chunks = await kernel.rag.retrieve('How does authentication work?', { topK: 5, threshold: 0.7,});
chunks.forEach(chunk => { console.log(`[${chunk.source}] Score: ${chunk.score}`); console.log(chunk.content);});
// Or get a pre-formatted context stringconst context = await kernel.rag.getContext('authentication flow', { topK: 3 });
// Check statsconst stats = kernel.rag.stats();console.log(`${stats.documents} documents, ${stats.chunks} chunks indexed`);When to Use
- Providing agents with relevant documentation context
- Building knowledge bases from existing documents
- Grounding agent responses in source material
- Reducing hallucination by supplying factual context
Built-in Tools
Kernova ships with a set of built-in tools that are automatically registered when the kernel starts. Each tool is sandboxed and configurable.
Key Exports
import { BuiltInToolRegistry, SandboxViolationError } from '@kernova/core';import type { BuiltInToolConfig } from '@kernova/core';Available Tools
| Tool ID | Description |
|---|---|
http-fetch | Make HTTP requests (GET, POST, PUT, DELETE, PATCH) with configurable timeout |
file-read | Read file contents (sandboxed to sandboxDir) |
file-write | Write file contents (sandboxed to sandboxDir) |
shell-exec | Execute shell commands (with timeout, sandboxed) |
date-time | Get current date/time in various formats and timezones |
web-search | Search the web (requires a WebSearchProvider implementation) |
Configuration
interface BuiltInToolConfig { enabled?: string[]; // Whitelist specific tools disabled?: string[]; // Blacklist specific tools sandboxDir?: string; // Root directory for file operations shellTimeout?: number; // Shell command timeout in ms}Sandbox Enforcement
File operations (file-read, file-write) are restricted to the configured sandboxDir. Path traversal attempts (e.g., ../../etc/passwd) throw a SandboxViolationError.
Example
const kernel = new KernovaKernel({ environment: 'development', builtInTools: { enabled: ['http-fetch', 'file-read', 'date-time'], // Only these tools sandboxDir: './workspace', shellTimeout: 10000, },});
// Tools are automatically available to agents// In a custom agent executor:async execute(intent, context, tools) { // Fetch external data const response = await tools.useTool('http-fetch', { url: 'https://api.example.com/data', method: 'GET', timeout: 5000, });
// Read a local file const content = await tools.useTool('file-read', { path: 'notes.md', });
// Get current time const now = await tools.useTool('date-time', { timezone: 'America/New_York', format: 'iso', });}http-fetch Details
// Parameters{ url: string; // Required — the URL to fetch method?: string; // GET, POST, PUT, DELETE, PATCH (default: GET) headers?: object; // HTTP headers body?: string; // Request body (for POST/PUT/PATCH) timeout?: number; // Timeout in ms (default: 30000)}
// Returns{ status: number; statusText: string; headers: Record<string, string>; body: string;}IdentityManager
Manages users, agents, services, API keys, sessions, permissions, and organizations.
Key Exports
import { IdentityManager, ApiKeyManager, PermissionEngine, SessionManager } from '@kernova/core';import type { RegisteredIdentity, Organization, ActorType, ApiKey, CreateKeyOptions, PermissionCheck, PermissionResult, Role, Session, CreateSessionOptions,} from '@kernova/core';Sub-modules
| Sub-module | Accessor | Description |
|---|---|---|
IdentityManager | kernel.identity | Core identity CRUD |
ApiKeyManager | via identity | API key creation, validation, revocation |
PermissionEngine | via identity | Role-based permission checks |
SessionManager | via identity | Session creation, validation, expiry |
Key Methods
| Method | Description |
|---|---|
registerIdentity(options) | Register a user, agent, or service identity ({ type, name, email?, roles? }; the ID is generated) |
getIdentity(id) | Get identity by ID |
checkPermission(check) | Check if an identity has a permission |
createApiKey(options) | Create an API key for an identity |
authenticateWithKey(key) | Resolve an API key to its identity and permissions (null if invalid) |
createSession(options) | Create a session for an identity |
authenticateWithSession(token) | Resolve a session token to its identity (null if invalid or expired) |
Actor Types
user— Human usersagent— AI agentsservice— Service accounts / integrations
Example
// Register a user (the ID is generated)const alice = kernel.identity.registerIdentity({ type: 'user', name: 'Alice', email: 'alice@company.com', roles: ['admin'],});
// Check permissions before executingconst check = kernel.identity.checkPermission({ identityId: alice.id, resource: 'intent', action: 'submit',});
if (!check.granted) { throw new Error(`Permission denied: ${check.reason}`);}
// The kernel automatically enforces permissions in submit()When to Use
- Multi-user Kernova deployments
- API key-based authentication for external access
- Role-based access control (admin, user, viewer)
- Organization-level isolation
BudgetManager
Token budgets, cost caps, and rate limiting per identity. Prevents runaway costs by blocking requests that exceed configured limits.
Key Exports
import { BudgetManager } from '@kernova/core';import type { BudgetConfig, IdentityBudget, BudgetCheckResult } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
setGlobalBudget(config) | (config: BudgetConfig) => void | Set system-wide budget |
setIdentityBudget(id, budget) | (id, budget) => void | Set per-identity budget |
check(id, tokens?) | (id, tokens?) => BudgetCheckResult | Check if request is allowed |
record(id, tokens) | (id, tokens: number) => void | Record token usage |
BudgetConfig
interface BudgetConfig { maxTokens?: number; // Total token budget maxCostUsd?: number; // Cost cap in USD maxTokensPerIntent?: number; // Per-request token limit requestsPerMinute?: number; // Rate limit}Example
// Set a global daily budgetkernel.budget.setGlobalBudget({ maxTokens: 1_000_000, maxCostUsd: 50.00, requestsPerMinute: 60,});
// Set a per-user budgetkernel.budget.setIdentityBudget('user-123', { maxTokens: 100_000, maxTokensPerIntent: 4096, requestsPerMinute: 10,});
// Check before expensive operationsconst check = kernel.budget.check('user-123', 2000);if (!check.allowed) { console.log(`Budget exceeded: ${check.reason}`); // The kernel does this automatically in submit()}
// Record actual usage (also automatic after submit)kernel.budget.record('user-123', 1523);When to Use
- Controlling costs in production
- Per-user or per-team token allocation
- Preventing abuse in multi-tenant setups
- Rate limiting expensive model calls
AgentGateway
An HTTP API server that exposes kernel capabilities over REST. Includes an OpenAI-compatible /v1/chat/completions endpoint for drop-in replacement.
Key Exports
import { AgentGateway } from '@kernova/core';import type { GatewayConfig, GatewayAuthConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
start(config?) | (config?: GatewayConfig) => Promise<void> | Start the HTTP server. config overrides the settings from the constructor or KernelConfig.gateway. Throws if no token is configured and auth.allowAnonymous isn’t set |
stop() | () => Promise<void> | Stop the server |
Configuration
| Option | Default | Description |
|---|---|---|
port | 3000 | Port to listen on |
host | '127.0.0.1' | Interface to bind |
auth.tokens | [KERNOVA_API_KEY] if set | Bearer tokens that grant access |
auth.allowAnonymous | false | Skip authentication (local development only) |
cors | false | false, true (any origin), or a list of allowed origins |
maxBodyBytes | 1_048_576 | Request body size limit |
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /health | Health check |
POST | /v1/intents | Submit an intent |
POST | /v1/chat/completions | OpenAI-compatible chat endpoint |
POST | /hooks/:path | Webhook receiver |
Authentication
All endpoints require a Bearer token in the Authorization header, checked against auth.tokens (or KERNOVA_API_KEY). Webhook routes registered with a secret are authenticated by their HMAC signature instead.
Example
// Start the gateway with a tokenawait kernel.gateway.start({ auth: { tokens: [process.env.GATEWAY_TOKEN!] } });
// From external clients:// curl -X POST http://localhost:3000/v1/intents \// -H "Authorization: Bearer sk-xxx" \// -H "Content-Type: application/json" \// -d '{"goal": "Summarize today'\''s news", "priority": "medium"}'
// OpenAI-compatible endpoint (works with any OpenAI SDK):// curl -X POST http://localhost:3000/v1/chat/completions \// -H "Authorization: Bearer sk-xxx" \// -H "Content-Type: application/json" \// -d '{"model": "kernova", "messages": [{"role": "user", "content": "Hello"}]}'When to Use
- Exposing Kernova as an API service
- Drop-in replacement for OpenAI API
- Receiving webhooks from external services
- Building UIs that talk to Kernova over HTTP
MCPBridge
Model Context Protocol integration. Connect to external MCP servers (via stdio or SSE transport) and expose their tools to Kernova agents.
Key Exports
import { MCPBridge } from '@kernova/core';import type { MCPBridgeConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
register(config) | (config: MCPServerConfig) => void | Register an MCP server definition |
connect(serverId) | (id: string) => Promise<void> | Connect to a registered server |
callTool(serverId, toolName, args) | (...) => Promise<unknown> | Call a tool on an MCP server |
getAllTools() | () => MCPTool[] | List all tools from all connected servers |
disconnect(serverId) | (id: string) => Promise<void> | Disconnect from a server |
dispose() | () => Promise<void> | Disconnect all and clean up |
Supported Transports
| Transport | Description |
|---|---|
stdio | Spawn a child process and communicate over stdin/stdout |
sse | Connect to a server-sent events endpoint over HTTP |
Example
// Register an MCP serverkernel.mcp.register({ id: 'filesystem', name: 'Filesystem MCP', transport: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/workspace'],});
// Connectawait kernel.mcp.connect('filesystem');
// List available toolsconst tools = kernel.mcp.getAllTools();tools.forEach(t => console.log(`${t.name}: ${t.description}`));
// Call a tool directlyconst result = await kernel.mcp.callTool('filesystem', 'read_file', { path: '/path/to/file.txt',});
// MCP tools are also automatically available to agents via the tool-calling loop
// Clean upawait kernel.mcp.disconnect('filesystem');When to Use
- Integrating with the MCP ecosystem (filesystem, databases, APIs)
- Extending Kernova with tools from third-party MCP servers
- Building bridges between Kernova and other AI tools
- Using existing MCP server implementations without rewriting
MetricsCollector
Collects runtime metrics including token usage, request counts, latencies, and custom metrics. Provides periodic snapshots.
Key Exports
import { MetricsCollector } from '@kernova/core';import type { MetricsSnapshot, MetricEntry, MetricsConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
start() | () => void | Begin collecting metrics |
stop() | () => void | Stop collection |
record(name, value, tags?) | (...) => void | Record a custom metric |
snapshot() | () => MetricsSnapshot | Get current metrics snapshot |
reset() | () => void | Reset all counters |
Example
// Metrics auto-start with the kernel (if debug: true)kernel.metrics.start();
// Record custom metricskernel.metrics.record('custom.operation.duration', 1523, { operation: 'sync' });
// Get a snapshotconst snapshot = kernel.metrics.snapshot();console.log(`Total requests: ${snapshot.totalRequests}`);console.log(`Total tokens: ${snapshot.totalTokens}`);console.log(`Avg latency: ${snapshot.avgLatencyMs}ms`);When to Use
- Monitoring production deployments
- Tracking token usage over time
- Custom business metrics
- Integration with observability platforms (Datadog, Prometheus)
HealthMonitor
Health check system with configurable checks and polling. Reports overall system health as healthy, degraded, or unhealthy.
Key Exports
import { HealthMonitor } from '@kernova/core';import type { HealthStatus, HealthCheck, HealthMonitorConfig } from '@kernova/core';Methods
| Method | Signature | Description |
|---|---|---|
addCheck(check) | (check: HealthCheck) => void | Register a health check |
removeCheck(id) | (id: string) => void | Remove a check |
check() | () => HealthStatus | Run all checks and return status |
startPolling(intervalMs) | (ms: number) => void | Begin periodic checks |
stopPolling() | () => void | Stop periodic checks |
Built-in Checks
The kernel automatically registers:
- Kernel Running — Is the kernel started?
- Model Providers — Are model providers available?
Example
// Add a custom health checkkernel.health.addCheck({ id: 'database', name: 'Database Connection', check: async () => { try { await db.ping(); return { state: 'healthy', message: 'Connected' }; } catch (e) { return { state: 'unhealthy', message: e.message }; } },});
// Run all checksconst status = kernel.health.check();console.log(`Overall: ${status.state}`); // 'healthy' | 'degraded' | 'unhealthy'status.checks.forEach(c => { console.log(` ${c.name}: ${c.state}`);});
// Poll every 30 seconds (emits events on state changes)kernel.health.startPolling(30000);When to Use
- Load balancer health endpoints
- Monitoring system dependencies
- Alerting on degraded state
- Kubernetes liveness/readiness probes
SandboxManager
Policy checks for agent runs: which paths, tools, network, and writes are allowed. It decides; it does not isolate processes.
Key Exports
import { SandboxManager } from '@kernova/core';import type { SandboxConfig, SandboxPolicy } from '@kernova/core';Methods
Policies are checked per context: create one for an agent’s run, then ask it before acting. The built-in file and shell tools enforce their own sandbox (builtInTools.sandboxDir); this manager is for your own tools and checks.
| Method | Signature | Description |
|---|---|---|
createContext(agentId, policy?) | (id: string, policy?: Partial<SandboxPolicy>) => SandboxContext | Start a sandbox context with a policy |
isPathAllowed(contextId, path) | (id: string, path: string) => boolean | Whether a path is inside the workspace and not denied |
isToolAllowed(contextId, tool) | (id: string, tool: string) => boolean | Check the policy’s allowed/denied tools |
isWriteAllowed(contextId) / isNetworkAllowed(contextId) | (id: string) => boolean | Check the policy’s write and network flags |
getTimeout(contextId) | (id: string) => number | The policy’s timeout in ms |
destroy(contextId) | (id: string) => void | End a context |
SandboxPolicy: allowedPaths, deniedPaths, allowedTools, deniedTools, timeoutMs, allowNetwork, allowWrite.
Example
const sandbox = kernel.sandbox.createContext('report-writer', { deniedTools: ['shell-exec'], allowNetwork: false,});
kernel.sandbox.isPathAllowed(sandbox.id, 'reports/q3.md'); // truekernel.sandbox.isPathAllowed(sandbox.id, '../../etc/passwd'); // false (emits sandbox.path.denied)kernel.sandbox.isToolAllowed(sandbox.id, 'shell-exec'); // false
kernel.sandbox.destroy(sandbox.id);When to Use
- Restricting agent file access to a workspace
- Preventing path traversal attacks
- Enforcing security policies on tool execution
Testing Utilities
Dedicated testing tools for verifying agent behavior without hitting live LLM APIs.
Key Exports
import { AgentTestRunner, MockModelProvider, ConversationSimulator } from '@kernova/core';import type { AgentTestRunnerConfig } from '@kernova/core';AgentTestRunner
Runs test scenarios against registered agents and asserts on results.
const runner = new AgentTestRunner(kernel, { timeout: 10000, verbose: true,});
const result = await runner.run({ name: 'basic-query-test', intent: { goal: 'What is 2+2?', intentType: 'query' }, assertions: [ (result) => result.success === true, (result) => result.summary?.includes('4'), ],});
console.log(`Test ${result.passed ? 'PASSED' : 'FAILED'}`);
// Run multiple scenariosconst results = await runner.runAll([scenario1, scenario2, scenario3]);const passed = results.filter(r => r.passed).length;console.log(`${passed}/${results.length} tests passed`);MockModelProvider
A fake model provider that returns deterministic responses. Use in tests to avoid real API calls.
const mockProvider = new MockModelProvider({ defaultResponse: 'This is a mock response', responses: { 'What is 2+2?': 'The answer is 4.', 'Hello': 'Hi there!', },});
const kernel = new KernovaKernel({ environment: 'development', ephemeral: true, providers: [mockProvider], models: { default: { provider: 'mock', model: 'mock-model' } },});ConversationSimulator
Simulates multi-turn conversations for integration testing.
const simulator = new ConversationSimulator(kernel);
const result = await simulator.simulate([ { role: 'user', content: 'Remember that my name is Alice' }, { role: 'user', content: 'What is my name?' },], { timeout: 30000 });
console.log(`Turns: ${result.turns.length}`);result.turns.forEach(turn => { console.log(` ${turn.role}: ${turn.content}`);});When to Use
- Unit testing agent behavior
- Integration testing without API costs
- CI/CD pipelines for agent quality checks
- Regression testing after agent changes
Configuration Reference
Full KernelConfig
import { KernovaKernel } from '@kernova/core';import type { KernelConfig } from '@kernova/core';
const config: KernelConfig = { // Instance identification instanceId: 'my-app-prod-1',
// Environment (required) environment: 'production',
// Debug logging debug: false,
// Model routing models: { default: { provider: 'anthropic', model: 'claude-sonnet-5-5' }, // Per-purpose models: reasoning, generation, classification, extraction, conversation, vision, code, ... overrides: { code: { provider: 'anthropic', model: 'claude-sonnet-5-5' }, classification: { provider: 'openai', model: 'gpt-4o-mini' }, }, // Tried once when the default provider fails fallback: { provider: 'openai', model: 'gpt-4o' }, },
// Additional providers (merged with auto-detected) providers: [],
// Persistence directory dataDir: '/var/lib/kernova',
// In-memory only (no SQLite) ephemeral: false,
// Built-in tool configuration builtInTools: { enabled: ['http-fetch', 'file-read', 'file-write', 'date-time', 'web-search'], disabled: ['shell-exec'], // Disable dangerous tools in production sandboxDir: '/var/lib/kernova/workspace', shellTimeout: 10000, },
// Self-reflection reflection: { enabled: true, threshold: 0.7, maxAttempts: 2, },};
const kernel = new KernovaKernel(config);ModelRoutingConfig
interface ModelRoutingConfig { // Default model for all requests default: { provider: string; // e.g. 'openai', 'anthropic', 'gemini', 'ollama' model: string; // e.g. 'gpt-4o', 'claude-sonnet-5-5' };
// Purpose-specific overrides purposes?: Record<string, { provider: string; model: string; }>;
// Fallback chain (tried in order if primary fails) fallback?: string[];}Environment Variables
Model providers are auto-detected from these environment variables:
| Variable | Provider |
|---|---|
OPENAI_API_KEY | OpenAI |
ANTHROPIC_API_KEY | Anthropic |
GEMINI_API_KEY | Google Gemini |
DEEPSEEK_API_KEY | DeepSeek |
GROQ_API_KEY | Groq |
TOGETHER_API_KEY | Together AI |
OPENROUTER_API_KEY | OpenRouter |
MISTRAL_API_KEY | Mistral |
COHERE_API_KEY | Cohere |
PERPLEXITY_API_KEY | Perplexity |
FIREWORKS_API_KEY | Fireworks AI |
XAI_API_KEY | xAI (Grok) |
CEREBRAS_API_KEY | Cerebras |
SAMBANOVA_API_KEY | SambaNova |
No configuration needed — if the key exists, the provider is available. Local servers (Ollama, LM Studio, vLLM, llama.cpp) need no key but aren’t detected: add them with providers: [createProvider('ollama', { baseUrl })].
Additional Modules
ModelFallbackManager
Automatic fallback when a provider fails. Tries providers in the configured fallback chain.
// Configured via models.fallback in KernelConfig// Automatic — no direct interaction needed// Access: kernel.fallbackTrajectoryRecorder
Records step-by-step execution traces for debugging. Enabled automatically when debug: true.
// Access traces for debugging (most recent first)const traces = kernel.trajectory.listTraces();traces.forEach(trace => { console.log(`Intent: ${trace.metadata.intentGoal}, Steps: ${trace.events.length}`);});RateLimiter
Token-bucket rate limiter applied per identity. Configured via BudgetConfig.requestsPerMinute.
import { RateLimiter } from '@kernova/core';// Usually accessed indirectly through budget enforcement// Direct access: kernel.rateLimiterContextEngineManager
Pluggable context assembly. Register custom context engines that determine what information is assembled for each agent invocation.
import { ContextEngineManager, DefaultContextEngine } from '@kernova/core';import type { ContextEnginePlugin } from '@kernova/core';ToolAvailabilityEngine & ToolPolicyEngine
Control which tools are visible and allowed for each agent execution.
// ToolAvailabilityEngine — declarative visibility rules// ToolPolicyEngine — layered allow/deny policies// Both applied automatically during intent executionHotReloader
Watches files for changes and reloads agent configs at runtime.
import { HotReloader } from '@kernova/core';import type { HotReloaderConfig } from '@kernova/core';// Used internally by DaemonRunner when watch: trueSecurityAuditor
Runs security checks against the kernel configuration and reports issues.
import { SecurityAuditor } from '@kernova/core';import type { AuditResult, AuditCheck, AuditSeverity } from '@kernova/core';PluginMarketplace
Discover and install plugins from a registry.
import { PluginMarketplace } from '@kernova/core';import type { MarketplaceConfig, PluginListing } from '@kernova/core';Complete Example
A full example combining multiple modules:
import { KernovaKernel, defineAgent, DaemonRunner, now } from '@kernova/core';
// 1. Create the kernelconst kernel = new KernovaKernel({ environment: 'production', dataDir: './kernova-data', models: { default: { provider: 'anthropic', model: 'claude-sonnet-5-5' }, fallback: { provider: 'openai', model: 'gpt-4o' }, }, builtInTools: { disabled: ['shell-exec'], sandboxDir: './workspace', }, reflection: { enabled: true, threshold: 0.75 },});
// 2. Define agentsconst researcher = defineAgent({ name: 'researcher', description: 'Researches topics and provides detailed summaries', capabilities: [ { id: 'research', name: 'Research', description: 'Deep research', confidence: 0.9 }, ], tools: [ { toolId: 'web-search', name: 'web-search', purpose: 'Search the web', required: true }, { toolId: 'http-fetch', name: 'http-fetch', purpose: 'Fetch web pages', required: false }, ], instructions: `You are an expert researcher. Search the web for accurate, up-to-date information and provide comprehensive summaries with sources.`,});
const writer = defineAgent({ name: 'writer', description: 'Writes polished content based on research', capabilities: [ { id: 'writing', name: 'Writing', description: 'Content creation', confidence: 0.95 }, ], tools: [{ toolId: 'file-write', name: 'file-write', purpose: 'Save drafts', required: false }], instructions: `You are a professional writer. Create engaging, well-structured content based on the provided context and research.`, reflection: { enabled: true, threshold: 0.8, maxAttempts: 3 },});
// 3. Start the kernel and register agentsawait kernel.start();kernel.agentRegistry.register(researcher.definition, researcher.executor);kernel.agentRegistry.register(writer.definition, writer.executor);
// 4. Ingest documents for RAGawait kernel.rag.ingest( 'Company style guide: Use active voice, keep paragraphs under 3 sentences...', 'style-guide.md', { category: 'guidelines' });
// 5. Set up a content workflow (steps run in order; each agent step gets its own goal)kernel.workflows.define({ id: 'blog-post', type: 'workflow_definition', version: '1.0.0', owner: 'system', status: 'active', createdAt: now(), updatedAt: now(), metadata: {}, name: 'Blog Post Pipeline', description: 'Research trending topics, then draft a post', steps: [ { id: 'research', name: 'Research', type: 'agent', onFailure: 'stop', config: { agentId: 'researcher', input: { goal: 'Research trending AI topics this week' } } }, { id: 'write', name: 'Write', type: 'agent', onFailure: 'stop', config: { agentId: 'writer', input: { goal: 'Draft a blog post on the top trending AI topic' } } }, ],});
// 6. Schedule weekly contentkernel.scheduler.register({ name: 'weekly-blog', cronExpression: '0 10 * * 1', // Monday at 10am target: { type: 'intent', goal: 'Run the blog-post workflow for trending AI topics' },});
// 7. Set budget limitskernel.budget.setGlobalBudget({ maxTokens: 500_000, maxCostUsd: 25.00 });
// 8. Subscribe to events for monitoringkernel.events.subscribe(['intent.completed'], (event) => { console.log(`✓ Completed: ${event.data.intentId}`);});
kernel.events.subscribe(['intent.failed'], (event) => { console.error(`✗ Failed: ${event.data.error}`);});
// 9. Run as a daemonconst daemon = new DaemonRunner(kernel, { watch: true, configPath: './agents/', heartbeatIntervalMs: 30000,});
await daemon.start(); // Blocks until SIGINT/SIGTERMExports Summary
Everything exported from @kernova/core:
// Coreexport { KernovaKernel, defineAgent };export type { KernelConfig, AgentSpec, DefinedAgent };
// Eventsexport { EventBus, EventStore };
// Memoryexport { MemoryEngine, MemoryStore };
// Modelsexport { ModelRouter, OpenAIProvider, AnthropicProvider, GeminiProvider, OllamaProvider, OpenAICompatibleProvider };export { createProvider, detectAvailableProviders, listPresets, createProviderFromConfig };
// Agentsexport { AgentRegistry, AgentCoordinator };export type { AgentExecutor, AgentTools };
// Pluginsexport { PluginRegistry };export type { KernovaPlugin, ToolDefinition, MiddlewareHook };
// Workflowsexport { WorkflowEngine };
// Intelligenceexport { AgentPlanner, SelfReflection, ConversationManager, RAGPipeline };
// Autonomyexport { Scheduler, TaskQueue, ProactiveTriggerEngine, BackgroundLoopModule };
// Channelsexport { ConnectorRegistry, WebhookChannelAdapter, WebSocketChannelAdapter };
// Infrastructureexport { DaemonRunner, AgentGateway, MCPBridge };export { MetricsCollector, HealthMonitor, SandboxManager };export { IdentityManager, ApiKeyManager, PermissionEngine, SessionManager };export { BudgetManager, RateLimiter };
// Testingexport { AgentTestRunner, MockModelProvider, ConversationSimulator };
// Built-in Toolsexport { BuiltInToolRegistry, SandboxViolationError };
// Utilitiesexport { generateId, now, ValidationError, QueueFullError, ConnectorError };