# Keemakr UI SDK

Build server-driven module screens that Keemakr renders in Dashboard and Kee clients. Your module
returns structured UI data. It does not send HTML or browser code.

## 1. Organize UI by surface

Keep `ui/` at the module root, separate from agents:

```text
ui/
  campaigns/
    surface.ts
    screen.ts
    campaign/
      screen.ts
  campaign-settings/
    surface.ts
    screen.ts
```

A surface is one complete navigable flow. Every nested `screen.ts` inherits its surface's
availability. Put shared helpers under `ui/_shared/`; the generator ignores underscore-prefixed
directories.

## 2. Declare where a surface is available

```ts
import { defineSurface } from '@keemakr/ui-sdk';

export default defineSurface({
  label: 'Campaigns',
  availableOn: ['dashboard', 'client'],
});
```

Use `['dashboard']` for tenant administration screens that should not appear in Kee clients. The
array is required and may contain `dashboard`, `client`, or both.

## 3. Define screens

```ts
import { defineScreen } from '@keemakr/ui-sdk';

export default defineScreen({
  load: async () => ({
    version: 1,
    title: 'Campaigns',
    children: [{ type: 'text', value: 'Your campaigns appear here.' }],
  }),
});
```

Folder names are screen identities. For example, `ui/campaigns/campaign/screen.ts` is the
`campaign` screen. Screen folder names must be unique across the module.

## 4. Generate before Eve runs

Use the SDK wrapper in the module scripts:

```json
{
  "scripts": {
    "dev": "keemakr-ui dev -- eve dev",
    "build": "keemakr-ui build && eve build"
  }
}
```

The generator validates `ui/`, writes `ui/screen-registry.ts`, and synchronizes
`manifest.surfaces` plus `manifest.screenRegistry` in `entry.json`. Do not edit those generated
fields or the registry by hand. A module with no surfaces omits both fields. Removing a screen
records its identity so later builds keep warning about the breaking change.

Core uses the installed manifest to filter navigation and to gate every load and action before it
calls the module runtime. Availability controls UI placement. Existing authentication and roles
still control who may enter Dashboard or a Kee client.

See [`examples/campaigns`](./examples/campaigns) for one complete in-memory example.
