⚙️

The Kernel

What runs when everything else is stripped away.

Two schemas, an AI conversation loop, a hook system, and an extension loader. Remove every extension and the kernel still boots. It defines the data contract that extensions build on and the resolution chains that determine what happens at every position in the tree.

Two Schemas

The entire data model is two documents. Everything an extension needs to store goes in the metadata Map. The schemas never change. Ever.

Node

_id, name, type, status
dateCreated, llmDefault, visibility
children[], parent
rootOwner, contributors[]
systemRole
metadata (Map)

12 fields. Type is free-form (custom types allowed). Status is active, completed, or trimmed. Extensions store all their data in metadata under their name. Values, prestige history, schedules, tool configs, extension scoping, all of it lives in the Map.

User

_id, username, password
roots[], recentRoots[], remoteRoots[]
llmDefault, profileType
isRemote, homeLand
metadata (Map)

10 fields. One default LLM connection. Extensions store energy budgets, API keys, LLM slot assignments, storage usage, and preferences in metadata.

The Conversation Loop

Every AI interaction goes through the same loop. Mode determines the system prompt and available tools. The loop calls the LLM, executes tool calls, and repeats until the LLM responds without tools or hits the iteration cap.

1

Resolve LLM

Walk the resolution chain: extension slot on tree, tree default, extension slot on user, user default. First match wins. Any OpenAI-compatible endpoint works.

2

Resolve Tools

Three layers: mode base tools, extension-injected tools, per-node config (allowed/blocked). Then spatial extension scoping filters out tools from blocked or restricted extensions. The AI only sees what's permitted at this position.

3

Build Prompt

The active mode's buildSystemPrompt() generates the system message with user context, tree position, and timezone. Extensions inject context via the enrichContext hook.

4

Tool Loop

Send to LLM. If it returns tool calls, execute them via MCP, append results, send again. Repeat until the LLM responds with text or hits maxToolIterations (default 15). Abort signal checked between iterations.

Extensions never call the loop directly. They use runChat() (single message, persistent session) or OrchestratorRuntime (multi-step chain). One call handles MCP connection, session management, AIChat tracking, abort propagation, and cleanup.

Hook System

An open pub/sub bus. The kernel fires events. Extensions listen. Extensions can also fire their own events for other extensions to listen to. Any hook name is valid. No whitelist. Typos are detected and warned, not blocked.

Before Hooks

Run sequentially before the operation. Can modify data (prestige tags version numbers). Can cancel (return false or throw). If one cancels, the operation stops. 5 second timeout per handler.

beforeNote
beforeStatusChange
beforeNodeDelete
beforeContribution
beforeRegister

After Hooks + enrichContext

After hooks run in parallel, fire-and-forget. Errors logged, never block. enrichContext runs sequentially during AI context building so extensions can inject their data (values, schedules, prestige history) for the AI to see.

afterNote
afterStatusChange
afterNodeCreate
afterRegister
enrichContext

Extensions fire their own hooks with extName:hookName convention. The gateway extension fires gateway:beforeDispatch. Other extensions listen. Spatial scoping filters: if an extension is blocked at a node, its hook handlers are skipped for operations on that node.

Extension Loader

At boot, the loader scans extension directories, reads manifests, validates dependencies, resolves load order (topological sort), and wires everything into the land. Extensions only receive the services they declared.

1

Discover

Scan extensions/ for directories with manifest.js. Skip disabled extensions (from env, file, or DB config). Validate manifest fields.

2

Resolve

Check needs (models, services, middleware, extensions with semver constraints). Check optional deps. Topological sort so dependencies load first. Skip extensions with unmet requirements.

3

Initialize

Call each extension's init(core) with a scoped services bundle. Extensions register modes, hooks, and set core.energy or other services. Return router, tools, jobs, exports.

4

Wire

Mount routes at /api/v1. Register MCP tools with ownership tracking. Register page routes. Start background jobs. Run schema migrations. Sync extension state to the .extensions system node.

Four Resolution Chains

Every operation at a node goes through resolution chains that determine what the AI can do and how it thinks. Each chain walks the parent hierarchy and applies layered rules. This is what makes position determine capability.

1. Extension Scope

Is this extension active, restricted, or blocked here? Walk parent chain, accumulate metadata.extensions.blocked[] and restricted. Blocked extensions lose all capabilities. Restricted extensions keep read-only tools.

2. Tool Scope

What tools does the AI have? Start with mode base tools. Add extension-injected tools. Apply per-node metadata.tools.allowed/blocked. Filter by extension scope. The AI sees only what survives all layers.

3. Mode Resolution

How does the AI think? Check metadata.modes[intent] for per-node override. Skip if owning extension is blocked. Fall back to default mapping (tree:respond). Then bigMode default.

4. LLM Resolution

Which model runs? Extension slot on tree, tree default, extension slot on user, user default. First match wins. Failover chain tried on failure.

Navigate to a different node. All four chains re-resolve. Different tools appear. Different mode fires. Different model runs. The tree reshapes around where you stand.

System Nodes

When a land boots for the first time, the kernel creates five system nodes. They hold infrastructure state, not user content.

root

Land Root

The top-level node. Parent of all trees and system nodes. rootOwner: "SYSTEM".

.id

.identity

Land UUID, domain, Ed25519 public key for Canopy federation signing. Set once at boot.

.cfg

.config

All runtime configuration as metadata keys. Readable and writable via CLI, API, or the land-manager AI.

.p

.peers

Canopy federation peer list. Children are peer land records with status and heartbeat history.

.ext

.extensions

Extension registry. Each loaded extension is a child node with version and schema version for migrations.

Kernel Config

Every tunable value in the kernel. Set from the CLI, the API, or through the land-manager AI. No code changes. No restarts.

llmTimeoutSeconds per LLM API call900
llmMaxRetriesRetry count on 429/5003
maxToolIterationsTool calls per message15
maxConversationMessagesContext window size30
defaultModelFallback LLM model
noteMaxCharsMax characters per note5000
treeSummaryMaxDepthHow deep AI sees the tree4
treeSummaryMaxNodesHow many nodes AI sees60
carryMessagesMessages carried across mode switch4
sessionTTLSession idle timeout (seconds)900
staleSessionTimeoutStale session cleanup (seconds)1800
maxSessionsMax concurrent sessions10000
aiChatRetentionDaysAuto-delete AI chats after N days90
contributionRetentionDaysAuto-delete contributions after N days365
canopyEventRetentionDaysAuto-delete canopy events after N days30
timezoneLand timezone for AI promptsauto
disabledExtensionsExtensions to skip on boot[]

Safety

The kernel protects itself from extensions, from runaway AI, and from time.

Hook timeout5s per handler. Hanging handlers killed and logged.
Hook cap100 handlers per hook. Flooding rejected.
Circuit breaker5 consecutive failures auto-disables the handler.
Metadata guardBlocked extensions can't write to nodes.
Session cap10K max with oldest-first eviction.
Depth limits50 for status cascade, 100 for auth traversal.
Name validationNo HTML, no dots, no slashes, max 150 chars.
Dependent checkCan't uninstall if other extensions depend on it.
Checksum verificationSHA256 verified on extension install.
Semver constraintsDependencies declare version requirements.
Upload cleanupOrphaned files deleted hourly with grace period.
Graceful shutdownSIGTERM closes server, disconnects DB, exits clean.

What the Kernel Does Not Do

The kernel does not know about fitness, food, wallets, blogs, scripts, energy budgets, understanding runs, dream cycles, or gateway channels. It does not render HTML pages. It does not meter usage. It does not tag version numbers. It does not schedule recurring tasks. It does not know what a "workout" or a "calorie" is.

All of that is extensions. The kernel provides nodes, notes, hooks, modes, tools, and the conversation loop. Extensions provide meaning. The kernel provides structure. Together they make an operating system where position determines reality and navigation is capability switching.

Get StartedExtensionsFull Guide