Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

← All guides

Offload work that does not fit a Worker isolate

Official Kody guide

Kody packages run on Cloudflare Workers. Publish checks and artifact rebuilds bundle every declared npm dependency inside a short-lived isolate. A dependency graph that is fine in ad hoc execute can still fail those checks with an isolate memory or CPU reset.

Kody does not host containers or long-running processes for a package. The owner operates that process. The saved package stays a thin orchestrator: authenticate, call the process, store results, notify. See No package services primitive.

Load this guide when:

  • repo_run_checks or publish artifact rebuild reports that bundle validation exceeded the isolated runner's memory or CPU limits
  • a Worker-compatible library is too large to bundle (PDF.js / unpdf, native addons, browsers, multi-minute CPU, large WASM)
  • you are about to vendor or dynamically import the same graph to "get around" the check — that still bundles it

Do not use this guide for CJS/ESM helper interop (tslib / import_tslib.default), missing exports, typecheck failures, or host-approval errors. Those are different failures.

The pattern

  1. Keep the Kody package. It owns secrets, storage, jobs, and the callable surface.
  2. Stop and show the owner a plan before creating paid compute. They create the process (Cloudflare Container, Fly machine, or a box they already run). Do not open a cloud account or start a machine from execute.
  3. The process exposes a narrow HTTPS API or MCP server. Prefer one job (extract text, render a page) over an unrestricted shell.
  4. Save the base URL and a bearer token as secrets. Mount them on the package. Ask the owner to approve the fetch host.
  5. The package fetches that URL (or calls kody.mcp["name"] for an MCP server). It does not import the heavy library.

A home or LAN process uses the home MCP guide instead of a public container.

What stays in the package

  • Input collection (email attachment, storage object, upload)
  • Auth to the owner's process (mounted secret, host approval)
  • fetch or MCP call with a hard timeout and a size cap
  • Result write to packageStorage() or a follow-up notification
  • Jobs and subscriptions that trigger the work
export default async function extractInvoiceText(input: { objectKey: string }) {
	const response = await fetch('https://extractor.example.com/extract', {
		method: 'POST',
		headers: {
			authorization: 'Bearer {{secret:invoiceExtractorToken}}',
			'content-type': 'application/json',
		},
		body: JSON.stringify({ objectKey: input.objectKey }),
		signal: AbortSignal.timeout(30_000),
	})
	if (!response.ok) {
		throw new Error(`Extractor returned ${response.status}.`)
	}
	const contentLength = Number(response.headers.get('content-length'))
	if (Number.isFinite(contentLength) && contentLength > 200_000) {
		throw new Error('Extractor response exceeded 200 KB.')
	}
	const body = await response.text()
	if (new TextEncoder().encode(body).byteLength > 200_000) {
		throw new Error('Extractor response exceeded 200 KB.')
	}
	return JSON.parse(body) as { text: string }
}

Replace the example origin with the owner's process and approve that host before calling it. Keep the bearer token in a saved secret.

What does not stay in the package

  • unpdf, pdfjs-dist, Playwright, native addons, or other graphs that blow the isolate
  • "Make the import dynamic so checks skip it" — checks still bundle declared dependencies
  • A Kody-owned container binding or package service

Ad hoc execute skips publish checks, so a large import can appear to work there and still be unpublishable. Treat execute success as a prototype, not a publish signal.

Owner-operated runtimes

These are examples, not a Kody product surface. The owner picks one and pays it:

  • Cloudflare Containers — a container next to Workers, called over HTTPS
  • Fly Machines — a small always-on or scale-to-zero process
  • An existing box — home NAS, VPS, or CI runner with a locked-down API

Write the extractor as a small HTTP service. Cap request body size and page count. Return structured text, not a raw PDF.js handle.

Secrets and approval

  1. Create the URL and token secrets through /account/secrets/new (see secret-backed integration).
  2. Declare them on the package (kody.secretMounts or {{secret:name}}).
  3. Stop and send the owner the host-approval and package-approval links. Do not retry a blocked host.
  4. Smoke-test the published export with a small fixture, not a 50 MB invoice.

If the isolate-limit error is a surprise

The check message points here on purpose. Typical causes:

  • A large npm dependency, even unused by some exports — every bundle target that imports it pays the cost
  • Vendored node_modules or generated data files in the repo
  • Twenty exports each inlining the same heavy graph

Fix: remove the heavy dependency from the package, move that work to the owner's process, and keep the Kody side to the snippet above.

Working with an agent? This guide is also plain markdown at /guides/heavy-work-offload.md, or load it over MCP with coding_guide_get({ guide: 'heavy_work_offload' }).