pb-collection
Skill40 starsChanged 40 days agoMITView on GitHub
Add or modify a field on the PocketBase tasks collection end-to-end — schema script, task-mapper, Zod schema, Dexie version bump, migration test. Use when the user wants to add/remove/rename a synced task field. Codifies the PocketBase v0.23+ gotchas and recurring step-order mistakes.
In this repository29 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- branch-preflightSkill
- cleaning-up-merged-branchesSkill
- diagnoseSkill
- grill-meSkill
- grill-with-docsSkill
- handoffSkill
- improve-codebase-architectureSkill
- inkwell-retrofitSkill
- open-knowledgeSkill
- pb-collectionSkill
- reviewable-pr-slicingSkill
- setup-matt-pocock-skillsSkill
- shadcnSkill
- shipSkill
- source-command-build-nextSkill
- source-command-qcheckSkill
- source-command-triage-prsSkill
- to-issuesSkill
- verify-frontend-changeSkill
- branch-preflightSkill
- claude-code-primitivesSkill
- cleaning-up-merged-branchesSkill
- inkwell-retrofitSkill
- reviewable-pr-slicingSkill
- verify-frontend-changeSkill
- verify-gsdSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
23 rules. About 0 are common, 9 are distinctive, and 14 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈9
Distinctive · estimate
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 25
Do NOT invoke for local-only Dexie fields (those don't need the PB layers).
- Very specific: line 29
Read .claude/rules/pocketbase-sync.md.
- Very specific: line 37
Add the field to the taskSchema (and taskInputSchema if user-settable).
- Very specific: line 38
Use .safeParse() callers; if this is a user-input path, the schema must already be wired to a safeParse boundary.
- Very specific: line 40
Update both exportSchema (.strict()) and importSchema (.strip()).
- Distinctive: line 43
Add the camelCase ↔ snake_case mapping.
- Very specific: line 45
Test the mapper round-trip in tests/data/task-mapper.test.ts.
- Very specific: line 48
Add the field to the tasks collection definition in the script.
- Very specific: line 49
If the field needs to be sortable/filterable, add a custom index — but the index must reference the new field, NEVER created or updated.
- Very specific: line 50
Run the script against https://api.vinny.io (requires _superusers admin auth — endpoint is /api/collections/_superusers/auth-with-password, …
- Distinctive: line 51
Verify the field appears in PB admin UI before continuing.
- Distinctive: line 55
Add the field to the relevant table schema.
- Distinctive: line 56
If the field is indexed locally, add it to the index list.
- Very specific: line 57
Write a migration block if existing rows need backfill (use upgrade() callback).
- Distinctive: line 60
If the field is settable on create/update, expose it on the input type.
- Distinctive: line 61
Default it where appropriate.
- Very specific: line 64
Verify push-side serializes the new field via task-mapper.
- Distinctive: line 65
Verify pull-side deserializes it.
- Distinctive: line 66
If the field affects LWW conflict resolution, document why in a code comment.
- Very specific: line 69
Add the field to schemas in tools/schemas/ if exposed through MCP tools.
- Very specific: line 70
Update handlers in tools/handlers/ to read/write it.
- Very specific: line 71
Run npm run build in packages/mcp-server/.
- Very specific: line 81
Run bun run test -- --coverage and confirm changed-file coverage ≥80%.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
pb-collection — End-to-end PocketBase tasks-collection field change
This skill walks through every place a field touches when added to the synced tasks collection. Skipping any step has bitten us before — the order matters.
When to invoke
User says any of:
- "Add a
<field>to tasks" - "Sync
<field>across devices" - "PocketBase needs
<field>" - "Update the tasks schema"
Do NOT invoke for local-only Dexie fields (those don't need the PB layers).
Prerequisites — verify before touching code
- Read
.claude/rules/pocketbase-sync.md. The gotchas below are condensed but the source of truth is there. - Confirm the user has the PocketBase admin password handy (needed to run
scripts/setup-pocketbase-collections.sh). - Confirm the field is not a system field name (
id,created,updated,collectionId,collectionName). - Confirm field type is supported by both Dexie and PocketBase:
text,number,bool,json,date. Never userelationto_pb_users_auth_(placeholder doesn't resolve at runtime).
Step order (do not reorder)
1. Update Zod schema — lib/schema.ts
- Add the field to the
taskSchema(andtaskInputSchemaif user-settable). - Use
.safeParse()callers; if this is a user-input path, the schema must already be wired to a safeParse boundary. - For optional fields, default to a sensible value (
.optional().default(...)) so legacy tasks parse without error. - Update both
exportSchema(.strict()) andimportSchema(.strip()).
2. Update task-mapper — lib/sync/task-mapper.ts
- Add the camelCase ↔ snake_case mapping. PocketBase uses snake_case; the app uses camelCase.
- Both directions:
mapToRemote()andmapFromRemote(). - Test the mapper round-trip in
tests/data/task-mapper.test.ts.
3. Update PocketBase collection — scripts/setup-pocketbase-collections.sh
- Add the field to the
taskscollection definition in the script. - If the field needs to be sortable/filterable, add a custom index — but the index must reference the new field, NEVER
createdorupdated. - Run the script against
https://api.vinny.io(requires_superusersadmin auth — endpoint is/api/collections/_superusers/auth-with-password, not/api/admins/). - Verify the field appears in PB admin UI before continuing.
4. Bump Dexie version — lib/db.ts
- Increment the version (read the latest
version(...)call inlib/db.ts;CLAUDE.mdtracks the current number). - Add the field to the relevant table schema.
- If the field is indexed locally, add it to the index list.
- Write a migration block if existing rows need backfill (use
upgrade()callback).
5. Update CRUD — lib/tasks.ts and lib/tasks/crud/
- If the field is settable on create/update, expose it on the input type.
- Default it where appropriate.
6. Update sync engine — lib/sync/pb-sync-engine.ts
- Verify push-side serializes the new field via
task-mapper. - Verify pull-side deserializes it.
- If the field affects LWW conflict resolution, document why in a code comment.
7. Update MCP server — packages/mcp-server/src/tools/
- Add the field to schemas in
tools/schemas/if exposed through MCP tools. - Update handlers in
tools/handlers/to read/write it. - Run
npm run buildinpackages/mcp-server/.
8. Tests — REQUIRED before claiming done
Write or update:
- A schema test under
tests/data/— Zod parse/safeParse with and without the new field. tests/data/sync/task-mapper.test.ts— round-trip mapping.tests/data/db-migrations.test.ts— Dexie version upgrade preserves existing data.tests/data/sync/pb-sync-engine.test.ts(andpb-push/pb-pull) — push/pull serializes the field correctly.tests/data/import.test.tsandtests/data/import-export-sync.test.ts— import (lenient.strip()) accepts old exports without the field; export (strict.strict()) emits it.
Run bun run test -- --coverage and confirm changed-file coverage ≥80%.
9. Verification gate — before declaring done
bun typecheckpassesbun lintpassesbun run testpasses- Created a task with the new field locally, synced to PocketBase, verified field present in PB admin
- Logged out + back in on a second device (or cleared local data and re-pulled), verified field round-trips
- Exported tasks → imported them back → field preserved
- If the field is user-input, verified
safeParserejects bad input with a useful error toast (sonner, notalert())
10. Commit
Conventional commit format: feat(sync): add <field> to tasks collection or feat(schema): .... Bump package.json patch or minor depending on user impact.
Gotchas (condensed — full list in .claude/rules/pocketbase-sync.md)
- Sort/filter restriction — Do not reference
createdorupdatedin PB sort/filter strings. Useclient_updated_at. - Admin endpoint —
/api/collections/_superusers/auth-with-password, not/api/admins/.... - Relation placeholder —
_pb_users_auth_doesn't resolve. Usetextfor owner FK. - Custom indexes — Cannot reference system columns. Index on the new custom field only.
- Rate limiting — Push throttled to 100ms between requests; if your change increases write volume, verify no 429s in PB logs.
- Test runner — Use
bun run test, NOTbun test(the latter invokes bun's built-in runner, not vitest). - localStorage in tests —
localStorage.clear()doesn't work in jsdom under bun; uselocalStorage.removeItem(key).
Anti-goals
This skill does NOT:
- Set up a brand-new PB collection (that's a one-time
scripts/setup-pocketbase-collections.shrun). - Migrate from a different sync backend.
- Handle local-only Dexie fields (skip steps 2, 3, 6, 7 — but the schema and Dexie steps still apply).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

