client.functions
A serverless function is developer-authored code that runs on the
accelerator. You write a single-module ES worker (export default { fetch }),
deploy it, and invoke it one of two ways: over HTTP at its own subdomain, or
bound to a Space so it runs on messages (the same model
as a Programmable Agent, but your code is the “brain”
instead of an LLM). Your client only manages functions — they execute on the
accelerator.
How it runs
Section titled “How it runs”- Compute-only (v1). A function is an untrusted, isolated worker with no privileged platform bindings. It talks to the platform like any external client and acts on behalf of the invoking user (its session is passed through). It cannot reach another app’s data.
- Encrypted at rest, JIT-decrypted. Your source is stored encrypted and decrypted only at invocation time, when it’s uploaded to the runtime. An idle function is torn down automatically and re-uploaded on the next call — so the first request after a cold period is a little slower (a one-time upload), then warm calls are fast.
Triggers
Section titled “Triggers”A function declares either or both triggers (toggle them any time from the editor):
http— the function is reachable athttps://<name>--<app-slug>.fns.<zone>/and receives the full request. It owns its own routes and CORS.space— the function is invoked on messages in Spaces you enable it on. It receives the decrypted message as input and its HTTP response body is posted back to the Space as a signed reply (an empty body /204stays silent). Matching uses the samekeyword/regex/alwaysrules as agents.
Methods
Section titled “Methods”// List the app's functions.client.functions.list(appId, opts?): Promise<FunctionConfig[]>
// Read one function's config.client.functions.get(appId, functionId, opts?): Promise<{ config: FunctionConfig }>
// Read a function's decrypted source (for an editor UI).client.functions.code(appId, functionId, opts?): Promise<{ functionId: string; code: string; codeHash: string | null }>
// Deploy (create) a function (owner/editor; paid tier).client.functions.deploy(appId, input, opts?): Promise<{ config: FunctionConfig }>
// Update editor-settable fields and/or redeploy the `code`.client.functions.update(appId, functionId, patch, opts?): Promise<{ config: FunctionConfig }>
// Delete a function (also tears down its deployed script + identity).client.functions.delete(appId, functionId, opts?): Promise<{ deleted: boolean }>
// Enable / disable the function on a specific Space (per-Space opt-in).client.functions.enable(appId, functionId, spaceId, opts?): Promise<{ config: FunctionConfig }>client.functions.disable(appId, functionId, spaceId, opts?): Promise<{ config: FunctionConfig }>opts is { space?: string } — a non-owner editor passes the app’s management
Space id for delegated access; the owner can omit it.
Example
Section titled “Example”// 1. Deploy an HTTP function (only an app owner / editor on a paid plan can).const { config } = await client.functions.deploy(appId, { name: "hello", // DNS-safe slug — the function's subdomain label displayName: "Hello", code: `export default { async fetch(request) { return new Response("Hello from your Muhkoo function!"); }, };`, triggers: { http: { enabled: true } },});
// 2. Call it — reachable at its own subdomain.// https://hello--<app-slug>.fns.<zone>/
// 3. (Optional) also run it on a Space's messages.await client.functions.update(appId, config.functionId, { triggers: { http: { enabled: true }, space: { match: [{ type: "always" }] } },});await client.functions.enable(appId, config.functionId, channelSpaceId);Configuration
Section titled “Configuration”FunctionConfig
Section titled “FunctionConfig”interface FunctionConfig { functionId: string; name: string; // DNS-safe slug; the subdomain label + script name displayName: string; triggers: FunctionTriggers; enabledSpaces: string[]; // Spaces the `space` trigger is active on caps: FunctionCaps; scriptName: string; codeHash?: string; // sha-256 of the last-deployed source deployedAt?: number; createdAt: number; updatedAt: number;}
interface FunctionTriggers { http?: { enabled: boolean; methods?: string[] }; // own-subdomain HTTP space?: { match: FunctionTrigger[] }; // invoked on Space messages}
interface FunctionTrigger { type: "keyword" | "regex" | "always"; pattern?: string; // required for "keyword" / "regex"}
interface FunctionCaps { cpuMs: number; // per-invocation CPU ceiling (clamped by plan) subRequests: number; // per-invocation subrequest ceiling (clamped by plan) dailyInvocationBudget: number; // hard daily circuit-breaker (0 = unlimited)}FunctionDeployInput is { name, displayName, code, triggers?, caps? };
FunctionUpdateInput is a partial of it (include code to redeploy the source).
A function with no triggers defaults to HTTP-only.
The Space-event contract
Section titled “The Space-event contract”When a Space-bound function fires, the accelerator dispatches a request to it:
POST /_muhkoo/eventX-Muhkoo-Event: space.message{ "type": "space.message", "spaceId": "…", "sender": "…", "text": "…", "functionId": "…" }A non-empty response body becomes the reply posted to the Space (a JSON
{ "reply": "…" } envelope is also honored); an empty body or 204 stays
silent.
Cost & billing
Section titled “Cost & billing”Each invocation is metered to your account as a request, and each function
has a hard caps.dailyInvocationBudget circuit breaker. Per-invocation
cpuMs / subRequests are clamped to your plan’s ceiling.