5.0 KiB
STTracker
Self-hosted meta media tracker: the user's own permanent record of books, games, film/TV, manga, podcasts
and music, pulled from Hardcover, Trakt, MangaBaka, ListenBrainz, Last.fm and more. Bun 1.3, TypeScript 5,
React, Kysely over SQLite (bun:sqlite) or Postgres (Bun.sql). Bun workspaces.
AGENTS.md is the single source of truth for agents here. CLAUDE.md and GEMINI.md only point here.
Deeper context on demand: docs/ARCHITECTURE.md, docs/DECISIONS.md, docs/TODO.md.
Product spec: docs/specs/001-sttracker-v1-design.md. Read it before any feature work.
Commands
Install: bun install --frozen-lockfile
Test: bun test | Single test: TODO(maintainer): confirm bun test <path> once tests exist
Typecheck: TODO(maintainer): confirm bun run typecheck (fails until source files exist)
Lint: TODO(maintainer): confirm once a linter is chosen
Dev / Build: TODO(maintainer): confirm once apps/server exists
Workflow
Required skills: superpowers, impeccable. Check at session start; install if missing.
Specs → docs/specs/NNN-slug.md (permanent). Plans → docs/plans/NNN-slug.md while in progress;
git rm them before opening a merge request. The spec is the record.
(Overrides the superpowers default paths.)
Anything beyond a trivial fix: brainstorm → spec (sign-off) → plan (sign-off) → TDD → review. TDD means failing test first, watch it fail, minimal code, watch it pass, commit. Tick plan checkboxes as you go so an interrupted session is resumable. Trivial changes (typo, version bump, one-line config): say "trivial, skipping spec" and proceed.
Use impeccable for user-facing UI: craft for new UI, audit/polish on existing UI,
harden before shipping. Design context: PRODUCT.md, DESIGN.md, docs/design/mockups/.
Rules
- Bun-native only:
Bun.serve()with HTML imports for the web app. No Express, no Vite.bun:sqliteandBun.sql. Nobetter-sqlite3,pgorpostgres.js.bun test. No Jest or Vitest.Bun.password,Bun.file.- Bun loads
.envitself. No dotenv.
- Domain code queries through Kysely from
packages/db. Dialect-specific SQL lives only inpackages/db. Every DB-touching test must pass on both SQLite and Postgres. - Syncs never overwrite or delete user data directly. Source records go through the change engine.
It applies a value only if
field_sourcessays the user never edited the field; anything else becomes a Changes-inbox event. Deletes are soft (deleted_at). - Plugins (
plugins/*) import only@sttracker/plugin-sdk. They never importpackages/dbor core internals, and they returnSourceRecords instead of writing. packages/*andplugins/*never import fromapps/*.- IDs are UUIDv7 (
newId()) generated in app code. Ratings are integers 0–100. Dates carry a precision (day | month | year | unknown). - Tests never call live APIs. Plugin tests use recorded fixtures through the SDK test harness.
- Write-back (
push) is opt-in per connection and off by default. No plugin pushes in Phase 1.
Architecture
apps/server -> Bun.serve: REST API /api/v1, /ingest/<plugin>, job worker, serves the web app
apps/web -> React app via HTML imports
packages/core -> domain services: entries, matching, change engine, history, export
packages/db -> Kysely setup, SQLite/Postgres dialects, migrations
packages/plugin-sdk -> plugin contract, SourceRecord types, http/rate-limit helpers, test harness
plugins/ -> one source integration each
Full picture: docs/ARCHITECTURE.md. Read it before your first change in a session.
Boundaries
Never touch: docs/design/mockups/ (reference only), node_modules/, data/.
Never commit .env, secrets, API keys, or recorded fixtures containing real tokens.
Never force-push, rewrite pushed history, or commit directly to main.
Ask first: new runtime dependencies · public API, export schema (sttracker-export/v1) or
migration changes after release · auth, token and credential-encryption code · anything destructive
(rm -rf, git reset --hard, DB resets) · work the approved plan does not cover.
If the task turns out much larger than the plan assumed: stop, report, re-plan.
Docs duties
Same commit as the code, not "later":
docs/ARCHITECTURE.md: when a module, boundary, or data flow changes.docs/DECISIONS.md: append-only; any choice a future maintainer would reverse-engineer.docs/TODO.md: anything noticed and deliberately not fixed. NoTODOcomments in source.docs/PERMISSIONS.md: together with.claude/settings.json,.codex/and.gemini/settings.json, in one commit.
Git
Branches: feat|fix|chore/<slug>. Commits: Conventional Commits. Keep them small, each leaving tests green.
Done means verified
Do not report success on work you have not run. Before saying done, all of these must hold:
- tests run in this session and seen passing, on both databases for DB code;
- typecheck clean;
- matches the approved spec;
- docs duties complete;
git statusclean and the diff is only what you intended.
"It should work" is not verification.