Agent skill

Pocketbase Jsvm

by pockethost in pockethost/pockethost

Writes PocketBase server-side JavaScript in the Goja JSVM: pbhooks, routerAdd, record hooks, cron jobs, and synchronous $app APIs.

MITAuto-check passedBackend & APIs

Install Pocketbase Jsvm

skills CLI
$ npx skills add pockethost/pockethost --skill pocketbase-jsvm -a claude-code

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

GitHub CLI
$ gh skill install pockethost/pockethost pocketbase-jsvm --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/pockethost/pockethost.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.cursor/skills/pocketbase-jsvm .claude/skills/pocketbase-jsvm && 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
pocketbase-jsvm
GitHub stars
1.4k
Token cost
~2.7k tokens
SKILL.md length
775 words
Files
7
Skills in repo
11
Repo updated
First seen
Licence
MIT

At a glance

Writes PocketBase server-side JavaScript in the Goja JSVM: pbhooks, routerAdd, record hooks, cron jobs, and synchronous $app APIs.

  • Works in 3 steps: Shared hook logic lives in… → Import via $common/ subpaths (tsconfig… → After build, confirm no…
  • Pbmigrations JS
  • SKILL.md covers Version split — read this first, Pre-flight checklist, File layout and Hook file hot reload…, plus 11 more sections
  • Calls git

What it does

Pocketbase Jsvm is an agent skill from pockethost/pockethost. Writes PocketBase server-side JavaScript in the Goja JSVM: pbhooks, routerAdd, record hooks, cron jobs, and synchronous $app APIs. Use for .pb.js files, pbhooks, pbmigrations JS, or server-side PocketBase extensions — not the npm JS SDK. Read quirks.md for Goja gotchas (toString, json fields, hoisting, BadRequestError). Always check target PocketBase version: v0.22 and v0.23+ use different JSVM APIs and docs. PocketBase watches pbhooks JS on disk and hot-reloads hooks inside the running process without exiting.

Its SKILL.md is about 2.7k tokens, which your agent loads only when the skill is triggered. The skill folder holds 6 other files (for example `app-store.md`, `constraints.md` and `hooks-examples.md`).

It sits in Backend & APIs, covering Backend development. It works with JavaScript and npm. The repository describes itself as: Open source multitenant PocketBase server. The licence is MIT.

When your agent uses it

  • Pbmigrations JS
  • Server-side PocketBase extensions — not the npm JS SDK

Example prompts

  • “Use the pocketbase-jsvm skill to write PocketBase server-side JavaScript in the Goja JSVM: pbhooks, routerAdd, record hooks, cron jobs, and…”
  • “/pocketbase-jsvm”

Requirements

  • Docker

Workflow steps

3 steps, taken from the first numbered list in SKILL.md.

  1. Shared hook logic lives in packages/pockethost/src/common/ — must be JSVM-safe (sync, no Node/browser APIs).
  2. Import via $common/ subpaths (tsconfig "$common/*": ["../common/*"]). Avoid runtime imports from the $common barrel.
  3. After build, confirm no [UNRESOLVED_IMPORT] warnings — unresolved imports break validation silently at runtime.

What it can do on your machine

Read from SKILL.md and the folder at commit 82c9ba3. 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

    Shell commands in SKILL.md call:

    • git

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

  • Network

    Links to these hosts (documentation or services it may open):

    • pocketbase.io

    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

Pocketbase Jsvm loads about 2.7k tokens when it runs. Until then it costs about 134 tokens; SKILL.md has 775 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~134
When it runs · the whole SKILL.md, loaded when a task matches
~2.7k

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 pockethost/pockethost at commit 82c9ba3, republished under its MIT licence (© pockethost). 775 words, ~2,724 tokens.

Download SKILL.mdSave it as .claude/skills/pocketbase-jsvm/SKILL.md (or your agent's skills folder). This skill also uses 6 other files; get the full folder from GitHub.
name
pocketbase-jsvm
description
Writes PocketBase server-side JavaScript in the Goja JSVM: pb_hooks, routerAdd, record hooks, cron jobs, and synchronous $app APIs. Use for *.pb.js files, pb_hooks, pb_migrations JS, or server-side PocketBase extensions — not the npm JS SDK. Read quirks.md for Goja gotchas (toString, json fields, hoisting, BadRequestError). Always check target PocketBase version: v0.22 and v0.23+ use different JSVM APIs and docs. PocketBase watches pb_hooks JS on disk and hot-reloads hooks inside the running process without exiting.

PocketBase JSVM

PocketBase embeds a Goja JavaScript engine for server-side extensions. Code runs inside the PocketBase process — synchronous, no Node/Browser APIs.

Version split — read this first

v0.23 is a breaking JSVM boundary. PocketHost runs both legacy (≤ v0.22) and modern (≥ v0.23) instances. Always confirm the instance PocketBase version before writing or porting hooks — do not mix APIs across versions.

≤ v0.22≥ v0.23
Overviewold/js-overviewjs-overview
API referenceold/jsvmjsvm
Typings (PocketHost)packages/pockethost/src/instance-app/v22/types/types.d.tspb_data/types.d.ts on instance; PocketHost templates in instance-app/v23/
Record access$app.dao().findRecordById(...)$app.findRecordById(...)
Startup hook$app.onBeforeServe().add((e) => { ... }) or onAfterBootstraponBootstrap((e) => { e.next(); ... })
Custom routes(c) =>, c.pathParam('id'), path /api/foo/:id(e) =>, e.request.pathValue('id'), path /api/foo/{id}
Record hooksonRecordAfterCreateRequest, …onRecordAfterCreateSuccess, … (call e.next())
Admin auth table_admins (passwordHash)_superusers (password)
Admin UI pluginsN/A$app.onServe() → e.uiExtensions (PB ≥0.37, experimental) — pocketbase-admin-plugins

When in doubt, open the JSVM reference for that version — hook names, route handler signatures, and $app methods differ. For mothership v0.39 port work, read v023-upgrade.md and the official JSVM upgrade guide.

Pre-flight checklist

Before writing hook code, verify:

  • Target PocketBase version — use the matching JSVM docs (≤ v0.22 vs ≥ v0.23)
  • No async/await, Promises, or .then()
  • No fetch, setTimeout, setInterval, DOM APIs
  • No Node built-ins (fs, http, path, etc.)
  • Use require() for modules (CommonJS only)
  • Use $app / record APIs — not new PocketBase()
  • External HTTP via $http.send() (sync), not fetch
  • $app.store() values that cross requests: JSON.stringify/parse at boundaries — never mutate get() results in place (app-store.md)
  • Json fields, hook routers, client errors: skim quirks.md if behavior looks like Node

For full environment constraints, see constraints.md. Goja behavioral quirks (toString, hoisting, json fields, error sanitization): quirks.md.

File layout

pb_hooks/
├── main.pb.js          # auto-loaded entry hooks
├── config/
│   └── config.js       # shared module (require target)
└── posts.create.pb.js
  • Only *.pb.js files are auto-loaded as hook entry points.
  • Shared modules: plain .js files loaded via require().
  • Use ${__hooks} for the hooks directory path:
js
const config = require(`${__hooks}/config/config.js`)

Hook file hot reload (in-process)

PocketBase watches hook JS on disk (pb_hooks/*.pb.js and files loaded via require()). When they change, it reloads hook code inside the running process — the PocketBase process does not exit. This is separate from PM2 or Docker restarts.

Operational implications:

  • Do not git checkout, rsync, or deploy while PocketBase is running if the operation swaps hook files incrementally. A mid-checkout tree can be picked up and loaded as a torn mix of old and new code.
  • Mothership: stop before branch switches or bulk hook deploys (e.g. v39.sh --forward keeps mothership stopped until checkout finishes, then pm2 reload).
  • Customer instances on PocketHost: FTP/phio deploy restarts the instance container so hooks reload from a consistent tree — different mechanism, same “don’t run torn hooks” goal.

Hook categories

Names differ by version — check the JSVM reference for your target.

Category≤ v0.22 examples≥ v0.23 examplesPurpose
BootstraponAfterBootstrap, $app.onBeforeServe().addonBootstrap (+ e.next())Startup initialization
HTTP routesrouterAdd(method, path, handler, ...middlewares)same global, different handler argCustom API endpoints
Record hooksonRecordBeforeCreateRequest, onRecordAfterCreateRequestonRecordBeforeCreateRequest, onRecordAfterCreateSuccess, …Validate/transform on CRUD
Model hooksonModelBeforeUpdate, onModelAfterCreatestill available — verify in JSVM refLower-level DAO events
CroncronAdd(id, expr, handler), cronRemove(id)sameScheduled jobs
MiddlewarerouterUse(...)sameGlobal route middleware

Collection-scoped hooks take the collection name/id as the last argument:

js
onRecordAfterCreateRequest((e) => {
  const record = e.record
  // ...
}, 'users')
Show full SKILL.md (284 more words)Show less

Custom routes

≤ v0.22 — Echo-style context c, colon params:

js
routerAdd('POST', '/test/:testId', (c) => {
  const testId = c.pathParam('testId')
  return c.json(200, { testId })
})

≥ v0.23 — request event e, brace params:

js
routerAdd('POST', '/test/{testId}', (e) => {
  const testId = e.request.pathValue('testId')
  return e.json(200, { testId })
})

With auth middleware (≤ v0.22 mothership pattern):

js
routerAdd('PUT', '/api/instance/:id', (c) => {
  return require(`${__hooks}/mothership`).HandleInstanceUpdate(c)
}, $apis.requireRecordAuth())

Request body (≥ v0.23) — use e.bindBody() + DynamicModel, not JSON.parse(readerToString(e.request.body)):

js
let data = new DynamicModel({ trusted_ips: [] })
e.bindBody(data)
data = JSON.parse(JSON.stringify(data)) // required before destructuring / $common validators
const { trusted_ips } = data

Quick reads: e.requestInfo().body. Raw stream: readerToString(e.request.body) only for webhooks / signature verification.

Full guide: request-body.md (includes BadRequestError wrapping for client-visible validation errors). Official docs: Reading request body.

Request body (≤ v0.22):

js
const body = $apis.requestInfo(c).data

Clients call custom routes via pb.send() — see pocketbase-js-sdk.

Record operations

≥ v0.23 — direct $app methods:

js
routerAdd('PATCH', '/posts/{postId}', (e) => {
  const postId = e.request.pathValue('postId')
  let data = new DynamicModel({ status: '' })
  e.bindBody(data)
  data = JSON.parse(JSON.stringify(data))

  const record = $app.findRecordById('posts', postId)
  record.set('status', data.status)
  $app.save(record)

  return e.json(200, { record })
})

≤ v0.22 — go through $app.dao():

js
routerAdd('PATCH', '/posts/:postId', (c) => {
  const postId = c.pathParam('postId')
  const { status } = $apis.requestInfo(c).data

  const record = $app.dao().findRecordById('posts', postId)
  record.set('status', status)
  $app.dao().saveRecord(record)

  return c.json(200, { record })
})

Raw SQL when needed:

js
$app.db().newQuery('SELECT * FROM posts WHERE id = {:id}')
  .bind({ id: postId })
  .one()

External HTTP

Use synchronous $http.send():

js
const res = $http.send({
  url: 'https://api.example.com/webhook',
  method: 'POST',
  body: { email: record.get('email') },
  headers: { Authorization: 'Bearer ...' },
})

Environment variables

Only process.env is shimmed:

js
const value = process.env.MY_SECRET || ''

PocketHost injects env vars (e.g. ADMIN_SYNC in instance hooks).

Modules

js
// pb_hooks/utils.js
module.exports = {
  mkLog: (ns) => (...args) => console.log(`[${ns}]`, ...args),
}
js
// pb_hooks/main.pb.js
const { mkLog } = require(`${__hooks}/utils.js`)
const log = mkLog('main')

PocketHost specifics

  • User hooks: upload to pb_hooks/ via FTP; changes restart the instance.
  • Instance templates: packages/pockethost/src/instance-app/v22/ (≤ v0.22) and v23/ (≥ v0.23) — compare _ph_admin_sync.pb.js for a side-by-side API diff.
  • Mothership hooks (≥ v0.23 / v0.39): packages/pockethost/src/mothership-app/pb_hooks/ — port guide in v023-upgrade.md. Source is src/lib/handlers/; see .cursor/rules/mothership-hooks.mdc
  • Typings: instance-app/v22/types/types.d.ts (legacy instances); mothership-app/src/types/types.d.ts (control plane)
  • PocketHost sandbox may restrict $os — avoid OS-level calls.

Mothership hook build boundary

Handlers compile with tsdown into pb_hooks/mothership.js and run in Goja, not Node.

  1. Shared hook logic lives in packages/pockethost/src/common/ — must be JSVM-safe (sync, no Node/browser APIs).
  2. Import via $common/<file> subpaths (tsconfig "$common/*": ["../common/*"]). Avoid runtime imports from the $common barrel.
  3. After build, confirm no [UNRESOLVED_IMPORT] warnings — unresolved imports break validation silently at runtime.
typescript
// ✅ validateSshKey.ts — subpath bundles sshPublicKey.ts only
import { parseSshEd25519PublicKey } from '$common/sshPublicKey'

// ❌ tsdown won't resolve without tsconfig path
import { parseSshEd25519PublicKey } from 'pockethost/common'

// ❌ pulls unrelated common modules into pb_hooks
import { parseSshEd25519PublicKey } from '$common'

$app.store() concurrency

Concurrent hooks must not share live Goja objects via $app.store(). Use JSON string boundaries and setFunc for atomic read-modify-write. See app-store.md.

Examples

See hooks-examples.md for copy-paste patterns from this repo and PocketHost docs.

API reference

  1. Pick the JSVM reference for the target version (see Version split above).
  2. Cross-check generated typings — v22: instance-app/v22/types/types.d.ts; mothership: mothership-app/src/types/types.d.ts.
  3. On a running instance, pb_data/types.d.ts matches that instance's PocketBase version.

© pockethost, 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 in .cursor/skills/pocketbase-jsvm of pockethost/pockethost.

  • SKILL.md
  • app-store.md
  • constraints.md
  • hooks-examples.md
  • quirks.md
  • request-body.md
  • v023-upgrade.md

Open the folder on GitHubat commit 82c9ba3

Compare with similar skills

Pocketbase Jsvm 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.

Pocketbase Jsvm compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Pocketbase Jsvm this skillpockethost/pockethost1.4k—~2.7kAutomated safety check: PassMIT
Page AgentTommy-yw/RunbookHermes5463 repos~2.3kAutomated safety check: NotesMIT
Htmlhintmanagedcode/dotnet-skills486—~1.2kAutomated safety check: PassMIT
Dr Jskilljdubois/dr-jskill342—~4.6kAutomated safety check: NotesApache-2.0
Holm Webvolfpeter/holm132—~1.2kAutomated safety check: PassMIT
Documentation Guidevolfpeter/holm132—~1.4kAutomated safety check: PassMIT

Similar skills

  • Page Agent

    Tommy-yw/RunbookHermes

    Embed alibaba/page-agent into your own web application — a pure-JavaScript in-page GUI agent that ships as a single <script tag or npm package and lets end-users of your site drive the UI with…

    546 GitHub starsUsed in 3 repos~2.3k tokens
    Productivity & AutomationAuto-check: notes
  • Htmlhint

    managedcode/dotnet-skills

    Use HTMLHint in .NET repositories that ship static HTML output or standalone frontend templates.

    486 GitHub stars~1.2k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Dr Jskill

    jdubois/dr-jskill

    Creates Java + Spring Boot projects: Web applications, full-stack apps with Vue.js or Angular or React or vanilla JS, PostgreSQL, REST APIs, and Docker.

    342 GitHub stars~4.6k tokensUpdated 8 days ago
    Backend & APIsAuto-check: notes
  • Holm Web

    volfpeter/holm

    A skill your agent uses when working on web apps built with holm, or to answer questions about holm.

    132 GitHub stars~1.2k tokensUpdated 22 days ago
    Backend & APIsAuto-check passed
  • Documentation Guide

    volfpeter/holm

    A skill your agent uses when writing or modifying documentation, guides, or example READMEs.

    132 GitHub stars~1.4k tokensUpdated 22 days ago
    Backend & APIsAuto-check passed
  • Build Perf Baseline

    dotnet/skills

    Official

    Establish MSBuild/.NET build performance baselines before optimizing.

    5.6k GitHub starsUsed in 1 repo~3.6k tokens
    Backend & APIsAuto-check passed

More from pockethost/pockethost

All 11 skills in this repo
  • Blog Voice

    pockethost/pockethost

    Write PocketHost blog posts in Ben Allfree's voice (@cap'n).

    1.4k GitHub stars~977 tokensUpdated 10 days ago
    Auto-check passed
  • Check Push

    pockethost/pockethost

    Run pnpm check:push (lint, types, tests) before git push or PR-ready work.

    1.4k GitHub stars~665 tokensUpdated 10 days ago
    Auto-check passed
  • Commit

    pockethost/pockethost

    Create scoped git commits from the current conversation (e.g.

    1.4k GitHub stars~1.3k tokensUpdated 10 days ago
    Auto-check: notes
  • Feature Blog

    pockethost/pockethost

    Ship user-facing PocketHost features with a blog post instead of semver release notes.

    1.4k GitHub stars~818 tokensUpdated 10 days ago
    Auto-check passed
  • Lemon Squeezy Integration

    pockethost/pockethost

    Full Lemon Squeezy integration — REST API, @lemonsqueezy/lemonsqueezy.js server SDK, Lemon.js checkout overlays, webhooks, customdata, and subscriptions.

    1.4k GitHub stars~1.1k tokensUpdated 10 days ago
    Auto-check passed
  • Pocketbase

    pockethost/pockethost

    Models PocketBase backends: collections, relations, auth, API rules, migrations, and architecture.

    1.4k GitHub stars~1k tokensUpdated 10 days ago
    Auto-check passed

Works with

Categories

Questions about Pocketbase Jsvm

What does Pocketbase Jsvm do?

Writes PocketBase server-side JavaScript in the Goja JSVM: pbhooks, routerAdd, record hooks, cron jobs, and synchronous $app APIs. Pocketbase Jsvm is an agent skill from pockethost/pockethost. Writes PocketBase server-side JavaScript in the Goja JSVM: pbhooks, routerAdd, record hooks, cron jobs, and synchronous $app APIs.

When should I use Pocketbase Jsvm?

Pocketbase Jsvm fits situations like: pbmigrations JS; server-side PocketBase extensions — not the npm JS SDK.

How do I install Pocketbase Jsvm in Claude Code?

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

How do I install Pocketbase Jsvm in Codex?

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

Can I use Pocketbase Jsvm 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 pockethost/pockethost --skill pocketbase-jsvm -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/pocketbase-jsvm, .gemini/skills/pocketbase-jsvm, .github/skills/pocketbase-jsvm and .opencode/skills/pocketbase-jsvm in your project.

What does Pocketbase Jsvm need to run?

Going by SKILL.md and its folder, Pocketbase Jsvm needs the command-line tools its instructions call (git). Our summary lists: Docker.

Does Pocketbase Jsvm access the network?

SKILL.md names 1 domain. As links in the text: pocketbase.io. This is read from the text; nothing was executed.

Is Pocketbase Jsvm 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 Pocketbase Jsvm use?

Pocketbase Jsvm 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 Pocketbase Jsvm use?

About 2.7k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Pocketbase Jsvm?

Skills that share tags, products or a category with Pocketbase Jsvm: Page Agent (Tommy-yw/RunbookHermes, 546 stars), Htmlhint (managedcode/dotnet-skills, 486 stars), Dr Jskill (jdubois/dr-jskill, 342 stars) and Holm Web (volfpeter/holm, 132 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Pocketbase Jsvm?

pockethost (a GitHub organization) maintains it in pockethost/pockethost, which has 1,444 GitHub stars. The repository holds 11 skills in this directory. The repository was last updated on September 28, 2026.

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