diff --git a/.gitignore b/.gitignore index 61b3db32..b2fcc709 100644 --- a/.gitignore +++ b/.gitignore @@ -38,11 +38,19 @@ go.work.sum # canonical record lives in commit messages and the running code). docs/superpowers/ -# Per-machine Claude Code settings + remember-skill memory artifacts. -# Both are operator-scoped; the canonical project memory lives under -# ~/.claude/projects/ outside the repo. +# Per-machine Claude Code settings + remember-skill memory artifacts + +# project-level Claude/AI instruction files. All operator-scoped; the +# canonical project memory lives under ~/.claude/projects/ outside the +# repo. CLAUDE.md/AGENTS.md/GEMINI.md stay on the operator's machine +# only — they're tool-specific working notes, not project artifacts. .claude/ .remember/ +CLAUDE.md +AGENTS.md +GEMINI.md +.cursorrules +.windsurfrules +.aider.conf.yml # Flutter flutter_client/.dart_tool/ diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 52d895d9..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,72 +0,0 @@ -# Minstrel — Claude working instructions - -## Porting discipline (HARD RULE — overrides default behavior) - -The Android native client (`android/`) is a **port of the Flutter client** -(`flutter_client/`). The Flutter client is the source of truth for behavior, -layout, copy, and data flow. When building or fixing any Android feature that -exists in Flutter: - -1. **Read the Flutter source FIRST.** Open the actual `flutter_client/lib/...` - file(s) for the feature before writing any Kotlin. Do not work from memory, - from a summary, or from an assumption about "the shape." If you have not - opened the Flutter file in this session, you have not earned the right to - write the Android version. - -2. **Replicate the user-visible behavior exactly; implement it idiomatically.** - Match what the user sees and feels: layout structure, section order, empty/ - loading/error states, copy strings, edge cases, and — critically — the - **responsiveness** (the app caches to make the UI feel instant; preserve - that). But you do NOT have to copy Flutter's *implementation*. Flutter uses - drift `watch()` + Riverpod `invalidate`; the well-supported Android idioms - are Room + Flow, Compose state, WorkManager, Media3. **Prefer the native - mechanism that delivers the same or better UX** over a literal transliteration - of the Dart. Exact on behavior + feel; idiomatic on structure. If a more - native approach genuinely improves the experience, do that (and note it in - the parity map as an intentional, better-supported divergence). - -3. **Never silently substitute a different design.** If the faithful port seems - hard, blocked, or impossible, STOP and verify by reading more of the Flutter - source + the Android data layer. The blocker is usually wrong — the data or - API you think is missing is often already there (e.g. `audio_cache_index` - already carried `lastPlayedAt`; the offline pool was never actually blocked). - If after reading it is genuinely blocked, **raise it as a question** rather - than shipping a scoped-down or alternative design. - -4. **Quote the Flutter file when you start a feature.** Lead the work with - "Here's `flutter_client/lib/` — here's what it does — here's the - Android port," so divergence is caught before code is written, not after. - -5. **Keep the parity map current.** `docs/superpowers/parity-map.md` maps every - feature → Flutter source path → Android target → status. Re-read the relevant - row before porting; update it after. This is the durable reference — rely on - it, not on session memory, because context gets compacted on long sessions. - -## Repo conventions (already in force) - -- **No GitHub — Gitea only.** PR/issue ops via the gitea MCP (server lives at - git.fabledsword.com, migrated from Forgejo); CI runs under `.gitea/workflows/`. - Never use `gh` or github.com URLs. -- **Git flow:** work on `dev` → PR to protected `main` → tag release. Never push - to `main`. -- **No in-task tests/builds.** Do not run flutter/gradle/npm `test`/`build`/ - `analyze` during implementation — CI verifies. Codegen scripts only. -- **CI is operator-side.** After `git push origin dev`, the operator reports the - result; don't poll Gitea. -- **Specs/plans/audits/parity-map live local.** `docs/superpowers/` is - `.gitignored` — save there for operator review; never commit those. -- **detekt gates CI.** Watch the recurring ones: 60-line `LongMethod`, - 11-function-per-file `TooManyFunctions` (use `@file:Suppress` with a one-line - rationale for Compose-helper density), `ReturnCount` ≤ 2, `MagicNumber`, - `MatchingDeclarationName`. Keep lines ≤ 100 chars. - -## Android port shape (quick reference) - -- Screens: `*Screen.kt` with the `@HiltViewModel` inline at the top of the file. -- Repositories: `*/data/*Repository.kt`. Wire models: `models/wire/*Wire.kt`. - Domain models: `models/*.kt`. -- App-lifetime singletons start via the "construct-the-singleton trick" — an - `@Inject lateinit var` in `MinstrelApplication` whose `init {}` wires up. -- Server errors are `{"error":{"code":"...","message":"..."}}`; surface them - through `ErrorCopy.fromThrowable(e)`, never raw `e.message`. -- Cross-device reactivity: collect `EventsStream.events` filtered by `kind`.