From daa0c6de94ed9d0a7624b539096c0d509a276a60 Mon Sep 17 00:00:00 2001 From: bradleyshep <148254416+bradleyshep@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:30:26 -0500 Subject: [PATCH 1/3] rules + apps --- docs/.cursor/rules/spacetimedb-csharp.mdc | 715 ++++ docs/.cursor/rules/spacetimedb-rust.mdc | 721 ++++ docs/.cursor/rules/spacetimedb-styling.mdc | 179 + docs/.cursor/rules/spacetimedb-typescript.mdc | 594 +++ docs/.cursor/rules/spacetimedb.mdc | 94 + tools/llm-oneshot/.cursor/rules/benchmark.mdc | 126 + .../llm-oneshot/.cursor/rules/deployment.mdc | 376 ++ .../.cursor/rules/frontend-csharp.mdc | 140 + .../.cursor/rules/frontend-rust.mdc | 114 + .../.cursor/rules/frontend-typescript.mdc | 87 + tools/llm-oneshot/.cursor/rules/grading.mdc | 125 + .../.cursor/rules/patterns-react.mdc | 128 + .../.cursor/rules/patterns-rust.mdc | 217 ++ .../.cursor/rules/patterns-typescript.mdc | 253 ++ tools/llm-oneshot/.cursor/rules/postgres.mdc | 144 + tools/llm-oneshot/.gitignore | 45 + tools/llm-oneshot/DEVELOP.md | 66 + .../chat-app-20260109-092206/README.md | 111 + .../chat-app-20260109-092206/backend/Lib.cs | 196 + .../backend/Module.cs | 781 ++++ .../backend/backend.csproj | 11 + .../backend/global.json | 6 + .../chat-app-20260109-092206/client/App.xaml | 40 + .../client/App.xaml.cs | 50 + .../client/MainPage.xaml | 215 ++ .../client/MainPage.xaml.cs | 589 +++ .../client/MauiProgram.cs | 24 + .../Platforms/Android/AndroidManifest.xml | 6 + .../client/Platforms/Android/MainActivity.cs | 10 + .../Platforms/Android/MainApplication.cs | 15 + .../Android/Resources/values/colors.xml | 6 + .../Platforms/MacCatalyst/AppDelegate.cs | 9 + .../Platforms/MacCatalyst/Entitlements.plist | 14 + .../client/Platforms/MacCatalyst/Info.plist | 40 + .../client/Platforms/MacCatalyst/Program.cs | 15 + .../client/Platforms/Windows/App.xaml | 8 + .../client/Platforms/Windows/App.xaml.cs | 25 + .../Platforms/Windows/Package.appxmanifest | 46 + .../client/Platforms/Windows/app.manifest | 17 + .../client/Platforms/iOS/AppDelegate.cs | 9 + .../client/Platforms/iOS/Info.plist | 32 + .../client/Platforms/iOS/Program.cs | 15 + .../iOS/Resources/PrivacyInfo.xcprivacy | 51 + .../client/Properties/launchSettings.json | 8 + .../client/Resources/AppIcon/appicon.svg | 4 + .../client/Resources/AppIcon/appiconfg.svg | 8 + .../Resources/Fonts/OpenSans-Regular.ttf | Bin 0 -> 107320 bytes .../Resources/Fonts/OpenSans-Semibold.ttf | Bin 0 -> 111208 bytes .../client/Resources/Images/dotnet_bot.png | Bin 0 -> 92532 bytes .../client/Resources/Raw/AboutAssets.txt | 15 + .../client/Resources/Splash/splash.svg | 8 + .../client/Resources/Styles/Colors.xaml | 44 + .../client/Resources/Styles/Styles.xaml | 434 +++ .../client/client.csproj | 56 + .../chat-app-20260113-143000/backend/Lib.cs | 230 ++ .../backend/Module.cs | 1079 ++++++ .../backend/backend.csproj | 11 + .../backend/global.json | 6 + .../chat-app-20260113-143000/client/App.xaml | 109 + .../client/App.xaml.cs | 10 + .../client/MainPage.xaml | 426 ++ .../client/MainPage.xaml.cs | 1306 +++++++ .../client/MauiProgram.cs | 18 + .../client/Platforms/Windows/App.xaml | 7 + .../client/Platforms/Windows/App.xaml.cs | 13 + .../client/client.csproj | 22 + .../client/global.json | 6 + .../chat-app-20260109-132430/backend/Lib.cs | 163 + .../backend/Module.cs | 753 ++++ .../backend/backend.csproj | 11 + .../backend/global.json | 6 + .../chat-app-20260109-132430/client/App.xaml | 88 + .../client/App.xaml.cs | 19 + .../client/MainPage.xaml | 431 +++ .../client/MainPage.xaml.cs | 944 +++++ .../client/MauiProgram.cs | 24 + .../client/Platforms/Windows/App.xaml | 7 + .../client/Platforms/Windows/App.xaml.cs | 13 + .../Platforms/Windows/Package.appxmanifest | 47 + .../client/Platforms/Windows/app.manifest | 19 + .../client/Services/SpacetimeService.cs | 224 ++ .../client/client.csproj | 25 + .../apps/chat-app/prompts/README.md | 141 + .../apps/chat-app/prompts/base_postgres.md | 37 + .../apps/chat-app/prompts/base_spacetime.md | 33 + .../chat-app/prompts/composed/01_basic.md | 37 + .../chat-app/prompts/composed/02_scheduled.md | 43 + .../chat-app/prompts/composed/03_realtime.md | 49 + .../chat-app/prompts/composed/04_reactions.md | 56 + .../prompts/composed/05_edit_history.md | 63 + .../prompts/composed/06_permissions.md | 70 + .../chat-app/prompts/composed/07_presence.md | 77 + .../chat-app/prompts/composed/08_threading.md | 84 + .../prompts/composed/09_private_rooms.md | 92 + .../chat-app/prompts/composed/10_activity.md | 99 + .../chat-app/prompts/composed/11_drafts.md | 106 + .../apps/chat-app/prompts/composed/12_full.md | 113 + .../chat-app/prompts/features/01_basic.md | 7 + .../prompts/features/02_typing_indicators.md | 5 + .../prompts/features/03_read_receipts.md | 5 + .../prompts/features/04_unread_counts.md | 5 + .../prompts/features/05_scheduled_messages.md | 5 + .../prompts/features/06_ephemeral_messages.md | 5 + .../chat-app/prompts/features/07_reactions.md | 6 + .../prompts/features/08_edit_history.md | 6 + .../features/09_realtime_permissions.md | 6 + .../prompts/features/10_rich_presence.md | 6 + .../chat-app/prompts/features/11_threading.md | 6 + .../prompts/features/12_private_rooms.md | 9 + .../features/13_activity_indicators.md | 8 + .../prompts/features/14_draft_sync.md | 7 + .../features/15_anonymous_migration.md | 8 + .../chat-app/prompts/grading_checklist.md | 184 + .../apps/chat-app/prompts/grading_rubric.md | 571 +++ .../prompts/language/csharp-spacetime.md | 27 + .../prompts/language/rust-spacetime.md | 33 + .../prompts/language/typescript-postgres.md | 27 + .../prompts/language/typescript-spacetime.md | 27 + .../chat-app/prompts/output_instructions.md | 3 + .../chat-app-20260109-120000/README.md | 136 + .../backend/Cargo.toml | 11 + .../backend/src/lib.rs | 739 ++++ .../client/Cargo.toml | 14 + .../client/src/index.html | 638 +++ .../client/src/main.rs | 538 +++ .../apps/chat-app/test-harness/.gitignore | 7 + .../apps/chat-app/test-harness/README.md | 393 ++ .../chat-app/test-harness/package-lock.json | 654 ++++ .../apps/chat-app/test-harness/package.json | 25 + .../test-harness/playwright.config.ts | 32 + .../chat-app/test-harness/scripts/ai-grade.ts | 524 +++ .../test-harness/scripts/collect-metrics.ts | 299 ++ .../test-harness/scripts/create-project.ts | 172 + .../test-harness/scripts/deploy-and-test.ts | 369 ++ .../test-harness/scripts/full-grade.ts | 390 ++ .../test-harness/scripts/promote-graded.ts | 203 + .../test-harness/scripts/run-benchmark.ts | 415 ++ .../test-harness/tests/01-basic-chat.spec.ts | 111 + .../tests/02-typing-indicators.spec.ts | 136 + .../tests/03-read-receipts.spec.ts | 86 + .../tests/04-unread-counts.spec.ts | 110 + .../tests/05-scheduled-messages.spec.ts | 128 + .../tests/06-ephemeral-messages.spec.ts | 100 + .../test-harness/tests/07-reactions.spec.ts | 148 + .../tests/08-edit-history.spec.ts | 191 + .../test-harness/tests/09-permissions.spec.ts | 136 + .../test-harness/tests/10-presence.spec.ts | 125 + .../test-harness/tests/11-threading.spec.ts | 154 + .../tests/12-activity-indicators.spec.ts | 94 + .../test-harness/tests/13-draft-sync.spec.ts | 133 + .../tests/14-anonymous-migration.spec.ts | 147 + .../chat-app/test-harness/tests/helpers.ts | 323 ++ .../apps/chat-app/test-harness/tsconfig.json | 16 + .../GRADING_RESULTS.md | 178 + .../client/Dockerfile | 12 + .../client/index.html | 12 + .../client/package-lock.json | 1894 +++++++++ .../client/package.json | 28 + .../client/src/App.tsx | 98 + .../client/src/components/ChatRoom.tsx | 193 + .../client/src/components/Layout.tsx | 14 + .../client/src/components/Login.tsx | 38 + .../client/src/components/MessageInput.tsx | 106 + .../client/src/components/MessageItem.tsx | 153 + .../client/src/components/RoomList.tsx | 111 + .../client/src/main.tsx | 8 + .../client/src/socket.ts | 19 + .../client/src/styles.css | 74 + .../client/src/types.ts | 38 + .../client/tsconfig.json | 20 + .../client/vite.config.ts | 20 + .../docker-compose.yml | 41 + .../chat-app-20260108-120000/logs.txt | 32 + .../server/Dockerfile | 12 + .../server/drizzle.config.ts | 13 + .../server/package-lock.json | 3429 +++++++++++++++++ .../server/package.json | 32 + .../server/src/check-db.ts | 32 + .../server/src/db/index.ts | 12 + .../server/src/db/schema.ts | 91 + .../server/src/index.ts | 433 +++ .../server/tsconfig.json | 13 + .../GRADING_RESULTS.md | 277 ++ .../chat-app-20260107-120000/README.md | 123 + .../backend/spacetimedb/package-lock.json | 120 + .../backend/spacetimedb/package.json | 11 + .../backend/spacetimedb/src/index.ts | 548 +++ .../backend/spacetimedb/src/schema.ts | 226 ++ .../backend/spacetimedb/tsconfig.json | 12 + .../client/index.html | 12 + .../client/package-lock.json | 1932 ++++++++++ .../client/package.json | 24 + .../client/src/App.tsx | 582 +++ .../client/src/config.ts | 2 + .../client/src/main.tsx | 37 + .../client/src/styles.css | 289 ++ .../client/tsconfig.json | 20 + .../client/tsconfig.node.json | 10 + .../client/vite.config.ts | 9 + .../GRADING_RESULTS.md | 174 + .../client/Dockerfile | 14 + .../client/index.html | 13 + .../client/package-lock.json | 1927 +++++++++ .../client/package.json | 25 + .../client/src/App.tsx | 640 +++ .../client/src/api.ts | 145 + .../client/src/config.ts | 2 + .../client/src/main.tsx | 6 + .../client/src/socket.ts | 25 + .../client/src/styles.css | 527 +++ .../client/src/types.ts | 39 + .../client/src/vite-env.d.ts | 2 + .../client/tsconfig.json | 20 + .../client/vite.config.ts | 10 + .../server/Dockerfile | 16 + .../server/docker-compose.yml | 46 + .../server/drizzle.config.js | 8 + .../server/drizzle.config.ts | 11 + .../server/env.example | 5 + .../server/package-lock.json | 2971 ++++++++++++++ .../server/package.json | 31 + .../server/src/auth.ts | 49 + .../server/src/db/index.ts | 13 + .../server/src/db/schema.ts | 127 + .../server/src/index.ts | 511 +++ .../server/src/jobs.ts | 78 + .../server/src/realtime.ts | 136 + .../server/src/validate.ts | 36 + .../server/tsconfig.json | 15 + .../GRADING_RESULTS.md | 150 + .../backend/spacetimedb/package-lock.json | 120 + .../backend/spacetimedb/package.json | 12 + .../backend/spacetimedb/src/index.ts | 506 +++ .../backend/spacetimedb/src/schema.ts | 246 ++ .../backend/spacetimedb/tsconfig.json | 13 + .../client/index.html | 13 + .../client/package-lock.json | 1932 ++++++++++ .../client/package.json | 25 + .../client/src/App.tsx | 767 ++++ .../client/src/config.ts | 3 + .../client/src/main.tsx | 65 + .../client/src/styles.css | 360 ++ .../client/tsconfig.json | 21 + .../client/tsconfig.node.json | 11 + .../client/vite.config.ts | 10 + .../GRADING_RESULTS.md | 370 ++ .../chat-app-20260107-120000/README.md | 152 + .../backend/spacetimedb/package-lock.json | 103 + .../backend/spacetimedb/package.json | 8 + .../backend/spacetimedb/src/index.ts | 475 +++ .../backend/spacetimedb/src/schema.ts | 178 + .../backend/spacetimedb/tsconfig.json | 19 + .../client/index.html | 13 + .../client/package-lock.json | 1408 +++++++ .../client/package.json | 22 + .../client/src/App.tsx | 56 + .../client/src/components/ChatArea.tsx | 201 + .../client/src/components/MessageInput.tsx | 225 ++ .../client/src/components/MessageItem.tsx | 219 ++ .../client/src/components/Sidebar.tsx | 167 + .../client/src/components/UserSetup.tsx | 78 + .../client/src/config.ts | 6 + .../client/src/index.css | 294 ++ .../client/src/main.tsx | 42 + .../client/tsconfig.json | 21 + .../client/tsconfig.node.json | 10 + .../client/vite.config.ts | 9 + .../opus-4-5/BENCHMARK_COMPARISON_REPORT.md | 173 + .../GRADING_RESULTS.md | 183 + .../chat-app-20260104-120000/README.md | 149 + .../client/Dockerfile | 16 + .../client/index.html | 16 + .../client/nginx.conf | 15 + .../client/package-lock.json | 1882 +++++++++ .../client/package.json | 24 + .../client/src/App.tsx | 1874 +++++++++ .../client/src/api.ts | 130 + .../client/src/index.css | 1045 +++++ .../client/src/main.tsx | 5 + .../client/src/socket.ts | 29 + .../client/src/types.ts | 101 + .../client/tsconfig.json | 21 + .../client/tsconfig.node.json | 10 + .../client/vite.config.ts | 9 + .../docker-compose.yml | 44 + .../server/Dockerfile | 11 + .../server/drizzle.config.ts | 10 + .../server/package-lock.json | 3030 +++++++++++++++ .../server/package.json | 31 + .../server/src/db/index.ts | 8 + .../server/src/db/push.ts | 143 + .../server/src/db/schema.ts | 168 + .../server/src/index.ts | 1442 +++++++ .../server/tsconfig.json | 13 + .../GRADING_RESULTS.md | 195 + .../chat-app-20260104-160000/README.md | 188 + .../client/Dockerfile | 18 + .../client/index.html | 15 + .../client/nginx.conf | 9 + .../client/package-lock.json | 1882 +++++++++ .../client/package.json | 22 + .../client/src/App.tsx | 1388 +++++++ .../client/src/api.ts | 159 + .../client/src/main.tsx | 5 + .../client/src/styles.css | 926 +++++ .../client/src/types.ts | 87 + .../client/tsconfig.json | 20 + .../client/vite.config.ts | 9 + .../docker-compose.yml | 44 + .../server/Dockerfile | 11 + .../server/drizzle.config.ts | 10 + .../server/package.json | 27 + .../chat-app-20260104-160000/server/src/db.ts | 8 + .../server/src/index.ts | 1041 +++++ .../server/src/schema.ts | 128 + .../server/tsconfig.json | 13 + .../GRADING_RESULTS.md | 197 + .../chat-app-20260104-180000/README.md | 163 + .../client/Dockerfile | 12 + .../client/index.html | 13 + .../client/package.json | 23 + .../client/src/App.tsx | 1245 ++++++ .../client/src/api.ts | 210 + .../client/src/main.tsx | 5 + .../client/src/socket.ts | 49 + .../client/src/styles.css | 954 +++++ .../client/src/types.ts | 57 + .../client/tsconfig.json | 20 + .../client/vite.config.ts | 9 + .../docker-compose.yml | 46 + .../server/Dockerfile | 11 + .../server/drizzle.config.ts | 10 + .../server/package.json | 28 + .../chat-app-20260104-180000/server/src/db.ts | 8 + .../server/src/index.ts | 1155 ++++++ .../server/src/schema.ts | 153 + .../server/tsconfig.json | 13 + .../GRADING_RESULTS.md | 230 ++ .../chat-app-20260102-162918/README.md | 133 + .../backend/spacetimedb/package-lock.json | 120 + .../backend/spacetimedb/package.json | 12 + .../backend/spacetimedb/src/index.ts | 864 +++++ .../backend/spacetimedb/src/schema.ts | 277 ++ .../backend/spacetimedb/tsconfig.json | 12 + .../client/index.html | 27 + .../client/package-lock.json | 1887 +++++++++ .../client/package.json | 22 + .../client/src/App.tsx | 109 + .../client/src/components/ChatArea.tsx | 221 ++ .../client/src/components/CreateRoomModal.tsx | 69 + .../src/components/EditHistoryModal.tsx | 46 + .../client/src/components/InvitesPanel.tsx | 58 + .../client/src/components/MembersPanel.tsx | 207 + .../client/src/components/MessageInput.tsx | 167 + .../client/src/components/MessageItem.tsx | 215 ++ .../src/components/RoomSettingsModal.tsx | 100 + .../src/components/ScheduledMessagesPanel.tsx | 52 + .../client/src/components/Sidebar.tsx | 210 + .../client/src/components/StartDmModal.tsx | 68 + .../client/src/components/StatusDropdown.tsx | 64 + .../client/src/components/ThreadPanel.tsx | 95 + .../client/src/components/UserSetup.tsx | 52 + .../client/src/main.tsx | 54 + .../client/src/styles.css | 935 +++++ .../client/tsconfig.json | 21 + .../client/vite.config.ts | 9 + .../GRADING_RESULTS.md | 265 ++ .../chat-app-20260102-170500/README.md | 109 + .../backend/spacetimedb/package-lock.json | 103 + .../backend/spacetimedb/package.json | 9 + .../backend/spacetimedb/src/index.ts | 721 ++++ .../backend/spacetimedb/src/schema.ts | 209 + .../backend/spacetimedb/tsconfig.json | 13 + .../client/index.html | 12 + .../client/package-lock.json | 1887 +++++++++ .../client/package.json | 23 + .../client/src/App.tsx | 1072 ++++++ .../client/src/index.css | 889 +++++ .../client/src/main.tsx | 54 + .../client/tsconfig.json | 20 + .../client/vite.config.ts | 9 + .../docker-compose.yml | 10 + .../GRADING_RESULTS.md | 211 + .../chat-app-20260102-171317/README.md | 183 + .../backend/spacetimedb/package-lock.json | 120 + .../backend/spacetimedb/package.json | 15 + .../backend/spacetimedb/src/index.ts | 1166 ++++++ .../backend/spacetimedb/src/schema.ts | 328 ++ .../backend/spacetimedb/tsconfig.json | 12 + .../client/index.html | 28 + .../client/package-lock.json | 1770 +++++++++ .../client/package.json | 22 + .../client/src/App.tsx | 1011 +++++ .../client/src/main.tsx | 63 + .../client/src/styles.css | 916 +++++ .../client/tsconfig.json | 17 + .../client/vite.config.ts | 9 + .../GRADING_RESULTS.md | 283 ++ .../chat-app-20260105-180000/README.md | 128 + .../backend/spacetimedb/package-lock.json | 103 + .../backend/spacetimedb/package.json | 8 + .../backend/spacetimedb/src/index.ts | 3 + .../backend/spacetimedb/src/reducers.ts | 1014 +++++ .../backend/spacetimedb/src/schema.ts | 259 ++ .../backend/spacetimedb/tsconfig.json | 13 + .../client/index.html | 16 + .../client/package-lock.json | 1932 ++++++++++ .../client/package.json | 23 + .../client/src/App.tsx | 1026 +++++ .../client/src/config.ts | 2 + .../client/src/main.tsx | 61 + .../client/src/styles.css | 1037 +++++ .../client/tsconfig.json | 20 + .../client/vite.config.ts | 9 + .../paint-app-20260109-180000/README.md | 211 + .../backend/Dockerfile | 20 + .../backend/Reducers.cs | 1487 +++++++ .../backend/Tables.cs | 399 ++ .../backend/backend.csproj | 11 + .../backend/backend.wasm | Bin 0 -> 3186462 bytes .../paint-app-20260109-180000/client/App.xaml | 67 + .../client/App.xaml.cs | 10 + .../client/Directory.Build.targets | 11 + .../client/MainPage.xaml | 224 ++ .../client/MainPage.xaml.cs | 1492 +++++++ .../client/MauiProgram.cs | 22 + .../client/Platforms/Windows/App.xaml | 7 + .../client/Platforms/Windows/App.xaml.cs | 11 + .../client/Platforms/Windows/app.manifest | 15 + .../client/client.csproj | 37 + .../paint-app-20260109-180000/deploy.ps1 | 93 + .../paint-app-20260109-180000/deploy.sh | 101 + .../docker-compose.yml | 19 + .../apps/paint-app/prompts/README.md | 117 + .../apps/paint-app/prompts/base_postgres.md | 33 + .../apps/paint-app/prompts/base_spacetime.md | 33 + .../paint-app/prompts/composed/01_basic.md | 29 + .../paint-app/prompts/composed/02_shapes.md | 37 + .../prompts/composed/03_selection.md | 48 + .../paint-app/prompts/composed/04_layers.md | 58 + .../paint-app/prompts/composed/05_presence.md | 67 + .../paint-app/prompts/composed/06_comments.md | 77 + .../paint-app/prompts/composed/07_versions.md | 86 + .../prompts/composed/08_permissions.md | 95 + .../paint-app/prompts/composed/09_follow.md | 104 + .../paint-app/prompts/composed/10_activity.md | 113 + .../paint-app/prompts/composed/11_sharing.md | 122 + .../paint-app/prompts/composed/12_full.md | 166 + .../paint-app/prompts/features/01_basic.md | 9 + .../prompts/features/02_cursor_indicators.md | 7 + .../paint-app/prompts/features/03_shapes.md | 7 + .../prompts/features/04_selection.md | 10 + .../prompts/features/05_layers_locking.md | 9 + .../paint-app/prompts/features/06_presence.md | 8 + .../paint-app/prompts/features/07_comments.md | 9 + .../prompts/features/08_version_history.md | 8 + .../features/09_realtime_permissions.md | 8 + .../prompts/features/10_follow_mode.md | 8 + .../prompts/features/11_activity_feed.md | 8 + .../prompts/features/12_private_canvases.md | 8 + .../prompts/features/13_canvas_chat.md | 8 + .../prompts/features/14_auto_cleanup.md | 8 + .../prompts/features/15_text_sticky.md | 10 + .../prompts/features/16_keyboard_shortcuts.md | 14 + .../paint-app/prompts/grading_checklist.md | 126 + .../apps/paint-app/prompts/grading_rubric.md | 201 + .../prompts/language/csharp-spacetime.md | 27 + .../prompts/language/rust-spacetime.md | 33 + .../prompts/language/typescript-postgres.md | 27 + .../prompts/language/typescript-spacetime.md | 27 + .../paint-app/prompts/output_instructions.md | 3 + .../paint-app-20260112-150000/README.md | 256 ++ .../backend/Cargo.toml | 14 + .../backend/src/lib.rs | 1860 +++++++++ .../client/Cargo.toml | 13 + .../client/src/main.rs | 1351 +++++++ .../backend/spacetimedb/package-lock.json | 103 + .../backend/spacetimedb/package.json | 8 + .../backend/spacetimedb/src/index.ts | 577 +++ .../backend/spacetimedb/src/schema.ts | 137 + .../backend/spacetimedb/tsconfig.json | 12 + .../client/index.html | 12 + .../client/package-lock.json | 1932 ++++++++++ .../client/package.json | 24 + .../client/src/App.tsx | 941 +++++ .../client/src/config.ts | 2 + .../client/src/main.tsx | 63 + .../client/src/styles.css | 606 +++ .../client/tsconfig.json | 20 + .../client/vite.config.ts | 9 + .../backend/spacetimedb/package-lock.json | 103 + .../backend/spacetimedb/package.json | 8 + .../backend/spacetimedb/src/index.ts | 1660 ++++++++ .../backend/spacetimedb/src/schema.ts | 428 ++ .../backend/spacetimedb/tsconfig.json | 12 + .../client/index.html | 12 + .../client/package-lock.json | 1938 ++++++++++ .../client/package.json | 24 + .../client/src/App.tsx | 1879 +++++++++ .../client/src/config.ts | 2 + .../client/src/main.tsx | 6 + .../client/src/styles.css | 1074 ++++++ .../client/tsconfig.json | 20 + .../client/vite.config.ts | 10 + 504 files changed, 116002 insertions(+) create mode 100644 docs/.cursor/rules/spacetimedb-csharp.mdc create mode 100644 docs/.cursor/rules/spacetimedb-rust.mdc create mode 100644 docs/.cursor/rules/spacetimedb-styling.mdc create mode 100644 docs/.cursor/rules/spacetimedb-typescript.mdc create mode 100644 docs/.cursor/rules/spacetimedb.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/benchmark.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/deployment.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/frontend-csharp.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/frontend-rust.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/frontend-typescript.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/grading.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/patterns-react.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/patterns-rust.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/patterns-typescript.mdc create mode 100644 tools/llm-oneshot/.cursor/rules/postgres.mdc create mode 100644 tools/llm-oneshot/.gitignore create mode 100644 tools/llm-oneshot/DEVELOP.md create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/backend/Lib.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/backend/Module.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/backend/backend.csproj create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/backend/global.json create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/App.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/MainPage.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/MainPage.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/MauiProgram.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Android/AndroidManifest.xml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Android/MainActivity.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Android/MainApplication.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Android/Resources/values/colors.xml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/MacCatalyst/AppDelegate.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/MacCatalyst/Entitlements.plist create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/MacCatalyst/Info.plist create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/MacCatalyst/Program.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Windows/App.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Windows/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Windows/Package.appxmanifest create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/Windows/app.manifest create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/iOS/AppDelegate.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/iOS/Info.plist create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/iOS/Program.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Platforms/iOS/Resources/PrivacyInfo.xcprivacy create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Properties/launchSettings.json create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/AppIcon/appicon.svg create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/AppIcon/appiconfg.svg create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/Fonts/OpenSans-Regular.ttf create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/Fonts/OpenSans-Semibold.ttf create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/Images/dotnet_bot.png create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/Raw/AboutAssets.txt create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/Splash/splash.svg create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/Styles/Colors.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/Resources/Styles/Styles.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260109-092206/client/client.csproj create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/backend/Lib.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/backend/Module.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/backend/backend.csproj create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/backend/global.json create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/App.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/MainPage.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/MainPage.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/MauiProgram.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/Platforms/Windows/App.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/Platforms/Windows/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/client.csproj create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/claude/spacetime/chat-app-20260113-143000/client/global.json create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/backend/Lib.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/backend/Module.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/backend/backend.csproj create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/backend/global.json create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/App.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/MainPage.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/MainPage.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/MauiProgram.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/Platforms/Windows/App.xaml create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/Platforms/Windows/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/Platforms/Windows/Package.appxmanifest create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/Platforms/Windows/app.manifest create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/Services/SpacetimeService.cs create mode 100644 tools/llm-oneshot/apps/chat-app/csharp/opus-4-5/spacetime/chat-app-20260109-132430/client/client.csproj create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/base_postgres.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/base_spacetime.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/01_basic.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/02_scheduled.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/03_realtime.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/04_reactions.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/05_edit_history.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/06_permissions.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/07_presence.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/08_threading.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/09_private_rooms.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/10_activity.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/11_drafts.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/composed/12_full.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/01_basic.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/02_typing_indicators.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/03_read_receipts.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/04_unread_counts.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/05_scheduled_messages.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/06_ephemeral_messages.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/07_reactions.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/08_edit_history.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/09_realtime_permissions.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/10_rich_presence.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/11_threading.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/12_private_rooms.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/13_activity_indicators.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/14_draft_sync.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/features/15_anonymous_migration.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/grading_checklist.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/grading_rubric.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/language/csharp-spacetime.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/language/rust-spacetime.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/language/typescript-postgres.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/language/typescript-spacetime.md create mode 100644 tools/llm-oneshot/apps/chat-app/prompts/output_instructions.md create mode 100644 tools/llm-oneshot/apps/chat-app/rust/claude-opus-4/spacetime/chat-app-20260109-120000/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/rust/claude-opus-4/spacetime/chat-app-20260109-120000/backend/Cargo.toml create mode 100644 tools/llm-oneshot/apps/chat-app/rust/claude-opus-4/spacetime/chat-app-20260109-120000/backend/src/lib.rs create mode 100644 tools/llm-oneshot/apps/chat-app/rust/claude-opus-4/spacetime/chat-app-20260109-120000/client/Cargo.toml create mode 100644 tools/llm-oneshot/apps/chat-app/rust/claude-opus-4/spacetime/chat-app-20260109-120000/client/src/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/rust/claude-opus-4/spacetime/chat-app-20260109-120000/client/src/main.rs create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/.gitignore create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/playwright.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/scripts/ai-grade.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/scripts/collect-metrics.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/scripts/create-project.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/scripts/deploy-and-test.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/scripts/full-grade.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/scripts/promote-graded.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/scripts/run-benchmark.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/01-basic-chat.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/02-typing-indicators.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/03-read-receipts.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/04-unread-counts.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/05-scheduled-messages.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/06-ephemeral-messages.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/07-reactions.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/08-edit-history.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/09-permissions.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/10-presence.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/11-threading.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/12-activity-indicators.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/13-draft-sync.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/14-anonymous-migration.spec.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tests/helpers.ts create mode 100644 tools/llm-oneshot/apps/chat-app/test-harness/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/components/ChatRoom.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/components/Layout.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/components/Login.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/components/MessageInput.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/components/MessageItem.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/components/RoomList.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/socket.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/src/types.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/docker-compose.yml create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/logs.txt create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/drizzle.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/src/check-db.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/src/db/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/src/db/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/postgres/chat-app-20260108-120000/server/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/src/config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/tsconfig.node.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/api.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/socket.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/types.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/src/vite-env.d.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/docker-compose.yml create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/drizzle.config.js create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/drizzle.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/env.example create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/src/auth.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/src/db/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/src/db/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/src/jobs.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/src/realtime.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/src/validate.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/postgres/chat-app-20260108-140800/server/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/src/config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/tsconfig.node.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/gpt-5-2/spacetime/chat-app-20260107-092240/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/components/ChatArea.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/components/MessageInput.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/components/MessageItem.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/components/Sidebar.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/components/UserSetup.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/index.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/tsconfig.node.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/grok-code/spacetime/chat-app-20260107-120000/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/BENCHMARK_COMPARISON_REPORT.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/nginx.conf create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/src/api.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/src/index.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/src/socket.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/src/types.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/tsconfig.node.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/docker-compose.yml create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/drizzle.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/src/db/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/src/db/push.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/src/db/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-120000/server/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/nginx.conf create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/src/api.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/src/types.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/docker-compose.yml create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/server/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/server/drizzle.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/server/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/server/src/db.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/server/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/server/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-160000/server/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/src/api.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/src/socket.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/src/types.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/docker-compose.yml create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/server/Dockerfile create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/server/drizzle.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/server/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/server/src/db.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/server/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/server/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/postgres/chat-app-20260104-180000/server/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/ChatArea.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/CreateRoomModal.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/EditHistoryModal.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/InvitesPanel.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/MembersPanel.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/MessageInput.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/MessageItem.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/RoomSettingsModal.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/ScheduledMessagesPanel.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/Sidebar.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/StartDmModal.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/StatusDropdown.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/ThreadPanel.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/components/UserSetup.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-162918/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/src/index.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-170500/docker-compose.yml create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260102-171317/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/GRADING_RESULTS.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/README.md create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/backend/spacetimedb/src/reducers.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/index.html create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/package.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/src/config.ts create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/chat-app/typescript/opus-4-5/spacetime/chat-app-20260105-180000/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/README.md create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/backend/Dockerfile create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/backend/Reducers.cs create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/backend/Tables.cs create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/backend/backend.csproj create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/backend/backend.wasm create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/App.xaml create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/Directory.Build.targets create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/MainPage.xaml create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/MainPage.xaml.cs create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/MauiProgram.cs create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/Platforms/Windows/App.xaml create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/Platforms/Windows/App.xaml.cs create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/Platforms/Windows/app.manifest create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/client/client.csproj create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/deploy.ps1 create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/deploy.sh create mode 100644 tools/llm-oneshot/apps/paint-app/csharp/opus-4-5/spacetime/paint-app-20260109-180000/docker-compose.yml create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/README.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/base_postgres.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/base_spacetime.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/01_basic.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/02_shapes.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/03_selection.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/04_layers.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/05_presence.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/06_comments.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/07_versions.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/08_permissions.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/09_follow.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/10_activity.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/11_sharing.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/composed/12_full.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/01_basic.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/02_cursor_indicators.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/03_shapes.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/04_selection.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/05_layers_locking.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/06_presence.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/07_comments.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/08_version_history.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/09_realtime_permissions.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/10_follow_mode.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/11_activity_feed.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/12_private_canvases.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/13_canvas_chat.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/14_auto_cleanup.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/15_text_sticky.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/features/16_keyboard_shortcuts.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/grading_checklist.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/grading_rubric.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/language/csharp-spacetime.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/language/rust-spacetime.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/language/typescript-postgres.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/language/typescript-spacetime.md create mode 100644 tools/llm-oneshot/apps/paint-app/prompts/output_instructions.md create mode 100644 tools/llm-oneshot/apps/paint-app/rust/opus-4-5/spacetime/paint-app-20260112-150000/README.md create mode 100644 tools/llm-oneshot/apps/paint-app/rust/opus-4-5/spacetime/paint-app-20260112-150000/backend/Cargo.toml create mode 100644 tools/llm-oneshot/apps/paint-app/rust/opus-4-5/spacetime/paint-app-20260112-150000/backend/src/lib.rs create mode 100644 tools/llm-oneshot/apps/paint-app/rust/opus-4-5/spacetime/paint-app-20260112-150000/client/Cargo.toml create mode 100644 tools/llm-oneshot/apps/paint-app/rust/opus-4-5/spacetime/paint-app-20260112-150000/client/src/main.rs create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/index.html create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/package.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/src/config.ts create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260109-164112/client/vite.config.ts create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/backend/spacetimedb/package-lock.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/backend/spacetimedb/package.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/backend/spacetimedb/src/index.ts create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/backend/spacetimedb/src/schema.ts create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/backend/spacetimedb/tsconfig.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/index.html create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/package-lock.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/package.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/src/App.tsx create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/src/config.ts create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/src/main.tsx create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/src/styles.css create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/tsconfig.json create mode 100644 tools/llm-oneshot/apps/paint-app/typescript/opus-4-5/spacetime/paint-app-20260112-154500/client/vite.config.ts diff --git a/docs/.cursor/rules/spacetimedb-csharp.mdc b/docs/.cursor/rules/spacetimedb-csharp.mdc new file mode 100644 index 00000000000..84d5057e46f --- /dev/null +++ b/docs/.cursor/rules/spacetimedb-csharp.mdc @@ -0,0 +1,715 @@ +--- +description: "⛔ MANDATORY: Read this ENTIRE file before writing ANY SpacetimeDB C# code. Contains SDK patterns from official documentation." +globs: **/*.cs +alwaysApply: true +--- + +# SpacetimeDB C# SDK + +> **Tested with:** SpacetimeDB runtime 1.11.x, NuGet `SpacetimeDB.ClientSDK` + `SpacetimeDB.Runtime` +> **Last updated:** 2026-01-09 +> +> ⚠️ **SDK Evolution:** The SDK is evolving rapidly. If using a newer version, check release notes for breaking changes. + +--- + +## ⛔ COMMON MISTAKES — LLM HALLUCINATIONS + +These are **actual errors** observed when LLMs generate SpacetimeDB C# code: + +### 1. Wrong Package Name for Server Modules +```csharp +// ❌ WRONG — this package doesn't exist + + +// ✅ CORRECT — use Runtime for server modules + +``` + +### 2. Lifecycle Hook Names Starting with "On" +```csharp +// ❌ WRONG — will cause STDB0010 error +[SpacetimeDB.Reducer(ReducerKind.ClientConnected)] +public static void OnClientConnected(ReducerContext ctx) { } + +// ✅ CORRECT — no "On" prefix +[SpacetimeDB.Reducer(ReducerKind.ClientConnected)] +public static void ClientConnected(ReducerContext ctx) { } +``` + +### 3. Wrong Timestamp Property Name +```csharp +// ❌ WRONG — property doesn't exist +var micros = timestamp.MicrosecondsSinceEpoch; + +// ✅ CORRECT — full name +var micros = timestamp.MicrosecondsSinceUnixEpoch; +``` + +### 4. Wrong ScheduleAt Syntax +```csharp +// ❌ WRONG — ScheduleAt.Time is not a method +ScheduledAt = ScheduleAt.Time(timestamp) + +// ✅ CORRECT — use constructor syntax +ScheduledAt = new ScheduleAt.Time(new Timestamp(microseconds)) +``` + +### 5. Table Accessor Casing: Server vs Client DIFFER! +```csharp +// Table defined as: +[SpacetimeDB.Table(Name = "user", Public = true)] +public partial class User { ... } + +// SERVER-SIDE (in reducers, using ReducerContext): +// Accessor matches the Name attribute value (lowercase if lowercase) +ctx.Db.user.Insert(...) // ✅ lowercase matches Name="user" + +// CLIENT-SIDE (in app code, using DbConnection): +// Generated bindings use PascalCase properties regardless of Name attribute! +_conn.Db.User.OnInsert += ... // ✅ PascalCase property +_conn.Db.user.OnInsert += ... // ❌ WRONG - lowercase doesn't exist on client! + +// The generated RemoteTables class has PascalCase properties: +// _conn.Db.User, _conn.Db.Canvas, _conn.Db.CanvasMember, etc. +``` + +### 6. Client Callback Signature Errors +```csharp +// ❌ WRONG — guessing at signatures +.OnDisconnect((conn, ctx, err) => ...) +.OnConnectError((ctx, err) => ...) + +// ✅ CORRECT — check actual delegate types (may vary by SDK version) +.OnDisconnect((conn, err) => ...) // DbConnection, Exception? +.OnConnectError(err => ...) // Exception + +// TIP: Let IDE show you the expected signature via autocomplete +``` + +### 7. WithUri Takes String, Not Uri +```csharp +// ❌ WRONG — Uri object not accepted +.WithUri(new Uri("http://localhost:3000")) + +// ✅ CORRECT — use string directly +.WithUri("http://localhost:3000") +``` + +### 8. Missing RuntimeIdentifier for WASM Build +```xml + +net8.0 + + +net8.0 +wasi-wasm +``` + +### 9. Subscribing Before Connected +```csharp +// ❌ WRONG — subscription fails silently, data never arrives +_conn = builder.Build(); +_conn.SubscriptionBuilder().SubscribeToAllTables(); // NOT CONNECTED YET! + +// ✅ CORRECT — subscribe inside OnConnect callback +private void OnConnected(DbConnection conn, Identity identity, string token) +{ + conn.SubscriptionBuilder() + .OnApplied(OnSubscriptionApplied) + .SubscribeToAllTables(); // Now connected! +} +``` + +### 10. Nullable Struct Handling with Find() +```csharp +// Find() returns a nullable struct (e.g., User?) +var existing = ctx.Db.User.Identity.Find(ctx.Sender); + +// ❌ WRONG — accessing properties directly on nullable struct +if (existing != null) +{ + ctx.Db.User.Identity.Update(new User { Identity = existing.Identity, ... }); +} + +// ✅ CORRECT — use .Value after null check +if (existing != null) +{ + var user = existing.Value; // Extract the struct value + ctx.Db.User.Identity.Update(new User { Identity = user.Identity, ... }); +} +``` + +### 11. Index Accessor Name Depends on Attribute Placement +```csharp +// OPTION A: Class-level attribute with custom Name +[SpacetimeDB.Table(Name = "Reaction", Public = true)] +[SpacetimeDB.Index.BTree(Name = "idx_reaction_msg", Columns = new[] { "MessageId" })] +public partial struct Reaction { public ulong MessageId; ... } + +// Accessor uses the Index Name: +ctx.Db.Reaction.idx_reaction_msg.Filter(messageId) // Uses index name! + +// OPTION B: Field-level attribute (RECOMMENDED) +[SpacetimeDB.Table(Name = "Reaction", Public = true)] +public partial struct Reaction +{ + [SpacetimeDB.Index.BTree] // On the field itself + public ulong MessageId; +} + +// ✅ Accessor uses the FIELD name: +ctx.Db.Reaction.MessageId.Filter(messageId) // Cleaner! +``` + +### 12. MAUI Windows Requires Platform Entry Point +``` +❌ WRONG — Missing entry point files +client/ +├── client.csproj +├── App.xaml +└── MainPage.xaml + +✅ CORRECT — Include Windows platform files +client/ +├── client.csproj +├── App.xaml +├── MainPage.xaml +└── Platforms/ + └── Windows/ + ├── App.xaml ← Required for Windows entry point + └── App.xaml.cs ← Required for Windows entry point +``` + +Windows App.xaml: +```xml + + +``` + +Windows App.xaml.cs: +```csharp +namespace MyApp.WinUI; + +public partial class App : MauiWinUIApplication +{ + public App() { this.InitializeComponent(); } + protected override MauiApp CreateMauiApp() => MyApp.MauiProgram.CreateMauiApp(); +} +``` + +--- + +## 1) Table Definition (Server-side Module) + +**Tables use `[SpacetimeDB.Table]` attribute on `partial struct` or `partial class`:** + +```csharp +using SpacetimeDB; + +[SpacetimeDB.Table(Name = "my_table", Public = true)] +public partial struct MyTable +{ + [SpacetimeDB.PrimaryKey] + [SpacetimeDB.AutoInc] + public ulong Id; + + [SpacetimeDB.Unique] + public Identity Owner; + + [SpacetimeDB.Index.BTree] + public string Name; + + public ulong Value; + public Timestamp CreatedAt; +} +``` + +### Column Attributes + +```csharp +[SpacetimeDB.PrimaryKey] // Primary key (auto-indexed) +[SpacetimeDB.AutoInc] // Auto-increment (use with PrimaryKey) +[SpacetimeDB.Unique] // Unique constraint (auto-indexed) +[SpacetimeDB.Index.BTree] // B-Tree index for queries +``` + +### Multi-Column Indexes + +```csharp +[SpacetimeDB.Table(Public = true)] +[SpacetimeDB.Index.BTree(Name = "by_foo_and_bar", Columns = new[] { "Foo", "Bar" })] +public partial struct MyTable +{ + public ulong Foo; + public Timestamp Bar; + // ... +} +``` + +### Table Visibility + +```csharp +// Public table - clients can subscribe +[SpacetimeDB.Table(Name = "my_table", Public = true)] + +// Private table - only reducers can access +[SpacetimeDB.Table(Name = "my_table")] // Public = false is default +``` + +--- + +## 2) Reducers (Server-side Module) + +### Definition Syntax + +```csharp +using SpacetimeDB; + +public static partial class Module +{ + [SpacetimeDB.Reducer] + public static void DoSomething(ReducerContext ctx, string param1, ulong param2) + { + // Validate input + if (string.IsNullOrEmpty(param1)) + { + throw new ArgumentException("param1 cannot be empty"); + } + + // Insert returns the inserted row (NOT the ID) + var row = ctx.Db.MyTable.Insert(new MyTable + { + Id = 0, // Auto-increment placeholder + Owner = ctx.Sender, + Name = param1, + Value = param2, + CreatedAt = ctx.Timestamp + }); + + // row.Id now contains the assigned ID + Log.Info($"Created row with ID: {row.Id}"); + } + + [SpacetimeDB.Reducer] + public static void UpdateSomething(ReducerContext ctx, ulong id, string newValue) + { + var row = ctx.Db.MyTable.Id.Find(id); + if (row == null) + { + throw new Exception("Row not found"); + } + + // Update by primary key - must provide complete row + ctx.Db.MyTable.Id.Update(new MyTable + { + Id = row.Id, + Owner = row.Owner, + Name = newValue, // Changed field + Value = row.Value, // Preserve other fields + CreatedAt = row.CreatedAt + }); + } + + [SpacetimeDB.Reducer] + public static void DeleteSomething(ReducerContext ctx, ulong id) + { + // Delete by primary key value + ctx.Db.MyTable.Id.Delete(id); + } +} +``` + +### Update Pattern (CRITICAL) + +```csharp +// ✅ CORRECT — provide complete row with all fields +var existing = ctx.Db.MyTable.Id.Find(id); +ctx.Db.MyTable.Id.Update(new MyTable +{ + Id = existing.Id, + Owner = existing.Owner, + Name = newValue, // Changed + Value = existing.Value, // Preserved + CreatedAt = existing.CreatedAt +}); + +// ❌ WRONG — partial update will null out other fields! +ctx.Db.MyTable.Id.Update(new MyTable { Id = id, Name = newValue }); +``` + +### Lifecycle Hooks + +**⚠️ CRITICAL: Method names must NOT start with "On" — causes STDB0010 error!** + +```csharp +// ✅ CORRECT — no "On" prefix +[SpacetimeDB.Reducer(ReducerKind.ClientConnected)] +public static void ClientConnected(ReducerContext ctx) +{ + // ctx.Sender is the connecting identity + Log.Info($"Client connected: {ctx.Sender}"); +} + +[SpacetimeDB.Reducer(ReducerKind.ClientDisconnected)] +public static void ClientDisconnected(ReducerContext ctx) +{ + // Clean up ephemeral data, set offline status, etc. + Log.Info($"Client disconnected: {ctx.Sender}"); +} +``` + +--- + +## 3) Index Access (Server-side) + +### Primary Key / Unique - `.Find()` returns single row or null + +```csharp +// Primary key lookup +var row = ctx.Db.MyTable.Id.Find(id); // Returns MyTable? +var row = ctx.Db.MyTable.Owner.Find(ctx.Sender); // Unique column + +if (row == null) +{ + throw new Exception("Not found"); +} +``` + +### BTree Index - `.Filter()` returns IEnumerable + +```csharp +// Index lookup - returns multiple rows +foreach (var row in ctx.Db.MyTable.SomeColumn.Filter(value)) +{ + // Process each matching row +} + +// Or collect to list +var rows = ctx.Db.MyTable.SomeColumn.Filter(value).ToList(); +``` + +### No Index - `.Iter()` + manual filter + +```csharp +// Full table scan - avoid for large tables +foreach (var row in ctx.Db.MyTable.Iter()) +{ + if (row.Name.StartsWith("A")) + { + // ... + } +} +``` + +--- + +## 4) Client SDK Setup + +### Project Setup + +```bash +# .NET Console/Library +dotnet add package SpacetimeDB.ClientSDK + +# Unity - use Package Manager with git URL: +# https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk.git +``` + +### Generate Bindings + +```bash +mkdir -p module_bindings +spacetime generate --lang cs --out-dir module_bindings --project-path +``` + +### Connection Setup + +```csharp +using SpacetimeDB; +using SpacetimeDB.Types; + +private DbConnection? _conn; +private Identity? _myIdentity; + +public void Connect() +{ + _conn = DbConnection.Builder() + .WithUri("http://localhost:3000") // String, NOT Uri object! + .WithModuleName("my-module") + .WithToken(savedToken) // null for first connection + .OnConnect(OnConnected) + .OnDisconnect((conn, err) => OnDisconnected()) // 2 params + .OnConnectError(err => OnConnectError(err)) // 1 param + .Build(); + + // NOTE: Do NOT subscribe here! Subscribe in OnConnected callback. +} + +public void Tick() +{ + // CRITICAL: Must call regularly! + _conn?.FrameTick(); +} + +private void OnConnected(DbConnection conn, Identity identity, string token) +{ + _myIdentity = identity; + // Save token for reconnection + + // SUBSCRIBE HERE — after connection is established! + conn.SubscriptionBuilder() + .OnApplied(OnSubscriptionApplied) + .OnError((ctx, err) => Console.WriteLine($"Subscription error: {err}")) + .SubscribeToAllTables(); +} + +private void OnSubscriptionApplied(SubscriptionEventContext ctx) +{ + // NOW safe to access ctx.Db + // Table accessor matches the Name attribute from [SpacetimeDB.Table(Name = "...")] + foreach (var row in ctx.Db.my_table.Iter()) + { + // Initial data available + } +} + +private void OnDisconnected() { } +private void OnConnectError(Exception error) { } +``` + +### ⚠️ CRITICAL: FrameTick + +**The SDK does NOT process messages automatically.** You MUST call `FrameTick()`: + +```csharp +// Call regularly in your main loop +while (running) +{ + conn.FrameTick(); + Thread.Sleep(16); // ~60 times per second +} +``` + +Without `FrameTick()`: +- No callbacks will ever fire +- `OnConnect` will never be called +- Subscription data will never arrive +- Reducer callbacks will never execute + +--- + +## 5) Row Callbacks (Client-side) + +```csharp +// Register callbacks BEFORE subscribing +_conn.Db.MyTable.OnInsert += (EventContext ctx, MyTable row) => +{ + // Row was inserted +}; + +_conn.Db.MyTable.OnUpdate += (EventContext ctx, MyTable oldRow, MyTable newRow) => +{ + // Row was updated +}; + +_conn.Db.MyTable.OnDelete += (EventContext ctx, MyTable row) => +{ + // Row was deleted +}; + +// Check if event came from our reducer call +if (ctx.Event is Event.Reducer reducerEvent) +{ + if (reducerEvent.ReducerEvent.CallerIdentity == _myIdentity) + { + // This was our call + } +} +``` + +--- + +## 6) Invoking Reducers (Client-side) + +```csharp +// Reducers are called as methods on conn.Reducers +_conn.Reducers.DoSomething("value", 123); + +// Register callback for reducer completion +_conn.Reducers.OnDoSomething += (ctx) => +{ + if (ctx.Event.Status is Status.Committed) + { + // Success + } + else if (ctx.Event.Status is Status.Failed failed) + { + // Failed: failed.Item contains error + } +}; +``` + +--- + +## 7) Timestamps + +### Server-side + +```csharp +// Use ctx.Timestamp for current time +ctx.Db.MyTable.Insert(new MyTable +{ + // ... + CreatedAt = ctx.Timestamp +}); + +// Never use DateTime.Now - it's non-deterministic! +``` + +### Client-side + +```csharp +// Timestamp has MicrosecondsSinceUnixEpoch property (NOT MicrosecondsSinceEpoch!) +var dateTime = DateTimeOffset.FromUnixTimeMilliseconds( + row.CreatedAt.MicrosecondsSinceUnixEpoch / 1000 +).LocalDateTime; +``` + +--- + +## 8) Scheduled Tables + +```csharp +// Server-side: Define scheduled table +[SpacetimeDB.Table(Scheduled = "process_job")] +public partial struct ScheduledJob +{ + [SpacetimeDB.PrimaryKey] + [SpacetimeDB.AutoInc] + public ulong ScheduledId; + + public SpacetimeDB.ScheduleAt ScheduledAt; + public ulong TargetId; // Your custom data +} + +// The scheduled reducer receives the row +[SpacetimeDB.Reducer] +public static void ProcessJob(ReducerContext ctx, ScheduledJob job) +{ + // job.TargetId available + // Row is auto-deleted after reducer completes + Log.Info($"Processing: {job.TargetId}"); +} + +// Schedule a job +[SpacetimeDB.Reducer] +public static void ScheduleJob(ReducerContext ctx, ulong targetId, ulong delayMs) +{ + var futureTime = ctx.Timestamp.MicrosecondsSinceUnixEpoch + (long)(delayMs * 1000); + ctx.Db.scheduled_job.Insert(new ScheduledJob // snake_case table name! + { + ScheduledId = 0, + ScheduledAt = new ScheduleAt.Time(new Timestamp(futureTime)), // constructor syntax! + TargetId = targetId + }); +} +``` + +--- + +## 9) Project Structure + +### Server Module + +``` +MyModule/ +├── MyModule.csproj +├── Lib.cs # Tables, types +└── Module.cs # Reducers, lifecycle hooks +``` + +**MyModule.csproj:** +```xml + + + net8.0 + wasi-wasm + enable + enable + + + + + +``` + +**global.json** (pin .NET 8.x SDK for spacetime publish - use your installed version): +```json +{ + "sdk": { + "version": "8.0.xxx", + "rollForward": "latestFeature" + } +} +``` +Run `dotnet --list-sdks` to find your installed 8.x version. + +### Client + +``` +MyClient/ +├── MyClient.csproj +├── module_bindings/ # Generated (spacetime generate) +└── Program.cs +``` + +--- + +## 10) Commands + +**C# requires building WASM before publish (unlike TypeScript/Rust):** + +```bash +# Start local server +spacetime start + +# 1. Build WASM module first (REQUIRED for C#) +cd +dotnet publish -c Release + +# 2. Publish using --bin-path +spacetime publish --bin-path /bin/Release/net8.0/wasi-wasm/AppBundle/.wasm + +# 3. Clear database and republish +spacetime publish --clear-database -y --bin-path /bin/Release/net8.0/wasi-wasm/AppBundle/.wasm + +# 4. Generate C# bindings (use --bin-path) +spacetime generate --lang csharp --out-dir /module_bindings --bin-path /bin/Release/net8.0/wasi-wasm/AppBundle/.wasm + +# View logs +spacetime logs +``` + +--- + +## 11) Hard Requirements + +> **See `spacetimedb.mdc`** for core concepts (reducers are transactional, deterministic, etc.) + +**C#-specific requirements:** + +1. **Tables MUST be `partial struct` or `partial class`** — required for code generation +2. **Reducers MUST be `static` methods** — instance methods won't work +3. **MUST call `FrameTick()` regularly** — callbacks won't fire otherwise +4. **Use `ctx.Timestamp`** — never `DateTime.Now` or `DateTime.UtcNow` in reducers +5. **Wait for `OnApplied` before accessing `Db`** — tables are empty until subscription applies +6. **Server uses lowercase table accessors** — `ctx.Db.user` matches `Name="user"` +7. **Client uses PascalCase table accessors** — `_conn.Db.User` (generated bindings) +8. **Lifecycle hook names must NOT start with "On"** — causes STDB0010 error +9. **DO NOT edit generated bindings** — regenerate with `spacetime generate` \ No newline at end of file diff --git a/docs/.cursor/rules/spacetimedb-rust.mdc b/docs/.cursor/rules/spacetimedb-rust.mdc new file mode 100644 index 00000000000..02fbaa4bc93 --- /dev/null +++ b/docs/.cursor/rules/spacetimedb-rust.mdc @@ -0,0 +1,721 @@ +--- +description: "⛔ MANDATORY: Read this ENTIRE file before writing ANY SpacetimeDB Rust code. Contains SDK patterns from official documentation." +globs: **/*.rs +alwaysApply: true +--- + +# SpacetimeDB Rust SDK + +> **Tested with:** SpacetimeDB runtime 1.11.x, `spacetimedb` crate (server), `spacetimedb-sdk` crate (client) +> **Last updated:** 2026-01-12 +> +> ⚠️ **SDK Evolution:** The SDK is evolving rapidly. If using a newer version, check release notes for breaking changes. + +--- + +## ⛔ COMMON MISTAKES — LLM HALLUCINATIONS + +These are **actual errors** observed when LLMs generate SpacetimeDB Rust code: + +### 1. Wrong Crate for Server vs Client + +```rust +// ❌ WRONG — using client crate for server module +use spacetimedb_sdk::*; // This is for CLIENTS only! + +// ✅ CORRECT — use spacetimedb for server modules +use spacetimedb::{table, reducer, Table, ReducerContext, Identity, Timestamp}; +``` + +### 2. Wrong Table Macro Syntax + +```rust +// ❌ WRONG — using attribute-style like C# +#[spacetimedb::table] +#[primary_key] +pub struct User { ... } + +// ✅ CORRECT — use #[table(...)] macro with options +#[table(name = user, public)] +pub struct User { + #[primary_key] + identity: Identity, + name: Option, +} +``` + +### 3. Wrong Table Access Pattern + +```rust +// ❌ WRONG — using ctx.Db or ctx.db() method +ctx.Db.user.Insert(...); +ctx.db().user().insert(...); + +// ✅ CORRECT — ctx.db is a field, table names are methods +ctx.db.user().insert(User { ... }); +ctx.db.user().identity().find(ctx.sender); +``` + +### 4. Wrong Update Pattern + +```rust +// ❌ WRONG — partial update or using .update() directly on table +ctx.db.user().update(User { name: Some("new".into()), ..Default::default() }); + +// ✅ CORRECT — find existing, spread it, update via primary key accessor +if let Some(user) = ctx.db.user().identity().find(ctx.sender) { + ctx.db.user().identity().update(User { name: Some("new".into()), ..user }); +} +``` + +### 5. Wrong Reducer Return Type + +```rust +// ❌ WRONG — returning data from reducer +#[reducer] +pub fn get_user(ctx: &ReducerContext, id: Identity) -> Option { ... } + +// ✅ CORRECT — reducers return Result<(), String> or nothing +#[reducer] +pub fn do_something(ctx: &ReducerContext, value: String) -> Result<(), String> { + if value.is_empty() { + return Err("Value cannot be empty".to_string()); + } + // ... do work ... + Ok(()) +} +``` + +### 6. Wrong Client Connection Pattern + +```rust +// ❌ WRONG — subscribing before connected +let conn = DbConnection::builder().build()?; +conn.subscription_builder().subscribe_to_all_tables(); // NOT CONNECTED YET! + +// ✅ CORRECT — subscribe in on_connect callback +DbConnection::builder() + .on_connect(|conn, identity, token| { + conn.subscription_builder() + .on_applied(|ctx| println!("Ready!")) + .subscribe_to_all_tables(); + }) + .build()?; +``` + +### 7. Forgetting to Advance the Connection + +```rust +// ❌ WRONG — connection never processes messages +let conn = DbConnection::builder().build()?; +// ... callbacks never fire ... + +// ✅ CORRECT — must call one of these to process messages +conn.run_threaded(); // Spawn background thread +// OR +conn.run_async().await; // Async task +// OR (in game loop) +conn.frame_tick()?; // Manual polling +``` + +### 8. Missing Table Trait Import + +```rust +// ❌ WRONG — "no method named `insert` found" +use spacetimedb::{table, reducer, ReducerContext}; +ctx.db.user().insert(...); // ERROR! + +// ✅ CORRECT — import Table trait for table methods +use spacetimedb::{table, reducer, Table, ReducerContext}; +ctx.db.user().insert(...); // Works! +``` + +### 9. Wrong ScheduleAt Variant + +```rust +// ❌ WRONG — At variant doesn't exist +scheduled_at: ScheduleAt::At(future_time), + +// ✅ CORRECT — use Time variant +scheduled_at: ScheduleAt::Time(future_time), +``` + +### 10. Identity to String Conversion + +```rust +// ❌ WRONG — to_hex() returns HexString<32>, not String +let id: String = identity.to_hex(); // Type mismatch! + +// ✅ CORRECT — chain .to_string() +let id: String = identity.to_hex().to_string(); +``` + +### 11. Timestamp Duration Extraction + +```rust +// ❌ WRONG — returns Result, not Duration directly +let micros = ctx.timestamp.to_duration_since_unix_epoch().as_micros(); + +// ✅ CORRECT — unwrap the Result +let micros = ctx.timestamp.to_duration_since_unix_epoch() + .unwrap_or_default() + .as_micros(); +``` + +### 12. Borrow After Move + +```rust +// ❌ WRONG — `tool` moved into struct, then borrowed +ctx.db.stroke().insert(Stroke { tool, color, ... }); +if tool == "eraser" { ... } // ERROR: value moved! + +// ✅ CORRECT — check before move, or use clone +let is_eraser = tool == "eraser"; +ctx.db.stroke().insert(Stroke { tool, color, ... }); +if is_eraser { ... } +``` + +### 13. Client SDK Uses Blocking I/O + +The SpacetimeDB Rust client SDK uses blocking I/O. If mixing with async runtimes (Tokio, async-std), use `spawn_blocking` or run the SDK on a dedicated thread to avoid blocking the async executor. + +--- + +## 1) Server Module — Table Definition + +**Tables use `#[table(...)]` macro on `pub struct`:** + +> ⚠️ **CRITICAL:** Always import `Table` trait — required for `.insert()`, `.iter()`, `.find()`, etc. + +```rust +use spacetimedb::{table, reducer, Table, ReducerContext, Identity, Timestamp}; + +#[table(name = user, public)] +pub struct User { + #[primary_key] + identity: Identity, + + #[unique] + username: Option, + + online: bool, +} + +#[table(name = message, public)] +pub struct Message { + #[primary_key] + #[auto_inc] + id: u64, + + sender: Identity, + text: String, + sent: Timestamp, +} +``` + +### Table Options + +```rust +#[table(name = my_table)] // Private table (default) +#[table(name = my_table, public)] // Public table - clients can subscribe +``` + +### Column Attributes + +```rust +#[primary_key] // Primary key (auto-indexed, enables .find()) +#[auto_inc] // Auto-increment (use with #[primary_key]) +#[unique] // Unique constraint (auto-indexed) +#[index(btree)] // B-Tree index for queries +``` + +### Scheduled Tables + +```rust +use spacetimedb::{table, reducer, ReducerContext, ScheduleAt, Timestamp}; + +#[table(name = cleanup_job, scheduled(cleanup_expired))] +pub struct CleanupJob { + #[primary_key] + #[auto_inc] + scheduled_id: u64, + + scheduled_at: ScheduleAt, + target_id: u64, +} + +#[reducer] +pub fn cleanup_expired(ctx: &ReducerContext, job: CleanupJob) { + // Job row is auto-deleted after reducer completes + log::info!("Cleaning up: {}", job.target_id); +} + +// Schedule a job +#[reducer] +pub fn schedule_cleanup(ctx: &ReducerContext, target_id: u64, delay_ms: u64) { + let future_time = ctx.timestamp + std::time::Duration::from_millis(delay_ms); + ctx.db.cleanup_job().insert(CleanupJob { + scheduled_id: 0, // auto-inc placeholder + scheduled_at: ScheduleAt::Time(future_time), + target_id, + }); +} +``` + +--- + +## 2) Server Module — Reducers + +### Definition Syntax + +```rust +use spacetimedb::{reducer, ReducerContext}; + +#[reducer] +pub fn send_message(ctx: &ReducerContext, text: String) -> Result<(), String> { + // Validate input + if text.is_empty() { + return Err("Message cannot be empty".to_string()); + } + + // Insert returns the inserted row + let row = ctx.db.message().insert(Message { + id: 0, // auto-inc placeholder + sender: ctx.sender, + text, + sent: ctx.timestamp, + }); + + log::info!("Message {} sent by {:?}", row.id, ctx.sender); + Ok(()) +} +``` + +### Update Pattern (CRITICAL) + +```rust +#[reducer] +pub fn set_name(ctx: &ReducerContext, name: String) -> Result<(), String> { + // Find existing row + let user = ctx.db.user().identity().find(ctx.sender) + .ok_or("User not found")?; + + // ✅ CORRECT — spread existing row, override specific fields + ctx.db.user().identity().update(User { + name: Some(name), + ..user // Preserves identity, online, etc. + }); + + Ok(()) +} + +// ❌ WRONG — partial update nulls out other fields! +// ctx.db.user().identity().update(User { identity: ctx.sender, name: Some(name), ..Default::default() }); +``` + +### Delete Pattern + +```rust +#[reducer] +pub fn delete_message(ctx: &ReducerContext, message_id: u64) -> Result<(), String> { + // Delete by primary key value + ctx.db.message().id().delete(message_id); + Ok(()) +} +``` + +### Lifecycle Hooks + +```rust +#[reducer(client_connected)] +pub fn client_connected(ctx: &ReducerContext) { + // ctx.sender is the connecting identity + if let Some(user) = ctx.db.user().identity().find(ctx.sender) { + // Returning user - set online + ctx.db.user().identity().update(User { online: true, ..user }); + } else { + // New user - create record + ctx.db.user().insert(User { + identity: ctx.sender, + username: None, + online: true, + }); + } +} + +#[reducer(client_disconnected)] +pub fn client_disconnected(ctx: &ReducerContext) { + if let Some(user) = ctx.db.user().identity().find(ctx.sender) { + ctx.db.user().identity().update(User { online: false, ..user }); + } +} +``` + +--- + +## 3) Server Module — Index Access + +### Primary Key / Unique — `.find()` returns `Option` + +```rust +// Primary key lookup +let user = ctx.db.user().identity().find(ctx.sender); + +// Unique column lookup +let user = ctx.db.user().username().find(&"alice".to_string()); + +if let Some(user) = user { + // Found +} +``` + +### BTree Index — `.filter()` returns iterator + +```rust +#[table(name = message, public)] +pub struct Message { + #[primary_key] + #[auto_inc] + id: u64, + + #[index(btree)] + room_id: u64, + + text: String, +} + +// Filter by indexed column +for msg in ctx.db.message().room_id().filter(&room_id) { + // Process each message in room +} +``` + +### No Index — `.iter()` + manual filter + +```rust +// Full table scan +for user in ctx.db.user().iter() { + if user.online { + // Process online users + } +} +``` + +--- + +## 4) Client SDK — Project Setup + +### Cargo.toml + +```toml +[dependencies] +spacetimedb-sdk = "1.0" +``` + +### Generate Module Bindings + +```bash +mkdir -p src/module_bindings +spacetime generate --lang rust --out-dir src/module_bindings --project-path +``` + +### Declare Module in main.rs + +```rust +mod module_bindings; +use module_bindings::*; +use spacetimedb_sdk::{DbContext, Error, Event, Identity, Status, Table, TableWithPrimaryKey}; +``` + +--- + +## 5) Client SDK — Connection Setup + +### Basic Connection + +```rust +use module_bindings::DbConnection; + +fn connect() -> DbConnection { + DbConnection::builder() + .with_uri("http://localhost:3000") + .with_module_name("my-module") + .with_token(load_saved_token()) // None for first connection + .on_connect(on_connected) + .on_connect_error(on_connect_error) + .on_disconnect(on_disconnected) + .build() + .expect("Failed to connect") +} + +fn on_connected(conn: &DbConnection, identity: Identity, token: &str) { + // Save token for reconnection + save_token(token); + + // Subscribe to tables HERE - after connection established! + conn.subscription_builder() + .on_applied(|ctx| println!("Subscriptions applied!")) + .on_error(|ctx, err| eprintln!("Subscription error: {}", err)) + .subscribe(["SELECT * FROM user", "SELECT * FROM message"]); +} + +fn on_connect_error(_ctx: &ErrorContext, err: Error) { + eprintln!("Connection error: {:?}", err); +} + +fn on_disconnected(_ctx: &ErrorContext, err: Option) { + if let Some(err) = err { + eprintln!("Disconnected with error: {}", err); + } +} +``` + +### ⚠️ CRITICAL: Advance the Connection + +**The SDK does NOT process messages automatically.** You MUST use one of: + +```rust +// Option 1: Background thread (simplest for CLI apps) +conn.run_threaded(); + +// Option 2: Async (for async runtimes) +conn.run_async().await; + +// Option 3: Manual polling (for game loops) +loop { + conn.frame_tick()?; + std::thread::sleep(std::time::Duration::from_millis(16)); +} +``` + +Without advancing the connection: +- No callbacks will fire +- `on_connect` will never be called +- Subscription data will never arrive + +--- + +## 6) Client SDK — Subscriptions + +```rust +// Subscribe to specific queries +conn.subscription_builder() + .on_applied(|ctx| { + // Initial data now available in ctx.db + for user in ctx.db.user().iter() { + println!("User: {:?}", user.username); + } + }) + .on_error(|ctx, err| eprintln!("Error: {}", err)) + .subscribe(["SELECT * FROM user", "SELECT * FROM message"]); + +// Or subscribe to ALL public tables (simple but less efficient) +conn.subscription_builder() + .on_applied(|ctx| println!("Ready!")) + .subscribe_to_all_tables(); +``` + +--- + +## 7) Client SDK — Table Access + +### Iterate Over Rows + +```rust +// From DbConnection or any context +for user in ctx.db.user().iter() { + println!("{}: online={}", user.username.unwrap_or_default(), user.online); +} + +// Count rows +let count = ctx.db.message().count(); +``` + +### Find by Primary Key / Unique + +```rust +// Primary key lookup +if let Some(user) = ctx.db.user().identity().find(&sender_identity) { + println!("Found: {:?}", user.username); +} + +// Unique column lookup +if let Some(user) = ctx.db.user().username().find(&"alice".to_string()) { + println!("Found alice"); +} +``` + +### Row Callbacks + +```rust +fn register_callbacks(ctx: &DbConnection) { + // On insert + ctx.db.user().on_insert(|ctx, user| { + println!("User joined: {:?}", user.username); + }); + + // On delete + ctx.db.user().on_delete(|ctx, user| { + println!("User left: {:?}", user.username); + }); + + // On update (only for tables with primary key) + ctx.db.user().on_update(|ctx, old, new| { + if old.online != new.online { + println!("User {} is now {}", + new.username.as_deref().unwrap_or("unknown"), + if new.online { "online" } else { "offline" } + ); + } + }); +} +``` + +--- + +## 8) Client SDK — Invoking Reducers + +### Call Reducers + +```rust +// Reducers are methods on ctx.reducers +ctx.reducers.set_name("Alice".to_string()).unwrap(); +ctx.reducers.send_message("Hello, world!".to_string()).unwrap(); +``` + +### Reducer Callbacks + +```rust +// Register callback for reducer completion +ctx.reducers.on_set_name(|ctx, name| { + match &ctx.event.status { + Status::Committed => println!("Name set to: {}", name), + Status::Failed(err) => eprintln!("Failed to set name: {}", err), + Status::OutOfEnergy => eprintln!("Out of energy!"), + } +}); + +ctx.reducers.on_send_message(|ctx, text| { + if let Status::Failed(err) = &ctx.event.status { + eprintln!("Failed to send '{}': {}", text, err); + } +}); +``` + +--- + +## 9) Client SDK — Event Context + +Row callbacks receive an `EventContext` with an `event` field: + +```rust +ctx.db.message().on_insert(|ctx, message| { + match &ctx.event { + Event::Reducer(reducer_event) => { + // Inserted by a reducer + println!("New message from reducer"); + } + Event::SubscribeApplied => { + // Initial data from subscription + println!("Historical message loaded"); + } + _ => {} + } +}); +``` + +### Event Variants + +```rust +Event::Reducer(ReducerEvent) // A reducer ran +Event::SubscribeApplied // Subscription initialized +Event::UnsubscribeApplied // Subscription removed +Event::SubscribeError(Error) // Subscription failed +Event::UnknownTransaction // Unknown transaction +``` + +--- + +## 10) Project Structure + +### Server Module + +``` +my-module/ +├── Cargo.toml +└── src/ + └── lib.rs +``` + +**Cargo.toml:** +```toml +[package] +name = "my-module" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +spacetimedb = "1.0" +log = "0.4" +``` + +### Client + +``` +client/ +├── Cargo.toml +└── src/ + ├── main.rs + └── module_bindings/ # Generated by spacetime generate + └── ... +``` + +--- + +## 11) Commands + +```bash +# Start local server +spacetime start + +# Build module (optional - publish auto-builds) +spacetime build --project-path + +# Publish module +spacetime publish --project-path + +# Clear database and republish +spacetime publish --clear-database -y --project-path + +# Generate Rust client bindings +spacetime generate --lang rust --out-dir /src/module_bindings --project-path + +# View logs +spacetime logs + +# Call reducer from CLI +spacetime call '' +``` + +--- + +## 12) Hard Requirements + +> **See `spacetimedb.mdc`** for core concepts (reducers are transactional, deterministic, etc.) + +**Rust-specific requirements:** + +1. **Server modules use `spacetimedb` crate** — clients use `spacetimedb-sdk` +2. **Tables MUST use `#[table(...)]` macro** — not attribute-style macros +3. **Reducers take `&ReducerContext` as first argument** — must be a reference +4. **Use `ctx.timestamp`** — never `std::time::SystemTime::now()` in reducers +5. **Client MUST advance connection** — call `run_threaded()`, `run_async()`, or `frame_tick()` +6. **Subscribe in `on_connect` callback** — not before connection is established +7. **Update requires full row** — spread existing row with `..existing` +8. **DO NOT edit generated bindings** — regenerate with `spacetime generate` +9. **Import `Table` trait** — `use spacetimedb::Table;` required for `.insert()`, `.iter()`, etc. +10. **Identity to String needs `.to_string()`** — `identity.to_hex().to_string()` +11. **Client SDK is blocking** — use `spawn_blocking` or dedicated thread if mixing with async runtimes diff --git a/docs/.cursor/rules/spacetimedb-styling.mdc b/docs/.cursor/rules/spacetimedb-styling.mdc new file mode 100644 index 00000000000..c288b8cf172 --- /dev/null +++ b/docs/.cursor/rules/spacetimedb-styling.mdc @@ -0,0 +1,179 @@ +--- +description: "Official SpacetimeDB/ClockworkLabs brand colors and styling" +globs: "**/*.xaml, **/*.cs, **/*.css, **/*.tsx, **/*.jsx, **/*.scss, **/*.rs" +alwaysApply: false +--- + +# SpacetimeDB Brand Styling + +When building UI for SpacetimeDB applications, use the **official ClockworkLabs brand colors** from spacetimedb.com. + +## Primary Brand Color + +The official SpacetimeDB brand uses **green (#4cf490)** as the primary accent — not purple/cyan. + +## Official Color Palette + +### Primary Accent — STDB Green +``` +#4cf490 — Primary green (main accent) +#2ef27d — Green dark +#1ff174 — Green darker +#0dd35d — Green darkest +#6af6a3 — Green light +#79f7ac — Green lighter +#a6fac8 — Green lightest + +Opacity variants: +#4cf490bf — 75% +#4cf49080 — 50% +#4cf49040 — 25% +#4cf49033 — 20% +#4cf4901a — 10% +``` + +### Secondary Colors +``` +#a880ff — Purple +#02befa — Blue +#fbdc8e — Yellow (used for code highlighting) +#ff80fb — Pink +#00ccb4 — Teal +#ff9e9e — Orange +#ff4c4c — Red (errors) +#fc6897 — Red 2 +``` + +### Backgrounds (Dark Theme) +``` +#060606 — Darkest background (n8) +#050505 — Near-black (n7) +#0d0d0e — Shade 2 (code backgrounds) +#141416 — Shade 1 +#202126 — Border color (n6) +#363840 — Surface/hover (n5) +``` + +### Text Colors +``` +#f4f6fc — White (headings, primary text) +#e6e9f0 — N1 (bright text) +#ced3e0 — N2 (strong text) +#b6c0cf — N3 (body text) +#6f7987 — N4 (muted/secondary text) +``` + +## Usage Examples + +### MAUI/XAML +```xml + + #4cf490 + #a880ff + #060606 + #f4f6fc + #b6c0cf + #202126 + +``` + +### C# (Unity, WinForms, code-behind) +```csharp +using System.Drawing; // WinForms +// or: using UnityEngine; // Unity + +public static class StdbColors +{ + // Primary + public static readonly Color Green = Color.FromArgb(0x4c, 0xf4, 0x90); + public static readonly Color Purple = Color.FromArgb(0xa8, 0x80, 0xff); + public static readonly Color Blue = Color.FromArgb(0x02, 0xbe, 0xfa); + + // Backgrounds + public static readonly Color BgDarkest = Color.FromArgb(0x06, 0x06, 0x06); + public static readonly Color BgSurface = Color.FromArgb(0x14, 0x14, 0x16); + public static readonly Color Border = Color.FromArgb(0x20, 0x21, 0x26); + + // Text + public static readonly Color TextPrimary = Color.FromArgb(0xf4, 0xf6, 0xfc); + public static readonly Color TextBody = Color.FromArgb(0xb6, 0xc0, 0xcf); + public static readonly Color TextMuted = Color.FromArgb(0x6f, 0x79, 0x87); + + // Status + public static readonly Color Error = Color.FromArgb(0xff, 0x4c, 0x4c); +} +``` + +### CSS/Tailwind +```css +:root { + --stdb-green: #4cf490; + --stdb-purple: #a880ff; + --stdb-blue: #02befa; + --stdb-bg: #060606; + --stdb-text: #f4f6fc; + --stdb-text-body: #b6c0cf; + --stdb-border: #202126; +} +``` + +### React/TypeScript +```typescript +const stdbColors = { + green: '#4cf490', + purple: '#a880ff', + blue: '#02befa', + background: '#060606', + text: '#f4f6fc', + textBody: '#b6c0cf', + border: '#202126', +} as const; +``` + +### Rust/egui +```rust +use eframe::egui::Color32; + +// Primary +const STDB_GREEN: Color32 = Color32::from_rgb(0x4c, 0xf4, 0x90); +const STDB_PURPLE: Color32 = Color32::from_rgb(0xa8, 0x80, 0xff); +const STDB_BLUE: Color32 = Color32::from_rgb(0x02, 0xbe, 0xfa); + +// Backgrounds +const BG_DARKEST: Color32 = Color32::from_rgb(0x06, 0x06, 0x06); +const BG_SURFACE: Color32 = Color32::from_rgb(0x14, 0x14, 0x16); +const BG_HOVER: Color32 = Color32::from_rgb(0x36, 0x38, 0x40); +const BORDER: Color32 = Color32::from_rgb(0x20, 0x21, 0x26); + +// Text +const TEXT_PRIMARY: Color32 = Color32::from_rgb(0xf4, 0xf6, 0xfc); +const TEXT_BODY: Color32 = Color32::from_rgb(0xb6, 0xc0, 0xcf); +const TEXT_MUTED: Color32 = Color32::from_rgb(0x6f, 0x79, 0x87); + +// Status +const ERROR_RED: Color32 = Color32::from_rgb(0xff, 0x4c, 0x4c); +``` + +## Design Guidelines + +### Colors +1. **Primary actions** use STDB Green (#4cf490) +2. **Dark backgrounds** — use near-black (#060606) not pure black +3. **Body text** — use #b6c0cf, NOT pure white +4. **Headings** — use #f4f6fc (off-white) +5. **Borders** — subtle, use #202126 +6. **Code blocks** — yellow text (#fbdc8e) on dark background (#0d0d0e) +7. **Success states** — use STDB Green +8. **Error states** — use #ff4c4c + +### UI Patterns +1. **Visual hierarchy** — clear active states, hover effects, focus indicators +2. **Responsive layout** — works on desktop (mobile optional) +3. **Loading states** — show spinner/skeleton while data loads +4. **Empty states** — helpful message when no data exists +5. **Feedback** — visual feedback for user actions (button states, success/error indicators) +6. **Glow effects** — subtle glow on interactive elements (buttons, inputs, hover) + +## Source + +These colors are from the official SpacetimeDB documentation site (spacetimedb.com). diff --git a/docs/.cursor/rules/spacetimedb-typescript.mdc b/docs/.cursor/rules/spacetimedb-typescript.mdc new file mode 100644 index 00000000000..a0224aae7a6 --- /dev/null +++ b/docs/.cursor/rules/spacetimedb-typescript.mdc @@ -0,0 +1,594 @@ +--- +description: "⛔ MANDATORY: Read this ENTIRE file before writing ANY SpacetimeDB TypeScript code. Contains critical SDK patterns and HALLUCINATED APIs to avoid." +globs: **/*.ts,**/*.tsx,**/*.js,**/*.jsx +alwaysApply: true +--- + +# SpacetimeDB TypeScript SDK + +> **Tested with:** SpacetimeDB runtime 1.11.x, npm `spacetimedb` 1.11.x +> **Last updated:** 2026-01-07 +> +> ⚠️ **SDK Evolution:** The SDK is evolving rapidly. If using a newer version, check release notes for breaking changes. + +--- + +## ⛔ HALLUCINATED APIs — DO NOT USE + +**These APIs DO NOT EXIST. LLMs frequently hallucinate them.** + +```typescript +// ❌ WRONG PACKAGE — does not exist +import { SpacetimeDBClient } from "@clockworklabs/spacetimedb-sdk"; + +// ❌ WRONG — these methods don't exist +SpacetimeDBClient.connect(...); +SpacetimeDBClient.call("reducer_name", [...]); +connection.call("reducer_name", [arg1, arg2]); + +// ❌ WRONG — positional reducer arguments +conn.reducers.doSomething("value"); // WRONG! + +// ❌ WRONG — static methods on generated types don't exist +User.filterByName('alice'); +Message.findById(123n); +tables.user.filter(u => u.name === 'alice'); // No .filter() on tables object! +``` + +### ✅ CORRECT PATTERNS: + +```typescript +// ✅ CORRECT IMPORTS +import { DbConnection, tables } from './module_bindings'; // Generated! +import { SpacetimeDBProvider, useTable, Identity } from 'spacetimedb/react'; + +// ✅ CORRECT REDUCER CALLS — object syntax, not positional! +conn.reducers.doSomething({ value: 'test' }); +conn.reducers.updateItem({ itemId: 1n, newValue: 42 }); + +// ✅ CORRECT DATA ACCESS — useTable returns [rows, isLoading] +const [items, isLoading] = useTable(tables.item); +``` + +### ⛔ DO NOT: +- **Invent hooks** like `useItems()`, `useData()` — use `useTable(tables.tableName)` +- **Import from fake packages** — only `spacetimedb`, `spacetimedb/react`, `./module_bindings` + +--- + +## 1) Common Mistakes Table + +### Server-side errors + +| Wrong | Right | Error | +|-------|-------|-------| +| Missing `package.json` | Create `package.json` | "could not detect language" | +| Missing `tsconfig.json` | Create `tsconfig.json` | "TsconfigNotFound" | +| Entrypoint not at `src/index.ts` | Use `src/index.ts` | Module won't bundle | +| `indexes` in COLUMNS (2nd arg) | `indexes` in OPTIONS (1st arg) | "reading 'tag'" error | +| Index without `algorithm` | `algorithm: 'btree'` | "reading 'tag'" error | +| `filter({ ownerId })` | `filter(ownerId)` | "does not exist in type 'Range'" | +| `.filter()` on unique column | `.find()` on unique column | TypeError | +| `insert({ ...without id })` | `insert({ id: 0n, ... })` | "Property 'id' is missing" | +| `const id = table.insert(...)` | `const row = table.insert(...)` | `.insert()` returns ROW, not ID | +| `.unique()` + explicit index | Just use `.unique()` | "name is used for multiple entities" | +| Index on `.primaryKey()` column | Don't — already indexed | "name is used for multiple entities" | +| Same index name in multiple tables | Prefix with table name | "name is used for multiple entities" | +| `.indexName.filter()` after removing index | Use `.iter()` + manual filter | "Cannot read properties of undefined" | +| Import spacetimedb from index.ts | Import from schema.ts | "Cannot access before initialization" | +| Multi-column index `.filter()` | **⚠️ BROKEN** — use single-column | PANIC or silent empty results | +| `JSON.stringify({ id: row.id })` | Convert BigInt first: `{ id: row.id.toString() }` | "Do not know how to serialize a BigInt" | +| `ScheduleAt.Time(timestamp)` | `ScheduleAt.time(timestamp)` (lowercase) | "ScheduleAt.Time is not a function" | +| `ctx.db.foo.myIndexName.filter()` | Use exact name: `ctx.db.foo.my_index_name.filter()` | "Cannot read properties of undefined" | + +### Client-side errors + +| Wrong | Right | Error | +|-------|-------|-------| +| `@spacetimedb/sdk` | `spacetimedb` | 404 / missing subpath | +| `conn.reducers.foo("val")` | `conn.reducers.foo({ param: "val" })` | Wrong reducer syntax | +| Inline `connectionBuilder` | `useMemo(() => ..., [])` | Reconnects every render | +| `const rows = useTable(table)` | `const [rows, isLoading] = useTable(table)` | Tuple destructuring | +| Optimistic UI updates | Let subscriptions drive state | Desync issues | +| `` | `connectionBuilder={...}` | Wrong prop name | + +--- + +## 2) Table Definition (CRITICAL) + +**`table()` takes TWO arguments: `table(OPTIONS, COLUMNS)`** + +```typescript +import { schema, table, t } from 'spacetimedb/server'; + +// ❌ WRONG — indexes in COLUMNS causes "reading 'tag'" error +export const Task = table({ name: 'task' }, { + id: t.u64().primaryKey().autoInc(), + ownerId: t.identity(), + indexes: [{ name: 'by_owner', algorithm: 'btree', columns: ['ownerId'] }] // ❌ WRONG! +}); + +// ✅ RIGHT — indexes in OPTIONS (first argument) +export const Task = table({ + name: 'task', + public: true, + indexes: [{ name: 'by_owner', algorithm: 'btree', columns: ['ownerId'] }] +}, { + id: t.u64().primaryKey().autoInc(), + ownerId: t.identity(), + title: t.string(), + createdAt: t.timestamp(), +}); +``` + +### Column types +```typescript +t.identity() // User identity (primary key for per-user tables) +t.u64() // Unsigned 64-bit integer (use for IDs) +t.string() // Text +t.bool() // Boolean +t.timestamp() // Timestamp (use ctx.timestamp for current time) +t.scheduleAt() // For scheduled tables only + +// Modifiers +t.string().optional() // Nullable +t.u64().primaryKey() // Primary key +t.u64().primaryKey().autoInc() // Auto-increment primary key +``` + +> ⚠️ **BIGINT SYNTAX:** All `u64`, `i64`, and ID fields use JavaScript BigInt. +> - Literals: `0n`, `1n`, `100n` (NOT `0`, `1`, `100`) +> - Comparisons: `row.id === 5n` (NOT `row.id === 5`) +> - Arithmetic: `row.count + 1n` (NOT `row.count + 1`) + +### Auto-increment placeholder +```typescript +// ✅ MUST provide 0n placeholder for auto-inc fields +ctx.db.task.insert({ id: 0n, ownerId: ctx.sender, title: 'New', createdAt: ctx.timestamp }); +``` + +### Insert returns ROW, not ID +```typescript +// ❌ WRONG +const id = ctx.db.task.insert({ ... }); + +// ✅ RIGHT +const row = ctx.db.task.insert({ ... }); +const newId = row.id; // Extract .id from returned row +``` + +### Schema export +```typescript +// At end of schema.ts +export const spacetimedb = schema(Table1, Table2, Table3); +``` + +--- + +## 3) Index Access + +> **See `spacetimedb.mdc`** for index principles (auto-indexing, naming, schema-code coupling). + +### TypeScript Query Patterns + +```typescript +// 1. PRIMARY KEY — use .pkColumn.find() +const user = ctx.db.user.identity.find(ctx.sender); +const msg = ctx.db.message.id.find(messageId); + +// 2. EXPLICIT INDEX — use .indexName.filter(value) +const msgs = [...ctx.db.message.message_room_id.filter(roomId)]; + +// 3. NO INDEX — use .iter() + manual filter +for (const m of ctx.db.roomMember.iter()) { + if (m.roomId === roomId) { /* ... */ } +} +``` + +### Index Definition Syntax + +```typescript +// In table OPTIONS (first argument), not columns +export const Message = table({ + name: 'message', + public: true, + indexes: [{ name: 'message_room_id', algorithm: 'btree', columns: ['roomId'] }] +}, { + id: t.u64().primaryKey().autoInc(), + roomId: t.u64(), + // ... +}); +``` + +### Naming conventions + +**Table names — automatic transformation:** +- Schema: `table({ name: 'my_messages' })` +- Access: `ctx.db.myMessages` (automatic snake_case → camelCase) + +**Index names — NO transformation, use EXACTLY as defined:** +```typescript +// Schema definition +indexes: [{ name: 'canvas_member_canvas_id', algorithm: 'btree', columns: ['canvasId'] }] + +// ❌ WRONG — don't assume camelCase transformation +ctx.db.canvasMember.canvasMember_canvas_id.filter(...) // WRONG! +ctx.db.canvasMember.canvasMemberCanvasId.filter(...) // WRONG! + +// ✅ RIGHT — use exact name from schema +ctx.db.canvasMember.canvas_member_canvas_id.filter(...) +``` + +> ⚠️ **Index names are used VERBATIM** — pick a convention (snake_case or camelCase) and stick with it. + +**Index naming pattern — use `{tableName}_{columnName}`:** +```typescript +// ✅ GOOD — unique names across entire module +indexes: [{ name: 'message_room_id', algorithm: 'btree', columns: ['roomId'] }] +indexes: [{ name: 'reaction_message_id', algorithm: 'btree', columns: ['messageId'] }] + +// ❌ BAD — will collide if multiple tables use same index name +indexes: [{ name: 'by_owner', ... }] // in Task table +indexes: [{ name: 'by_owner', ... }] // in Note table — CONFLICT! +``` + +**Client-side table names:** +- Check generated `module_bindings/index.ts` for exact export names +- Usage: `useTable(tables.MyMessages)` or `tables.myMessages` (varies by SDK version) + +### Filter vs Find +```typescript +// Filter takes VALUE directly, not object — returns iterator +const rows = [...ctx.db.task.by_owner.filter(ownerId)]; + +// Unique columns use .find() — returns single row or undefined +const row = ctx.db.player.identity.find(ctx.sender); +``` + +### ⚠️ Multi-column indexes are BROKEN +```typescript +// ❌ DON'T — causes PANIC +ctx.db.scores.by_player_level.filter(playerId); + +// ✅ DO — use single-column index + manual filter +for (const row of ctx.db.scores.by_player.filter(playerId)) { + if (row.level === targetLevel) { /* ... */ } +} +``` + +--- + +## 4) Reducers + +### Definition syntax +```typescript +import { spacetimedb } from './schema'; +import { t, SenderError } from 'spacetimedb/server'; + +spacetimedb.reducer('reducer_name', { param1: t.string(), param2: t.u64() }, (ctx, { param1, param2 }) => { + // Validation + if (!param1) throw new SenderError('param1 required'); + + // Access tables via ctx.db + const row = ctx.db.myTable.primaryKey.find(param2); + + // Mutations + ctx.db.myTable.insert({ ... }); + ctx.db.myTable.primaryKey.update({ ...row, newField: value }); + ctx.db.myTable.primaryKey.delete(param2); +}); +``` + +### Update pattern (CRITICAL) +```typescript +// ✅ CORRECT — spread existing row, override specific fields +const existing = ctx.db.task.id.find(taskId); +if (!existing) throw new SenderError('Task not found'); +ctx.db.task.id.update({ ...existing, title: newTitle, updatedAt: ctx.timestamp }); + +// ❌ WRONG — partial update nulls out other fields! +ctx.db.task.id.update({ id: taskId, title: newTitle }); +``` + +### Delete pattern +```typescript +// Delete by primary key VALUE (not row object) +ctx.db.task.id.delete(taskId); // taskId is the u64 value +ctx.db.player.identity.delete(ctx.sender); // delete by identity +``` + +### Lifecycle hooks +```typescript +spacetimedb.clientConnected((ctx) => { + // ctx.sender is the connecting identity + // Create/update user record, set online status, etc. +}); + +spacetimedb.clientDisconnected((ctx) => { + // Clean up: set offline status, remove ephemeral data, etc. +}); +``` + +### Snake_case to camelCase conversion +- Server: `spacetimedb.reducer('do_something', ...)` +- Client: `conn.reducers.doSomething({ ... })` + +### Object syntax required +```typescript +// ❌ WRONG - positional +conn.reducers.doSomething('value'); + +// ✅ RIGHT - object +conn.reducers.doSomething({ param: 'value' }); +``` + +--- + +## 5) Scheduled Tables + +```typescript +// Scheduled table MUST use scheduledId and scheduledAt columns +export const CleanupJob = table({ + name: 'cleanup_job', + scheduled: 'run_cleanup' // reducer name +}, { + scheduledId: t.u64().primaryKey().autoInc(), + scheduledAt: t.scheduleAt(), + targetId: t.u64(), // Your custom data +}); + +// Scheduled reducer receives full row as arg +spacetimedb.reducer('run_cleanup', { arg: CleanupJob.rowType }, (ctx, { arg }) => { + // arg.scheduledId, arg.targetId available + // Row is auto-deleted after reducer completes +}); + +// Schedule a job +import { ScheduleAt } from 'spacetimedb'; +const futureTime = ctx.timestamp.microsSinceUnixEpoch + 60_000_000n; // 60 seconds +ctx.db.cleanupJob.insert({ + scheduledId: 0n, + scheduledAt: ScheduleAt.time(futureTime), + targetId: someId +}); + +// Cancel a job by deleting the row +ctx.db.cleanupJob.scheduledId.delete(jobId); +``` + +--- + +## 6) Timestamps + +### Server-side +```typescript +import { Timestamp, ScheduleAt } from 'spacetimedb'; + +// Current time +ctx.db.item.insert({ id: 0n, createdAt: ctx.timestamp }); + +// Future time (add microseconds) +const future = ctx.timestamp.microsSinceUnixEpoch + 300_000_000n; // 5 minutes +``` + +### Client-side (CRITICAL) +**Timestamps are objects, not numbers:** +```typescript +// ❌ WRONG +const date = new Date(row.createdAt); +const date = new Date(Number(row.createdAt / 1000n)); + +// ✅ RIGHT +const date = new Date(Number(row.createdAt.microsSinceUnixEpoch / 1000n)); +``` + +### ScheduleAt on client +```typescript +// ScheduleAt is a tagged union +if (scheduleAt.tag === 'Time') { + const date = new Date(Number(scheduleAt.value.microsSinceUnixEpoch / 1000n)); +} +``` + +--- + +## 7) Data Visibility & Subscriptions + +**`public: true` exposes ALL rows to ALL clients.** + +| Scenario | Pattern | +|----------|---------| +| Everyone sees all rows | `public: true` | +| Users see only their data | Private table + filtered subscription | + +### Subscription patterns (client-side) +```typescript +// Subscribe to ALL public tables (simplest) +conn.subscriptionBuilder().subscribeToAll(); + +// Subscribe to specific tables with SQL +conn.subscriptionBuilder().subscribe([ + 'SELECT * FROM message', + 'SELECT * FROM room WHERE is_public = true', +]); + +// Handle subscription lifecycle +conn.subscriptionBuilder() + .onApplied(() => console.log('Initial data loaded')) + .onError((e) => console.error('Subscription failed:', e)) + .subscribeToAll(); +``` + +### Private table + view pattern (RECOMMENDED) + +**Views are the recommended approach** for controlling data visibility. They provide: +- Server-side filtering (reduces network traffic) +- Real-time updates when underlying data changes +- Full control over what data clients can access + +> ⚠️ **Do NOT use Row Level Security (RLS)** — it is deprecated. + +```typescript +// Private table (no public: true) +export const PrivateData = table( + { name: 'private_data' }, + { id: t.u64().primaryKey().autoInc(), ownerId: t.identity(), secret: t.string() } +); + +// Public view filtered by sender — use spacetimedb.view() for identity-aware views +spacetimedb.view( + { name: 'my_data', public: true }, + t.array(t.row('MyDataRow', { id: t.u64(), secret: t.string() })), + (ctx) => [...ctx.db.privateData.iter()] + .filter(row => row.ownerId.toHexString() === ctx.sender.toHexString()) + .map(row => ({ id: row.id, secret: row.secret })) +); + +// Use spacetimedb.anonymousView() for views that don't depend on caller identity +spacetimedb.anonymousView( + { name: 'public_stats', public: true }, + t.array(t.row('StatsRow', { count: t.u64() })), + (ctx) => [{ count: BigInt([...ctx.db.privateData.iter()].length) }] +); +``` + +**Views require explicit subscription:** +```typescript +conn.subscriptionBuilder().subscribe([ + 'SELECT * FROM public_table', + 'SELECT * FROM my_data', // Views need explicit SQL! +]); +``` + +--- + +## 8) React Integration + +### Connection setup +```typescript +// Store connection and identity globally +declare global { + interface Window { + __db_conn: DbConnection | null; + __my_identity: Identity | null; + } +} + +// In onConnect callback +window.__db_conn = conn; +window.__my_identity = identity; +``` + +### Memoize connectionBuilder +```typescript +const builder = useMemo(() => + DbConnection.builder() + .withUri(SPACETIMEDB_URI) + .withModuleName(MODULE_NAME) + .withToken(localStorage.getItem('auth_token') || undefined) + .onConnect(onConnect) + .onConnectError(onConnectError), + [] // Empty deps - only create once +); +``` + +### Connection event handlers +```typescript +DbConnection.builder() + .withUri(SPACETIMEDB_URI) + .withModuleName(MODULE_NAME) + .onConnect((conn, identity, token) => { + // Persist token for reconnection + localStorage.setItem('auth_token', token); + window.__db_conn = conn; + window.__my_identity = identity; + }) + .onDisconnect(() => { + console.log('Disconnected - SDK will auto-reconnect'); + }) + .onConnectError((ctx, err) => { + console.error('Connection failed:', err.message); + }) +``` + +### Stale token handling +```typescript +const onConnectError = (_ctx: ErrorContext, err: Error) => { + if (err.message?.includes('Unauthorized') || err.message?.includes('401')) { + localStorage.removeItem('auth_token'); + window.location.reload(); + } +}; +``` + +### useTable returns tuple +```typescript +const [rows, isLoading] = useTable(tables.myTable); +``` + +### Identity comparison +```typescript +// Compare identities using toHexString() +const isOwner = row.ownerId.toHexString() === myIdentity.toHexString(); +``` + +--- + +## 9) Project Structure + +### Server (`backend/spacetimedb/`) +``` +src/schema.ts → Tables, export spacetimedb +src/index.ts → Reducers, lifecycle, import schema +package.json → { "type": "module", "dependencies": { "spacetimedb": "^1.11.0" } } +tsconfig.json → Standard config +``` + +### Avoiding circular imports +``` +schema.ts → defines tables AND exports spacetimedb +index.ts → imports spacetimedb from ./schema, defines reducers +``` + +### Client (`client/`) +``` +src/module_bindings/ → Generated (spacetime generate) +src/main.tsx → Provider, connection setup +src/App.tsx → UI components +src/config.ts → MODULE_NAME, SPACETIMEDB_URI +``` + +--- + +## 10) Commands + +```bash +# Start local server +spacetime start + +# Publish module +spacetime publish --project-path + +# Clear database and republish +spacetime publish --clear-database -y --project-path + +# Generate TypeScript bindings +spacetime generate --lang typescript --out-dir /src/module_bindings --project-path + +# View logs +spacetime logs +``` + +--- + +## 11) Hard Requirements + +> **See `spacetimedb.mdc`** for core concepts (reducers are transactional, deterministic, etc.) + +**TypeScript-specific requirements:** + +1. **Reducer calls use object syntax** — `{ param: 'value' }` not positional args +2. **Import `DbConnection` from `./module_bindings`** — not from `spacetimedb` +3. **DO NOT edit generated bindings** — regenerate with `spacetime generate` +4. **Indexes go in OPTIONS (1st arg)** — not in COLUMNS (2nd arg) of `table()` +5. **Use BigInt for u64/i64 fields** — `0n`, `1n`, not `0`, `1` diff --git a/docs/.cursor/rules/spacetimedb.mdc b/docs/.cursor/rules/spacetimedb.mdc new file mode 100644 index 00000000000..4320774908a --- /dev/null +++ b/docs/.cursor/rules/spacetimedb.mdc @@ -0,0 +1,94 @@ +--- +description: "⛔ MANDATORY: Core SpacetimeDB concepts (all languages)." +globs: **/*.ts,**/*.tsx,**/*.js,**/*.jsx,**/*.rs,**/*.cs +alwaysApply: true +--- +# SpacetimeDB Rules (All Languages) + +> **Last updated:** 2026-01-08 + +## Language-Specific Rules + +| Language | Rule File | +|----------|-----------| +| **TypeScript/React** | `spacetimedb-typescript.mdc` (MANDATORY) | +| **C#/Unity** | `spacetimedb-csharp.mdc` (MANDATORY) | +| **Rust** | `spacetimedb-rust.mdc` (MANDATORY) | + +--- + +## Core Concepts + +1. **Reducers are transactional** — they do not return data to callers +2. **Reducers must be deterministic** — no filesystem, network, timers, or random +3. **Read data via tables/subscriptions** — not reducer return values +4. **Auto-increment IDs are not sequential** — gaps are normal, don't use for ordering +5. **`ctx.sender` is the authenticated principal** — never trust identity args + +--- + +## Index System + +SpacetimeDB automatically creates indexes for: +- Primary key columns +- Columns marked as unique + +You can add explicit indexes on non-unique columns for query performance. + +**How index naming works:** +- You declare an index name in your schema +- SpacetimeDB generates internal identifiers from that name +- These identifiers must be unique across your **entire module** (all tables) +- If two tables have indexes with the same declared name → conflict error + +**Implication:** When multiple tables have similar columns (e.g., `roomId`, `ownerId`), ensure your index names don't collide. Any naming convention that guarantees uniqueness works. + +**Schema ↔ Code coupling:** +- Your query code references indexes by name +- If you add/remove/rename an index in the schema, update all code that uses it +- Removing an index without updating queries causes runtime errors + +--- + +## Feature Implementation Checklist + +When implementing a feature that spans backend and client: + +1. **Backend:** Define table(s) to store the data +2. **Backend:** Define reducer(s) to mutate the data +3. **Client:** Subscribe to the table(s) +4. **Client:** Call the reducer(s) from UI — **don't forget this step!** +5. **Client:** Render the data from the table(s) + +**Common mistake:** Building backend tables/reducers but forgetting to wire up the client to call them. + +--- + +## Commands + +```bash +spacetime start # Start local server +spacetime publish --project-path # Publish module +spacetime publish --clear-database -y ... # Clear and republish +spacetime generate --lang --out-dir ... # Generate client bindings +spacetime logs # View server logs +``` + +--- + +## Debugging Checklist + +1. Is SpacetimeDB server running? (`spacetime start`) +2. Is the module published? (`spacetime publish`) +3. Are client bindings generated? (`spacetime generate`) +4. Check server logs for errors (`spacetime logs `) +5. **Is the reducer actually being called from the client?** + +--- + +## Editing Behavior + +- Make the smallest change necessary +- Do NOT touch unrelated files, configs, or dependencies +- Do NOT invent new SpacetimeDB APIs — use only what exists in docs or this repo +- Do NOT add restrictions the prompt didn't ask for — if "users can do X", implement X for all users diff --git a/tools/llm-oneshot/.cursor/rules/benchmark.mdc b/tools/llm-oneshot/.cursor/rules/benchmark.mdc new file mode 100644 index 00000000000..c0e938f08be --- /dev/null +++ b/tools/llm-oneshot/.cursor/rules/benchmark.mdc @@ -0,0 +1,126 @@ +--- +description: Rules for executing benchmark prompts. Ensures clean, uncontaminated code generation for fair AI comparison. +globs: apps/**/* +--- + +# Benchmark Generation Rules + +## ⛔ CRITICAL: No Cross-Contamination + +When executing prompts from any `apps/*/prompts/` folder: + +### NEVER read or reference: +- Other timestamped implementation folders (e.g., `app-name-YYYYMMDD-HHMMSS/`) +- Any folder under `apps/*///` containing previously generated code +- Any folder under `apps/*/staging/` containing other implementations +- Any other AI-generated implementations in the workspace + +These folders contain other AI-generated code. Looking at them contaminates the benchmark and invalidates results. + +### ONLY use these sources: +1. **The prompt itself** — The specific `.md` file being executed +2. **Official documentation** — `docs/docs/**/*.md` +3. **Language/framework rules** — `.cursor/rules/*.mdc` +4. **Test harness** — `apps/*/test-harness/` (for understanding test expectations, not implementations) + +## Prompt Execution Process + +### Project Location + +All new benchmark apps must be created in the **staging** folder: +``` +apps//staging////app-YYYYMMDD-HHMMSS/ +``` + +Example: `apps/chat-app/staging/typescript/opus-4-5/spacetime/chat-app-20260108-120000/` + +Use the test harness to scaffold: +```bash +cd apps/chat-app/test-harness +npm run create -- --lang=typescript --llm=opus-4-5 --backend=spacetime +``` + +### For SpacetimeDB Apps (5-Phase Workflow) + +**Phase 1: Backend** +1. Read the prompt file completely +2. Read relevant documentation (never existing implementations) +3. Create timestamped folder in `staging////` +4. Write backend code (`schema.ts`, reducers, `index.ts`) +5. Install backend dependencies: `cd && npm install` +6. Publish to SpacetimeDB: `spacetime publish --project-path ` + +**Phase 2: Bindings** +7. Generate client bindings: `spacetime generate --lang typescript --out-dir /src/module_bindings --project-path ` + +**Phase 3: Client** +8. Write client code (imports from `./module_bindings` now resolve) +9. Implement ONLY the features listed in the prompt +10. Do NOT add features not explicitly requested + +**Phase 4: Verify** +11. Install client dependencies: `cd && npm install` +12. Type-check: `npx tsc --noEmit` +13. Build: `npm run build` +14. **Both must pass before proceeding** + +**Phase 5: Deploy** +15. Ask to deploy when verification passes + +### For PostgreSQL Apps + +1. Read the prompt file completely +2. Read relevant documentation (never existing implementations) +3. Create timestamped folder as specified in the prompt +4. Implement ONLY the features listed in the prompt +5. Do NOT add features not explicitly requested +6. Do NOT add "nice to have" improvements +7. Ask to deploy when done + +## Feature Scope + +- Implement exactly what the prompt requests — nothing more, nothing less +- Do not carry over patterns from other sessions or existing code +- Each generation must be independent and uncontaminated +- If uncertain about a feature, implement the minimal interpretation + +## Implementation Patterns + +### Database Time in Containers +When using containerized databases (Docker), calculate time-based expiration entirely within the database using its native functions (e.g., `NOW() + INTERVAL '60 seconds'`) rather than passing timestamps from JavaScript. Container and host clocks may differ significantly. + +--- + +## Running the Test Harness + +**After deploying a benchmark app, ALWAYS ask:** + +> "The app is running. Would you like me to run the benchmark test harness?" + +**If yes:** +```bash +cd apps//test-harness +npm install +npx playwright install chromium + +# Use --level=N matching the prompt (path is in staging folder) +CLIENT_URL=http://localhost:5173 npm run benchmark -- ../staging////-YYYYMMDD-HHMMSS/ --level=N +``` + +**Prompt level mapping (for chat-app):** +| Prompt | Level | +|--------|-------| +| `01_*_basic` | `--level=1` | +| `05_*_edit_history` | `--level=5` | +| `08_*_threading` | `--level=8` | +| `12_*_anonymous` | `--level=12` | + +## After Grading + +After grading is complete, ask to promote: + +> "Grading complete! Would you like me to promote this app from staging to the final location?" + +```bash +npm run promote -- ../staging////-YYYYMMDD-HHMMSS/ +``` diff --git a/tools/llm-oneshot/.cursor/rules/deployment.mdc b/tools/llm-oneshot/.cursor/rules/deployment.mdc new file mode 100644 index 00000000000..34f78eb8414 --- /dev/null +++ b/tools/llm-oneshot/.cursor/rules/deployment.mdc @@ -0,0 +1,376 @@ +--- +description: Deployment commands and workflow for SpacetimeDB and PostgreSQL apps. +globs: +--- + +# Deployment Guide + +> **Last updated:** 2026-01-08 + +This file covers deployment workflows for benchmark apps in this repository (SpacetimeDB and PostgreSQL). + +--- + +## 0) Folder Structure & Staging Workflow + +All new benchmark apps should be created in the **staging** folder: + +``` +apps/chat-app/ +├── staging/ # ← CREATE NEW APPS HERE +│ ├── typescript/ +│ │ └── / # e.g., opus-4-5, gpt-5, gemini-3-pro +│ │ └── spacetime|postgres/ +│ │ └── chat-app-YYYYMMDD-HHMMSS/ +│ ├── rust/ +│ └── csharp/ +│ +├── typescript/ # ← GRADED apps get promoted here +├── rust/ +├── csharp/ +├── prompts/ +└── test-harness/ +``` + +### Creating New Projects + +Use the test harness to scaffold new projects: + +```bash +cd apps/chat-app/test-harness +npm run create -- --lang=typescript --llm=opus-4-5 --backend=spacetime +``` + +This creates: `staging/typescript/opus-4-5/spacetime/chat-app-YYYYMMDD-HHMMSS/` + +### After Grading: Promote to Final Location + +```bash +npm run promote -- ../staging/typescript/opus-4-5/spacetime/chat-app-YYYYMMDD-HHMMSS/ +``` + +This verifies `GRADING_RESULTS.md` exists and moves to `typescript/opus-4-5/spacetime/...` + +--- + +## 1) Agent Workflow Rules + +| Wrong | Right | +|-------|-------| +| Create app in `typescript/llm/...` directly | Create app in `staging/typescript/llm/...` first | +| Write backend AND client, then deploy | Write backend, publish, generate bindings, THEN write client | +| Create files, list commands, stop | Create files, verify, **ASK** to deploy, **RUN** commands if yes | +| Deploy benchmark app, stop | Deploy, **ASK** to run benchmark test harness | +| `spacetime publish` without `npm install` | Run `npm install` in backend first | +| Write client code before bindings exist | Generate bindings first so imports resolve correctly | + +**After creating AND VERIFYING project files, ALWAYS ask:** + +> "Would you like me to deploy this? +> - **Local** — Deploy locally +> - **Cloud/Docker** — Deploy to cloud or containers +> - **Skip** — Skip deployment" + +**Then execute if they say yes.** Don't just list commands. + +--- + +## 2) Running Dev Servers (CRITICAL for Cursor AI) + +**Run dev servers with `is_background: true`** in Cursor AI context. Long-running foreground commands will time out. + +Check the terminals folder files to verify servers started successfully (look for "ready" messages). + +--- + +## 3) SpacetimeDB Development Workflow (5 Phases) + +SpacetimeDB apps MUST follow this phased workflow to ensure type safety: + +``` +Phase 1: Backend → Phase 2: Bindings → Phase 3: Client → Phase 4: Verify → Phase 5: Deploy +``` + +### Why This Order Matters + +Client code imports from generated `module_bindings/`. If you write client code BEFORE generating bindings: +- Imports won't resolve +- Type errors won't be caught +- You're guessing at generated types + +**Generate bindings FIRST, then write client code against real types.** + +--- + +### Phase 1: Write and Publish Backend + +1. Create backend files (`schema.ts`, reducers, `index.ts`) +2. Install dependencies and publish: + +```bash +cd && npm install +spacetime publish --project-path +``` + +**Module naming:** Use the timestamped folder name (e.g., `chat-app-20260106-180327`) for unique module names. + +--- + +### Phase 2: Generate Bindings + +```bash +spacetime generate --lang typescript --out-dir /src/module_bindings --project-path +``` + +This creates the `module_bindings/` folder with: +- `DbConnection` class +- Table types (e.g., `User`, `Message`) +- `tables` object for `useTable()` +- Reducer type signatures + +--- + +### Phase 3: Write Client Code + +NOW write client code. Imports from `./module_bindings` will resolve correctly: + +```ts +import { DbConnection, tables, User, Message } from './module_bindings'; +``` + +TypeScript will catch type errors because bindings actually exist. + +--- + +### Phase 4: Verify Client Compiles + +Before deployment, verify the client builds successfully: + +```bash +cd && npm install +npx tsc --noEmit # Type-check only +npm run build # Full production build +``` + +**Both must pass.** If either fails, fix the errors before deploying. + +--- + +### Phase 5: Deploy (Run Dev Servers) + +Only after verification passes: + +```bash +cd && npm run dev +``` + +**Note:** If bindings were generated in Phase 2, skip regeneration in deployment. + +--- + +## 4) SpacetimeDB Deployment Commands + +### 4.1 Port Configuration (CRITICAL) + +**SpacetimeDB local server uses port 3000 by default.** + +| Service | Port | +|---------|------| +| SpacetimeDB server | 3000 (WebSocket) | +| Vite client | 5173 (or 5174 if 5173 in use) | + +**NEVER set Vite to port 3000** — it will conflict with SpacetimeDB. + +In `vite.config.ts`: +```ts +export default defineConfig({ + plugins: [react()], + server: { + port: 5173, // NOT 3000! + }, +}); +``` + +### 4.2 Docker Deployment (RECOMMENDED) + +```bash +# 1. Create docker-compose.yml +version: '3.8' +services: + spacetimedb: + image: clockworklabs/spacetimedb-standalone:latest + ports: + - "3000:3000" + volumes: + - spacetimedb-data:/stdb +volumes: + spacetimedb-data: + +# 2. Clean up and start fresh +docker-compose down -v +docker-compose up -d + +# 3. Wait for ready, then add server +spacetime server add docker http://localhost:3000 --no-fingerprint +spacetime server set-default docker + +# 4. Run Phase 1-4 if not already done (see workflow above) +# If bindings already exist from Phase 2, skip step 6 + +# 5. Publish module (use echo y to auto-confirm) +echo y | spacetime publish --clear-database --project-path + +# 6. Generate bindings (skip if already done in Phase 2) +spacetime generate --lang typescript --out-dir /src/module_bindings --project-path + +# 7. Install and run client (background) +cd && npm install && npm run dev +``` + +### 4.3 Local Deployment (Alternative) + +```bash +# 1. Check local server +spacetime server ping local + +# If not running, start in background: +spacetime start + +# 2. Publish module (use echo y to auto-confirm) +echo y | spacetime publish --clear-database --project-path + +# 3. Generate bindings (skip if already done in Phase 2) +spacetime generate --lang typescript --out-dir /src/module_bindings --project-path + +# 4. Install and run client (background) +cd && npm install && npm run dev +``` + +### 4.4 Maincloud Deployment + +Use URI: `wss://maincloud.spacetimedb.com` + +Same commands as local, but publishing goes to maincloud automatically if configured. + +### 4.5 Kill Port Before Dev Server + +Add to client `package.json`: +```json +"scripts": { + "kill-port": "npx kill-port 5173 2>nul || true", + "dev": "npm run kill-port && vite" +} +``` + +--- + +## 5) PostgreSQL Deployment + +### 5.1 Docker Deployment (Recommended) + +1. **Clean up previous deployments** — Stop containers and remove volumes: + ```bash + docker-compose down -v + ``` + +2. **Use unique JWT secret per deployment** — Include timestamp: + ```yaml + JWT_SECRET: my-app-YYYYMMDD-HHMMSS-secret + ``` + +3. **Build and run:** + ```bash + docker-compose up --build -d + ``` + +4. **Verify:** Check logs for schema push: + ```bash + docker-compose logs server + ``` + +### 5.2 Local Deployment + +```bash +# 1. Check PostgreSQL is running +pg_isready + +# 2. Create database if needed + +# 3. Server (background) +cd && npm install && npm run db:push && npm run dev + +# 4. Client (background, separate terminal) +cd && npm install && npm run dev +``` + +### 5.3 Kill Port Before Dev Server + +Add to client `package.json`: +```json +"scripts": { + "kill-port": "npx kill-port 5174 2>nul || true", + "dev": "npm run kill-port && vite" +} +``` + +### 5.4 Default Ports + +- PostgreSQL: 5432 +- Server API: 3001 +- Client: 5174 + +--- + +## 6) C# SpacetimeDB Deployment + +### 6.1 GUI Framework + +**Use .NET MAUI for C# GUI clients** — Microsoft's recommended cross-platform framework. + +| Framework | Use Case | +|-----------|----------| +| **.NET MAUI** | ✅ Desktop/mobile GUI apps (RECOMMENDED) | +| Console | Backend tools, CLI utilities only | +| WPF/WinForms | ❌ DO NOT USE (legacy, Windows-only) | + +### 6.2 Backend Module Build + +C# modules require WASI-WASM compilation: + +```bash +# 1. Add global.json for .NET 8 +echo '{"sdk":{"version":"8.0.319","rollForward":"latestFeature"}}' > backend/global.json + +# 2. Build WASM module +cd backend && dotnet publish -c Release + +# 3. Publish to SpacetimeDB +spacetime publish -c=always -y --bin-path bin/Release/net8.0/wasi-wasm/AppBundle/backend.wasm +``` + +### 6.3 Generate C# Bindings + +```bash +spacetime generate --lang csharp --out-dir client/module_bindings --bin-path backend/bin/Release/net8.0/wasi-wasm/AppBundle/backend.wasm +``` + +### 6.4 MAUI Client Setup + +```bash +# Create MAUI project +dotnet new maui -n client +cd client +dotnet add package SpacetimeDB.ClientSDK +``` + +### 6.5 Run MAUI Client + +```bash +# Windows +dotnet build -f net8.0-windows10.0.19041.0 +dotnet run -f net8.0-windows10.0.19041.0 + +# macOS +dotnet build -f net8.0-maccatalyst +dotnet run -f net8.0-maccatalyst +``` diff --git a/tools/llm-oneshot/.cursor/rules/frontend-csharp.mdc b/tools/llm-oneshot/.cursor/rules/frontend-csharp.mdc new file mode 100644 index 00000000000..356ddbaa6b2 --- /dev/null +++ b/tools/llm-oneshot/.cursor/rules/frontend-csharp.mdc @@ -0,0 +1,140 @@ +--- +description: "GUI framework choice for C# applications in this project" +globs: **/*.cs, **/*.xaml +alwaysApply: false +--- + +# C# GUI Framework — Use MAUI + +When building a **GUI application** in C# for this project, use **.NET MAUI**. + +## Setup + +```bash +# Install MAUI workload +dotnet workload install maui-windows + +# Create MAUI app +dotnet new maui -n MyClient +cd MyClient +dotnet add package SpacetimeDB.ClientSDK +``` + +## Project File (Windows-only) + +```xml + + + net8.0-windows10.0.19041.0 + WinExe + MyClient + true + true + None + false + true + enable + enable + + + + + + + + +``` + +## MAUI XAML Gotchas + +```xml + + + + + + + +