tarwin/tinyjsapp/skill

Claude Code and agent skill by tarwin/tinyjsapp

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Build and modify tinyjs desktop apps — tiny macOS, Windows and Linux apps with a txiki.js JavaScript backend and a native webview window. Use when working in a project with a tinyjs.json, when the user mentions tinyjs, tiny.api, or tinyjs dev/build, or when porting an Electron app to tinyjs.

Install

npx vskill@latest install tarwin/tinyjsapp/skill

SKILL.md

Building tinyjs apps

tinyjs (https://tinyjs.app, repo tarwin/tinyjsapp) makes ~6 MB desktop apps: a txiki.js backend (full system access: files, sockets, processes, FFI)

  • a native webview window — WKWebView on macOS, WebView2 on Windows,

WebKitGTK 4.1 on Linux. They talk over a private socket — no HTTP server, no ports. The page has no direct system access: everything privileged crosses tiny.api (which the tinyjs.json "api" gate can narrow), which is why anything interpolated into innerHTML must be escaped. Two launcher-side paths skip that crossing, both limited to the app's own pages and the origins "api" trusts: tiny.proxyURL's tiny-media:// proxy (cross-origin http(s) reads, macOS + Linux; media.proxy) and mic/camera (media.microphone / media.camera).

Current release: 0.68.0. App floors: macOS 15+ — a default build opens only on the build Mac's CPU (build --arch arm64|x86_64 or --universal for the other); Windows 10/11 (WebView2), x64 or arm64 per the tinyjs install; Linux glibc 2.35+ (Ubuntu 22.04 / Debian 12 / Mint 21 and up).

Read the reference for the job at hand

doingread
any API beyond the basics below (windows, menus, tray, clipboard, audio, permissions, system…)references/api.md
per-OS support, Windows/Linux quirks, capability gatingreferences/platforms.md
starting a tray app, desktop pet/overlay, media app, document app, site wrapper, agent appreferences/recipes.md
shipping: build/sign/notarize, per-OS packaging, auto-update manifestsreferences/release.md
porting from Electron (API map, what won't work)references/electron-migration.md
deciding where code runs, wire/binary payloads, throttling, memoryreferences/performance.md

Exact signatures are in the project's types/tiny.d.ts (page and app) and types/tjs.d.ts (txiki.js). For detail the references leave out, the docs are online as markdown: https://tinyjs.app/llms.txt indexes every page (https://tinyjs.app/docs/<page>.md), and https://tinyjs.app/llms-full.txt is all of them in one file.

Commands

sh
tinyjs new <dir> # scaffold (zero dependencies)
tinyjs new <dir> --template react-ts|vue-ts|svelte-ts|solid-ts|preact-ts|lit-ts|alpine-ts|vanilla-ts|…
# create-vite + tinyjs overlay: HMR dev server in the
# native window, esbuild-bundled TS backend (npm pkgs ok).
# No name = asks framework + language. --pm npm|pnpm|
# yarn|bun|vp[:pnpm] (else asks; npm off a terminal),
# --no-install. Agents: pass both flags — no prompts.
# vp needs Vite+ ≥ 1.0. alpine = vanilla + Alpine.js.
tinyjs wrap <url> # site wrapper: the site IS the app, origin-gated API
# (--origins subdomains, --menubar [--panel], --top,
# --external a.com, --ua, --force re-wraps in place)
tinyjs dev # run with hot reload (frontend edits swap in place;
# backend edits restart the process)
tinyjs build # dist/<name> binary + dist/<Name>.app (codesigned)
# --dmg installer image; --cli [name] terminal shim
# --arch arm64|x86_64: macOS .app for that CPU (any Mac;
# 0.42+); --universal: one .app for both (needs the
# Command Line Tools' lipo). Bare dist/<name> = host CPU
tinyjs publish # build + dist/publish/<name>-<ver>.zip|tarball + manifest
tinyjs notarize # macOS: notarytool submit + staple (--dmg re-makes dmg)
# publish/notarize take --arch too — repeat the build's
tinyjs doctor # find why tinyjs or the project won't run (read-only;
# exit 1 on any FAIL) — run it first when things break
tinyjs update # update tinyjs itself (--check); also: uninstall, version
tinyjs update-project # then, in the project: refresh THIS skill and the
# types from the installed tinyjs (names every file
# it changes; overwrites edits to them)
TINYJS_DEBUG=1 tinyjs dev # trace every bridge message

Project layout

tinyjs.json { name, title, size, id, version, icon?,
minTinyjsVersion?, // refuse older tinyjs with a
// real message; `tinyjs new`
// stamps its own version — raise
// it for newer APIs you adopt
update?: { url: "https://…/manifest.json", auto? },
urlScheme?: "myapp", fileExtensions?: ["md"],
openFolders?: true, readAccess?: true | "/path",
userAgent?: "…", activation?: "accessory",
mainWindow?: false, // no main window/WebView (tray agents)
offscreenRescue?: false, windowPlacement?: true,
contextMenu?: false, audioTap?: "app" | "system",
audioTapReason?: "why", about?: "menu",
attribution?: "…", // About panel credit line (macOS);
// assets/Credits.html|rtf wins
resources?: ["a.json", "dir/"], // narrow resources/ (default: all)
executables?: ["my-cli.exe", "linux/"], // narrow executables/ (default: all for this OS)
// macos.executableEntitlements: { "my-cli": ["com.apple.security.cs.allow-jit"] }
debug?: true | "open", browserAccelerators?: true,
permissions?: { microphone?: "why", camera?: "why",
speechRecognition?: "why" },
chrome?: { frame, windowControls, windowControlsPos,
transparent, vibrancy, squareCorners,
acceptsFirstMouse, menu },
signIdentity?, notarize?: { profile },
backend?: "backend/main.ts", // .ts → esbuild bundle;
// default src/backend/main.{js,ts}, then
// src/main.{js,ts} (pre-0.52), backend/main.{js,ts}
frontend?: { dir?, build, dist, dev, devUrl, reload? },
// dir: plain page folder (default src/frontend);
// reload: false = dev leaves reloads to your tool;
// build/dev need the packages installed first
// wrapping a hosted site (recipes.md) — "url" replaces
// the local frontend, "api" gates what that origin may
// call. NEVER wrap a site you don't control without it.
url?: "https://app.example.com",
inject?: "src/shim.js", // document-start, every page
downloads?: "auto" | "ask" | "deny",
popups?: "external" | "window" | "deny",
api?: "wrapper" | "none" | [...allowed] | { disable?, enable?, origins? },
// false/"" = "none"; { enable } alone = only those
macos?/windows?/linux?: { …merged on top per OS }
// macos.helpBook: "My Help" = folder in assets/ }
assets/ files the OS reads, by name: icon.png (1024×1024 app
icon), Credits.html|rtf|rtfd (macOS About), help book
folder (macOS Help menu). Older projects: icon.png and
Credits.html at the root still work
resources/ data the backend reads at runtime → (await app.paths()).resources
(the folder in dev, bundled copy in builds; null if none)
executables/ sidecar binaries → (await app.paths()).executables (flat). Ships
this OS's binaries from the top, overridden by name from
<os>/ then <os>-arm64|-x86_64/; signed into
Contents/Helpers on macOS
extras/ README, licence… for the person downloading: shipped
BESIDE the app (macOS dmg root, Windows/Linux app
folder), never inside it. Top level + <os>/ overrides
src/backend/main.js backend
src/frontend/ index.html + assets — served as real files (file://),
so relative paths just work
src/shared/ code both sides import as '../shared/x.js' (same path
from backend and page, dev and build). Ships with the
page: no secrets, no tjs:* imports. Not available in
the pre-0.52 src/main.js layout

Backend (src/backend/main.js)

js
export const api = {
// page calls tiny.api.call('readNotes', { dir }) — return resolves the
// page's promise, throwing rejects it; meta.window = calling window id
readNotes: async ({ dir }, app, meta) => { ... },
};
export function init(app) {
app.push('event-name', data); // page: tiny.api.on('event-name')
// app mirrors the page: app.window(id).*, app.win.open, app.menu.*,
// app.tray.*, app.audio.sampler.*, app.clipboard.*, app.store.*,
// app.paths(), app.system.*, notify, quit, … — main-window ops also sit at
// the top level (app.setTitle, app.setChrome, …); see references/api.md
}
// other exports the scaffold wires, each (info, app): onMenu, onTray (id
// null = bare icon click), onContextMenu, onHotkey, onWindowState,
// onWindowClosed, onOpenUrl, onOpenFiles, onMediaKey, onNotificationClick,
// onNotificationAction, onUpdateAvailable, onClipboardChange, onLocale,
// onAudioTap, onNavigate, onDownload, onWindowOpen — except
// onSystem(kind, value, app)

Runtime is txiki.js (tjs global): tjs.readFile/writeFile/readDir/stat, tjs.spawn, tjs.watch, fetch, WebSocket, tjs:sqlite, FFI. It is NOT Node (no require, no Node builtins, no native npm modules) and it has no JIT — compute-heavy work belongs in the page (references/performance.md). Streams need getReader() (no for await); tjs.cwd is a property; no Intl (format in the page). Every tjs.* fs call is async — await it — while tjs:sqlite is fully sync (never await; statements have run/all/finalize only, no get(), run() returns void).

Frontend essentials

js
await tiny.api.call('method', { params }); // -> backend api.<method>
const off = tiny.api.on('event', fn); // <- app.push; returns unsubscribe
audio.src = tiny.fileURL(path); // ALWAYS this, never 'file://' + path
// (breaks on Windows drive letters)
const r = await tiny.fetch(url, opts); // backend-proxied, no CORS/CSP
tiny.win.open('settings', { page: 'settings.html', size: '420x300',
chrome: { frame: false } });
// chrome/x/y/minSize in open() (or tinyjs.json "chrome" for main) apply
// BEFORE first paint — a late setChrome flashes the default window.

Everything else — windows/chrome/state events, menus (in every window), dialogs, tray, notifications, clipboard, hotkeys, audio (sampler / filters / audioTap / proxyURL), store/secrets, cookies, permissions, deep links, auto-update, tiny.macos.* — is in references/api.md with signatures and gotchas.

Cross-platform rules

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
642
Repository forks
19
7-day trend score
37

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/tarwin/tinyjsapp/skill/badge)](https://verified-skill.com/skills/tarwin/tinyjsapp/skill)

Something wrong with this skill or its page? Tell us.