Skip to content

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

← All guides

Personal playbook authoring guide

Official Kody guide

A playbook is private executable code owned by the signed-in user. Its complete text files and metadata live in the application database. package.json is the manifest. There is no Git checkout, community catalog, fork, publish step, or retained history.

Create

Call playbookSave with a complete map of UTF-8 text files. Include package.json and every referenced source or types file. Binary files are not supported. Save validates the manifest, source limits, and execution artifacts before accepting the source. Failure leaves the previous saved source unchanged. Saving does not execute external actions.

import { kody } from 'kody:runtime'

export default async function main() {
	return await kody.playbookSave({
		files: {
			'package.json': JSON.stringify({
				name: '@your-username/hello',
				exports: { '.': './main.ts' },
				kody: {
					description: 'Return a personal greeting.',
					tags: ['example'],
				},
			}),
			'main.ts':
				'export default function main(input: { name: string }) { return { greeting: `Hello ${input.name}` } }',
		},
	})
}

Use the signed-in user's actual username in the manifest. Save returns playbook_id and edit_token. Keep the stable ID for later reads and edits. README.md and AGENTS.md are optional documentation, never save gates.

Edit safely

  1. Call playbookGet({ playbook_id }) for the current complete files, export contracts, and edit_token.
  2. Modify that file map. Preserve every unchanged file you intend to keep.
  3. Call playbookSave({ playbook_id, expected_edit_token: current.edit_token, files: completeFiles }).
  4. Keep the new edit_token from the successful save.

The file map is a complete replacement, not a patch. Omitted files are deleted. An existing ID always requires expected_edit_token; do not create a new playbook as a workaround for a stale-token conflict. On conflict, get the current files again, reconcile the user's intended changes, and save with the new token. Never blindly retry an old replacement against a fresh token.

An edit token is concurrency control, not a version or history entry. No restore or rollback history exists. To undo an edit, read current files, change them back deliberately, then save with the current token.

Manifest and exports

  • name: scoped name @your-username/playbook; its leaf is the URL slug.
  • exports: callable modules, such as { ".": "./main.ts" }.
  • kody.description: concise description, at most 200 characters.
  • kody.tags and optional kody.searchText: personal search metadata.
  • Optional runtime surfaces: kody.jobs, kody.app, kody.subscriptions, kody.retrievers, and kody.webhooks.
  • Declare Worker-compatible npm modules under dependencies.
  • Declare direct static playbook imports under kody.dependencies, using { "@your-username/helpers": "*" }. Dependencies remain owner-scoped and resolve current saved code; there are no publication pins.

Use JSDoc on exported functions (or their declared types file) to explain purpose, inputs, outputs, and an import-and-call example. Search uses it to help choose the right export. Optional README intent and agent notes may help maintenance but are not required.

Run and verify

After a successful save, new runs use current saved code. An already-started run finishes with what it loaded. Inspect playbookGet for the exact call shape, then invoke an export through execute:

import hello from 'kody:@your-username/hello'

export default function main() {
	return hello({ name: 'Ada' })
}

Use read-only smoke tests or a playbook-defined dryRun that genuinely skips external writes. Synthetic invocations have real side effects:

  • Exports: import and call with representative inputs; test expected errors.
  • Apps: playbookAppFetch checks status, headers, body, and storage effects. Browser verification remains necessary for layout and OAuth redirects.
  • Subscriptions: playbookSubscriptionDispatch with a safe fixture.
  • Jobs: begin disabled, test the no-argument scheduled wrapper, then enable.
  • Webhooks: validate authentication, replay protection, and payload handling.

Obtain fresh user confirmation before irreversible external actions. A save, successful check, or dry run is not consent to send, charge, or write.

Permissions and storage

Use existing secret and integration APIs rather than hardcoding credentials. Secret access, host approval, integration allowlists, and runtime isolation still apply. Editing never widens permissions automatically. Resolve required approvals before testing an authenticated call.

Use playbookStorage() for durable personal playbook data. Jobs, exports, apps, and subscriptions share the playbook's storage identity. Do not put runtime state or secrets into source files to bypass these APIs.

Apps and larger workloads

Build app links from playbookContext.hostedUrl and playbookContext.appBasePath; do not hardcode a username or mount prefix. See Playbook apps.

If a dependency cannot fit Worker CPU or memory limits, keep a thin orchestrator and use heavy-work offload. Do not skip validation or attempt to store binary source in the text-file map.

Delete

Use playbookDelete only when the owner requests deletion, with playbook_id and the exact confirm_name returned by inspection. Deletion is permanent and cleans up owned runtime surfaces, grants, storage, and derived search/cache data. It is not hiding, and no retained source history can restore it. See Personal playbook lifecycle.

Working with an agent? This guide is also plain markdown at /guides/playbook-authoring.md, or load it over MCP with search({ entity: 'playbook_authoring:guide' }).