The microkernel that orchestrates Pons modules.
The smallest seed of a thinking system.
The kernel is a thin process orchestrator. It has five responsibilities — and only these:
- Message Bus — in-memory pub/sub forwarding between modules. No persistence, no queue. Fire-and-forget.
- Module Lifecycle — spawn, kill, restart, hot-swap. Each module runs as an isolated child process.
- RPC Routing — direct IPC routing for request/response between modules, with timeouts and origin validation.
- Service Directory — dynamic discovery of module-provided services via
provides/requiresdeclarations. - Configuration — layered YAML config with schema validation, hot-reload via
SIGUSR1, and per-module config sections.
Everything else lives in modules.
┌─────────────────────────────────────────────┐
│ Kernel │
│ │
│ ┌───────────┐ ┌──────────┐ ┌───────────┐ │
│ │ Message │ │ Lifecycle│ │ Service │ │
│ │ Bus │ │ Manager │ │ Directory │ │
│ └─────┬─────┘ └────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
└────────┼─────────────┼───────────────┼───────┘
│ │ │
┌────┴──┐ ┌─────┴──┐ ┌──────┴──┐
│ Agent │ │ LLM │ │ Gateway │ ...modules
│ │ │ │ │ │
└───────┘ └────────┘ └─────────┘
process process process
Modules never import each other. All communication flows through the kernel via IPC.
The recommended way to install Pons is via the CLI:
deno install -gA jsr:@pons/cliThen start the kernel:
pons startIf you need just the kernel without the CLI:
deno install -gA -n pons-kernel jsr:@pons/kernelpons-kernel # start
pons-kernel --log debug # verbose loggingModules communicate through topics. A module declares which topics it subscribes to in its manifest, and publishes messages to any topic.
Module A ──publish("llm:generate", payload)──▶ Kernel ──deliver──▶ Module B
The bus is pure routing — no persistence, no retry. If a module needs delivery guarantees, it implements them itself.
For request/response patterns, modules use RPC through the kernel's service directory:
Agent ──rpc_request(service: "providerRegistry", method: "generate")──▶ Kernel ──▶ LLM
◀──rpc_response(result)────────────────────────────────────────── Kernel ◀── LLM
The kernel resolves the service name to a module ID, forwards the request, and routes the response back. Timeout: 30s.
- Kernel discovers modules from
~/.pons/modules/ - Each module is spawned as a child process with its own
deno.json - Module sends
ready→ kernel checksrequiresdependencies - When all required services are available → kernel sends
deps_ready - Health checks run every 30s via
ping/pong - On crash: exponential backoff restart (max 5 attempts)
Layered YAML config at ~/.pons/config.yaml:
logging:
level: info
levels:
agent: debug
models:
providers:
- id: anthropic
type: anthropicModules declare a configKey in their manifest. When that section changes, the kernel pushes config:update to the module. Hot-reload: send SIGUSR1 to the kernel process.
Every module has a module.json:
{
"id": "llm",
"name": "LLM Services",
"description": "Provider registry, model routing, cost tracking",
"provides": ["providerRegistry", "model-router", "cost-tracker"],
"subscribes": ["llm:generate", "llm:stream:request"],
"requires": [],
"optionalRequires": ["http-router"],
"configKey": "models",
"configSchema": "./src/config.schema.ts",
"priority": 5
}| Field | Description |
|---|---|
id |
Unique module identifier |
provides |
Services this module exposes for RPC |
subscribes |
Bus topics this module listens to |
requires |
Services that must be available before activation |
optionalRequires |
Services the module can use but doesn't need to start |
configKey |
Top-level config section this module owns |
configSchema |
Path to Zod schema for config validation |
priority |
Spawn order (lower = earlier) |
Built-in methods available to modules via call:
| Method | Params | Returns |
|---|---|---|
config.get |
{ key: string } |
Config value |
config.set |
{ key: string, value: unknown } |
{ success: boolean } |
config.sections |
— | Available config sections |
module.list |
— | All registered modules |
module.commands |
— | CLI commands from modules |
service.discover |
— | All registered services |
service.resolve |
{ service: string } |
Module ID providing the service |
src/
├── index.ts # Entry point — CLI flags, boot, start
├── kernel.ts # Kernel class: boot/start/shutdown
├── lifecycle.ts # Spawn/kill/hot-swap, RPC routing, health checks
├── messaging/
│ └── bus.ts # In-memory pub/sub registry
├── module/
│ ├── loader.ts # Module discovery from filesystem
│ └── registry.ts # Module tracking + service directory
├── config/
│ ├── manager.ts # Config CRUD, schema discovery, validation
│ └── types.ts # Config types
├── logs/
│ └── logger.ts # Logger factory + module log forwarding
└── formatters.ts # Shared formatting utilities
deno task dev # Watch mode
deno task start # Production
deno check src/index.ts # Type checkSee CONTRIBUTING.md for guidelines.