Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude/agents/browser-check.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,5 @@ playwright-cli -s=verify-webkit snapshot
- If playwright-cli is not installed, report it immediately and stop
- If the dev server is unreachable, report the error and stop
- Don't modify any code — you are read-only, verification only
- Default to a fresh isolated `playwright-cli` browser session. If the requested verification depends on auth, cookies, extensions, open tabs, or other existing browser state and the parent agent did not specify session mode, stop and ask whether to use a fresh browser or the contributor's current browser session.
- Never attach to a live personal browser session without explicit permission. If current-session reuse is requested, use the supported attach path only when available; otherwise report the limitation instead of silently switching modes.
2 changes: 1 addition & 1 deletion .claude/agents/code-quality.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ For each failure:
1. Read the affected file to understand context
2. Check git history for the affected lines (`git log --oneline -5 -- <file>`) to avoid reverting intentional code
3. Apply the minimal fix that resolves the error
4. Follow project patterns from AGENTS.md (Zustand for shared state, plebbit-react-hooks for data, derive state during render)
4. Follow project patterns from AGENTS.md (Zustand for shared state, bitsocial-react-hooks for data, derive state during render)

### Step 4: Re-verify

Expand Down
8 changes: 4 additions & 4 deletions .claude/agents/profiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ model: haiku
description: Performance profiler that browses seedit routes via playwright-cli, collecting Web Vitals and React rerender data via react-scan. Returns a structured issues list for a batch of routes. Use proactively when profiling browsing performance, finding bottlenecks, or diagnosing excessive React rerenders.
---

You are a performance profiling agent for the seedit React app at http://localhost:3000. You use playwright-cli to automate browsing and collect both browser-level (Web Vitals) and React-level (commit counts, per-component render data via react-scan) performance metrics.
You are a performance profiling agent for the seedit React app at http://seedit.localhost:1355. You use playwright-cli to automate browsing and collect both browser-level (Web Vitals) and React-level (commit counts, per-component render data via react-scan) performance metrics.

**MUST: Never start a dev server.** The orchestrator guarantees one is already running. If the app is unreachable, report the error and stop — do not run `yarn start` or any other server command.

Expand Down Expand Up @@ -49,7 +49,7 @@ playwright-cli -s=SESSION run-code "async page => await page.addInitScript(() =>
`window.__PROFILING__=true` tells react-scan to disable its toolbar and sounds during automated profiling.

```bash
playwright-cli -s=SESSION goto http://localhost:3000
playwright-cli -s=SESSION goto http://seedit.localhost:1355
playwright-cli -s=SESSION tracing-start
```

Expand All @@ -62,7 +62,7 @@ For each route, navigate, interact, and **collect data before moving to the next
```bash
# Navigate
playwright-cli -s=SESSION eval "performance.mark('pre-ROUTE')"
playwright-cli -s=SESSION goto http://localhost:3000/ROUTE
playwright-cli -s=SESSION goto http://seedit.localhost:1355/ROUTE
playwright-cli -s=SESSION snapshot
playwright-cli -s=SESSION eval "performance.mark('post-ROUTE');performance.measure('ROUTE','pre-ROUTE','post-ROUTE')"

Expand Down Expand Up @@ -164,6 +164,6 @@ Routes profiled: /route1, /route2, ...
- If `__getReactScanReport` returns null, note "react-scan report unavailable" and rely on commit counts
- If a route has no content or fails to load, note it in Info and move on
- **Always stop tracing and close the browser when done, even on errors** — wrap your workflow in a try/finally mindset: if any step fails, still run `tracing-stop` and `close`
- Board codes (`biz`, `pol`, `g`, etc.) map to subplebbit addresses via the app's directory
- Board codes (`biz`, `pol`, `g`, etc.) map to community addresses via the app's directory
- High commit counts without long tasks = frequent cheap rerenders — still worth fixing for efficiency
- React-scan report pinpoints exact components — prioritize these in recommendations
2 changes: 1 addition & 1 deletion .claude/agents/react-doctor-fixer.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Follow the plan provided by the parent agent. Apply changes using project patter
| Concern | Avoid | Use Instead |
|---------|-------|-------------|
| Shared state | `useState` + prop drilling | Zustand store (`src/stores/`) |
| Data fetching | `useEffect` + fetch | plebbit-react-hooks |
| Data fetching | `useEffect` + fetch | bitsocial-react-hooks |
| Derived state | `useEffect` to sync | Calculate during render |
| Side effects | Effects without cleanup | AbortController or event handlers |
| Complex flows | Boolean flags | State machine in Zustand |
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/react-patterns-enforcer.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Read each changed file and check for these project-critical anti-patterns:
| Violation | Fix |
|-----------|-----|
| `useState` for shared/global state | Move to Zustand store in `src/stores/` |
| `useEffect` for data fetching | Replace with plebbit-react-hooks |
| `useEffect` for data fetching | Replace with bitsocial-react-hooks |
| `useEffect` syncing derived state | Calculate during render instead |
| Boolean flag soup (`isLoading`, `isError`) | Use state machine in Zustand |
| Copy-pasted logic across components | Extract to custom hook in `src/hooks/` |
Expand Down
6 changes: 6 additions & 0 deletions .claude/hooks.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"version": 1,
"hooks": {
"sessionStart": [
{
"command": ".claude/hooks/session-start.sh",
"timeout": 120
}
],
"afterFileEdit": [
{
"command": ".claude/hooks/format.sh",
Expand Down
22 changes: 22 additions & 0 deletions .claude/hooks/session-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

# SessionStart hook: ensure dependencies are installed for the current worktree.
# Runs `corepack yarn install` when node_modules is missing, so new Claude-created
# worktrees are usable immediately without a manual install step.

set -u

repo_root="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
cd "$repo_root" 2>/dev/null || exit 0

# No yarn.lock → not a yarn project or fresh clone; nothing to do.
[ -f "yarn.lock" ] || exit 0

# node_modules already populated → nothing to do (fast path).
if [ -d "node_modules" ] && [ -n "$(ls -A node_modules 2>/dev/null | head -1)" ]; then
exit 0
fi

echo "[claude hook] node_modules missing in $repo_root — running corepack yarn install..."
corepack yarn install
exit 0
8 changes: 4 additions & 4 deletions .claude/skills/deslop/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const [count, setCount] = useState(0); // Initialize count state to 0
const user = useComment({ commentCid });

// ✅ Keep — explains non-obvious intent
// plebbit-react-hooks returns undefined while loading, null if not found
// bitsocial-react-hooks returns undefined while loading, null if not found
const isLoading = comment === undefined;
```

Expand All @@ -53,15 +53,15 @@ const isLoading = comment === undefined;
AI adds try/catch blocks and null guards everywhere, even on trusted codepaths. Remove guards that the surrounding code doesn't need.

```typescript
// ❌ Slop — plebbit-react-hooks already handles errors internally
// ❌ Slop — bitsocial-react-hooks already handles errors internally
try {
const { feed } = useFeed({ subplebbitAddresses });
const { feed } = useFeed({ communities });
} catch (error) {
console.error('Failed to fetch feed:', error);
}

// ✅ Clean — just use the hook directly
const { feed } = useFeed({ subplebbitAddresses });
const { feed } = useFeed({ communities });
```

### `as any` casts
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/implement-plan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Each subagent prompt must include:
- **File paths** and context needed to work independently
- **Constraints** or edge cases from the plan

Use `model: "fast"` for straightforward tasks. Omit model for complex ones.
Use the `plan-implementer` agent's configured model unless the harness explicitly requires a supported model override for a straightforward task. Omit overrides for complex or cross-cutting tasks.

Wait for all subagents in a batch to complete before starting the next batch.

Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/inspect-elements/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Use this skill to jump from a concrete DOM node in the running seedit app to the

## Prerequisites

- Dev server running at `http://localhost:3000`
- Dev server running at `http://seedit.localhost:1355`
- `playwright-cli` installed
- Use the local dev app, not production. The element-source helpers are only exposed in dev mode.

Expand All @@ -33,8 +33,8 @@ The result includes:
## Session setup

```bash
playwright-cli -s=inspect open http://localhost:3000
playwright-cli -s=inspect goto http://localhost:3000/all
playwright-cli -s=inspect open http://seedit.localhost:1355
playwright-cli -s=inspect goto http://seedit.localhost:1355/all
playwright-cli -s=inspect eval "window.__ELEMENT_SOURCE__?.ready ?? false"
playwright-cli -s=inspect snapshot
```
Expand Down
6 changes: 5 additions & 1 deletion .claude/skills/make-closed-issue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ Creates a GitHub issue, commits relevant changes on a review branch, pushes the

### 1. Determine label(s)

Ask the user using AskQuestion (multi-select):
The agent should choose the issue label(s) itself from the conversation context and diff. Do **not** ask the user to pick labels unless the work is genuinely ambiguous after reviewing both.

Default mapping:

| Option | When |
|--------|------|
Expand All @@ -25,6 +27,8 @@ Ask the user using AskQuestion (multi-select):
| `bug` + `enhancement` | New feature that also fixes a bug |
| `documentation` | README, AGENTS.md, docs-only changes |

When the classification is ambiguous, make the best reasonable choice and note the reasoning in the final summary. Only ask the user if the ambiguity would materially affect tracking or triage.

### 2. Resolve the current GitHub assignee

Before creating or editing any issue assignee, determine the current contributor's GitHub username from the authenticated `gh` session.
Expand Down
28 changes: 28 additions & 0 deletions .claude/skills/playwright-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ playwright-cli screenshot
playwright-cli close
```

## Session mode selection

Default to a fresh isolated browser session for reproducible verification.

Before browser work where existing state may matter, explicitly confirm the mode if the user has not already said which one they want:

1. Fresh isolated `playwright-cli` session
2. Current browser session reuse

Existing state usually matters when the task depends on auth, cookies, extensions, open tabs, or reproducing something already happening in the contributor's browser.

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

If current-session reuse is requested, prefer the supported attach path in the local setup:

```bash
# Fresh isolated browser (default)
playwright-cli -s=verify open https://example.com

# Reusable Playwright-managed profile
playwright-cli -s=verify open https://example.com --persistent

# Attach to an existing browser when the local extension bridge is set up
playwright-cli open --extension
```

If the task requires the contributor's current browser session and the attach path is not available in the current setup, stop and ask whether to switch to a fresh session or provide an explicit CDP-based Playwright script.

## Commands

### Core
Expand Down
11 changes: 5 additions & 6 deletions .claude/skills/profile-browsing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Two-layer profiling: browser-level symptoms (Web Vitals, long tasks, scroll jank

## Prerequisites

- Dev server running at http://localhost:3000 (`yarn start`)
- Dev server running at http://seedit.localhost:1355 (`yarn start` via Portless)
- `playwright-cli` installed (`npm install -g @playwright/cli@latest`)

**IMPORTANT:** The orchestrator (you) is responsible for ensuring exactly ONE dev server is running. Profiler subagents must NEVER start a dev server themselves.
Expand Down Expand Up @@ -54,16 +54,15 @@ Keep batches balanced. Add thread views (`/:boardIdentifier/thread/:cid`) as nee

## Step 2: Spawn Profiler Subagents

Read the profiler subagent definition at `.claude/agents/profiler.md`. Then spawn one `shell` Task per batch **in parallel** (single message, multiple Task calls):
Read the profiler subagent definition at `.claude/agents/profiler.md`. Then spawn one `profiler` Task per batch **in parallel** (single message, multiple Task calls):

```
For each batch, create a Task:
subagent_type: "shell"
subagent_type: "profiler"
prompt: |
You are a performance profiler. Follow the workflow in .claude/agents/profiler.md.
Session name: "prof-N"
Routes to profile: /route1, /route2, ...
[Include the full profiler workflow from the agent file]
Any non-default app URL or extra profiling constraints
```

Spawn up to 4 subagents simultaneously. Each opens its own browser session, navigates routes, scrolls, collects both Web Vitals and react-scan data per route, and returns a structured issues list.
Expand Down Expand Up @@ -160,5 +159,5 @@ playwright-cli -s=prof-3 close 2>/dev/null
- **Per-route collection**: Data resets on each `goto` — the profiler collects before navigating away.
- **addInitScript persistence**: Instrumentation re-injects automatically in each new document.
- **Tracing**: Each subagent produces a `trace.zip` viewable in [Trace Viewer](https://trace.playwright.dev).
- **Board codes**: `biz`, `pol`, `g`, `a`, `v`, etc. map to subplebbit addresses via the directory.
- **Board codes**: `biz`, `pol`, `g`, `a`, `v`, etc. map to community addresses via the app's directory.
- **Without react-scan**: If `__getReactScanReport` returns null, the profiler falls back to commit counts + render bursts (still useful, just no component names).
2 changes: 1 addition & 1 deletion .claude/skills/refactor-pass/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ When refactoring, watch for these anti-patterns from AGENTS.md:
| Anti-pattern | Refactor to |
|---|---|
| `useState` for shared state | Zustand store in `src/stores/` |
| `useEffect` for data fetching | plebbit-react-hooks (`useComment`, `useFeed`, etc.) |
| `useEffect` for data fetching | bitsocial-react-hooks (`useComment`, `useFeed`, etc.) |
| `useEffect` to sync derived state | Calculate during render |
| Copy-pasted logic across components | Custom hook in `src/hooks/` |
| Boolean flag soup (`isLoading`, `isError`, `isSuccess`) | State machine in Zustand |
Expand Down
68 changes: 68 additions & 0 deletions .claude/skills/release-description/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
name: release-description
description: Update the one-liner release description in scripts/release-body.js by analyzing commit titles since the last git tag. Use when the user asks to update the release description, release notes one-liner, or prepare release body for a new version.
---

# Release Description

Update `oneLinerDescription` in `scripts/release-body.js` before each release.

## Steps

### 1. Find the latest release tag

```bash
git tag --sort=-creatordate | head -1
```

### 2. List commit titles since that tag

```bash
git log --oneline <tag>..HEAD
```

If there are no commits since the tag, stop — nothing to update.

### 3. Analyze the commits

Categorize by Conventional Commits prefix:

| Prefix | Category |
|--------|----------|
| `feat:` | New features |
| `fix:` | Bug fixes |
| `perf:` | Performance improvements |
| `refactor:` | Refactors / internal changes |
| `chore:`, `docs:`, `ci:` | Maintenance (mention only if significant) |
| No prefix | Read the title to infer category |

### 4. Write the one-liner

Compose a single sentence that summarizes the release at a high level. Rules:

- **Start with** "This version..." or "This release..."
- **Be concise** — one sentence, no bullet points
- **Highlight the most impactful changes** — lead with the biggest features or fixes
- **Group similar changes** — e.g. "several bug fixes" instead of listing each one
- **Use plain language** — this is user-facing, not developer-facing
- **Don't mention every commit** — summarize the theme

Examples of good one-liners:
- "This version adds community filtering, a copy user ID menu item, and several bug fixes."
- "This version introduces feed improvements and performance optimizations."
- "This release adds reply threading enhancements and fixes timezone display issues."

### 5. Update the constant

Edit `oneLinerDescription` in `scripts/release-body.js` (around line 104–105):

```js
const oneLinerDescription = 'Your new one-liner here.';
```

### 6. Verify

Read the updated line back to confirm it looks right. The string should:
- Be a single sentence
- End with a period
- Not contain backticks or markdown
11 changes: 5 additions & 6 deletions .claude/skills/test-apk/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ description: Test and debug Android APK features using a local Android emulator.

## Overview

Delegates APK testing to a **shell subagent** (`model: fast`) to keep the main context clean.
The subagent manages the emulator, builds/installs the APK, executes tests, and returns structured diagnostics.
Delegates APK testing to the dedicated `test-apk` subagent to keep the main context clean.
That subagent manages the emulator, builds and installs only when needed, executes the requested tests, and returns structured diagnostics.

## Workflow

Expand All @@ -25,14 +25,13 @@ Ask the user (or infer from context) what to test. Common scenarios:
| Manual APK interaction | Build, install, launch, capture logcat |
| Contract tests (fixtures) | `yarn contract:postimages` |

### Step 2: Delegate to Shell Subagent
### Step 2: Delegate to the `test-apk` Subagent

Spawn a **shell** subagent with `model: fast`. Use the prompt template below, filling in `{TEST_DESCRIPTION}` with the user's requirements.
Spawn the `test-apk` subagent with the prompt template below, filling in `{TEST_DESCRIPTION}` with the user's requirements and any exact commands or classes you want run.

```
Use the Task tool:
subagent_type: "shell"
model: "fast"
subagent_type: "test-apk"
prompt: <see Prompt Template below>
```

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/translate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ For each key, check if the English value already exists in `public/translations/

### Step 3 — Spawn translator subagents

For **each key**, spawn a `translator` subagent (using the Task tool with `subagent_type: "generalPurpose"` and `model: "fast"`). The prompt for each subagent must include:
For **each key**, spawn a `translator` subagent using the Task tool with `subagent_type: "translator"`. The prompt for each subagent must include:
- The key name
- The English value
- An instruction to follow the translator subagent's system prompt
Expand Down
8 changes: 4 additions & 4 deletions .claude/skills/you-might-not-need-an-effect/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ useEffect(() => {
<CommentForm key={postCid} />
```

### 4. Fetching data (use plebbit-react-hooks, not useEffect)
### 4. Fetching data (use bitsocial-react-hooks, not useEffect)

This project uses `plebbit-react-hooks` for all data fetching. Never use `useEffect` + `fetch`.
This project uses `bitsocial-react-hooks` for all data fetching. Never use `useEffect` + `fetch`.

```typescript
// ❌ Anti-pattern
Expand Down Expand Up @@ -134,10 +134,10 @@ if (typeof window !== 'undefined') {

| useEffect pattern | Replace with |
|-------------------|-------------|
| Fetch data | `useComment`, `useFeed`, `useSubplebbit`, etc. from plebbit-react-hooks |
| Fetch data | `useComment`, `useFeed`, `useCommunity`, etc. from bitsocial-react-hooks |
| Sync shared state | Zustand store in `src/stores/` |
| Derive values from state | Calculate during render |
| Boolean loading/error flags | `state` field from plebbit-react-hooks, or state machine in Zustand |
| Boolean loading/error flags | `state` field from bitsocial-react-hooks, or state machine in Zustand |

## When useEffect IS Appropriate

Expand Down
Loading
Loading