Guidance for AI coding agents working in this repository.
This file is the hard-rules and orientation index. Longer reference material lives in:
README.md- project overview.docs/product.md- product strategy, users, brand, and design principles.docs/design.md/docs/design.json- visual design system and machine-readable sidecar.docs/media-persistence.md- media persistence policy details.docs/agent/product.md- product intent plus Reddit/NSFW notes.docs/agent/testing.md- detailed testing decision policy and test priorities.docs/agent/tools.md- MCP/tool-server usage map.docs/agent/skills.md- skill usage map.skills/- repo-local copies of skills referenced bydocs/agent/skills.md.- Supabase migrations and current committed specs/plans - source of truth for schema and approved work.
archive/ai-artifacts/README.md- historical AI-generated specs, plans, prompts, and mockups; reference-only, not production source of truth.
Current installed stack:
- Next.js 16.2.4 App Router, React 19.2.4, TypeScript 5.x
- Tailwind CSS v4 and shadcn 4.4.0
- Supabase for auth and database through
@supabase/ssr @supabase/ssr0.10.x and@supabase/supabase-js2.104.x- Supabase CLI 2.95.x
- Vitest 4.x, Playwright 1.59.x, ESLint 9.x
- Runtime arbitrary-site URL extraction uses the bundled
youtube-dl-execyt-dlpbinary in production. Local overrides can useYTDLP_PATH, ayt-dlpexecutable onPATH, orpython3 -m yt_dlp. - Root
postinstalldownloads the standalone platformyt-dlpbinary intonode_modules/youtube-dl-exec/binso Vercel Functions do not depend on system Python. - Optional server-only
NHENTAI_API_KEYfor runtime nHentai gallery API requests. Store it in local/deployment secrets only, never asNEXT_PUBLIC_*. - Reddit runtime fetching intentionally does not use Reddit OAuth credentials. It uses public Reddit JSON and then public Reddit RSS when JSON is forbidden by Reddit. RSS fallback resolves Reddit-hosted
v.redd.itvideos through Reddit's publicredditmedia.com/mediaembed/<postId>endpoint, Reddit gallery links through old Reddit gallery HTML, and external provider links such as Redgifs through the bundled runtimeyt-dlpextractor. All paths are runtime-only. - Optional server-only
REDDIT_REDLIB_ORIGINoverrides the last-resort Redlib origin(s) used when Reddit JSON/RSS and old Reddit are forbidden for pasted post URLs or listing URLs. Redlib fallback must convert media links back to original Reddit CDN URLs and remain runtime-only. Browser-side Reddit JSONP fallback may be used only as runtime recovery when the app API is forbidden/rate-limited; it must not persist returned Reddit payloads or media URLs. - Auth providers: email/password and Google. Reddit is a runtime content source only, not a login provider.
- Vercel Git integration for preview branch deployments; production deployment/promotion remains manual.
- Mobile-first user experience
Current package/runtime defaults:
- Use Node 24 via
nvm use 24. - Use npm workspaces and the checked-in root
package-lock.json. - The Next.js frontend app lives in
frontend/; root npm scripts delegate to that workspace. - The default shell may still expose system Node 18. Always run
nvm use 24before npm commands; Next.js 16 will not run on Node 18. - Main scripts:
npm run dev,npm run build,npm start,npm run lint,npm run format,npm run format:check,npm run typecheck,npm test,npm run test:watch,npm run e2e. - Supabase local scripts:
npm run supabase:start,npm run supabase:stop,npm run supabase:reset,npm run supabase:test. npm testruns Vitest/jsdom unit tests infrontend/. It excludesfrontend/tests/e2e.npm run e2eruns Playwright desktop Chrome and iPhone 15 mobile projects and starts the dev server throughnvm use 24. GitHub E2E setsPLAYWRIGHT_CHROMIUM_CHANNEL=chromeand uses the hosted runner's system Chrome, so do not add a Playwright browser install step back to CI unless the runner image changes.- Prettier 3.x is configured. Use
npm run formatto write formatting andnpm run format:checkfor verification. - Keep local app environment files in
frontend/.env.local; keepsupabase/,.beads/,.serena/, and docs at repo root. - Vercel deployment should use
frontend/as the project root directory. - Browser tests require Linux browser dependencies in WSL; if Chromium cannot launch, report the missing shared library and do not claim browser verification passed.
- Supabase local verification requires Docker socket access. If
supabase startfails with Docker permission errors, report the blocker. Current Supabase local config uses API port54321, DB port54322, and Postgres major17. - GitHub Actions workflow
.github/workflows/ci-cd.ymlruns format check, ESLint, typecheck, Vitest, Next build, local Supabase DB tests, and Playwright desktop/mobile e2e on pull requests andmain. - CI install steps pass the built-in
GITHUB_TOKENtonpm cisoyoutube-dl-execcan fetch theyt-dlprelease binary without anonymous GitHub API rate-limit failures. - Vercel Git integration creates preview branch deployments for pull requests.
frontend/vercel.jsondisables automatic deployments frommainonly, so production deployment/promotion remains a deliberate manual action. CI must not deploy or promote production frommainor any branch. - GitHub Actions workflow
.github/workflows/release.ymlmanually creates GitHub Releases frommain. It requires a human-selectedvX.Y.Zversion, reruns core gates, refuses duplicate tags/releases, and prepends production URL plus commit metadata to generated release notes. - CI Supabase tests must stay local-only. Do not add
--linked,db push,SUPABASE_ACCESS_TOKEN, or remote database URLs to the test workflow unless the production/staging database deployment strategy is explicitly changed. - Saved free-layout templates use
viewer_templatesin Supabase andscrollable.workspace-templates.v1in localStorage.
Build a reels-like scrollable image/video feed viewer. Full product direction and Reddit/NSFW implementation notes live in docs/agent/product.md.
These rules are core product constraints. Keep them visible here because violations are high risk.
- Never persist third-party media from Reddit or any other site.
- Never rehost third-party media.
- Never proxy-cache third-party media as application-owned content.
- Never persist third-party media URLs, thumbnails, cached Reddit JSON responses, raw
yt-dlpJSON, normalized runtime feed/media items, raw Reddit item/post IDs, or local upload object URLs. - User-pasted Reddit post permalinks and subreddit listing URLs are allowed as saved configuration data because the user intentionally provides them.
- User-hidden Reddit listing or post media items may be saved only as opaque
sha256:hashes of runtime Reddit item IDs scoped to the source configuration. Do not store raw item/post IDs, titles, authors, permalinks, media URLs, thumbnails, payloads, or normalized runtime items for hidden Reddit content. - Never persist absolute local filesystem paths.
- Store only user-created configuration data and operational records needed for the app.
- Fetch third-party media metadata at runtime through approved APIs where possible.
- Do not display images or videos when browsing saved or shared configurations/workspaces. Saved and shared surfaces should show configuration metadata only until a runtime feed is opened.
Acceptable stored data:
- User identity records from Supabase Auth.
- User profile/preferences needed for the app.
- Feed configurations, including user-pasted Reddit post permalinks and subreddit listing URLs.
- User-authored native video time ranges for URL rows and local file order indexes.
- Viewer workspace/session layout metadata in
viewer_sessions, including tab names, layout mode, grid dimensions, source configuration metadata, timer settings, slots, and free-layout rectangles. - Sharing settings, ownership, timestamps, and audit/security metadata for saved configurations/workspaces.
- Runtime logs or rate-limit records that do not contain third-party media payloads.
- User-selected local image/video/audio file byte copies in browser IndexedDB for saved local layouts, plus metadata-only local
cacheSetIdreferences in saved layouts. display_optionsmay store display/config preferences only, not third-party media metadata.viewer_sessions.sessionsmust remain metadata-only and must not contain raw Reddit item/post IDs, media URLs, thumbnails, listing payloads, normalized runtime items, or local upload object URLs. Opaquesha256:Reddit hidden-item hashes are allowed.- Layout layers may store layer IDs, layer names, active layer IDs, and per-source layer membership only.
- Free-layout templates may store empty box rectangles, layer IDs, active layer IDs, and timer settings only. They must not store source configs, pasted third-party URLs, local cache set IDs, runtime media URLs, thumbnails, provider payloads, local object URLs, or normalized runtime items.
- URL resolver hints may include
provider:gallery,provider:hitomi, andprovider:yt-dlp, but extracted gallery image URLs, stream URLs, HLS segment query parameters, thumbnails, cookies, headers, API keys, raw gallery HTML/JSON, and rawyt-dlpoutput remain runtime-only.
Prefer these boundaries when implementation starts:
frontend/src/sources: source adapters for Reddit and local uploads.frontend/src/normalization: convert source responses into runtime feed items.frontend/src/viewer: vertical reels feed, timer, keyboard/touch navigation, and horizontal media carousel.frontend/src/viewer/workspaces: local/Supabase workspace tab, layout layer, and layout serialization. Keep this metadata-only.frontend/src/viewer/templates: reusable free-layout empty box templates. Keep templates source-empty and metadata-only.frontend/src/local-uploads: object URL lifecycle and browser IndexedDB Blob cache for user-selected local files. Do not store local paths.frontend/src/configurations: saved feed configs and validation.frontend/src/auth: Supabase auth integration and provider setup.frontend/src/data-access: Supabase queries/mutations and RLS-aware access patterns.frontend/src/ui: shadcn/ui components, layout primitives, and mobile-first interaction controls.
Keep data fetching, normalization, persistence, and UI rendering separate enough that each can be tested independently.
Build mobile first. Treat the iPhone 15 Playwright project and narrow browser viewport as primary, then enhance for desktop.
- Start UI/layout work from the smallest supported viewport and touch workflow, not from desktop.
- Prefer single-column, thumb-reachable controls and compact progressive disclosure before adding desktop grids or wide toolbars.
- Use responsive constraints that prevent overflow, clipped dialogs, hidden controls, and text collisions on mobile.
- Keep desktop behavior as an enhancement of the mobile workflow, not a separate implementation.
mobile-compact-controlsintentionally allows compact 40px controls. Do not increase those compact buttons to 44px to satisfy touch-target checks; preserve the 40px design and adjust tests for browser subpixel rounding when needed.- When UI, layout, interaction, dialogs, overlays, drag/drop, or fullscreen behavior changes, verify mobile and desktop before completion.
- If mobile verification cannot run, report the exact blocker and do not claim mobile behavior passed.
Use these rules to prevent the kind of large-file refactors already needed in the workbench. They are based on Brooks-Lint decay risks: cognitive overload, change propagation, knowledge duplication, accidental complexity, dependency disorder, and domain model distortion.
The 800-line number is not a Brooks-Lint or book rule. It is a local repo guardrail derived from Brooks-Lint's cognitive-overload risk. Brooks-Lint's concrete signals are smaller: mixed-abstraction functions over 20 lines, parameter lists over 4 parameters, boolean expressions with 3 or more combined conditions, nesting deeper than 3, fan-out over 5 imports, and changes that ripple across more than 3 unrelated files.
Before adding behavior:
- Name the Brooks-Lint risk most likely to grow if the behavior is added inline.
- Choose the smallest existing module that owns the behavior, or create a focused module before adding feature logic.
- Keep React components responsible for state ownership, effects, side effects, and UI wiring. Move validation, state transitions, serialization, payload building, placement, timer math, drag math, and runtime orchestration into focused helpers.
- If a change would add more than 50 lines to a file already over 500 lines, create or extend a helper module in the same branch.
- If a file is over 800 lines, add no new feature/business logic there unless the change is only wiring existing helpers. Extract first.
- If a function grows past 20 lines while mixing UI, state transitions, persistence, and runtime work, split it before continuing.
- If a helper needs more than 4 parameters, prefer a typed input object with domain names.
- If one change touches more than 3 unrelated modules, stop and write/update the implementation plan so the boundaries are explicit.
- Avoid speculative abstractions. Extract around current repeated decisions or current complexity, not imagined future providers.
- Treat large test files like large production files: if a test file is over 800 lines, add new scenarios to a focused sibling test file or colocated helper test unless the scenario is truly broad integration coverage.
- Before completion, state whether any large file grew, why, and what remains to extract.
Workbench ownership rules:
feed-workbench.tsx: React state ownership, effects, side-effect boundaries, handler wiring, toasts, and composing dialogs/views.*-state.ts: pure state transitions, validation, and calculations.*-actions.ts: pure orchestration that returns setter-ready state.runtime-sources.ts: runtime source fetching/orchestration only; no persistence.local-sources.ts: local upload filtering, local cache helpers, and object URL helpers.workspace-state.ts: workspace serialization, localStorage, and sessionStorage state.workspace-actions.ts: workspace tab/open/close/library orchestration.workspace-save-state.ts: save validation and Supabase payload builders.free-layout-state.ts/free-drag-state.ts: free-layout rect updates and drag math.timer-actions.ts: timer state orchestration.
Before implementation:
- Write or update a short product/design spec for new major features.
- Confirm the data persistence rules above.
- Create an implementation plan before touching app code.
During implementation:
- Prefer existing repo patterns over new abstractions.
- Use TypeScript types for persisted config and runtime media items.
- Use structured API clients/parsers rather than ad hoc string parsing.
- Build mobile-first. Do not treat mobile as a final pass after desktop works.
- Use
docs/agent/tools.mdanddocs/agent/skills.mdfor task-specific tool/skill choices. - Use
docs/agent/testing.mdfor detailed test decisions and verification expectations.
Use tests intentionally. Do not add tests just to satisfy a process rule.
- TDD is required for business logic, normalization/parsing, validation, auth/RLS/privacy, persistence, API routes/server actions, state transitions, timers, feed advancement, carousel behavior, error handling, accessibility-relevant interaction, and bug fixes where a regression test can reproduce the issue.
- New automated tests are usually not required for purely presentational or documentation-only changes.
- UI-only changes still need typecheck/lint/format checks where relevant, plus browser/mobile viewport verification when layout, responsiveness, or interaction changed.
- See
docs/agent/testing.mdfor detailed rules, completion wording, and high-value test areas.
Test ownership rules:
- Use the narrowest test owner that proves the behavior. Pure helper tests belong next to helper modules as
*.test.tsor*.test.tsx. - Do not add new tests to
frontend/src/components/viewer/feed-workbench.test.tsxby default. If a test file is over 800 lines, choose or create a focused sibling test file unless broad integration coverage is required. - Split workbench integration tests by workflow, for example
feed-workbench-workspaces.test.tsx,feed-workbench-layers.test.tsx,feed-workbench-local-files.test.tsx, andfeed-workbench-interactions.test.tsx. - Keep shared render/setup helpers in one test utility module. Do not copy setup helpers across split test files.
- Before adding to a large integration test file, state why a narrower helper test or focused workflow test would not catch the regression.
- Use Conventional Commits for commit messages, for example
feat: add feed timerorfix: prevent media persistence. - Do not create branches with the
codex/prefix. Use descriptive feature branches without that prefix. - Before completion, run lint, typecheck, tests, build, and browser verification when applicable. The GitHub Actions CI/CD workflow mirrors these checks and also runs local Supabase DB tests.
- Ensure the lint pass includes ESLint and run the configured Prettier check.
- For overlay-style UI changes, include a viewport-bounds check in browser verification.
- Verify auth and RLS paths for signed-out, signed-in, owner, and shared recipient cases when those areas changed.
- Check
git status --short --branch. - Summarize changed files and any checks that could not be run.
- If durable project facts changed, update the relevant Serena memories before finishing. Prefer assigning this to a background Serena memory refresh subagent while implementation or verification continues, then review the memory changes before completion.
This project uses bd (beads) for issue tracking. Run bd prime for current workflow context, or install hooks with bd hooks install when hook-based workflow injection is wanted.
Bead creation expectations:
- Default to creating or claiming a bead before changing code, docs, configuration, tests, schema, workflows, or deployment setup unless the user explicitly asks not to track the task.
- Create beads for bug fixes, feature work, refactors, investigation tasks, verification tasks, and docs/process changes that future agents should remember.
- If a request is more than a tiny one-shot answer or command, make a bead. When unsure, create the bead; extra tracked context is better than lost chat context.
- For large or multi-part work, create a parent
epicorfeaturebead plus child task/bug beads with dependencies instead of one oversized issue. - When substantial follow-up work is discovered but not handled immediately, create a new bead. If it belongs to the current work, add a note or dependency instead of leaving it only in the chat.
- Do not create duplicate beads. Search existing open, in-progress, and recently closed issues first when the task sounds similar.
- At completion, close completed beads with a reason and leave any remaining follow-up as open beads.
Quick reference:
bd ready- Find unblocked work.bd create "Title" --type task --priority 2- Create an issue.bd show <id>- Show issue details.bd update <id> --claim- Claim work.bd close <id>- Complete work.bd dolt push- Push beads to the configured remote.
Use subagents for code review, testing, and continuous refactoring when those activities are requested or when a substantial implementation is in progress or nearing completion. If the active agent runtime requires explicit permission before spawning subagents, ask for that permission first.
Recommended subagent usage:
- Code review subagent: inspect changed files for bugs, regressions, data persistence violations, auth/RLS gaps, mobile UI regressions, and missing tests.
- Testing subagent: run or design focused verification for unit tests, integration tests, browser flows, and mobile layouts.
- Continuous refactoring subagent: while substantial feature work is underway, keep a parallel pass focused on small, behavior-preserving cleanup such as removing duplication, tightening types, improving names, simplifying component boundaries, and aligning code with existing project patterns.
- Serena memory refresh subagent: while another substantial task is running, keep a background pass focused on refreshing relevant Serena memories so durable project context stays current.
- AGENTS.md maintenance subagent: review and update this file when project rules, architecture, commands, MCP servers, skills, deployment setup, auth/data constraints, or testing workflow change.
- Keep subagent tasks bounded and non-overlapping.
- Keep Serena memory refresh work read-focused and non-overlapping with implementation work. Do not ask it to edit files already owned by another subagent or active task.
- Serena memories must stay high-level and durable. Do not store secrets, local paths, third-party media URLs, raw provider payloads, raw Reddit IDs, transient runtime state, or other privacy-sensitive data.
- Do not ask subagents to modify the same files in parallel unless ownership boundaries are explicit.
Use the AGENTS.md maintenance subagent after substantial setup or workflow changes, including:
- New package scripts, test commands, ESLint/Prettier commands, lint/typecheck/build commands, or dev server commands.
- New MCP servers, tools, plugins, or required skills.
- Changes to Supabase schema, RLS policy strategy, auth providers, or stored data rules.
- Changes to Vercel deployment, environment variables, or runtime architecture.
- New product constraints that future agents must preserve.
- Use MCP/tool servers according to the task. Prefer official or local project sources for current facts. See
docs/agent/tools.md. - Use Serena MCP for repository-aware code work when available. At task start, activate
/home/seanlongcc/repos/scrollable, check onboarding status, and read only relevant memories before broad code navigation. - Prefer Serena semantic tools for symbol discovery, references, and symbol-aware edits when changing TypeScript/React code. Use local shell tools like
rg,sed, and package scripts for fast text search, docs, and verification. - Refresh Serena memories after substantial changes to stack, commands, architecture, testing workflow, Supabase schema/RLS, deployment, or project rules. Prefer using a background Serena memory refresh subagent during substantial work when the runtime supports non-overlapping subagents.
- Use
impeccablefor frontend interface design, redesign, critique, audit, polish, and UI quality work. - When a skill is available and its trigger matches the task, read its
SKILL.mdand follow it. Use the minimal set of skills that covers the task. Prefer the repo-local copies inskills/for inspection and onboarding. Seedocs/agent/skills.md. - Supabase MCP is configured for project
ppxkvapcmblfkhregiwb. Use it for schema inspection, migrations, RLS checks, and auth configuration when the current agent session exposes it; otherwise use Supabase CLI, local migrations, and official Supabase documentation.