pb-collection — End-to-end PocketBase tasks-collection field change
SkillProductivityAdd 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.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the pb-collection — End-to-end PocketBase tasks-collection field change skill
What this skill tells your AI
The instructions your AI receives, as published by vscarpenter/gsd-task-manager in .agents/skills/pb-collection/SKILL.md and read by ahel’s review.
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
AGENTS.md→ "PocketBase v0.23+ Gotchas" section. 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 (current is v13).
- 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:
tests/data/schema.test.ts— Zod parse/safeParse with and without the new field.tests/data/task-mapper.test.ts— round-trip mapping.tests/data/db-migration.test.ts— Dexie version upgrade preserves existing data.tests/data/sync-engine.test.ts— push/pull serializes the field correctly.tests/data/import-export.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 typecheckpasses -
bun lintpasses -
bun 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 AGENTS.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).
Signals
- GitHub stars
- 25
- Forks
- 3
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
pb-collection- Source
- github.com/vscarpenter/gsd-task-manager