> ## Documentation Index
> Fetch the complete documentation index at: https://docs.summerengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Summer apps skill for AI agents

> Build a Summer App, a team tool inside Summer Studio (balance table, quest editor, tracker), data and tools. A Summer Engine skill for AI agents.

`summer-apps` is a skill from the [Summer skill library](/mcp/skills): a guide your AI agent reads when the task matches, so it builds the good version on the first try. Build a Summer App, a team tool inside Summer Studio (balance table, quest editor, tracker), data and tools.

| | |
| - | - |
| Status | Preview: not yet exercised in-engine by the Summer team |
| Domains | Tools, UI, Agent workflow |
| Version | `0.1.0` |
| Engine version | `>=4.6` |
| Recommended set | Yes, installed by `--recommended` |

## When your agent uses it

* The person asks for a tool for their team ("build us a loot balance tool", "a board to track creatures")
* The person needs a UI to decide, rate or edit something they will come back to
* Reading or changing the data of an existing Summer App
* Calling an app's agent tools or waiting for what an app sends

## Install

`summer setup` installs every skill for your agent. To add only this one:

```bash theme={null}
npx -y summer-engine@latest skills install summer-apps --agent claude-code
```

Swap `claude-code` for your agent, such as `codex` or `cursor`. See [Skills](/mcp/skills#quick-start) for every option.

## The skill

A Summer App is a tool the person's team uses inside Summer Studio: shared with
the workspace, live on its assets, game data and engine, dockable in the editor.
You build it in minutes; the team keeps it.

A call written `area.action({...})` is one operation: use the tool `summer_area_action` when
your client lists it, else `summer_call({ op: "area.action", input: {...} })`.
`summer_search` finds any operation and its exact input.

## First: does Summer already do it?

A custom app is something the team has to maintain. Before you build one, check whether
Summer already does the job: Studio features (the asset library with its collections and
groups, Pick one and sound choices, Grow dashboards, Team) and the existing Summer
operations (`summer_search` finds them). If it does, use that and tell the person where it lives.

Build an app only when the need is real and Summer lacks it, or as a Scratch throwaway (a
quick asset review, a UI prototype) that you call throwaway when you make it, and archive
when it is done (`apps.update({ appId, status: "archived" })`). When
something is missing natively, report it with `apps.report_gap` (and
`summer_call` with `docs.feedback` when a library entry fell short), so Summer can build it for
everyone.

| Ask | Do |
| - | - |
| "Let me pick from these 12 sword sounds" | Pick one: `assets.generate_sfx_choices`, or put the sounds in a library collection. No app. |
| "Group our Studio assets into a moodboard for the forest level" | Organize them with the asset library's collections and groups. No app. |
| "A weapon balance table that writes res\://data/weapons.json" | Build an app: nothing in Summer edits game data with the team's balance rules. |

## When to build one

* The person asks for a tool ("build us a loot balance tool", "track every creature
  from concept to in-engine", "a board to review playtest clips").
* They need a UI to decide or edit something they will come back to.
* Not for a one-off answer: reply in chat instead.
* Not when Summer already does it (above).

## Layout or code

* **Layout** (`format: "layout"`): a JSON layout of kit nodes. Quick, throwaway,
  always on brand. Use it to ask the person to pick, rate or fill something now.
* **Code** (default): `index.html` + JS/CSS with the Summer SDK and UI kit. Use it
  for state, editing, shared data, generation or engine access.

## Start from the working app

Read these before writing code; they are exact:

* [minimal-app.md](/skills/summer-apps/minimal-app): a complete working app (manifest, `index.html`,
  `app.js`) built from kit components, using shared data, live changes, the viewer, `page.declare`, an
  agent event, an agent tool and frame-move state. Copy it and change it.
* [sdk-reference.md](/skills/summer-apps/sdk-reference): every SDK call with its exact arguments and
  return shape.
* [manifest.md](/skills/summer-apps/manifest): every manifest field.
* The kit's component catalog (every `<summer-*>` element with attributes, events and a
  copyable example) is `apps.guide({ section: "kit" })`, also at `/summer-ui/v1/catalog.json`
  on the app host. Copy its examples instead of inventing markup.

To see an app, publish it and call `apps.screenshot({ appId })`: Summer renders it headless
with the person's data and returns the picture plus the console, uncaught errors, refused calls
and the fields and buttons it declared. No Studio tab needed; the person sees it at
`/studio/apps/<appId>` (`apps.create` opens it for them). Opening `index.html` on its own
never connects. There is no offline host: do not build one or mock the SDK.

The app is served from its own host, apps.summerengine.app. Load the SDK and the kit as
ES modules with root paths: `<script type="module" src="/summer-sdk/v1.js">` and
`<script type="module" src="/summer-ui/v1/ui.js">`. Then `await summer.ready` before
the first call, and reach data only through `summer.data.collection(name)`.

## The loop

1. `apps.guide({ section: "overview" })` first, then `examples` and the sections the app needs.
   Load the `summer-apps-design` skill for how it must look.
2. `apps.create({ name, purpose, format })`. The person's Studio tab opens it.
3. Write the files in a local folder, then `apps.publish({ appId, files, manifest, note })` with
   every file as `{ path, content, encoding }` (`index.html` at the root; or `layout` for a layout
   app). Each publish is an immutable version the tab boots. A publish error names the file or
   rule: fix it and publish again.
4. Seed starter data with `apps.write_data({ appId, ops, as: "seed" })` when the app should
   start full. Seed rows belong to the team and show no author.
5. Look at it: `apps.screenshot({ appId })`, then `width: 390` (phone) and `theme: "dark"`;
   `steps: [{click: "#edit"}]` or `[{press: "<action id>"}]` shows a dialog or a second state.
   Fix the publish `warnings` too.
   Fix every error and console line it reports, publish again, look again. It is read-only:
   writes, sends and paid calls are refused there and work in Studio.
6. `apps.events({ appId, after })` waits for what the app sends you
   (`summer.agent.send`), errors (uncaught and `console.error`) and feedback. Act on them;
   pass the cursor on.
7. Change the app by publishing again; `apps.get({ appId })` returns the current files.

## Data is the API

Read an app's shared collections with `apps.read_data` and write them with `apps.write_data`. Both work with
no app open, and everyone in the app sees your edits live. "Nerf the bow in our
balance sheet" is a data write, not a click.

Declare each collection's record shape in the manifest `collections`; `apps.tools`
and `apps.read_data` return it, so any agent knows what a record looks like.

```json theme={null}
{ "appId": "<id>", "ops": [
  { "op": "patch", "collection": "items", "recordId": "bow", "patch": { "damage": 36 }, "ifRevision": 4 },
  { "op": "put", "collection": "notes", "recordId": "n-17", "data": { "text": "Boss too long", "status": "open" } },
  { "op": "remove", "collection": "notes", "recordId": "n-3" }
] }
```

That is the input of `apps.write_data`: up to 100 ops per call. Send an `idempotencyKey` and reuse it
only to retry the same write, so it applies once. `apps.read_data({ appId, collection, limit, cursor })`
reads records (`items`, then `nextCursor` for the next page); removed records are not returned. Your writes are recorded as `actor { kind: "agent" }` (and
as `createdBy` on records you create), so the app can show which rows an agent made. Add
`"as": "seed"` for starter data that belongs to the team (`kind: "seed"`, no author). `patch` merges keys
(`null` removes one); `ifRevision` guards against overwriting a newer change.

## Agent tools

Logic that lives in the app (a balance formula, an export) can be exposed in the
manifest `agentTools` and implemented with `summer.agent.tool(name, handler)`.
`apps.tools` lists them; `apps.call({ appId, tool, input })` runs one inside the person's open
app and answers a `conflict` error when the app is not open (its `next` is the app's link for the
person). Prefer data for plain reads and edits. `apps.page` reads the fields and buttons an open app
declared, and `apps.use_page({ appId, fill, press })` fills and presses them; the ones the app marks
critical are the person's to press.

## Rules

* Declare only the permissions the app uses; declare every `engineFiles` path and
  every `agentEvents` name. A missing one fails at runtime with `permission_missing`.
* The app runs sandboxed (`allow-scripts allow-forms allow-popups allow-modals
  allow-downloads`, never `allow-same-origin`): no cookies, no `localStorage`, no network
  unless the workspace allows a domain. Keep state in `summer.data`.
* Paid SDK calls spend the credits of the person using the app. Say so before
  building an app that generates.
* Use real data (`summer.data`, `summer.assets`, `summer.engine.readFile`), never
  placeholder numbers.
* Studio moves an idle app to a fresh frame every few minutes. Keep UI state you care
  about in shared data, or return it from `summer.app.onSnapshot(() => state)` (up to
  256 KB) and read it back from `(await summer.ready).restored`. Wrap Web Audio playback
  in `summer.app.busy(true)` / `summer.app.busy(false)` so a long sound is not cut;
  `<audio>` and `<video>` count on their own.
* Call `summer.page.declare` so agents can read and use the UI; mark delete,
  publish, pay and send actions `critical`.
* When the SDK cannot do what the app needs, say so and call
  `apps.report_gap`.
* `apps.dock` docks an app in the editor (it runs in the Summer MCP on this computer); on engines
  without app docks it returns `engine_lacks_op`: open the app in the Studio tab instead.
* Keep, archive, restore, rename and pin with `apps.update` (`status`, `name`, `folder`, `pinned`);
  copy one with `apps.duplicate`; add a starter app with `apps.add_starter`; send the makers a note
  with `apps.feedback`. `apps.delete` asks the person, and `apps.rollback` (an older version goes
  live) and `apps.update_starter` ask the app's owner: each answers `needs_approval` with a link to
  give them, and nothing changes until they approve (`jobs.wait` on the job).

## Done means

The app is published; `apps.screenshot` shows it with real data in light, dark and at
390 px with no errors; its states (loading, empty, error) work; and the person knows what it
does and where its data goes.

## From a shell

No Summer MCP tools in this session? Run each one as a command; when `summer --version` is missing or below 4.0, use `npx -y summer-engine@latest` in place of `summer`. Fields are flags in kebab-case (`--scene-path res://main.tscn`) or one `--input '<json>'`, and `summer ops describe <op>` prints the exact input. The `summer-cli` skill has the rest.

| In this skill | Command |
| - | - |
| `apps.call`, `summer_apps_call` | `summer apps call` |
| `apps.create`, `summer_apps_create` | `summer apps create` |
| `apps.dock` | `summer apps dock` |
| `apps.events`, `summer_apps_events` | `summer apps events` |
| `apps.get`, `summer_apps_get` | `summer apps get` |
| `apps.guide`, `summer_apps_guide` | `summer apps guide` |
| `summer_apps_list` | `summer apps list` |
| `apps.page`, `summer_apps_page` | `summer apps page` |
| `apps.publish`, `summer_apps_publish` | `summer apps publish` |
| `apps.read_data`, `summer_apps_read_data` | `summer apps read-data` |
| `apps.report_gap`, `summer_apps_report_gap` | `summer apps report-gap` |
| `apps.screenshot`, `summer_apps_screenshot` | `summer apps screenshot` |
| `apps.tools`, `summer_apps_tools` | `summer apps tools` |
| `apps.update`, `summer_apps_update` | `summer apps update` |
| `apps.use_page`, `summer_apps_use_page` | `summer apps use-page` |
| `apps.write_data`, `summer_apps_write_data` | `summer apps write-data` |
| `assets.generate_sfx_choices` | `summer assets generate-sfx-choices` |
| `docs.feedback` | `summer docs feedback` |
| `jobs.wait` | `summer jobs wait` |
| `summer_search` | `summer ops search "<what you want>"` |

## Files in this skill

* [`manifest.md`](/skills/summer-apps/manifest)
* [`minimal-app.md`](/skills/summer-apps/minimal-app)
* [`sdk-reference.md`](/skills/summer-apps/sdk-reference)

## Related skills

* [`summer-apps-design`](/skills/summer-apps-design): How a Summer App should look: layout, Summer UI kit components, tables, charts, states, pre-ship check.

***

Source: [`library/skills/summer-apps/SKILL.md`](https://github.com/SummerEngine/summer/blob/main/library/skills/summer-apps/SKILL.md), rendered from `summer-engine@4.3.0` on npm.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.