Agent skill

Tinyjs

by tarwin in tarwin/tinyjsapp

Build and modify tinyjs desktop apps — tiny macOS (and beta Windows/Linux) apps with a txiki.js JavaScript backend and a native webview window.

MITAuto-check passed

Install Tinyjs

skills CLI
$ npx skills add tarwin/tinyjsapp --skill tinyjs -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install tarwin/tinyjsapp tinyjs --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/tarwin/tinyjsapp.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skill .claude/skills/tinyjs && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
tinyjs
GitHub stars
671
Token cost
~2.9k tokens
SKILL.md length
650 words
Files
7 (incl. references)
Skills in repo
1
Repo updated
First seen
Licence
MIT

At a glance

Build and modify tinyjs desktop apps — tiny macOS (and beta Windows/Linux) apps with a txiki.js JavaScript backend and a native webview window.

  • Working in a project with a tinyjs.json
  • SKILL.md covers Read the reference for the job…, Commands, Project layout and Backend (src/main.js), plus 3 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • The user mentions tinyjs

What it does

Tinyjs is an agent skill from tarwin/tinyjsapp. Build and modify tinyjs desktop apps — tiny macOS (and beta Windows/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.

Its SKILL.md is about 2.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 7 other files, including reference files (for example `references/api.md`, `references/electron-migration.md` and `references/performance.md`).

It works with Linux, macOS, Electron and JavaScript. The repository describes itself as: Build native apps in JS. Backend, frontend. ~5Mb. The licence is MIT.

When your agent uses it

  • Working in a project with a tinyjs.json
  • The user mentions tinyjs
  • Tinyjs dev/build
  • Porting an Electron app to tinyjs

Example prompts

  • “/tinyjs”

What it can do on your machine

Read from SKILL.md and the folder at commit 24d21a2. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are javascript and bash).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Tinyjs loads about 2.9k tokens when it runs, and up to ~20k if it reads all its reference files. Until then it costs about 76 tokens; SKILL.md has 650 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~76
When it runs · the whole SKILL.md, loaded when a task matches
~2.9k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~20k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from tarwin/tinyjsapp at commit 24d21a2, republished under its MIT licence (© tarwin). 650 words, ~2,928 tokens.

Download SKILL.mdSave it as .claude/skills/tinyjs/SKILL.md (or your agent's skills folder). This skill also uses 6 other files; get the full folder from GitHub.
name
tinyjs
description
Build and modify tinyjs desktop apps — tiny macOS (and beta Windows/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.

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 (both beta). 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.50.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); 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

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 update       # update tinyjs itself (--check); also: uninstall, version
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",
                       offscreenRescue?: false, windowPlacement?: true,
                       contextMenu?: false, audioTap?: "app" | "system",
                       audioTapReason?: "why", about?: "menu",
                       attribution?: "…",  // About panel credit line (macOS);
                                           // a project-root Credits.html wins
                       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/main.{js,ts} or backend/main.{js,ts}
                       frontend?: { dir?, build, dist, dev, devUrl },
                                      // dir: plain page folder (default src/frontend);
                                      // 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" | { disable?, enable?, origins? },
                       macos?/windows?/linux?: { …merged on top per OS } }
icon.png             1024×1024 app icon
src/main.js          backend
src/frontend/        index.html + assets — served as real files (file://),
                     so relative paths just work

Backend (src/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 mostly mirrors the page: app.window(id).*, app.openWindow,
  // app.tray.*, app.audio.sampler.*, app.clipboard.*, app.store.*,
  // app.paths (plain object), notify, quit, … — but some names differ
  // (app.setMenu, app.setChrome, …): name map in 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, permissions, deep links, auto-update, tiny.macos.* — is in references/api.md with signatures and gotchas.

Show full SKILL.md (317 more words)Show less

Cross-platform rules

  • Gate features, don't fork code. capabilities() lists only the EXCEPTIONS: test caps.x !== false, never if (caps.x) (the truthy form reports "unsupported" on the OS that has it). Query calls resolve null where unsupported, capability calls reject with the reason, fire-and-forget ones no-op — but tiny.macos.* off macOS REJECTS. caps.sampler is a string ('native'|'page') — informational, don't branch.
  • Use app.paths / tiny.app.paths() — never hardcode ~/Library or %APPDATA%; join with '/' (works everywhere).
  • tiny.system.os()/isMacOS()/isWindows()/isLinux() are synchronous; architecture() must be awaited (navigator lies on Apple Silicon).
  • Missing system pieces (codecs, speech, tray…) → tiny.system.promptMissing([ids]) puts the fix in front of the user.
  • Edit menu: never declare { title: 'Edit' } — macOS already has one, so the bar shows two. Use { role: 'edit', items: [...] }; for the SAME menu on all three OSes, place the stock items yourself: items: [{ role: 'standard' }, { separator: true }, ...yours] (details in references/api.md → Menus).

Rules of thumb

  • Backend capabilities go in api methods; keep the frontend thin — but keep COMPUTE in the page and bytes off the wire (pass paths, not ArrayBuffers; references/performance.md).
  • Escape anything interpolated into innerHTML — the page holds an RPC channel to full system access.
  • Never declare a top-level chrome identifier in frontend code: window.chrome is a non-configurable global on WebView2, so a top-level const chrome is a PARSE-time SyntaxError that kills the whole script.
  • Linux audio: never route Web Audio to ctx.destination (it crackles — measured, unfixable page-side). SFX → tiny.audio.sampler; EQ → tiny.audio.filters; details in references/platforms.md.
  • Occluded/hidden windows are throttled (rAF stops) — continuous work lives in a visible window or the backend.
  • Verify changes with a self-driving test page (references/recipes.md): TINYJS_HTML=/abs/page.html tinyjs dev. The bundled test/smoke.html only fits an UNMODIFIED zero-dependency scaffold (it calls the template's sysinfo/listDir and waits for its tick push).
  • No display (SSH, CI, sandbox, headless Linux): the launcher prints a tinyjs: explanation and exits 3 ("launcher exited before connecting") — the environment, not your code; there is no headless mode.
  • dist/<Name>.app is the distributable; bare dist/<name> is local-only.

© tarwin, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 6 other files (references) in skill of tarwin/tinyjsapp.

  • SKILL.md
  • references/api.md
  • references/electron-migration.md
  • references/performance.md
  • references/platforms.md
  • references/recipes.md
  • references/release.md

Open the folder on GitHubat commit 24d21a2

Compare with similar skills

Tinyjs next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Tinyjs compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Tinyjs this skilltarwin/tinyjsapp671—~2.9kAutomated safety check: PassMIT
JS Cpp Protocolnotepadqq/notepadqq2.3k—~3.2kAutomated safety check: PassGPL-3.0
Releasing Blancbnfy/blanc105—~2.9kAutomated safety check: NotesMIT
Debug CIweb-infra-dev/rslint460—~2.8kAutomated safety check: PassMIT
Import Open Tabsbnfy/blanc105—~510Automated safety check: PassMIT
Windows macOS Test Packageswjybky/deepwrite559—~574Automated safety check: PassApache-2.0

Similar skills

  • JS Cpp Protocol

    notepadqq/notepadqq

    Reference for the communication protocol between the JavaScript editor (CodeMirror or Monaco) and the C++/Qt UI layer via QWebChannel.

    2.3k GitHub stars~3.2k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Releasing Blanc

    bnfy/blanc

    Full runbook for cutting a Blanc desktop release — scripts/release.sh mechanics and its required BLANCRELEASE env vars, macOS notarization via 1Password, the Touch ID provisioning profile and…

    105 GitHub stars~2.9k tokensUpdated today
    DevOps & CloudAuto-check: notes
  • Debug CI

    web-infra-dev/rslint

    Reproduce Linux CI failures locally using Docker when the same tests pass on the host, especially Go platform differences and VS Code extension tests requiring xvfb.

    460 GitHub stars~2.8k tokensUpdated today
    DevelopmentAuto-check passed
  • Copy the current Chrome, Edge, Brave, Opera, or Vivaldi window into the current Blanc window through a private one-time handoff, with a new window available as an explicit choice in Blanc.

    105 GitHub stars~510 tokensUpdated today
    Auto-check passed
  • 构建并验证 DeepWrite Windows、macOS 测试安装包,排查打包错误、修复后继续。用于打包、测试包、Win/Mac 包及相关流程修改;版本递增和发布另用 package-patch-release。

    559 GitHub stars~574 tokensUpdated 3 days ago
    Auto-check passed
  • Electron Builder

    pedronauck/skills

    Comprehensive guide for electron-builder (v26.x) packaging, code signing, auto-updates, and release workflows.

    633 GitHub stars~2.7k tokensUpdated 22 days ago
    MobileAuto-check passed

Questions about Tinyjs

What does Tinyjs do?

Build and modify tinyjs desktop apps — tiny macOS (and beta Windows/Linux) apps with a txiki.js JavaScript backend and a native webview window. Tinyjs is an agent skill from tarwin/tinyjsapp.js JavaScript backend and a native webview window.

When should I use Tinyjs?

Tinyjs fits situations like: working in a project with a tinyjs.json; the user mentions tinyjs; tinyjs dev/build; porting an Electron app to tinyjs.

How do I install Tinyjs in Claude Code?

Run `npx skills add tarwin/tinyjsapp --skill tinyjs -a claude-code`. Or copy the skill folder (skill in tarwin/tinyjsapp) into .claude/skills/tinyjs in your project. Claude Code loads it when a task matches its description.

How do I install Tinyjs in Codex?

Run `npx skills add tarwin/tinyjsapp --skill tinyjs -a codex`. Or copy the skill folder (skill in tarwin/tinyjsapp) into .agents/skills/tinyjs in your project. Codex loads it when a task matches its description.

Can I use Tinyjs in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add tarwin/tinyjsapp --skill tinyjs -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/tinyjs, .gemini/skills/tinyjs, .github/skills/tinyjs and .opencode/skills/tinyjs in your project.

What does Tinyjs need to run?

SKILL.md names no scripts, command-line tools or credentials: Tinyjs is instructions for the agent only.

Does Tinyjs access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Tinyjs safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Tinyjs use?

Tinyjs is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Tinyjs use?

About 2.9k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 17k tokens, read only when the agent opens those files.

What are the alternatives to Tinyjs?

Skills that share tags, products or a category with Tinyjs: JS Cpp Protocol (notepadqq/notepadqq, 2.3k stars), Releasing Blanc (bnfy/blanc, 105 stars), Debug CI (web-infra-dev/rslint, 460 stars) and Import Open Tabs (bnfy/blanc, 105 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Tinyjs?

tarwin (a GitHub user) maintains it in tarwin/tinyjsapp, which has 671 GitHub stars. The repository was last updated on October 6, 2026.

Source: tarwin/tinyjsapp on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.