Skip to content
Back to skills

Summer Apps

ASecurity

Build a Summer App, a team tool inside Summer Studio (balance table, quest editor, tracker), data and tools.

  • 77 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 16, 2026
ai-agentsgoshellnodeapi

Works with

  • claude code
  • cursor
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 16, 2026

npx -y skills add SummerEngine/summer --skill summer-apps --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Summer Apps?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Summer Apps
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/summerengine-summer-apps-summer/badge)](https://www.skillsdirectory.com/skills/summerengine-summer-apps-summer)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: summer-apps
description: "Build a Summer App, a team tool inside Summer Studio (balance table, quest editor, tracker), data and tools."
license: MIT
compatibility: [Cursor, Claude Code, Windsurf, Codex]
category: tools
user-invocable: true
allowed-tools: Read Write Edit Glob summer_apps_guide summer_apps_list summer_apps_create summer_apps_publish summer_apps_get summer_apps_update summer_apps_events summer_apps_page summer_apps_use_page summer_apps_screenshot summer_apps_read_data summer_apps_write_data summer_apps_tools summer_apps_call summer_apps_report_gap summer_call
---

# Summer Apps

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](minimal-app.md): 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](sdk-reference.md): every SDK call with its exact arguments and
  return shape.
- [manifest.md](manifest.md): 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
{ "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.

<!-- shell-commands: generated from the operation catalog by npm run generate:registry; do not edit by hand -->
## 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@4.3.0` 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>"` |
<!-- /shell-commands -->

Files in this skill

  • SKILL.md11.5 KB
  • manifest.md2.9 KB
  • minimal-app.md7.4 KB
  • resource.yaml920 B
  • sdk-reference.md8.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.