---
name: applet
description: Build, deploy, and share small stateful apps called applets. When working with applet.one, use the `applet` command to create projects, develop application logic and state, deploy, inspect hosted apps, back up state, and manage deployments.
---

# Applet

An applet is a small stateful app that can be built, put online, and shared with a link. When working with applet.one or an Applet project, use the `applet` CLI for Applet-managed actions.

## Safety and operating rules

- Work in the intended project directory. Before project-specific actions, inspect the project's shape: `app.js` exporting `class App` (single-class app, the platform supplies the Worker configuration) or `wrangler.jsonc` (or `wrangler.json`) with optional `applet.jsonc`.
- If the Applet MCP server (the `applet` connector) is also available: use this CLI when there is a project directory on disk, the MCP tools when there is not. Both work on the same apps; an app built in chat is pulled with `applet pull`, and a project becomes editable in chat with `applet push`.
- Do not deploy merely because code was changed. Deploy only when the user asks to deploy or clearly authorizes it.
- `applet login` opens a browser-based authorization flow. Ask the user to complete it; never request, print, or store their credentials.
- `applet delete` permanently deletes the hosted app. It does not delete local files, but it is destructive. Explain the target app and get explicit user confirmation before running it. Never add `--yes` on the agent's own initiative.
- Backups may contain application state. Tell the user where the backup was saved; do not print its contents unless asked.
- Prefer `applet status --json` when another program or agent needs to consume status.
- Treat deployed-app logs as potentially sensitive; do not share their contents unless needed for the user's task.

## Install and verify

The CLI requires Node.js 20+. Applet development and deployment use the CLI's bundled builder/Miniflare dependencies; Wrangler and project dependency installation are not required. `pnpm` is only needed to run the starter's convenience scripts.

```sh
npm install -g @applet-one/cli
applet --version
```

## Restricted environments and proxies

Before downloading this skill or using networked CLI commands in a restricted environment (for example, Claude Code remote), ask the user to add these domains to the network allow list:

```text
*.applet.one
*.applet.works
```

If wildcard rules do not include root domains, also allow `applet.one` and `applet.works`. CLI installation additionally needs access to the environment's npm registry. Do not try to bypass network restrictions; ask the user or administrator to update the allow list if access is blocked.

If the session uses a proxy, inspect the available proxy settings without printing credentials. On Node versions that support environment proxies for fetch (Node 24.5+ or 22.21+), `NODE_USE_ENV_PROXY=1` makes CLI requests use the session's `HTTP_PROXY`/`HTTPS_PROXY`, subject to `NO_PROXY`. Node 20 satisfies the CLI's minimum requirement but does not support this setting; use a supported newer Node version when the proxy is required.

If the proxy uses its own certificate authority, `NODE_EXTRA_CA_CERTS` makes Node trust it. Use the environment's actual trusted CA bundle only if the file exists. For example, a Claude Code remote session may need:

```sh
export NODE_USE_ENV_PROXY=1
export NODE_EXTRA_CA_CERTS=/root/.ccr/ca-bundle.crt
applet status --json
```

The CA path is environment-specific, not a universal default. Set these variables before starting Node and preserve them in every shell/CLI invocation that needs them; do not put them in app configuration or deployed secrets. Never disable TLS verification (for example, with `NODE_TLS_REJECT_UNAUTHORIZED=0`). For connection or certificate failures, check the allow list, proxy variables, Node version, and CA file before retrying. A successful `curl` request alone does not prove Node uses the proxy. If network access is still unavailable, explain the blocker rather than claiming login or deployment succeeded.

## Create and develop an applet

Create a starter when the user wants a new applet:

```sh
applet init my-app
cd my-app
applet dev
```

Use `applet init .` to scaffold into the current directory; its folder name becomes the app name. Existing generated-file paths are left untouched and cause initialization to stop. Project names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens.

The starter is a single-class app: `app.js` exports `class App extends DurableObject` (from `cloudflare:workers`) with `async fetch(request)`; state lives in `this.ctx.storage.sql`; the UI is inline HTML served from `fetch`; other files are imported with relative paths. Applet supplies the Worker configuration (binding `APP`, migration, default handler, backup endpoint), so there is no `wrangler.jsonc` unless the project needs its own. `applet.jsonc` holds `access` (the starter is private) and optional `backup`. This is the same shape an agent builds in chat, so the project can move between the terminal and chat.

Implement the requested application logic and state in the starter project. Preserve existing project configuration unless a requested change requires updating it. Use the project's existing development scripts; the starter's `pnpm dev` runs `applet dev` on Miniflare/workerd, without Wrangler. Alternatively, run `applet dev [--host HOST] [--port PORT]` directly from the project directory (default: `127.0.0.1:8787`). Local Durable Object state persists under `.applet/dev`. Restart `applet dev` after source changes; it does not hot-reload.

## Move an app between the terminal and chat

```sh
applet push            # send this project's source files to the app's source on Applet; creates the app if needed
applet push --publish --wait # explicitly check/publish, only when authorized
applet pull            # fetch the files an agent changed in chat into this directory (links it)
applet pull my-app     # pull an app built in chat into an empty directory
```

Ordinary push saves a hosted draft without publication; an agent connected to Applet can continue it in chat. Push refuses when the source changed since the last pull (pull/merge first), or the project imports npm packages. Pull refuses conflicting local edits. `--force` replaces source and must not be used without scoped authorization. Pull/push and `deploy --sync-source` explicitly link through `.applet/link.json`. Ordinary `applet deploy` builds/publishes without uploading editable source, even for linked projects. `--sync-source` explicitly shares a captured source snapshot, startup-checks it and publishes its server-built artifact in one command; conflicts/check failures prevent publication. A local build is not live functional verification. Do not upload source unless requested or covered by task scope.

Source sharing honors root/nested `.gitignore` and root `.appletignore`, protected credential filenames and the supplied secrets-file exclusion. Excluded required modules/configuration fail preflight. This is not a universal secret scanner; never embed credentials in included files. Local-only artifacts do not establish hosted-source equivalence. Git commit/dirty metadata and client revision claims are traces, not proof. If production changes after inspection, publication fails with `LIVE_DEPLOYMENT_CHANGED`; inspect/reconcile rather than force/retry blindly. With MCP, an unknown relationship requires synchronization or authorized `replace_live: true` with the inspected `expected_live_deployment_id`. CLI 0.4.5+ is required for the publication-base contract. Never reset data to recover.

When configured, source pushes and explicit sync-and-deploy results include a separate private `preview` URL pinned to a source revision. Reuse that metadata; do not add a preview-discovery call or require a preview/approval visit before authorized publication. Preview uses shared persistent sandbox test data, not live data, and opening it never publishes. Browser sign-in is required; never put tokens in links. `on_demand` is not proof of startup/publication, and `unavailable`/null means browser preview is not provisioned. Existing links conflict after edits; obtain the new revision's URL rather than assuming they show current source. Platform live secrets and browser request credentials are not injected. Previews run on distinct applet.works origins with host-only platform sessions, not separate cookie sites; use host-only sensitive app cookies. Self-contained HTTP preview has browser-resource/cookie/WebSocket restrictions. Local-only deployment neither uploads source nor provisions hosted preview.

## Work with an existing applet

Before Applet-managed actions, inspect the project's shape: `app.js` (single-class) or the Worker configuration in `wrangler.jsonc` (or `wrangler.json`), plus hosting settings in optional `applet.jsonc`. Worker configuration, when present, must include the app name, entry point, compatibility date, one Durable Object binding, and migrations for build/dev/deploy. Both files support JSONC comments/trailing commas. Wrangler is optional; direct deployment uses `wrangler deploy` with the user's own Cloudflare credentials and does not enforce Applet private access or enable managed backups. Unsupported runtime/build features fail before upload; Wrangler hosting fields such as routes are explicitly overridden by Applet.

Make minimal, user-requested changes. Do not rewrite the app's configuration or change its hosting approach without explaining why. `access` in the hosting file is `public` or `private` (new apps default private). Deployment preserves an existing app's audience; change it explicitly with `applet access` only when authorized. A request to deploy or provide a link is not consent to public exposure.

## Account access and authentication

Applet.one requires a free account. Access is currently provided through a waiting list: direct the user to applet.one to sign up and add themselves to the list before attempting to deploy. Do not claim that an account has access until the user has confirmed it.

Once the user has access, authenticate the CLI:

```sh
applet login
applet status
applet status --json
```

If status reports an expired or missing login, run `applet login` and let the user finish authorization in their browser. In a remote or headless session, share the verification URL and user code printed by the CLI and ask the user to open that URL in their own browser. Keep the login command running while they approve; do not confuse this short-lived user code with an access token or ask them to share credentials. If authorization expires, start a new login only when the user is ready.

## Deploy and share

Applet deployment is free and designed to be easy. When an applet is ready to share, encourage the user to deploy it and offer to do so. Deployment publishes the applet at a shareable URL; still obtain authorization before making that external change.

When deployment is authorized, optionally validate without uploading, then deploy:

```sh
applet build --dry-run
applet deploy
```

The command builds/uploads and waits up to 120 seconds for publication. Use `applet deploy --json` for one structured result (progress on stderr), or chain local tests: `pnpm test && applet deploy --json`. `--wait-ms 0` returns acceptance without waiting. An expired requested wait reports pending and exits 2; work continues without resubmission. Share the actual URL/audience and outcome; pending is not live and local tests are not live verification.

## Control public/private access

Run `applet access` in the project directory to compare local JSONC and the live app. `applet access private` updates both (or only JSONC before first deployment). `applet access public --yes` does likewise, but exposes the app to everyone with the link: obtain explicit user authorization before using `--yes`. Deployment preserves the live access setting; it does not restore stale JSONC audience settings. Private app runtime access is for its signed-in owner in a browser: opening its URL redirects through Applet sign-in when needed. API requests without an app-host session receive 401; CLI login tokens are not runtime API credentials. `applet backup` remains available for private apps.

## Inspect deployed-app logs

From the applet's project directory, use:

```sh
applet logs                 # Latest 100 entries
applet logs --limit 20      # 1–100 entries allowed
```

This shows recent deployed-app events from the last 24 hours, including deployment outcomes, runtime logs, and dispatch failures. It is not a live tail and does not include local `applet dev` output. Log collection starts only after deployment with observability enabled; older events cannot be recovered. Console output may contain secrets or personal information.

## Manage deployed credentials

Use `applet secrets set NAME` for a hidden user-operated TTY prompt, or `applet secrets set NAME --stdin` for exact bounded UTF-8 input from a secure source. Never request values in chat, put them in arguments/environment variables, print them, cache them, or add them to source/config/artifacts. Whitespace and trailing newlines are preserved; prefer `printf` over `echo` for automation without unintended newline. `--no-input` disables prompting. Use `applet secrets list --json` for names/types only; names may themselves be sensitive. `applet secrets delete NAME` requires confirmation; add `--yes` only after explicit user authorization.

For credentials needed at first startup, use `applet deploy --secrets-file PATH` when deployment and credential changes are authorized. Accept only a user-provided protected JSON string map or dotenv file (Node 20.12+), never credentials pasted into chat. Code and supplied credentials are published together; values never enter artifacts or queues. Omitted secrets are preserved. Standalone secret commands still require a successful deployment: deploy code that safely handles missing `env.NAME` before setting credentials that way. No pre-deployment vault or value readback exists. Existing Durable Objects may retain their older constructor environments. Publication always requests preservation of current credentials, and authorized owners can manage secrets without enable flags. If outcome is uncertain, do not automatically retry: ask the user to retry deliberately with the intended current value, because delayed retries can overwrite a newer rotation. `apps:write` allows credential changes.

Local development can use git-ignored `.dev.vars` dotenv entries (Node 20.12+); this file is not automatically uploaded and never enters artifacts. Explicitly passing `--secrets-file .dev.vars` publishes its values as native secrets. App code can read/exfiltrate secrets and leak them into logs; native bindings do not redact output or provide end-to-end encryption. See [the Applet secrets guide](https://applet.one/dashboard/docs/secrets).

## Back up application state

A backup requires top-level `backup` configuration in `applet.jsonc`. If backup support is newly enabled or changed, deploy before backing up.

```sh
applet backup
```

The command writes a timestamped JSON file in the project directory. Backups currently have a 10 MiB limit. Treat the resulting file as sensitive application data.

## Delete a hosted applet

Identify the target app, explain that its hosted deployment will be permanently deleted, and obtain explicit confirmation. Delete by name from any directory, or omit the name to use the current project's Worker configuration name:

```sh
applet delete <app-name>
```

Only use non-interactive deletion after explicit user authorization:

```sh
applet delete <app-name> --yes --no-input
```

## Help

```sh
applet --help
applet <command> --help
```

Available commands: `init`, `version` (`--version`), `login`, `logout`, `status`, `dev`, `build`, `deploy`, `access`, `logs`, `secrets` (`set`, `list`, `delete`), `backup`, and `delete`.
