# Nook

Nook is Tau's bundled Cloudflare-backed static mini-app platform. It deploys static directories to path-based site URLs and gives each site a small same-origin JSON KV API exposed through `window.nook`.

V0 scope is intentionally narrow:

- Cloudflare only: one Worker, R2 assets, a global Registry Durable Object, and one Site Durable Object per site.
- Static assets only. Build locally first, then deploy the output directory.
- Templates are Nook-hosted editable directories. Copy them locally, modify/build normally, then deploy explicitly.
- Sites live at `https://<nook-domain>/<site>/`; there are no wildcard subdomain app URLs or `workers.dev` fallback.
- Deploys are private by default. `--public` makes the active deployment public; omitting it on the next deploy makes the active deployment private again.
- Browser KV is per-site JSON state. It survives redeploys and is public-writable when the active deployment is public.

## setup

Install Wrangler yourself and authenticate it non-interactively with `CLOUDFLARE_API_TOKEN`.

```sh
tau nook setup \
  --domain nook.example.com \
  --zone-name example.com \
  --access-team-domain https://team.cloudflareaccess.com \
  --access-aud <access-application-audience>
```

Setup deploys the bundled Worker as `tau-nook`, creates the `tau-nook-assets` R2 bucket where possible, and prints the Tau config block to add after you create a Cloudflare Access service token:

```json
{
  "nook": {
    "domain": "nook.example.com",
    "accessClientId": "...",
    "accessClientSecretEnv": "NOOK_ACCESS_CLIENT_SECRET"
  }
}
```

DNS and Cloudflare Access applications/policies are external V0 setup steps. Setup configures a Worker route for `nook.example.com` in the supplied Cloudflare zone. Configure one self-hosted Access application for `https://nook.example.com/__nook/*`, not the complete hostname. Disable the application's Cookie Path Attribute so its `CF_Authorization` cookie is scoped to the hostname. Add the user Allow policies needed for private sites and a Service Auth policy for the service token used by Tau.

The setup command writes the Access team domain and application audience into the Worker environment. Public site paths do not match the Access application and reach the Worker anonymously. Private sites redirect unauthenticated browser navigation through `/__nook/auth`; after Access login, the Worker validates the hostname-scoped JWT and returns the browser to the site. The Worker loads the Access JWKS from the configured team domain and checks every JWT's issuer, audience, expiry, and signature. Tau sends service-token headers to Cloudflare Access for control-plane API calls, but the Worker never treats raw service-token headers as authentication.

Destroy is intentionally explicit:

```sh
tau nook destroy \
  --domain nook.example.com \
  --access-client-id <cloudflare-access-client-id> \
  --access-client-secret <cloudflare-access-client-secret> \
  --yes
```

Destroy first calls `https://<domain>/__nook/api/destroy` through Cloudflare Access to delete site Durable Object data and R2 objects, then deletes the Worker and R2 bucket with Wrangler. The Access client id and secret can also come from `NOOK_ACCESS_CLIENT_ID` and `NOOK_ACCESS_CLIENT_SECRET`.

## deploy

```sh
tau nook deploy ./dist --site demo
tau nook deploy ./dist --site demo --public
mkdir restored-demo
tau nook copy demo ./restored-demo
```

Deploy requirements:

- `index.html` is required at the root.
- Hidden files and directories are rejected, including `.env`, `.git`, and `.DS_Store`.
- Symlinks are rejected.
- `/__nook/*` is reserved and cannot be deployed.
- Site slugs are lowercase path labels with letters, numbers, and hyphens.
- Apps should use relative asset URLs or be built with a base path of `/<site>/`.
- Successful deploys exactly replace the active static asset set. KV data survives.
- Uploads are checked against the manifest byte size and SHA-256 digest.
- Each site can have at most three non-expired pending deploy sessions.
- Deployed asset URLs remain stable across deploys, so responses require cache revalidation.
- `copy` downloads the active deployment into an existing empty directory and verifies every file against its manifest. Site KV is not copied.

## templates

Templates are reusable directory snapshots stored in the configured Nook backend. They are not deployed directly and do not perform variable substitution or builds.

```sh
tau nook template list
tau nook template save starter ./app
tau nook template copy starter ./next-app
tau nook template delete starter
```

`save` creates or replaces the named template from a local directory. `copy` requires the destination directory to already exist and be empty, then writes the template there so you can edit it locally, install dependencies, build, and deploy the resulting static output with `tau nook deploy`.

Template files use the same safety rules as deploy artifacts: hidden files/directories, symlinks, reserved `/__nook/*` paths, and invalid paths are rejected. Unlike deploys, templates do not need a root `index.html`.

## browser SDK

The Worker injects `/<site>/__nook/client.js` just after the opening HTML body tag. If your code runs from the document head, wait for `DOMContentLoaded` (or otherwise run after the page has loaded) before using `window.nook`:

```js
window.addEventListener("DOMContentLoaded", async () => {
  await window.nook.kv.put("settings", { theme: "dark" });
  const settings = await window.nook.kv.get("settings");
  await window.nook.kv.delete("settings");
  const keys = await window.nook.kv.list({ prefix: "todos/" });
});
```

KV values must be JSON-serializable. Keys and total site KV storage have fixed guardrails in the Worker. Browser KV uses `/<site>/__nook/kv/*`: public deployments expose it anonymously, while private deployments require the hostname-scoped Access cookie. Tau's CLI and model tool instead use the Access-protected `/__nook/api/sites/<site>/kv/*` management route.

## CLI

```sh
tau nook skill
tau nook list
tau nook delete demo
tau nook template list
tau nook template copy starter ./app
tau nook template save starter ./app
tau nook template delete starter
tau nook kv get demo settings
tau nook kv put demo settings '{"theme":"dark"}'
tau nook kv delete demo settings
tau nook kv list demo --prefix todos/
```

The assistant-facing code-mode tool named `nook` appears automatically when Tau config contains `nook`. Its generated JavaScript receives a bounded management SDK as `nook`, agent-scoped UTF-8 scratch files as `files`, static agent-facing SDK documentation as `docs`, and console output. `nook.skill()` separately loads this deployment's version-matched app-authoring guide. The sandbox has no ambient filesystem, process, environment, network, credential, import, timer, or `fetch` access; authenticated HTTP stays in the host, while scratch files and Nook copy/deploy paths are serviced through the session execution environment.
