# Personal playbook authoring

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.

```ts
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`:

```ts
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](/guides/playbook-apps).

If a dependency cannot fit Worker CPU or memory limits, keep a thin orchestrator
and use [heavy-work offload](/guides/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](/guides/playbook-lifecycle).
