Files
STTracker/docs/plans/001-phase1-handoff.md
T
Lucas WintherandClaude Opus 5.5 be04fab098 docs: phase 1 handoff, execution ledger and task reports
Captures the owner's requirements and decisions from the planning
conversation, current branch/worktree state, open tasks 17-19, pending
owner decisions and the controller's rulings so a new agent can resume.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 04:53:02 +01:00

11 KiB
Raw Blame History

status
status
in-progress

Phase 1 handoff (state as of 2026-11-02)

Read this first if you are picking up STTracker Phase 1. It is the bridge between the original conversation with the owner and the repo. Everything the owner decided is in the spec. Everything the controller decided while executing is in docs/plans/001-phase1-sdd/ledger.md (search for "Ruling").

Read in this order:

  1. AGENTS.md
  2. this file
  3. docs/specs/001-sttracker-v1-design.md
  4. docs/plans/001-phase1-own-your-data.md
  5. docs/plans/001-phase1-sdd/ledger.md

1. What the owner asked for, and decided

The original request. A self-hosted "meta" entertainment tracker.

  • Users connect their accounts on other platforms and get everything in one place.
  • They can create their own entries when no platform has the item.
  • Required platforms: Hardcover, Backloggd, Trakt and Last.fm.
  • Stack: Bun with SQLite or Postgres.
  • After the research, prepare the repo with the "preparing repos for agents" skill and push it to https://gitea.lucaswinther.info/lucasw89/STTracker.git.

Why the owner wants it (their own words, summarised):

  • Detect entries that were deleted or merged without their knowledge.
  • Get backups that platforms don't offer.
  • Move data between services that have no link to each other.
  • Let an AI help convert data between services.
  • Log things quickly without needing a "real" ID such as an ISBN or a TMDB id, and fix them later.
  • Have the same features for every kind of media, instead of a separate "Trakt for X" per media type.
  • Get cross-media recommendations and lists, e.g. Leitner → Magnus Archives → Voices of the Void → Twilight Zone.
  • Have a personal, shareable page.
  • The app must put the user in control. Users who keep a spreadsheet or Obsidian/Joplin notes must not have to conform to the data. Examples they gave:
    • screenshots on games;
    • where they bought something;
    • rating a whole series as well as each book.

Owner decisions (all are already in the spec):

  • Audience: the owner first, then a few friends, maybe a small public instance later. Social features are a nice-to-have, not now.
  • Backloggd: wait for its official CSV export. Do not scrape it (it has no API and sits behind Anubis bot protection).
  • Music: ListenBrainz is primary, with Libre.fm as a mirror and Last.fm as a read-only archive.
  • Sources are plugins, so they can be fixed or added without big core changes.
  • Owned library: a private "owned library" (Steam, Jellyfin and so on) that never shows on the profile.
  • Other apps plug in later: Jellyfin, Kavita and Calibre-Web, through STTracker's own API, app tokens and OAuth. Phase 3 ingest: webhooks, a ListenBrainz-compatible endpoint and kosync.
  • Stack: React plus Docker.
  • Look:
    • The app is "Hardcover-style".
    • The public page is "scrapbook + river".
    • "Shelf" and "card catalogue" are parked as future themes.
    • Mockups: docs/design/mockups/.
  • Conflicts: when two sources disagree, ask the user via the Changes inbox. The same play from two sources is merged.
  • Write-back: Phase 1 is read-only. Write-back is opt-in per connection, off by default, and comes in Phase 2.
  • Execution: "Use subagent drive, and use multiple agents at once."
  • The owner's global preference (~/.claude/CLAUDE.md): once a design is approved, carry it through spec → plan → execution with no extra review stops, and report decisions at the end.

2. Where the code is

  • main (on Gitea): only the bootstrap commit (560c27c). Nothing else has been pushed.
  • feat/phase1 (local only, not pushed) @ 42fea7d contains Tasks 1–16, all reviewed, fixed and merged:
    • db layer, schema, migrations 0001–0003;
    • plugin SDK;
    • auth;
    • works and matching;
    • user layer (entries, engagements, history, lists, copies, custom fields);
    • attachments and crypto;
    • all six plugins (Trakt, Hardcover, MangaBaka, CSV/JSON, ListenBrainz, Last.fm);
    • sync engine and Changes inbox;
    • jobs, scheduler, registry and connections;
    • export, restore and backups;
    • the server API.
  • Last full verification on feat/phase1: 520 tests pass on SQLite+Postgres, and typecheck is clean.

Open work (each item is a branch with a worktree under .worktrees/):

Task Branch @ head State Next step
17 web shell, library, entry detail task/17 @ 9546fa1 Fix round 3 done. Its re-review died on a usage limit before finishing. Re-run the scoped re-review of 4608c97..9546fa1 (review-draft sync; see ledger). If clean, merge into feat/phase1.
18 Changes, Sources, Log, Lists, Owned, Settings, About task/18 @ bbd04a5 Partly done. Committed: core/server log feed, change titles, copy work titles, the plugins device flag, the library cache fix, and the Changes, Sources, Log and Lists screens. Not done: Owned, Settings (prefs, custom fields, tokens, invites, reload, export/import), About, the describeChange/scheduleLabel tests, the CDP check and docs. The implementer stopped on a usage limit. Dispatch a fresh implementer with task-18 brief + this table + "continue from bbd04a5". Then review it. It also must git merge task/17 again after Task 17 is final.
19 Docker, compose, CI, docs task/19 @ 0a54020 Barely started. Only an uncommitted DECISIONS.md reorder exists in .worktrees/t19. Dispatch a fresh implementer (brief + the Task 19 rulings in the ledger). Base it on feat/phase1 after 17/18 land, or merge them in later. The uncommitted DECISIONS edit can be kept or redone.

After 17, 18 and 19 are merged, follow the plan's Completion section:

  1. Full suite on both DBs, plus typecheck.
  2. A whole-branch final review on the most capable model, triaging the deferred minors in the ledger.
  3. git rm the plan, this handoff and docs/plans/001-phase1-sdd/.
  4. Mark the spec implemented.
  5. Merge to main via superpowers:finishing-a-development-branch.
  6. Push only with owner approval.

Branches task/4…task/16 are merged and can be deleted. The .worktrees/t8, t9, t15, t16 worktrees are merged too and can be removed with git worktree remove.

3. How the work is being run (for the next controller)

  • Skill: superpowers:subagent-driven-development, with parallel implementers. The owner asked for this, overriding the skill's one-at-a-time default.

  • Worktrees: the controller creates them itself:

    git worktree add .worktrees/tN -b task/N feat/phase1
    cd .worktrees/tN && bun install --frozen-lockfile
    

    Do not use the Agent tool's isolation: "worktree". It branches from main, not feat/phase1.

  • Workspace scripts:

    • SDD workspace and briefs: bash <superpowers>/skills/subagent-driven-development/scripts/{sdd-workspace,task-brief,review-package}.
    • The ignored workspace is .superpowers/sdd/001-phase1-own-your-data/. A copy of the ledger, rulings, fix findings and implementer reports is in docs/plans/001-phase1-sdd/, because .superpowers/ is gitignored.
  • Dispatch pattern:

    • Implementers read docs/plans/001-phase1-sdd/common-implementer.md, their brief and any task-N-rulings.md.
    • Reviewers read common-reviewer.md.
    • Every fix round gets a scoped re-review.
    • Merge with git merge --no-ff task/N, then run the full suite on both DBs.
    • The owner has interrupted merge commands twice, then replied "Approved." Expect a permission prompt on merges into feat/phase1.
  • Test Postgres: the docker container sttracker-pg-test on 127.0.0.1:55432 (docker start sttracker-pg-test if it is stopped).

    TEST_POSTGRES_URL=postgres://postgres:postgres@127.0.0.1:55432/postgres bun test
    
  • Model choice that worked:

    • Opus for core, engine, server and web implementers and their reviewers.
    • Sonnet for plugins and small fixes.
    • Haiku only for tiny re-reviews.

4. Pending owner decisions (surface these, don't work around them)

  1. Agent permission files. Task 16's implementer tried to add verified commands to .claude/settings.json and .gemini/settings.json, and the harness denied it as agent self-modification. Nobody has worked around this.
    • The wanted change is in docs/TODO.md: allow bun run typecheck, bun apps/server/src/main.ts and bun --hot apps/server/src/main.ts.
    • docs/PERMISSIONS.md and the AGENTS.md Commands section are waiting on the same decision.
    • The owner should either make the edit, or approve an agent making it.
  2. Pushing feat/phase1 to Gitea, and the final merge to main.

5. Key technical decisions made during execution

The full list is in the ledger and docs/DECISIONS.md. The ones a newcomer would otherwise trip on:

  • Database access:
    • A single Kysely dialect over Bun.SQL serves both sqlite:// and postgres://.
    • SQLite runs on one connection behind a mutex, so inside a transaction always use tx, never db.k, or it deadlocks.
    • IDs are UUIDv7. JSON is stored as text.
  • External-ID namespaces are type-specific (trakt_movie, tvdb_episode, anilist_manga, …). Private works can't carry external IDs.
  • field_sources:
    • It records who owns each field. Any non-plugin: actor is stored as "user"; history keeps the full actor (token:<name>).
    • A sync only applies a field it owns. Otherwise it files a pending changed or conflict event.
    • Stale pending events are superseded.
    • Plugin actors never revive deletes.
  • Hierarchy:
    • Creating a child entry also ensures the root ancestor has an entry.
    • Rollups and drill-down work to depth 3, skipping untracked intermediates.
  • Lists from sources are applied. A list becomes user-owned after a user edit.
  • Secrets:
    • Secret config is stored only in encrypted credentials_enc (AES-GCM, key from STTRACKER_SECRET).
    • Rate limits are declared on the plugin manifest (rateLimit).
  • Jobs:
    • The queue lives in the DB, with an advisory-locked enqueue, an atomic claim, a heartbeat and a stale-reaper.
    • Pre-run failures (bad secret, missing plugin) are non-retryable and visible.
  • API:
    • Cookie sessions plus app tokens.
    • CSRF uses the X-Requested-With: sttracker header on every non-Bearer write, including login.
    • JSON bodies require content-type: application/json.
  • Export:
    • The format is sttracker-export/v1: a per-user zip with JSONL files, including deleted rows, aliases and tombstones, and no secrets.
    • Restore goes into an empty account only.
    • Backups are daily, with 0600 files.

6. Not in Phase 1 (from the spec)

The following come later:

  • the public page (scrapbook + river);
  • Markdown vault sync;
  • Steam and Jellyfin owned-library connectors;
  • IGDB, TMDB and OpenLibrary lookups;
  • Libre.fm;
  • write-back and migration;
  • the ingest endpoints;
  • the Kavita, Audiobookshelf, Komga and Calibre-Web connectors;
  • Backloggd CSV import;
  • an MCP server;
  • themes;
  • an OAuth provider;
  • social features.

Deferred minors from every task review are in the ledger, with "minor (deferred)" lines, and in docs/TODO.md.