create-canvas-app
Build a GitHub Copilot App canvas extension the right way, fast.
Skill by jongio
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/jongio-create-canvas-app
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: documents, design, agent-building
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Node.js package
Network hosts it talks to 4
api.github.com· found in codecodeload.github.com· found in install commandgithub.com· found in codejsonplaceholder.typicode.com· found in code
Files it touches
~/.claude/skills/create-canvas-app- Your home directory (~)
What's inside
- Skill name
create-canvas-app- Description
- Build a GitHub Copilot App canvas extension the right way, fast. Use when the user wants to create, scaffold, or improve an interactive canvas (a side-panel UI the agent can open and drive) — dashboards, editors, trackers, boards, document/preview surfaces. Provides a no-build Preact + htm kit with live SSE state, durable per-user storage, Primer theming, and the official GitHub Lucide icon set, plus a generator that stamps a working canvas in one command. Do NOT use for non-canvas extensions (plain agent tools) or for shipping web apps unrelated to Copilot canvases.
- License
- MIT
- Metadata
- version: 1.0.0
- Instructions
- 407 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
- Instructions call the network
Files (62)
- .npmrc
- .vally.yaml
- LICENSE
- README.md
- SKILL.md
- invoke.png · docs/
- stock-ticker.png · docs/
- README.md · evals/
- eval.yaml · evals/create-canvas-app/
- client.mjs · kit/
- core-client.mjs · kit/
- deeplinks.mjs · kit/
- format.mjs · kit/
- github-store.mjs · kit/
- icons.mjs · kit/
- net.mjs · kit/
- server.mjs · kit/
- storage.mjs · kit/
- theme.css · kit/
- validate.mjs · kit/
- lucide.mjs · kit/vendor/
- preact-htm-standalone.mjs · kit/vendor/
- version.mjs · kit/
- package-lock.json
- package.json
- .kit-version.json · reference/decision-log/canvas-kit/
- client.mjs · reference/decision-log/canvas-kit/
- core-client.mjs · reference/decision-log/canvas-kit/
- deeplinks.mjs · reference/decision-log/canvas-kit/
- format.mjs · reference/decision-log/canvas-kit/
- github-store.mjs · reference/decision-log/canvas-kit/
- icons.mjs · reference/decision-log/canvas-kit/
- net.mjs · reference/decision-log/canvas-kit/
- server.mjs · reference/decision-log/canvas-kit/
- storage.mjs · reference/decision-log/canvas-kit/
- theme.css · reference/decision-log/canvas-kit/
- validate.mjs · reference/decision-log/canvas-kit/
- lucide.mjs · reference/decision-log/canvas-kit/vendor/
- preact-htm-standalone.mjs · reference/decision-log/canvas-kit/vendor/
- version.mjs · reference/decision-log/canvas-kit/
- canvas.mjs · reference/decision-log/
- copilot-extension.json · reference/decision-log/
- extension.mjs · reference/decision-log/
- app.mjs · reference/decision-log/web/
- index.html · reference/decision-log/web/
- deeplinks.md · reference/
- advanced-patterns.md · references/
- check-kit-freshness.mjs · scripts/
- install-local.ps1 · scripts/
- kit-features.mjs · scripts/
- new-canvas.mjs · scripts/
- sync-kit.mjs · scripts/
- vendor-lucide.mjs · scripts/
- client.test.mjs · test/
- deeplinks.test.mjs · test/
- generator.test.mjs · test/
- http.test.mjs · test/
- kit-parity.test.mjs · test/
- kit-runtime.test.mjs · test/
- tooling.test.mjs · test/
- …and 2 more
SKILL.md (first lines)
# Create Canvas App
## What a canvas is (and when to build one)
A canvas is an interactive surface the agent opens in a side panel via
`open_canvas`. Both the **agent** and the **user** act on the **same state**
through the **same action handlers**. Reach for a canvas when chat text or a diff
isn't enough: live dashboards, editors, spreadsheets, trackers, kanban/board
views, document previews, tool-specific workflows.
If the user just needs a non-visual agent tool, build a normal extension tool
instead — not a canvas.
## Rendering tier — decide first
| Tier | Use when | How |
| --- | --- | --- |
| **Static HTML string** | Read-only or near-static content; no inputs to protect | The runtime's vanilla scaffold (`extensions_manage scaffold kind:canvas`). |
| **Preact + htm + this kit** | Anything interactive: inputs, live updates, lists, forms, shared state | This kit. **Default choice for real canvases.** |
For the static tier, use the vanilla scaffold as generated and keep the HTML in
its single extension module. Do not copy `canvas-kit/` into that extension. Move
to a generated Preact template as soon as the canvas needs inputs, shared state,
agent actions, or live updates. A one-file interactive counter is not the upgrade
path because it duplicates action logic and keeps state per panel.
The single most important reason to use the kit: **Preact diffs the DOM**, so a
live state push from the agent does **not** clobber focus, caret position, or
half-typed text in an input. The `innerHTML = ...` pattern most early canvases
use repaints the whole tree and loses keystrokes on every push. Don't do that.
## The model (read this before coding)
```text
extension.mjs ── the ONLY file that imports the Copilot SDK (thin adapter; also wires host AI)
canvas.mjs ── your canvas: id, schema, state load/save, action handlers (SDK-free)
canvas-kit/ ── the template's feature-scoped kit (do not edit)
web/index.html ── shell: loads /kit/theme.css and ./app.mjs
web/app.mjs ── your Preact view
```
- **State is shared and durable.** It's keyed by a *domain id* resolved from the
open input (`resolveDomainId`), **not** by `instanceId` — open the same domain
in two panels and they show the same data. Persistence goes through
`userStore(extName, file)` → `$COPILOT_HOME/extensions/<name>/artifacts/<domain>.json`.
Two more tiers exist in `kit/storage.mjs` for non-durable/scoped state:
`sessionStore(sessionId, extName, file)` (per-session scratch, discarded with
the session) and `workspaceStore(workspacePath, file)` (rooted at the session
workspace). All three write atomically (temp + rename) and **serialize
concurrent saves to the same file**, so a racing agent + UI save can't corrupt
or `EPERM` the durable file.
- **Shared, multiplayer state (optional).** For a board multiple *people* edit,
swap the local tier for `githubStore({ owner, repo, path })` from
`kit/github-store.mjs`: it persists the same JSON to a file in a (private) repo
via the GitHub Contents API, so every collaborator with push access edits ONE
document — GitHub is both the store and the access control. Wire it as
`loadState`/`saveState`, and add `syncState: () => store.poll()` +
`syncIntervalMs` so the runtime polls for other people's edits (cheap ETag `304`
when unchanged) and adopts them live — but only while a panel is being viewed.
Writes are optimistic-locked by blob SHA (a conflicting commit re-reads +
retries; last-writer-wins by default, or pass a `merge(remote, mine)`). Token
comes from `GH_TOKEN`/`GITHUB_TOKEN` or `gh auth token` and is only ever sent as
an `Authorization` header.
- **Agent and UI share handlers.** An action invoked by the agent and the same
action invoked from a button run the identical handler and produce the identical
state mutation. Write the logic once, in `canvas.mjs`.
- **Live updates are automatic.** The kit serves `GET /state`, `GET /events`
(SSE), and `POST /action`. `mountCanvas` wires them up; every state change fans
out to all open panels.
- **`server.mjs` is SDK-free** so the whole runtime is testable with plain Node
HTTP (see `test/http.test.mjs`). Keep SDK calls in `extension.mjs` only.
### Two kinds of state in the view — keep them separate
- **Shared domain state** arrives via SSE and is re-rendered on every push. Treat
it as read-only in the view; change it only by calling `invoke(action, input)`.
- **Local UI state** (a draft input value, the active tab/filter) lives in
`useState` and must never be pushed to the server until the user commits it.
### Action results & errors — how failures surface
Both callers (agent and UI) hit the same handler, and the runtime wraps every
invocation in the same envelope, so model failures deliberately:
- **Return** a small plain object for success (`{ id, status }`, `{ count }`).
`POST /action` answers `{ ok: true, result }`.
- **Throw** for a hard failure (bad input, missing id). The runtime answers
`{ ok: false, code, message }` — HTTP **400** for a known kit error (e.g. an
unknown action) and **500** for a handler `throw` — and `mountCanvas`'s
`invoke` **rejects** with a `CanvasActionError` carrying that `code`/`message`,
so a button handler can `try/catch` it. On the agent side, `extension.mjs` maps
the same error to a `CanvasError`. A throw is *surfaced*, never a crash.
- For an **expected, transient** failure (a flaky upstream fetch on a background
poll), don't throw — capture it into `state.error` and **return** so the error
card shows while the poll stays quiet (see the data template's `refresh`).
### Input & state are schema-validated at the boundary
An action's `inputSchema` is **enforced by the runtime**, not just declared: a
payload that violates it (wrong type, missing required field, out-of-enum value,
or an unexpected property under `additionalProperties: false`) is rejected with
an `invalid_input` error (**HTTP 400**) *before* your handler runs — from the
agent side too. So `inputSchema` is your typed contract; write it precisely and
your handler only sees well-shaped input. **Business rules still live in the
handler** (a schema-valid but empty `" "` title reaches the handler, which
throws → 500). Open input is validated against `config.inputSchema` the same way.
Optionally set `config.stateSchema` (same JSON-Schema subset, `kit/validate.mjs`)
to guard the **durable shape**: if a handler produces state that violates it, the
mutation is rolled back and the action fails loud (500) instead of persisting
corrupt state. It's opt-in — omit it and any state shape is allowed.
## Icons — official GitHub Lucide, always
The kit vendors the **exact Lucide set github-app ships** (`lucide-react@1.23.0`,
byte-identical). Use it for *every* icon; do not hand-write SVGs or pull a CDN.
```js
import { Icon } from "/kit/icons.mjs";From jongio/skills, MIT.
More from jongio/skills
- 0.647score
pr
jongio
**WORKFLOW SKILL** - A concise checklist workflow for taking changes from local commit and preflight checks through PR submission, review resolution, CI…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
repo-ready
jongio
Scaffold and maintain the standard community health files every GitHub repository needs: .gitignore, .gitattributes, LICENSE, README.md, CONTRIBUTING.md…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
retro
jongio
**WORKFLOW SKILL** - Close out a session with an evidence-backed task and feedback audit, source-skill improvements, and safely approved branch and worktree…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
create-skill
jongio
**WORKFLOW SKILL** - Create and register a complete portable agent skill in a managed skills-repo.config.json repository or an existing skills repository.
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
skill-doctor
jongio
**WORKFLOW SKILL** - Improve skills from recent sessions and reduce instruction bloat, using cached audits, a dedicated worktree, and one PR.
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
deps-doctor
jongio
Audit, update, and secure project dependencies across npm, pnpm, Yarn, pip, Pipenv, Poetry, uv, Go, Cargo, Bundler, Composer, NuGet, Maven, Gradle, Swift…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
dns-doctor
jongio
Evidence-first DNS and domain health audit covering delegation, records, DNSSEC, CAA, website routing, TLS, CDN behavior, SPF, DKIM, DMARC, MTA-STS, TLS…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
backlog-groom
jongio
**WORKFLOW SKILL** - Groom GitHub backlogs across issue and source repositories, with or without Projects, using scoped evidence and approved changes.
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
ci-hound
jongio
**WORKFLOW SKILL** - Continuously monitor GitHub Actions workflows with a zero-token ETag-cached background daemon, alert on main failures, repair broken…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
naming-is-hard
jongio
Interactive naming assistant: help the user land on a name for a project, product, repo, company, package, or feature they love AND can actually use.
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
git-tidy
jongio
Git repository triage across branches, worktrees, stashes, remote refs, tags, remotes, artifacts, ignored-but-tracked files, large blobs, and maintenance.
SkillAFreshness: A★ 18Claude Code +9 - 0.643score
create-skills-repo
jongio
**WORKFLOW SKILL** - Create or safely maintain a portable skills marketplace repository for multiple AI coding agents.
SkillAFreshness: A★ 18Claude Code +9
Signals
- Stars
- 18
- Forks
- 5
- Open issues
- 2
- Last commit (this folder)
- Oct 22, 2026 (5 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- Version
- 1.0.0
- License
- MIT
- Repository
- github.com/jongio/skills
- Website
- jongio.github.io/skills/
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from jongio
- 0.647score
git-tidy
jongio
Git repository triage across branches, worktrees, stashes, remote refs, tags, remotes, artifacts, ignored-but-tracked files, large blobs, and maintenance.
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
ci-hound
jongio
**WORKFLOW SKILL** - Continuously monitor GitHub Actions workflows with a zero-token ETag-cached background daemon, alert on main failures, repair broken…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
create-skill
jongio
**WORKFLOW SKILL** - Create and register a complete portable agent skill in a managed skills-repo.config.json repository or an existing skills repository.
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
backlog-groom
jongio
**WORKFLOW SKILL** - Groom GitHub backlogs across issue and source repositories, with or without Projects, using scoped evidence and approved changes.
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
deps-doctor
jongio
Audit, update, and secure project dependencies across npm, pnpm, Yarn, pip, Pipenv, Poetry, uv, Go, Cargo, Bundler, Composer, NuGet, Maven, Gradle, Swift…
SkillAFreshness: A★ 18Claude Code +9 - 0.647score
dns-doctor
jongio
Evidence-first DNS and domain health audit covering delegation, records, DNSSEC, CAA, website routing, TLS, CDN behavior, SPF, DKIM, DMARC, MTA-STS, TLS…
SkillAFreshness: A★ 18Claude Code +9
Cite this page
create-canvas-app skill. Agent Mart. https://agentmart.dev/skills/jongio-create-canvas-app (last updated 2026-10-24)