ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
17
fork

Configure Feed

Select the types of activity you want to include in your feed.

1# CLAUDE.md 2 3This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 5# Project Instructions 6 7## Decision Graph Workflow 8 9**THIS IS MANDATORY. Log decisions IN REAL-TIME, not retroactively.** 10 11### The Core Rule 12 13``` 14BEFORE you do something -> Log what you're ABOUT to do 15AFTER it succeeds/fails -> Log the outcome 16CONNECT immediately -> Link every node to its parent 17AUDIT regularly -> Check for missing connections 18``` 19 20### Behavioral Triggers - MUST LOG WHEN: 21 22| Trigger | Log Type | Example | 23|---------|----------|---------| 24| User asks for a new feature | `goal` **with -p** | "Add dark mode" | 25| Choosing between approaches | `decision` | "Choose state management" | 26| About to write/edit code | `action` | "Implementing Redux store" | 27| Something worked or failed | `outcome` | "Redux integration successful" | 28| Notice something interesting | `observation` | "Existing code uses hooks" | 29 30### CRITICAL: Capture VERBATIM User Prompts 31 32**Prompts must be the EXACT user message, not a summary.** When a user request triggers new work, capture their full message word-for-word. 33 34**BAD - summaries are useless for context recovery:** 35```bash 36# DON'T DO THIS - this is a summary, not a prompt 37deciduous add goal "Add auth" -p "User asked: add login to the app" 38``` 39 40**GOOD - verbatim prompts enable full context recovery:** 41```bash 42# Use --prompt-stdin for multi-line prompts 43deciduous add goal "Add auth" -c 90 --prompt-stdin << 'EOF' 44I need to add user authentication to the app. Users should be able to sign up 45with email/password, and we need OAuth support for Google and GitHub. The auth 46should use JWT tokens with refresh token rotation. 47EOF 48 49# Or use the prompt command to update existing nodes 50deciduous prompt 42 << 'EOF' 51The full verbatim user message goes here... 52EOF 53``` 54 55**When to capture prompts:** 56- Root `goal` nodes: YES - the FULL original request 57- Major direction changes: YES - when user redirects the work 58- Routine downstream nodes: NO - they inherit context via edges 59 60**Updating prompts on existing nodes:** 61```bash 62deciduous prompt <node_id> "full verbatim prompt here" 63cat prompt.txt | deciduous prompt <node_id> # Multi-line from stdin 64``` 65 66Prompts are viewable in the TUI detail panel (`deciduous tui`) and web viewer. 67 68### ⚠️ CRITICAL: Maintain Connections 69 70**The graph's value is in its CONNECTIONS, not just nodes.** 71 72| When you create... | IMMEDIATELY link to... | 73|-------------------|------------------------| 74| `outcome` | The action/goal it resolves | 75| `action` | The goal/decision that spawned it | 76| `option` | Its parent decision | 77| `observation` | Related goal/action | 78 79**Root `goal` nodes are the ONLY valid orphans.** 80 81### Quick Commands 82 83```bash 84deciduous add goal "Title" -c 90 -p "User's original request" 85deciduous add action "Title" -c 85 86deciduous link FROM TO -r "reason" # DO THIS IMMEDIATELY! 87deciduous serve # View live (auto-refreshes every 30s) 88deciduous sync # Export for static hosting 89 90# Metadata flags 91# -c, --confidence 0-100 Confidence level 92# -p, --prompt "..." Store the user prompt (use when semantically meaningful) 93# -f, --files "a.rs,b.rs" Associate files 94# -b, --branch <name> Git branch (auto-detected) 95# --commit <hash|HEAD> Link to git commit (use HEAD for current commit) 96 97# Branch filtering 98deciduous nodes --branch main 99deciduous nodes -b feature-auth 100``` 101 102### ⚠️ CRITICAL: Link Commits to Actions/Outcomes 103 104**After every git commit, link it to the decision graph!** 105 106```bash 107git commit -m "feat: add auth" 108deciduous add action "Implemented auth" -c 90 --commit HEAD 109deciduous link <goal_id> <action_id> -r "Implementation" 110``` 111 112The `--commit HEAD` flag captures the commit hash and links it to the node. The web viewer will show commit messages, authors, and dates. 113 114### Git Commit Message Format 115 116**Keep commit messages clean and concise:** 117- NO "Generated with Claude Code" or similar by-lines 118- NO "Co-Authored-By:" lines 119- NO "Files updated:" sections or file lists 120- Use concise summary line describing the change 121- Add additional details if needed, but keep it focused 122 123**CRITICAL: Commit separate concerns separately** 124- Each commit should address ONE specific fix or feature 125- DO NOT bundle multiple unrelated changes into a single commit 126- If fixing multiple bugs, create separate commits for each bug fix 127- Example: Login typeahead fix, card spacing fix, and toast refactor = 3 commits 128 129**Example:** 130```bash 131git commit -m "remove deprecated 'followed' field and cleanup codebase 132 133Removed backward compatibility code for deprecated 'followed' field: 134- Removed from AtprotoMatch type 135- Updated 6 files to use only followStatus Record 136- Replaced simple boolean check with multi-lexicon support 137- Database schema preserved (no migration needed) 138 139Also removed empty 'nul' file created accidentally." 140``` 141 142### Git History & Deployment 143 144```bash 145# Export graph AND git history for web viewer 146deciduous sync 147 148# This creates: 149# - docs/graph-data.json (decision graph) 150# - docs/git-history.json (commit info for linked nodes) 151``` 152 153To deploy to GitHub Pages: 1541. `deciduous sync` to export 1552. Push to GitHub 1563. Settings > Pages > Deploy from branch > /docs folder 157 158Your graph will be live at `https://<user>.github.io/<repo>/` 159 160### Branch-Based Grouping 161 162Nodes are auto-tagged with the current git branch. Configure in `.deciduous/config.toml`: 163```toml 164[branch] 165main_branches = ["main", "master"] 166auto_detect = true 167``` 168 169### Audit Checklist (Before Every Sync) 170 1711. Does every **outcome** link back to what caused it? 1722. Does every **action** link to why you did it? 1733. Any **dangling outcomes** without parents? 174 175### Session Start Checklist 176 177```bash 178deciduous nodes # What decisions exist? 179deciduous edges # How are they connected? Any gaps? 180git status # Current state 181``` 182 183### Multi-User Sync 184 185Share decisions across teammates: 186 187```bash 188# Export your branch's decisions 189deciduous diff export --branch feature-x -o .deciduous/patches/my-feature.json 190 191# Apply patches from teammates (idempotent) 192deciduous diff apply .deciduous/patches/*.json 193 194# Preview before applying 195deciduous diff apply --dry-run .deciduous/patches/teammate.json 196``` 197 198PR workflow: Export patch → commit patch file → PR → teammates apply. 199 200### API Trace Capture 201 202Capture Claude API traffic to correlate decisions with actual API work: 203 204```bash 205# Run Claude through the deciduous proxy 206deciduous proxy -- claude 207 208# View traces in TUI (press 't' for Trace view) 209deciduous tui 210 211# View traces in web viewer (click "Traces" tab) 212deciduous serve 213``` 214 215**Auto-linking**: When running through `deciduous proxy`, any `deciduous add` commands automatically link to the active API span. You'll see output like: 216 217``` 218Created action #42 "Implementing auth" [traced: span #7] 219``` 220 221This lets you see exactly which API calls produced which decisions - perfect for "vibe coding" visibility. 222 223**Trace commands:** 224```bash 225deciduous trace sessions # List all sessions 226deciduous trace spans <session_id> # List spans in a session 227deciduous trace link <session_id> <node_id> # Manual linking 228deciduous trace prune --days 30 # Cleanup old traces 229``` 230 231## Project Overview 232 233ATlast is a web application that helps users find their followed accounts from other social platforms (TikTok, Instagram, Twitter/X) on Bluesky/AT Protocol. Users upload their data export files, which are parsed for usernames, then searched in the AT Protocol network. 234 235## Development Commands 236 237### Local Development 238```bash 239# Mock mode (frontend only, no backend/OAuth/database) 240npm run dev:mock 241 242# Full mode (with backend, OAuth, database) 243npm run dev:full # or npm run dev 244 245# Build for production 246npm run build 247 248# Initialize local database 249npm run init-db 250 251# Generate encryption keys for OAuth 252npm run generate-key 253``` 254 255### Environment Configuration 256 257Two development modes supported: 258 259**Mock Mode** (.env.mock): 260- Set `VITE_LOCAL_MOCK=true` 261- No database or OAuth required 262- Uses MockApiAdapter for fake data 263 264**Full Mode** (.env): 265- Set `VITE_LOCAL_MOCK=false` 266- Requires PostgreSQL (local or Neon) 267- Requires OAuth keys and configuration 268- Must use `http://127.0.0.1:8888` (NOT localhost) for OAuth to work 269- See CONTRIBUTING.md for detailed setup 270 271## Architecture Overview 272 273### Frontend (React + TypeScript + Vite) 274 275**Core Structure:** 276- `src/pages/` - Page components (Login, Upload, Results, etc.) 277- `src/components/` - Reusable UI components 278- `src/lib/parsers/` - File parsing logic for different platforms 279- `src/lib/api/` - API client with adapter pattern (Real vs Mock) 280- `src/contexts/` - React contexts (SettingsContext for theme/preferences) 281- `src/hooks/` - Custom React hooks 282 283**API Client Pattern:** 284The app uses an adapter pattern for the API layer: 285- `src/lib/api/client.ts` - Factory that returns Real or Mock adapter based on ENV.IS_LOCAL_MOCK 286- `src/lib/api/adapters/RealApiAdapter.ts` - Calls Netlify Functions 287- `src/lib/api/adapters/MockApiAdapter.ts` - Returns fake data for frontend development 288- `src/lib/api/IApiClient.ts` - Interface both adapters implement 289 290**Platform Parsers:** 291- `src/lib/parsers/platformDefinitions.ts` - Defines parsing rules for each platform (Instagram, TikTok, etc.) 292- `src/lib/parsers/fileExtractor.ts` - Handles ZIP file uploads and extracts usernames 293- `src/lib/parsers/parserLogic.ts` - Implements extraction logic (HTML regex, JSON path traversal, TEXT regex) 294 295Each platform has multiple ParseRule entries defining: 296- `zipPath` - Location inside ZIP archive 297- `format` - "HTML" | "TEXT" | "JSON" 298- `rule` - Regex pattern string or JSON key path array 299 300### Backend (Netlify Functions) 301 302**Function Structure:** 303``` 304netlify/functions/ 305├── core/ 306│ ├── middleware/ # Auth, error handling, session security 307│ ├── types/ # Shared types 308│ ├── errors/ # Custom error classes 309│ └── config/ # Configuration 310├── infrastructure/ 311│ ├── oauth/ # OAuth client factory, stores 312│ ├── database/ # Database connection, service layer 313│ ├── cache/ # Caching utilities 314│ └── lexicons/ # AT Protocol lexicons 315├── services/ # Business logic (SessionService, FollowService, etc.) 316├── repositories/ # Data access layer 317└── utils/ # Shared utilities 318``` 319 320**Key Functions:** 321- `oauth-start.ts` / `oauth-callback.ts` - AT Protocol OAuth flow 322- `session.ts` - Session management and validation 323- `batch-search-actors.ts` - Searches multiple usernames on Bluesky (includes ranking algorithm) 324- `check-follow-status.ts` - Checks if user follows specific DIDs 325- `batch-follow-users.ts` - Bulk follow operations 326- `save-results.ts` - Persists search results to database 327- `get-uploads.ts` - Retrieves user's upload history 328 329**Authentication Pattern:** 330All protected endpoints use: 3311. `withAuthErrorHandling()` middleware wrapper 3322. `AuthenticatedHandler` type (provides `context.sessionId`, `context.did`, `context.event`) 3333. `SessionService.getAgentForSession()` to get authenticated AT Protocol agent 334 335**Database:** 336- PostgreSQL via Neon serverless 337- Accessed through `DatabaseService` (infrastructure/database/) 338- Repositories pattern for data access (repositories/) 339 340**OAuth:** 341- AT Protocol OAuth using `@atproto/oauth-client-node` 342- OAuth client factory creates client with session/state stores 343- Private key (ES256) stored in `OAUTH_PRIVATE_KEY` env var 344- Public JWK served at `/jwks` endpoint 345- Must use `127.0.0.1` (not localhost) for local OAuth redirects 346 347### UI/Styling 348 349**Tailwind CSS with dual theme support:** 350- Light mode: purple/cyan color scheme 351- Dark mode: cyan/purple inverted 352- All components use `dark:` variant classes 353 354**Color System (from CONTRIBUTING.md):** 355- Text: purple-950/cyan-50 (primary), purple-750/cyan-250 (secondary) 356- Borders: cyan-500/purple-500 with opacity variants 357- Buttons: orange-600 (primary CTA), slate-600/700 (secondary) 358- Backgrounds: white/slate-900 (primary), purple-50/slate-900 (secondary) 359- Selected states: cyan-50 border-cyan-500 / purple-950/30 border-purple-500 360- Accents: orange-500/amber-500 (badges, progress) 361 362**Key Patterns:** 363- Mobile-first responsive design 364- List virtualization with `@tanstack/react-virtual` for large result sets 365- Code splitting and lazy loading for pages 366- Error boundaries throughout the app 367- Loading skeletons for async operations 368 369### Search & Matching Algorithm 370 371**Username Matching (batch-search-actors.ts):** 372The search uses a scoring system (0-100): 3731. Exact handle match (before first dot): 100 3742. Exact full handle match: 90 3753. Exact display name match: 80 3764. Partial handle match (contains): 60 3775. Partial full handle match: 50 3786. Partial display name match: 40 3797. Reverse partial match: 30 380 381All comparisons use normalized strings (lowercase, no special chars). 382Returns top 5 ranked results per username. 383 384**Result Enrichment:** 385- Fetches profiles in batches of 25 for post/follower counts 386- Checks follow status using custom lexicons (default: `app.bsky.graph.follow`) 387- Attaches follow status to each actor result 388 389## Key Technical Details 390 391### AT Protocol Integration 392- Uses `@atproto/api` for Bluesky API interactions 393- Uses `@atcute/identity-resolver` for DID resolution 394- Supports custom lexicons for experimental features 395- OAuth flow follows AT Protocol OAuth spec 396 397### File Upload Flow 3981. User uploads ZIP file (Instagram/TikTok data export) 3992. `fileExtractor.ts` reads ZIP in browser (using JSZip) 4003. Matches file paths to platform rules from `platformDefinitions.ts` 4014. `parserLogic.ts` extracts usernames (regex for HTML/TEXT, path traversal for JSON) 4025. Deduplicates and returns username list 4036. Frontend calls `/batch-search-actors` with username batches (max 50) 4047. Results stored in database via `/save-results` 405 406### Session Management 407- Session IDs stored in httpOnly cookies 408- Sessions linked to encrypted OAuth state stores 409- Session validation middleware checks database and expiry 410- Sessions tied to specific DIDs (user accounts) 411 412### Deployment 413- Hosted on Netlify 414- Static frontend built with Vite 415- Serverless functions for backend 416- Database on Neon (PostgreSQL) 417- OAuth redirects configured in netlify.toml 418 419## Adding New Features 420 421### Adding a New Social Platform 4221. Add parsing rules to `src/lib/parsers/platformDefinitions.ts`: 423```typescript 424export const PLATFORM_RULES: Record<string, ParseRule[]> = { 425 newplatform: [ 426 { 427 zipPath: "path/in/zip/file.json", 428 format: "JSON", 429 rule: ["key", "path", "to", "username"], 430 }, 431 ], 432}; 433``` 4342. Test with real data export from that platform 4353. Update UI in platform selection components 436 437### Adding a New API Endpoint 4381. Create function in `netlify/functions/your-endpoint.ts` 4392. Use `withAuthErrorHandling()` for protected endpoints 4403. Implement `AuthenticatedHandler` type 4414. Add method to `IApiClient.ts` interface 4425. Implement in both `RealApiAdapter.ts` and `MockApiAdapter.ts` 4436. Use via `apiClient.yourMethod()` in components 444 445### Adding Database Models 4461. Create migration script in `scripts/` 4472. Run against local database 4483. Update repository in `netlify/functions/repositories/` 4494. Update DatabaseService if needed 450 451## Important Notes 452 453- **OAuth Localhost Issue**: Must use `127.0.0.1:8888` not `localhost:8888` for local OAuth to work 454- **Batch Limits**: Search endpoint limited to 50 usernames per request 455- **Profile Fetching**: Batched in groups of 25 to avoid rate limits 456- **Normalization**: All username comparisons use lowercase + special char removal 457- **Security**: CSP headers configured in netlify.toml, session security middleware prevents CSRF 458- **Error Handling**: Custom error classes (ValidationError, AuthenticationError, etc.) with proper HTTP status codes