# 5chan Full LLM Context

> 5chan is a static, serverless, adminless, decentralized imageboard client built on the Bitsocial protocol.

This file is generated by `scripts/generate-llms-files.mjs`. Do not hand-edit it; update the source docs or generator config, then run `yarn llms:generate`.

Use this as compiled context only. Source files, tests, manifests, and live/runtime evidence remain authoritative.

## Index

- [README.md](#readmemd)
- [AGENTS.md](#agentsmd)
- [PRODUCT.md](#productmd)
- [DESIGN.md](#designmd)
- [src/AGENTS.md](#srcagentsmd)
- [scripts/AGENTS.md](#scriptsagentsmd)
- [docs/agent-playbooks/known-surprises.md](#docsagent-playbooksknown-surprisesmd)
- [docs/agent-playbooks/long-running-agent-workflow.md](#docsagent-playbookslong-running-agent-workflowmd)
- [docs/agent-playbooks/bug-investigation.md](#docsagent-playbooksbug-investigationmd)
- [docs/agent-playbooks/translations.md](#docsagent-playbookstranslationsmd)
- [docs/agent-playbooks/skills-and-tools.md](#docsagent-playbooksskills-and-toolsmd)
- [docs/upload-automation-retest-checklist.md](#docsupload-automation-retest-checklistmd)

---

## README.md

Source: https://github.com/bitsocialnet/5chan/blob/master/README.md

```markdown
[![Build Status](https://img.shields.io/github/actions/workflow/status/bitsocialnet/5chan/ci.yml?branch=master)](https://github.com/bitsocialnet/5chan/actions/workflows/ci.yml)
[![Coverage](https://img.shields.io/endpoint?url=https://bitsocialnet.github.io/5chan/badges/coverage.json)](https://github.com/bitsocialnet/5chan/blob/master/scripts/write-coverage-badge.mjs)
[![Release](https://img.shields.io/github/v/release/bitsocialnet/5chan)](https://github.com/bitsocialnet/5chan/releases/latest)
[![License](https://img.shields.io/badge/license-GPL--3.0--or--later-red.svg)](https://github.com/bitsocialnet/5chan/blob/master/LICENSE)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/bitsocialnet/5chan)

<img src="https://github.com/plebeius-eth/assets/blob/main/5chan-logo.jpg" width="378" height="123">

_Telegram group for this repo https://t.me/fivechandev_

# 5chan

5chan is a serverless, adminless, decentralized and open-source imageboard built on the [Bitsocial protocol](https://bitsocial.net). It features the classic imageboard directory structure, but with a crucial difference: **anyone can create and own boards, and multiple boards can compete for each directory slot**.

## Key Features

### Decentralized Board Ownership
Unlike traditional imageboards, 5chan has no global admins or central authority. Anyone can create unlimited boards using [5chan Board Manager](https://github.com/bitsocialnet/5chan-board-manager). Each board owner runs their own P2P node that users connect to peer-to-peer, giving them complete control over their board's content, moderation, and rules.

### Competitive Directory System
5chan maintains the familiar imageboard directory structure (Japanese Culture, Video Games, Interests, Creative, etc.), but introduces competition: **multiple boards can compete for each directory slot**. For example, there can be unlimited "Business & Finance" boards, but only the highest-voted one appears in the directory on the homepage.

Currently, directory assignments are temporarily handpicked by developers through GitHub pull requests. In the future, each directory will have its own voting page. 5chan Pass holders are expected to participate in directory voting, while final governance mechanics are still being designed to include BSO-holder alignment instead of pass-only final control.

### How It Works

- **Current System**: Developers manually curate directory assignments by reviewing pull requests to the [5chan directory files](https://github.com/bitsocialnet/lists/tree/master/5chan-directories).

- **Future System**: Each directory will have its own voting page listing the boards competing for that slot. 5chan Pass holders are expected to participate in directory voting, while final governance mechanics are still being designed to include BSO-holder alignment instead of pass-only final control.

- **Accessing Boards**: Users can access any board at any time using its address, regardless of directory assignment. Boards can be accessed via the search bar, by subscribing to them (which adds them to the top bar), or by directly navigating to their address.

### Future Roadmap

#### In-App Board Creation

Creating boards directly from the 5chan web app (5chan.app) is planned. This requires connecting via RPC to a bitsocial node—technically already possible, but there's no default connection configured. A default connection would require a public RPC service (similar to what Infura provides for crypto wallets, but for bitsocial nodes). This would allow all users to be connected to a P2P node by default using a free tier subscription in the background, potentially monetized via ads injected in the RPC service-owned boards.

#### Directory Voting

Directory voting pages are planned for each slot on 5chan. These pages will list the competing boards for that directory, and 5chan Pass holders are expected to participate in voting. Final governance mechanics are still being designed to include BSO-holder alignment instead of pass-only final control.

## Downloads

- **Web version**: https://5chan.app (also available using Brave/IPFS Companion on https://5chan.eth)
- **Desktop version** (full P2P bitsocial node, seeds automatically): Available for Mac/Windows/Linux, [download from the release page](https://github.com/bitsocialnet/5chan/releases/latest)
- **Mobile version**: Available for Android, [download from the release page](https://github.com/bitsocialnet/5chan/releases/latest)

## Run 5chan in Your Browser With a Local Node

If you want the full P2P node but prefer opening 5chan in your normal browser instead of using the desktop app, use [bitsocial-cli](https://github.com/bitsocialnet/bitsocial-cli). It runs the Bitsocial/IPFS node and serves the bundled 5chan Web UI locally, so you do not need to run this repository separately.

```sh-session
npm install -g @bitsocial/bitsocial-cli
bitsocial daemon
```

When the daemon starts, it prints a `WebUI (5chan - Imageboard-style UI)` URL. Open that URL in your browser to use 5chan through your local node. See the [bitsocial-cli daemon docs](https://github.com/bitsocialnet/bitsocial-cli#running-daemon) for details.

## Creating a Board

In the bitsocial protocol, a 5chan board is called a _community_. To deliver the expected 5chan imageboard UX, a board should run on a bitsocial node together with [5chan Board Manager](https://github.com/bitsocialnet/5chan-board-manager). The board manager applies imageboard-style lifecycle rules that bitsocial communities do not enforce by themselves: thread limits, bump limits, archived-thread retention, and purging of author-deleted content.

To create and run a board:

1. Follow the Docker Compose flow in the [5chan-board-manager README](https://github.com/bitsocialnet/5chan-board-manager#docker-compose-recommended);
2. Create your community and add it to 5chan Board Manager using the commands shown there;
3. Keep the manager running so it can apply 5chan board behavior such as thread archiving, bump limits, and retention cleanup.

Once created, anyone can connect to your community using any bitsocial client (such as 5chan) by using the community address. The address is not stored in any central database—bitsocial is a pure peer-to-peer protocol.

Without 5chan Board Manager, a community can still be opened in 5chan, but it will not behave like a conventional imageboard board: old threads will not be archived when they fall past the last page, bump limits will not be enforced, archived threads will not be purged after the retention window, and author-deleted content will not be automatically purged.

**Note**: Creating boards directly from the 5chan web app is planned for the future (see [Future Roadmap](#future-roadmap)).

## Submitting Your Board to a Directory

To have your board appear in a directory on the 5chan homepage:

1. Ensure your board meets these requirements:
   - Active and well-moderated
   - Relevant to the directory category
   - **99% uptime** (since a board acts like its own server—it's a P2P node)

2. Open a pull request on GitHub by editing the relevant file in the [5chan-directories folder](https://github.com/bitsocialnet/lists/tree/master/5chan-directories)

3. Add your board's entry with:
   - Title: in the format `/directoryCode/ - Title`, e.g. "/biz/ - Business & Finance";
   - Address: the bitsocial community address, whether IPNS key (`12KooW...`) or readable crypto address (`mydomain.eth`);
   - NSFW status: `true` or `false`, must match the standard classification for the directory code.

4. The developers will review your PR and merge it if approved

**Note**: Even if your board isn't assigned to a directory, users can still access it at any time using its bitsocial community address. Directory assignment only affects visibility on the homepage.

## Development

### Prerequisites

- Node.js 22.12.0, pinned in [`.nvmrc`](./.nvmrc)
- Corepack enabled once per machine: `corepack enable`

### Contributor Setup

1. Run `nvm install && nvm use`
2. Run `corepack enable` once
3. Use plain `yarn install`, `yarn build`, and `yarn test`

### Setup

1. Clone the repository
2. Install dependencies: `yarn install`
3. Start the web client: `yarn start`

The dev server normally runs at https://5chan.localhost via [Portless](https://github.com/vercel-labs/portless), which gives each Bitsocial project a stable, named URL instead of a random port. Portless 0.11 serves this URL through an HTTPS proxy on port 443, so the first `yarn start` after install or proxy reset may prompt for sudo; accept the prompt so the URL can stay portless. On non-`master` branches, or when another legacy process is already holding the canonical route, `yarn start` will automatically use a branch-scoped `*.5chan.localhost` URL instead of failing. To bypass Portless and use a plain Vite dev server, run `PORTLESS=0 yarn start`; it will start at `http://localhost:3000` and automatically fall forward to the next free port if `3000` is already in use.

For device testing on a USB-connected Android phone (without relying on `5chan.localhost` DNS from the device):

- `yarn start:android-usb` starts Vite bound to `127.0.0.1` and runs `adb reverse`, so the phone can load the dev site at `http://localhost:3000`. When the server is up, it opens that URL in each connected device’s default browser via `adb`. Set `ANDROID_USB_OPEN_BROWSER=0` to skip auto-open. Requires [Android platform-tools](https://developer.android.com/tools/releases/platform-tools) (`adb` on your `PATH`), USB debugging enabled, and the device showing as `device` in `adb devices`.

### Scripts

- **Web client**: `yarn start` (https://5chan.localhost)
- **Web client (Android phone over USB)**: `yarn start:android-usb` (see above)
- **Electron client** (must start web client first): `yarn electron`
- **Electron client** (don't delete data): `yarn electron:no-delete-data`
- **Web client and electron client**: `yarn electron:start`
- **Web client and electron client** (don't delete data): `yarn electron:start:no-delete-data`

### Challenge Types

Bitsocial communities can require users to solve one or more anti-spam challenges before a publication is accepted. 5chan already supports multiple challenge types, including `url/iframe` challenges so [Mintpass](https://github.com/bitsocialnet/mintpass) communities can run their iframe flow directly inside a modal. The modal first shows a hostname confirmation (showing only the host for mintpass.org, full URL otherwise), then opens the HTTPS iframe with the current theme, replaces `{userAddress}` tokens with the signed-in address, and submits automatically when the user finishes.

### Build

The Linux/Windows/macOS/Android build scripts are in [.github/workflows/release.yml](https://github.com/bitsocialnet/5chan/blob/master/.github/workflows/release.yml)

## License

5chan is open-source software (GPL-3.0-or-later) with no owner—anyone can host their own instance on any domain. The operator of any domain is merely hosting the web app and does not own, create, moderate, or control 5chan or any board content, which is stored peer-to-peer and generated by board owners and users.
```

---

## AGENTS.md

Source: https://github.com/bitsocialnet/5chan/blob/master/AGENTS.md

```markdown
# AGENTS.md

## Purpose

This file defines the always-on rules for AI agents working on 5chan.
Use this as the default policy. Load linked playbooks only when their trigger condition applies.

## Surprise Handling

The role of this file is to reduce recurring agent mistakes and confusion points in this repository.
If you encounter something surprising or ambiguous while working, alert the developer immediately.
After confirmation, add a concise entry to `docs/agent-playbooks/known-surprises.md` so future agents avoid the same issue.
Only record items that are repo-specific, likely to recur, and have a concrete mitigation.

## Project Overview

5chan is a serverless, adminless, decentralized imageboard built on the Bitsocial protocol.

## Instruction Priority

- **MUST** rules are mandatory.
- **SHOULD** rules are strong defaults unless task context requires a different choice.
- If guidance conflicts, prefer: user request > MUST > SHOULD > playbooks.

## Agent Operating Principles

- Before editing, state important assumptions when the task is ambiguous. Ask instead of silently choosing between materially different interpretations.
- After understanding the affected flow, apply the [Ponytail](https://github.com/DietrichGebert/ponytail) solution ladder: skip work that is not required; reuse repository code; prefer the standard library, native platform features, then installed dependencies; only then write the minimum new code. Never trade away explicit requirements, correctness, clarity, validation, error handling, security, accessibility, or necessary tests.
- Keep diffs surgical. Do not refactor, reformat, rename, or "improve" adjacent code unless it is necessary for the task.
- Clean up only artifacts created by the current change, such as newly unused imports or dead helper code.
- For non-trivial work, define success criteria and verify them with the narrowest reliable checks before marking the task complete.

## LLM Knowledge Base Policy

Use compiled context for orientation, not as source of truth.

Source of truth:

- Code, tests, package manifests, docs, and runtime/live evidence when relevant.

Compiled context:

- `AGENTS.md`, directory-specific `AGENTS.md` files, `CLAUDE.md`, and repo-managed `.codex/`, `.cursor/`, and `.claude/` workflow files.
- `docs/agent-playbooks/**`, `docs/agent-runs/**`, `docs/agent-playbooks/known-surprises.md`, and tracked `llms.txt` / `llms-full.txt` files when present.

Agents may use compiled context to navigate quickly, but must verify against source files before making behavioral claims or edits. External code graph, RAG, MCP, or wiki tools are optional local accelerators unless the developer explicitly asks to make one part of the committed workflow.
For very large non-source artifacts such as CI logs, debug traces, generated JSON, or massive tool output, contributors may optionally use `chopratejas/headroom` or a similar local compression tool as a navigation aid, but agents must verify conclusions against the original uncompressed artifact before editing code or making final claims.
When CodeGraph MCP tools are available and `.codegraph/` exists, prefer them for initial symbol lookup, caller/callee tracing, and impact analysis before broad `rg` or file-reading sweeps; still verify important claims against source files before editing or reporting conclusions.

## Task Router (Read First)

| Situation | Required action |
|---|---|
| New UI designed or styled, or any visual/component/theme work (`src/components`, `src/views`, CSS modules, `src/themes.css`) | Read `DESIGN.md` first and follow it; self-review the diff against its Do/Don't list before verifying. 5chan is a classic imageboard: square edges, 1px theme borders, flat surfaces, dense text, theme palette. No rounded corners, pill/badge shapes, hover background fills, CSS transitions, or soft shadows on product UI |
| React UI logic changed (`src/components`, `src/views`, `src/hooks`, UI stores) | Follow React architecture rules below, review the diff with `vercel-react-best-practices` and `vercel:react-best-practices` when available, fix valid findings, then run `yarn doctor` |
| `package.json` changed | Run `corepack yarn install` to keep `yarn.lock` in sync |
| Dependencies or import graph changed | Run `yarn knip` as an advisory manifest/import audit |
| Translation key/value changed | Use the `translate` skill (spawns parallel `translator` subagents); for manual script operations see `docs/agent-playbooks/translations.md` |
| Public-facing English content or AI context changed (`README.md`, `index.html`, `AGENTS.md`, `PRODUCT.md`, `DESIGN.md`, docs pages, or `scripts/generate-llms-files.mjs`) | Run `yarn llms:generate`; inspect and commit any resulting changes to `public/llms*.txt` so LLM indexes stay current |
| Bug report in a specific file/line | Start with git history scan from `docs/agent-playbooks/bug-investigation.md` before editing |
| `CHANGELOG.md` or package version changed | Run `yarn blotter:check`; if needed add a concise release one-liner |
| UI/visual behavior changed | Verify in browser with `playwright-cli` across Chrome/Blink, Firefox/Gecko, and WebKit/Safari; use `./scripts/pw-session.sh` so only one browser is active machine-wide, run engines sequentially, reuse each session for desktop/mobile, and close it before opening the next; if existing browser state matters, confirm whether to use a fresh session or the contributor's current browser session |
| Loading, navigation, or interaction speed matters (or perf may just be a fast dev machine) | Run a low-spec pass: throttle a Chromium `playwright-cli` session with `./scripts/pw-throttle.sh <session> mid` (or `low`), then verify. Chromium only. See `docs/agent-playbooks/low-spec-verification.md` |
| Long-running task spans multiple sessions, handoffs, or spawned agents | Use `docs/agent-playbooks/long-running-agent-workflow.md`, keep a machine-readable feature list plus a progress log, and run `./scripts/agent-init.sh --smoke` before starting a fresh feature slice |
| New reviewable feature/fix started while on `master` | Create a short-lived `codex/feature/*`, `codex/fix/*`, `codex/docs/*`, or `codex/chore/*` branch from `master` before editing; use a separate worktree only for parallel tasks |
| New unrelated task started while another task branch is already checked out or being worked on by another agent | Create a separate worktree from `master`, create a new short-lived task branch there, and keep each agent on its own worktree/branch/PR |
| Open PR needs feedback triage or merge readiness check | Use the `review-and-merge-pr` skill to inspect bot/human feedback, fix valid findings, and merge only after verification |
| Before finishing or committing code, docs, or AI workflow changes, and before pushing/opening a PR | Run the advisory `code-quality-review` skill on the current diff; treat findings as suggestions, not blockers, and address only high-confidence improvements |
| Repo AI workflow files changed (`.codex/**`, `.cursor/**`, `.claude/**`) | Keep the Codex, Cursor, and Claude copies aligned when they represent the same workflow; run `yarn ai-workflow:check` to catch parity and drift issues; update `AGENTS.md` if the default agent policy changes |
| GitHub operation needed | Use `gh` CLI, not GitHub MCP |
| User asks for commit/issue phrasing | Use `docs/agent-playbooks/commit-issue-format.md` |
| Surprising/ambiguous repo behavior encountered | Alert developer and, once confirmed, document in `docs/agent-playbooks/known-surprises.md` |

## Stack

- React 19 + TypeScript
- Zustand for shared state
- React Router v6
- Vite
- bitsocial-react-hooks
- i18next
- yarn
- oxlint
- oxfmt
- tsc (TypeScript 7 native compiler)

## Project Structure

```text
src/
├── components/   # Reusable UI components
├── views/        # Page-level route views
├── hooks/        # Custom hooks
├── stores/       # Zustand stores
├── lib/          # Utilities/helpers
└── data/         # Static data
```

## Core MUST Rules

### Package and Dependency Rules

- Use Corepack-managed Yarn 4, never `npm`. Run `corepack enable` once on a new machine before using `yarn`.
- Pin exact dependency versions (`package@x.y.z`), never `^` or `~`.
- Keep lockfile synchronized when dependency manifests change.

### React Architecture Rules

- Do not use `useState` for shared/global state. Use Zustand stores in `src/stores/`.
- Do not use `useEffect` for data fetching. Use `bitsocial-react-hooks`.
- Do not sync derived state with effects. Compute during render.
- Avoid copy-paste logic across components. Extract custom hooks in `src/hooks/`.
- Avoid boolean flag soup for complex flows; model state clearly in Zustand.
- Use React Router for navigation; no manual history manipulation.

### Design Rules

- Read `DESIGN.md` before designing, styling, or adding any UI, and self-review the diff against its Do/Don't list before verification. `DESIGN.md` is the source of truth for 5chan's classic-imageboard look.
- Preserve the old-school imageboard aesthetic: square edges, 1px theme borders, flat surfaces, dense compact text, and the existing theme palette (CSS variables in `src/themes.css` or `currentColor`).
- Do not introduce modern UI patterns on product surfaces: no rounded corners/`border-radius`, no pill/capsule/badge shapes, no hover background-color changes or CSS transitions/animations on rows or cards, and no soft shadows, glass, gradients, or new accent/marketing colors.
- Functional per-entity colors (e.g. a small hashed swatch identifying a peer) are allowed, but render them flat and square as small indicators, not as decorative gradients.
- New decentralized/technical surfaces (P2P stats, addresses, tables) still follow the same language: compact, square, theme-aware, terse labels.

### Code Organization Rules

- Keep components focused; split large components.
- Follow DRY: shared UI in `src/components/`, shared logic in `src/hooks/`.
- Add comments for complex/non-obvious code; skip obvious comments.

### Git Workflow Rules

- Keep `master` releasable. Do not treat `master` as a scratch branch.
- If the user asks for a reviewable feature/fix and the current branch is `master`, create a short-lived task branch before making code changes unless the user explicitly asks to work directly on `master`.
- Name short-lived AI task branches by intent under the Codex prefix: `codex/feature/*`, `codex/fix/*`, `codex/docs/*`, `codex/chore/*`.
- Open PRs from task branches into `master` so review bots can run against the actual change.
- Open PRs as ready for review, not draft. Draft PRs prevent CodeRabbit, Cursor Bugbot, and similar review bots from running.
- Prefer short-lived task branches over a long-lived `develop` branch unless the user explicitly asks for a staging branch workflow.
- Use worktrees only when parallel tasks need isolated checkouts. One active task branch per worktree.
- If a new task is unrelated to the currently checked out branch, do not stack it on that branch. Create a new worktree from `master` and create a separate short-lived task branch there.
- Always give a new worktree a descriptive name that reflects the task (e.g. `fix-login-redirect`, not `wt1`, `tmp`, `feature`, or a numbered slug), so it can be identified at a glance in a long list of worktrees. When using `./scripts/create-task-worktree.sh`, the `<slug>` argument must be that descriptive name.
- Prefer `./scripts/create-task-worktree.sh <feature|fix|docs|chore> <slug>` when you need a new task worktree and do not have a stronger repo-specific reason to create it manually.
- Treat branch and worktree as different things: the branch is the change set; the worktree is the checkout where that branch is worked on.
- For parallel unrelated tasks, give each task its own branch from `master`, its own worktree, and its own PR into `master`.
- After a reviewed branch is merged, prefer deleting it to keep branch drift and merge conflicts low.

### Bug Investigation Rules

- For bug reports tied to a specific file/line, check relevant git history before any fix.
- Minimum sequence: `git log --oneline` or `git blame` first, then scoped `git show` for relevant commits.
- Full workflow: `docs/agent-playbooks/bug-investigation.md`.

### Verification Rules

- Never mark work complete without verification.
- After code changes, run: `yarn build`, `yarn lint`, `yarn type-check`.
- After adding or changing tests, run `yarn test`.
- Do not commit or force-add local rebuild output. `build/` is the main generated build output in this repo; remove or restore generated output directories after local verification before committing.
- After React UI logic changes, run: `yarn doctor`.
- Treat React Doctor output as guidance for *newly introduced* issues (the CI PR check in `.github/workflows/react-doctor.yml` runs `yarn doctor --scope changed --base <base branch>` to flag those), not as an aggregate score to grind up: many `error`-level diagnostics flag intentional patterns or current React-Compiler limitations, not bugs. See `docs/agent-playbooks/known-surprises.md`.
- For UI/visual changes, use Chrome/Blink for iterative checks, then perform final verification across Chrome/Blink, Firefox/Gecko, and WebKit/Safari.
- Cover desktop and a mobile viewport flow in each browser engine when the change affects layout, touch behavior, or responsiveness.
- Browser automation has a machine-wide resource budget of one active Playwright browser session, shared by every worktree. Use `./scripts/pw-session.sh open <session> ...` to acquire the slot, reuse that session for desktop and mobile, then run `./scripts/pw-session.sh close <session>` in a finally-style cleanup before opening another engine.
- Run browser engines and profiler batches sequentially. Do not spawn browser-driving agents in parallel. When `open` exits 75 the slot is busy: finish non-browser checks first, or block on `./scripts/pw-session.sh open --wait[=SECONDS] <session> ...`, rather than bypassing the lock.
- Use short, task-specific session names. Close the exact named session even when verification fails; `close` stops the browser even if the lock was already lost. Do not use `playwright-cli close-all` or `kill-all` while concurrent agents may own other sessions.
- A lock left behind by an interrupted workflow is reclaimed automatically by the next `open` once its browser is gone. Run `./scripts/pw-session.sh status` before assuming the slot is stuck; it reports whether the holder's browser is still alive.
- When loading, navigation, or interaction speed matters (or you cannot tell whether perf is real or just a fast dev machine), run a low-spec pass: `./scripts/pw-throttle.sh <session> mid` (or `low`) applies CPU + network throttling to a Chromium `playwright-cli` session before you measure. Throttling is Chromium-only; keep the Firefox/WebKit checks unthrottled. See `docs/agent-playbooks/low-spec-verification.md`.
- For browser automation and verification, default to a fresh isolated `playwright-cli` session for reproducibility.
- If the task depends on existing auth, cookies, extensions, open tabs, or another live browser state, explicitly confirm whether to use a fresh isolated session or the contributor's current browser session.
- Do not assume permission to drive the contributor's active personal browser session.
- The shared hook verification path is strict by default. Only set `AGENT_VERIFY_MODE=advisory` when you intentionally need signal from a broken tree without blocking the session.
- Use `yarn test:coverage` as an advisory check when expanding test coverage or auditing risky logic; do not invent a repo-wide coverage gate unless the user asks for one.
- If verification fails, fix and re-run until passing.

### Tooling Constraints

- Use `gh` CLI for GitHub work (issues, PRs, actions, dependabot, projects, search).
- Do not use GitHub MCP.
- Do not use browser MCP servers (cursor-ide-browser, playwright-mcp, chrome MCP, etc.).
- Use `playwright-cli` for browser automation.
- If many MCP tools are present in context, warn user and suggest disabling unused MCPs.

### AI Tooling Rules

- Treat `.codex/`, `.cursor/`, and `.claude/` as repo-managed contributor tooling, not private scratch space.
- Keep equivalent workflow files aligned across all toolchains when their directories contain the same skill, hook, or agent.
- Keep shared behavior equivalent while preserving harness-specific models, config formats, hook entry points, and tool invocation syntax.
- Do not configure `.claude` agents to use `composer-2`; that model is Cursor-only in this repo. Keep `.claude` agent models on Claude-supported options.
- Do not pin `model` or `model_reasoning_effort` in committed Codex custom-agent TOMLs under `.codex/**/agents/*.toml`; omit both so subagents inherit the current parent settings. Do not use undocumented aliases such as `latest`.
- When changing shared agent behavior, update the relevant files in `.codex/skills/`, `.cursor/skills/`, `.claude/skills/`, `.codex/agents/`, `.cursor/agents/`, `.claude/agents/`, `.codex/hooks/`, `.cursor/hooks/`, `.claude/hooks/`, and the hook entry points as needed. Hook entry points are harness-specific: the `hooks` key in `.claude/settings.json` (Claude Code does not read a standalone hooks.json), `.cursor/hooks.json` (Cursor schema), and `.codex/hooks.json` (Codex schema, intentionally Claude-compatible).
- If `AGENTS.md` references a skill, agent, or hook, prefer a tracked file under `.codex/`, `.cursor/`, or `.claude/` rather than an untracked local-only instruction.
- Review `.codex/config.toml`, `.codex/hooks.json`, `.cursor/hooks.json`, and `.claude/settings.json` before changing agent orchestration or hook behavior, because they are the entry points contributors will actually load.
- Before finishing any React UI logic change under `src/components`, `src/views`, `src/hooks`, or UI stores, review the changed diff with `vercel-react-best-practices` and, in Codex/Vercel-plugin sessions, `vercel:react-best-practices`. Fix valid findings before final verification; do not limit this review to diffs that add new hooks or memoization.
- When a diff adds new `useEffect`, `useLayoutEffect`, `useInsertionEffect`, `useMemo`, `useCallback`, or `memo(...)` usage under `src/`, treat the repo hook reminder as mandatory and also reconsider the change with `you-might-not-need-an-effect` before finishing.
- Directory-specific auto-loaded rules live under `src/AGENTS.md` and `scripts/AGENTS.md`; read them before editing files in those trees.
- For work expected to span multiple sessions, keep explicit task state in a `feature-list.json` plus `progress.md` pair using `docs/agent-playbooks/long-running-agent-workflow.md`.
- If more than one human or toolchain needs the same task state, keep it in a tracked location such as `docs/agent-runs/<slug>/` instead of burying it in a tool-specific hidden directory.

### Project Maintenance Rules

- If `CHANGELOG.md` or package version changes, run `yarn blotter:check`.
- If blotter check fails for missing release coverage, add a concise one-line release entry.
- Blotter entries are shown to 5chan end users, not developers. Every release message must be plain English a non-dev can understand: no internal library names (e.g. `Pretext`, `Zustand`), no dev shorthand (`perf`, `deps`, `refactor`, `a11y`, `CI`), no file paths, and no PR numbers. Mention only the most interesting user-visible changes in the release, if any; do not pad entries with routine maintenance, regression fixes, invisible security/stability work, or generic labels like `security fixes`, `bug fixes`, or `stability fixes`. Prefer dropping a weak highlight to making the entry longer. Full rules and examples live in the `release` skill's Step 3.
- Ignore manual entries for release coverage logic.
- Use `yarn blotter` / `yarn blotter:manual` for manual dev messages.

### Security and Boundaries

- Never commit secrets or API keys.
- Never push to a remote unless the user explicitly asks.
- Test responsive behavior on mobile viewport.

## Core SHOULD Rules

- Keep context lean: delegate heavy/verbose tasks to subprocesses when available.
- For complex work, parallelize independent checks, except browser-driving checks, which must respect the machine-wide single-session resource budget.
- Add or update tests for bug fixes and non-trivial logic changes when the code is reasonably testable.
- When touching already-covered code, prefer extending nearby tests so measured coverage does not regress without a clear reason.
- Use `yarn knip` when adding/removing dependencies or introducing new direct imports; treat findings as advisory, but resolve real issues before finishing.
- When proposing or implementing meaningful code changes, include both:
  - a Conventional Commit title suggestion
  - a short GitHub issue suggestion
  Use the format playbook: `docs/agent-playbooks/commit-issue-format.md`.
- When stuck on a bug, search the web for recent fixes/workarounds.
- After user corrections, identify root cause and apply the lesson in subsequent steps.

## Local Development URLs

This project uses [Portless](https://github.com/vercel-labs/portless) for local dev. The canonical dev URL is https://5chan.localhost, and non-`master` branches can automatically fall back to a branch-scoped `*.5chan.localhost` route when needed so parallel worktrees do not collide. Other Bitsocial projects use the same proxy (seedit, mintpass, bitsocial at `.localhost`), so they can all run simultaneously without port conflicts. The launcher intentionally starts the Portless HTTPS proxy on port 443 before registering app routes; keep that step so legacy `~/.portless` state on port 1355 is not reused.

To bypass Portless: `PORTLESS=0 yarn start`

Android phone over USB (default browser opens via `adb`; `ANDROID_USB_OPEN_BROWSER=0` to skip): `yarn start:android-usb`

## Common Commands

```bash
corepack yarn install
yarn start                # https://5chan.localhost
yarn start:android-usb    # Vite + adb reverse for USB Android (http://localhost:3000 on device)
yarn build
yarn test
yarn test:coverage
yarn knip
yarn knip:full
yarn prettier
yarn electron
yarn doctor
yarn doctor:score
yarn doctor:verbose
yarn ai-workflow:check
./scripts/pw-session.sh status
./scripts/create-task-worktree.sh chore ai-workflow-improvement
./scripts/agent-init.sh --smoke
```

## Playbooks (Load On Demand)

Use these only when relevant to the active task:

- Hooks setup and scripts: `docs/agent-playbooks/hooks-setup.md`
- Long-running agent workflow: `docs/agent-playbooks/long-running-agent-workflow.md`
- Translations workflow: `docs/agent-playbooks/translations.md`
- Commit/issue output format: `docs/agent-playbooks/commit-issue-format.md`
- Skills/tools setup, MCP rationale, and the index of all committed skills/subagents: `docs/agent-playbooks/skills-and-tools.md`
- Bug investigation workflow: `docs/agent-playbooks/bug-investigation.md`
- Known surprises log: `docs/agent-playbooks/known-surprises.md`
- Low-spec device verification (CPU/network throttling): `docs/agent-playbooks/low-spec-verification.md`
```

---

## PRODUCT.md

Source: https://github.com/bitsocialnet/5chan/blob/master/PRODUCT.md

```markdown
# Product

## Register

product

## Users

5chan is for people who already understand classic imageboards, especially users whose habits depend on dense boards, terse navigation, reply flows, catalog scanning, familiar colors, and old-school post mechanics. The primary user should be able to land on 5chan and feel that the interface behaves like an imageboard they already know.

Secondary users include board owners, board moderators, and contributors building decentralized features around Bitsocial. Their tools should still feel native to the same imageboard environment instead of becoming a separate admin dashboard aesthetic.

## Product Purpose

5chan exists to preserve the classic imageboard habit while removing the dependency on global admins. It keeps the familiar imageboard directory structure and browsing experience, but runs on the Bitsocial protocol so anyone can create, own, and moderate boards independently.

Success means experienced imageboard users do not need to relearn how to browse, post, reply, search, use catalogs, read threads, or understand board identity. The decentralization should matter structurally, but it should not make the core user experience feel unfamiliar.

## Brand Personality

5chan should feel familiar, blunt, resilient, and low-friction. It is not polished in the startup sense. It should feel like a functional old internet place that kept its original interface discipline while replacing the governance layer underneath.

The voice is plain and direct. Prefer short labels, conventional imageboard wording, and visible system behavior over explanatory product copy.

## Anti-references

Do not make 5chan look like a modern social network, crypto app, SaaS dashboard, mobile-first content platform, or polished community product. Avoid feed algorithms, engagement framing, large hero layouts, decorative cards, rounded modern controls, soft gradients, animated brand flourishes, and "Web3" visual language.

Do not modernize classic imageboard affordances unless there is a concrete usability, accessibility, or protocol-driven reason. When 5chan needs custom decentralized features, they should look like they belong inside the existing classic imageboard UI.

Do not imply official affiliation with any existing imageboard. The design goal is alignment with long-standing imageboard user expectations, not brand ownership or endorsement.

## Text and Expression

5chan adds no emoji affordances: no emoji picker, no shortcode or custom-emote system, and no Twemoji-style emoji styling. Emoji a user types or pastes pass through as raw, unstyled Unicode, neither encouraged nor blocked — the same posture 4chan itself takes, which renders Unicode but ships no emoji tooling.

This is deliberate. On imageboards the expressive vocabulary is greentext, reaction images, and text faces (kaomoji and ASCII / Shift-JIS art), not graphical emoji. Heavy emoji use reads as an outsider, other-platform, or phone-poster marker, and persistent personal-expression tokens cut against the anonymous, no-personal-branding norm the format depends on. The native surfaces — greentext, image replies, and plain-Unicode text faces — already do what emoji do elsewhere.

It is also strategic. 5chan improves on classic imageboards structurally — independent board ownership, no global admins, the Bitsocial protocol underneath — not by modernizing the posting experience. Imageboard history is consistent: "more modern UX" does not win users and erodes the authenticity that does, and an emoji picker is exactly that kind of modernization. With no global admins to run wordfilters or per-board character rules, the norm holds simply by not building the affordances and by leaving emoji as plain Unicode; board-level moderation can address the rest.

## Design Principles

1. Classic parity first. For boards, threads, posts, replies, catalogs, post forms, navigation, and theme behavior, familiar imageboard behavior is the baseline.
2. Preserve muscle memory. Existing imageboard users should not have to learn new interaction patterns for familiar tasks.
3. Make decentralization invisible until it matters. Board ownership, competing directories, Bitsocial addresses, and moderation differences should be clear when relevant, but should not dominate routine browsing.
4. Custom features inherit the old UI language. Passes, board creation, mod queues, challenges, subscriptions, and directory competition should use compact, flat, text-first imageboard patterns.
5. Favor density over polish. The interface should optimize for scanning, comparison, and repeated use, not marketing impact.

## Accessibility & Inclusion

Keep the nostalgic interface, but do not use nostalgia as an excuse for broken accessibility. Preserve keyboard access, readable focus states, sufficient contrast within each theme, reduced-motion safety, predictable tab order, and responsive behavior on mobile.

When accessibility improvements conflict with exact visual parity, choose the smallest adjustment that fixes the usability issue while preserving the classic imageboard feel.
```

---

## DESIGN.md

Source: https://github.com/bitsocialnet/5chan/blob/master/DESIGN.md

```markdown
---
version: alpha
name: 5chan
description: A decentralized imageboard with a classic imageboard user experience.
colors:
  yotsuba-body-bg: "#ffffee"
  yotsuba-reply-bg: "#f0e0d6"
  yotsuba-mobile-reply-bg: "#f5e9e1"
  yotsuba-border: "#d9bfb7"
  yotsuba-title: "#880000"
  yotsuba-link: "#0000ee"
  yotsuba-hover: "#ff0000"
  yotsuba-name: "#117743"
  yotsuba-subject: "#cc1105"
  yotsuba-greentext: "#789922"
  yotsuba-b-body-bg: "#eef2ff"
  yotsuba-b-reply-bg: "#d6daf0"
  yotsuba-b-border: "#b7c5d9"
  yotsuba-b-title: "#af0a0f"
  yotsuba-b-link: "#34345c"
  futaba-body-bg: "#ffffee"
  modal-preview-bg: "#181f24"
  neutral-white: "#ffffff"
  neutral-black: "#000000"
typography:
  board-title:
    fontFamily: "Tahoma, sans-serif"
    fontSize: "28px"
    fontWeight: 700
    lineHeight: 1.2
    letterSpacing: "normal"
  body:
    fontFamily: "Arial, Helvetica, sans-serif"
    fontSize: "13px"
    fontWeight: 400
    lineHeight: 1.3
    letterSpacing: "normal"
  form-label:
    fontFamily: "Arial, Helvetica, sans-serif"
    fontSize: "10pt"
    fontWeight: 700
    lineHeight: 1.2
    letterSpacing: "normal"
  mobile-post:
    fontFamily: "Arial, Helvetica, sans-serif"
    fontSize: "11pt"
    fontWeight: 400
    lineHeight: 1.3
    letterSpacing: "normal"
rounded:
  square: "0"
spacing:
  page-edge: "5px"
  field-padding: "2px"
  compact-padding: "0.5em"
  hairline: "1px"
components:
  desktop-text-button:
    textColor: "{colors.yotsuba-link}"
    typography: "{typography.body}"
    rounded: "{rounded.square}"
    padding: "0"
  mobile-button:
    backgroundColor: "{colors.yotsuba-reply-bg}"
    textColor: "{colors.yotsuba-title}"
    typography: "{typography.form-label}"
    rounded: "{rounded.square}"
    padding: "3px 5px"
  input:
    backgroundColor: "{colors.neutral-white}"
    textColor: "{colors.neutral-black}"
    typography: "{typography.body}"
    rounded: "{rounded.square}"
    padding: "2px"
  reply-surface:
    backgroundColor: "{colors.yotsuba-reply-bg}"
    textColor: "{colors.yotsuba-title}"
    rounded: "{rounded.square}"
---

## Overview

**Creative North Star: "The Preserved Imageboard"**

5chan's visual system is intentionally conservative. The product should feel like a classic imageboard with a decentralized substrate, not like a redesigned forum or a modern community platform. The default answer for any board, thread, catalog, post, reply, or post-form UI is to preserve familiar imageboard density, typography, color, and interaction shape.

Most surfaces are flat, compact, text-first, and visibly old web. Controls may look plain by modern standards because that plainness is part of the product promise. New decentralized features should enter through the same visual language: small links, square fields, compact tables, simple modal bars, terse labels, and theme-aware colors.

**Key Characteristics:**

- Dense layouts with minimal padding.
- Square edges and 1px borders.
- Arial/Helvetica body text with Tahoma board titles.
- Yotsuba, Yotsuba B, and Futaba-style palettes as first-class themes.
- Text links and bracketed actions over large button components.
- Visual compatibility with classic imageboard user expectations.

## Colors

The palette is inherited from classic imageboard themes and should remain recognizable. Use the existing CSS variables in `src/themes.css` as the source of truth for implementation.

### Primary

- **Yotsuba Body** (`#ffffee`): default warm page background for NSFW-style boards.
- **Yotsuba Reply** (`#f0e0d6`): reply containers, modal surfaces, pagination, menu backgrounds, and compact UI panels.
- **Yotsuba Title Red** (`#880000`): board headers, bars, button text, and theme-defining chrome.
- **Yotsuba B Body** (`#eef2ff`): default cool page background for SFW-style boards.
- **Yotsuba B Reply** (`#d6daf0`): reply containers and panel surfaces in the blue theme.

### Secondary

- **Classic Link Blue** (`#0000ee` / `#34345c`): links, post actions, desktop text buttons, and navigational affordances.
- **Hover Red** (`#ff0000` / `#dd0000`): hover states for links and compact actions.
- **Name Green** (`#117743`): poster names and identity markers.
- **Subject Red** (`#cc1105`): post subjects and title emphasis.
- **Greentext** (`#789922`): quote text and imageboard-specific content convention.

### Neutral

- **Black** (`#000000`): body text in light themes and table borders where the original style calls for it.
- **White** (`#ffffff`): homepage boxes, input fields, and legacy modal surfaces where defined by the theme.
- **Hairline Borders** (`#d9bfb7` / `#b7c5d9`): dividers, reply borders, modal edges, pagination, and mobile post separators.
- **Preview Dark** (`#181f24`): catalog and quote preview overlays only.

### Named Rules

**The Theme Fidelity Rule.** Use existing theme variables before adding new colors. If a color is needed for a new feature, derive its role from the closest established imageboard component in the active theme.

**The No Modern Accent Rule.** Do not introduce a new brand accent, gradient palette, neon crypto palette, or marketing color system for core product UI.

**The Functional Color Exception.** Small, deterministic per-entity colors used as data — for example a hashed swatch that gives each connected peer a stable identity — are allowed. Render them as flat, square, small indicators (not gradients, glows, or large fills). This exception is for conveying data, not for decoration or branding.

## Typography

**Display Font:** Tahoma, sans-serif.
**Body Font:** Arial, Helvetica, sans-serif.
**Label/Mono Font:** Use inherited body fonts unless a compact error or technical address requires monospace.

**Character:** Typography should feel like a browser-native imageboard, not a designed publication. Small sizes, simple weights, default line wrapping, and dense text are expected.

### Hierarchy

- **Board Title** (bold, `28px`, Tahoma): board names and top-level board identity.
- **Box Heading** (bold, `131%`, Arial/Helvetica): homepage bars and compact panel headings.
- **Body** (regular, `13px`, Arial/Helvetica): global app text, board chrome, metadata, and link rows.
- **Post Content** (regular, `11pt` on mobile): comment bodies and mobile post content.
- **Form Label** (bold, `10pt`): post form field headers, modal bars, and compact control labels.
- **Small Metadata** (`9pt` to `10pt`): board bars, file info, timestamps, addresses, and post counts.

### Named Rules

**The Browser-Native Rule.** Do not add custom web fonts, variable-font display systems, negative letter spacing, oversized headings, or marketing typography to product surfaces.

## Layout

Layouts are dense, compact, and text-first, mirroring classic imageboard information density. Spacing is small and deliberate rather than generous, and structure comes from tables, inline rows, and slash-separated links instead of large spaced-out cards.

- **Page edge** (`5px`): outer gutters around boards, catalogs, and threads.
- **Field padding** (`2px`): inputs, table cells, and compact controls.
- **Compact padding** (`0.5em`): reply blocks, menus, and small panels.
- **Hairline** (`1px`): borders and separators between rows, posts, and panels.

Desktop and mobile intentionally differ: desktop stays maximally compact, while mobile raises tap-target and text sizes only as much as needed to stay usable and avoid browser zoom.

### Named Rules

**The Density Rule.** When in doubt, choose the more compact layout. Whitespace is not a feature on core imageboard surfaces.

## Elevation & Depth

5chan is flat by default. Depth is conveyed through background color, 1px borders, hard separators, and occasional legacy-style hard shadows on small menus. Avoid soft elevation, glass, blur, ambient shadows, floating cards, and layered dashboard surfaces.

### Shadow Vocabulary

- **Small Legacy Menu Shadow** (`box-shadow: 2px 2px 0 1px rgba(0, 0, 0, .1)`): small popover menus such as compact filters, when a flat border alone is not enough.

### Named Rules

**The Flat Surface Rule.** If a surface can be separated with a border or theme background, do that instead of adding shadow.

## Shapes

5chan is uniformly square. Corner radius is `0` everywhere on product surfaces, and structure comes from 1px theme borders rather than rounding or elevation.

- **Corners:** square (`0` radius) on buttons, inputs, cards, replies, modals, and menus.
- **Borders:** 1px theme border colors (for example Yotsuba `#d9bfb7`, Yotsuba B `#b7c5d9`).
- **Indicators:** functional per-entity swatches render as small flat squares, never rounded chips.

### Named Rules

**The No Rounding Rule.** Do not introduce `border-radius`, pill, capsule, chip, or rounded badge shapes on product UI. A label is square text, not a rounded token.

## Components

### Buttons

- **Shape:** square corners (`0` radius).
- **Desktop:** prefer text links, bracketed actions, or image-backed icon buttons over filled button components.
- **Mobile:** use theme-colored rectangular buttons with compact padding, bold `10pt` text, and existing button fade assets.
- **Hover / Focus:** hover changes color to the theme hover red; focus must stay visible and keyboard accessible.

### Cards / Containers

- **Corner Style:** square.
- **Background:** theme surfaces such as Yotsuba reply, Yotsuba B reply, homepage white, or the active post/mobile background token.
- **Shadow Strategy:** none except the small legacy menu shadow.
- **Border:** 1px theme borders.
- **Internal Padding:** compact, commonly `2px`, `5px`, or `0.5em`.
- **Hover:** do not change a row's or card's background on hover, and do not add CSS transitions or animations to them. Reserve hover feedback for text-link color changes.
- **Inline labels:** plain text, bold for emphasis. Do not wrap labels (tags, statuses, transports, counts) in pill, capsule, chip, or rounded badge shapes; a label is text, not a button.

### Inputs / Fields

- **Style:** square native fields, white or theme-defined background, `1px solid #aaa` by default.
- **Focus:** border shifts to the theme focus color, such as Yotsuba `#ea8`.
- **Sizing:** preserve compact desktop sizes; on mobile, raise text size where needed to prevent browser zoom.

### Navigation

- **Boards bar:** compact slash-separated board links, small text, theme separators, no pill navigation.
- **Pagination:** small flat cells using theme background and border colors.
- **Directory navigation:** preserve classic board code patterns such as `/a/`, `/b/`, and category groupings.

### Posts And Replies

- **Post metadata:** compact inline text, subject red, name green, timestamps, IDs, roles, and action links in the expected order.
- **Replies:** theme-colored blocks with square borders and minimal padding.
- **Greentext and quote links:** preserve classic color behavior and hover states.
- **Media:** thumbnails should fit the existing imageboard layout and should not create modern card previews unless the current surface already uses that pattern.
- **Emoji and text faces:** pass post text through as raw Unicode. Do not add an emoji picker, shortcode/emote system, or Twemoji-style emoji rendering. Kaomoji and ASCII / Shift-JIS art are the native text-face vocabulary; preserve them and their alignment where used. See `PRODUCT.md` → Text and Expression for the rationale.

### Modals And Popovers

- **Style:** compact movable bars, square borders, theme backgrounds, and legacy close icons where available.
- **Copy:** short labels and direct status messages.
- **Behavior:** custom features such as challenges, settings, and posting flows should feel like imageboard utilities, not app dialogs.

## Do's and Don'ts

### Do

- Start UI changes by checking the closest established imageboard behavior and the existing 5chan implementation.
- Preserve theme variables and add new variables only when a new role is genuinely needed.
- Keep layouts dense, square, and text-first.
- Make decentralized concepts understandable without redesigning the familiar browsing flow.
- Verify desktop and mobile because 5chan intentionally has different post and control treatments across viewports.

### Don't

- Do not modernize core imageboard UI for taste.
- Do not add rounded cards, gradient hero areas, glass panels, soft shadows, dark-mode defaults, or large marketing sections to product surfaces.
- Do not use pill, capsule, chip, or rounded badge shapes for labels, tags, statuses, transports, or counts.
- Do not add hover background fills, color fades, or CSS transitions/animations to rows, cards, or list items.
- Do not replace compact text links with large icon-button toolbars unless the existing surface already uses that pattern.
- Do not introduce a new design system that competes with Yotsuba, Yotsuba B, Futaba, or the existing theme variable model.
- Do not make Bitsocial, crypto, or decentralization visuals dominate routine browsing.
- Do not add an emoji picker, emoji shortcode/emote system, or Twemoji-style emoji rendering; emoji pass through as raw Unicode only.
```

---

## src/AGENTS.md

Source: https://github.com/bitsocialnet/5chan/blob/master/src/AGENTS.md

```markdown
# src/AGENTS.md

These rules apply to `src/**`. Follow the repo-root `AGENTS.md` first, then use this file for code inside the application source tree.

- Keep route composition in `src/views/`, reusable UI in `src/components/`, shared logic in `src/hooks/`, and shared app state in `src/stores/`.
- Before adding new state, decide whether it belongs in render, a reusable hook, or a Zustand store. Do not duplicate the same state logic across views.
- Use `@bitsocial/bitsocial-react-hooks` for data access. Do not add data-fetching `useEffect` calls or effects that only synchronize derived state.
- When changing React UI logic, review the changed diff with `vercel-react-best-practices` and `vercel:react-best-practices` when available before final verification. Run `yarn doctor` in addition to build, lint, and type-check. When changing layout or interaction, verify desktop and mobile behavior with `playwright-cli`.
- Prefer extending nearby tests under `src/**/__tests__/` when touching already-covered behavior.
```

---

## scripts/AGENTS.md

Source: https://github.com/bitsocialnet/5chan/blob/master/scripts/AGENTS.md

```markdown
# scripts/AGENTS.md

These rules apply to `scripts/**`. Follow the repo-root `AGENTS.md` first, then use this file for automation and workflow helpers.

- Keep scripts non-interactive and idempotent. Print the command, URL, branch, or path being acted on so failures are diagnosable.
- Use repo-relative paths and environment variables instead of user-specific absolute paths.
- For dev-server helpers, default to `https://5chan.localhost`, but allow a branch-scoped `*.5chan.localhost` route when the launcher is avoiding a Portless name collision. Start the Portless HTTPS proxy on port 443 before registering routes so legacy `~/.portless` state on port 1355 is not reused. Respect the existing `PORTLESS=0` fallback instead of hard-coding alternate ports. For USB Android preview, `scripts/start-android-usb.mjs` mirrors bitsocial-web: `adb reverse` plus Vite on `127.0.0.1`, then `am start` VIEW to open the default browser when the port is listening (disable with `ANDROID_USB_OPEN_BROWSER=0`).
- Keep shell helpers thin. When logic becomes stateful or cross-platform, prefer a Node script.
- `scripts/pw-session.sh` owns the machine-wide Playwright resource lock shared by every worktree and checkout, so its default lock path must stay repository-independent. Keep acquisition atomic, treat `playwright-cli list --all` as the only liveness oracle and leave the lock alone when it cannot be read, require exact-owner release, and close the named browser before normal release; never broaden cleanup to unrelated sessions.
- Git and worktree helpers must validate input and default to safe operations.
- If a helper deletes local branches automatically, document the exact eligibility checks and keep the behavior conservative.
```

---

## docs/agent-playbooks/known-surprises.md

Source: https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/known-surprises.md

```markdown
# Known Surprises

This file tracks repository-specific confusion points that caused agent mistakes.

## Entry Criteria

Add an entry only if all are true:

- It is specific to this repository (not generic advice).
- It is likely to recur for future agents.
- It has a concrete mitigation that can be followed.

If uncertain, ask the developer before adding an entry.

## Entry Template

```md
### [Short title]

- **Date:** YYYY-MM-DD
- **Observed by:** agent name or contributor
- **Context:** where/when it happened
- **What was surprising:** concrete unexpected behavior
- **Impact:** what went wrong or could go wrong
- **Mitigation:** exact step future agents should take
- **Status:** confirmed | superseded
```

## Entries

### GitHub Projects are not used for repository workflow

- **Date:** 2026-07-23
- **Observed by:** Tommaso + Claude
- **Context:** porting the `review-and-merge-pr` skill fix from `bitsocial-react-hooks` after a merged PR was finalized against a project board
- **What was surprising:** the `review-and-merge-pr` and `make-closed-issue` skills still referenced an organization project and project item even though this repository no longer uses GitHub Projects.
- **Impact:** agents can waste time querying a nonexistent project or report a successful merge as incomplete.
- **Mitigation:** keep pull-request review and merge workflows independent of GitHub issues and Projects; only create or manage an issue when the user explicitly requests one.
- **Status:** confirmed

### react-doctor score reflects React-Compiler coverage, not code health — do not chase it

- **Date:** 2026-06-05
- **Observed by:** Tommaso + Claude
- **Context:** Trying to raise the `yarn doctor` (react-doctor) score to 90 (PR #1155).
- **What was surprising:** The score is overwhelmingly driven by React-Compiler *optimizability* diagnostics, not code quality. Most of the ~92 "errors" are the `react-hooks-js` plugin flagging valid, idiomatic code the React Compiler (v1.0) cannot optimize *yet* — `refs` (the deliberate latest-ref idiom for a stable callback) and `todo` (`try/finally` and throw-in-`try/catch` the compiler can't lower). The score also saturates on the *fraction of files with zero diagnostics*: removing 150 warnings moved it +1; suppressing all 76 compiler-bailout errors reached only 63; only suppressing essentially every rule reaches 90.
- **Impact:** Agents/contributors can burn large effort (and risk real regressions) "fixing" the score by rewriting correct code into compiler-friendly-but-worse shapes, or by suppressing rules until the badge is meaningless. ~63 is the honest, no-regression ceiling.
- **Mitigation:** Do NOT treat the aggregate react-doctor score as a target to grind up (the README badge was removed for this reason). Use react-doctor as a PR-diff reviewer — `yarn doctor --scope changed --base <base> --annotations`, already wired in `.github/workflows/react-doctor.yml` (releases use `yarn doctor --diff <previous tag>` in `release.yml`) — to catch *newly introduced* issues. `doctor.config.jsonc` deliberately does not enforce the `react-hooks-js` rules or `react-compiler-no-manual-memoization` (intentional patterns / current compiler limits). Only fix genuine bugs (e.g. clean `no-adjust-state-on-prop-change` cases). Full reasoning: `docs/agent-runs/react-doctor-score/`.
- **Status:** confirmed

### Portless 0.11 reuses legacy proxy state unless the launcher forces HTTPS

- **Date:** 2026-04-28
- **Observed by:** Tommaso + Codex
- **Context:** Upgrading the normal `yarn start` flow from the old `http://5chan.localhost:1355` proxy URL to `https://5chan.localhost`.
- **What was surprising:** Even with `portless@0.11.1` installed, Portless reused the existing `~/.portless/proxy.port = 1355` HTTP proxy and printed the legacy `:1355` URL.
- **Impact:** Updating package versions and docs is not enough; `yarn start` can still advertise and use the old URL when a contributor has legacy Portless state running.
- **Mitigation:** Keep `scripts/start-dev.js` explicitly starting the Portless HTTPS proxy on port `443` before registering the app route, so the runtime flow migrates away from persisted `1355` state instead of inheriting it.
- **Status:** confirmed

### Android release signing still uses legacy keystore names

- **Date:** 2026-04-23
- **Observed by:** Codex
- **Context:** Cutting the `v0.8.0` release after the core terminology rename changed release workflow signing references.
- **What was surprising:** The tracked Android release keystore is still `android/plebbit.keystore`, and the available GitHub secret is still `PLEBBIT_REACT_KEYSTORE_PASSWORD`; changing only the workflow references to `bitsocial.keystore` / `BITSOCIAL_KEYSTORE_PASSWORD` made the Android release artifact fail at signing.
- **Impact:** Tag releases can pass the Android build and then fail before publishing because `apksigner` cannot find the keystore or password secret.
- **Mitigation:** Until the keystore migration is done, keep release APK signing pointed at `android/plebbit.keystore` and `PLEBBIT_REACT_KEYSTORE_PASSWORD`. If renaming, migrate the tracked file, workflow path, and GitHub secret in one change and verify with a tag release dry run or full release.
- **Status:** confirmed

### 5chan consumes a pinned hooks tarball instead of using the local hooks repo

- **Date:** 2026-04-15
- **Observed by:** Codex
- **Context:** Debugging strict `{name, publicKey}` community refs after upstream fixes landed in `bitsocial-react-hooks`
- **What was surprising:** 5chan does not consume the nearby `/Users/Tommaso/Desktop/bitsocial/bitsocial-react-hooks` checkout by default; `package.json` installs a pinned GitHub tarball of `@bitsocialnet/bitsocial-react-hooks`.
- **Impact:** Agents can wrongly assume local hooks source changes are already active in 5chan, or debug the wrong package build when the app is really running a tarball revision from GitHub.
- **Mitigation:** Before debugging hooks behavior from 5chan, check `package.json` to see whether the app points at a tarball commit or a local path. If you need fresh hooks behavior, update the tarball commit or temporarily switch 5chan to a local path intentionally.
- **Status:** superseded — `package.json` now installs `@bitsocial/bitsocial-react-hooks` from npm (e.g. `0.1.26`), not a GitHub tarball. The general advice (check `package.json` before assuming local hooks changes are active) still applies.

### Hooks source commits can land before the generated tarball payload

- **Date:** 2026-04-18
- **Observed by:** Codex
- **Context:** 5chan CI failed after `expandTimeWindow` landed in `bitsocial-react-hooks` because the app was pinned to the feature source commit.
- **What was surprising:** `bitsocial-react-hooks` uses `dist/` as its published entrypoint, and the repo's CI writes that generated payload in a follow-up `chore(ci): update dist and coverage badge` commit after the source commit lands on `master`.
- **Impact:** Pinning 5chan to the feature source SHA can install a tarball whose runtime and typings still omit the new API, causing downstream type errors even though the hooks repo's source and CI look green.
- **Mitigation:** When updating 5chan to a new hooks change, verify whether hooks `master` has a newer follow-up `chore(ci): update dist and coverage badge` commit and pin 5chan to that dist-synced SHA rather than the source-only SHA.
- **Status:** superseded — 5chan now consumes `@bitsocial/bitsocial-react-hooks` as a published npm version, so tarball-SHA pinning mechanics no longer apply.

### Portless breaks Windows installs

- **Date:** 2026-03-04
- **Observed by:** Codex
- **Context:** GitHub Actions `Test Windows` dependency install on `windows-2022`
- **What was surprising:** `portless@0.5.2` is a local dev-only tool, but keeping it in `devDependencies` makes `yarn install` fail on Windows because the package declares `win32` unsupported.
- **Impact:** Windows CI fails before build steps run, even though the app does not need `portless` there.
- **Mitigation:** Keep `portless` in `optionalDependencies` and make `yarn start` fall back to direct `vite` startup when `portless` is unavailable.
- **Status:** confirmed

### Electron RPC uses direct pkc-js imports

- **Date:** 2026-03-07
- **Observed by:** Codex
- **Context:** The desktop bootstrap now imports `@pkcprotocol/pkc-js/rpc` directly from `electron/start-pkc-rpc.js`.
- **What was surprising:** Most app data access still goes through `@bitsocialnet/bitsocial-react-hooks`, but the Electron-local RPC bootstrap is intentionally a direct `pkc-js` integration.
- **Impact:** Agents may try to route Electron RPC back through hooks, or reintroduce the legacy protocol package name while fixing dependency/tooling warnings.
- **Mitigation:** Keep Electron RPC on direct `@pkcprotocol/pkc-js` imports. If `knip` flags `electron/start-pkc-rpc.js`, audit the actual dependency graph before adding ignores or legacy packages.
- **Status:** confirmed

### Electron packaging can ship a broken `better-sqlite3` binary

- **Date:** 2026-03-17
- **Observed by:** Codex
- **Context:** Investigating the `v0.7.1` macOS arm64 DMG after the app showed a live IPFS node but never loaded boards or comments.
- **What was surprising:** The packaged app can start IPFS successfully while `electron/start-pkc-rpc.js` loops forever because `/Applications/5chan.app/.../better_sqlite3.node` was built for plain Node 22 (`NODE_MODULE_VERSION 127`) instead of Electron 36 (`NODE_MODULE_VERSION 135`).
- **Impact:** The local RPC server on `ws://localhost:9138` never starts, so the desktop app cannot load boards, posts, or comments even though node stats look healthy.
- **Mitigation:** Before any Electron package/build job, run `yarn electron:prepare-package` so `better-sqlite3` is rebuilt for Electron and immediately verified via `ELECTRON_RUN_AS_NODE=1 electron`.
- **Status:** confirmed

### Plain Vite fallback used to hard-fail on port 1355

- **Date:** 2026-03-30
- **Observed by:** Codex
- **Context:** Running `PORTLESS=0 yarn start` while another local service already owned port `3000`
- **What was surprising:** The non-Portless dev fallback forced Vite onto `5chan.localhost` with `--strictPort`, so the fallback path could fail immediately even though the main Portless flow is collision-safe.
- **Impact:** Contributors could lose the fallback dev path or interrupt their startup flow when `3000` was already busy.
- **Mitigation:** Keep the fallback behind `scripts/start-dev.js`, which now probes from `3000` upward and starts Vite on the next free port instead of exiting.
- **Status:** confirmed

### Fixed Portless app names collide across 5chan worktrees

- **Date:** 2026-03-30
- **Observed by:** Codex
- **Context:** Starting `yarn start` in one 5chan worktree while another 5chan worktree was already serving through Portless
- **What was surprising:** Using the literal Portless app name `5chan` in every worktree makes the route itself collide, even when the backing ports are different, so the second process fails with `"5chan.localhost" is already registered`.
- **Impact:** Parallel 5chan branches can block each other even though Portless is meant to let them coexist safely.
- **Mitigation:** Keep Portless startup behind `scripts/start-dev.js`, which now uses a branch-scoped `*.5chan.localhost` route outside the canonical case and automatically increments a `-2`, `-3`, ... suffix when that branch-scoped route is already occupied.
- **Status:** confirmed

### Toolchain model names and inheritance are not interchangeable

- **Date:** 2026-04-08
- **Updated:** 2026-07-10
- **Observed by:** contributor + Codex
- **Context:** Reviewing repo-managed agent configs under `.codex/agents`, `.cursor/agents`, and `.claude/agents`
- **What was surprising:** Model names remain harness-specific, while Codex custom-agent `model` and `model_reasoning_effort` settings are optional and inherit from the parent when omitted; Codex does not document a `latest` alias for these files.
- **Impact:** Hard-coded Codex model or reasoning-effort settings can become stale or unsupported and prevent subagents from following the contributor's current parent configuration.
- **Mitigation:** Keep `.cursor` agents on Cursor-supported models, never use `composer-2` in `.claude`, and omit `model` and `model_reasoning_effort` from committed custom-agent TOMLs under `.codex/**/agents/*.toml`; `yarn ai-workflow:check` rejects pins so Codex agents keep inheriting parent settings.
- **Status:** confirmed

### codesign parses "5chan.app" as process ID 5

- **Date:** 2026-06-12
- **Observed by:** contributor + Claude
- **Context:** Running the first signed + notarized mac Electron build (`yarn electron:build:mac:arm64` with Apple credentials set)
- **What was surprising:** `@electron/notarize` 2.x runs its pre-upload signature check as `codesign -dv 5chan.app` from the bundle's parent directory, and `codesign` accepts a process ID in place of a path — so it parses the digit-leading basename as PID 5 and fails with `5chan.app: No such process` even though the app is signed correctly.
- **Impact:** Notarization aborts after a successful signing pass; the error message looks like a signing failure and invites debugging the certificate/keychain instead of the real cause. Any tool that shells out to `codesign` with a bare relative path can hit this because the app is literally named `5chan`.
- **Mitigation:** Keep the yarn patch `.yarn/patches/@electron-notarize-npm-2.5.0-*.patch` (backport of electron/notarize#245, prefixes the basename with `./`) until electron-forge depends on `@electron/notarize` >= 3.x. When invoking `codesign` manually on the app bundle, always use an absolute or `./`-prefixed path.
- **Status:** confirmed

### react-scan's `getReport()` is dead API and can never return data

- **Date:** 2026-07-27
- **Observed by:** contributor + Claude
- **Context:** Running the `profile-browsing` skill against a branch to measure excessive rerenders, and getting no component data back
- **What was surprising:** Three independent failures stacked up silently. (1) `getReport()` returns `Store.legacyReportData`, which react-scan 0.5.3 initializes as an empty `Map` and never writes to anywhere in the bundle. (2) The live `Store.reportData` is only populated inside `if (options.showToolbar !== false && Store.inspectState.value.kind === 'focused')` — but the profiler sets `__PROFILING__=true`, which sets `showToolbar: false`, and `'focused'` requires a human clicking the inspector onto one component, so it is unreachable under automation. (3) `getReport()` returns a `Map`, and `JSON.stringify(new Map())` is `"{}"` regardless of contents, so the skill's collection line would have printed `{}` even if data existed. The skill and profiler agent additionally claimed the app was configured with `report: true`; react-scan 0.5.3 has no `report` option at all, and passing one logs `[React Scan] Invalid options: - Unknown option "report"`.
- **Impact:** Every profiling run reported zero react-scan component data without erroring, so rerender hotspots looked invisible and profiling silently degraded to raw commit counts.
- **Mitigation:** `src/lib/react-scan.ts` now accumulates render data through react-scan's `onRender` option, which is only skipped when `isPaused && inspectorInactive` (verified `isPaused: false` with the toolbar off). It exposes `window.__getReactScanReport()` returning a plain, JSON-serializable object and `window.__resetReactScanReport()`. Never reintroduce `getReport()`, and never `JSON.stringify` a `Map`. Set `window.__PROFILING_UNNECESSARY__ = true` to opt into `trackUnnecessaryRenders`; it is off by default because it adds overhead that skews the `time` field.
- **Status:** confirmed
```

---

## docs/agent-playbooks/long-running-agent-workflow.md

Source: https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/long-running-agent-workflow.md

```markdown
# Long-Running Agent Workflow

Use this playbook when a task is likely to span multiple sessions, handoffs, or spawned agents.

## Goals

- Give each fresh session a fast way to regain context
- Keep work incremental instead of one-shotting a large change
- Catch a broken local baseline before adding more code
- Leave durable artifacts that the next session can trust

## Where to Keep State

- Use `docs/agent-runs/<slug>/` when humans, review bots, or multiple toolchains need the same task state.
- Use a tool-local directory such as `.codex/runs/<slug>/` only when the task state is intentionally local to one workstation or one toolchain.
- Do not hide multi-session shared state in a private scratch file if another contributor or agent will need it later.

## Required Files

Create these files at the start of the long-running task:

- `feature-list.json`
- `progress.md`

Use the templates in `docs/agent-playbooks/templates/feature-list.template.json` and `docs/agent-playbooks/templates/progress.template.md`.

Prefer JSON for the feature list so agents can update a small number of fields without rewriting the whole document.

## Session Start Checklist

1. Run `pwd`.
2. Read `progress.md`.
3. Read `feature-list.json`.
4. Run `git log --oneline -20`.
5. Run `./scripts/agent-init.sh --smoke`.
6. Choose exactly one highest-priority item that is still `pending`, `in_progress`, or `blocked`.

If the smoke step fails, fix the broken baseline before implementing a new feature slice.

## Session Rules

- Work on one feature or task slice at a time.
- Keep the feature list machine-readable and stable. Update status, notes, files, and verification fields instead of rewriting unrelated items.
- Only mark an item verified after running the command or user flow listed in that item.
- Use spawned agents for bounded slices, not for overall task-state ownership.
- When a child agent owns one item, give it the exact item id, acceptance criteria, and files it may touch.

## Session End Checklist

1. Append a short progress entry to `progress.md`.
2. Update the touched item in `feature-list.json`.
3. Record the exact commands run for verification.
4. Capture blockers, follow-ups, and the next best item to resume.

## Recommended Progress Entry Shape

Use a short structure like:

```markdown
## 2026-03-17 14:30

- Item: F003
- Summary: Updated the browser-check flow to use the shared init/bootstrap path.
- Files: `.cursor/agents/browser-check.md`, `.codex/agents/browser-check.toml`
- Verification: `yarn build`, `yarn lint`, `yarn type-check`
- Next: Run the smoke flow and update the task-board status.
```
```

---

## docs/agent-playbooks/bug-investigation.md

Source: https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/bug-investigation.md

```markdown
# Bug Investigation Workflow

Use this when a bug is reported in a specific file/line/code block.

## Mandatory First Step

Before editing, check git history for the relevant code. Previous contributors may have introduced behavior for an edge case/workaround.

## Workflow

1. Scan recent commit titles (titles only) for the file/area:

```bash
# Recent commit titles for a specific file
git log --oneline -10 -- src/components/post-desktop/post-desktop.tsx

# Recent commit titles for a specific line range
git blame -L 120,135 src/components/post-desktop/post-desktop.tsx
```

2. Inspect only relevant commits with scoped diffs:

```bash
# Show commit message + diff for one file
git show <commit-hash> -- path/to/file.tsx
```

3. Continue with reproduction and fix after understanding the history context.

## Troubleshooting Rule

When blocked, search the web for recent fixes/workarounds.
```

---

## docs/agent-playbooks/translations.md

Source: https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/translations.md

```markdown
# Translations Workflow

This project uses i18next translation files in `public/translations/{lang}/default.json`.

## Rule

Do not manually edit every language file. Use `scripts/update-translations.js`.

## Add or Update a Key

1. Create a temporary dictionary file, e.g. `translations-temp.json`:

```json
{
  "en": "English text",
  "es": "Spanish text",
  "fr": "French text",
  "de": "German text"
}
```

2. Apply the translation map:

```bash
node scripts/update-translations.js --key my_new_key --map translations-temp.json --include-en --write
```

3. Delete the temporary dictionary file.

## Other Useful Commands

```bash
# Copy a key from English to all languages (dry run then write)
node scripts/update-translations.js --key some_key --from en --dry
node scripts/update-translations.js --key some_key --from en --write

# Delete a key from all languages
node scripts/update-translations.js --key obsolete_key --delete --write

# Audit for unused translation keys
node scripts/update-translations.js --audit --dry
node scripts/update-translations.js --audit --write
```
```

---

## docs/agent-playbooks/skills-and-tools.md

Source: https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/skills-and-tools.md

```markdown
# Skills and Tools

Use this playbook when setting up/adjusting skills and external tooling, or to discover what is already committed.

## Committed Skills Index

These live in `.claude/skills/`, `.cursor/skills/`, and `.codex/skills/` (mirrored; run `yarn ai-workflow:check` after edits). No install needed — prefer them over re-implementing the flow by hand.

| Skill | Use when |
|---|---|
| `commit` | Committing current work (splits into logical scoped commits) |
| `commit-format` / `issue-format` | Formatting commit/issue *suggestions* in chat output |
| `make-closed-issue` | Creating an issue + branch + PR into `master` for already-done work |
| `review-and-merge-pr` | Triaging bot/human PR feedback, fixing, merging, finalizing issues |
| `fix-merge-conflicts` | Resolving merge conflicts non-interactively and validating the build |
| `release` / `release-description` | Cutting a release / updating the release one-liner |
| `code-quality-review` | Advisory final-diff quality pass before finishing, committing, pushing, or opening a PR |
| `refactor-pass` | Simplicity-focused refactor of recent changes |
| `deslop` | Removing AI-generated slop from the branch diff |
| `debug-agent` | Evidence-based debugging with runtime NDJSON logs |
| `you-might-not-need-an-effect` | Auditing/refactoring `useEffect` anti-patterns |
| `vercel-react-best-practices` | React performance review rules (vendored from Vercel) |
| `translate` | i18next key changes across all 35 languages (spawns `translator` subagents) |
| `playwright-cli` | Browser automation and cross-engine UI verification |
| `inspect-elements` | Mapping a live DOM node to its React source file/component stack |
| `profile-browsing` | Web Vitals + react-scan rerender profiling (spawns `profiler` subagents) |
| `test-apk` | Android emulator APK testing (spawns the `test-apk` subagent) |
| `implement-plan` | Executing a multi-task plan via parallel `plan-implementer` subagents |
| `readme` | Creating/updating README.md |
| `context7` | Fetching up-to-date library docs |
| `find-skills` | Discovering/installing ecosystem skills |

## Committed Subagents

Defined in `.claude/agents/*.md`, `.cursor/agents/*.md`, `.codex/agents/*.toml` (+ `.codex/config.toml` entries): `browser-check`, `code-quality`, `plan-implementer`, `profiler`, `react-doctor-fixer`, `react-patterns-enforcer`, `test-apk`, `translator`. Most are driven by the skills above; read the agent file before spawning one directly.

## Recommended Skills

### Context7 (library docs)

For up-to-date docs on libraries.

```bash
npx skills add https://github.com/intellectronica/agent-skills --skill context7
```

### Vercel React Best Practices

For deeper React/Next performance guidance.

```bash
npx skills add https://github.com/vercel-labs/agent-skills --skill vercel-react-best-practices
```

### Find Skills

Discover/install skills from the open ecosystem.

```bash
npx skills add https://github.com/vercel-labs/skills --skill find-skills
```

### Playwright CLI

Use `playwright-cli` for browser automation (navigation, interaction, screenshots, tests, extraction).

Default to a fresh isolated browser session for normal verification. If the task depends on the contributor's existing browser state, ask whether they want:

- a fresh isolated `playwright-cli` session
- their current browser session reused

Do not attach to a live personal browser session without explicit confirmation.

When using `playwright-cli` for repo UI verification, run the relevant flow in all three main browser engines:

- `chrome` for Blink
- `firefox` for Gecko
- `webkit` for Safari/WebKit coverage

Use separate named sessions per engine so results stay isolated, but run those sessions sequentially. Only one Playwright browser session may be active at a time, machine-wide, because the contended resource is machine RAM and CPU rather than the repository. Open and close sessions through `./scripts/pw-session.sh`; it holds that shared lock so concurrent agents defer and retry browser work instead of saturating the machine.

During iteration, use Chrome/Blink only. Run the full Chrome, Firefox, and WebKit sequence once the change is ready for final verification. Reuse each engine session for desktop and mobile by resizing it, close it in a finally-style cleanup, and only then open the next engine. Do not run profiler batches in parallel, and do not use `close-all` or `kill-all` while other agents may be active.

```bash
./scripts/pw-session.sh open verify-chrome https://5chan.localhost --browser=chrome
playwright-cli -s=verify-chrome snapshot
playwright-cli -s=verify-chrome resize 375 812
playwright-cli -s=verify-chrome snapshot
./scripts/pw-session.sh close verify-chrome
```

When the slot is busy, `open` exits 75; block on `./scripts/pw-session.sh open --wait[=SECONDS] ...` (default 300s) instead of retrying by hand. A lock left behind by an interrupted workflow is reclaimed automatically, because `open` drops any slot whose recorded browser is no longer running. Inspect the holder with `./scripts/pw-session.sh status`, which reports whether that browser is still alive; `release <session>` is a last resort for the rare case where `status` cannot verify the browser state.

```bash
npm install -g @playwright/cli@latest
playwright-cli install --skills
```

Skill install locations:

- `.codex/skills/playwright-cli/`
- `.cursor/skills/playwright-cli/`
- `.claude/skills/playwright-cli/`

## MCP Policy Rationale

Avoid GitHub MCP and browser MCP servers for this project because they add significant tool-schema/context overhead.

- GitHub operations: use `gh` CLI.
- Browser operations: use `playwright-cli`.
- If current browser reuse is needed, keep using Playwright-based attach paths rather than browser MCP servers.
```

---

## docs/upload-automation-retest-checklist.md

Source: https://github.com/bitsocialnet/5chan/blob/master/docs/upload-automation-retest-checklist.md

```markdown
# Upload Automation Retest Checklist

Retest checklist for Android and desktop after changes to media upload automation (`MediaUploadAutomationRunner`, `MediaUploadRecipes`, `upload-orchestrator`, etc.).

## Quality Gate (blocking)

Run before merge/rollout. All must pass.

| Command | Purpose | Interpretation |
|---------|---------|----------------|
| `yarn test` | Unit tests (Vitest) | Exit 0 = pass. Fix failing tests before merge. |
| `yarn build` | Production build | Exit 0 = pass. No build errors. |
| `yarn lint` | Lint (oxlint) | Exit 0 = pass. Fix lint errors. |
| `yarn type-check` | TypeScript (tsc) | Exit 0 = pass. Fix type errors. |
| `yarn doctor` | React Doctor | Advisory. Prioritize `error` > `warning`. |

**Quick run (all quality gates):**

```bash
yarn retest:quality
```

---

## Imgur chooser contract (required local gate)

Runs imgur-specific emulator contract tests against deterministic fixtures. **Emulator required.** Must pass before merge.

```bash
yarn contract:imgur
```

- **Prereq:** Android emulator running or USB device connected.
- **Interpretation:** Exit 0 = contract tests pass. Runs `MediaUploadAutomationRunnerTest` (imgur chooser contract + generic fixtures). Uses deterministic fixtures in `android/app/src/main/assets/fixtures/`.

---

## Android Emulator Verification (report-only)

Instrumentation tests run on an **emulator or physical device**. Requires an emulator/device to be running and connected.

### Standard run

```bash
yarn android:connectedTest
```

Or directly (uses UTP workaround for protobuf compatibility):

```bash
cd android && ./gradlew :app:connectedDebugAndroidTest -Pandroid.experimental.androidTest.useUnifiedTestPlatform=false
```

- **Prereq:** Emulator running (`emulator -avd <avd_name>` or Android Studio) or USB device.
- **Interpretation:** Exit 0 = all instrumented tests pass. `MediaUploadAutomationRunnerTest` exercises fixtures in `android/app/src/main/assets/fixtures/`.

### UTP / Protobuf issue (known)

On some setups, `connectedDebugAndroidTest` fails with protobuf classloader conflicts (e.g. `IllegalAccessError` involving `com.google.protobuf.CodedInputStream`). This is a known UTP/Espresso + protobuf incompatibility.

**Workaround (disable UTP, use legacy test runner):**

Use this exact command, which passes `-Pandroid.experimental.androidTest.useUnifiedTestPlatform=false` to disable the unified test platform:

```bash
cd android && ./gradlew :app:connectedDebugAndroidTest -Pandroid.experimental.androidTest.useUnifiedTestPlatform=false
```

> **Caveat:** The `useUnifiedTestPlatform=false` flag may be deprecated in future Android Gradle Plugin versions; if it stops working, use the fallback below.

If the above does not resolve it, exclude conflicting protobuf from Espresso in `android/app/build.gradle`:

```gradle
androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0") {
    exclude group: "com.google.protobuf", module: "protobuf-java"
    exclude group: "com.google.protobuf", module: "protobuf-lite"
}
```

---

## Upload Selector Smoke Run (report-only, non-blocking)

Probes live upload sites (Imgur) to verify selectors in `media-upload-recipes` still match. **Always exits 0**; intended for CI report-only and local triage. **Not a merge gate**—check report for selector drift but do not block.

```bash
yarn smoke:upload-selectors
```

- **Output (report):** `scripts/upload-selectors-smoke-report.json`
- **Output (snapshots):** `scripts/upload-selectors-smoke-snapshots/` (provider PNGs)
- **Interpretation:** Check `summary.ok` vs `summary.warn` in the report. Warnings indicate selectors may need updates; do not block merge without further triage.

---

## Desktop (Electron)

Build and run the Electron app to manually verify upload flows:

```bash
yarn electron:start
```

Unit tests for Electron automation (non-blocking, report-only):

```bash
node electron/media-upload-automation.test.js
node electron/media-upload-recipes.test.js
```

---

## Summary

| Check | Blocking? | Command |
|-------|-----------|---------|
| Quality gate | Yes | `yarn retest:quality` |
| Imgur chooser contract | Yes | `yarn contract:imgur` |
| Android instrumentation | No (report-only) | `yarn android:connectedTest` |
| Upload selector smoke | No (report-only) | `yarn smoke:upload-selectors` |
| Electron unit tests | No (report-only) | `node electron/media-upload-*.test.js` |
```

---
