ThinkingRoot Docs
Concepts

Root Functions

A Root Function is durable, co-located compute that runs inside the cognition

What a Root Function is

A Root Function is durable, co-located compute that runs inside the cognition graph. It is not just "a CLI command" — it is a unit of logic you deploy into a workspace that can recall memories, think with an LLM, act, remember new facts, fork and merge branches, and call other tools — all in one function body, running right next to the data it operates on.

The differentiator: a developer writes one function that lives inside the brain. It reads the workspace's compiled memory, reasons over it, takes an action, writes the result back as new grounded memory, and is itself exposed as a callable tool. There is no separate app server shuttling data back and forth — the function is co-located with the graph, the vector index, and the LLM.

A Root Function is:

  • Durable — every step is journaled, so a function replays deterministically. An interrupted run resumes; a replay never double-writes or re-calls the model.
  • Versioned — each deploy is a new version; runs are logged with inputs/outputs.
  • A tool — once deployed, a function greet is advertised to MCP clients as function::greet and can be invoked by agents, other functions, or over REST.
  • Sandboxed — the body runs in a V8 isolate (Deno Core). Network egress is gated by an allowlist; secrets are injected, never baked in.

The ctx surface (what a function can do)

Inside a Root Function body you get a ctx object. Every call is journaled for durable, exactly-once replay.

  • ctx.memory.recall(query) — semantic recall over the workspace's compiled claims. Returns grounded, cited memories.
  • ctx.memory.remember(text) — write a new fact with a deterministic claim id (idempotent on replay — no duplicates) and rootfn:// provenance.
  • ctx.prompt(name, vars) — assemble a Compiled Prompt stored in the workspace.
  • ctx.branch.fork(name) / ctx.branch.merge(name) — create or merge a branch, so a function can do speculative work in isolation and merge only if it verifies.
  • ctx.mcp.call(tool, args) — call any MCP tool, including other deployed functions (function::<name>).
  • ctx.llm.ask(prompt) — call the workspace LLM as a tools-blind coprocessor. Journaled, so replays don't re-call the model.
  • ctx.acquire({ name, description, body })self-extension: deploy a NEW function at runtime (LLM-authored or supplied), then call it. See below.

Example: a memory-aware function

// A function that recalls context, decides, remembers the outcome, and
// branches — all co-located with the graph.
export default async function (ctx, input) {
  const related = await ctx.memory.recall(`history for customer ${input.customerId}`);

  const verdict = await ctx.llm.ask(
    `Given these notes, is the customer at churn risk? Notes: ${JSON.stringify(related)}`
  );

  // Write the decision back as a grounded, provenance-tagged memory.
  await ctx.memory.remember(
    `Customer ${input.customerId} churn assessment: ${verdict}`
  );

  if (verdict.includes("risk")) {
    const b = await ctx.branch.fork(`retention/${input.customerId}`);
    await ctx.mcp.call("function::draft_retention_email", { customerId: input.customerId });
  }
  return { verdict };
}

Deploying and invoking

Deploy a function from a JS file, then invoke it with a JSON input:

# Deploy (creates a new version)
root function deploy churn_check --code ./churn_check.js

# Invoke with input
root function invoke churn_check --input '{"customerId": 42}'

# List deployed functions and inspect run history
root function list
root function runs churn_check

Over REST through the gateway:

POST /api/v1/ws/{ws}/functions/{name}/invoke   # body: the JSON input

Self-extension: ctx.acquire

The spine of the system: a function can author and deploy a brand-new function at runtime. The new function can be supplied directly, or written by the workspace LLM (tools-blind, journaled), then deployed and called — without redeploying the caller.

export default async function (ctx, input) {
  // Reuse-or-forge: deploy a capability that doesn't exist yet.
  await ctx.acquire({
    name: "greeter",
    description: "Return a friendly greeting for a given name",
    // body optional — if omitted, the LLM authors it
  });
  return await ctx.mcp.call("function::greeter", { name: input.name });
}

This is how ThinkingRoot is self-compounding: capabilities are self-authored and verified before they are kept (deploy → invoke → keep or roll back), and every verify-invoke seeds the capability router so the right function is chosen next time.

Why it matters

Traditional architecture: your app server fetches data, calls an LLM, writes back — three network hops, no memory of what it learned. A Root Function collapses that into one durable, co-located, self-improving unit that lives in the brain and gets smarter each time it runs. That is the "living database" idea made concrete.