CSPL: a program is stored separately from the way it is executed

Version of 2 October 2026. Every statement is labelled with how we know it: [verified] means we ran it ourselves; where the raw answers are saved, the statement names the file; [documented] means it is in the platform's API reference and our working code relies on it; [stated] means the designer of the runtime says so and we have not reproduced it.

1. The problem, and what this document describes

An agent can call the tools its MCP server offers. When the server is a fixed set of functions, each new tool is a change to that server: edit the code, deploy it, restart it, and do the same on every machine where it should run. MCP does not require this: a server may change its list of tools while it runs, or offer a general executor. This document describes one way to add tools without changing the server.

In Extella a tool for the agent is a saved program, not a function in a server. A model, or a person, saves the program through an API (save, get, run, search), whose operations are also available as MCP tools, and runs it by name on a chosen device. The MCP server and its list of tools do not change.

If tools are saved programs, four questions follow at once. CSPL, Container Specific Programming Language, is the mechanism in Extella that answers them. It is our own design, described in the published international application WO 2026/102343 (priority date 8 November 2024). This document describes that mechanism and nothing else: not the Extella product, not agents, not model training.

QuestionCSPL's answerWhere in this document
In what language is the program written?In any language for which the device has a handler; the record names its languagesections 2, 3 and 5
What executes it?That language's handler, registered on the device and replaceablesections 4 and 5
Where does it run?On the device named in the callsections 3 and 5
How can a model be allowed to add code?Not safely by default; a small language limits what a program can say, and its handler can check a program before running itsections 4, 5 and 7

The mechanism in one line:

a saved program that names its language → a call that names the program and a device → the handler of that language on the device → a result.

A saved program is called an expert. Its record holds source text and, in the cspl field, the name of the language the text is written in. A handler for that language is registered on a device, a machine that runs the Extella listener. A handler can be registered or replaced without rewriting the programs written in its language.

When this can be useful. When the same saved program has to run on any of several devices you have prepared, with the device chosen in each call, or when many programs share a small language of your own whose handler you want to control in one place.

When it is not. A function in your own MCP server answers in about a millisecond, and a general executor with program storage is about a hundred lines of code; a call through Extella to a device took 6 to 14 seconds in our measurement (section 5). If that covers your case, either of those is the simpler choice; we did not run either of them on a second machine and do not know what that takes.

What this is, and what it is not. It is a way to run saved programs through pluggable handlers on prepared devices. It is not a general-purpose safe environment for running untrusted code written by a model; section 7 says why.

2. Terms

TermMeaning
CSPLThe mechanism: programs stored with the name of their language, executed by a handler for that language.
LanguageA set of permitted statements and the rules for writing them. The cspl field of an expert holds the name of its language.
ExpertA saved program: name, code (source text), cspl (language name), default parameters, a description. It is stored in an account, in the scope of one of the account's agents (the X-Agent-Id header in section 3).
HandlerCode on a device that executes programs in one language. For a language of your own it is a Python function.
DeviceA machine running the Extella listener, signed in to an account. It has an id and can be named as the target of a run.
RegistrarAn expert whose job is to register a handler on the device it runs on.

3. The expert record and the two calls

Saving and running go through an HTTP API [documented, and verified in our demo servers]:

POST https://api.extella.ai/api/expert/save
headers: X-Auth-Token, X-Profile-Id: default, X-Agent-Id: <agent>
body:    {"name": "tally_demo", "code": "add 5\nadd 7\nsub 2\n", "cspl": "tally", "kwargs": {}, "description": "..."}

POST https://api.extella.ai/api/expert/run
body:    {"name": "tally_demo", "params": {}, "targets": ["<device id>"]}
answer:  {"status": "success", "expert_name": "tally_demo", "result": "...", "execution_log": [...]}

A long run comes back as {"task_id": ...} and is polled with POST /api/tasks/check. Saving under an existing name overwrites the record; there is no versioning [documented].

4. Declaring a language: an example you can run

The example has four parts: a language of two statements, its handler, a registrar, and a program. The handler below is the file as we ran it. The registrar is shown with the handler text elided; the script that builds it, saves both experts and runs them is one file, run_tiny.py. Both files are published next to this document.

python3 run_tiny.py          # needs Extella installed and signed in; Python 3.8+

The handler. It receives the source text of an expert and returns a dictionary. It checks the whole program first; if any statement is not in the language, nothing is executed:

def tally(code = "", filtered_source_code = "", func_name = "", **extra):
    # Handler of the language "tally": a program is lines "add N" or "sub N", N up to nine digits 0-9.
    # The whole program is checked first; if any line is not a tally statement, nothing is executed.
    import platform, socket
    lines = [line.split() for line in (code or filtered_source_code or "").splitlines() if line.split()]
    for n, parts in enumerate(lines, 1):
        if len(parts) != 2 or parts[0] not in ("add", "sub") or not (parts[1].isascii() and parts[1].isdigit() and len(parts[1]) <= 9):
            return {"status": "rejected", "reason": "statement %d is not a tally statement: %s" % (n, " ".join(parts)[:40])}
    total = 0
    for op, number in lines:
        total += int(number) if op == "add" else -int(number)
    return {"status": "success", "language": "tally", "expert": func_name, "total": total, "host": socket.gethostname(), "os": platform.system() + " " + platform.machine()}

Changed on 16 October 2026. The number check now accepts only the digits 0 to 9, at most nine of them. The version run on 1 October checked parts[1].isdigit(). Python counts “²” as a digit, so add ² passed the check and then failed in int() instead of being refused. The answers below are from 1 October and that version (918 bytes). On 16 October the fixed handler (991 bytes) was registered and run on a Linux server: the same program gave 10, import os was refused as before, and add ² was refused [verified, 16 October 2026; runs-2026-10-16.json].

The registrar is an expert in the built-in language fython (Python with a dependency directive). Run once on a device, it registers the handler there under the language name:

$extens("include.py")
include("import os", [])

def register_tally() -> dict:
    import disnet
    handler_code = '''...the handler text above, inserted by run_tiny.py...'''
    d = disnet.Disnet(url="https://disnet.extella.ai")
    envelope = {"filtered_source_code": "", "func_name": "", "args": None, "kwargs": None, "cspl": "tally", "response_format": None}
    d.container(code=handler_code, func_name="tally", container_path="tally", args=None, kwargs=envelope, cspl_type="fython", push=False)
    return {"status": "success", "registered": "tally", "bytes": len(handler_code)}

What the device answered on 1 October 2026, on a MacBook (Darwin arm64) [verified; the host name is shortened here, the raw answers are in the appendix file]:

StepThe device's answerRound trip
Run register_tally{'status': 'success', 'registered': 'tally', 'bytes': 918}13.1 s
Run tally_demo (add 5, add 7, sub 2){'status': 'success', 'language': 'tally', 'expert': 'tally_demo', 'total': 10, 'host': '<laptop>', 'os': 'Darwin arm64'}11.1 s
Run an expert whose second line is import os{'status': 'rejected', 'reason': 'statement 2 is not a tally statement: import os'}11.1 s

The round trip is the full time of one call as seen by the caller. In an earlier pass the same day the same steps took 7 to 9 s. These runs were not a measurement of speed; the measurement of 2 October is in section 5.

5. What we have shown

Adding a program does not change the server. We added the same ten small Python functions in three ways: as fixed tools of an MCP server (official Python SDK), through a general executor with program storage that we wrote in about a hundred lines, and through Extella's MCP server. Fixed tools: 10 edits and 10 restarts, because that is how this baseline is built; MCP does not require it. The general executor and Extella: 0 edits and 0 restarts. A new function, saved and run for the first time, took 0.36 s with fixed tools (restart included), 0.026 s with the general executor, and 9 to 12 s with Extella (median about 10 s over ten functions with the session already open; in this run every save overwrote a program of the same name, so creating a program for the first time was not timed; two earlier runs the same day gave medians of about 11 s, and the first function together with opening the session took 14.4 s). A repeat call took 0.0014 s, 0.025 s, and 6 to 14 s (median about 9 s, 30 calls). Only Extella was run on a second machine: 30 of 30 calls were correct there with no second save, in 5 to 9 s. No Extella call failed in the 80 calls of this measurement on that day (72 run_expert calls in the final run and 8 in a short check before it; that check is not in the published results); a re-run during review saw one failure in 73 calls, which we could not reproduce. A script made every call; no model was driving any of the servers. The two local ways ran as local processes with no network; Extella is a remote service that dispatches to a device, and that device was the same laptop that made the calls; the difference in seconds is therefore not a comparison of two remote services. Extella's MCP server lists 44 tools, 53 KB of definitions with every listed field and 33 KB in name, description and input schema; the general executor lists 4 tools in 2 KB [verified, 2 October 2026; measure3.py, generic_server.py, measure3-result-2026-10-02.json; two earlier runs: measure3-result-2026-10-02-run1.json, measure3-result-2026-10-02-run2.json]. What follows: the measurement confirms for Extella one narrow property, a program saved once runs on a prepared machine chosen by a parameter of the call. It does not show an advantage over a general executor placed on a second machine, because that was not run, and it says nothing about the products of Anthropic or Cloudflare, which we did not run.

Calling a saved expert through this API needs no call to a model. In our demo runs the counter of model calls showed 0 for a run and 1 for creating an expert from a sentence [verified, 1 October 2026]. The counter sits in the demo server, the only component of that demo that holds a model-provider key; its source is published at extella.dev/robot/server/. This is evidence from one component, not an audit of a closed system. An expert may itself be written to call a model; nothing prevents that.

The same program runs under different handlers. One expert in the language block (a JSON document describing a quote on a web page, sha256 ba2de0dd…) was executed by three handlers on two Linux servers in six runs. Two handlers produce HTML and differ only by a constant; the third is separately written code that renders the same documents as plain text. Registering a handler took 6.8 to 7.9 s; the model-call counter was 0 in every run; the handler hash returned by the device matched the hash of the published file in all six [verified, 1 October 2026; extella.dev/blocks/server/].

Replacing a handler changes how the programs of its language run on that device. A fix or a new rule goes into one handler and the stored programs stay as they are. The saved record is one stored program executed by three handlers without being edited [verified on the block language: one program, six runs]; the live page extella.dev/blocks/ renders its six stored blocks with whichever of the three handlers you choose. That the same holds for every program of a language is the stated design of the runtime [stated]; we have not measured it on a larger set of programs. This is a wide effect, not a guarantee of a safe update: keeping existing programs working when a handler is replaced is the responsibility of the handler's author, and the platform does not version handlers or programs. It applies to languages whose handler you write; for a general language the handler is that language's own toolchain.

Languages are not limited to small ones. Experts in four languages ran on one MacBook through the same call: tally, Go, Rust and C [verified, 1 October 2026]. The Go and Rust handlers were already registered on the device. For C we wrote a handler of sixteen lines that compiles the source with the device's compiler and runs the binary (handler_c.py). A language of this kind needs its toolchain on the device.

No separate application service has to be deployed around each program. Every expert is called by name through the one Extella API, so a chain is a sequence of calls, and a caller does not need to know what language the next step is written in. The API and the platform behind it are a network layer; what goes away is a service per program. A chain of three experts in three languages (a read-only query language, Go, and a page language) ran on one machine on 29 September 2026 [verified; the raw answers of that run are not published], and a chain of three experts in three languages (a read-only query language, Python, and a page language) ran on a Linux server on 2 October 2026, each result passed to the next as parameters [verified; three_languages.py, three-languages-2026-10-02.json].

One expert can be replaced without touching the others. Saving new source under the same name replaces the program; the next run uses it. We replaced the tally program between two runs and the answer changed from 10 to 99 [verified, 1 October 2026].

A small language limits what a program can say. A program in tally cannot open a file because the language has no statement for it. Our public demos use this: visitors add content to a live page in a language of seven block types with text fields only [verified for those languages]. This is a property of one language and its handler. It does not carry over to other experts or to the platform; see section 7.

An expert is exported and installed as data. A bundle of two experts, the registrar and the program, exported as one JSON file, was saved into an account and run on a laptop by one script [verified on macOS, 1 October 2026; extella.dev/robot/classic/take_home.py]. The target device needs Extella installed and the handler registered; the script does the second.

Three published approaches are close to this one. They address different parts of a system, and we do not claim they cannot do what is described here.

Code execution with MCP (Anthropic)Code Mode (Cloudflare)Agent Skills (Anthropic)This document
SubjectPresenting tools to a model as code it can call, so tool definitions and intermediate data stay out of its contextConverting MCP tools into a typed API and running model-written code in an isolatePackaging instructions, resources and scripts that an agent loads when relevantStoring a program with the name of its language and executing it by a handler on a chosen device
Language of the codeTypeScript in the post's examplesTypeScriptInstructions plus scriptsDeclared per program
What executes itA sandboxed execution environmentA V8 isolate with bindings to MCP serversThe code execution toolA handler registered on a device of the account
Reuse of codeThe post describes saving working code as reusable functionsNot in the post; the Code Mode documentation describes named snippets that a model can find and run againA skill is reusable by designAn expert is saved and called by name
Replacing the executorNot addressedThe Code Mode package has an executor interface you can implement for another environment; it runs JavaScript only, and we found no handler per named language in what we readNot addressedA handler is installed by an expert
IsolationSandboxing is required by the designAn isolate without general network accessSandboxed code executionNone by default, see section 7

Sources, as we read them on 1 October 2026: anthropic.com/engineering/code-execution-with-mcp; blog.cloudflare.com/code-mode; claude.com/blog/skills. Read on 2 October 2026: developers.cloudflare.com/agents/tools/codemode/how-it-works; github.com/cloudflare/agents/blob/main/packages/codemode/README.md.

MCP is a way into this mechanism: the operations of section 3 are exposed as MCP tools, and an application that already speaks MCP can keep doing so.

How Extella puts this together: a named program, the name of its language, a handler that can be registered and replaced on each device, and the device chosen in each call. On 2 October 2026 a small language of two statements was registered on a laptop, four programs in it were run, its handler was replaced and the same four programs, not saved again, ran under the new handler; the first handler was then registered on a Linux server, and two of the four programs ran there under it; the laptop, whose last runs were under the second handler, was not called again after that. Every step was a call of the MCP tools save_expert and run_expert [verified; handler_via_mcp.py, handler-via-mcp-2026-10-02.json].

This document describes how Extella connects a stored program, its language, a handler and a chosen device through one calling interface. We have not compared it experimentally with the approaches above.

7. Limits

8. Reproduce

Without an account, call the demo server:

curl -s -X POST https://extella.dev/api/blocks/render -H "Content-Type: application/json" \
  -d '{"device":"second","handler":3,"blocks":["skill_block_quote"],"force":true}'

With Extella installed and signed in (it writes ~/.extella/api_token.txt and ~/.extella/device.txt) and Python 3.8 or newer:

python3 run_tiny.py                                  # the tally example of section 4
curl -sO https://raw.githubusercontent.com/AnvarBakiyev/extella-research/main/cspl/take-home/take_home.py
python3 take_home.py "https://extella.dev/api/blocks/export/skill_block_quote?handler=3" --level render

Appendix. What was run

Date1 October 2026 for the runs listed below; 2 October 2026 for the three-way measurement of section 5
MachineMacBook, macOS, Apple silicon; two Linux x86_64 servers for the block runs
Listenerextella-listener 1.2.5 (Extella desktop app 1.3.0)
Sourceshandler.py, handler_c.py, run_tiny.py, verify_all.py
Raw answersruns-2026-10-01.json: eight runs with time stamps, round-trip times and the device's answers
Measurement of section 5measure3.py, generic_server.py, measure3-result-2026-10-02.json: the script, the general executor and the raw results

verify_all.py repeats the eight runs in order: register the tally handler, run a program, run a rejected program, replace the program and run again, run Go, run Rust, register the C handler, run C.

The runtime was designed by Timur Ryspekov, CTO and co-founder of Extella.