axon

Questions

Answers, not fog.

If something here is vague, it is a bug in the page. The limits below are the limits the Worker actually enforces.

What is a logic coprocessor?

A small, deterministic service that does the part of a task a language model is worst at: exact computation. Your agent sends code, axon runs it, your agent gets a typed JSON value back. It is a coprocessor in the old sense: a second unit that handles one class of instruction so the main unit does not have to.

Is my code safe to send?

Your code runs inside QuickJS, a JavaScript engine compiled to WebAssembly, not inside Node and not inside the Worker's own isolate. From inside the sandbox there is no fetch, no filesystem, no process, no require, no environment and no shared memory with another request. Each call gets a new runtime and a new 8 MB heap (configurable up to 32 MB), and every handle is disposed before the response leaves.

That protects the platform from your code. It does not make arbitrary code harmless to you: if you paste a secret into the code field, it is in the request. Do not do that. The sandbox has no access to secrets because it has no access to anything.

What are the limits?

LimitValueNotes
CPU per request10 ms publishedCloudflare free plan. Measured calls above it were served, but do not rely on that: keep work small.
Request body64 KBChecked on the stream, not only on Content-Length.
Code size32 KBUTF-8 bytes.
Deadline750 msUpper bound, clamped to 50..1500. In practice the fixed CPU budget stops a runaway loop first.
Heap8 MB defaultClamped to 4..32 MB per call. A deliberate allocation bomb returns MEMORY_LIMIT, not a platform kill.
Modules10Whole graph, 1 MB total, depth 2.
Concurrency4Per isolate, 64 queued, 2 s maximum wait.
Rate30 / 60 sBurst 10, per IP, per colo, best effort.
Daily requests100,000Cloudflare free plan, account wide.

Why the free tier?

Because the useful version of this idea fits in it, and a paid plan would force a different product: queues, durable sessions, long jobs. axon is deliberately the other thing. Ten milliseconds of CPU is a lot of arithmetic and a very small amount of video encoding. If you need the second one, this is the wrong service.

Which packages work?

Any package that esm.sh can resolve and bundle as ESM, subject to the CPU budget. Small and medium libraries work: lodash, zod, nanoid, small utilities, and submodules of large ones such as date-fns/addDays. A full import _ from 'lodash' costs 44 to 120 ms of CPU on this build, because QuickJS has to parse the whole 82 KB bundle. Import a submodule instead (lodash/chunk) and it is a fraction of that. A package whose root is a barrel of hundreds of files, such as date-fns itself, is refused with MODULE_NOT_FOUND once the graph passes 10 modules. A full UI framework, a parser generator or a crypto suite is likely to exceed the instruction budget and return EXEC_TIMEOUT.

The Worker fetches https://esm.sh/<package>?bundle&target=es2022, follows at most two levels of imports, stores the result in the isolate and in the Cloudflare cache, then hands QuickJS a synchronous map of sources. That is why the second call for the same package is much cheaper than the first.

What does not work?

  • Filesystem, sockets, subprocesses, environment variables.
  • Node builtins, including node:fs, node:http and path.
  • State between calls. There is no storage API inside the sandbox.
  • Top-level await in modules. The runtime is the synchronous QuickJS build.
  • DOM, window, document, browser storage.
  • Heavy compute. See the CPU row above.

Why esm.sh?

It returns one bundled file per package instead of a graph of relative imports, which keeps the number of subrequests low and makes caching effective. It also serves plain ESM, which is what QuickJS wants, without a build step on our side. The origin is fixed and only reachable by the Worker, never by the sandbox.

How bad is the cold start?

The wasm module is compiled once per isolate and reused, so the first request in a new isolate pays for instantiation, and later ones do not. On the free plan an idle isolate is evicted, so a quiet endpoint will occasionally look slower. Measured warm, a trivial call is 3 to 9 ms of CPU and 10 ms at the median wall time; a cold isolate is the difference you see. Time it from your client, or read cpuTime in wrangler tail: Workers freezes the clock inside a request, so a server side duration field would always read zero.

What about rate limits?

There are two layers: Cloudflare's Workers rate-limit binding (30 requests per 60 seconds per IP, per location) and a token bucket of 10 per isolate. Both are best effort. Measured on this deployment, one 25-request burst produced 11 successes and 14 429, while another run of 40 parallel and 80 sequential requests all passed, because requests are spread across isolates and machines and no counter is global. Treat the limit as abuse mitigation, not a quota.

There is no global counter because Queues and Durable Objects are paid products and using them would break the "free, no account" promise. The service answers 429 with Retry-After rather than dropping requests. If you need a hard quota, self-host and put your own limiter in front.

Do you keep my code?

No. The Worker does not write request bodies anywhere and does not log them. There is no database, no bucket and no queue in this deployment. Cloudflare's own request logs and error reports exist at the platform level, as they do for any website, but the code you send is not copied into a store by axon.

Can I self-host it?

Yes. The repository is MIT licensed, the Worker has no paid bindings, and deployment is three commands. See Self-host in the docs.

Is there an SLA?

No. It is a free, best-effort service on a free plan, with no uptime commitment and no support contract. If you need one, self-host or talk to the studio.

Who runs this?

LPP Development Studio, the independent studio of Quentin Mouilhaud, in France. See About and License.