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.
The entire data model is two documents. Everything an extension needs to store goes in the metadata Map. The schemas never change. Ever.
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.
10 fields. One default LLM connection. Extensions store energy budgets, API keys, LLM slot assignments, storage usage, and preferences in metadata.
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.
Walk the resolution chain: extension slot on tree, tree default, extension slot on user, user default. First match wins. Any OpenAI-compatible endpoint works.
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.
The active mode's buildSystemPrompt() generates the system message with user context, tree position, and timezone. Extensions inject context via the enrichContext hook.
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.
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.
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.
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.
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.
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.
Scan extensions/ for directories with manifest.js. Skip disabled extensions (from env, file, or DB config). Validate manifest fields.
Check needs (models, services, middleware, extensions with semver constraints). Check optional deps. Topological sort so dependencies load first. Skip extensions with unmet requirements.
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.
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.
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.
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.
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.
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.
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.
When a land boots for the first time, the kernel creates five system nodes. They hold infrastructure state, not user content.
The top-level node. Parent of all trees and system nodes. rootOwner: "SYSTEM".
Land UUID, domain, Ed25519 public key for Canopy federation signing. Set once at boot.
All runtime configuration as metadata keys. Readable and writable via CLI, API, or the land-manager AI.
Canopy federation peer list. Children are peer land records with status and heartbeat history.
Extension registry. Each loaded extension is a child node with version and schema version for migrations.
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 call900llmMaxRetriesRetry count on 429/5003maxToolIterationsTool calls per message15maxConversationMessagesContext window size30defaultModelFallback LLM modelnoteMaxCharsMax characters per note5000treeSummaryMaxDepthHow deep AI sees the tree4treeSummaryMaxNodesHow many nodes AI sees60carryMessagesMessages carried across mode switch4sessionTTLSession idle timeout (seconds)900staleSessionTimeoutStale session cleanup (seconds)1800maxSessionsMax concurrent sessions10000aiChatRetentionDaysAuto-delete AI chats after N days90contributionRetentionDaysAuto-delete contributions after N days365canopyEventRetentionDaysAuto-delete canopy events after N days30timezoneLand timezone for AI promptsautodisabledExtensionsExtensions to skip on boot[]The kernel protects itself from extensions, from runaway AI, and from time.
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.