# Kazi Kazi deploys and invokes small JavaScript functions in fresh V8 runtimes. Canonical API contract: /openapi.yaml Human documentation: / and the repository README.md This guide: /llm.txt (also available at /llms.txt) ## Authentication All function list, deploy, and invocation endpoints require a verified Worklyn identity. For programmatic use, send a Worklyn session token or PAT: Authorization: Bearer Kazi sends that credential to worklyn.me/verify and derives the owner userId from the verified response. Never send or invent a userId in a deployment body. Function ownership cannot be selected by the caller. Browser requests with an Origin header are accepted only from HTTPS worklyn.com/worklyn.me domains and their subdomains, plus the configured loopback origin during local development. CLI and server-to-server requests normally have no Origin and remain authorized by their verified Worklyn Bearer. For browser use, open / and choose "Login with Worklyn". Kazi exchanges the one-shot Worklyn auth code server-side and keeps the Worklyn bearer out of browser JavaScript. ## Function format A deployment is one complete JavaScript function expression: async function (input, context) { return { received: input, userId: context.userId, functionName: context.functionName, version: context.version, }; } Arguments: - input: any JSON value sent as the invocation request body - context.userId: verified Worklyn owner/invoker ID - context.functionName: deployed function name - context.version: immutable source version The function may return a JSON-serializable value or a Promise of one. undefined becomes null. Throwing or rejecting fails the invocation. Do not send an ES module, imports, TypeScript, a CommonJS module, or surrounding application code. Bundle any dependencies into the single function expression before deployment. ## Deploy POST /api/functions Authorization: Bearer Content-Type: application/json { "name": "hello", "atomId": "", "source": "async function (input, context) { return { message: `Hello ${input.name}`, version: context.version }; }" } Names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens. Maximum source size is 512 KiB. Kazi compiles the function, stores an immutable source version in Azure Blob, and updates the current manifest. The authenticated Worklyn user becomes the owner. For functions built as part of an atom-scoped task or application, atomId is required: Kazi verifies the caller can access that parent and creates or updates a type `tool` child atom. The tool atom contains safe deployment metadata and a deep link to `/?view=functions&atom=&function=`; it never contains source code or credentials. Omit atomId only when the function is intentionally account-global. If the host was explicitly started with KAZI_BLOB_OFFLINE=1, the dashboard and documentation work but deployment and invocation storage are unavailable. This mode is for local UI inspection only. ## List the authenticated user's functions GET /api/functions Authorization: Bearer The response includes deployment metadata and process-local invocation statistics. It never lists another Worklyn user's functions. Add `?atomId=` to list only functions attached to one atom. ## Invoke POST /functions/hello Authorization: Bearer Content-Type: application/json {"name":"Thandi"} The authenticated user may invoke only a function with that name in their own workspace. There is no ownerId query or body override. ## Register a public application After deploying every function used by an application, register the public actions: POST /api/apps Authorization: Bearer Content-Type: application/json { "name": "Invoice helper", "actions": { "calculate": "invoice-calculator", "send": "send-invoice" } } The response contains an appId and proxyPaths. Public action names map server-side to private functions. Put the appId/action path in frontend code; it is an identifier, not a secret. Generated browser applications MUST call only the returned root-relative Desk proxy path: await fetch("/cloud/kazi/apps/app_.../actions/calculate", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(input), }); Never call kazi.worklyn.com directly from generated browser code. Never include a Worklyn PAT/session, ownerId, functionName, Azure key, or Kazi gateway secret in public files. Desk issues an HttpOnly anonymous visitor session when it serves the initial HTML and signs the proxy request to Kazi. ## Supported JavaScript APIs Language and async: ECMAScript built-ins from V8, Promise, async/await, JSON, Date, Math, RegExp, Map, Set, ArrayBuffer, and typed arrays. Web APIs: URL, URLSearchParams, TextEncoder, TextDecoder, encoding streams, Event, EventTarget, CustomEvent, ErrorEvent, AbortController, AbortSignal, timers, performance.now, ReadableStream, WritableStream, TransformStream, queuing strategies, atob, btoa, DOMException, Blob, File, Headers, FormData, Request, Response, and fetch. Crypto: crypto.randomUUID, crypto.getRandomValues, crypto.subtle, Crypto, CryptoKey, and SubtleCrypto. Diagnostics: console.log, console.info, console.warn, console.error, and console.debug write to Kazi process logs. ## Scoped persistent KV Every invocation has `kazi.kv`. Kazi supplies the owner and scope; function code supplies only its key suffix and cannot access another user or app. async function (input) { const count = (await kazi.kv.get(["visits"])) ?? 0; await kazi.kv.set(["visits"], count + 1); return { visits: count + 1 }; } Supported methods: - await kazi.kv.get(key) -> JSON value or null - await kazi.kv.set(key, JSON value) -> { versionstamp } - await kazi.kv.delete(key) - await kazi.kv.list(prefix, { limit: 100 }) -> [{ key, value, versionstamp }] Keys are arrays of 1-16 non-empty string parts, each at most 256 bytes. Values must be JSON-serializable and at most 64 KiB. Public app actions share one app-scoped namespace. Direct function calls use a function-scoped namespace. ## Timed and recurring work Do not put Deno.cron, setInterval, or a long timer inside a Kazi function. A Kazi isolate is dropped after one invocation and the Deno namespace is not exposed. Register the schedule with Kazi's durable host scheduler instead. POST /api/schedules Authorization: Bearer Content-Type: application/json { "name": "Daily cleanup", "functionName": "cleanup", "cron": "0 1 * * *", "input": { "retentionDays": 30 }, "enabled": true } Cron uses five UTC fields: minute, hour, day-of-month, month, day-of-week. Prefer named weekdays such as MON-FRI. Kazi durably advances the schedule, prevents the same schedule from overlapping itself, starts a fresh V8 isolate for each occurrence, records running/succeeded/failed/timed_out state, and exposes run history at GET /api/schedules//runs. Run the Kazi scheduler as a separate process with KAZI_MODE=scheduler. The HTTP/API process does not execute due schedules itself. Scheduled functions receive context.trigger="schedule", context.scheduleId, context.runId, context.scheduledAt, and context.attempt. Use context.runId as an idempotency key for external side effects. The scheduled invocation uses the same function-scoped kazi.kv namespace as direct invocation. ## Unsupported APIs Node.js process, Buffer, require, node:* modules, Deno APIs, filesystem access, environment variables, child processes, shell commands, native addons, npm loading, CommonJS, ES module imports, remote imports, and TypeScript compilation are not supported. JavaScript globals never persist between invocations. ## Limits and security Defaults are a 5-second wall-clock timeout and 64 MiB V8 heap. The input limit is 1 MiB. Functions currently have unrestricted outbound fetch. Do not assume a V8 runtime is a kernel or VM security boundary. Kazi should run inside an outer VM sandbox before accepting hostile public code. Browser sessions are process-local and last up to 24 hours. A Kazi restart requires browser users to log in again. Programmatic bearer requests are verified on every request.